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

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

Changes in case of different number of processes per secondary-server pool.

No incorrect behaviour had been found in the previous versions; this commit is just to play safe.

  • 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["reduce_axis"] = TRANS_REDUCE_AXIS_TO_AXIS;
54     m["extract_domain"] = TRANS_EXTRACT_DOMAIN_TO_AXIS;
55     m["temporal_splitting"] = TRANS_TEMPORAL_SPLITTING;
56     m["duplicate_scalar"] = TRANS_DUPLICATE_SCALAR_TO_AXIS;
57
58   }
59
60   ///---------------------------------------------------------------
61
62   const std::set<StdString> & CAxis::getRelFiles(void) const
63   {
64      return (this->relFiles);
65   }
66
67   bool CAxis::IsWritten(const StdString & filename) const
68   {
69      return (this->relFiles.find(filename) != this->relFiles.end());
70   }
71
72   bool CAxis::isWrittenCompressed(const StdString& filename) const
73   {
74      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
75   }
76
77   bool CAxis::isDistributed(void) const
78   {
79      bool distributed = (!this->begin.isEmpty() && !this->n.isEmpty() && (this->begin + this->n < this->n_glo)) ||
80             (!this->n.isEmpty() && (this->n != this->n_glo));
81      // A same stupid condition to make sure that if there is only one client, axis
82      // should be considered to be distributed. This should be a temporary solution     
83      distributed |= (1 == CContext::getCurrent()->client->clientSize);
84      return distributed;
85   }
86
87   /*!
88    * Test whether the data defined on the axis can be outputted in a compressed way.
89    *
90    * \return true if and only if a mask was defined for this axis
91    */
92   bool CAxis::isCompressible(void) const
93   {
94      return isCompressible_;
95   }
96
97   void CAxis::addRelFile(const StdString & filename)
98   {
99      this->relFiles.insert(filename);
100   }
101
102   void CAxis::addRelFileCompressed(const StdString& filename)
103   {
104      this->relFilesCompressed.insert(filename);
105   }
106
107   //----------------------------------------------------------------
108
109   /*!
110     Returns the number of indexes written by each server.
111     \return the number of indexes written by each server
112   */
113   int CAxis::getNumberWrittenIndexes(MPI_Comm writtenCom)
114   {
115     int writtenSize;
116     MPI_Comm_size(writtenCom, &writtenSize);
117     return numberWrittenIndexes_[writtenSize];
118   }
119
120   /*!
121     Returns the total number of indexes written by the servers.
122     \return the total number of indexes written by the servers
123   */
124   int CAxis::getTotalNumberWrittenIndexes(MPI_Comm writtenCom)
125   {
126     int writtenSize;
127     MPI_Comm_size(writtenCom, &writtenSize);
128     return totalNumberWrittenIndexes_[writtenSize];
129   }
130
131   /*!
132     Returns the offset of indexes written by each server.
133     \return the offset of indexes written by each server
134   */
135   int CAxis::getOffsetWrittenIndexes(MPI_Comm writtenCom)
136   {
137     int writtenSize;
138     MPI_Comm_size(writtenCom, &writtenSize);
139     return offsetWrittenIndexes_[writtenSize];
140   }
141
142   CArray<int, 1>& CAxis::getCompressedIndexToWriteOnServer(MPI_Comm writtenCom)
143   {
144     int writtenSize;
145     MPI_Comm_size(writtenCom, &writtenSize);
146     return compressedIndexToWriteOnServer[writtenSize];
147   }
148   //----------------------------------------------------------------
149
150   /*!
151    * Compute the minimum buffer size required to send the attributes to the server(s).
152    *
153    * \return A map associating the server rank with its minimum buffer size.
154    */
155   std::map<int, StdSize> CAxis::getAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= false*/)
156   {
157
158     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
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, nbServer);
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    if (nbIndexGlob==0) index.resize(nbIndexGlob) ;
1275    else index.resizeAndPreserve(nbIndexGlob);
1276
1277    int nbData = nbIndexGlob;
1278    CArray<int,1> nonCompressedData(nbData);
1279    nonCompressedData = -1;   
1280    mask.resize(nbData);
1281    if (hasValue)
1282      value.resize(nbData);
1283    if (hasBounds)
1284      bounds.resize(2,nbData);
1285    if (hasLabel)
1286      label.resize(nbData);
1287
1288    nbData = 0;
1289    for (idx = 0; idx < nbReceived; ++idx)
1290    {
1291      CArray<int,1>& indi = vec_indi[idx];
1292      CArray<int,1>& dataIndi = vec_dataInd[idx];
1293      CArray<bool,1>& maskIndi = vec_mask[idx];
1294      int nb = indi.numElements();
1295      for (int n = 0; n < nb; ++n)
1296      { 
1297        locInd = globalLocalIndexMap_[size_t(indi(n))];
1298
1299        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1300
1301        if (!mask(locInd)) // Only rewrite mask if it's not true
1302          mask(locInd) = maskIndi(n);
1303       
1304        if (hasValue)
1305          value(locInd) = vec_val[idx](n);
1306
1307        if (hasBounds)
1308        {
1309          bounds(0,locInd) = vec_bounds[idx](0,n);
1310          bounds(1,locInd) = vec_bounds[idx](1,n);
1311        }
1312
1313        if (hasLabel)
1314          label(locInd) = vec_label[idx](n);
1315      }
1316    }
1317   
1318    int nbCompressedData = 0; 
1319    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1320    {
1321      if (0 <= nonCompressedData(idx))
1322        ++nbCompressedData;       
1323    }
1324
1325    data_index.resize(nbCompressedData);
1326    nbCompressedData = 0;
1327    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1328    {
1329      if (0 <= nonCompressedData(idx))
1330      {
1331        data_index(nbCompressedData) = idx % n;
1332        ++nbCompressedData;       
1333      }
1334    }
1335
1336    data_begin.setValue(0);
1337  }
1338
1339
1340  /*!
1341    Compare two axis objects.
1342    They are equal if only if they have identical attributes as well as their values.
1343    Moreover, they must have the same transformations.
1344  \param [in] axis Compared axis
1345  \return result of the comparison
1346  */
1347  bool CAxis::isEqual(CAxis* obj)
1348  {
1349    vector<StdString> excludedAttr;
1350    excludedAttr.push_back("axis_ref");
1351
1352    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1353    if (!objEqual) return objEqual;
1354
1355    TransMapTypes thisTrans = this->getAllTransformations();
1356    TransMapTypes objTrans  = obj->getAllTransformations();
1357
1358    TransMapTypes::const_iterator it, itb, ite;
1359    std::vector<ETranformationType> thisTransType, objTransType;
1360    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1361      thisTransType.push_back(it->first);
1362    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1363      objTransType.push_back(it->first);
1364
1365    if (thisTransType.size() != objTransType.size()) return false;
1366    for (int idx = 0; idx < thisTransType.size(); ++idx)
1367      objEqual &= (thisTransType[idx] == objTransType[idx]);
1368
1369    return objEqual;
1370  }
1371
1372  /*
1373    Add transformation into axis. This function only servers for Fortran interface
1374    \param [in] transType transformation type
1375    \param [in] id identifier of the transformation object
1376  */
1377  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1378  {
1379    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1380    return transformationMap_.back().second;
1381  }
1382
1383  /*
1384    Check whether an axis has (spatial) transformation
1385  */
1386  bool CAxis::hasTransformation()
1387  {
1388    return (!transformationMap_.empty());
1389  }
1390
1391  /*
1392    Set transformation
1393    \param [in] axisTrans transformation to set
1394  */
1395  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1396  {
1397    transformationMap_ = axisTrans;
1398  }
1399
1400  /*
1401    Return all transformation held by the axis
1402    \return transformation the axis has
1403  */
1404  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1405  {
1406    return transformationMap_;
1407  }
1408
1409  /*
1410    Duplicate transformation of another axis
1411    \param [in] src axis whose transformations are copied
1412  */
1413  void CAxis::duplicateTransformation(CAxis* src)
1414  {
1415    if (src->hasTransformation())
1416    {
1417      this->setTransformations(src->getAllTransformations());
1418    }
1419  }
1420
1421  /*!
1422   * Go through the hierarchy to find the axis from which the transformations must be inherited
1423   */
1424  void CAxis::solveInheritanceTransformation()
1425  {
1426    if (hasTransformation() || !hasDirectAxisReference())
1427      return;
1428
1429    CAxis* axis = this;
1430    std::vector<CAxis*> refAxis;
1431    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1432    {
1433      refAxis.push_back(axis);
1434      axis = axis->getDirectAxisReference();
1435    }
1436
1437    if (axis->hasTransformation())
1438      for (size_t i = 0; i < refAxis.size(); ++i)
1439        refAxis[i]->setTransformations(axis->getAllTransformations());
1440  }
1441
1442  void CAxis::parse(xml::CXMLNode & node)
1443  {
1444    SuperClass::parse(node);
1445
1446    if (node.goToChildElement())
1447    {
1448      StdString nodeElementName;
1449      do
1450      {
1451        StdString nodeId("");
1452        if (node.getAttributes().end() != node.getAttributes().find("id"))
1453        { nodeId = node.getAttributes()["id"]; }
1454
1455        nodeElementName = node.getElementName();
1456        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1457        it = transformationMapList_.find(nodeElementName);
1458        if (ite != it)
1459        {
1460          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1461                                                                                                               nodeId,
1462                                                                                                               &node)));
1463        }
1464        else
1465        {
1466          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1467                << "The transformation " << nodeElementName << " has not been supported yet.");
1468        }
1469      } while (node.goToNextElement()) ;
1470      node.goToParentElement();
1471    }
1472  }
1473
1474  DEFINE_REF_FUNC(Axis,axis)
1475
1476   ///---------------------------------------------------------------
1477
1478} // namespace xios
Note: See TracBrowser for help on using the repository browser.