source: XIOS/trunk/src/node/axis.cpp @ 1558

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

Adding transformation "extract" for axis.

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