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

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

Exception handling on trunk.

To activate it, compilation flag -DXIOS_EXCEPTION should be added.

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