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

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

Avoiding recalculation of domain/axis distributions for server-pools of the same size. This commit is complimentary to r1263.

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