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

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

implement diurnal cycle transformation taken as a grid tranformation : scalar -> axis

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