source: XIOS/dev/dev_olga/src/node/axis.cpp @ 1589

Last change on this file since 1589 was 1589, checked in by oabramkina, 5 years ago

Backporting r1578 and r1586 to dev, cleaning the code before merging it to XIOS 2.5.

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