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

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

Bug fix on server side when receiving a distributed axis with zoom index.

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.6 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  }
1096
1097  /*
1098    Send attributes of axis from a group of client to other group of clients/servers
1099    on supposing that these attributes are distributed among the clients of the sending group
1100    In the future, if new attributes are added, they should also be processed in this function
1101  */
1102  void CAxis::sendDistributedAttributes(void)
1103  {
1104    int ns, n, i, j, ind, nv, idx;
1105    std::list<CContextClient*>::iterator it;
1106
1107    for (it=clients.begin(); it!=clients.end(); ++it)
1108    {
1109      CContextClient* client = *it;
1110      int nbServer = client->serverSize;
1111
1112      CEventClient eventData(getType(), EVENT_ID_DISTRIBUTED_ATTRIBUTES);
1113
1114      list<CMessage> listData;
1115      list<CArray<int,1> > list_indi, list_dataInd, list_zoomInd;
1116      list<CArray<bool,1> > list_mask;
1117      list<CArray<double,1> > list_val;
1118      list<CArray<double,2> > list_bounds;
1119      list<CArray<string,1> > list_label;
1120
1121      int nbIndex = index.numElements();
1122      CArray<int,1> dataIndex(nbIndex);
1123      dataIndex = -1;
1124      for (idx = 0; idx < data_index.numElements(); ++idx)
1125      {
1126        if (0 <= data_index(idx) && data_index(idx) < nbIndex)
1127          dataIndex(idx) = 1;
1128      }
1129
1130      boost::unordered_map<int, std::vector<size_t> >::const_iterator it, iteMap;
1131      iteMap = indSrv_[nbServer].end();
1132      for (int k = 0; k < connectedServerRank_[nbServer].size(); ++k)
1133      {
1134        int nbData = 0;
1135        int rank = connectedServerRank_[nbServer][k];
1136        it = indSrv_[nbServer].find(rank);
1137        if (iteMap != it)
1138          nbData = it->second.size();
1139
1140        list_indi.push_back(CArray<int,1>(nbData));
1141        list_dataInd.push_back(CArray<int,1>(nbData));       
1142        list_mask.push_back(CArray<bool,1>(nbData));
1143
1144        if (hasValue)
1145          list_val.push_back(CArray<double,1>(nbData));
1146
1147        if (hasBounds)       
1148          list_bounds.push_back(CArray<double,2>(2,nbData));
1149
1150        if (hasLabel)
1151          list_label.push_back(CArray<string,1>(nbData));
1152
1153        CArray<int,1>& indi = list_indi.back();
1154        CArray<int,1>& dataIndi = list_dataInd.back();       
1155        CArray<bool,1>& maskIndi = list_mask.back();
1156
1157        for (n = 0; n < nbData; ++n)
1158        {
1159          idx = static_cast<int>(it->second[n]);
1160          indi(n) = idx;
1161
1162          ind = globalLocalIndexMap_[idx];
1163          dataIndi(n) = dataIndex(ind);
1164          maskIndi(n) = mask(ind);
1165
1166          if (hasValue)
1167          {
1168            CArray<double,1>& val = list_val.back();
1169            val(n) = value(ind);
1170          }
1171
1172          if (hasBounds)
1173          {
1174            CArray<double,2>& boundsVal = list_bounds.back();
1175            boundsVal(0, n) = bounds(0,ind);
1176            boundsVal(1, n) = bounds(1,ind);
1177          }
1178
1179          if (hasLabel)
1180          {
1181            CArray<string,1>& labelVal = list_label.back();
1182            labelVal(n) = label(ind); 
1183          }
1184        }
1185
1186        listData.push_back(CMessage());
1187        listData.back() << this->getId()
1188                        << list_indi.back() << list_dataInd.back() << list_mask.back();
1189
1190        listData.back() << hasValue;
1191        if (hasValue)
1192          listData.back() << list_val.back();
1193
1194        listData.back() << hasBounds;
1195        if (hasBounds)
1196          listData.back() << list_bounds.back();
1197
1198        listData.back() << hasLabel;
1199        if (hasLabel)
1200          listData.back() << list_label.back();
1201
1202        eventData.push(rank, nbSenders[nbServer][rank], listData.back());
1203      }
1204
1205      client->sendEvent(eventData);
1206    }
1207  }
1208
1209  /*
1210    Receive the distributed attributes from another group of clients
1211    \param [in] event event containing data of these attributes
1212  */
1213  void CAxis::recvDistributedAttributes(CEventServer& event)
1214  {
1215    string axisId;
1216    vector<int> ranks;
1217    vector<CBufferIn*> buffers;
1218
1219    list<CEventServer::SSubEvent>::iterator it;
1220    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1221    {
1222      ranks.push_back(it->rank);
1223      CBufferIn* buffer = it->buffer;
1224      *buffer >> axisId;
1225      buffers.push_back(buffer);
1226    }
1227    get(axisId)->recvDistributedAttributes(ranks, buffers);
1228  }
1229
1230  /*
1231    Receive the non-distributed attributes from another group of clients
1232    \param [in] ranks rank of the sender
1233    \param [in] buffers buffer containing data sent from the sender
1234  */
1235  void CAxis::recvDistributedAttributes(vector<int>& ranks, vector<CBufferIn*> buffers)
1236  {
1237    int nbReceived = ranks.size(), idx, ind, gloInd, locInd;
1238    vector<CArray<int,1> > vec_indi(nbReceived), vec_dataInd(nbReceived), vec_zoomInd(nbReceived);   
1239    vector<CArray<bool,1> > vec_mask(nbReceived);
1240    vector<CArray<double,1> > vec_val(nbReceived);
1241    vector<CArray<double,2> > vec_bounds(nbReceived);
1242    vector<CArray<string,1> > vec_label(nbReceived);
1243   
1244    for (idx = 0; idx < nbReceived; ++idx)
1245    {     
1246      CBufferIn& buffer = *buffers[idx];
1247      buffer >> vec_indi[idx];
1248      buffer >> vec_dataInd[idx];     
1249      buffer >> vec_mask[idx];
1250
1251      buffer >> hasValue;
1252      if (hasValue)
1253        buffer >> vec_val[idx];
1254
1255      buffer >> hasBounds;
1256      if (hasBounds)
1257        buffer >> vec_bounds[idx];
1258
1259      buffer >> hasLabel;
1260      if (hasLabel)
1261        buffer >> vec_label[idx]; 
1262    }
1263
1264    // Estimate size of index array
1265    int nbIndexGlob = 0;
1266    for (idx = 0; idx < nbReceived; ++idx)
1267    {
1268      nbIndexGlob += vec_indi[idx].numElements();
1269    }
1270
1271    // Recompute global index
1272    // Take account of the overlapped index
1273    index.resize(nbIndexGlob);
1274    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1275    nbIndexGlob = 0;
1276    for (idx = 0; idx < nbReceived; ++idx)
1277    {
1278      CArray<int,1>& tmp = vec_indi[idx];
1279      for (ind = 0; ind < tmp.numElements(); ++ind)
1280      {
1281         gloInd = tmp(ind);
1282         if (0 == globalLocalIndexMap_.count(gloInd))
1283         {
1284           index(nbIndexGlob) = gloInd % n_glo;           
1285           globalLocalIndexMap_[gloInd] = nbIndexGlob; 
1286           ++nbIndexGlob;
1287         } 
1288      } 
1289    }
1290
1291    // Resize index to its real size
1292    if (nbIndexGlob==0) index.resize(nbIndexGlob) ;
1293    else index.resizeAndPreserve(nbIndexGlob);
1294
1295    int nbData = nbIndexGlob;
1296    CArray<int,1> nonCompressedData(nbData);
1297    nonCompressedData = -1;   
1298    mask.resize(nbData);
1299    if (hasValue)
1300      value.resize(nbData);
1301    if (hasBounds)
1302      bounds.resize(2,nbData);
1303    if (hasLabel)
1304      label.resize(nbData);
1305
1306    nbData = 0;
1307    for (idx = 0; idx < nbReceived; ++idx)
1308    {
1309      CArray<int,1>& indi = vec_indi[idx];
1310      CArray<int,1>& dataIndi = vec_dataInd[idx];
1311      CArray<bool,1>& maskIndi = vec_mask[idx];
1312      int nb = indi.numElements();
1313      for (int n = 0; n < nb; ++n)
1314      { 
1315        locInd = globalLocalIndexMap_[size_t(indi(n))];
1316
1317        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1318
1319        if (!mask(locInd)) // Only rewrite mask if it's not true
1320          mask(locInd) = maskIndi(n);
1321       
1322        if (hasValue)
1323          value(locInd) = vec_val[idx](n);
1324
1325        if (hasBounds)
1326        {
1327          bounds(0,locInd) = vec_bounds[idx](0,n);
1328          bounds(1,locInd) = vec_bounds[idx](1,n);
1329        }
1330
1331        if (hasLabel)
1332          label(locInd) = vec_label[idx](n);
1333      }
1334    }
1335   
1336    int nbCompressedData = 0; 
1337    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1338    {
1339      if (0 <= nonCompressedData(idx))
1340        ++nbCompressedData;       
1341    }
1342
1343    data_index.resize(nbCompressedData);
1344    nbCompressedData = 0;
1345    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1346    {
1347      if (0 <= nonCompressedData(idx))
1348      {
1349        data_index(nbCompressedData) = idx % n;
1350        ++nbCompressedData;       
1351      }
1352    }
1353
1354    data_begin.setValue(0);
1355  }
1356
1357
1358  /*!
1359    Compare two axis objects.
1360    They are equal if only if they have identical attributes as well as their values.
1361    Moreover, they must have the same transformations.
1362  \param [in] axis Compared axis
1363  \return result of the comparison
1364  */
1365  bool CAxis::isEqual(CAxis* obj)
1366  {
1367    vector<StdString> excludedAttr;
1368    excludedAttr.push_back("axis_ref");
1369
1370    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1371    if (!objEqual) return objEqual;
1372
1373    TransMapTypes thisTrans = this->getAllTransformations();
1374    TransMapTypes objTrans  = obj->getAllTransformations();
1375
1376    TransMapTypes::const_iterator it, itb, ite;
1377    std::vector<ETranformationType> thisTransType, objTransType;
1378    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1379      thisTransType.push_back(it->first);
1380    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1381      objTransType.push_back(it->first);
1382
1383    if (thisTransType.size() != objTransType.size()) return false;
1384    for (int idx = 0; idx < thisTransType.size(); ++idx)
1385      objEqual &= (thisTransType[idx] == objTransType[idx]);
1386
1387    return objEqual;
1388  }
1389
1390  /*
1391    Add transformation into axis. This function only servers for Fortran interface
1392    \param [in] transType transformation type
1393    \param [in] id identifier of the transformation object
1394  */
1395  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1396  {
1397    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1398    return transformationMap_.back().second;
1399  }
1400
1401  /*
1402    Check whether an axis has (spatial) transformation
1403  */
1404  bool CAxis::hasTransformation()
1405  {
1406    return (!transformationMap_.empty());
1407  }
1408
1409  /*
1410    Set transformation
1411    \param [in] axisTrans transformation to set
1412  */
1413  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1414  {
1415    transformationMap_ = axisTrans;
1416  }
1417
1418  /*
1419    Return all transformation held by the axis
1420    \return transformation the axis has
1421  */
1422  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1423  {
1424    return transformationMap_;
1425  }
1426
1427  /*
1428    Duplicate transformation of another axis
1429    \param [in] src axis whose transformations are copied
1430  */
1431  void CAxis::duplicateTransformation(CAxis* src)
1432  {
1433    if (src->hasTransformation())
1434    {
1435      this->setTransformations(src->getAllTransformations());
1436    }
1437  }
1438
1439  /*!
1440   * Go through the hierarchy to find the axis from which the transformations must be inherited
1441   */
1442  void CAxis::solveInheritanceTransformation()
1443  {
1444    if (hasTransformation() || !hasDirectAxisReference())
1445      return;
1446
1447    CAxis* axis = this;
1448    std::vector<CAxis*> refAxis;
1449    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1450    {
1451      refAxis.push_back(axis);
1452      axis = axis->getDirectAxisReference();
1453    }
1454
1455    if (axis->hasTransformation())
1456      for (size_t i = 0; i < refAxis.size(); ++i)
1457        refAxis[i]->setTransformations(axis->getAllTransformations());
1458  }
1459
1460  void CAxis::setContextClient(CContextClient* contextClient)
1461  {
1462    if (clientsSet.find(contextClient)==clientsSet.end())
1463    {
1464      clients.push_back(contextClient) ;
1465      clientsSet.insert(contextClient);
1466    }
1467}
1468
1469  void CAxis::parse(xml::CXMLNode & node)
1470  {
1471    SuperClass::parse(node);
1472
1473    if (node.goToChildElement())
1474    {
1475      StdString nodeElementName;
1476      do
1477      {
1478        StdString nodeId("");
1479        if (node.getAttributes().end() != node.getAttributes().find("id"))
1480        { nodeId = node.getAttributes()["id"]; }
1481
1482        nodeElementName = node.getElementName();
1483        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1484        it = transformationMapList_.find(nodeElementName);
1485        if (ite != it)
1486        {
1487          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1488                                                                                                               nodeId,
1489                                                                                                               &node)));
1490        }
1491        else
1492        {
1493          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1494                << "The transformation " << nodeElementName << " has not been supported yet.");
1495        }
1496      } while (node.goToNextElement()) ;
1497      node.goToParentElement();
1498    }
1499  }
1500
1501  DEFINE_REF_FUNC(Axis,axis)
1502
1503   ///---------------------------------------------------------------
1504
1505} // namespace xios
Note: See TracBrowser for help on using the repository browser.