source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/axis.cpp @ 2338

Last change on this file since 2338 was 2304, checked in by ymipsl, 2 years ago

Fix problem in remote connector for read variable : supress redondance optimisation on remote connector in read case.
YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 41.1 KB
RevLine 
[219]1#include "axis.hpp"
2
[352]3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "message.hpp"
7#include "type.hpp"
[567]8#include "context.hpp"
9#include "context_client.hpp"
[676]10#include "context_server.hpp"
[591]11#include "xios_spl.hpp"
[633]12#include "server_distribution_description.hpp"
13#include "client_server_mapping_distributed.hpp"
[676]14#include "distribution_client.hpp"
[219]15
[2203]16#include <algorithm>
17#include <regex>
18
[335]19namespace xios {
[540]20
[1421]21   /// ////////////////////// Definitions ////////////////////// ///
[219]22
23   CAxis::CAxis(void)
24      : CObjectTemplate<CAxis>()
[1975]25      , CAxisAttributes(), isChecked(false), relFiles()
[1235]26      , hasBounds(false), isCompressible_(false)
[1202]27      , transformationMap_(), hasValue(false), hasLabel(false)
[1975]28      , clients()
[621]29   {
30   }
[219]31
32   CAxis::CAxis(const StdString & id)
33      : CObjectTemplate<CAxis>(id)
[1975]34      , CAxisAttributes(), isChecked(false), relFiles()
[1235]35      , hasBounds(false), isCompressible_(false)
[1202]36      , transformationMap_(), hasValue(false), hasLabel(false)
[1975]37      , clients()
[621]38   {
39   }
[219]40
41   CAxis::~CAxis(void)
42   { /* Ne rien faire de plus */ }
43
[836]44   std::map<StdString, ETranformationType> CAxis::transformationMapList_ = std::map<StdString, ETranformationType>();
45   bool CAxis::dummyTransformationMapList_ = CAxis::initializeTransformationMap(CAxis::transformationMapList_);
46   bool CAxis::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
[1622]47   TRY
[836]48   {
49     m["zoom_axis"] = TRANS_ZOOM_AXIS;
50     m["interpolate_axis"] = TRANS_INTERPOLATE_AXIS;
[1558]51     m["extract_axis"] = TRANS_EXTRACT_AXIS;
[836]52     m["inverse_axis"] = TRANS_INVERSE_AXIS;
[895]53     m["reduce_domain"] = TRANS_REDUCE_DOMAIN_TO_AXIS;
[1301]54     m["reduce_axis"] = TRANS_REDUCE_AXIS_TO_AXIS;
[895]55     m["extract_domain"] = TRANS_EXTRACT_DOMAIN_TO_AXIS;
[1275]56     m["temporal_splitting"] = TRANS_TEMPORAL_SPLITTING;
[1314]57     m["duplicate_scalar"] = TRANS_DUPLICATE_SCALAR_TO_AXIS;
[2196]58     return true;
[836]59   }
[1622]60   CATCH
[2274]61   
62   void CAxis::releaseStaticAllocation(void)
63   {
64     transformationMapList_.clear() ;
65     CTransformation<CAxis>::unregisterAllTransformations() ;
66     CGridTransformationFactory<CAxis>::unregisterAllTransformations() ;
67   }
[836]68
[219]69   ///---------------------------------------------------------------
[1158]70
71   const std::set<StdString> & CAxis::getRelFiles(void) const
[1622]72   TRY
[1158]73   {
74      return (this->relFiles);
75   }
[1622]76   CATCH
[1158]77
[219]78   bool CAxis::IsWritten(const StdString & filename) const
[1622]79   TRY
[219]80   {
81      return (this->relFiles.find(filename) != this->relFiles.end());
82   }
[1622]83   CATCH
[219]84
[676]85   bool CAxis::isWrittenCompressed(const StdString& filename) const
[1622]86   TRY
[676]87   {
88      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
89   }
[1622]90   CATCH
[676]91
[594]92   bool CAxis::isDistributed(void) const
[1622]93   TRY
[594]94   {
[1158]95      bool distributed = (!this->begin.isEmpty() && !this->n.isEmpty() && (this->begin + this->n < this->n_glo)) ||
96             (!this->n.isEmpty() && (this->n != this->n_glo));
[1622]97      // A condition to make sure that if there is only one client, axis
[1158]98      // should be considered to be distributed. This should be a temporary solution     
[1787]99      distributed |= (1 == CContext::getCurrent()->intraCommSize_);
[1158]100      return distributed;
[594]101   }
[1622]102   CATCH
[594]103
[676]104   /*!
[1956]105    * Compute if the axis can be ouput in a compressed way.
106    * In this case the workflow view on server side must be the same
107    * than the full view for all context rank. The result is stored on
108    * internal isCompressible_ attribute.
[676]109    */
[1956]110   void CAxis::computeIsCompressible(void)
[1622]111   TRY
[676]112   {
[1956]113     // mesh is compressible contains some masked or indexed value, ie if full view is different of workflow view.
114     // But now assume that the size of the 2 view must be equal for everybody. True on server side
115     int isSameView = getLocalView(CElementView::FULL)->getSize() ==  getLocalView(CElementView::WORKFLOW)->getSize();
116     MPI_Allreduce(MPI_IN_PLACE, &isSameView, 1, MPI_INT, MPI_LAND, CContext::getCurrent()->getIntraComm()) ;
117     if (isSameView) isCompressible_ = false ;
118     else isCompressible_ = true ;
119     isCompressibleComputed_=true ;
[676]120   }
[1622]121   CATCH
[676]122
[219]123   void CAxis::addRelFile(const StdString & filename)
[1622]124   TRY
[219]125   {
126      this->relFiles.insert(filename);
127   }
[1622]128   CATCH_DUMP_ATTR
[219]129
[676]130   void CAxis::addRelFileCompressed(const StdString& filename)
[1622]131   TRY
[676]132   {
133      this->relFilesCompressed.insert(filename);
134   }
[1622]135   CATCH_DUMP_ATTR
[676]136
[1975]137    //----------------------------------------------------------------
[219]138
[676]139   /*!
[731]140    * Compute the minimum buffer size required to send the attributes to the server(s).
141    *
142    * \return A map associating the server rank with its minimum buffer size.
143    */
[1371]144   std::map<int, StdSize> CAxis::getAttributesBufferSize(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid,
145                                                         CServerDistributionDescription::ServerDistributionType distType)
[1622]146   TRY
[731]147   {
148
[1330]149     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
[731]150
[1371]151//     bool isNonDistributed = (n_glo == n);
152     bool isDistributed = (orderPositionInGrid == CServerDistributionDescription::defaultDistributedDimension(globalDim.size(), distType))
153                                 || (index.numElements() != n_glo);
[731]154
155     if (client->isServerLeader())
156     {
157       // size estimation for sendServerAttribut
158       size_t size = 6 * sizeof(size_t);
159       // size estimation for sendNonDistributedValue
[1371]160       if (!isDistributed)
161       {
162//         size = std::max(size, CArray<double,1>::size(n_glo) + (isCompressible_ ? CArray<int,1>::size(n_glo) : 0));
163         size += CArray<int,1>::size(n_glo);
164         size += CArray<int,1>::size(n_glo);
165         size += CArray<bool,1>::size(n_glo);
166         size += CArray<double,1>::size(n_glo);
167         if (hasBounds)
168           size += CArray<double,2>::size(2*n_glo);
169         if (hasLabel)
170          size += CArray<StdString,1>::size(n_glo);
171       }
[731]172       size += CEventClient::headerSize + getId().size() + sizeof(size_t);
173
174       const std::list<int>& ranks = client->getRanksServerLeader();
175       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
176       {
177         if (size > attributesSizes[*itRank])
178           attributesSizes[*itRank] = size;
179       }
[1371]180       const std::list<int>& ranksNonLeaders = client->getRanksServerNotLeader();
181       for (std::list<int>::const_iterator itRank = ranksNonLeaders.begin(), itRankEnd = ranksNonLeaders.end(); itRank != itRankEnd; ++itRank)
182       {
183         if (size > attributesSizes[*itRank])
184           attributesSizes[*itRank] = size;
185       }
186
[731]187     }
188
[1371]189     if (isDistributed)
[731]190     {
191       // size estimation for sendDistributedValue
[1542]192       std::unordered_map<int, vector<size_t> >::const_iterator it, ite = indSrv_[client->serverSize].end();
[1337]193       for (it = indSrv_[client->serverSize].begin(); it != ite; ++it)
[731]194       {
[1371]195         size_t size = 6 * sizeof(size_t);
196         size += CArray<int,1>::size(it->second.size());
197         size += CArray<int,1>::size(it->second.size());
198         size += CArray<bool,1>::size(it->second.size());
199         size += CArray<double,1>::size(it->second.size());
[1235]200         if (hasBounds)
[1371]201           size += CArray<double,2>::size(2 * it->second.size());
[1158]202         if (hasLabel)
[1371]203           size += CArray<StdString,1>::size(it->second.size());
[731]204
[1371]205         size += CEventClient::headerSize + getId().size() + sizeof(size_t);
[731]206         if (size > attributesSizes[it->first])
207           attributesSizes[it->first] = size;
208       }
209     }
210     return attributesSizes;
211   }
[1622]212   CATCH_DUMP_ATTR
[731]213
214   //----------------------------------------------------------------
215
[219]216   StdString CAxis::GetName(void)   { return (StdString("axis")); }
217   StdString CAxis::GetDefName(void){ return (CAxis::GetName()); }
218   ENodeType CAxis::GetType(void)   { return (eAxis); }
219
220   //----------------------------------------------------------------
221
[622]222   CAxis* CAxis::createAxis()
[1622]223   TRY
[622]224   {
225     CAxis* axis = CAxisGroup::get("axis_definition")->createChild();
226     return axis;
227   }
[1622]228   CATCH
[622]229
[2206]230   CAxis* CAxis::get(const string& id, bool noError)
[2203]231   {
232     const regex r("::");
233     smatch m;
234     if (regex_search(id, m, r))
235     {
236        if (m.size()!=1) ERROR("CAxis* CAxis::get(string& id)", <<" id = "<<id<< "  -> bad format id, separator :: append more than one time");
237        string fieldId=m.prefix() ;
238        if (fieldId.empty()) ERROR("CAxis* CAxis::get(string& id)", <<" id = "<<id<< "  -> bad format id, field name is empty");
239        string suffix=m.suffix() ;
[2206]240        if (!CField::has(fieldId)) 
241          if (noError)  return nullptr ;
242          else ERROR("CAxis* CAxis::get(string& id, bool noError)", <<" id = "<<id<< "  -> field Id : < "<<fieldId<<" > doesn't exist");
[2203]243        CField* field=CField::get(fieldId) ;
[2206]244        return field->getAssociatedAxis(suffix, noError) ;
[2203]245     }
[2206]246     {
247       if (noError) if(!CObjectFactory::HasObject<CAxis>(id)) return nullptr ;
248       return CObjectFactory::GetObject<CAxis>(id).get();
249     }
[2203]250   }
[2206]251   
252   bool CAxis::has(const string& id)
253   {
254     if (CAxis::get(id,true)==nullptr) return false ;
255     else return true ;
256   }
257   
258   CField* CAxis::getFieldFromId(const string& id)
259   {
260     const regex r("::");
261     smatch m;
262     if (regex_search(id, m, r))
263     {
264        if (m.size()!=1) ERROR("CField* CAxis::getFieldFromId(const string& id)", <<" id = "<<id<< "  -> bad format id, separator :: append more than one time");
265        string fieldId=m.prefix() ;
266        if (fieldId.empty()) ERROR("CField* CAxis::getFieldFromId(const string& id)", <<" id = "<<id<< "  -> bad format id, field name is empty");
267        string suffix=m.suffix() ;
268        CField* field=CField::get(fieldId) ;
269        return field ;
270     }
271     else return nullptr;
272   }
[2203]273
[1144]274   /*!
275     Check common attributes of an axis.
276     This check should be done in the very beginning of work flow
277   */
[2291]278   
[219]279   void CAxis::checkAttributes(void)
[2291]280   {
281      if (checkAttributes_done_) return ;
282      checkGeometricAttributes(true) ;
283      initializeLocalElement() ;
284      addFullView() ;
285      addWorkflowView() ;
286      addModelView() ;
287
288      checkAttributes_done_ = true ;
289   }
290   
291   void CAxis::resetGeometricAttributes(void)
292   {
293     n_glo.reset();
294     index.reset();
295     n.reset();
296     begin.reset();
297     mask.reset();
298     data_index.reset();
299     data_n.reset();
300     data_begin.reset();
301     value.reset();
302     bounds.reset();
303     label.reset() ;
304   }
305
306   void CAxis::setGeometricAttributes(const CAxis& axisSrc)
307   {
308     resetGeometricAttributes() ;
309     n_glo=axisSrc.n_glo;
310     if (!axisSrc.index.isEmpty())
311     {
312       index.resize(axisSrc.index.shape()) ;
313       index=axisSrc.index;
314     }
315
316     n=axisSrc.n;
317     begin=axisSrc.begin;
318     if (!axisSrc.mask.isEmpty())
319     {
320       mask.resize(axisSrc.mask.shape()) ;
321       mask=axisSrc.mask;
322     }
323     if (!axisSrc.data_index.isEmpty())
324     {
325       data_index.resize(axisSrc.data_index.shape()) ;
326       data_index=axisSrc.data_index;
327     }
328     data_n=axisSrc.data_n;
329     data_begin=axisSrc.data_begin;
330     if (!axisSrc.value.isEmpty())
331     {
332       value.resize(axisSrc.value.shape()) ;
333       value=axisSrc.value;
334     }
335     
336     if (!axisSrc.bounds.isEmpty())
337     {
338       bounds.resize(axisSrc.bounds.shape()) ;
339       bounds=axisSrc.bounds;
340     }
341     if (!axisSrc.label.isEmpty())
342     {
343       label.resize(axisSrc.label.shape()) ;
344       label=axisSrc.label;
345     }
346
347   }
348   
349   bool CAxis::checkGeometricAttributes(bool generateError)
[1622]350   TRY
[219]351   {
[1637]352     CContext* context=CContext::getCurrent();
353
354     if (this->n_glo.isEmpty())
[2291]355        if (generateError) ERROR("CAxis::checkAttributes(void)",
356                                << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
357                                << "The axis is wrongly defined, attribute 'n_glo' must be specified")
358        else return false ; 
[666]359      StdSize size = this->n_glo.getValue();
[540]360
[970]361      if (!this->index.isEmpty())
[551]362      {
[970]363        if (n.isEmpty()) n = index.numElements();
364
365        // It's not so correct but if begin is not the first value of index
366        // then data on the local axis has user-defined distribution. In this case, begin has no meaning.
367        if (begin.isEmpty()) begin = index(0);         
[551]368      }
[970]369      else 
370      {
371        if (!this->begin.isEmpty())
372        {
373          if (begin < 0 || begin > size - 1)
[2291]374             if (generateError) ERROR("CAxis::checkAttributes(void)",
375                                      << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
376                                      << "The axis is wrongly defined, attribute 'begin' (" 
377                                      << begin.getValue() << ") must be non-negative and smaller than size-1 (" << size - 1 << ").")
378              else return false ; 
[970]379        }
380        else this->begin.setValue(0);
[551]381
[970]382        if (!this->n.isEmpty())
383        {
384          if (n < 0 || n > size)
[2291]385            if (generateError) ERROR("CAxis::checkAttributes(void)",
386                                      << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
387                                      << "The axis is wrongly defined, attribute 'n' (" << n.getValue() << ") must be non-negative and smaller than size (" 
388                                      << size << ").")
389            else return false ; 
[970]390        }
391        else this->n.setValue(size);
392
393        {
394          index.resize(n);
395          for (int i = 0; i < n; ++i) index(i) = i+begin;
396        }
[551]397      }
[624]398
[816]399      if (!this->value.isEmpty())
400      {
[1869]401        StdSize true_size = value.numElements();
402        if (this->n.getValue() != true_size)
[2291]403          if (generateError) ERROR("CAxis::checkAttributes(void)",
404                                   << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
405                                   << "The axis is wrongly defined, attribute 'value' has a different size (" << true_size
406                                   << ") than the one defined by the \'size\' attribute (" << n.getValue() << ").")
407          else return false ; 
[816]408        this->hasValue = true;
409      }
[219]410
[2291]411      if (!this->checkBounds(generateError)) return false;
412      if (!this->checkMask(generateError))   return false;
413      if (!this->checkData(generateError))   return false;
414      if (!this->checkLabel(generateError))  return false;
415     
416      return true ;
[219]417   }
[1622]418   CATCH_DUMP_ATTR
[219]419
[1918]420
[1144]421   /*!
[1637]422      Check the validity of data, fill in values if any, and apply mask.
[1144]423   */
[2291]424   bool CAxis::checkData(bool generateError)
[1622]425   TRY
[551]426   {
427      if (data_begin.isEmpty()) data_begin.setValue(0);
[679]428
429      if (data_n.isEmpty())
[551]430      {
[679]431        data_n.setValue(n);
432      }
433      else if (data_n.getValue() < 0)
434      {
[2291]435        if (generateError) ERROR("CAxis::checkData(void)",
436                              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
437                              << "The data size should be strictly positive ('data_n' = " << data_n.getValue() << ").")
438        else return false ;
[551]439      }
440
441      if (data_index.isEmpty())
442      {
[679]443        data_index.resize(data_n);
[1637]444        for (int i = 0; i < data_n; ++i)
445        {
446          if ((i+data_begin) >= 0 && (i+data_begin<n))
447          {
448            if (mask(i+data_begin))
449              data_index(i) = i+data_begin;
450            else
451              data_index(i) = -1;
452          }
453          else
454            data_index(i) = -1;
455        }
[551]456      }
[1637]457      else
458      {
459        if (data_index.numElements() != data_n)
460        {
[2291]461          if (generateError) ERROR("CAxis::checkData(void)",
462                               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
463                               << "The size of data_index = "<< data_index.numElements() << "is not equal to the data size data_n = " 
464                               << data_n.getValue() << ").")
465          else return false ;
[1637]466        }
467        for (int i = 0; i < data_n; ++i)
468        {
[1872]469           if (data_index(i) >= 0 && data_index(i)<n)
470             if (!mask(data_index(i))) data_index(i) = -1;
[1637]471        }
472      }
[2291]473      return true ;
[551]474   }
[1622]475   CATCH_DUMP_ATTR
[551]476
[2291]477/*!
478   Check validity of mask info and fill in values if any.
479  */
480   bool CAxis::checkMask(bool generateError)
[1622]481   TRY
[551]482   {
483      if (!mask.isEmpty())
484      {
[1637]485        if (mask.extent(0) != n)
486        {
[2291]487          if (generateError) ERROR("CAxis::checkMask(void)",
488                                  << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
489                                  << "The mask does not have the same size as the local domain." << std::endl
490                                  << "Local size is " << n.getValue() << "." << std::endl
491                                  << "Mask size is " << mask.extent(0) << ".")
492          else return false ;
[1637]493        }
[551]494      }
[1637]495      else
496      {
497        mask.resize(n);
498        mask = true;
[551]499      }
[2291]500      return true ;
[551]501   }
[1622]502   CATCH_DUMP_ATTR
[551]503
[1144]504   /*!
505     Check validity of bounds info and fill in values if any.
506   */
[2291]507   bool CAxis::checkBounds(bool generateError)
[1622]508   TRY
[1144]509   {
510     if (!bounds.isEmpty())
511     {
512       if (bounds.extent(0) != 2 || bounds.extent(1) != n)
[2291]513         if (generateError) ERROR("CAxis::checkAttributes(void)",
514                               << "The bounds array of the axis [ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] must be of dimension 2 x axis size." << std::endl
515                               << "Axis size is " << n.getValue() << "." << std::endl
516                               << "Bounds size is "<< bounds.extent(0) << " x " << bounds.extent(1) << ".")
517         else return false ;
[1235]518       hasBounds = true;
[1144]519     }
[1235]520     else hasBounds = false;
[2291]521     return true ;
[1144]522   }
[1622]523   CATCH_DUMP_ATTR
[633]524
[2291]525  bool CAxis::checkLabel(bool generateError)
[1622]526  TRY
[1158]527  {
528    if (!label.isEmpty())
529    {
530      if (label.extent(0) != n)
[2291]531        if (generateError) ERROR("CAxis::checkLabel(void)",
532                              << "The label array of the axis [ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] must be of dimension of axis size." << std::endl
533                              << "Axis size is " << n.getValue() << "." << std::endl
534                              << "label size is "<< label.extent(0)<<  " .")
535        else return false ;
[1158]536      hasLabel = true;
537    }
538    else hasLabel = false;
[2291]539    return true ;
[1158]540  }
[1622]541  CATCH_DUMP_ATTR
[1202]542
[2291]543
544  size_t CAxis::getGlobalWrittenSize(void)
545  {
546    return n_glo ;
547  }
548
549   
550
[1956]551 
[1235]552  /*!
553    Dispatch event from the lower communication layer then process event according to its type
554  */
555  bool CAxis::dispatchEvent(CEventServer& event)
[1622]556  TRY
[1235]557  {
558     if (SuperClass::dispatchEvent(event)) return true;
559     else
560     {
561       switch(event.type)
562       {
[1930]563         case EVENT_ID_AXIS_DISTRIBUTION:
564           recvAxisDistribution(event);
565           return true;
566           break;
567         case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
[1235]568           recvDistributedAttributes(event);
569           return true;
570           break;
571          default :
572            ERROR("bool CAxis::dispatchEvent(CEventServer& event)",
573                   << "Unknown Event");
574          return false;
575        }
576     }
577  }
[1622]578  CATCH
[567]579
[1975]580   /* to remove later when reimplementing coupling */
[1875]581   void CAxis::sendAxisToCouplerOut(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid, const string& fieldId, int posInGrid)
582   {
[1975]583     if (sendAxisToCouplerOut_done_.count(client)!=0) return ;
584     else sendAxisToCouplerOut_done_.insert(client) ;
[1875]585     
586     string axisId="_axis["+std::to_string(posInGrid)+"]_of_"+fieldId ;
587
588    }
589
[2022]590  string CAxis::getCouplingAlias(const string& fieldId, int posInGrid)
591  {
592    return "_axis["+std::to_string(posInGrid)+"]_of_"+fieldId ;
593  }
594
[1875]595  void CAxis::makeAliasForCoupling(const string& fieldId, int posInGrid)
596  {
[2022]597    const string axisId = getCouplingAlias(fieldId,posInGrid)  ;
[1875]598    this->createAlias(axisId) ;
599  }
600
[1975]601 
[1144]602  /*!
[1158]603    Compare two axis objects.
604    They are equal if only if they have identical attributes as well as their values.
605    Moreover, they must have the same transformations.
606  \param [in] axis Compared axis
607  \return result of the comparison
608  */
609  bool CAxis::isEqual(CAxis* obj)
[1622]610  TRY
[1158]611  {
612    vector<StdString> excludedAttr;
613    excludedAttr.push_back("axis_ref");
[987]614
[1158]615    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
616    if (!objEqual) return objEqual;
617
618    TransMapTypes thisTrans = this->getAllTransformations();
619    TransMapTypes objTrans  = obj->getAllTransformations();
620
621    TransMapTypes::const_iterator it, itb, ite;
622    std::vector<ETranformationType> thisTransType, objTransType;
623    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
624      thisTransType.push_back(it->first);
625    for (it = objTrans.begin(); it != objTrans.end(); ++it)
626      objTransType.push_back(it->first);
627
628    if (thisTransType.size() != objTransType.size()) return false;
629    for (int idx = 0; idx < thisTransType.size(); ++idx)
630      objEqual &= (thisTransType[idx] == objTransType[idx]);
631
632    return objEqual;
633  }
[1622]634  CATCH_DUMP_ATTR
[1158]635
[1235]636  /*
637    Add transformation into axis. This function only servers for Fortran interface
638    \param [in] transType transformation type
639    \param [in] id identifier of the transformation object
640  */
[836]641  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
[1622]642  TRY
[836]643  {
644    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
645    return transformationMap_.back().second;
646  }
[1622]647  CATCH_DUMP_ATTR
[836]648
[1235]649  /*
650    Check whether an axis has (spatial) transformation
651  */
[619]652  bool CAxis::hasTransformation()
[1622]653  TRY
[619]654  {
[621]655    return (!transformationMap_.empty());
[619]656  }
[1622]657  CATCH_DUMP_ATTR
[619]658
[1235]659  /*
660    Set transformation
661    \param [in] axisTrans transformation to set
662  */
[621]663  void CAxis::setTransformations(const TransMapTypes& axisTrans)
[1622]664  TRY
[619]665  {
[621]666    transformationMap_ = axisTrans;
[619]667  }
[1622]668  CATCH_DUMP_ATTR
[619]669
[1235]670  /*
671    Return all transformation held by the axis
672    \return transformation the axis has
673  */
[621]674  CAxis::TransMapTypes CAxis::getAllTransformations(void)
[1622]675  TRY
[620]676  {
[621]677    return transformationMap_;
678  }
[1622]679  CATCH_DUMP_ATTR
[620]680
[1235]681  /*
682    Duplicate transformation of another axis
683    \param [in] src axis whose transformations are copied
684  */
[823]685  void CAxis::duplicateTransformation(CAxis* src)
[1622]686  TRY
[823]687  {
688    if (src->hasTransformation())
689    {
690      this->setTransformations(src->getAllTransformations());
691    }
692  }
[1622]693  CATCH_DUMP_ATTR
[823]694
[747]695  /*!
696   * Go through the hierarchy to find the axis from which the transformations must be inherited
697   */
[1984]698  void CAxis::solveInheritanceTransformation_old()
[1622]699  TRY
[619]700  {
[747]701    if (hasTransformation() || !hasDirectAxisReference())
702      return;
[619]703
[747]704    CAxis* axis = this;
[619]705    std::vector<CAxis*> refAxis;
[747]706    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
[619]707    {
[747]708      refAxis.push_back(axis);
709      axis = axis->getDirectAxisReference();
[619]710    }
711
[747]712    if (axis->hasTransformation())
713      for (size_t i = 0; i < refAxis.size(); ++i)
714        refAxis[i]->setTransformations(axis->getAllTransformations());
[619]715  }
[1622]716  CATCH_DUMP_ATTR
[619]717
[1984]718  void CAxis::solveInheritanceTransformation()
719  TRY
720  {
721    if (solveInheritanceTransformation_done_) return;
722    else solveInheritanceTransformation_done_=true ;
723
724    CAxis* axis = this;
725    std::list<CAxis*> refAxis;
726    bool out=false ;
727    vector<StdString> excludedAttr;
728    excludedAttr.push_back("axis_ref");
729   
730    refAxis.push_front(axis) ;
731    while (axis->hasDirectAxisReference() && !out)
732    {
733      CAxis* lastAxis=axis ;
734      axis = axis->getDirectAxisReference();
735      axis->solveRefInheritance() ;
736      if (!axis->SuperClass::isEqual(lastAxis,excludedAttr)) out=true ;
737      refAxis.push_front(axis) ;
738    }
739
740    CTransformationPaths::TPath path ;
741    auto& pathList = std::get<2>(path) ;
742    std::get<0>(path) = EElement::AXIS ;
743    std::get<1>(path) = refAxis.front()->getId() ;
744    for (auto& axis : refAxis)
745    {
746      CAxis::TransMapTypes transformations = axis->getAllTransformations();
747      for(auto& transformation : transformations) pathList.push_back({transformation.second->getTransformationType(), 
748                                                                      transformation.second->getId()}) ;
749    }
750    transformationPaths_.addPath(path) ;
751
752  }
753  CATCH_DUMP_ATTR
754
[2206]755  bool CAxis::activateFieldWorkflow(CGarbageCollector& gc)
756  TRY
757  {
758    if (!axis_ref.isEmpty())
759    {
760      CField* field=getFieldFromId(axis_ref) ;
761      if (field!=nullptr)
762      {
763        bool ret = field->buildWorkflowGraph(gc) ;
764        if (!ret) return false ; // cannot build workflow graph at this state
765      }
766      else 
767      {
768        CAxis* axis = get(axis_ref) ;
769        bool ret = axis->activateFieldWorkflow(gc) ;
770        if (!ret) return false ; // cannot build workflow graph at this state
771        axis_ref=axis->getId() ; // replace domain_ref by solved reference
772      }
773    }
774    activateFieldWorkflow_done_=true ;
775    return true ;
776  }
777  CATCH_DUMP_ATTR
778
779
[1345]780  void CAxis::setContextClient(CContextClient* contextClient)
[1622]781  TRY
[1345]782  {
[1353]783    if (clientsSet.find(contextClient)==clientsSet.end())
784    {
785      clients.push_back(contextClient) ;
786      clientsSet.insert(contextClient);
787    }
[1622]788  }
789  CATCH_DUMP_ATTR
[1345]790
[619]791  void CAxis::parse(xml::CXMLNode & node)
[1622]792  TRY
[619]793  {
794    SuperClass::parse(node);
795
796    if (node.goToChildElement())
797    {
[836]798      StdString nodeElementName;
[619]799      do
800      {
[784]801        StdString nodeId("");
802        if (node.getAttributes().end() != node.getAttributes().find("id"))
803        { nodeId = node.getAttributes()["id"]; }
804
[836]805        nodeElementName = node.getElementName();
806        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
807        it = transformationMapList_.find(nodeElementName);
808        if (ite != it)
809        {
810          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
811                                                                                                               nodeId,
812                                                                                                               &node)));
[786]813        }
[968]814        else
815        {
816          ERROR("void CAxis::parse(xml::CXMLNode & node)",
817                << "The transformation " << nodeElementName << " has not been supported yet.");
818        }
[619]819      } while (node.goToNextElement()) ;
820      node.goToParentElement();
821    }
822  }
[1622]823  CATCH_DUMP_ATTR
[619]824
[1930]825
826   //////////////////////////////////////////////////////////////////////////////////////
827   //  this part is related to distribution, element definition, views and connectors  //
828   //////////////////////////////////////////////////////////////////////////////////////
829
830   void CAxis::initializeLocalElement(void)
831   {
832      // after checkAttribute index of size n
833      int rank = CContext::getCurrent()->getIntraCommRank() ;
834     
835      CArray<size_t,1> ind(n) ;
836      for (int i=0;i<n;i++) ind(i)=index(i) ;
837
[2267]838      localElement_ = make_shared<CLocalElement>(rank, n_glo, ind) ;
[1930]839   }
840
841   void CAxis::addFullView(void)
842   {
843      CArray<int,1> index(n) ;
844      for(int i=0; i<n ; i++) index(i)=i ;
845      localElement_ -> addView(CElementView::FULL, index) ;
846   }
847
848   void CAxis::addWorkflowView(void)
849   {
850     // mask + data are included into data_index
851     int nk=data_index.numElements() ;
852     int nMask=0 ;
853     for(int k=0;k<nk;k++) if (data_index(k)>=0 && data_index(k)<n) nMask++ ;
854     
855     CArray<int,1> index(nMask) ;
856     nMask=0 ;
857     for(int k=0;k<nk;k++) 
858       if (data_index(k)>=0 && data_index(k)<n) 
859       {
860         index(nMask) = data_index(k) ;
861         nMask++ ;
862       }
863     localElement_ -> addView(CElementView::WORKFLOW, index) ;
864   }
865
866   void CAxis::addModelView(void)
867   {
868     // information for model view is stored in data_index
869     localElement_->addView(CElementView::MODEL, data_index) ;
870   }
871
872   void CAxis::computeModelToWorkflowConnector(void)
873   { 
[2267]874     shared_ptr<CLocalView> srcView=getLocalView(CElementView::MODEL) ;
875     shared_ptr<CLocalView> dstView=getLocalView(CElementView::WORKFLOW) ;
876     modelToWorkflowConnector_ = make_shared<CLocalConnector>(srcView, dstView); 
[1930]877     modelToWorkflowConnector_->computeConnector() ;
878   }
879
880
881   void CAxis::computeRemoteElement(CContextClient* client, EDistributionType type)
882  {
883    CContext* context = CContext::getCurrent();
884    map<int, CArray<size_t,1>> globalIndex ;
885
886    if (type==EDistributionType::BANDS) // Bands distribution to send to file server
887    {
888      int nbServer = client->serverSize;
889      int nbClient = client->clientSize ;
890      int rankClient = client->clientRank ;
891      int size = nbServer / nbClient ;
892      int start ;
893      if (nbServer%nbClient > rankClient)
894      {
895       start = (size+1) * rankClient ;
896       size++ ;
897      }
898      else start = size*rankClient + nbServer%nbClient ;
899     
900      for(int i=0; i<size; i++)
901      { 
902        int rank=start+i ; 
903        size_t indSize = n_glo/nbServer ;
904        size_t indStart ;
905        if (n_glo % nbServer > rank)
906        {
907          indStart = (indSize+1) * rank ;
908          indSize++ ;
909        }
910        else indStart = indSize*rank + n_glo%nbServer ;
911       
912        auto& globalInd =  globalIndex[rank] ;
913        globalInd.resize(indSize) ;
914        for(size_t n = 0 ; n<indSize; n++) globalInd(n)=indStart+n ;
915      }
916    }
917    else if (type==EDistributionType::NONE) // domain is not distributed ie all servers get the same local domain
918    {
919      int nbServer = client->serverSize;
920      size_t nglo=n_glo ;
921      CArray<size_t,1> indGlo(nglo) ;
922      for(size_t i=0;i<nglo;i++) indGlo(i) = i ;
[1939]923      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer].reference(indGlo.copy()); 
[1930]924    }
[2267]925    remoteElement_[client] = make_shared<CDistributedElement>(n_glo, globalIndex) ;
[1930]926    remoteElement_[client]->addFullView() ;
927  }
928 
[2304]929  void CAxis::distributeToServer(CContextClient* client, std::map<int, CArray<size_t,1>>& globalIndexOut, std::map<int, CArray<size_t,1>>& globalIndexIn, 
[2267]930                                 shared_ptr<CScattererConnector> &scattererConnector, const string& axisId)
[1930]931  {
932    string serverAxisId = axisId.empty() ? this->getId() : axisId ;
933    CContext* context = CContext::getCurrent();
934
935    this->sendAllAttributesToServer(client, serverAxisId)  ;
936
[2304]937    auto scatteredElement = make_shared<CDistributedElement>(n_glo,globalIndexOut) ;
[2267]938    scatteredElement->addFullView() ;
939    scattererConnector = make_shared<CScattererConnector>(localElement_->getView(CElementView::FULL), scatteredElement->getView(CElementView::FULL), 
940                                                          context->getIntraComm(), client->getRemoteSize()) ;
[1956]941    scattererConnector->computeConnector() ;
[1930]942   
943    // phase 0
944    // send remote element to construct the full view on server, ie without hole
945    CEventClient event0(getType(), EVENT_ID_AXIS_DISTRIBUTION);
946    CMessage message0 ;
947    message0<<serverAxisId<<0 ; 
948    remoteElement_[client]->sendToServer(client,event0,message0) ; 
949   
950    // phase 1
951    // send the full view of element to construct the connector which connect distributed data coming from client to the full local view
952    CEventClient event1(getType(), EVENT_ID_AXIS_DISTRIBUTION);
953    CMessage message1 ;
954    message1<<serverAxisId<<1<<localElement_->getView(CElementView::FULL)->getGlobalSize() ; 
[1956]955    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
[1930]956
[2267]957    sendDistributedAttributes(client, scattererConnector, axisId) ;
[1930]958 
959    // phase 2 send the mask : data index + mask2D
[2304]960    {
961      CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
962      CArray<bool,1> maskOut ;
963      auto workflowToFull = make_shared<CLocalConnector>(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
964      workflowToFull->computeConnector() ;
965      maskIn=true ;
966      workflowToFull->transfer(maskIn,maskOut,false) ;
[1930]967
[2304]968      //  prepare grid scatterer connector to send data from client to server
969      map<int,CArray<size_t,1>> workflowGlobalIndex ;
970      map<int,CArray<bool,1>> maskOut2 ; 
971      scattererConnector->transfer(maskOut, maskOut2) ;
972      scatteredElement->addView(CElementView::WORKFLOW, maskOut2) ;
973      scatteredElement->getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
974      // create new workflow view for scattered element
975      auto clientToServerElement = make_shared<CDistributedElement>(scatteredElement->getGlobalSize(), workflowGlobalIndex) ;
976      clientToServerElement->addFullView() ;
977      CEventClient event2(getType(), EVENT_ID_AXIS_DISTRIBUTION);
978      CMessage message2 ;
979      message2<<serverAxisId<<2 ; 
980      clientToServerElement->sendToServer(client, event2, message2) ; 
981      clientToServerConnector_[client] = make_shared<CScattererConnector>(localElement_->getView(CElementView::WORKFLOW), clientToServerElement->getView(CElementView::FULL), 
[2267]982                                                                        context->getIntraComm(), client->getRemoteSize()) ;
[2304]983      clientToServerConnector_[client]->computeConnector() ;
984    }
[1930]985
[2304]986    ////////////
987    // phase 3 : compute connector to receive from server
988    ////////////
989    {
990      auto scatteredElement = make_shared<CDistributedElement>(n_glo, globalIndexIn) ;
991      scatteredElement->addFullView() ;
992      auto scattererConnector = make_shared<CScattererConnector>(localElement_->getView(CElementView::FULL), scatteredElement->getView(CElementView::FULL), 
993                                                                 context->getIntraComm(), client->getRemoteSize()) ;
994      scattererConnector->computeConnector() ;
995      CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
996      CArray<bool,1> maskOut ;
997      auto workflowToFull = make_shared<CLocalConnector>(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
998      workflowToFull->computeConnector() ;
999      maskIn=true ;
1000      workflowToFull->transfer(maskIn,maskOut,false) ;
[1930]1001
[2304]1002      map<int,CArray<size_t,1>> workflowGlobalIndex ;
1003      map<int,CArray<bool,1>> maskOut2 ; 
1004      scattererConnector->transfer(maskOut, maskOut2, false) ;
1005      scatteredElement->addView(CElementView::WORKFLOW, maskOut2) ;
1006      scatteredElement->getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
1007      auto clientToServerElement = make_shared<CDistributedElement>(scatteredElement->getGlobalSize(), workflowGlobalIndex) ;
1008      clientToServerElement->addFullView() ;
1009      CEventClient event3(getType(), EVENT_ID_AXIS_DISTRIBUTION);
1010      CMessage message3 ;
1011      message3<<serverAxisId<<3 ; 
1012      clientToServerElement->sendToServer(client, event3, message3) ; 
[1930]1013
[2304]1014      clientFromServerConnector_[client] = make_shared<CGathererConnector>(clientToServerElement->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1015      clientFromServerConnector_[client]->computeConnector() ;     
1016    }
1017
1018//    clientFromServerConnector_[client] = make_shared<CGathererConnector>(clientToServerElement->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1019//    clientFromServerConnector_[client]->computeConnector() ;
1020
1021
[1930]1022  }
1023
1024  void CAxis::recvAxisDistribution(CEventServer& event)
1025  TRY
1026  {
1027    string axisId;
1028    int phasis ;
1029    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> axisId >> phasis ;
1030    get(axisId)->receivedAxisDistribution(event, phasis);
1031  }
1032  CATCH
1033
1034
1035  void CAxis::receivedAxisDistribution(CEventServer& event, int phasis)
1036  TRY
1037  {
1038    CContext* context = CContext::getCurrent();
1039    if (phasis==0) // receive the remote element to construct the full view
1040    {
[2267]1041      localElement_ = make_shared<CLocalElement>(context->getIntraCommRank(),event) ;
[1930]1042      localElement_->addFullView() ;
1043      // construct the local dimension and indexes
1044      auto& globalIndex=localElement_->getGlobalIndex() ;
1045      int nk=globalIndex.numElements() ;
1046      int minK=n_glo,maxK=-1 ;
1047      int nGlo=n_glo ;
1048      int indGlo ;
1049      for(int k=0;k<nk;k++)
1050      {
1051        indGlo=globalIndex(k) ;
1052        if (indGlo<minK) minK=indGlo ;
1053        if (indGlo>maxK) maxK=indGlo ;
1054      } 
1055      if (maxK>=minK) { begin=minK ; n=maxK-minK+1 ; }
1056      else {begin=0; n=0 ;}
1057
1058    }
1059    else if (phasis==1) // receive the sent view from client to construct the full distributed full view on server
1060    {
1061      CContext* context = CContext::getCurrent();
[2267]1062      shared_ptr<CDistributedElement> elementFrom = make_shared<CDistributedElement>(event) ;
[1930]1063      elementFrom->addFullView() ;
[2267]1064      gathererConnector_ = make_shared<CGathererConnector>(elementFrom->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
[1930]1065      gathererConnector_->computeConnector() ; 
1066    }
1067    else if (phasis==2)
1068    {
[1956]1069//      delete gathererConnector_ ;
[2267]1070      elementFrom_ = make_shared<CDistributedElement>(event) ;
[1930]1071      elementFrom_->addFullView() ;
[2267]1072//      gathererConnector_ =  make_shared<CGathererConnector>(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
[1956]1073//      gathererConnector_ -> computeConnector() ;
[1930]1074    }
[2304]1075    else if (phasis==3)
1076    {
1077      elementTo_ = make_shared<CDistributedElement>(event) ;
1078      elementTo_->addFullView() ;
1079    }
[1930]1080  }
1081  CATCH
1082
[1943]1083  void CAxis::setServerMask(CArray<bool,1>& serverMask, CContextClient* client)
1084  TRY
1085  {
1086    CContext* context = CContext::getCurrent();
1087    localElement_->addView(CElementView::WORKFLOW, serverMask) ;
1088    mask.reference(serverMask.copy()) ;
1089 
[2267]1090    serverFromClientConnector_ = make_shared<CGathererConnector>(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW)) ;
[1943]1091    serverFromClientConnector_->computeConnector() ;
1092     
[2304]1093    serverToClientConnector_ = make_shared<CScattererConnector>(localElement_->getView(CElementView::WORKFLOW), elementTo_->getView(CElementView::FULL),
[2267]1094                                                                context->getIntraComm(), client->getRemoteSize()) ;
[1943]1095    serverToClientConnector_->computeConnector() ;
1096  }
1097  CATCH_DUMP_ATTR
1098
[2267]1099  void CAxis::sendDistributedAttributes(CContextClient* client, shared_ptr<CScattererConnector> scattererConnector, const string& axisId)
[1930]1100  {
1101    string serverAxisId = axisId.empty() ? this->getId() : axisId ;
1102    CContext* context = CContext::getCurrent();
1103
1104    if (hasValue)
1105    {
1106      { // send level value
1107        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1108        CMessage message ;
1109        message<<serverAxisId<<string("value") ; 
[2267]1110        scattererConnector->transfer(value, client, event,message) ;
[1930]1111      }
1112    }
1113
1114    if (hasBounds)
1115    {
1116      { // send bounds level value
1117        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1118        CMessage message ;
1119        message<<serverAxisId<<string("bounds") ; 
[2267]1120        scattererConnector->transfer(2, bounds, client, event,message) ;
[1930]1121      }
1122    }
1123
1124    if (hasLabel)
1125    {
1126      { // send label
[1950]1127        // need to transform array of string (no fixed size for string) into array of array of char
1128        // to use connector to transfer
1129        // the strings must have fixed size which the maximum lenght over the string label. 
1130        int maxSize=0 ;
1131        for(int i=0; i<label.numElements();i++) 
1132          if (maxSize < label(i).size()) maxSize=label(i).size() ;
1133        MPI_Allreduce(MPI_IN_PLACE, &maxSize,1,MPI_INT,MPI_MAX, context->getIntraComm()) ;
1134        maxSize=maxSize+1 ;
1135        CArray<char,2> charArray(maxSize,label.numElements()) ;
1136        for(int j=0; j<label.numElements();j++) 
1137        {
1138          const char* str = label(j).c_str() ;
1139          int strSize=label(j).size()+1 ;
1140          for(int i=0; i<strSize; i++) charArray(i,j) = str[i] ;
1141        }
[1930]1142        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1143        CMessage message ;
[1950]1144        message<<serverAxisId<<string("label")<<maxSize ;
[2267]1145        scattererConnector->transfer(maxSize, charArray, client, event,message) ;
[1930]1146      }
1147    }
1148  }
1149
1150  void CAxis::recvDistributedAttributes(CEventServer& event)
1151  TRY
1152  {
1153    string axisId;
1154    string type ;
1155    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> axisId >> type ;
1156    get(axisId)->recvDistributedAttributes(event, type);
1157  }
1158  CATCH
1159
1160  void CAxis::recvDistributedAttributes(CEventServer& event, const string& type)
1161  TRY
1162  {
1163    if (type=="value") 
1164    {
1165      gathererConnector_->transfer(event, value, 0.); 
1166    }
1167    else if (type=="bounds")
1168    {
1169      CArray<double,1> value ;
1170      gathererConnector_->transfer(event, 2, value, 0.); 
1171      bounds.resize(2,n) ;
[1950]1172      if (bounds.numElements() > 0 ) bounds=CArray<double,2>(value.dataFirst(),shape(2,n),neverDeleteData) ; 
[1930]1173    }
1174    else if (type=="label")
1175    {
[1950]1176      int maxSize ;
1177      for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> maxSize ;
1178      CArray<char,1> value ;
1179      gathererConnector_->transfer(event, maxSize, value, '\0'); 
1180      CArray<char,2> charArray(maxSize,n) ;
1181      label.resize(n) ;
1182      if (n>0)
1183      {
1184        charArray=CArray<char,2>(value.dataFirst(),shape(maxSize,n),neverDeleteData) ;
1185        for(int j=0;j<n;j++)
1186        {
1187          int strSize ;
1188          for(int i=0;i<maxSize;i++) 
1189            if (charArray(i,j)=='\0') { strSize=i ; break; }
1190          string str(strSize,'\0') ;
1191          for(int i=0;i<strSize;i++) str[i]=charArray(i,j) ; 
1192          label(j)=str ;
1193        }
1194      } 
[1930]1195    }
1196  }
1197  CATCH
1198
[620]1199  DEFINE_REF_FUNC(Axis,axis)
[619]1200
[219]1201   ///---------------------------------------------------------------
1202
[335]1203} // namespace xios
Note: See TracBrowser for help on using the repository browser.