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

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

Various bug fixes on mask and zoom

+) Rearrange local index on the receiving side to be coherent global index
+) Include masking information in compress data (data_index) on the receiving side
+) Correct zoom to work in case there are several (not all) processes participating to write data

Test
+) On Curie
+) Simple test

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