source: XIOS/dev/XIOS_DEV_CMIP6/src/node/axis.cpp @ 1235

Last change on this file since 1235 was 1235, checked in by mhnguyen, 7 years ago

Fixing a bug on writting axis label

+) Axis label is correctly processed before being written
+) Do some code cleaning and add some comments

Test
+) On Curie
+) OK

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