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

Last change on this file since 1258 was 1258, checked in by ymipsl, 7 years ago

Fix problem of axis distribution. When a grid is composed of a distributed axis and an non distributed axis on client side , on server side the first axis will be non distributed and second axis will be distributed. In this case, attributes (value, bounds, etc) was not sent in correct distribution.

YM

  • 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.8 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         computeConnectedClients(globalDim, orderPositionInGrid, distType);
457       else if (index.numElements() != n_glo) computeConnectedClients(globalDim, orderPositionInGrid,  CServerDistributionDescription::ROOT_DISTRIBUTION);
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
592      CServerDistributionDescription serverDescription(nGlobAxis, nbServer, distType);
593     
594      std::vector<int> serverZeroIndex;
595      serverZeroIndex = serverDescription.computeServerGlobalIndexInRange(std::make_pair<size_t,size_t>(indexBegin, indexEnd), 0);     
596
597      std::list<int> serverZeroIndexLeader;
598      std::list<int> serverZeroIndexNotLeader; 
599      CContextClient::computeLeader(client->clientRank, client->clientSize, serverZeroIndex.size(), serverZeroIndexLeader, serverZeroIndexNotLeader);
600      for (std::list<int>::iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
601        *it = serverZeroIndex[*it];
602
603      // Find out the connection between client and server side
604      CClientServerMapping* clientServerMap = new CClientServerMappingDistributed(serverDescription.getGlobalIndexRange(), client->intraComm);
605      clientServerMap->computeServerIndexMapping(globalIndex);
606      CClientServerMapping::GlobalIndexMap& globalIndexAxisOnServer = clientServerMap->getGlobalIndexOnServer();     
607
608
609      indSrv_[client].swap(globalIndexAxisOnServer);
610
611      if (distType==CServerDistributionDescription::ROOT_DISTRIBUTION)
612      {
613        for(int i=1; i<nbServer; ++i) indSrv_[client].insert(pair<int, vector<size_t> >(i,indSrv_[client][0]) ) ;
614        serverZeroIndexLeader.clear() ;
615      }
616         
617      CClientServerMapping::GlobalIndexMap::const_iterator it  = indSrv_[client].begin(),
618                                                           ite = indSrv_[client].end();
619
620      for (it = indSrv_[client].begin(); it != ite; ++it) connectedServerRank_[client].push_back(it->first);
621
622      for (std::list<int>::const_iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
623        connectedServerRank_[client].push_back(*it);
624
625       // Even if a client has no index, it must connect to at least one server and
626       // send an "empty" data to this server
627       if (connectedServerRank_[client].empty())
628        connectedServerRank_[client].push_back(client->clientRank % client->serverSize);
629
630      nbSenders[client] = CClientServerMapping::computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_[client]);
631
632      delete clientServerMap;
633    }
634  }
635
636  /*
637    Compute the index of data to write into file
638    (Different from the previous version, this version of XIOS allows data be written into file (classical role),
639    or transfered to another clients)
640  */
641  void CAxis::computeWrittenIndex()
642  { 
643    if (computedWrittenIndex_) return;
644    computedWrittenIndex_ = true;
645
646    CContext* context=CContext::getCurrent();     
647    CContextServer* server = context->server; 
648
649    // We describe the distribution of client (server) on which data are written
650    std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
651    nBegin[0]       = zoom_begin;
652    nSize[0]        = zoom_n;   
653    nBeginGlobal[0] = 0; 
654    nGlob[0]        = n_glo;
655    CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
656    const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
657
658    // Because all written data are local on a client,
659    // we need to compute the local index on the server from its corresponding global index
660    size_t nbWritten = 0, indGlo;     
661    boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
662                                                        ite = globalLocalIndexMap_.end(), it;         
663    CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
664                                     itSrve = writtenGlobalIndex.end(), itSrv; 
665    if (!zoomByIndex())
666    {   
667      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
668      {
669        indGlo = *itSrv;
670        if (ite != globalLocalIndexMap_.find(indGlo))
671        {         
672          ++nbWritten;
673        }                 
674      }
675
676      localIndexToWriteOnServer.resize(nbWritten);
677
678      nbWritten = 0;
679      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
680      {
681        indGlo = *itSrv;
682        if (ite != globalLocalIndexMap_.find(indGlo))
683        {
684          localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
685          ++nbWritten;
686        }                 
687      }
688    }
689    else
690    {
691      nbWritten = 0;
692      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
693                                                          ite = globalLocalIndexMap_.end(), it;
694      for (int i = 0; i < zoom_index.numElements(); ++i)
695      {
696         if (ite != globalLocalIndexMap_.find(zoom_index(i)))
697          ++nbWritten;
698      }
699
700      localIndexToWriteOnServer.resize(nbWritten);
701
702      nbWritten = 0;
703      for (int i = 0; i < zoom_index.numElements(); ++i)
704      {
705         if (ite != globalLocalIndexMap_.find(zoom_index(i)))
706         {
707           localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[zoom_index(i)];
708           ++nbWritten;
709         }
710      }
711    }
712
713    // if (isCompressible())
714    // {
715    //   nbWritten = 0;
716    //   boost::unordered_map<size_t,size_t> localGlobalIndexMap;
717    //   for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
718    //   {
719    //     indGlo = *itSrv;
720    //     if (ite != globalLocalIndexMap_.find(indGlo))
721    //     {
722    //       localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
723    //       ++nbWritten;
724    //     }                 
725    //   }
726
727    //   nbWritten = 0;
728    //   for (int idx = 0; idx < data_index.numElements(); ++idx)
729    //   {
730    //     if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
731    //     {
732    //       ++nbWritten;
733    //     }
734    //   }
735
736    //   compressedIndexToWriteOnServer.resize(nbWritten);
737    //   nbWritten = 0;
738    //   for (int idx = 0; idx < data_index.numElements(); ++idx)
739    //   {
740    //     if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
741    //     {
742    //       compressedIndexToWriteOnServer(nbWritten) = localGlobalIndexMap[data_index(idx)];
743    //       ++nbWritten;
744    //     }
745    //   }
746
747    //   numberWrittenIndexes_ = nbWritten;
748    //   if (isDistributed())
749    //   {
750             
751    //     MPI_Allreduce(&numberWrittenIndexes_, &totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
752    //     MPI_Scan(&numberWrittenIndexes_, &offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
753    //     offsetWrittenIndexes_ -= numberWrittenIndexes_;
754    //   }
755    //   else
756    //     totalNumberWrittenIndexes_ = numberWrittenIndexes_;
757    // }
758  }
759
760  void CAxis::computeWrittenCompressedIndex(MPI_Comm writtenComm)
761  {
762    int writtenCommSize;
763    MPI_Comm_size(writtenComm, &writtenCommSize);
764    if (compressedIndexToWriteOnServer.find(writtenCommSize) != compressedIndexToWriteOnServer.end())
765      return;
766
767    if (isCompressible())
768    {
769      size_t nbWritten = 0, indGlo;
770      CContext* context=CContext::getCurrent();     
771      CContextServer* server = context->server; 
772
773      // We describe the distribution of client (server) on which data are written
774      std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
775      nBegin[0]       = zoom_begin;
776      nSize[0]        = zoom_n;   
777      nBeginGlobal[0] = 0; 
778      nGlob[0]        = n_glo;
779      CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
780      const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
781      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
782                                                          ite = globalLocalIndexMap_.end(), it;   
783
784      CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
785                                       itSrve = writtenGlobalIndex.end(), itSrv;
786      boost::unordered_map<size_t,size_t> localGlobalIndexMap;
787      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
788      {
789        indGlo = *itSrv;
790        if (ite != globalLocalIndexMap_.find(indGlo))
791        {
792          localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
793          ++nbWritten;
794        }                 
795      }
796
797      nbWritten = 0;
798      for (int idx = 0; idx < data_index.numElements(); ++idx)
799      {
800        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
801        {
802          ++nbWritten;
803        }
804      }
805
806      compressedIndexToWriteOnServer[writtenCommSize].resize(nbWritten);
807      nbWritten = 0;
808      for (int idx = 0; idx < data_index.numElements(); ++idx)
809      {
810        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
811        {
812          compressedIndexToWriteOnServer[writtenCommSize](nbWritten) = localGlobalIndexMap[data_index(idx)];
813          ++nbWritten;
814        }
815      }
816
817      numberWrittenIndexes_[writtenCommSize] = nbWritten;
818      if (isDistributed())
819      {
820             
821        MPI_Allreduce(&numberWrittenIndexes_[writtenCommSize], &totalNumberWrittenIndexes_[writtenCommSize], 1, MPI_INT, MPI_SUM, writtenComm);
822        MPI_Scan(&numberWrittenIndexes_[writtenCommSize], &offsetWrittenIndexes_[writtenCommSize], 1, MPI_INT, MPI_SUM, writtenComm);
823        offsetWrittenIndexes_[writtenCommSize] -= numberWrittenIndexes_[writtenCommSize];
824      }
825      else
826        totalNumberWrittenIndexes_[writtenCommSize] = numberWrittenIndexes_[writtenCommSize];
827    }
828  }
829
830  /*!
831    Send distribution information from a group of client (client role) to another group of client (server role)
832    The distribution of a group of client (server role) is imposed by the group of client (client role)
833    \param [in] globalDim global dimension of grid containing this axis
834    \param [in] orderPositionInGrid the relative order of this axis in the grid (e.g grid composed of domain+axis -> orderPositionInGrid is 2)
835    \param [in] distType distribution type of the server. For now, we only have band distribution.
836  */
837  void CAxis::sendDistributionAttribute(const std::vector<int>& globalDim, int orderPositionInGrid,
838                                        CServerDistributionDescription::ServerDistributionType distType)
839  {
840    CContext* context = CContext::getCurrent();
841
842    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 0) : 1;
843    for (int i = 0; i < nbSrvPools; ++i)
844    {
845      CContextClient* contextClientTmp = (context->hasServer) ? context->clientPrimServer[i]
846                                                                         : context->client;
847      int nbServer = contextClientTmp->serverSize;
848
849      CServerDistributionDescription serverDescription(globalDim, nbServer);
850      serverDescription.computeServerDistribution();
851
852      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
853      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
854
855      CEventClient event(getType(),EVENT_ID_DISTRIBUTION_ATTRIBUTE);
856      if (contextClientTmp->isServerLeader())
857      {
858        std::list<CMessage> msgs;
859
860        const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
861        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
862        {
863          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
864          const int begin = serverIndexBegin[*itRank][orderPositionInGrid];
865          const int ni    = serverDimensionSizes[*itRank][orderPositionInGrid];
866          const int end   = begin + ni - 1;         
867
868          msgs.push_back(CMessage());
869          CMessage& msg = msgs.back();
870          msg << this->getId();
871          msg << ni << begin << end;         
872          msg << isCompressible_;                   
873
874          event.push(*itRank,1,msg);
875        }
876        contextClientTmp->sendEvent(event);
877      }
878      else contextClientTmp->sendEvent(event);
879    }
880  }
881
882  /*
883    Receive distribution attribute from another client
884    \param [in] event event containing data of these attributes
885  */
886  void CAxis::recvDistributionAttribute(CEventServer& event)
887  {
888    CBufferIn* buffer = event.subEvents.begin()->buffer;
889    string axisId;
890    *buffer >> axisId;
891    get(axisId)->recvDistributionAttribute(*buffer);
892  }
893
894  /*
895    Receive distribution attribute from another client
896    \param [in] buffer buffer containing data of these attributes
897  */
898  void CAxis::recvDistributionAttribute(CBufferIn& buffer)
899  {
900    int ni_srv, begin_srv, end_srv;
901    int global_zoom_end, zoom_end;
902    bool zoomIndex = zoomByIndex();
903   
904    std::vector<int> zoom_index_tmp;
905    std::vector<int>::iterator itZoomBegin, itZoomEnd, itZoom;
906
907    buffer >> ni_srv >> begin_srv >> end_srv;   
908    buffer >> isCompressible_;           
909
910    // Set up new local size of axis on the receiving clients
911    n.setValue(ni_srv);
912    begin.setValue(begin_srv);
913
914    // If we have zoom by index then process it
915    if (zoomIndex)
916    {
917      zoom_index_tmp.resize(global_zoom_index.numElements());
918      std::copy(global_zoom_index.begin(), global_zoom_index.end(), zoom_index_tmp.begin());
919      std::sort(zoom_index_tmp.begin(), zoom_index_tmp.end());
920      itZoomBegin = std::lower_bound(zoom_index_tmp.begin(), zoom_index_tmp.end(), begin_srv);
921      itZoomEnd   = std::upper_bound(zoom_index_tmp.begin(), zoom_index_tmp.end(), end_srv);     
922      int sz = std::distance(itZoomBegin, itZoomEnd);
923      zoom_index.resize(sz);
924      itZoom = itZoomBegin;
925      for (int i = 0; i < sz; ++i, ++itZoom)
926      {
927        zoom_index(i) = *(itZoom);
928      }
929    }
930
931    global_zoom_begin = zoomIndex ? 0 : global_zoom_begin ;
932    global_zoom_n     = zoomIndex ? zoom_index_tmp.size() : global_zoom_n;
933    global_zoom_end   = global_zoom_begin + global_zoom_n - 1;
934
935    zoom_begin = zoomIndex ? std::distance(itZoomBegin, zoom_index_tmp.begin())
936                           : global_zoom_begin > begin_srv ? global_zoom_begin : begin_srv ;
937    zoom_end   = zoomIndex ? std::distance(zoom_index_tmp.begin(), itZoomEnd) - 1 
938                           : global_zoom_end < end_srv ? global_zoom_end : end_srv ;
939    zoom_n     = zoom_end - zoom_begin + 1;
940
941    if (zoom_n<=0)
942    {
943      zoom_n = 0; zoom_begin=global_zoom_begin; //0; zoom_begin = 0;
944    }
945
946    if (n_glo == n)
947    {
948      zoom_begin = zoomIndex ? std::distance(itZoomBegin, zoom_index_tmp.begin())
949                             : global_zoom_begin;     
950      zoom_n     = zoomIndex ? zoom_index_tmp.size() : global_zoom_n;
951    }
952  }
953
954  /*
955    Send attributes of axis from a group of client to other group of clients/servers
956    on supposing that these attributes are not distributed among the sending group
957    In the future, if new attributes are added, they should also be processed in this function
958  */
959  void CAxis::sendNonDistributedAttributes()
960  {
961    CContext* context = CContext::getCurrent();
962
963    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 1) : 1;
964    for (int p = 0; p < nbSrvPools; ++p)
965    {
966      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
967
968      CEventClient event(getType(), EVENT_ID_NON_DISTRIBUTED_ATTRIBUTES);
969      size_t nbIndex = index.numElements();
970      size_t nbDataIndex = 0;
971
972      for (int idx = 0; idx < data_index.numElements(); ++idx)
973      {
974        int ind = data_index(idx);
975        if (ind >= 0 && ind < nbIndex) ++nbDataIndex;
976      }
977
978      CArray<int,1> dataIndex(nbDataIndex);
979      nbDataIndex = 0;
980      for (int idx = 0; idx < data_index.numElements(); ++idx)
981      {
982        int ind = data_index(idx);
983        if (ind >= 0 && ind < nbIndex)
984        {
985          dataIndex(nbDataIndex) = ind;
986          ++nbDataIndex;
987        }
988      }
989
990      if (client->isServerLeader())
991      {
992        std::list<CMessage> msgs;
993
994        const std::list<int>& ranks = client->getRanksServerLeader();
995        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
996        {
997          msgs.push_back(CMessage());
998          CMessage& msg = msgs.back();
999          msg << this->getId();
1000          msg << index.getValue() << dataIndex << mask.getValue();
1001          msg << hasValue;
1002          if (hasValue) msg << value.getValue();
1003          msg << hasBounds;
1004          if (hasBounds) msg << bounds.getValue();
1005          msg << hasLabel;
1006          if (hasLabel) msg << label.getValue();
1007
1008          event.push(*itRank, 1, msg);
1009        }
1010        client->sendEvent(event);
1011      }
1012      else client->sendEvent(event);
1013    }
1014  }
1015
1016  /*
1017    Receive the non-distributed attributes from another group of clients
1018    \param [in] event event containing data of these attributes
1019  */
1020  void CAxis::recvNonDistributedAttributes(CEventServer& event)
1021  {
1022    list<CEventServer::SSubEvent>::iterator it;
1023    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1024    {
1025      CBufferIn* buffer = it->buffer;
1026      string axisId;
1027      *buffer >> axisId;
1028      get(axisId)->recvNonDistributedAttributes(it->rank, *buffer);
1029    }
1030  }
1031
1032  /*
1033    Receive the non-distributed attributes from another group of clients
1034    \param [in] rank rank of the sender
1035    \param [in] buffer buffer containing data sent from the sender
1036  */
1037  void CAxis::recvNonDistributedAttributes(int rank, CBufferIn& buffer)
1038  { 
1039    CArray<int,1> tmp_index, tmp_data_index, tmp_zoom_index;
1040    CArray<bool,1> tmp_mask;
1041    CArray<double,1> tmp_val;
1042    CArray<double,2> tmp_bnds;
1043    CArray<string,1> tmp_label;
1044
1045    buffer >> tmp_index;
1046    index.reference(tmp_index);
1047    buffer >> tmp_data_index;
1048    data_index.reference(tmp_data_index);
1049    buffer >> tmp_mask;
1050    mask.reference(tmp_mask);
1051
1052    buffer >> hasValue;
1053    if (hasValue)
1054    {
1055      buffer >> tmp_val;
1056      value.reference(tmp_val);
1057    }
1058
1059    buffer >> hasBounds;
1060    if (hasBounds)
1061    {
1062      buffer >> tmp_bnds;
1063      bounds.reference(tmp_bnds);
1064    }
1065
1066    buffer >> hasLabel;
1067    if (hasLabel)
1068    {
1069      buffer >> tmp_label;
1070      label.reference(tmp_label);
1071    }
1072
1073    // Some value should be reset here
1074    data_begin.setValue(0);
1075    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1076    for (int idx = 0; idx < index.numElements(); ++idx) globalLocalIndexMap_[idx] = index(idx);
1077  }
1078
1079  /*
1080    Send attributes of axis from a group of client to other group of clients/servers
1081    on supposing that these attributes are distributed among the clients of the sending group
1082    In the future, if new attributes are added, they should also be processed in this function
1083  */
1084  void CAxis::sendDistributedAttributes(void)
1085  {
1086    int ns, n, i, j, ind, nv, idx;
1087    CContext* context = CContext::getCurrent();
1088   
1089    int nbSrvPools = (context->hasServer) ? (context->hasClient ? context->clientPrimServer.size() : 1) : 1;
1090    for (int p = 0; p < nbSrvPools; ++p)
1091    {
1092      CContextClient* client = (0 != context->clientPrimServer.size()) ? context->clientPrimServer[p] : context->client;
1093
1094      CEventClient eventData(getType(), EVENT_ID_DISTRIBUTED_ATTRIBUTES);
1095
1096      list<CMessage> listData;
1097      list<CArray<int,1> > list_indi, list_dataInd, list_zoomInd;
1098      list<CArray<bool,1> > list_mask;
1099      list<CArray<double,1> > list_val;
1100      list<CArray<double,2> > list_bounds;
1101      list<CArray<string,1> > list_label;
1102
1103      int nbIndex = index.numElements();
1104      CArray<int,1> dataIndex(nbIndex);
1105      dataIndex = -1;
1106      for (idx = 0; idx < data_index.numElements(); ++idx)
1107      {
1108        if (0 <= data_index(idx) && data_index(idx) < nbIndex)
1109          dataIndex(idx) = 1;
1110      }
1111
1112      boost::unordered_map<int, std::vector<size_t> >::const_iterator it, iteMap;
1113      iteMap = indSrv_[client].end();
1114      for (int k = 0; k < connectedServerRank_[client].size(); ++k)
1115      {
1116        int nbData = 0;
1117        int rank = connectedServerRank_[client][k];       
1118        it = indSrv_[client].find(rank);
1119        if (iteMap != it)
1120          nbData = it->second.size();
1121
1122        list_indi.push_back(CArray<int,1>(nbData));
1123        list_dataInd.push_back(CArray<int,1>(nbData));       
1124        list_mask.push_back(CArray<bool,1>(nbData));
1125
1126        if (hasValue)
1127          list_val.push_back(CArray<double,1>(nbData));
1128
1129        if (hasBounds)       
1130          list_bounds.push_back(CArray<double,2>(2,nbData));
1131
1132        if (hasLabel)
1133          list_label.push_back(CArray<string,1>(nbData));
1134
1135        CArray<int,1>& indi = list_indi.back();
1136        CArray<int,1>& dataIndi = list_dataInd.back();       
1137        CArray<bool,1>& maskIndi = list_mask.back();
1138
1139        for (n = 0; n < nbData; ++n)
1140        {
1141          idx = static_cast<int>(it->second[n]);
1142          indi(n) = idx;
1143
1144          ind = globalLocalIndexMap_[idx];
1145          dataIndi(n) = dataIndex(ind);
1146          maskIndi(n) = mask(ind);
1147
1148          if (hasValue)
1149          {
1150            CArray<double,1>& val = list_val.back();
1151            val(n) = value(ind);
1152          }
1153
1154          if (hasBounds)
1155          {
1156            CArray<double,2>& boundsVal = list_bounds.back();
1157            boundsVal(0, n) = bounds(0,n);
1158            boundsVal(1, n) = bounds(1,n);
1159          }
1160
1161          if (hasLabel)
1162          {
1163            CArray<string,1>& labelVal = list_label.back();
1164            labelVal(n) = label(ind); 
1165          }
1166        }
1167
1168        listData.push_back(CMessage());
1169        listData.back() << this->getId()
1170                        << list_indi.back() << list_dataInd.back() << list_mask.back();
1171
1172        listData.back() << hasValue;
1173        if (hasValue)
1174          listData.back() << list_val.back();
1175
1176        listData.back() << hasBounds;
1177        if (hasBounds)
1178          listData.back() << list_bounds.back();
1179
1180        listData.back() << hasLabel;
1181        if (hasLabel)
1182          listData.back() << list_label.back();
1183
1184        eventData.push(rank, nbSenders[client][rank], listData.back());
1185      }
1186
1187      client->sendEvent(eventData);
1188    }
1189  }
1190
1191  /*
1192    Receive the distributed attributes from another group of clients
1193    \param [in] event event containing data of these attributes
1194  */
1195  void CAxis::recvDistributedAttributes(CEventServer& event)
1196  {
1197    string axisId;
1198    vector<int> ranks;
1199    vector<CBufferIn*> buffers;
1200
1201    list<CEventServer::SSubEvent>::iterator it;
1202    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1203    {
1204      ranks.push_back(it->rank);
1205      CBufferIn* buffer = it->buffer;
1206      *buffer >> axisId;
1207      buffers.push_back(buffer);
1208    }
1209    get(axisId)->recvDistributedAttributes(ranks, buffers);
1210  }
1211
1212  /*
1213    Receive the non-distributed attributes from another group of clients
1214    \param [in] ranks rank of the sender
1215    \param [in] buffers buffer containing data sent from the sender
1216  */
1217  void CAxis::recvDistributedAttributes(vector<int>& ranks, vector<CBufferIn*> buffers)
1218  {
1219    int nbReceived = ranks.size(), idx, ind, gloInd, locInd;
1220    vector<CArray<int,1> > vec_indi(nbReceived), vec_dataInd(nbReceived), vec_zoomInd(nbReceived);   
1221    vector<CArray<bool,1> > vec_mask(nbReceived);
1222    vector<CArray<double,1> > vec_val(nbReceived);
1223    vector<CArray<double,2> > vec_bounds(nbReceived);
1224    vector<CArray<string,1> > vec_label(nbReceived);
1225   
1226    for (idx = 0; idx < nbReceived; ++idx)
1227    {     
1228      CBufferIn& buffer = *buffers[idx];
1229      buffer >> vec_indi[idx];
1230      buffer >> vec_dataInd[idx];     
1231      buffer >> vec_mask[idx];
1232
1233      buffer >> hasValue;
1234      if (hasValue)
1235        buffer >> vec_val[idx];
1236
1237      buffer >> hasBounds;
1238      if (hasBounds)
1239        buffer >> vec_bounds[idx];
1240
1241      buffer >> hasLabel;
1242      if (hasLabel)
1243        buffer >> vec_label[idx]; 
1244    }
1245
1246    // Estimate size of index array
1247    int nbIndexGlob = 0;
1248    for (idx = 0; idx < nbReceived; ++idx)
1249    {
1250      nbIndexGlob += vec_indi[idx].numElements();
1251    }
1252
1253    // Recompute global index
1254    // Take account of the overlapped index
1255    index.resize(nbIndexGlob);
1256    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1257    nbIndexGlob = 0;
1258    for (idx = 0; idx < nbReceived; ++idx)
1259    {
1260      CArray<int,1>& tmp = vec_indi[idx];
1261      for (ind = 0; ind < tmp.numElements(); ++ind)
1262      {
1263         gloInd = tmp(ind);
1264         if (0 == globalLocalIndexMap_.count(gloInd))
1265         {
1266           index(nbIndexGlob) = gloInd % n_glo;           
1267           globalLocalIndexMap_[gloInd] = nbIndexGlob; 
1268           ++nbIndexGlob;
1269         } 
1270      } 
1271    }
1272
1273    // Resize index to its real size
1274    index.resizeAndPreserve(nbIndexGlob);
1275
1276    int nbData = nbIndexGlob;
1277    CArray<int,1> nonCompressedData(nbData);
1278    nonCompressedData = -1;   
1279    mask.resize(nbData);
1280    if (hasValue)
1281      value.resize(nbData);
1282    if (hasBounds)
1283      bounds.resize(2,nbData);
1284    if (hasLabel)
1285      label.resize(nbData);
1286
1287    nbData = 0;
1288    for (idx = 0; idx < nbReceived; ++idx)
1289    {
1290      CArray<int,1>& indi = vec_indi[idx];
1291      CArray<int,1>& dataIndi = vec_dataInd[idx];
1292      CArray<bool,1>& maskIndi = vec_mask[idx];
1293      int nb = indi.numElements();
1294      for (int n = 0; n < nb; ++n)
1295      { 
1296        locInd = globalLocalIndexMap_[size_t(indi(n))];
1297
1298        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1299
1300        if (!mask(locInd)) // Only rewrite mask if it's not true
1301          mask(locInd) = maskIndi(n);
1302       
1303        if (hasValue)
1304          value(locInd) = vec_val[idx](n);
1305
1306        if (hasBounds)
1307        {
1308          bounds(0,locInd) = vec_bounds[idx](0,n);
1309          bounds(1,locInd) = vec_bounds[idx](1,n);
1310        }
1311
1312        if (hasLabel)
1313          label(locInd) = vec_label[idx](n);
1314      }
1315    }
1316   
1317    int nbCompressedData = 0; 
1318    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1319    {
1320      if (0 <= nonCompressedData(idx))
1321        ++nbCompressedData;       
1322    }
1323
1324    data_index.resize(nbCompressedData);
1325    nbCompressedData = 0;
1326    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1327    {
1328      if (0 <= nonCompressedData(idx))
1329      {
1330        data_index(nbCompressedData) = idx % n;
1331        ++nbCompressedData;       
1332      }
1333    }
1334
1335    data_begin.setValue(0);
1336  }
1337
1338
1339  /*!
1340    Compare two axis objects.
1341    They are equal if only if they have identical attributes as well as their values.
1342    Moreover, they must have the same transformations.
1343  \param [in] axis Compared axis
1344  \return result of the comparison
1345  */
1346  bool CAxis::isEqual(CAxis* obj)
1347  {
1348    vector<StdString> excludedAttr;
1349    excludedAttr.push_back("axis_ref");
1350
1351    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1352    if (!objEqual) return objEqual;
1353
1354    TransMapTypes thisTrans = this->getAllTransformations();
1355    TransMapTypes objTrans  = obj->getAllTransformations();
1356
1357    TransMapTypes::const_iterator it, itb, ite;
1358    std::vector<ETranformationType> thisTransType, objTransType;
1359    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1360      thisTransType.push_back(it->first);
1361    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1362      objTransType.push_back(it->first);
1363
1364    if (thisTransType.size() != objTransType.size()) return false;
1365    for (int idx = 0; idx < thisTransType.size(); ++idx)
1366      objEqual &= (thisTransType[idx] == objTransType[idx]);
1367
1368    return objEqual;
1369  }
1370
1371  /*
1372    Add transformation into axis. This function only servers for Fortran interface
1373    \param [in] transType transformation type
1374    \param [in] id identifier of the transformation object
1375  */
1376  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1377  {
1378    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1379    return transformationMap_.back().second;
1380  }
1381
1382  /*
1383    Check whether an axis has (spatial) transformation
1384  */
1385  bool CAxis::hasTransformation()
1386  {
1387    return (!transformationMap_.empty());
1388  }
1389
1390  /*
1391    Set transformation
1392    \param [in] axisTrans transformation to set
1393  */
1394  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1395  {
1396    transformationMap_ = axisTrans;
1397  }
1398
1399  /*
1400    Return all transformation held by the axis
1401    \return transformation the axis has
1402  */
1403  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1404  {
1405    return transformationMap_;
1406  }
1407
1408  /*
1409    Duplicate transformation of another axis
1410    \param [in] src axis whose transformations are copied
1411  */
1412  void CAxis::duplicateTransformation(CAxis* src)
1413  {
1414    if (src->hasTransformation())
1415    {
1416      this->setTransformations(src->getAllTransformations());
1417    }
1418  }
1419
1420  /*!
1421   * Go through the hierarchy to find the axis from which the transformations must be inherited
1422   */
1423  void CAxis::solveInheritanceTransformation()
1424  {
1425    if (hasTransformation() || !hasDirectAxisReference())
1426      return;
1427
1428    CAxis* axis = this;
1429    std::vector<CAxis*> refAxis;
1430    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1431    {
1432      refAxis.push_back(axis);
1433      axis = axis->getDirectAxisReference();
1434    }
1435
1436    if (axis->hasTransformation())
1437      for (size_t i = 0; i < refAxis.size(); ++i)
1438        refAxis[i]->setTransformations(axis->getAllTransformations());
1439  }
1440
1441  void CAxis::parse(xml::CXMLNode & node)
1442  {
1443    SuperClass::parse(node);
1444
1445    if (node.goToChildElement())
1446    {
1447      StdString nodeElementName;
1448      do
1449      {
1450        StdString nodeId("");
1451        if (node.getAttributes().end() != node.getAttributes().find("id"))
1452        { nodeId = node.getAttributes()["id"]; }
1453
1454        nodeElementName = node.getElementName();
1455        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1456        it = transformationMapList_.find(nodeElementName);
1457        if (ite != it)
1458        {
1459          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1460                                                                                                               nodeId,
1461                                                                                                               &node)));
1462        }
1463        else
1464        {
1465          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1466                << "The transformation " << nodeElementName << " has not been supported yet.");
1467        }
1468      } while (node.goToNextElement()) ;
1469      node.goToParentElement();
1470    }
1471  }
1472
1473  DEFINE_REF_FUNC(Axis,axis)
1474
1475   ///---------------------------------------------------------------
1476
1477} // namespace xios
Note: See TracBrowser for help on using the repository browser.