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

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

Add new transformation : reduce axis_to_axis
This a global reduction implying all process whih own the same source axis global point.

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