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

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

Add 2 new spatial transformations :

  • reduce_scalar_to_scalar : global reduction between scalar
  • duplicate_scalar_to_axis : a scalar value is duplicated on each level of the axis.

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