source: XIOS/dev/dev_trunk_omp/src/node/axis.cpp @ 1610

Last change on this file since 1610 was 1601, checked in by yushan, 6 years ago

branch_openmp merged with trunk r1597

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