source: XIOS3/trunk/src/node/axis.cpp

Last change on this file was 2632, checked in by ymipsl, 6 weeks ago
  • Recheck grid/domain/axis/scalar after reading grid from file, otherwise some attributes are not taking into account.

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