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

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

In addition to r1294: all domain/axis attributes are only sent to secondary-server pools that need them (and not to all pools).

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 50.5 KB
Line 
1#include "axis.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "message.hpp"
7#include "type.hpp"
8#include "context.hpp"
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "xios_spl.hpp"
12#include "server_distribution_description.hpp"
13#include "client_server_mapping_distributed.hpp"
14#include "distribution_client.hpp"
15
16namespace xios {
17
18   /// ////////////////////// Définitions ////////////////////// ///
19
20   CAxis::CAxis(void)
21      : CObjectTemplate<CAxis>()
22      , CAxisAttributes(), isChecked(false), relFiles(), areClientAttributesChecked_(false)
23      , isClientAfterTransformationChecked(false)
24      , hasBounds(false), isCompressible_(false)
25      , numberWrittenIndexes_(), totalNumberWrittenIndexes_(), offsetWrittenIndexes_()
26      , transformationMap_(), hasValue(false), hasLabel(false)
27      , computedWrittenIndex_(false)
28          , clients()
29   {
30   }
31
32   CAxis::CAxis(const StdString & id)
33      : CObjectTemplate<CAxis>(id)
34      , CAxisAttributes(), isChecked(false), relFiles(), areClientAttributesChecked_(false)
35      , isClientAfterTransformationChecked(false)
36      , hasBounds(false), isCompressible_(false)
37      , numberWrittenIndexes_(), totalNumberWrittenIndexes_(), offsetWrittenIndexes_()
38      , transformationMap_(), hasValue(false), hasLabel(false)
39      , computedWrittenIndex_(false)
40          , clients()
41   {
42   }
43
44   CAxis::~CAxis(void)
45   { /* Ne rien faire de plus */ }
46
47   std::map<StdString, ETranformationType> CAxis::transformationMapList_ = std::map<StdString, ETranformationType>();
48   bool CAxis::dummyTransformationMapList_ = CAxis::initializeTransformationMap(CAxis::transformationMapList_);
49   bool CAxis::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
50   {
51     m["zoom_axis"] = TRANS_ZOOM_AXIS;
52     m["interpolate_axis"] = TRANS_INTERPOLATE_AXIS;
53     m["inverse_axis"] = TRANS_INVERSE_AXIS;
54     m["reduce_domain"] = TRANS_REDUCE_DOMAIN_TO_AXIS;
55     m["reduce_axis"] = TRANS_REDUCE_AXIS_TO_AXIS;
56     m["extract_domain"] = TRANS_EXTRACT_DOMAIN_TO_AXIS;
57     m["temporal_splitting"] = TRANS_TEMPORAL_SPLITTING;
58     m["duplicate_scalar"] = TRANS_DUPLICATE_SCALAR_TO_AXIS;
59
60   }
61
62   ///---------------------------------------------------------------
63
64   const std::set<StdString> & CAxis::getRelFiles(void) const
65   {
66      return (this->relFiles);
67   }
68
69   bool CAxis::IsWritten(const StdString & filename) const
70   {
71      return (this->relFiles.find(filename) != this->relFiles.end());
72   }
73
74   bool CAxis::isWrittenCompressed(const StdString& filename) const
75   {
76      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
77   }
78
79   bool CAxis::isDistributed(void) const
80   {
81      bool distributed = (!this->begin.isEmpty() && !this->n.isEmpty() && (this->begin + this->n < this->n_glo)) ||
82             (!this->n.isEmpty() && (this->n != this->n_glo));
83      // A same stupid condition to make sure that if there is only one client, axis
84      // should be considered to be distributed. This should be a temporary solution     
85      distributed |= (1 == CContext::getCurrent()->client->clientSize);
86      return distributed;
87   }
88
89   /*!
90    * Test whether the data defined on the axis can be outputted in a compressed way.
91    *
92    * \return true if and only if a mask was defined for this axis
93    */
94   bool CAxis::isCompressible(void) const
95   {
96      return isCompressible_;
97   }
98
99   void CAxis::addRelFile(const StdString & filename)
100   {
101      this->relFiles.insert(filename);
102   }
103
104   void CAxis::addRelFileCompressed(const StdString& filename)
105   {
106      this->relFilesCompressed.insert(filename);
107   }
108
109   //----------------------------------------------------------------
110
111   /*!
112     Returns the number of indexes written by each server.
113     \return the number of indexes written by each server
114   */
115   int CAxis::getNumberWrittenIndexes(MPI_Comm writtenCom)
116   {
117     int writtenSize;
118     MPI_Comm_size(writtenCom, &writtenSize);
119     return numberWrittenIndexes_[writtenSize];
120   }
121
122   /*!
123     Returns the total number of indexes written by the servers.
124     \return the total number of indexes written by the servers
125   */
126   int CAxis::getTotalNumberWrittenIndexes(MPI_Comm writtenCom)
127   {
128     int writtenSize;
129     MPI_Comm_size(writtenCom, &writtenSize);
130     return totalNumberWrittenIndexes_[writtenSize];
131   }
132
133   /*!
134     Returns the offset of indexes written by each server.
135     \return the offset of indexes written by each server
136   */
137   int CAxis::getOffsetWrittenIndexes(MPI_Comm writtenCom)
138   {
139     int writtenSize;
140     MPI_Comm_size(writtenCom, &writtenSize);
141     return offsetWrittenIndexes_[writtenSize];
142   }
143
144   CArray<int, 1>& CAxis::getCompressedIndexToWriteOnServer(MPI_Comm writtenCom)
145   {
146     int writtenSize;
147     MPI_Comm_size(writtenCom, &writtenSize);
148     return compressedIndexToWriteOnServer[writtenSize];
149   }
150   //----------------------------------------------------------------
151
152   /*!
153    * Compute the minimum buffer size required to send the attributes to the server(s).
154    *
155    * \return A map associating the server rank with its minimum buffer size.
156    */
157   std::map<int, StdSize> CAxis::getAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= false*/)
158   {
159
160     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
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->serverSize].end();
185       for (it = indSrv_[client->serverSize].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, nbServer);
608      CClientServerMapping::GlobalIndexMap& globalIndexAxisOnServer = clientServerMap->getGlobalIndexOnServer();     
609
610
611      indSrv_[nbServer].swap(globalIndexAxisOnServer);
612
613      if (distType==CServerDistributionDescription::ROOT_DISTRIBUTION)
614      {
615        for(int i=1; i<nbServer; ++i) indSrv_[nbServer].insert(pair<int, vector<size_t> >(i,indSrv_[nbServer][0]) ) ;
616        serverZeroIndexLeader.clear() ;
617      }
618         
619      CClientServerMapping::GlobalIndexMap::const_iterator it  = indSrv_[nbServer].begin(),
620                                                           ite = indSrv_[nbServer].end();
621
622      for (it = indSrv_[nbServer].begin(); it != ite; ++it) connectedServerRank_[nbServer].push_back(it->first);
623
624      for (std::list<int>::const_iterator it = serverZeroIndexLeader.begin(); it != serverZeroIndexLeader.end(); ++it)
625        connectedServerRank_[nbServer].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_[nbServer].empty())
630        connectedServerRank_[nbServer].push_back(client->clientRank % client->serverSize);
631
632//       nbSenders[client] = CClientServerMapping::computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_[client]);
633       nbSenders[nbServer] = CClientServerMapping::computeConnectedClients(client->serverSize, client->clientSize, client->intraComm, connectedServerRank_[nbServer]);
634
635      delete clientServerMap;
636    }
637  }
638
639  /*
640    Compute the index of data to write into file
641    (Different from the previous version, this version of XIOS allows data be written into file (classical role),
642    or transfered to another clients)
643  */
644  void CAxis::computeWrittenIndex()
645  { 
646    if (computedWrittenIndex_) return;
647    computedWrittenIndex_ = true;
648
649    CContext* context=CContext::getCurrent();     
650    CContextServer* server = context->server; 
651
652    // We describe the distribution of client (server) on which data are written
653    std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
654    nBegin[0]       = zoom_begin;
655    nSize[0]        = zoom_n;   
656    nBeginGlobal[0] = 0; 
657    nGlob[0]        = n_glo;
658    CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
659    const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
660
661    // Because all written data are local on a client,
662    // we need to compute the local index on the server from its corresponding global index
663    size_t nbWritten = 0, indGlo;     
664    boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
665                                                        ite = globalLocalIndexMap_.end(), it;         
666    CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
667                                     itSrve = writtenGlobalIndex.end(), itSrv; 
668    if (!zoomByIndex())
669    {   
670      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
671      {
672        indGlo = *itSrv;
673        if (ite != globalLocalIndexMap_.find(indGlo))
674        {         
675          ++nbWritten;
676        }                 
677      }
678
679      localIndexToWriteOnServer.resize(nbWritten);
680
681      nbWritten = 0;
682      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
683      {
684        indGlo = *itSrv;
685        if (ite != globalLocalIndexMap_.find(indGlo))
686        {
687          localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[indGlo];
688          ++nbWritten;
689        }                 
690      }
691    }
692    else
693    {
694      nbWritten = 0;
695      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
696                                                          ite = globalLocalIndexMap_.end(), it;
697      for (int i = 0; i < zoom_index.numElements(); ++i)
698      {
699         if (ite != globalLocalIndexMap_.find(zoom_index(i)))
700          ++nbWritten;
701      }
702
703      localIndexToWriteOnServer.resize(nbWritten);
704
705      nbWritten = 0;
706      for (int i = 0; i < zoom_index.numElements(); ++i)
707      {
708         if (ite != globalLocalIndexMap_.find(zoom_index(i)))
709         {
710           localIndexToWriteOnServer(nbWritten) = globalLocalIndexMap_[zoom_index(i)];
711           ++nbWritten;
712         }
713      }
714    }
715
716    // if (isCompressible())
717    // {
718    //   nbWritten = 0;
719    //   boost::unordered_map<size_t,size_t> localGlobalIndexMap;
720    //   for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
721    //   {
722    //     indGlo = *itSrv;
723    //     if (ite != globalLocalIndexMap_.find(indGlo))
724    //     {
725    //       localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
726    //       ++nbWritten;
727    //     }                 
728    //   }
729
730    //   nbWritten = 0;
731    //   for (int idx = 0; idx < data_index.numElements(); ++idx)
732    //   {
733    //     if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
734    //     {
735    //       ++nbWritten;
736    //     }
737    //   }
738
739    //   compressedIndexToWriteOnServer.resize(nbWritten);
740    //   nbWritten = 0;
741    //   for (int idx = 0; idx < data_index.numElements(); ++idx)
742    //   {
743    //     if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
744    //     {
745    //       compressedIndexToWriteOnServer(nbWritten) = localGlobalIndexMap[data_index(idx)];
746    //       ++nbWritten;
747    //     }
748    //   }
749
750    //   numberWrittenIndexes_ = nbWritten;
751    //   if (isDistributed())
752    //   {
753             
754    //     MPI_Allreduce(&numberWrittenIndexes_, &totalNumberWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
755    //     MPI_Scan(&numberWrittenIndexes_, &offsetWrittenIndexes_, 1, MPI_INT, MPI_SUM, server->intraComm);
756    //     offsetWrittenIndexes_ -= numberWrittenIndexes_;
757    //   }
758    //   else
759    //     totalNumberWrittenIndexes_ = numberWrittenIndexes_;
760    // }
761  }
762
763  void CAxis::computeWrittenCompressedIndex(MPI_Comm writtenComm)
764  {
765    int writtenCommSize;
766    MPI_Comm_size(writtenComm, &writtenCommSize);
767    if (compressedIndexToWriteOnServer.find(writtenCommSize) != compressedIndexToWriteOnServer.end())
768      return;
769
770    if (isCompressible())
771    {
772      size_t nbWritten = 0, indGlo;
773      CContext* context=CContext::getCurrent();     
774      CContextServer* server = context->server; 
775
776      // We describe the distribution of client (server) on which data are written
777      std::vector<int> nBegin(1), nSize(1), nBeginGlobal(1), nGlob(1);
778      nBegin[0]       = zoom_begin;
779      nSize[0]        = zoom_n;   
780      nBeginGlobal[0] = 0; 
781      nGlob[0]        = n_glo;
782      CDistributionServer srvDist(server->intraCommSize, nBegin, nSize, nBeginGlobal, nGlob); 
783      const CArray<size_t,1>& writtenGlobalIndex  = srvDist.getGlobalIndex();
784      boost::unordered_map<size_t,size_t>::const_iterator itb = globalLocalIndexMap_.begin(),
785                                                          ite = globalLocalIndexMap_.end(), it;   
786
787      CArray<size_t,1>::const_iterator itSrvb = writtenGlobalIndex.begin(),
788                                       itSrve = writtenGlobalIndex.end(), itSrv;
789      boost::unordered_map<size_t,size_t> localGlobalIndexMap;
790      for (itSrv = itSrvb; itSrv != itSrve; ++itSrv)
791      {
792        indGlo = *itSrv;
793        if (ite != globalLocalIndexMap_.find(indGlo))
794        {
795          localGlobalIndexMap[localIndexToWriteOnServer(nbWritten)] = indGlo;
796          ++nbWritten;
797        }                 
798      }
799
800      nbWritten = 0;
801      for (int idx = 0; idx < data_index.numElements(); ++idx)
802      {
803        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
804        {
805          ++nbWritten;
806        }
807      }
808
809      compressedIndexToWriteOnServer[writtenCommSize].resize(nbWritten);
810      nbWritten = 0;
811      for (int idx = 0; idx < data_index.numElements(); ++idx)
812      {
813        if (localGlobalIndexMap.end() != localGlobalIndexMap.find(data_index(idx)))
814        {
815          compressedIndexToWriteOnServer[writtenCommSize](nbWritten) = localGlobalIndexMap[data_index(idx)];
816          ++nbWritten;
817        }
818      }
819
820      numberWrittenIndexes_[writtenCommSize] = nbWritten;
821      if (isDistributed())
822      {
823             
824        MPI_Allreduce(&numberWrittenIndexes_[writtenCommSize], &totalNumberWrittenIndexes_[writtenCommSize], 1, MPI_INT, MPI_SUM, writtenComm);
825        MPI_Scan(&numberWrittenIndexes_[writtenCommSize], &offsetWrittenIndexes_[writtenCommSize], 1, MPI_INT, MPI_SUM, writtenComm);
826        offsetWrittenIndexes_[writtenCommSize] -= numberWrittenIndexes_[writtenCommSize];
827      }
828      else
829        totalNumberWrittenIndexes_[writtenCommSize] = numberWrittenIndexes_[writtenCommSize];
830    }
831  }
832
833  /*!
834    Send distribution information from a group of client (client role) to another group of client (server role)
835    The distribution of a group of client (server role) is imposed by the group of client (client role)
836    \param [in] globalDim global dimension of grid containing this axis
837    \param [in] orderPositionInGrid the relative order of this axis in the grid (e.g grid composed of domain+axis -> orderPositionInGrid is 2)
838    \param [in] distType distribution type of the server. For now, we only have band distribution.
839  */
840  void CAxis::sendDistributionAttribute(const std::vector<int>& globalDim, int orderPositionInGrid,
841                                        CServerDistributionDescription::ServerDistributionType distType)
842  {
843    std::set<CContextClient*>::iterator it;
844    for (it=clients.begin(); it!=clients.end(); ++it)
845    {
846      CContextClient* client = *it;
847      int nbServer = client->serverSize;
848
849      CServerDistributionDescription serverDescription(globalDim, nbServer);
850      serverDescription.computeServerDistribution();
851
852      std::vector<std::vector<int> > serverIndexBegin = serverDescription.getServerIndexBegin();
853      std::vector<std::vector<int> > serverDimensionSizes = serverDescription.getServerDimensionSizes();
854
855      CEventClient event(getType(),EVENT_ID_DISTRIBUTION_ATTRIBUTE);
856      if (client->isServerLeader())
857      {
858        std::list<CMessage> msgs;
859
860        const std::list<int>& ranks = client->getRanksServerLeader();
861        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
862        {
863          // Use const int to ensure CMessage holds a copy of the value instead of just a reference
864          const int begin = serverIndexBegin[*itRank][orderPositionInGrid];
865          const int ni    = serverDimensionSizes[*itRank][orderPositionInGrid];
866          const int end   = begin + ni - 1;         
867
868          msgs.push_back(CMessage());
869          CMessage& msg = msgs.back();
870          msg << this->getId();
871          msg << ni << begin << end;         
872          msg << isCompressible_;                   
873
874          event.push(*itRank,1,msg);
875        }
876        client->sendEvent(event);
877      }
878      else client->sendEvent(event);
879    }
880  }
881
882  /*
883    Receive distribution attribute from another client
884    \param [in] event event containing data of these attributes
885  */
886  void CAxis::recvDistributionAttribute(CEventServer& event)
887  {
888    CBufferIn* buffer = event.subEvents.begin()->buffer;
889    string axisId;
890    *buffer >> axisId;
891    get(axisId)->recvDistributionAttribute(*buffer);
892  }
893
894  /*
895    Receive distribution attribute from another client
896    \param [in] buffer buffer containing data of these attributes
897  */
898  void CAxis::recvDistributionAttribute(CBufferIn& buffer)
899  {
900    int ni_srv, begin_srv, end_srv;
901    int global_zoom_end, zoom_end;
902    bool zoomIndex = zoomByIndex();
903   
904    std::vector<int> zoom_index_tmp;
905    std::vector<int>::iterator itZoomBegin, itZoomEnd, itZoom;
906
907    buffer >> ni_srv >> begin_srv >> end_srv;   
908    buffer >> isCompressible_;           
909
910    // Set up new local size of axis on the receiving clients
911    n.setValue(ni_srv);
912    begin.setValue(begin_srv);
913
914    // If we have zoom by index then process it
915    if (zoomIndex)
916    {
917      zoom_index_tmp.resize(global_zoom_index.numElements());
918      std::copy(global_zoom_index.begin(), global_zoom_index.end(), zoom_index_tmp.begin());
919      std::sort(zoom_index_tmp.begin(), zoom_index_tmp.end());
920      itZoomBegin = std::lower_bound(zoom_index_tmp.begin(), zoom_index_tmp.end(), begin_srv);
921      itZoomEnd   = std::upper_bound(zoom_index_tmp.begin(), zoom_index_tmp.end(), end_srv);     
922      int sz = std::distance(itZoomBegin, itZoomEnd);
923      zoom_index.resize(sz);
924      itZoom = itZoomBegin;
925      for (int i = 0; i < sz; ++i, ++itZoom)
926      {
927        zoom_index(i) = *(itZoom);
928      }
929    }
930
931    global_zoom_begin = zoomIndex ? 0 : global_zoom_begin ;
932    global_zoom_n     = zoomIndex ? zoom_index_tmp.size() : global_zoom_n;
933    global_zoom_end   = global_zoom_begin + global_zoom_n - 1;
934
935    zoom_begin = zoomIndex ? std::distance(itZoomBegin, zoom_index_tmp.begin())
936                           : global_zoom_begin > begin_srv ? global_zoom_begin : begin_srv ;
937    zoom_end   = zoomIndex ? std::distance(zoom_index_tmp.begin(), itZoomEnd) - 1 
938                           : global_zoom_end < end_srv ? global_zoom_end : end_srv ;
939    zoom_n     = zoom_end - zoom_begin + 1;
940
941    if (zoom_n<=0)
942    {
943      zoom_n = 0; zoom_begin=global_zoom_begin; //0; zoom_begin = 0;
944    }
945
946    if (n_glo == n)
947    {
948      zoom_begin = zoomIndex ? std::distance(itZoomBegin, zoom_index_tmp.begin())
949                             : global_zoom_begin;     
950      zoom_n     = zoomIndex ? zoom_index_tmp.size() : global_zoom_n;
951    }
952  }
953
954  /*
955    Send attributes of axis from a group of client to other group of clients/servers
956    on supposing that these attributes are not distributed among the sending group
957    In the future, if new attributes are added, they should also be processed in this function
958  */
959  void CAxis::sendNonDistributedAttributes()
960  {
961    std::set<CContextClient*>::iterator it;
962    for (it=clients.begin(); it!=clients.end(); ++it)
963        {
964          CContextClient* client = *it;
965
966      CEventClient event(getType(), EVENT_ID_NON_DISTRIBUTED_ATTRIBUTES);
967      size_t nbIndex = index.numElements();
968      size_t nbDataIndex = 0;
969
970      for (int idx = 0; idx < data_index.numElements(); ++idx)
971      {
972        int ind = data_index(idx);
973        if (ind >= 0 && ind < nbIndex) ++nbDataIndex;
974      }
975
976      CArray<int,1> dataIndex(nbDataIndex);
977      nbDataIndex = 0;
978      for (int idx = 0; idx < data_index.numElements(); ++idx)
979      {
980        int ind = data_index(idx);
981        if (ind >= 0 && ind < nbIndex)
982        {
983          dataIndex(nbDataIndex) = ind;
984          ++nbDataIndex;
985        }
986      }
987
988      if (client->isServerLeader())
989      {
990        std::list<CMessage> msgs;
991
992        const std::list<int>& ranks = client->getRanksServerLeader();
993        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
994        {
995          msgs.push_back(CMessage());
996          CMessage& msg = msgs.back();
997          msg << this->getId();
998          msg << index.getValue() << dataIndex << mask.getValue();
999          msg << hasValue;
1000          if (hasValue) msg << value.getValue();
1001          msg << hasBounds;
1002          if (hasBounds) msg << bounds.getValue();
1003          msg << hasLabel;
1004          if (hasLabel) msg << label.getValue();
1005
1006          event.push(*itRank, 1, msg);
1007        }
1008        client->sendEvent(event);
1009      }
1010      else client->sendEvent(event);
1011    }
1012  }
1013
1014  /*
1015    Receive the non-distributed attributes from another group of clients
1016    \param [in] event event containing data of these attributes
1017  */
1018  void CAxis::recvNonDistributedAttributes(CEventServer& event)
1019  {
1020    list<CEventServer::SSubEvent>::iterator it;
1021    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1022    {
1023      CBufferIn* buffer = it->buffer;
1024      string axisId;
1025      *buffer >> axisId;
1026      get(axisId)->recvNonDistributedAttributes(it->rank, *buffer);
1027    }
1028  }
1029
1030  /*
1031    Receive the non-distributed attributes from another group of clients
1032    \param [in] rank rank of the sender
1033    \param [in] buffer buffer containing data sent from the sender
1034  */
1035  void CAxis::recvNonDistributedAttributes(int rank, CBufferIn& buffer)
1036  { 
1037    CArray<int,1> tmp_index, tmp_data_index, tmp_zoom_index;
1038    CArray<bool,1> tmp_mask;
1039    CArray<double,1> tmp_val;
1040    CArray<double,2> tmp_bnds;
1041    CArray<string,1> tmp_label;
1042
1043    buffer >> tmp_index;
1044    index.reference(tmp_index);
1045    buffer >> tmp_data_index;
1046    data_index.reference(tmp_data_index);
1047    buffer >> tmp_mask;
1048    mask.reference(tmp_mask);
1049
1050    buffer >> hasValue;
1051    if (hasValue)
1052    {
1053      buffer >> tmp_val;
1054      value.reference(tmp_val);
1055    }
1056
1057    buffer >> hasBounds;
1058    if (hasBounds)
1059    {
1060      buffer >> tmp_bnds;
1061      bounds.reference(tmp_bnds);
1062    }
1063
1064    buffer >> hasLabel;
1065    if (hasLabel)
1066    {
1067      buffer >> tmp_label;
1068      label.reference(tmp_label);
1069    }
1070
1071    // Some value should be reset here
1072    data_begin.setValue(0);
1073    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1074    for (int idx = 0; idx < index.numElements(); ++idx) globalLocalIndexMap_[idx] = index(idx);
1075  }
1076
1077  /*
1078    Send attributes of axis from a group of client to other group of clients/servers
1079    on supposing that these attributes are distributed among the clients of the sending group
1080    In the future, if new attributes are added, they should also be processed in this function
1081  */
1082  void CAxis::sendDistributedAttributes(void)
1083  {
1084    int ns, n, i, j, ind, nv, idx;
1085    std::set<CContextClient*>::iterator it;
1086
1087    for (it=clients.begin(); it!=clients.end(); ++it)
1088    {
1089      CContextClient* client = *it;
1090      int nbServer = client->serverSize;
1091
1092      CEventClient eventData(getType(), EVENT_ID_DISTRIBUTED_ATTRIBUTES);
1093
1094      list<CMessage> listData;
1095      list<CArray<int,1> > list_indi, list_dataInd, list_zoomInd;
1096      list<CArray<bool,1> > list_mask;
1097      list<CArray<double,1> > list_val;
1098      list<CArray<double,2> > list_bounds;
1099      list<CArray<string,1> > list_label;
1100
1101      int nbIndex = index.numElements();
1102      CArray<int,1> dataIndex(nbIndex);
1103      dataIndex = -1;
1104      for (idx = 0; idx < data_index.numElements(); ++idx)
1105      {
1106        if (0 <= data_index(idx) && data_index(idx) < nbIndex)
1107          dataIndex(idx) = 1;
1108      }
1109
1110      boost::unordered_map<int, std::vector<size_t> >::const_iterator it, iteMap;
1111      iteMap = indSrv_[nbServer].end();
1112      for (int k = 0; k < connectedServerRank_[nbServer].size(); ++k)
1113      {
1114        int nbData = 0;
1115        int rank = connectedServerRank_[nbServer][k];
1116        it = indSrv_[nbServer].find(rank);
1117        if (iteMap != it)
1118          nbData = it->second.size();
1119
1120        list_indi.push_back(CArray<int,1>(nbData));
1121        list_dataInd.push_back(CArray<int,1>(nbData));       
1122        list_mask.push_back(CArray<bool,1>(nbData));
1123
1124        if (hasValue)
1125          list_val.push_back(CArray<double,1>(nbData));
1126
1127        if (hasBounds)       
1128          list_bounds.push_back(CArray<double,2>(2,nbData));
1129
1130        if (hasLabel)
1131          list_label.push_back(CArray<string,1>(nbData));
1132
1133        CArray<int,1>& indi = list_indi.back();
1134        CArray<int,1>& dataIndi = list_dataInd.back();       
1135        CArray<bool,1>& maskIndi = list_mask.back();
1136
1137        for (n = 0; n < nbData; ++n)
1138        {
1139          idx = static_cast<int>(it->second[n]);
1140          indi(n) = idx;
1141
1142          ind = globalLocalIndexMap_[idx];
1143          dataIndi(n) = dataIndex(ind);
1144          maskIndi(n) = mask(ind);
1145
1146          if (hasValue)
1147          {
1148            CArray<double,1>& val = list_val.back();
1149            val(n) = value(ind);
1150          }
1151
1152          if (hasBounds)
1153          {
1154            CArray<double,2>& boundsVal = list_bounds.back();
1155            boundsVal(0, n) = bounds(0,n);
1156            boundsVal(1, n) = bounds(1,n);
1157          }
1158
1159          if (hasLabel)
1160          {
1161            CArray<string,1>& labelVal = list_label.back();
1162            labelVal(n) = label(ind); 
1163          }
1164        }
1165
1166        listData.push_back(CMessage());
1167        listData.back() << this->getId()
1168                        << list_indi.back() << list_dataInd.back() << list_mask.back();
1169
1170        listData.back() << hasValue;
1171        if (hasValue)
1172          listData.back() << list_val.back();
1173
1174        listData.back() << hasBounds;
1175        if (hasBounds)
1176          listData.back() << list_bounds.back();
1177
1178        listData.back() << hasLabel;
1179        if (hasLabel)
1180          listData.back() << list_label.back();
1181
1182        eventData.push(rank, nbSenders[nbServer][rank], listData.back());
1183      }
1184
1185      client->sendEvent(eventData);
1186    }
1187  }
1188
1189  /*
1190    Receive the distributed attributes from another group of clients
1191    \param [in] event event containing data of these attributes
1192  */
1193  void CAxis::recvDistributedAttributes(CEventServer& event)
1194  {
1195    string axisId;
1196    vector<int> ranks;
1197    vector<CBufferIn*> buffers;
1198
1199    list<CEventServer::SSubEvent>::iterator it;
1200    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
1201    {
1202      ranks.push_back(it->rank);
1203      CBufferIn* buffer = it->buffer;
1204      *buffer >> axisId;
1205      buffers.push_back(buffer);
1206    }
1207    get(axisId)->recvDistributedAttributes(ranks, buffers);
1208  }
1209
1210  /*
1211    Receive the non-distributed attributes from another group of clients
1212    \param [in] ranks rank of the sender
1213    \param [in] buffers buffer containing data sent from the sender
1214  */
1215  void CAxis::recvDistributedAttributes(vector<int>& ranks, vector<CBufferIn*> buffers)
1216  {
1217    int nbReceived = ranks.size(), idx, ind, gloInd, locInd;
1218    vector<CArray<int,1> > vec_indi(nbReceived), vec_dataInd(nbReceived), vec_zoomInd(nbReceived);   
1219    vector<CArray<bool,1> > vec_mask(nbReceived);
1220    vector<CArray<double,1> > vec_val(nbReceived);
1221    vector<CArray<double,2> > vec_bounds(nbReceived);
1222    vector<CArray<string,1> > vec_label(nbReceived);
1223   
1224    for (idx = 0; idx < nbReceived; ++idx)
1225    {     
1226      CBufferIn& buffer = *buffers[idx];
1227      buffer >> vec_indi[idx];
1228      buffer >> vec_dataInd[idx];     
1229      buffer >> vec_mask[idx];
1230
1231      buffer >> hasValue;
1232      if (hasValue)
1233        buffer >> vec_val[idx];
1234
1235      buffer >> hasBounds;
1236      if (hasBounds)
1237        buffer >> vec_bounds[idx];
1238
1239      buffer >> hasLabel;
1240      if (hasLabel)
1241        buffer >> vec_label[idx]; 
1242    }
1243
1244    // Estimate size of index array
1245    int nbIndexGlob = 0;
1246    for (idx = 0; idx < nbReceived; ++idx)
1247    {
1248      nbIndexGlob += vec_indi[idx].numElements();
1249    }
1250
1251    // Recompute global index
1252    // Take account of the overlapped index
1253    index.resize(nbIndexGlob);
1254    globalLocalIndexMap_.rehash(std::ceil(index.numElements()/globalLocalIndexMap_.max_load_factor()));
1255    nbIndexGlob = 0;
1256    for (idx = 0; idx < nbReceived; ++idx)
1257    {
1258      CArray<int,1>& tmp = vec_indi[idx];
1259      for (ind = 0; ind < tmp.numElements(); ++ind)
1260      {
1261         gloInd = tmp(ind);
1262         if (0 == globalLocalIndexMap_.count(gloInd))
1263         {
1264           index(nbIndexGlob) = gloInd % n_glo;           
1265           globalLocalIndexMap_[gloInd] = nbIndexGlob; 
1266           ++nbIndexGlob;
1267         } 
1268      } 
1269    }
1270
1271    // Resize index to its real size
1272    if (nbIndexGlob==0) index.resize(nbIndexGlob) ;
1273    else index.resizeAndPreserve(nbIndexGlob);
1274
1275    int nbData = nbIndexGlob;
1276    CArray<int,1> nonCompressedData(nbData);
1277    nonCompressedData = -1;   
1278    mask.resize(nbData);
1279    if (hasValue)
1280      value.resize(nbData);
1281    if (hasBounds)
1282      bounds.resize(2,nbData);
1283    if (hasLabel)
1284      label.resize(nbData);
1285
1286    nbData = 0;
1287    for (idx = 0; idx < nbReceived; ++idx)
1288    {
1289      CArray<int,1>& indi = vec_indi[idx];
1290      CArray<int,1>& dataIndi = vec_dataInd[idx];
1291      CArray<bool,1>& maskIndi = vec_mask[idx];
1292      int nb = indi.numElements();
1293      for (int n = 0; n < nb; ++n)
1294      { 
1295        locInd = globalLocalIndexMap_[size_t(indi(n))];
1296
1297        nonCompressedData(locInd) = (-1 == nonCompressedData(locInd)) ? dataIndi(n) : nonCompressedData(locInd);
1298
1299        if (!mask(locInd)) // Only rewrite mask if it's not true
1300          mask(locInd) = maskIndi(n);
1301       
1302        if (hasValue)
1303          value(locInd) = vec_val[idx](n);
1304
1305        if (hasBounds)
1306        {
1307          bounds(0,locInd) = vec_bounds[idx](0,n);
1308          bounds(1,locInd) = vec_bounds[idx](1,n);
1309        }
1310
1311        if (hasLabel)
1312          label(locInd) = vec_label[idx](n);
1313      }
1314    }
1315   
1316    int nbCompressedData = 0; 
1317    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1318    {
1319      if (0 <= nonCompressedData(idx))
1320        ++nbCompressedData;       
1321    }
1322
1323    data_index.resize(nbCompressedData);
1324    nbCompressedData = 0;
1325    for (idx = 0; idx < nonCompressedData.numElements(); ++idx)
1326    {
1327      if (0 <= nonCompressedData(idx))
1328      {
1329        data_index(nbCompressedData) = idx % n;
1330        ++nbCompressedData;       
1331      }
1332    }
1333
1334    data_begin.setValue(0);
1335  }
1336
1337
1338  /*!
1339    Compare two axis objects.
1340    They are equal if only if they have identical attributes as well as their values.
1341    Moreover, they must have the same transformations.
1342  \param [in] axis Compared axis
1343  \return result of the comparison
1344  */
1345  bool CAxis::isEqual(CAxis* obj)
1346  {
1347    vector<StdString> excludedAttr;
1348    excludedAttr.push_back("axis_ref");
1349
1350    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
1351    if (!objEqual) return objEqual;
1352
1353    TransMapTypes thisTrans = this->getAllTransformations();
1354    TransMapTypes objTrans  = obj->getAllTransformations();
1355
1356    TransMapTypes::const_iterator it, itb, ite;
1357    std::vector<ETranformationType> thisTransType, objTransType;
1358    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
1359      thisTransType.push_back(it->first);
1360    for (it = objTrans.begin(); it != objTrans.end(); ++it)
1361      objTransType.push_back(it->first);
1362
1363    if (thisTransType.size() != objTransType.size()) return false;
1364    for (int idx = 0; idx < thisTransType.size(); ++idx)
1365      objEqual &= (thisTransType[idx] == objTransType[idx]);
1366
1367    return objEqual;
1368  }
1369
1370  /*
1371    Add transformation into axis. This function only servers for Fortran interface
1372    \param [in] transType transformation type
1373    \param [in] id identifier of the transformation object
1374  */
1375  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
1376  {
1377    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
1378    return transformationMap_.back().second;
1379  }
1380
1381  /*
1382    Check whether an axis has (spatial) transformation
1383  */
1384  bool CAxis::hasTransformation()
1385  {
1386    return (!transformationMap_.empty());
1387  }
1388
1389  /*
1390    Set transformation
1391    \param [in] axisTrans transformation to set
1392  */
1393  void CAxis::setTransformations(const TransMapTypes& axisTrans)
1394  {
1395    transformationMap_ = axisTrans;
1396  }
1397
1398  /*
1399    Return all transformation held by the axis
1400    \return transformation the axis has
1401  */
1402  CAxis::TransMapTypes CAxis::getAllTransformations(void)
1403  {
1404    return transformationMap_;
1405  }
1406
1407  /*
1408    Duplicate transformation of another axis
1409    \param [in] src axis whose transformations are copied
1410  */
1411  void CAxis::duplicateTransformation(CAxis* src)
1412  {
1413    if (src->hasTransformation())
1414    {
1415      this->setTransformations(src->getAllTransformations());
1416    }
1417  }
1418
1419  /*!
1420   * Go through the hierarchy to find the axis from which the transformations must be inherited
1421   */
1422  void CAxis::solveInheritanceTransformation()
1423  {
1424    if (hasTransformation() || !hasDirectAxisReference())
1425      return;
1426
1427    CAxis* axis = this;
1428    std::vector<CAxis*> refAxis;
1429    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
1430    {
1431      refAxis.push_back(axis);
1432      axis = axis->getDirectAxisReference();
1433    }
1434
1435    if (axis->hasTransformation())
1436      for (size_t i = 0; i < refAxis.size(); ++i)
1437        refAxis[i]->setTransformations(axis->getAllTransformations());
1438  }
1439
1440  void CAxis::setContextClient(CContextClient* contextClient)
1441  {
1442    clients.insert(contextClient);
1443  }
1444
1445  void CAxis::parse(xml::CXMLNode & node)
1446  {
1447    SuperClass::parse(node);
1448
1449    if (node.goToChildElement())
1450    {
1451      StdString nodeElementName;
1452      do
1453      {
1454        StdString nodeId("");
1455        if (node.getAttributes().end() != node.getAttributes().find("id"))
1456        { nodeId = node.getAttributes()["id"]; }
1457
1458        nodeElementName = node.getElementName();
1459        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
1460        it = transformationMapList_.find(nodeElementName);
1461        if (ite != it)
1462        {
1463          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
1464                                                                                                               nodeId,
1465                                                                                                               &node)));
1466        }
1467        else
1468        {
1469          ERROR("void CAxis::parse(xml::CXMLNode & node)",
1470                << "The transformation " << nodeElementName << " has not been supported yet.");
1471        }
1472      } while (node.goToNextElement()) ;
1473      node.goToParentElement();
1474    }
1475  }
1476
1477  DEFINE_REF_FUNC(Axis,axis)
1478
1479   ///---------------------------------------------------------------
1480
1481} // namespace xios
Note: See TracBrowser for help on using the repository browser.