source: XIOS/trunk/src/node/axis.cpp @ 1566

Last change on this file since 1566 was 1566, checked in by oabramkina, 6 years ago

Bugfix for masked distributed axis.

Previously mask wasn't working at all, an exception was thrown.

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 46.9 KB
Line 
1#include "axis.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "message.hpp"
7#include "type.hpp"
8#include "context.hpp"
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "xios_spl.hpp"
12#include "server_distribution_description.hpp"
13#include "client_server_mapping_distributed.hpp"
14#include "distribution_client.hpp"
15
16namespace xios {
17
18   /// ////////////////////// Definitions ////////////////////// ///
19
20   CAxis::CAxis(void)
21      : CObjectTemplate<CAxis>()
22      , CAxisAttributes(), isChecked(false), relFiles(), areClientAttributesChecked_(false)
23      , isClientAfterTransformationChecked(false)
24      , hasBounds(false), isCompressible_(false)
25      , numberWrittenIndexes_(), totalNumberWrittenIndexes_(), offsetWrittenIndexes_()
26      , transformationMap_(), hasValue(false), hasLabel(false)
27      , computedWrittenIndex_(false)
28          , clients()
29   {
30   }
31
32   CAxis::CAxis(const StdString & id)
33      : CObjectTemplate<CAxis>(id)
34      , CAxisAttributes(), isChecked(false), relFiles(), areClientAttributesChecked_(false)
35      , isClientAfterTransformationChecked(false)
36      , hasBounds(false), isCompressible_(false)
37      , numberWrittenIndexes_(), totalNumberWrittenIndexes_(), offsetWrittenIndexes_()
38      , transformationMap_(), hasValue(false), hasLabel(false)
39      , computedWrittenIndex_(false)
40          , clients()
41   {
42   }
43
44   CAxis::~CAxis(void)
45   { /* Ne rien faire de plus */ }
46
47   std::map<StdString, ETranformationType> CAxis::transformationMapList_ = std::map<StdString, ETranformationType>();
48   bool CAxis::dummyTransformationMapList_ = CAxis::initializeTransformationMap(CAxis::transformationMapList_);
49   bool CAxis::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
50   {
51     m["zoom_axis"] = TRANS_ZOOM_AXIS;
52     m["interpolate_axis"] = TRANS_INTERPOLATE_AXIS;
53     m["extract_axis"] = TRANS_EXTRACT_AXIS;
54     m["inverse_axis"] = TRANS_INVERSE_AXIS;
55     m["reduce_domain"] = TRANS_REDUCE_DOMAIN_TO_AXIS;
56     m["reduce_axis"] = TRANS_REDUCE_AXIS_TO_AXIS;
57     m["extract_domain"] = TRANS_EXTRACT_DOMAIN_TO_AXIS;
58     m["temporal_splitting"] = TRANS_TEMPORAL_SPLITTING;
59     m["duplicate_scalar"] = TRANS_DUPLICATE_SCALAR_TO_AXIS;
60
61   }
62
63   ///---------------------------------------------------------------
64
65   const std::set<StdString> & CAxis::getRelFiles(void) const
66   {
67      return (this->relFiles);
68   }
69
70   bool CAxis::IsWritten(const StdString & filename) const
71   {
72      return (this->relFiles.find(filename) != this->relFiles.end());
73   }
74
75   bool CAxis::isWrittenCompressed(const StdString& filename) const
76   {
77      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
78   }
79
80   bool CAxis::isDistributed(void) const
81   {
82      bool distributed = (!this->begin.isEmpty() && !this->n.isEmpty() && (this->begin + this->n < this->n_glo)) ||
83             (!this->n.isEmpty() && (this->n != this->n_glo));
84      // A same stupid condition to make sure that if there is only one client, axis
85      // should be considered to be distributed. This should be a temporary solution     
86      distributed |= (1 == CContext::getCurrent()->client->clientSize);
87      return distributed;
88   }
89
90   /*!
91    * Test whether the data defined on the axis can be outputted in a compressed way.
92    *
93    * \return true if and only if a mask was defined for this axis
94    */
95   bool CAxis::isCompressible(void) const
96   {
97      return isCompressible_;
98   }
99
100   void CAxis::addRelFile(const StdString & filename)
101   {
102      this->relFiles.insert(filename);
103   }
104
105   void CAxis::addRelFileCompressed(const StdString& filename)
106   {
107      this->relFilesCompressed.insert(filename);
108   }
109
110   //----------------------------------------------------------------
111
112   /*!
113     Returns the number of indexes written by each server.
114     \return the number of indexes written by each server
115   */
116   int CAxis::getNumberWrittenIndexes(MPI_Comm writtenCom)
117   {
118     int writtenSize;
119     MPI_Comm_size(writtenCom, &writtenSize);
120     return numberWrittenIndexes_[writtenSize];
121   }
122
123   /*!
124     Returns the total number of indexes written by the servers.
125     \return the total number of indexes written by the servers
126   */
127   int CAxis::getTotalNumberWrittenIndexes(MPI_Comm writtenCom)
128   {
129     int writtenSize;
130     MPI_Comm_size(writtenCom, &writtenSize);
131     return totalNumberWrittenIndexes_[writtenSize];
132   }
133
134   /*!
135     Returns the offset of indexes written by each server.
136     \return the offset of indexes written by each server
137   */
138   int CAxis::getOffsetWrittenIndexes(MPI_Comm writtenCom)
139   {
140     int writtenSize;
141     MPI_Comm_size(writtenCom, &writtenSize);
142     return offsetWrittenIndexes_[writtenSize];
143   }
144
145   CArray<int, 1>& CAxis::getCompressedIndexToWriteOnServer(MPI_Comm writtenCom)
146   {
147     int writtenSize;
148     MPI_Comm_size(writtenCom, &writtenSize);
149     return compressedIndexToWriteOnServer[writtenSize];
150   }
151   //----------------------------------------------------------------
152
153   /*!
154    * Compute the minimum buffer size required to send the attributes to the server(s).
155    *
156    * \return A map associating the server rank with its minimum buffer size.
157    */
158   std::map<int, StdSize> CAxis::getAttributesBufferSize(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid,
159                                                         CServerDistributionDescription::ServerDistributionType distType)
160   {
161
162     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
163
164//     bool isNonDistributed = (n_glo == n);
165     bool isDistributed = (orderPositionInGrid == CServerDistributionDescription::defaultDistributedDimension(globalDim.size(), distType))
166                                 || (index.numElements() != n_glo);
167
168     if (client->isServerLeader())
169     {
170       // size estimation for sendServerAttribut
171       size_t size = 6 * sizeof(size_t);
172       // size estimation for sendNonDistributedValue
173       if (!isDistributed)
174       {
175//         size = std::max(size, CArray<double,1>::size(n_glo) + (isCompressible_ ? CArray<int,1>::size(n_glo) : 0));
176         size += CArray<int,1>::size(n_glo);
177         size += CArray<int,1>::size(n_glo);
178         size += CArray<bool,1>::size(n_glo);
179         size += CArray<double,1>::size(n_glo);
180         if (hasBounds)
181           size += CArray<double,2>::size(2*n_glo);
182         if (hasLabel)
183          size += CArray<StdString,1>::size(n_glo);
184       }
185       size += CEventClient::headerSize + getId().size() + sizeof(size_t);
186
187       const std::list<int>& ranks = client->getRanksServerLeader();
188       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
189       {
190         if (size > attributesSizes[*itRank])
191           attributesSizes[*itRank] = size;
192       }
193       const std::list<int>& ranksNonLeaders = client->getRanksServerNotLeader();
194       for (std::list<int>::const_iterator itRank = ranksNonLeaders.begin(), itRankEnd = ranksNonLeaders.end(); itRank != itRankEnd; ++itRank)
195       {
196         if (size > attributesSizes[*itRank])
197           attributesSizes[*itRank] = size;
198       }
199
200     }
201
202     if (isDistributed)
203     {
204       // size estimation for sendDistributedValue
205       std::unordered_map<int, vector<size_t> >::const_iterator it, ite = indSrv_[client->serverSize].end();
206       for (it = indSrv_[client->serverSize].begin(); it != ite; ++it)
207       {
208         size_t size = 6 * sizeof(size_t);
209         size += CArray<int,1>::size(it->second.size());
210         size += CArray<int,1>::size(it->second.size());
211         size += CArray<bool,1>::size(it->second.size());
212         size += CArray<double,1>::size(it->second.size());
213         if (hasBounds)
214           size += CArray<double,2>::size(2 * it->second.size());
215         if (hasLabel)
216           size += CArray<StdString,1>::size(it->second.size());
217
218         size += CEventClient::headerSize + getId().size() + sizeof(size_t);
219         if (size > attributesSizes[it->first])
220           attributesSizes[it->first] = size;
221       }
222     }
223
224     return attributesSizes;
225   }
226
227   //----------------------------------------------------------------
228
229   StdString CAxis::GetName(void)   { return (StdString("axis")); }
230   StdString CAxis::GetDefName(void){ return (CAxis::GetName()); }
231   ENodeType CAxis::GetType(void)   { return (eAxis); }
232
233   //----------------------------------------------------------------
234
235   CAxis* CAxis::createAxis()
236   {
237     CAxis* axis = CAxisGroup::get("axis_definition")->createChild();
238     return axis;
239   }
240
241   /*!
242     Check common attributes of an axis.
243     This check should be done in the very beginning of work flow
244   */
245   void CAxis::checkAttributes(void)
246   {
247      if (this->n_glo.isEmpty())
248        ERROR("CAxis::checkAttributes(void)",
249              << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
250              << "The axis is wrongly defined, attribute 'n_glo' must be specified");
251      StdSize size = this->n_glo.getValue();
252
253      if (!this->index.isEmpty())
254      {
255        if (n.isEmpty()) n = index.numElements();
256
257        // It's not so correct but if begin is not the first value of index
258        // then data on the local axis has user-defined distribution. In this case, begin has no meaning.
259        if (begin.isEmpty()) begin = index(0);         
260      }
261      else 
262      {
263        if (!this->begin.isEmpty())
264        {
265          if (begin < 0 || begin > size - 1)
266            ERROR("CAxis::checkAttributes(void)",
267                  << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
268                  << "The axis is wrongly defined, attribute 'begin' (" << begin.getValue() << ") must be non-negative and smaller than size-1 (" << size - 1 << ").");
269        }
270        else this->begin.setValue(0);
271
272        if (!this->n.isEmpty())
273        {
274          if (n < 0 || n > size)
275            ERROR("CAxis::checkAttributes(void)",
276                  << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
277                  << "The axis is wrongly defined, attribute 'n' (" << n.getValue() << ") must be non-negative and smaller than size (" << size << ").");
278        }
279        else this->n.setValue(size);
280
281        {
282          index.resize(n);
283          for (int i = 0; i < n; ++i) index(i) = i+begin;
284        }
285      }
286
287      // Remove this check because it doen't make sense in case of a hole or overlapping axes
288      if (!this->value.isEmpty())
289      {
290//        StdSize true_size = value.numElements();
291//        if (this->n.getValue() != true_size)
292//          ERROR("CAxis::checkAttributes(void)",
293//                << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
294//                << "The axis is wrongly defined, attribute 'value' has a different size (" << true_size << ") than the one defined by the \'size\' attribute (" << n.getValue() << ").");
295        this->hasValue = true;
296      }
297
298      this->checkBounds();
299
300      CContext* context=CContext::getCurrent();
301      if (context->hasClient)
302      {
303        this->checkData();
304        this->checkMask();
305        this->checkLabel();
306      }
307   }
308
309   /*!
310      Check the validity of data and fill in values if any.
311   */
312   void CAxis::checkData()
313   {
314      if (data_begin.isEmpty()) data_begin.setValue(0);
315
316      if (data_n.isEmpty())
317      {
318        data_n.setValue(n);
319      }
320      else if (data_n.getValue() < 0)
321      {
322        ERROR("CAxis::checkData(void)",
323              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
324              << "The data size should be strictly positive ('data_n' = " << data_n.getValue() << ").");
325      }
326
327      if (data_index.isEmpty())
328      {
329        data_index.resize(data_n);
330        for (int i = 0; i < data_n; ++i) data_index(i) = i;
331      }
332   }
333
334    size_t CAxis::getGlobalWrittenSize(void)
335    {
336      return n_glo ;
337    }
338
339   /*!
340     Check validity of mask info and fill in values if any.
341   */
342   void CAxis::checkMask()
343   {
344      if (!mask.isEmpty())
345      {
346         if (mask.extent(0) != n)
347           ERROR("CAxis::checkMask(void)",
348                 << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
349                 << "The mask does not have the same size as the local domain." << std::endl
350                 << "Local size is " << n.getValue() << "." << std::endl
351                 << "Mask size is " << mask.extent(0) << ".");
352      }
353      else // (mask.isEmpty())
354      { // If no mask was defined, we create a default one without any masked point.
355         mask.resize(n);
356         for (int i = 0; i < n; ++i)
357         {
358           mask(i) = true;
359         }
360      }
361   }
362
363   /*!
364     Check validity of bounds info and fill in values if any.
365   */
366   void CAxis::checkBounds()
367   {
368     if (!bounds.isEmpty())
369     {
370       if (bounds.extent(0) != 2 || bounds.extent(1) != n)
371         ERROR("CAxis::checkAttributes(void)",
372               << "The bounds array of the axis [ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] must be of dimension 2 x axis size." << std::endl
373               << "Axis size is " << n.getValue() << "." << std::endl
374               << "Bounds size is "<< bounds.extent(0) << " x " << bounds.extent(1) << ".");
375       hasBounds = true;
376     }
377     else hasBounds = false;
378   }
379
380  void CAxis::checkLabel()
381  {
382    if (!label.isEmpty())
383    {
384      if (label.extent(0) != n)
385        ERROR("CAxis::checkLabel(void)",
386              << "The label array of the axis [ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] must be of dimension of axis size." << std::endl
387              << "Axis size is " << n.getValue() << "." << std::endl
388              << "label size is "<< label.extent(0)<<  " .");
389      hasLabel = true;
390    }
391    else hasLabel = false;
392  }
393
394  /*!
395    Check whether we can do compressed output
396  */
397  void CAxis::checkEligibilityForCompressedOutput()
398  {
399    // We don't check if the mask is valid here, just if a mask has been defined at this point.
400    isCompressible_ = !mask.isEmpty();
401  }
402
403  /*!
404    Dispatch event from the lower communication layer then process event according to its type
405  */
406  bool CAxis::dispatchEvent(CEventServer& event)
407  {
408     if (SuperClass::dispatchEvent(event)) return true;
409     else
410     {
411       switch(event.type)
412       {
413          case EVENT_ID_DISTRIBUTION_ATTRIBUTE :
414            recvDistributionAttribute(event);
415            return true;
416            break;
417         case EVENT_ID_NON_DISTRIBUTED_ATTRIBUTES:
418           recvNonDistributedAttributes(event);
419           return true;
420           break;
421         case EVENT_ID_DISTRIBUTED_ATTRIBUTES:
422           recvDistributedAttributes(event);
423           return true;
424           break;
425          default :
426            ERROR("bool CAxis::dispatchEvent(CEventServer& event)",
427                   << "Unknown Event");
428          return false;
429        }
430     }
431  }
432
433   /*!
434     Check attributes on client side (This name is still adequate???)
435   */
436   void CAxis::checkAttributesOnClient()
437   {
438     if (this->areClientAttributesChecked_) return;
439
440     CContext* context=CContext::getCurrent();
441     if (context->hasClient && !context->hasServer) this->checkAttributes();
442
443     this->areClientAttributesChecked_ = true;
444   }
445
446   /*
447     The (spatial) transformation sometimes can change attributes of an axis (e.g zoom can change mask or generate can change whole attributes)
448     Therefore, we should recheck them.
449   */
450   void CAxis::checkAttributesOnClientAfterTransformation(const std::vector<int>& globalDim, int orderPositionInGrid,
451                                                          CServerDistributionDescription::ServerDistributionType distType)
452   {
453     CContext* context=CContext::getCurrent() ;
454
455     if (this->isClientAfterTransformationChecked) return;
456     if (context->hasClient)
457     {       
458       if (orderPositionInGrid == CServerDistributionDescription::defaultDistributedDimension(globalDim.size(), distType))
459         computeConnectedClients(globalDim, orderPositionInGrid, distType);
460       else if (index.numElements() != n_glo) computeConnectedClients(globalDim, orderPositionInGrid,  CServerDistributionDescription::ROOT_DISTRIBUTION);
461     }
462
463     this->isClientAfterTransformationChecked = true;
464   }
465
466   /*
467     Send all checked attributes to server? (We dont have notion of server any more so client==server)
468     \param [in] globalDim global dimension of grid containing this axis
469     \param [in] orderPositionInGrid the relative order of this axis in the grid (e.g grid composed of domain+axis -> orderPositionInGrid is 2)
470     \param [in] distType distribution type of the server. For now, we only have band distribution.
471
472   */
473   void CAxis::sendCheckedAttributes(const std::vector<int>& globalDim, int orderPositionInGrid,
474                                     CServerDistributionDescription::ServerDistributionType distType)
475   {
476     if (!this->areClientAttributesChecked_) checkAttributesOnClient();
477     if (!this->isClientAfterTransformationChecked) checkAttributesOnClientAfterTransformation(globalDim, orderPositionInGrid, distType);
478     CContext* context = CContext::getCurrent();
479
480     if (this->isChecked) return;
481     if (context->hasClient) sendAttributes(globalDim, orderPositionInGrid, distType);   
482
483     this->isChecked = true;
484   }
485
486  /*!
487    Send attributes from one client to other clients
488    \param[in] globalDim global dimension of grid which contains this axis
489    \param[in] order
490  */
491  void CAxis::sendAttributes(const std::vector<int>& globalDim, int orderPositionInGrid,
492                             CServerDistributionDescription::ServerDistributionType distType)
493  {
494     sendDistributionAttribute(globalDim, orderPositionInGrid, distType);
495
496     // if (index.numElements() == n_glo.getValue())
497     if ((orderPositionInGrid == CServerDistributionDescription::defaultDistributedDimension(globalDim.size(), distType))
498         || (index.numElements() != n_glo))
499     {
500       sendDistributedAttributes();       
501     }
502     else
503     {
504       sendNonDistributedAttributes();   
505     }     
506  }
507
508  /*
509    Compute the connection between group of clients (or clients/servers).
510    (E.g: Suppose we have 2 group of clients in two model: A (client role) connect to B (server role),
511    this function calculate number of clients B connect to one client of A)
512     \param [in] globalDim global dimension of grid containing this axis
513     \param [in] orderPositionInGrid the relative order of this axis in the grid (e.g grid composed of domain+axis -> orderPositionInGrid is 2)
514     \param [in] distType distribution type of the server. For now, we only have band distribution.
515  */
516  void CAxis::computeConnectedClients(const std::vector<int>& globalDim, int orderPositionInGrid,
517                                     CServerDistributionDescription::ServerDistributionType distType)
518  {
519    CContext* context = CContext::getCurrent();
520
521    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 1) : 1;
522
523    connectedServerRank_.clear();
524    nbSenders.clear();
525
526    for (int p = 0; p < nbSrvPools; ++p)
527    {
528      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
529      int nbServer = client->serverSize;
530      int range, clientSize = client->clientSize;
531      int rank = client->clientRank;
532
533      if (connectedServerRank_.find(nbServer) == connectedServerRank_.end())
534      {
535        size_t ni = this->n.getValue();
536        size_t ibegin = this->begin.getValue();
537        size_t nbIndex = index.numElements();
538
539        // First of all, we should compute the mapping of the global index and local index of the current client
540        if (globalLocalIndexMap_.empty())
541        {
542          for (size_t idx = 0; idx < nbIndex; ++idx)
543          {
544            globalLocalIndexMap_[index(idx)] = idx;
545          }
546        }
547
548        // Calculate the compressed index if any
549        std::set<int> writtenInd;
550        if (isCompressible_)
551        {
552          for (int idx = 0; idx < data_index.numElements(); ++idx)
553          {
554            int ind = CDistributionClient::getAxisIndex(data_index(idx), data_begin, ni);
555
556            if (ind >= 0 && ind < ni && mask(ind))
557            {
558              ind += ibegin;
559              writtenInd.insert(ind);
560            }
561          }
562        }
563
564        // Compute the global index of the current client (process) hold
565        std::vector<int> nGlobAxis(1);
566        nGlobAxis[0] = n_glo.getValue();
567
568        size_t globalSizeIndex = 1, indexBegin, indexEnd;
569        for (int i = 0; i < nGlobAxis.size(); ++i) globalSizeIndex *= nGlobAxis[i];
570        indexBegin = 0;
571        if (globalSizeIndex <= clientSize)
572        {
573          indexBegin = rank%globalSizeIndex;
574          indexEnd = indexBegin;
575        }
576        else
577        {
578          for (int i = 0; i < clientSize; ++i)
579          {
580            range = globalSizeIndex / clientSize;
581            if (i < (globalSizeIndex%clientSize)) ++range;
582            if (i == client->clientRank) break;
583            indexBegin += range;
584          }
585          indexEnd = indexBegin + range - 1;
586        }
587
588        CArray<size_t,1> globalIndex(index.numElements());
589        for (size_t idx = 0; idx < globalIndex.numElements(); ++idx)
590          globalIndex(idx) = index(idx);
591
592        // Describe the distribution of server side
593
594        CServerDistributionDescription serverDescription(nGlobAxis, nbServer, distType);
595     
596        std::vector<int> serverZeroIndex;
597        serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t&,size_t&>(indexBegin, indexEnd), 0);
598
599        std::list<int> serverZeroIndexLeader;
600        std::list<int> serverZeroIndexNotLeader; 
601        CContextClient::computeLeader(client->clientRank, client->clientSize, serverZeroIndex.size(), serverZeroIndexLeader, serverZeroIndexNotLeader);
602        for (std::list<int>::iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
603          *it = serverZeroIndex[*it];
604
605        // Find out the connection between client and server side
606        CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(), client->intraComm);
607        clientServerMap->computeServerIndexMapping(globalIndex, nbServer);
608        CClientServerMapping::GlobalIndexMap& globalIndexAxisOnServer = clientServerMap->getGlobalIndexOnServer();     
609
610        indSrv_[nbServer].swap(globalIndexAxisOnServer);
611
612        if (distType==CServerDistributionDescription::ROOT_DISTRIBUTION)
613        {
614          for(int i=1; i<nbServer; ++i) indSrv_[nbServer].insert(pair<int, vector<size_t> >(i,indSrv_[nbServer][0]) ) ;
615          serverZeroIndexLeader.clear() ;
616        }
617         
618        CClientServerMapping::GlobalIndexMap::const_iterator it  = indSrv_[nbServer].begin(),
619                                                             ite = indSrv_[nbServer].end();
620
621        for (it = indSrv_[nbServer].begin(); it != ite; ++it) connectedServerRank_[nbServer].push_back(it->first);
622
623        for (std::list<int>::const_iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
624          connectedServerRank_[nbServer].push_back(*it);
625
626         // Even if a client has no index, it must connect to at least one server and
627         // send an "empty" data to this server
628         if (connectedServerRank_[nbServer].empty())
629          connectedServerRank_[nbServer].push_back(client->clientRank % client->serverSize);
630
631         nbSenders[nbServer] = CClientServerMapping::computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_[nbServer]);
632
633        delete clientServerMap;
634      }
635    }
636  }
637
638  /*
639    Compute the index of data to write into file
640    (Different from the previous version, this version of XIOS allows data be written into file (classical role),
641    or transfered to another clients)
642  */
643  void CAxis::computeWrittenIndex()
644  { 
645    if (computedWrittenIndex_) return;
646    computedWrittenIndex_ = true;
647
648    CContext* context=CContext::getCurrent();     
649    CContextServer* server = context->server; 
650
651    // We describe the distribution of client (server) on which data are written
652    std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
653    nBegin[0]       = begin;
654    nSize[0]        = n;
655    nBeginGlobal[0] = 0; 
656    nGlob[0]        = n_glo;
657    CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
658    const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
659
660    // Because all written data are local on a client,
661    // we need to compute the local index on the server from its corresponding global index
662    size_t nbWritten = 0, indGlo;     
663    std::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
664                                                        ite = globalLocalIndexMap_.end(), it;         
665    CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
666                                     itSrve = writtenGlobalIndex.end(), itSrv; 
667    for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
668    {
669      indGlo = *itSrv;
670      if (ite != globalLocalIndexMap_.find(indGlo))
671      {
672        ++nbWritten;
673      }
674    }
675
676    localIndexToWriteOnServer.resize(writtenGlobalIndex.numElements());
677//      localIndexToWriteOnServer.resize(nbWritten);
678
679    nbWritten = 0;
680    for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
681    {
682      indGlo = *itSrv;
683      if (ite != globalLocalIndexMap_.find(indGlo))
684      {
685        localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
686        ++nbWritten;
687      }
688    }
689  }
690
691  void CAxis::computeWrittenCompressedIndex(MPI_Comm writtenComm)
692  {
693    int writtenCommSize;
694    MPI_Comm_size(writtenComm, &writtenCommSize);
695    if (compressedIndexToWriteOnServer.find(writtenCommSize) != compressedIndexToWriteOnServer.end())
696      return;
697
698    if (isCompressible())
699    {
700      size_t nbWritten = 0, indGlo;
701      CContext* context=CContext::getCurrent();     
702      CContextServer* server = context->server; 
703
704      // We describe the distribution of client (server) on which data are written
705      std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
706      nBegin[0]       = 0;
707      nSize[0]        = n;
708      nBeginGlobal[0] = 0; 
709      nGlob[0]        = n_glo;
710      CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
711      const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
712      std::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
713                                                          ite = globalLocalIndexMap_.end(), it;   
714
715      CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
716                                       itSrve = writtenGlobalIndex.end(), itSrv;
717      std::unordered_map<size_t,size_t> localGlobalIndexMap;
718      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
719      {
720        indGlo = *itSrv;
721        if (ite != globalLocalIndexMap_.find(indGlo))
722        {
723          localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
724          ++nbWritten;
725        }                 
726      }
727
728      nbWritten = 0;
729      for (int idx = 0; idx < data_index.numElements(); ++idx)
730      {
731        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
732        {
733          ++nbWritten;
734        }
735      }
736
737      compressedIndexToWriteOnServer[writtenCommSize].resize(nbWritten);
738      nbWritten = 0;
739      for (int idx = 0; idx < data_index.numElements(); ++idx)
740      {
741        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
742        {
743          compressedIndexToWriteOnServer[writtenCommSize](nbWritten) = localGlobalIndexMap[data_index(idx)];
744          ++nbWritten;
745        }
746      }
747
748      numberWrittenIndexes_[writtenCommSize] = nbWritten;
749      if (isDistributed())
750      {
751             
752        MPI_Allreduce(&numberWrittenIndexes_[writtenCommSize], &totalNumberWrittenIndexes_[writtenCommSize], 1, MPI_INT, MPI_SUM, writtenComm);
753        MPI_Scan(&numberWrittenIndexes_[writtenCommSize], &offsetWrittenIndexes_[writtenCommSize], 1, MPI_INT, MPI_SUM, writtenComm);
754        offsetWrittenIndexes_[writtenCommSize] -= numberWrittenIndexes_[writtenCommSize];
755      }
756      else
757        totalNumberWrittenIndexes_[writtenCommSize] = numberWrittenIndexes_[writtenCommSize];
758    }
759  }
760
761  /*!
762    Send distribution information from a group of client (client role) to another group of client (server role)
763    The distribution of a group of client (server role) is imposed by the group of client (client role)
764    \param [in] globalDim global dimension of grid containing this axis
765    \param [in] orderPositionInGrid the relative order of this axis in the grid (e.g grid composed of domain+axis -> orderPositionInGrid is 2)
766    \param [in] distType distribution type of the server. For now, we only have band distribution.
767  */
768  void CAxis::sendDistributionAttribute(const std::vector<int>& globalDim, int orderPositionInGrid,
769                                        CServerDistributionDescription::ServerDistributionType distType)
770  {
771    std::list<CContextClient*>::iterator it;
772    for (it=clients.begin(); it!=clients.end(); ++it)
773    {
774      CContextClient* client = *it;
775      int nbServer = client->serverSize;
776
777      CServerDistributionDescription serverDescription(globalDim, nbServer);
778      serverDescription.computeServerDistribution();
779
780      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
781      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
782
783      CEventClient event(getType(),EVENT_ID_DISTRIBUTION_ATTRIBUTE);
784      if (client->isServerLeader())
785      {
786        std::list<CMessage> msgs;
787
788        const std::list<int>& ranks = client->getRanksServerLeader();
789        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
790        {
791          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
792          const int begin = serverIndexBegin[*itRank][orderPositionInGrid];
793          const int ni    = serverDimensionSizes[*itRank][orderPositionInGrid];
794
795          msgs.push_back(CMessage());
796          CMessage& msg = msgs.back();
797          msg << this->getId();
798          msg << ni << begin;
799          msg << isCompressible_;                   
800
801          event.push(*itRank,1,msg);
802        }
803        client->sendEvent(event);
804      }
805      else client->sendEvent(event);
806    }
807  }
808
809  /*
810    Receive distribution attribute from another client
811    \param [in] event event containing data of these attributes
812  */
813  void CAxis::recvDistributionAttribute(CEventServer& event)
814  {
815    CBufferIn* buffer = event.subEvents.begin()->buffer;
816    string axisId;
817    *buffer >> axisId;
818    get(axisId)->recvDistributionAttribute(*buffer);
819  }
820
821  /*
822    Receive distribution attribute from another client
823    \param [in] buffer buffer containing data of these attributes
824  */
825  void CAxis::recvDistributionAttribute(CBufferIn& buffer)
826  {
827    int ni_srv, begin_srv;
828    buffer >> ni_srv >> begin_srv;
829    buffer >> isCompressible_;           
830
831    // Set up new local size of axis on the receiving clients
832    n.setValue(ni_srv);
833    begin.setValue(begin_srv);
834  }
835
836  /*
837    Send attributes of axis from a group of client to other group of clients/servers
838    on supposing that these attributes are not distributed among the sending group
839    In the future, if new attributes are added, they should also be processed in this function
840  */
841  void CAxis::sendNonDistributedAttributes()
842  {
843    std::list<CContextClient*>::iterator it;
844    for (it=clients.begin(); it!=clients.end(); ++it)
845        {
846          CContextClient* client = *it;
847
848      CEventClient event(getType(), EVENT_ID_NON_DISTRIBUTED_ATTRIBUTES);
849      size_t nbIndex = index.numElements();
850      size_t nbDataIndex = 0;
851
852      for (int idx = 0; idx < data_index.numElements(); ++idx)
853      {
854        int ind = data_index(idx);
855        if (ind >= 0 && ind < nbIndex) ++nbDataIndex;
856      }
857
858      CArray<int,1> dataIndex(nbDataIndex);
859      nbDataIndex = 0;
860      for (int idx = 0; idx < data_index.numElements(); ++idx)
861      {
862        int ind = data_index(idx);
863        if (ind >= 0 && ind < nbIndex)
864        {
865          dataIndex(nbDataIndex) = ind;
866          ++nbDataIndex;
867        }
868      }
869
870      if (client->isServerLeader())
871      {
872        std::list<CMessage> msgs;
873
874        const std::list<int>& ranks = client->getRanksServerLeader();
875        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
876        {
877          msgs.push_back(CMessage());
878          CMessage& msg = msgs.back();
879          msg << this->getId();
880          msg << index.getValue() << dataIndex << mask.getValue();
881          msg << hasValue;
882          if (hasValue) msg << value.getValue();
883          msg << hasBounds;
884          if (hasBounds) msg << bounds.getValue();
885          msg << hasLabel;
886          if (hasLabel) msg << label.getValue();
887
888          event.push(*itRank, 1, msg);
889        }
890        client->sendEvent(event);
891      }
892      else client->sendEvent(event);
893    }
894  }
895
896  /*
897    Receive the non-distributed attributes from another group of clients
898    \param [in] event event containing data of these attributes
899  */
900  void CAxis::recvNonDistributedAttributes(CEventServer& event)
901  {
902    list<CEventServer::SSubEvent>::iterator it;
903    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
904    {
905      CBufferIn* buffer = it->buffer;
906      string axisId;
907      *buffer >> axisId;
908      get(axisId)->recvNonDistributedAttributes(it->rank, *buffer);
909    }
910  }
911
912  /*
913    Receive the non-distributed attributes from another group of clients
914    \param [in] rank rank of the sender
915    \param [in] buffer buffer containing data sent from the sender
916  */
917  void CAxis::recvNonDistributedAttributes(int rank, CBufferIn& buffer)
918  { 
919    CArray<int,1> tmp_index, tmp_data_index;
920    CArray<bool,1> tmp_mask;
921    CArray<double,1> tmp_val;
922    CArray<double,2> tmp_bnds;
923    CArray<string,1> tmp_label;
924
925    buffer >> tmp_index;
926    index.reference(tmp_index);
927    buffer >> tmp_data_index;
928    data_index.reference(tmp_data_index);
929    buffer >> tmp_mask;
930    mask.reference(tmp_mask);
931
932    buffer >> hasValue;
933    if (hasValue)
934    {
935      buffer >> tmp_val;
936      value.reference(tmp_val);
937    }
938
939    buffer >> hasBounds;
940    if (hasBounds)
941    {
942      buffer >> tmp_bnds;
943      bounds.reference(tmp_bnds);
944    }
945
946    buffer >> hasLabel;
947    if (hasLabel)
948    {
949      buffer >> tmp_label;
950      label.reference(tmp_label);
951    }
952
953    // Some value should be reset here
954    data_begin.setValue(0);
955    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
956//    for (int idx = 0; idx < index.numElements(); ++idx) globalLocalIndexMap_[idx] = index(idx);
957    for (int idx = 0; idx < index.numElements(); ++idx) globalLocalIndexMap_[index(idx)] = idx;
958  }
959
960  /*
961    Send attributes of axis from a group of client to other group of clients/servers
962    on supposing that these attributes are distributed among the clients of the sending group
963    In the future, if new attributes are added, they should also be processed in this function
964  */
965  void CAxis::sendDistributedAttributes(void)
966  {
967    int ns, n, i, j, ind, nv, idx;
968    std::list<CContextClient*>::iterator it;
969
970    for (it=clients.begin(); it!=clients.end(); ++it)
971    {
972      CContextClient* client = *it;
973      int nbServer = client->serverSize;
974
975      CEventClient eventData(getType(), EVENT_ID_DISTRIBUTED_ATTRIBUTES);
976
977      list<CMessage> listData;
978      list<CArray<int,1> > list_indi, list_dataInd;
979      list<CArray<bool,1> > list_mask;
980      list<CArray<double,1> > list_val;
981      list<CArray<double,2> > list_bounds;
982      list<CArray<string,1> > list_label;
983
984      int nbIndex = index.numElements();
985      CArray<int,1> dataIndex(nbIndex);
986      dataIndex = -1;
987      for (idx = 0; idx < data_index.numElements(); ++idx)
988      {
989        if (0 <= data_index(idx) && data_index(idx) < nbIndex)
990          dataIndex(idx) = 1;
991      }
992
993      std::unordered_map<int, std::vector<size_t> >::const_iterator it, iteMap;
994      iteMap = indSrv_[nbServer].end();
995      for (int k = 0; k < connectedServerRank_[nbServer].size(); ++k)
996      {
997        int nbData = 0;
998        int rank = connectedServerRank_[nbServer][k];
999        it = indSrv_[nbServer].find(rank);
1000        if (iteMap != it)
1001          nbData = it->second.size();
1002
1003        list_indi.push_back(CArray<int,1>(nbData));
1004        list_dataInd.push_back(CArray<int,1>(nbData));       
1005        list_mask.push_back(CArray<bool,1>(nbData));
1006
1007        if (hasValue)
1008          list_val.push_back(CArray<double,1>(nbData));
1009
1010        if (hasBounds)       
1011          list_bounds.push_back(CArray<double,2>(2,nbData));
1012
1013        if (hasLabel)
1014          list_label.push_back(CArray<string,1>(nbData));
1015
1016        CArray<int,1>& indi = list_indi.back();
1017        CArray<int,1>& dataIndi = list_dataInd.back();       
1018        CArray<bool,1>& maskIndi = list_mask.back();
1019
1020        for (n = 0; n < nbData; ++n)
1021        {
1022          idx = static_cast<int>(it->second[n]);
1023          indi(n) = idx;
1024
1025          ind = globalLocalIndexMap_[idx];
1026          dataIndi(n) = dataIndex(ind);
1027          maskIndi(n) = mask(ind);
1028
1029          if (hasValue)
1030          {
1031            CArray<double,1>& val = list_val.back();
1032            val(n) = value(ind);
1033          }
1034
1035          if (hasBounds)
1036          {
1037            CArray<double,2>& boundsVal = list_bounds.back();
1038            boundsVal(0, n) = bounds(0,ind);
1039            boundsVal(1, n) = bounds(1,ind);
1040          }
1041
1042          if (hasLabel)
1043          {
1044            CArray<string,1>& labelVal = list_label.back();
1045            labelVal(n) = label(ind); 
1046          }
1047        }
1048
1049        listData.push_back(CMessage());
1050        listData.back() << this->getId()
1051                        << list_indi.back() << list_dataInd.back() << list_mask.back();
1052
1053        listData.back() << hasValue;
1054        if (hasValue)
1055          listData.back() << list_val.back();
1056
1057        listData.back() << hasBounds;
1058        if (hasBounds)
1059          listData.back() << list_bounds.back();
1060
1061        listData.back() << hasLabel;
1062        if (hasLabel)
1063          listData.back() << list_label.back();
1064
1065        eventData.push(rank, nbSenders[nbServer][rank], listData.back());
1066      }
1067
1068      client->sendEvent(eventData);
1069    }
1070  }
1071
1072  /*
1073    Receive the distributed attributes from another group of clients
1074    \param [in] event event containing data of these attributes
1075  */
1076  void CAxis::recvDistributedAttributes(CEventServer& event)
1077  {
1078    string axisId;
1079    vector<int> ranks;
1080    vector<CBufferIn*> buffers;
1081
1082    list<CEventServer::SSubEvent>::iterator it;
1083    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1084    {
1085      ranks.push_back(it->rank);
1086      CBufferIn* buffer = it->buffer;
1087      *buffer >> axisId;
1088      buffers.push_back(buffer);
1089    }
1090    get(axisId)->recvDistributedAttributes(ranks, buffers);
1091  }
1092
1093  /*
1094    Receive the non-distributed attributes from another group of clients
1095    \param [in] ranks rank of the sender
1096    \param [in] buffers buffer containing data sent from the sender
1097  */
1098  void CAxis::recvDistributedAttributes(vector<int>& ranks, vector<CBufferIn*> buffers)
1099  {
1100    int nbReceived = ranks.size(), idx, ind, gloInd, locInd;
1101    vector<CArray<int,1> > vec_indi(nbReceived), vec_dataInd(nbReceived);
1102    vector<CArray<bool,1> > vec_mask(nbReceived);
1103    vector<CArray<double,1> > vec_val(nbReceived);
1104    vector<CArray<double,2> > vec_bounds(nbReceived);
1105    vector<CArray<string,1> > vec_label(nbReceived);
1106   
1107    for (idx = 0; idx < nbReceived; ++idx)
1108    {     
1109      CBufferIn& buffer = *buffers[idx];
1110      buffer >> vec_indi[idx];
1111      buffer >> vec_dataInd[idx];     
1112      buffer >> vec_mask[idx];
1113
1114      buffer >> hasValue;
1115      if (hasValue)
1116        buffer >> vec_val[idx];
1117
1118      buffer >> hasBounds;
1119      if (hasBounds)
1120        buffer >> vec_bounds[idx];
1121
1122      buffer >> hasLabel;
1123      if (hasLabel)
1124        buffer >> vec_label[idx]; 
1125    }
1126
1127    // Estimate size of index array
1128    int nbIndexGlob = 0;
1129    for (idx = 0; idx < nbReceived; ++idx)
1130    {
1131      nbIndexGlob += vec_indi[idx].numElements();
1132    }
1133
1134    // Recompute global index
1135    // Take account of the overlapped index
1136    index.resize(nbIndexGlob);
1137    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1138    nbIndexGlob = 0;
1139    int nbIndLoc = 0;
1140    for (idx = 0; idx < nbReceived; ++idx)
1141    {
1142      CArray<int,1>& tmp = vec_indi[idx];
1143      for (ind = 0; ind < tmp.numElements(); ++ind)
1144      {
1145         gloInd = tmp(ind);
1146         nbIndLoc = (gloInd % n_glo)-begin;
1147         if (0 == globalLocalIndexMap_.count(gloInd))
1148         {
1149           index(nbIndLoc) = gloInd % n_glo;
1150           globalLocalIndexMap_[gloInd] = nbIndLoc;
1151           ++nbIndexGlob;
1152         } 
1153      } 
1154    }
1155
1156    // Resize index to its real size
1157    if (nbIndexGlob==0) index.resize(nbIndexGlob) ;
1158    else index.resizeAndPreserve(nbIndexGlob);
1159
1160    int nbData = nbIndexGlob;
1161    CArray<int,1> nonCompressedData(nbData);
1162    nonCompressedData = -1;   
1163    mask.resize(nbData);
1164    if (hasValue)
1165      value.resize(nbData);
1166    if (hasBounds)
1167      bounds.resize(2,nbData);
1168    if (hasLabel)
1169      label.resize(nbData);
1170
1171    nbData = 0;
1172    for (idx = 0; idx < nbReceived; ++idx)
1173    {
1174      CArray<int,1>& indi = vec_indi[idx];
1175      CArray<int,1>& dataIndi = vec_dataInd[idx];
1176      CArray<bool,1>& maskIndi = vec_mask[idx];
1177      int nb = indi.numElements();
1178      for (int n = 0; n < nb; ++n)
1179      { 
1180        locInd = globalLocalIndexMap_[size_t(indi(n))];
1181
1182        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1183
1184        if (!mask(locInd)) // Only rewrite mask if it's not true
1185          mask(locInd) = maskIndi(n);
1186       
1187        if (hasValue)
1188          value(locInd) = vec_val[idx](n);
1189
1190        if (hasBounds)
1191        {
1192          bounds(0,locInd) = vec_bounds[idx](0,n);
1193          bounds(1,locInd) = vec_bounds[idx](1,n);
1194        }
1195
1196        if (hasLabel)
1197          label(locInd) = vec_label[idx](n);
1198      }
1199    }
1200   
1201    int nbCompressedData = 0; 
1202    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1203    {
1204      if (0 <= nonCompressedData(idx))
1205        ++nbCompressedData;       
1206    }
1207
1208    data_index.resize(nbCompressedData);
1209    nbCompressedData = 0;
1210    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1211    {
1212      if (0 <= nonCompressedData(idx))
1213      {
1214        data_index(nbCompressedData) = idx % n;
1215        ++nbCompressedData;       
1216      }
1217    }
1218
1219    data_begin.setValue(0);
1220  }
1221
1222
1223  /*!
1224    Compare two axis objects.
1225    They are equal if only if they have identical attributes as well as their values.
1226    Moreover, they must have the same transformations.
1227  \param [in] axis Compared axis
1228  \return result of the comparison
1229  */
1230  bool CAxis::isEqual(CAxis* obj)
1231  {
1232    vector<StdString> excludedAttr;
1233    excludedAttr.push_back("axis_ref");
1234
1235    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1236    if (!objEqual) return objEqual;
1237
1238    TransMapTypes thisTrans = this->getAllTransformations();
1239    TransMapTypes objTrans  = obj->getAllTransformations();
1240
1241    TransMapTypes::const_iterator it, itb, ite;
1242    std::vector<ETranformationType> thisTransType, objTransType;
1243    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1244      thisTransType.push_back(it->first);
1245    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1246      objTransType.push_back(it->first);
1247
1248    if (thisTransType.size() != objTransType.size()) return false;
1249    for (int idx = 0; idx < thisTransType.size(); ++idx)
1250      objEqual &= (thisTransType[idx] == objTransType[idx]);
1251
1252    return objEqual;
1253  }
1254
1255  /*
1256    Add transformation into axis. This function only servers for Fortran interface
1257    \param [in] transType transformation type
1258    \param [in] id identifier of the transformation object
1259  */
1260  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1261  {
1262    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1263    return transformationMap_.back().second;
1264  }
1265
1266  /*
1267    Check whether an axis has (spatial) transformation
1268  */
1269  bool CAxis::hasTransformation()
1270  {
1271    return (!transformationMap_.empty());
1272  }
1273
1274  /*
1275    Set transformation
1276    \param [in] axisTrans transformation to set
1277  */
1278  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1279  {
1280    transformationMap_ = axisTrans;
1281  }
1282
1283  /*
1284    Return all transformation held by the axis
1285    \return transformation the axis has
1286  */
1287  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1288  {
1289    return transformationMap_;
1290  }
1291
1292  /*
1293    Duplicate transformation of another axis
1294    \param [in] src axis whose transformations are copied
1295  */
1296  void CAxis::duplicateTransformation(CAxis* src)
1297  {
1298    if (src->hasTransformation())
1299    {
1300      this->setTransformations(src->getAllTransformations());
1301    }
1302  }
1303
1304  /*!
1305   * Go through the hierarchy to find the axis from which the transformations must be inherited
1306   */
1307  void CAxis::solveInheritanceTransformation()
1308  {
1309    if (hasTransformation() || !hasDirectAxisReference())
1310      return;
1311
1312    CAxis* axis = this;
1313    std::vector<CAxis*> refAxis;
1314    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1315    {
1316      refAxis.push_back(axis);
1317      axis = axis->getDirectAxisReference();
1318    }
1319
1320    if (axis->hasTransformation())
1321      for (size_t i = 0; i < refAxis.size(); ++i)
1322        refAxis[i]->setTransformations(axis->getAllTransformations());
1323  }
1324
1325  void CAxis::setContextClient(CContextClient* contextClient)
1326  {
1327    if (clientsSet.find(contextClient)==clientsSet.end())
1328    {
1329      clients.push_back(contextClient) ;
1330      clientsSet.insert(contextClient);
1331    }
1332}
1333
1334  void CAxis::parse(xml::CXMLNode & node)
1335  {
1336    SuperClass::parse(node);
1337
1338    if (node.goToChildElement())
1339    {
1340      StdString nodeElementName;
1341      do
1342      {
1343        StdString nodeId("");
1344        if (node.getAttributes().end() != node.getAttributes().find("id"))
1345        { nodeId = node.getAttributes()["id"]; }
1346
1347        nodeElementName = node.getElementName();
1348        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1349        it = transformationMapList_.find(nodeElementName);
1350        if (ite != it)
1351        {
1352          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1353                                                                                                               nodeId,
1354                                                                                                               &node)));
1355        }
1356        else
1357        {
1358          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1359                << "The transformation " << nodeElementName << " has not been supported yet.");
1360        }
1361      } while (node.goToNextElement()) ;
1362      node.goToParentElement();
1363    }
1364  }
1365
1366  DEFINE_REF_FUNC(Axis,axis)
1367
1368   ///---------------------------------------------------------------
1369
1370} // namespace xios
Note: See TracBrowser for help on using the repository browser.