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

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

Bug fix : Assigned context client to grid/axis/domain was not in same order for each process, causing synchronisation problems.

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