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

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

Fixing a bug on axis zoom that crawled in with r1559.

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