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

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

Dev: removing traces of sending mask on domain and axis.

  • 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.9 KB
Line 
1#include "axis.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "message.hpp"
7#include "type.hpp"
8#include "context.hpp"
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "xios_spl.hpp"
12#include "server_distribution_description.hpp"
13#include "client_server_mapping_distributed.hpp"
14#include "distribution_client.hpp"
15
16namespace xios {
17
18   /// ////////////////////// Definitions ////////////////////// ///
19
20   CAxis::CAxis(void)
21      : CObjectTemplate<CAxis>()
22      , CAxisAttributes(), isChecked(false), relFiles(), areClientAttributesChecked_(false)
23      , isClientAfterTransformationChecked(false)
24      , hasBounds(false), isCompressible_(false)
25      , numberWrittenIndexes_(), totalNumberWrittenIndexes_(), offsetWrittenIndexes_()
26      , transformationMap_(), hasValue(false), hasLabel(false)
27      , computedWrittenIndex_(false)
28          , clients()
29   {
30   }
31
32   CAxis::CAxis(const StdString & id)
33      : CObjectTemplate<CAxis>(id)
34      , CAxisAttributes(), isChecked(false), relFiles(), areClientAttributesChecked_(false)
35      , isClientAfterTransformationChecked(false)
36      , hasBounds(false), isCompressible_(false)
37      , numberWrittenIndexes_(), totalNumberWrittenIndexes_(), offsetWrittenIndexes_()
38      , transformationMap_(), hasValue(false), hasLabel(false)
39      , computedWrittenIndex_(false)
40          , clients()
41   {
42   }
43
44   CAxis::~CAxis(void)
45   { /* Ne rien faire de plus */ }
46
47   std::map<StdString, ETranformationType> CAxis::transformationMapList_ = std::map<StdString, ETranformationType>();
48   bool CAxis::dummyTransformationMapList_ = CAxis::initializeTransformationMap(CAxis::transformationMapList_);
49   bool CAxis::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
50   {
51     m["zoom_axis"] = TRANS_ZOOM_AXIS;
52     m["interpolate_axis"] = TRANS_INTERPOLATE_AXIS;
53     m["extract_axis"] = TRANS_EXTRACT_AXIS;
54     m["inverse_axis"] = TRANS_INVERSE_AXIS;
55     m["reduce_domain"] = TRANS_REDUCE_DOMAIN_TO_AXIS;
56     m["reduce_axis"] = TRANS_REDUCE_AXIS_TO_AXIS;
57     m["extract_domain"] = TRANS_EXTRACT_DOMAIN_TO_AXIS;
58     m["temporal_splitting"] = TRANS_TEMPORAL_SPLITTING;
59     m["duplicate_scalar"] = TRANS_DUPLICATE_SCALAR_TO_AXIS;
60
61   }
62
63   ///---------------------------------------------------------------
64
65   const std::set<StdString> & CAxis::getRelFiles(void) const
66   {
67      return (this->relFiles);
68   }
69
70   bool CAxis::IsWritten(const StdString & filename) const
71   {
72      return (this->relFiles.find(filename) != this->relFiles.end());
73   }
74
75   bool CAxis::isWrittenCompressed(const StdString& filename) const
76   {
77      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
78   }
79
80   bool CAxis::isDistributed(void) const
81   {
82      bool distributed = (!this->begin.isEmpty() && !this->n.isEmpty() && (this->begin + this->n < this->n_glo)) ||
83             (!this->n.isEmpty() && (this->n != this->n_glo));
84      // A same stupid condition to make sure that if there is only one client, axis
85      // should be considered to be distributed. This should be a temporary solution     
86      distributed |= (1 == CContext::getCurrent()->client->clientSize);
87      return distributed;
88   }
89
90   /*!
91    * Test whether the data defined on the axis can be outputted in a compressed way.
92    *
93    * \return true if and only if a mask was defined for this axis
94    */
95   bool CAxis::isCompressible(void) const
96   {
97      return isCompressible_;
98   }
99
100   void CAxis::addRelFile(const StdString & filename)
101   {
102      this->relFiles.insert(filename);
103   }
104
105   void CAxis::addRelFileCompressed(const StdString& filename)
106   {
107      this->relFilesCompressed.insert(filename);
108   }
109
110   //----------------------------------------------------------------
111
112   /*!
113     Returns the number of indexes written by each server.
114     \return the number of indexes written by each server
115   */
116   int CAxis::getNumberWrittenIndexes(MPI_Comm writtenCom)
117   {
118     int writtenSize;
119     MPI_Comm_size(writtenCom, &writtenSize);
120     return numberWrittenIndexes_[writtenSize];
121   }
122
123   /*!
124     Returns the total number of indexes written by the servers.
125     \return the total number of indexes written by the servers
126   */
127   int CAxis::getTotalNumberWrittenIndexes(MPI_Comm writtenCom)
128   {
129     int writtenSize;
130     MPI_Comm_size(writtenCom, &writtenSize);
131     return totalNumberWrittenIndexes_[writtenSize];
132   }
133
134   /*!
135     Returns the offset of indexes written by each server.
136     \return the offset of indexes written by each server
137   */
138   int CAxis::getOffsetWrittenIndexes(MPI_Comm writtenCom)
139   {
140     int writtenSize;
141     MPI_Comm_size(writtenCom, &writtenSize);
142     return offsetWrittenIndexes_[writtenSize];
143   }
144
145   CArray<int, 1>& CAxis::getCompressedIndexToWriteOnServer(MPI_Comm writtenCom)
146   {
147     int writtenSize;
148     MPI_Comm_size(writtenCom, &writtenSize);
149     return compressedIndexToWriteOnServer[writtenSize];
150   }
151   //----------------------------------------------------------------
152
153   /*!
154    * Compute the minimum buffer size required to send the attributes to the server(s).
155    *
156    * \return A map associating the server rank with its minimum buffer size.
157    */
158   std::map<int, StdSize> CAxis::getAttributesBufferSize(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid,
159                                                         CServerDistributionDescription::ServerDistributionType distType)
160   {
161
162     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
163
164//     bool isNonDistributed = (n_glo == n);
165     bool isDistributed = (orderPositionInGrid == CServerDistributionDescription::defaultDistributedDimension(globalDim.size(), distType))
166                                 || (index.numElements() != n_glo);
167
168     if (client->isServerLeader())
169     {
170       // size estimation for sendServerAttribut
171       size_t size = 6 * sizeof(size_t);
172       // size estimation for sendNonDistributedValue
173       if (!isDistributed)
174       {
175//         size = std::max(size, CArray<double,1>::size(n_glo) + (isCompressible_ ? CArray<int,1>::size(n_glo) : 0));
176         size += CArray<int,1>::size(n_glo);
177         size += CArray<int,1>::size(n_glo);
178         size += CArray<bool,1>::size(n_glo);
179         size += CArray<double,1>::size(n_glo);
180         if (hasBounds)
181           size += CArray<double,2>::size(2*n_glo);
182         if (hasLabel)
183          size += CArray<StdString,1>::size(n_glo);
184       }
185       size += CEventClient::headerSize + getId().size() + sizeof(size_t);
186
187       const std::list<int>& ranks = client->getRanksServerLeader();
188       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
189       {
190         if (size > attributesSizes[*itRank])
191           attributesSizes[*itRank] = size;
192       }
193       const std::list<int>& ranksNonLeaders = client->getRanksServerNotLeader();
194       for (std::list<int>::const_iterator itRank = ranksNonLeaders.begin(), itRankEnd = ranksNonLeaders.end(); itRank != itRankEnd; ++itRank)
195       {
196         if (size > attributesSizes[*itRank])
197           attributesSizes[*itRank] = size;
198       }
199
200     }
201
202     if (isDistributed)
203     {
204       // size estimation for sendDistributedValue
205       std::unordered_map<int, vector<size_t> >::const_iterator it, ite = indSrv_[client->serverSize].end();
206       for (it = indSrv_[client->serverSize].begin(); it != ite; ++it)
207       {
208         size_t size = 6 * sizeof(size_t);
209         size += CArray<int,1>::size(it->second.size());
210         size += CArray<int,1>::size(it->second.size());
211         size += CArray<bool,1>::size(it->second.size());
212         size += CArray<double,1>::size(it->second.size());
213         if (hasBounds)
214           size += CArray<double,2>::size(2 * it->second.size());
215         if (hasLabel)
216           size += CArray<StdString,1>::size(it->second.size());
217
218         size += CEventClient::headerSize + getId().size() + sizeof(size_t);
219         if (size > attributesSizes[it->first])
220           attributesSizes[it->first] = size;
221       }
222     }
223
224     return attributesSizes;
225   }
226
227   //----------------------------------------------------------------
228
229   StdString CAxis::GetName(void)   { return (StdString("axis")); }
230   StdString CAxis::GetDefName(void){ return (CAxis::GetName()); }
231   ENodeType CAxis::GetType(void)   { return (eAxis); }
232
233   //----------------------------------------------------------------
234
235   CAxis* CAxis::createAxis()
236   {
237     CAxis* axis = CAxisGroup::get("axis_definition")->createChild();
238     return axis;
239   }
240
241   /*!
242     Check common attributes of an axis.
243     This check should be done in the very beginning of work flow
244   */
245   void CAxis::checkAttributes(void)
246   {
247     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<double,1> > vec_val(nbReceived);
1147    vector<CArray<double,2> > vec_bounds(nbReceived);
1148    vector<CArray<string,1> > vec_label(nbReceived);
1149   
1150    for (idx = 0; idx < nbReceived; ++idx)
1151    {     
1152      CBufferIn& buffer = *buffers[idx];
1153      buffer >> vec_indi[idx];
1154      buffer >> vec_dataInd[idx];     
1155
1156      buffer >> hasValue;
1157      if (hasValue)
1158        buffer >> vec_val[idx];
1159
1160      buffer >> hasBounds;
1161      if (hasBounds)
1162        buffer >> vec_bounds[idx];
1163
1164      buffer >> hasLabel;
1165      if (hasLabel)
1166        buffer >> vec_label[idx]; 
1167    }
1168
1169    // Estimate size of index array
1170    int nbIndexGlob = 0;
1171    for (idx = 0; idx < nbReceived; ++idx)
1172    {
1173      nbIndexGlob += vec_indi[idx].numElements();
1174    }
1175
1176    // Recompute global index
1177    // Take account of the overlapped index
1178    index.resize(nbIndexGlob);
1179    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1180    nbIndexGlob = 0;
1181    int nbIndLoc = 0;
1182    for (idx = 0; idx < nbReceived; ++idx)
1183    {
1184      CArray<int,1>& tmp = vec_indi[idx];
1185      for (ind = 0; ind < tmp.numElements(); ++ind)
1186      {
1187         gloInd = tmp(ind);
1188         nbIndLoc = (gloInd % n_glo)-begin;
1189         if (0 == globalLocalIndexMap_.count(gloInd))
1190         {
1191           index(nbIndexGlob) = gloInd % n_glo;
1192           globalLocalIndexMap_[gloInd] = nbIndexGlob;
1193           ++nbIndexGlob;
1194         } 
1195      } 
1196    }
1197
1198    // Resize index to its real size
1199    if (nbIndexGlob==0) index.resize(nbIndexGlob) ;
1200    else index.resizeAndPreserve(nbIndexGlob);
1201
1202    int nbData = nbIndexGlob;
1203    CArray<int,1> nonCompressedData(nbData);
1204    nonCompressedData = -1;   
1205    // Mask is incorporated into data_index and is not sent/received anymore
1206    mask.resize(0);
1207    if (hasValue)
1208      value.resize(nbData);
1209    if (hasBounds)
1210      bounds.resize(2,nbData);
1211    if (hasLabel)
1212      label.resize(nbData);
1213
1214    nbData = 0;
1215    for (idx = 0; idx < nbReceived; ++idx)
1216    {
1217      CArray<int,1>& indi = vec_indi[idx];
1218      CArray<int,1>& dataIndi = vec_dataInd[idx];
1219      int nb = indi.numElements();
1220      for (int n = 0; n < nb; ++n)
1221      { 
1222        locInd = globalLocalIndexMap_[size_t(indi(n))];
1223
1224        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1225
1226        if (hasValue)
1227          value(locInd) = vec_val[idx](n);
1228
1229        if (hasBounds)
1230        {
1231          bounds(0,locInd) = vec_bounds[idx](0,n);
1232          bounds(1,locInd) = vec_bounds[idx](1,n);
1233        }
1234
1235        if (hasLabel)
1236          label(locInd) = vec_label[idx](n);
1237      }
1238    }
1239   
1240    int nbCompressedData = 0;
1241    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1242    {
1243      if (0 <= nonCompressedData(idx))
1244        ++nbCompressedData;
1245    }
1246
1247    data_index.resize(nbCompressedData);
1248    nbCompressedData = 0;
1249    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1250    {
1251      if (0 <= nonCompressedData(idx))
1252      {
1253        data_index(nbCompressedData) = idx % n;
1254        ++nbCompressedData;
1255      }
1256    }
1257
1258    data_begin.setValue(0);
1259    data_n.setValue(data_index.numElements());
1260  }
1261
1262  /*!
1263    Compare two axis objects.
1264    They are equal if only if they have identical attributes as well as their values.
1265    Moreover, they must have the same transformations.
1266  \param [in] axis Compared axis
1267  \return result of the comparison
1268  */
1269  bool CAxis::isEqual(CAxis* obj)
1270  {
1271    vector<StdString> excludedAttr;
1272    excludedAttr.push_back("axis_ref");
1273
1274    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1275    if (!objEqual) return objEqual;
1276
1277    TransMapTypes thisTrans = this->getAllTransformations();
1278    TransMapTypes objTrans  = obj->getAllTransformations();
1279
1280    TransMapTypes::const_iterator it, itb, ite;
1281    std::vector<ETranformationType> thisTransType, objTransType;
1282    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1283      thisTransType.push_back(it->first);
1284    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1285      objTransType.push_back(it->first);
1286
1287    if (thisTransType.size() != objTransType.size()) return false;
1288    for (int idx = 0; idx < thisTransType.size(); ++idx)
1289      objEqual &= (thisTransType[idx] == objTransType[idx]);
1290
1291    return objEqual;
1292  }
1293
1294  /*
1295    Add transformation into axis. This function only servers for Fortran interface
1296    \param [in] transType transformation type
1297    \param [in] id identifier of the transformation object
1298  */
1299  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1300  {
1301    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1302    return transformationMap_.back().second;
1303  }
1304
1305  /*
1306    Check whether an axis has (spatial) transformation
1307  */
1308  bool CAxis::hasTransformation()
1309  {
1310    return (!transformationMap_.empty());
1311  }
1312
1313  /*
1314    Set transformation
1315    \param [in] axisTrans transformation to set
1316  */
1317  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1318  {
1319    transformationMap_ = axisTrans;
1320  }
1321
1322  /*
1323    Return all transformation held by the axis
1324    \return transformation the axis has
1325  */
1326  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1327  {
1328    return transformationMap_;
1329  }
1330
1331  /*
1332    Duplicate transformation of another axis
1333    \param [in] src axis whose transformations are copied
1334  */
1335  void CAxis::duplicateTransformation(CAxis* src)
1336  {
1337    if (src->hasTransformation())
1338    {
1339      this->setTransformations(src->getAllTransformations());
1340    }
1341  }
1342
1343  /*!
1344   * Go through the hierarchy to find the axis from which the transformations must be inherited
1345   */
1346  void CAxis::solveInheritanceTransformation()
1347  {
1348    if (hasTransformation() || !hasDirectAxisReference())
1349      return;
1350
1351    CAxis* axis = this;
1352    std::vector<CAxis*> refAxis;
1353    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1354    {
1355      refAxis.push_back(axis);
1356      axis = axis->getDirectAxisReference();
1357    }
1358
1359    if (axis->hasTransformation())
1360      for (size_t i = 0; i < refAxis.size(); ++i)
1361        refAxis[i]->setTransformations(axis->getAllTransformations());
1362  }
1363
1364  void CAxis::setContextClient(CContextClient* contextClient)
1365  {
1366    if (clientsSet.find(contextClient)==clientsSet.end())
1367    {
1368      clients.push_back(contextClient) ;
1369      clientsSet.insert(contextClient);
1370    }
1371  }
1372
1373  void CAxis::parse(xml::CXMLNode & node)
1374  {
1375    SuperClass::parse(node);
1376
1377    if (node.goToChildElement())
1378    {
1379      StdString nodeElementName;
1380      do
1381      {
1382        StdString nodeId("");
1383        if (node.getAttributes().end() != node.getAttributes().find("id"))
1384        { nodeId = node.getAttributes()["id"]; }
1385
1386        nodeElementName = node.getElementName();
1387        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1388        it = transformationMapList_.find(nodeElementName);
1389        if (ite != it)
1390        {
1391          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1392                                                                                                               nodeId,
1393                                                                                                               &node)));
1394        }
1395        else
1396        {
1397          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1398                << "The transformation " << nodeElementName << " has not been supported yet.");
1399        }
1400      } while (node.goToNextElement()) ;
1401      node.goToParentElement();
1402    }
1403  }
1404
1405  DEFINE_REF_FUNC(Axis,axis)
1406
1407   ///---------------------------------------------------------------
1408
1409} // namespace xios
Note: See TracBrowser for help on using the repository browser.