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

Last change on this file since 1416 was 1416, checked in by ymipsl, 6 years ago

Bug fix when writing axis coordinate in some specific cases.

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