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

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

Making some changes to allow pools with different number of server

+) Associate context client to each grid distribution (This should be changed in the future)
+) Correct some buffer size estimation
+) Clean some redundant code and add comments

  • 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: 47.1 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(CContextClient* client)
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_[client].end();
171       for (it = indSrv_[client].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
508    connectedServerRank_.clear();
509    nbSenders.clear();
510
511    for (int p = 0; p < nbSrvPools; ++p)
512    {
513      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
514      int nbServer = client->serverSize;
515      int range, clientSize = client->clientSize;
516      int rank = client->clientRank;
517
518      size_t ni = this->n.getValue();
519      size_t ibegin = this->begin.getValue();
520      size_t global_zoom_end = global_zoom_begin+global_zoom_n-1;
521      size_t nZoomCount = 0;
522      size_t nbIndex = index.numElements();
523
524      // First of all, we should compute the mapping of the global index and local index of the current client
525      if (globalLocalIndexMap_.empty())
526      {
527        for (size_t idx = 0; idx < nbIndex; ++idx)
528        {
529          globalLocalIndexMap_[index(idx)] = idx;
530        }
531      }
532
533      // Calculate the compressed index if any
534      std::set<int> writtenInd;
535      if (isCompressible_)
536      {
537        for (int idx = 0; idx < data_index.numElements(); ++idx)
538        {
539          int ind = CDistributionClient::getAxisIndex(data_index(idx), data_begin, ni);
540
541          if (ind >= 0 && ind < ni && mask(ind))
542          {
543            ind += ibegin;
544            if (ind >= global_zoom_begin && ind <= global_zoom_end)
545              writtenInd.insert(ind);
546          }
547        }
548      }
549
550      // Compute the global index of the current client (process) hold
551      std::vector<int> nGlobAxis(1);
552      nGlobAxis[0] = n_glo.getValue();
553
554      size_t globalSizeIndex = 1, indexBegin, indexEnd;
555      for (int i = 0; i < nGlobAxis.size(); ++i) globalSizeIndex *= nGlobAxis[i];
556      indexBegin = 0;
557      if (globalSizeIndex <= clientSize)
558      {
559        indexBegin = rank%globalSizeIndex;
560        indexEnd = indexBegin;
561      }
562      else
563      {
564        for (int i = 0; i < clientSize; ++i)
565        {
566          range = globalSizeIndex / clientSize;
567          if (i < (globalSizeIndex%clientSize)) ++range;
568          if (i == client->clientRank) break;
569          indexBegin += range;
570        }
571        indexEnd = indexBegin + range - 1;
572      }
573
574      CArray<size_t,1> globalIndex(index.numElements());
575      for (size_t idx = 0; idx < globalIndex.numElements(); ++idx)
576        globalIndex(idx) = index(idx);
577
578      // Describe the distribution of server side
579      CServerDistributionDescription serverDescription(nGlobAxis, nbServer);
580      std::vector<int> serverZeroIndex;
581      serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);     
582
583      std::list<int> serverZeroIndexLeader;
584      std::list<int> serverZeroIndexNotLeader; 
585      CContextClient::computeLeader(client->clientRank, client->clientSize, serverZeroIndex.size(), serverZeroIndexLeader, serverZeroIndexNotLeader);
586      for (std::list<int>::iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
587        *it = serverZeroIndex[*it];
588
589      // Find out the connection between client and server side
590      CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(), client->intraComm);
591      clientServerMap->computeServerIndexMapping(globalIndex);
592      CClientServerMapping::GlobalIndexMap& globalIndexAxisOnServer = clientServerMap->getGlobalIndexOnServer();     
593
594
595      indSrv_[client].swap(globalIndexAxisOnServer);
596      CClientServerMapping::GlobalIndexMap::const_iterator it  = indSrv_[client].begin(),
597                                                           ite = indSrv_[client].end();
598     
599      for (it = indSrv_[client].begin(); it != ite; ++it) {
600        connectedServerRank_[client].push_back(it->first);
601      }
602
603      for (std::list<int>::const_iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
604        connectedServerRank_[client].push_back(*it);
605
606       // Even if a client has no index, it must connect to at least one server and
607       // send an "empty" data to this server
608       if (connectedServerRank_[client].empty())
609        connectedServerRank_[client].push_back(client->clientRank % client->serverSize);
610
611      nbSenders[client] = CClientServerMapping::computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_[client]);
612
613      delete clientServerMap;
614    }
615  }
616
617  /*
618    Compute the index of data to write into file
619    (Different from the previous version, this version of XIOS allows data be written into file (classical role),
620    or transfered to another clients)
621  */
622  void CAxis::computeWrittenIndex()
623  { 
624    if (computedWrittenIndex_) return;
625    computedWrittenIndex_ = true;
626
627    CContext* context=CContext::getCurrent();     
628    CContextServer* server = context->server; 
629
630    // We describe the distribution of client (server) on which data are written
631    std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
632    nBegin[0]       = zoom_begin;
633    nSize[0]        = zoom_n;   
634    nBeginGlobal[0] = 0; 
635    nGlob[0]        = n_glo;
636    CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
637    const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
638
639    // Because all written data are local on a client,
640    // we need to compute the local index on the server from its corresponding global index
641    size_t nbWritten = 0, indGlo;     
642    boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
643                                                        ite = globalLocalIndexMap_.end(), it;         
644    CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
645                                     itSrve = writtenGlobalIndex.end(), itSrv; 
646    if (!zoomByIndex())
647    {   
648      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
649      {
650        indGlo = *itSrv;
651        if (ite != globalLocalIndexMap_.find(indGlo))
652        {         
653          ++nbWritten;
654        }                 
655      }
656
657      localIndexToWriteOnServer.resize(nbWritten);
658
659      nbWritten = 0;
660      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
661      {
662        indGlo = *itSrv;
663        if (ite != globalLocalIndexMap_.find(indGlo))
664        {
665          localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
666          ++nbWritten;
667        }                 
668      }
669    }
670    else
671    {
672      nbWritten = 0;
673      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
674                                                          ite = globalLocalIndexMap_.end(), it;
675      for (int i = 0; i < zoom_index.numElements(); ++i)
676      {
677         if (ite != globalLocalIndexMap_.find(zoom_index(i)))
678          ++nbWritten;
679      }
680
681      localIndexToWriteOnServer.resize(nbWritten);
682
683      nbWritten = 0;
684      for (int i = 0; i < zoom_index.numElements(); ++i)
685      {
686         if (ite != globalLocalIndexMap_.find(zoom_index(i)))
687         {
688           localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[zoom_index(i)];
689           ++nbWritten;
690         }
691      }
692    }
693
694    if (isCompressible())
695    {
696      nbWritten = 0;
697      boost::unordered_map<size_t,size_t> localGlobalIndexMap;
698      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
699      {
700        indGlo = *itSrv;
701        if (ite != globalLocalIndexMap_.find(indGlo))
702        {
703          localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
704          ++nbWritten;
705        }                 
706      }
707
708      nbWritten = 0;
709      for (int idx = 0; idx < data_index.numElements(); ++idx)
710      {
711        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
712        {
713          ++nbWritten;
714        }
715      }
716
717      compressedIndexToWriteOnServer.resize(nbWritten);
718      nbWritten = 0;
719      for (int idx = 0; idx < data_index.numElements(); ++idx)
720      {
721        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
722        {
723          compressedIndexToWriteOnServer(nbWritten) = localGlobalIndexMap[data_index(idx)];
724          ++nbWritten;
725        }
726      }
727
728      numberWrittenIndexes_ = nbWritten;
729      if (isDistributed())
730      {
731             
732        MPI_Allreduce(&numberWrittenIndexes_, &totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
733        MPI_Scan(&numberWrittenIndexes_, &offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
734        offsetWrittenIndexes_ -= numberWrittenIndexes_;
735      }
736      else
737        totalNumberWrittenIndexes_ = numberWrittenIndexes_;
738    }
739  }
740
741
742  /*!
743    Send distribution information from a group of client (client role) to another group of client (server role)
744    The distribution of a group of client (server role) is imposed by the group of client (client role)
745    \param [in] globalDim global dimension of grid containing this axis
746    \param [in] orderPositionInGrid the relative order of this axis in the grid (e.g grid composed of domain+axis -> orderPositionInGrid is 2)
747    \param [in] distType distribution type of the server. For now, we only have band distribution.
748  */
749  void CAxis::sendDistributionAttribute(const std::vector<int>& globalDim, int orderPositionInGrid,
750                                        CServerDistributionDescription::ServerDistributionType distType)
751  {
752    CContext* context = CContext::getCurrent();
753
754    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
755    for (int i = 0; i < nbSrvPools; ++i)
756    {
757      CContextClient* contextClientTmp = (context->hasServer) ? context->clientPrimServer[i]
758                                                                         : context->client;
759      int nbServer = contextClientTmp->serverSize;
760
761      CServerDistributionDescription serverDescription(globalDim, nbServer);
762      serverDescription.computeServerDistribution();
763
764      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
765      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
766
767      CEventClient event(getType(),EVENT_ID_DISTRIBUTION_ATTRIBUTE);
768      if (contextClientTmp->isServerLeader())
769      {
770        std::list<CMessage> msgs;
771
772        const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
773        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
774        {
775          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
776          const int begin = serverIndexBegin[*itRank][orderPositionInGrid];
777          const int ni    = serverDimensionSizes[*itRank][orderPositionInGrid];
778          const int end   = begin + ni - 1;         
779
780          msgs.push_back(CMessage());
781          CMessage& msg = msgs.back();
782          msg << this->getId();
783          msg << ni << begin << end;         
784          msg << isCompressible_;                   
785
786          event.push(*itRank,1,msg);
787        }
788        contextClientTmp->sendEvent(event);
789      }
790      else contextClientTmp->sendEvent(event);
791    }
792  }
793
794  /*
795    Receive distribution attribute from another client
796    \param [in] event event containing data of these attributes
797  */
798  void CAxis::recvDistributionAttribute(CEventServer& event)
799  {
800    CBufferIn* buffer = event.subEvents.begin()->buffer;
801    string axisId;
802    *buffer >> axisId;
803    get(axisId)->recvDistributionAttribute(*buffer);
804  }
805
806  /*
807    Receive distribution attribute from another client
808    \param [in] buffer buffer containing data of these attributes
809  */
810  void CAxis::recvDistributionAttribute(CBufferIn& buffer)
811  {
812    int ni_srv, begin_srv, end_srv;
813    int global_zoom_end, zoom_end;
814    bool zoomIndex = zoomByIndex();
815   
816    std::vector<int> zoom_index_tmp;
817    std::vector<int>::iterator itZoomBegin, itZoomEnd, itZoom;
818
819    buffer >> ni_srv >> begin_srv >> end_srv;   
820    buffer >> isCompressible_;           
821
822    // Set up new local size of axis on the receiving clients
823    n.setValue(ni_srv);
824    begin.setValue(begin_srv);
825
826    // If we have zoom by index then process it
827    if (zoomIndex)
828    {
829      zoom_index_tmp.resize(global_zoom_index.numElements());
830      std::copy(global_zoom_index.begin(), global_zoom_index.end(), zoom_index_tmp.begin());
831      std::sort(zoom_index_tmp.begin(), zoom_index_tmp.end());
832      itZoomBegin = std::lower_bound(zoom_index_tmp.begin(), zoom_index_tmp.end(), begin_srv);
833      itZoomEnd   = std::upper_bound(zoom_index_tmp.begin(), zoom_index_tmp.end(), end_srv);     
834      int sz = std::distance(itZoomBegin, itZoomEnd);
835      zoom_index.resize(sz);
836      itZoom = itZoomBegin;
837      for (int i = 0; i < sz; ++i, ++itZoom)
838      {
839        zoom_index(i) = *(itZoom);
840      }
841    }
842
843    global_zoom_begin = zoomIndex ? 0 : global_zoom_begin ;
844    global_zoom_n     = zoomIndex ? zoom_index_tmp.size() : global_zoom_n;
845    global_zoom_end   = global_zoom_begin + global_zoom_n - 1;
846
847    zoom_begin = zoomIndex ? std::distance(itZoomBegin, zoom_index_tmp.begin())
848                           : global_zoom_begin > begin_srv ? global_zoom_begin : begin_srv ;
849    zoom_end   = zoomIndex ? std::distance(zoom_index_tmp.begin(), itZoomEnd) - 1 
850                           : global_zoom_end < end_srv ? global_zoom_end : end_srv ;
851    zoom_n     = zoom_end - zoom_begin + 1;
852
853    if (zoom_n<=0)
854    {
855      zoom_begin = 0; zoom_n = 0;
856    }
857
858    if (n_glo == n)
859    {
860      zoom_begin = zoomIndex ? std::distance(itZoomBegin, zoom_index_tmp.begin())
861                             : global_zoom_begin;     
862      zoom_n     = zoomIndex ? zoom_index_tmp.size() : global_zoom_n;
863    }
864  }
865
866  /*
867    Send attributes of axis from a group of client to other group of clients/servers
868    on supposing that these attributes are not distributed among the sending group
869    In the future, if new attributes are added, they should also be processed in this function
870  */
871  void CAxis::sendNonDistributedAttributes()
872  {
873    CContext* context = CContext::getCurrent();
874
875    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 1) : 1;
876    for (int p = 0; p < nbSrvPools; ++p)
877    {
878      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
879
880      CEventClient event(getType(), EVENT_ID_NON_DISTRIBUTED_ATTRIBUTES);
881      size_t nbIndex = index.numElements();
882      size_t nbDataIndex = 0;
883
884      for (int idx = 0; idx < data_index.numElements(); ++idx)
885      {
886        int ind = data_index(idx);
887        if (ind >= 0 && ind < nbIndex) ++nbDataIndex;
888      }
889
890      CArray<int,1> dataIndex(nbDataIndex);
891      nbDataIndex = 0;
892      for (int idx = 0; idx < data_index.numElements(); ++idx)
893      {
894        int ind = data_index(idx);
895        if (ind >= 0 && ind < nbIndex)
896        {
897          dataIndex(nbDataIndex) = ind;
898          ++nbDataIndex;
899        }
900      }
901
902      if (client->isServerLeader())
903      {
904        std::list<CMessage> msgs;
905
906        const std::list<int>& ranks = client->getRanksServerLeader();
907        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
908        {
909          msgs.push_back(CMessage());
910          CMessage& msg = msgs.back();
911          msg << this->getId();
912          msg << index.getValue() << dataIndex << mask.getValue();
913          msg << hasValue;
914          if (hasValue) msg << value.getValue();
915          msg << hasBounds;
916          if (hasBounds) msg << bounds.getValue();
917          msg << hasLabel;
918          if (hasLabel) msg << label.getValue();
919
920          event.push(*itRank, 1, msg);
921        }
922        client->sendEvent(event);
923      }
924      else client->sendEvent(event);
925    }
926  }
927
928  /*
929    Receive the non-distributed attributes from another group of clients
930    \param [in] event event containing data of these attributes
931  */
932  void CAxis::recvNonDistributedAttributes(CEventServer& event)
933  {
934    list<CEventServer::SSubEvent>::iterator it;
935    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
936    {
937      CBufferIn* buffer = it->buffer;
938      string axisId;
939      *buffer >> axisId;
940      get(axisId)->recvNonDistributedAttributes(it->rank, *buffer);
941    }
942  }
943
944  /*
945    Receive the non-distributed attributes from another group of clients
946    \param [in] rank rank of the sender
947    \param [in] buffer buffer containing data sent from the sender
948  */
949  void CAxis::recvNonDistributedAttributes(int rank, CBufferIn& buffer)
950  { 
951    CArray<int,1> tmp_index, tmp_data_index, tmp_zoom_index;
952    CArray<bool,1> tmp_mask;
953    CArray<double,1> tmp_val;
954    CArray<double,2> tmp_bnds;
955    CArray<string,1> tmp_label;
956
957    buffer >> tmp_index;
958    index.reference(tmp_index);
959    buffer >> tmp_data_index;
960    data_index.reference(tmp_data_index);
961    buffer >> tmp_mask;
962    mask.reference(tmp_mask);
963
964    buffer >> hasValue;
965    if (hasValue)
966    {
967      buffer >> tmp_val;
968      value.reference(tmp_val);
969    }
970
971    buffer >> hasBounds;
972    if (hasBounds)
973    {
974      buffer >> tmp_bnds;
975      bounds.reference(tmp_bnds);
976    }
977
978    buffer >> hasLabel;
979    if (hasLabel)
980    {
981      buffer >> tmp_label;
982      label.reference(tmp_label);
983    }
984
985    // Some value should be reset here
986    data_begin.setValue(0);
987    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
988    for (int idx = 0; idx < index.numElements(); ++idx) globalLocalIndexMap_[idx] = index(idx);
989  }
990
991  /*
992    Send attributes of axis from a group of client to other group of clients/servers
993    on supposing that these attributes are distributed among the clients of the sending group
994    In the future, if new attributes are added, they should also be processed in this function
995  */
996  void CAxis::sendDistributedAttributes(void)
997  {
998    int ns, n, i, j, ind, nv, idx;
999    CContext* context = CContext::getCurrent();
1000   
1001    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 1) : 1;
1002    for (int p = 0; p < nbSrvPools; ++p)
1003    {
1004      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1005
1006      CEventClient eventData(getType(), EVENT_ID_DISTRIBUTED_ATTRIBUTES);
1007
1008      list<CMessage> listData;
1009      list<CArray<int,1> > list_indi, list_dataInd, list_zoomInd;
1010      list<CArray<bool,1> > list_mask;
1011      list<CArray<double,1> > list_val;
1012      list<CArray<double,2> > list_bounds;
1013      list<CArray<string,1> > list_label;
1014
1015      int nbIndex = index.numElements();
1016      CArray<int,1> dataIndex(nbIndex);
1017      dataIndex = -1;
1018      for (idx = 0; idx < data_index.numElements(); ++idx)
1019      {
1020        if (0 <= data_index(idx) && data_index(idx) < nbIndex)
1021          dataIndex(idx) = 1;
1022      }
1023
1024      boost::unordered_map<int, std::vector<size_t> >::const_iterator it, iteMap;
1025      iteMap = indSrv_[client].end();
1026      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
1027      {
1028        int nbData = 0;
1029        int rank = connectedServerRank_[client][k];       
1030        it = indSrv_[client].find(rank);
1031        if (iteMap != it)
1032          nbData = it->second.size();
1033
1034        list_indi.push_back(CArray<int,1>(nbData));
1035        list_dataInd.push_back(CArray<int,1>(nbData));       
1036        list_mask.push_back(CArray<bool,1>(nbData));
1037
1038        if (hasValue)
1039          list_val.push_back(CArray<double,1>(nbData));
1040
1041        if (hasBounds)       
1042          list_bounds.push_back(CArray<double,2>(2,nbData));
1043
1044        if (hasLabel)
1045          list_label.push_back(CArray<string,1>(nbData));
1046
1047        CArray<int,1>& indi = list_indi.back();
1048        CArray<int,1>& dataIndi = list_dataInd.back();       
1049        CArray<bool,1>& maskIndi = list_mask.back();
1050
1051        for (n = 0; n < nbData; ++n)
1052        {
1053          idx = static_cast<int>(it->second[n]);
1054          indi(n) = idx;
1055
1056          ind = globalLocalIndexMap_[idx];
1057          dataIndi(n) = dataIndex(ind);
1058          maskIndi(n) = mask(ind);
1059
1060          if (hasValue)
1061          {
1062            CArray<double,1>& val = list_val.back();
1063            val(n) = value(ind);
1064          }
1065
1066          if (hasBounds)
1067          {
1068            CArray<double,2>& boundsVal = list_bounds.back();
1069            boundsVal(0, n) = bounds(0,n);
1070            boundsVal(1, n) = bounds(1,n);
1071          }
1072
1073          if (hasLabel)
1074          {
1075            CArray<string,1>& labelVal = list_label.back();
1076            labelVal(n) = label(ind); 
1077          }
1078        }
1079
1080        listData.push_back(CMessage());
1081        listData.back() << this->getId()
1082                        << list_indi.back() << list_dataInd.back() << list_mask.back();
1083
1084        listData.back() << hasValue;
1085        if (hasValue)
1086          listData.back() << list_val.back();
1087
1088        listData.back() << hasBounds;
1089        if (hasBounds)
1090          listData.back() << list_bounds.back();
1091
1092        listData.back() << hasLabel;
1093        if (hasLabel)
1094          listData.back() << list_label.back();
1095
1096        eventData.push(rank, nbSenders[client][rank], listData.back());
1097      }
1098
1099      client->sendEvent(eventData);
1100    }
1101  }
1102
1103  /*
1104    Receive the distributed attributes from another group of clients
1105    \param [in] event event containing data of these attributes
1106  */
1107  void CAxis::recvDistributedAttributes(CEventServer& event)
1108  {
1109    string axisId;
1110    vector<int> ranks;
1111    vector<CBufferIn*> buffers;
1112
1113    list<CEventServer::SSubEvent>::iterator it;
1114    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1115    {
1116      ranks.push_back(it->rank);
1117      CBufferIn* buffer = it->buffer;
1118      *buffer >> axisId;
1119      buffers.push_back(buffer);
1120    }
1121    get(axisId)->recvDistributedAttributes(ranks, buffers);
1122  }
1123
1124  /*
1125    Receive the non-distributed attributes from another group of clients
1126    \param [in] ranks rank of the sender
1127    \param [in] buffers buffer containing data sent from the sender
1128  */
1129  void CAxis::recvDistributedAttributes(vector<int>& ranks, vector<CBufferIn*> buffers)
1130  {
1131    int nbReceived = ranks.size(), idx, ind, gloInd, locInd;
1132    vector<CArray<int,1> > vec_indi(nbReceived), vec_dataInd(nbReceived), vec_zoomInd(nbReceived);   
1133    vector<CArray<bool,1> > vec_mask(nbReceived);
1134    vector<CArray<double,1> > vec_val(nbReceived);
1135    vector<CArray<double,2> > vec_bounds(nbReceived);
1136    vector<CArray<string,1> > vec_label(nbReceived);
1137   
1138    for (idx = 0; idx < nbReceived; ++idx)
1139    {     
1140      CBufferIn& buffer = *buffers[idx];
1141      buffer >> vec_indi[idx];
1142      buffer >> vec_dataInd[idx];     
1143      buffer >> vec_mask[idx];
1144
1145      buffer >> hasValue;
1146      if (hasValue)
1147        buffer >> vec_val[idx];
1148
1149      buffer >> hasBounds;
1150      if (hasBounds)
1151        buffer >> vec_bounds[idx];
1152
1153      buffer >> hasLabel;
1154      if (hasLabel)
1155        buffer >> vec_label[idx]; 
1156    }
1157
1158    // Estimate size of index array
1159    int nbIndexGlob = 0;
1160    for (idx = 0; idx < nbReceived; ++idx)
1161    {
1162      nbIndexGlob += vec_indi[idx].numElements();
1163    }
1164
1165    // Recompute global index
1166    // Take account of the overlapped index
1167    index.resize(nbIndexGlob);
1168    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1169    nbIndexGlob = 0;
1170    for (idx = 0; idx < nbReceived; ++idx)
1171    {
1172      CArray<int,1>& tmp = vec_indi[idx];
1173      for (ind = 0; ind < tmp.numElements(); ++ind)
1174      {
1175         gloInd = tmp(ind);
1176         if (0 == globalLocalIndexMap_.count(gloInd))
1177         {
1178           index(nbIndexGlob) = gloInd % n_glo;           
1179           globalLocalIndexMap_[gloInd] = nbIndexGlob; 
1180           ++nbIndexGlob;
1181         } 
1182      } 
1183    }
1184
1185    // Resize index to its real size
1186    index.resizeAndPreserve(nbIndexGlob);
1187
1188    int nbData = nbIndexGlob;
1189    CArray<int,1> nonCompressedData(nbData);
1190    nonCompressedData = -1;   
1191    mask.resize(nbData);
1192    if (hasValue)
1193      value.resize(nbData);
1194    if (hasBounds)
1195      bounds.resize(2,nbData);
1196    if (hasLabel)
1197      label.resize(nbData);
1198
1199    nbData = 0;
1200    for (idx = 0; idx < nbReceived; ++idx)
1201    {
1202      CArray<int,1>& indi = vec_indi[idx];
1203      CArray<int,1>& dataIndi = vec_dataInd[idx];
1204      CArray<bool,1>& maskIndi = vec_mask[idx];
1205      int nb = indi.numElements();
1206      for (int n = 0; n < nb; ++n)
1207      { 
1208        locInd = globalLocalIndexMap_[size_t(indi(n))];
1209
1210        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1211
1212        if (!mask(locInd)) // Only rewrite mask if it's not true
1213          mask(locInd) = maskIndi(n);
1214       
1215        if (hasValue)
1216          value(locInd) = vec_val[idx](n);
1217
1218        if (hasBounds)
1219        {
1220          bounds(0,locInd) = vec_bounds[idx](0,n);
1221          bounds(1,locInd) = vec_bounds[idx](1,n);
1222        }
1223
1224        if (hasLabel)
1225          label(locInd) = vec_label[idx](n);
1226      }
1227    }
1228   
1229    int nbCompressedData = 0; 
1230    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1231    {
1232      if (0 <= nonCompressedData(idx))
1233        ++nbCompressedData;       
1234    }
1235
1236    data_index.resize(nbCompressedData);
1237    nbCompressedData = 0;
1238    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1239    {
1240      if (0 <= nonCompressedData(idx))
1241      {
1242        data_index(nbCompressedData) = idx % n;
1243        ++nbCompressedData;       
1244      }
1245    }
1246
1247    data_begin.setValue(0);
1248  }
1249
1250
1251  /*!
1252    Compare two axis objects.
1253    They are equal if only if they have identical attributes as well as their values.
1254    Moreover, they must have the same transformations.
1255  \param [in] axis Compared axis
1256  \return result of the comparison
1257  */
1258  bool CAxis::isEqual(CAxis* obj)
1259  {
1260    vector<StdString> excludedAttr;
1261    excludedAttr.push_back("axis_ref");
1262
1263    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1264    if (!objEqual) return objEqual;
1265
1266    TransMapTypes thisTrans = this->getAllTransformations();
1267    TransMapTypes objTrans  = obj->getAllTransformations();
1268
1269    TransMapTypes::const_iterator it, itb, ite;
1270    std::vector<ETranformationType> thisTransType, objTransType;
1271    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1272      thisTransType.push_back(it->first);
1273    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1274      objTransType.push_back(it->first);
1275
1276    if (thisTransType.size() != objTransType.size()) return false;
1277    for (int idx = 0; idx < thisTransType.size(); ++idx)
1278      objEqual &= (thisTransType[idx] == objTransType[idx]);
1279
1280    return objEqual;
1281  }
1282
1283  /*
1284    Add transformation into axis. This function only servers for Fortran interface
1285    \param [in] transType transformation type
1286    \param [in] id identifier of the transformation object
1287  */
1288  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1289  {
1290    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1291    return transformationMap_.back().second;
1292  }
1293
1294  /*
1295    Check whether an axis has (spatial) transformation
1296  */
1297  bool CAxis::hasTransformation()
1298  {
1299    return (!transformationMap_.empty());
1300  }
1301
1302  /*
1303    Set transformation
1304    \param [in] axisTrans transformation to set
1305  */
1306  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1307  {
1308    transformationMap_ = axisTrans;
1309  }
1310
1311  /*
1312    Return all transformation held by the axis
1313    \return transformation the axis has
1314  */
1315  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1316  {
1317    return transformationMap_;
1318  }
1319
1320  /*
1321    Duplicate transformation of another axis
1322    \param [in] src axis whose transformations are copied
1323  */
1324  void CAxis::duplicateTransformation(CAxis* src)
1325  {
1326    if (src->hasTransformation())
1327    {
1328      this->setTransformations(src->getAllTransformations());
1329    }
1330  }
1331
1332  /*!
1333   * Go through the hierarchy to find the axis from which the transformations must be inherited
1334   */
1335  void CAxis::solveInheritanceTransformation()
1336  {
1337    if (hasTransformation() || !hasDirectAxisReference())
1338      return;
1339
1340    CAxis* axis = this;
1341    std::vector<CAxis*> refAxis;
1342    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1343    {
1344      refAxis.push_back(axis);
1345      axis = axis->getDirectAxisReference();
1346    }
1347
1348    if (axis->hasTransformation())
1349      for (size_t i = 0; i < refAxis.size(); ++i)
1350        refAxis[i]->setTransformations(axis->getAllTransformations());
1351  }
1352
1353  void CAxis::parse(xml::CXMLNode & node)
1354  {
1355    SuperClass::parse(node);
1356
1357    if (node.goToChildElement())
1358    {
1359      StdString nodeElementName;
1360      do
1361      {
1362        StdString nodeId("");
1363        if (node.getAttributes().end() != node.getAttributes().find("id"))
1364        { nodeId = node.getAttributes()["id"]; }
1365
1366        nodeElementName = node.getElementName();
1367        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1368        it = transformationMapList_.find(nodeElementName);
1369        if (ite != it)
1370        {
1371          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1372                                                                                                               nodeId,
1373                                                                                                               &node)));
1374        }
1375        else
1376        {
1377          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1378                << "The transformation " << nodeElementName << " has not been supported yet.");
1379        }
1380      } while (node.goToNextElement()) ;
1381      node.goToParentElement();
1382    }
1383  }
1384
1385  DEFINE_REF_FUNC(Axis,axis)
1386
1387   ///---------------------------------------------------------------
1388
1389} // namespace xios
Note: See TracBrowser for help on using the repository browser.