source: XIOS3/dev/XIOS_ATTACHED/src/node/axis.cpp @ 2482

Last change on this file since 2482 was 2482, checked in by ymipsl, 15 months ago

First guess in supression of attached mode replaced by online reader and write filters

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: 43.5 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(void)
282   {
283      if (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     // Compute the hash of distributed attributs (value ...)
311     int globalSize = this->n_glo.getValue();
312     CArray<size_t,1> globalIndex; // No redundancy globalIndex will be computed with the connector
313     shared_ptr<CGridTransformConnector> gridTransformConnector;
314     // Compute a without redundancy element FULL view to enable a consistent hash computation (and a distributed globalIndex)
315     this->getLocalView(CElementView::FULL)->createWithoutRedundancyFullViewConnector( globalSize, comm, gridTransformConnector, globalIndex );
316     int localSize = globalIndex.numElements();
317
318     CArray<double,1> distributedValue ;
319     gridTransformConnector->transfer(this->value, distributedValue );
320       
321     size_t localHash = 0;
322     for (int iloc=0; iloc<localSize ; iloc++ ) localHash+=globalIndex(iloc)*distributedValue(iloc);
323     size_t distributedHash = 0;
324     MPI_Allreduce( &localHash, &distributedHash, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm  );
325
326     // Compute the hash of global attributs (unit, prec ...)
327     vector<StdString> excludedAttr;
328     //excludedAttr.push_back("name");
329     // internal attributs
330     excludedAttr.insert(excludedAttr.end(), { "index", "data_n", "data_begin", "data_index"  });
331     excludedAttr.insert(excludedAttr.end(), { "begin", "n" });     
332     excludedAttr.push_back("axis_ref");
333     // in distributed
334     excludedAttr.push_back("value");
335     // should be considered in distributed
336     excludedAttr.push_back("bounds");
337     excludedAttr.push_back("label");
338     excludedAttr.push_back("mask"); // ???
339
340     size_t globalHash = this->computeGlobalAttributesHash( excludedAttr );
341
342     return distributedHash + globalHash;
343   }
344 
345   void CAxis::renameAttributesBeforeWriting(CAxis* writtenAxis)
346   {
347     if (writtenAxis!=NULL)
348     {
349       this->name = writtenAxis->getAxisOutputName();
350       // + label if necessary, other attributs concerned ?
351     }
352     else
353     {
354       this->name =  this->getId();
355       // + label if necessary, other attributs concerned ?
356     }
357   }
358 
359   void CAxis::setGeometricAttributes(const CAxis& axisSrc)
360   {
361     resetGeometricAttributes() ;
362     n_glo=axisSrc.n_glo;
363     if (!axisSrc.index.isEmpty())
364     {
365       index.resize(axisSrc.index.shape()) ;
366       index=axisSrc.index;
367     }
368
369     n=axisSrc.n;
370     begin=axisSrc.begin;
371     if (!axisSrc.mask.isEmpty())
372     {
373       mask.resize(axisSrc.mask.shape()) ;
374       mask=axisSrc.mask;
375     }
376     if (!axisSrc.data_index.isEmpty())
377     {
378       data_index.resize(axisSrc.data_index.shape()) ;
379       data_index=axisSrc.data_index;
380     }
381     data_n=axisSrc.data_n;
382     data_begin=axisSrc.data_begin;
383     if (!axisSrc.value.isEmpty())
384     {
385       value.resize(axisSrc.value.shape()) ;
386       value=axisSrc.value;
387     }
388     
389     if (!axisSrc.bounds.isEmpty())
390     {
391       bounds.resize(axisSrc.bounds.shape()) ;
392       bounds=axisSrc.bounds;
393     }
394     if (!axisSrc.label.isEmpty())
395     {
396       label.resize(axisSrc.label.shape()) ;
397       label=axisSrc.label;
398     }
399
400   }
401   
402   bool CAxis::checkGeometricAttributes(bool generateError)
403   TRY
404   {
405     CContext* context=CContext::getCurrent();
406
407     if (this->n_glo.isEmpty())
408        if (generateError) ERROR("CAxis::checkAttributes(void)",
409                                << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
410                                << "The axis is wrongly defined, attribute 'n_glo' must be specified")
411        else return false ; 
412      StdSize size = this->n_glo.getValue();
413
414      if (!this->index.isEmpty())
415      {
416        if (n.isEmpty()) n = index.numElements();
417
418        // It's not so correct but if begin is not the first value of index
419        // then data on the local axis has user-defined distribution. In this case, begin has no meaning.
420        if (begin.isEmpty()) begin = index(0);         
421      }
422      else 
423      {
424        if (!this->begin.isEmpty())
425        {
426          if (begin < 0 || begin > size - 1)
427             if (generateError) ERROR("CAxis::checkAttributes(void)",
428                                      << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
429                                      << "The axis is wrongly defined, attribute 'begin' (" 
430                                      << begin.getValue() << ") must be non-negative and smaller than size-1 (" << size - 1 << ").")
431              else return false ; 
432        }
433        else this->begin.setValue(0);
434
435        if (!this->n.isEmpty())
436        {
437          if (n < 0 || n > size)
438            if (generateError) ERROR("CAxis::checkAttributes(void)",
439                                      << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
440                                      << "The axis is wrongly defined, attribute 'n' (" << n.getValue() << ") must be non-negative and smaller than size (" 
441                                      << size << ").")
442            else return false ; 
443        }
444        else this->n.setValue(size);
445
446        {
447          index.resize(n);
448          for (int i = 0; i < n; ++i) index(i) = i+begin;
449        }
450      }
451
452      if (!this->value.isEmpty())
453      {
454        StdSize true_size = value.numElements();
455        if (this->n.getValue() != true_size)
456          if (generateError) ERROR("CAxis::checkAttributes(void)",
457                                   << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
458                                   << "The axis is wrongly defined, attribute 'value' has a different size (" << true_size
459                                   << ") than the one defined by the \'size\' attribute (" << n.getValue() << ").")
460          else return false ; 
461        this->hasValue_ = true;
462      }
463
464      if (!this->checkBounds(generateError)) return false;
465      if (!this->checkMask(generateError))   return false;
466      if (!this->checkData(generateError))   return false;
467      if (!this->checkLabel(generateError))  return false;
468     
469      return true ;
470   }
471   CATCH_DUMP_ATTR
472
473
474   /*!
475      Check the validity of data, fill in values if any, and apply mask.
476   */
477   bool CAxis::checkData(bool generateError)
478   TRY
479   {
480      if (data_begin.isEmpty()) data_begin.setValue(0);
481
482      if (data_n.isEmpty())
483      {
484        data_n.setValue(n);
485      }
486      else if (data_n.getValue() < 0)
487      {
488        if (generateError) ERROR("CAxis::checkData(void)",
489                              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
490                              << "The data size should be strictly positive ('data_n' = " << data_n.getValue() << ").")
491        else return false ;
492      }
493
494      if (data_index.isEmpty())
495      {
496        data_index.resize(data_n);
497        for (int i = 0; i < data_n; ++i)
498        {
499          if ((i+data_begin) >= 0 && (i+data_begin<n))
500          {
501            if (mask(i+data_begin))
502              data_index(i) = i+data_begin;
503            else
504              data_index(i) = -1;
505          }
506          else
507            data_index(i) = -1;
508        }
509      }
510      else
511      {
512        if (data_index.numElements() != data_n)
513        {
514          if (generateError) ERROR("CAxis::checkData(void)",
515                               << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
516                               << "The size of data_index = "<< data_index.numElements() << "is not equal to the data size data_n = " 
517                               << data_n.getValue() << ").")
518          else return false ;
519        }
520        for (int i = 0; i < data_n; ++i)
521        {
522           if (data_index(i) >= 0 && data_index(i)<n)
523             if (!mask(data_index(i))) data_index(i) = -1;
524        }
525      }
526      return true ;
527   }
528   CATCH_DUMP_ATTR
529
530/*!
531   Check validity of mask info and fill in values if any.
532  */
533   bool CAxis::checkMask(bool generateError)
534   TRY
535   {
536      if (!mask.isEmpty())
537      {
538        if (mask.extent(0) != n)
539        {
540          if (generateError) ERROR("CAxis::checkMask(void)",
541                                  << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
542                                  << "The mask does not have the same size as the local domain." << std::endl
543                                  << "Local size is " << n.getValue() << "." << std::endl
544                                  << "Mask size is " << mask.extent(0) << ".")
545          else return false ;
546        }
547      }
548      else
549      {
550        mask.resize(n);
551        mask = true;
552      }
553      return true ;
554   }
555   CATCH_DUMP_ATTR
556
557   /*!
558     Check validity of bounds info and fill in values if any.
559   */
560   bool CAxis::checkBounds(bool generateError)
561   TRY
562   {
563     if (!bounds.isEmpty())
564     {
565       if (bounds.extent(0) != 2 || bounds.extent(1) != n)
566         if (generateError) ERROR("CAxis::checkAttributes(void)",
567                               << "The bounds array of the axis [ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] must be of dimension 2 x axis size." << std::endl
568                               << "Axis size is " << n.getValue() << "." << std::endl
569                               << "Bounds size is "<< bounds.extent(0) << " x " << bounds.extent(1) << ".")
570         else return false ;
571       hasBounds_ = true;
572     }
573     else hasBounds_ = false;
574     return true ;
575   }
576   CATCH_DUMP_ATTR
577
578  bool CAxis::checkLabel(bool generateError)
579  TRY
580  {
581    if (!label.isEmpty())
582    {
583      if (label.extent(0) != n)
584        if (generateError) ERROR("CAxis::checkLabel(void)",
585                              << "The label array of the axis [ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] must be of dimension of axis size." << std::endl
586                              << "Axis size is " << n.getValue() << "." << std::endl
587                              << "label size is "<< label.extent(0)<<  " .")
588        else return false ;
589      hasLabel_ = true;
590    }
591    else hasLabel_ = false;
592    return true ;
593  }
594  CATCH_DUMP_ATTR
595
596
597  size_t CAxis::getGlobalWrittenSize(void)
598  {
599    return n_glo ;
600  }
601
602   
603
604 
605  /*!
606    Dispatch event from the lower communication layer then process event according to its type
607  */
608  bool CAxis::dispatchEvent(CEventServer& event)
609  TRY
610  {
611     if (SuperClass::dispatchEvent(event)) return true;
612     else
613     {
614       switch(event.type)
615       {
616         case EVENT_ID_AXIS_DISTRIBUTION:
617           recvAxisDistribution(event);
618           return true;
619           break;
620         case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
621           recvDistributedAttributes(event);
622           return true;
623           break;
624          default :
625            ERROR("bool CAxis::dispatchEvent(CEventServer& event)",
626                   << "Unknown Event");
627          return false;
628        }
629     }
630  }
631  CATCH
632
633   /* to remove later when reimplementing coupling */
634   void CAxis::sendAxisToCouplerOut(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid, const string& fieldId, int posInGrid)
635   {
636     if (sendAxisToCouplerOut_done_.count(client)!=0) return ;
637     else sendAxisToCouplerOut_done_.insert(client) ;
638     
639     string axisId="_axis["+std::to_string(posInGrid)+"]_of_"+fieldId ;
640
641    }
642
643  string CAxis::getCouplingAlias(const string& fieldId, int posInGrid)
644  {
645    return "_axis["+std::to_string(posInGrid)+"]_of_"+fieldId ;
646  }
647
648  void CAxis::makeAliasForCoupling(const string& fieldId, int posInGrid)
649  {
650    const string axisId = getCouplingAlias(fieldId,posInGrid)  ;
651    this->createAlias(axisId) ;
652  }
653
654 
655  /*!
656    Compare two axis objects.
657    They are equal if only if they have identical attributes as well as their values.
658    Moreover, they must have the same transformations.
659  \param [in] axis Compared axis
660  \return result of the comparison
661  */
662  bool CAxis::isEqual(CAxis* obj)
663  TRY
664  {
665    vector<StdString> excludedAttr;
666    excludedAttr.push_back("axis_ref");
667
668    bool objEqual = SuperClass::isEqual(obj, excludedAttr);   
669    if (!objEqual) return objEqual;
670
671    TransMapTypes thisTrans = this->getAllTransformations();
672    TransMapTypes objTrans  = obj->getAllTransformations();
673
674    TransMapTypes::const_iterator it, itb, ite;
675    std::vector<ETranformationType> thisTransType, objTransType;
676    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
677      thisTransType.push_back(it->first);
678    for (it = objTrans.begin(); it != objTrans.end(); ++it)
679      objTransType.push_back(it->first);
680
681    if (thisTransType.size() != objTransType.size()) return false;
682    for (int idx = 0; idx < thisTransType.size(); ++idx)
683      objEqual &= (thisTransType[idx] == objTransType[idx]);
684
685    return objEqual;
686  }
687  CATCH_DUMP_ATTR
688
689  /*
690    Add transformation into axis. This function only servers for Fortran interface
691    \param [in] transType transformation type
692    \param [in] id identifier of the transformation object
693  */
694  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
695  TRY
696  {
697    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
698    return transformationMap_.back().second;
699  }
700  CATCH_DUMP_ATTR
701
702  /*
703    Check whether an axis has (spatial) transformation
704  */
705  bool CAxis::hasTransformation()
706  TRY
707  {
708    return (!transformationMap_.empty());
709  }
710  CATCH_DUMP_ATTR
711
712  /*
713    Set transformation
714    \param [in] axisTrans transformation to set
715  */
716  void CAxis::setTransformations(const TransMapTypes& axisTrans)
717  TRY
718  {
719    transformationMap_ = axisTrans;
720  }
721  CATCH_DUMP_ATTR
722
723  /*
724    Return all transformation held by the axis
725    \return transformation the axis has
726  */
727  CAxis::TransMapTypes CAxis::getAllTransformations(void)
728  TRY
729  {
730    return transformationMap_;
731  }
732  CATCH_DUMP_ATTR
733
734  /*
735    Duplicate transformation of another axis
736    \param [in] src axis whose transformations are copied
737  */
738  void CAxis::duplicateTransformation(CAxis* src)
739  TRY
740  {
741    if (src->hasTransformation())
742    {
743      this->setTransformations(src->getAllTransformations());
744    }
745  }
746  CATCH_DUMP_ATTR
747
748  /*!
749   * Go through the hierarchy to find the axis from which the transformations must be inherited
750   */
751  void CAxis::solveInheritanceTransformation_old()
752  TRY
753  {
754    if (hasTransformation() || !hasDirectAxisReference())
755      return;
756
757    CAxis* axis = this;
758    std::vector<CAxis*> refAxis;
759    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
760    {
761      refAxis.push_back(axis);
762      axis = axis->getDirectAxisReference();
763    }
764
765    if (axis->hasTransformation())
766      for (size_t i = 0; i < refAxis.size(); ++i)
767        refAxis[i]->setTransformations(axis->getAllTransformations());
768  }
769  CATCH_DUMP_ATTR
770
771  void CAxis::solveInheritanceTransformation()
772  TRY
773  {
774    if (solveInheritanceTransformation_done_) return;
775    else solveInheritanceTransformation_done_=true ;
776
777    CAxis* axis = this;
778    std::list<CAxis*> refAxis;
779    bool out=false ;
780    vector<StdString> excludedAttr;
781    excludedAttr.push_back("axis_ref");
782   
783    refAxis.push_front(axis) ;
784    while (axis->hasDirectAxisReference() && !out)
785    {
786      CAxis* lastAxis=axis ;
787      axis = axis->getDirectAxisReference();
788      axis->solveRefInheritance() ;
789      if (!axis->SuperClass::isEqual(lastAxis,excludedAttr)) out=true ;
790      refAxis.push_front(axis) ;
791    }
792
793    CTransformationPaths::TPath path ;
794    auto& pathList = std::get<2>(path) ;
795    std::get<0>(path) = EElement::AXIS ;
796    std::get<1>(path) = refAxis.front()->getId() ;
797    for (auto& axis : refAxis)
798    {
799      CAxis::TransMapTypes transformations = axis->getAllTransformations();
800      for(auto& transformation : transformations) pathList.push_back({transformation.second->getTransformationType(), 
801                                                                      transformation.second->getId()}) ;
802    }
803    transformationPaths_.addPath(path) ;
804
805  }
806  CATCH_DUMP_ATTR
807
808  bool CAxis::activateFieldWorkflow(CGarbageCollector& gc)
809  TRY
810  {
811    if (!axis_ref.isEmpty())
812    {
813      CField* field=getFieldFromId(axis_ref) ;
814      if (field!=nullptr)
815      {
816        bool ret = field->buildWorkflowGraph(gc) ;
817        if (!ret) return false ; // cannot build workflow graph at this state
818      }
819      else 
820      {
821        CAxis* axis = get(axis_ref) ;
822        bool ret = axis->activateFieldWorkflow(gc) ;
823        if (!ret) return false ; // cannot build workflow graph at this state
824        axis_ref=axis->getId() ; // replace domain_ref by solved reference
825      }
826    }
827    activateFieldWorkflow_done_=true ;
828    return true ;
829  }
830  CATCH_DUMP_ATTR
831
832
833  void CAxis::setContextClient(CContextClient* contextClient)
834  TRY
835  {
836    if (clientsSet.find(contextClient)==clientsSet.end())
837    {
838      clients.push_back(contextClient) ;
839      clientsSet.insert(contextClient);
840    }
841  }
842  CATCH_DUMP_ATTR
843
844  void CAxis::parse(xml::CXMLNode & node)
845  TRY
846  {
847    SuperClass::parse(node);
848
849    if (node.goToChildElement())
850    {
851      StdString nodeElementName;
852      do
853      {
854        StdString nodeId("");
855        if (node.getAttributes().end() != node.getAttributes().find("id"))
856        { nodeId = node.getAttributes()["id"]; }
857
858        nodeElementName = node.getElementName();
859        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
860        it = transformationMapList_.find(nodeElementName);
861        if (ite != it)
862        {
863          if (it->first == "zoom_axis")
864          {
865            info(0) << "WARNING : " << it->first << " is deprecated, replaced by extract_axis." << endl;
866          }
867          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CAxis>::createTransformation(it->second,
868                                                                                                               nodeId,
869                                                                                                               &node)));
870        }
871        else
872        {
873          ERROR("void CAxis::parse(xml::CXMLNode & node)",
874                << "The transformation " << nodeElementName << " has not been supported yet.");
875        }
876      } while (node.goToNextElement()) ;
877      node.goToParentElement();
878    }
879  }
880  CATCH_DUMP_ATTR
881
882
883   //////////////////////////////////////////////////////////////////////////////////////
884   //  this part is related to distribution, element definition, views and connectors  //
885   //////////////////////////////////////////////////////////////////////////////////////
886
887   void CAxis::initializeLocalElement(void)
888   {
889      // after checkAttribute index of size n
890      int rank = CContext::getCurrent()->getIntraCommRank() ;
891     
892      CArray<size_t,1> ind(n) ;
893      for (int i=0;i<n;i++) ind(i)=index(i) ;
894
895      localElement_ = make_shared<CLocalElement>(rank, n_glo, ind) ;
896   }
897
898   void CAxis::addFullView(void)
899   {
900      CArray<int,1> index(n) ;
901      for(int i=0; i<n ; i++) index(i)=i ;
902      localElement_ -> addView(CElementView::FULL, index) ;
903   }
904
905   void CAxis::addWorkflowView(void)
906   {
907     // mask + data are included into data_index
908     int nk=data_index.numElements() ;
909     int nMask=0 ;
910     for(int k=0;k<nk;k++) if (data_index(k)>=0 && data_index(k)<n) nMask++ ;
911     
912     CArray<int,1> index(nMask) ;
913     nMask=0 ;
914     for(int k=0;k<nk;k++) 
915       if (data_index(k)>=0 && data_index(k)<n) 
916       {
917         index(nMask) = data_index(k) ;
918         nMask++ ;
919       }
920     localElement_ -> addView(CElementView::WORKFLOW, index) ;
921   }
922
923   void CAxis::addModelView(void)
924   {
925     // information for model view is stored in data_index
926     localElement_->addView(CElementView::MODEL, data_index) ;
927   }
928
929   void CAxis::computeModelToWorkflowConnector(void)
930   { 
931     shared_ptr<CLocalView> srcView=getLocalView(CElementView::MODEL) ;
932     shared_ptr<CLocalView> dstView=getLocalView(CElementView::WORKFLOW) ;
933     modelToWorkflowConnector_ = make_shared<CLocalConnector>(srcView, dstView); 
934     modelToWorkflowConnector_->computeConnector() ;
935   }
936
937
938   void CAxis::computeRemoteElement(CContextClient* client, EDistributionType type)
939  {
940    CContext* context = CContext::getCurrent();
941    map<int, CArray<size_t,1>> globalIndex ;
942
943    if (type==EDistributionType::BANDS) // Bands distribution to send to file server
944    {
945      int nbServer = client->getRemoteSize();
946      int nbClient = client->getIntraCommSize() ;
947      int rankClient = client->getIntraCommRank() ;
948      int size = nbServer / nbClient ;
949      int start ;
950      if (nbServer%nbClient > rankClient)
951      {
952       start = (size+1) * rankClient ;
953       size++ ;
954      }
955      else start = size*rankClient + nbServer%nbClient ;
956     
957      for(int i=0; i<size; i++)
958      { 
959        int rank=start+i ; 
960        size_t indSize = n_glo/nbServer ;
961        size_t indStart ;
962        if (n_glo % nbServer > rank)
963        {
964          indStart = (indSize+1) * rank ;
965          indSize++ ;
966        }
967        else indStart = indSize*rank + n_glo%nbServer ;
968       
969        auto& globalInd =  globalIndex[rank] ;
970        globalInd.resize(indSize) ;
971        for(size_t n = 0 ; n<indSize; n++) globalInd(n)=indStart+n ;
972      }
973    }
974    else if (type==EDistributionType::NONE) // domain is not distributed ie all servers get the same local domain
975    {
976      int nbServer = client->getRemoteSize();
977      size_t nglo=n_glo ;
978      CArray<size_t,1> indGlo(nglo) ;
979      for(size_t i=0;i<nglo;i++) indGlo(i) = i ;
980      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer].reference(indGlo.copy()); 
981    }
982    remoteElement_[client] = make_shared<CDistributedElement>(n_glo, globalIndex) ;
983    remoteElement_[client]->addFullView() ;
984  }
985 
986  void CAxis::distributeToServer(CContextClient* client, bool inOut, std::map<int, CArray<size_t,1>>& globalIndexOut, std::map<int, CArray<size_t,1>>& globalIndexIn, 
987                                 shared_ptr<CScattererConnector> &scattererConnector, const string& axisId)
988  {
989    string serverAxisId = axisId.empty() ? this->getId() : axisId ;
990    CContext* context = CContext::getCurrent();
991
992    this->sendAllAttributesToServer(client, serverAxisId)  ;
993
994    auto scatteredElement = make_shared<CDistributedElement>(n_glo,globalIndexOut) ;
995    scatteredElement->addFullView() ;
996    scattererConnector = make_shared<CScattererConnector>(localElement_->getView(CElementView::FULL), scatteredElement->getView(CElementView::FULL), 
997                                                          context->getIntraComm(), client->getRemoteSize()) ;
998    scattererConnector->computeConnector() ;
999   
1000    // phase 0
1001    // send remote element to construct the full view on server, ie without hole
1002    CEventClient event0(getType(), EVENT_ID_AXIS_DISTRIBUTION);
1003    CMessage message0 ;
1004    message0<<serverAxisId<<0 ; 
1005    remoteElement_[client]->sendToServer(client,event0,message0) ; 
1006   
1007    // phase 1
1008    // send the full view of element to construct the connector which connect distributed data coming from client to the full local view
1009    CEventClient event1(getType(), EVENT_ID_AXIS_DISTRIBUTION);
1010    CMessage message1 ;
1011    message1<<serverAxisId<<1<<localElement_->getView(CElementView::FULL)->getGlobalSize() ; 
1012    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
1013
1014    sendDistributedAttributes(client, scattererConnector, axisId) ;
1015 
1016    // phase 2 send the mask : data index + mask2D
1017    {
1018      CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
1019      CArray<bool,1> maskOut ;
1020      auto workflowToFull = make_shared<CLocalConnector>(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
1021      workflowToFull->computeConnector() ;
1022      maskIn=true ;
1023      workflowToFull->transfer(maskIn,maskOut,false) ;
1024
1025      //  prepare grid scatterer connector to send data from client to server
1026      map<int,CArray<size_t,1>> workflowGlobalIndex ;
1027      map<int,CArray<bool,1>> maskOut2 ; 
1028      scattererConnector->transfer(maskOut, maskOut2) ;
1029      scatteredElement->addView(CElementView::WORKFLOW, maskOut2) ;
1030      scatteredElement->getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
1031      // create new workflow view for scattered element
1032      auto clientToServerElement = make_shared<CDistributedElement>(scatteredElement->getGlobalSize(), workflowGlobalIndex) ;
1033      clientToServerElement->addFullView() ;
1034      CEventClient event2(getType(), EVENT_ID_AXIS_DISTRIBUTION);
1035      CMessage message2 ;
1036      message2<<serverAxisId<<2 ; 
1037      clientToServerElement->sendToServer(client, event2, message2) ; 
1038      clientToServerConnector_[client] = make_shared<CScattererConnector>(localElement_->getView(CElementView::WORKFLOW), clientToServerElement->getView(CElementView::FULL), 
1039                                                                        context->getIntraComm(), client->getRemoteSize()) ;
1040      clientToServerConnector_[client]->computeConnector() ;
1041    }
1042
1043    ////////////
1044    // phase 3 : compute connector to receive from server
1045    ////////////
1046    if (inOut)
1047    {
1048      auto scatteredElement = make_shared<CDistributedElement>(n_glo, globalIndexIn) ;
1049      scatteredElement->addFullView() ;
1050      auto scattererConnector = make_shared<CScattererConnector>(localElement_->getView(CElementView::FULL), scatteredElement->getView(CElementView::FULL), 
1051                                                                 context->getIntraComm(), client->getRemoteSize()) ;
1052      scattererConnector->computeConnector() ;
1053      CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
1054      CArray<bool,1> maskOut ;
1055      auto workflowToFull = make_shared<CLocalConnector>(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
1056      workflowToFull->computeConnector() ;
1057      maskIn=true ;
1058      workflowToFull->transfer(maskIn,maskOut,false) ;
1059
1060      map<int,CArray<size_t,1>> workflowGlobalIndex ;
1061      map<int,CArray<bool,1>> maskOut2 ; 
1062      scattererConnector->transfer(maskOut, maskOut2, false) ;
1063      scatteredElement->addView(CElementView::WORKFLOW, maskOut2) ;
1064      scatteredElement->getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
1065      auto clientToServerElement = make_shared<CDistributedElement>(scatteredElement->getGlobalSize(), workflowGlobalIndex) ;
1066      clientToServerElement->addFullView() ;
1067      CEventClient event3(getType(), EVENT_ID_AXIS_DISTRIBUTION);
1068      CMessage message3 ;
1069      message3<<serverAxisId<<3 ; 
1070      clientToServerElement->sendToServer(client, event3, message3) ; 
1071
1072      clientFromServerConnector_[client] = make_shared<CGathererConnector>(clientToServerElement->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1073      clientFromServerConnector_[client]->computeConnector() ;     
1074    }
1075
1076//    clientFromServerConnector_[client] = make_shared<CGathererConnector>(clientToServerElement->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
1077//    clientFromServerConnector_[client]->computeConnector() ;
1078
1079
1080  }
1081
1082  void CAxis::recvAxisDistribution(CEventServer& event)
1083  TRY
1084  {
1085    string axisId;
1086    int phasis ;
1087    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> axisId >> phasis ;
1088    get(axisId)->receivedAxisDistribution(event, phasis);
1089  }
1090  CATCH
1091
1092
1093  void CAxis::receivedAxisDistribution(CEventServer& event, int phasis)
1094  TRY
1095  {
1096    CContext* context = CContext::getCurrent();
1097    if (phasis==0) // receive the remote element to construct the full view
1098    {
1099      localElement_ = make_shared<CLocalElement>(context->getIntraCommRank(),event) ;
1100      localElement_->addFullView() ;
1101      // construct the local dimension and indexes
1102      auto& globalIndex=localElement_->getGlobalIndex() ;
1103      int nk=globalIndex.numElements() ;
1104      int minK=n_glo,maxK=-1 ;
1105      int nGlo=n_glo ;
1106      int indGlo ;
1107      for(int k=0;k<nk;k++)
1108      {
1109        indGlo=globalIndex(k) ;
1110        if (indGlo<minK) minK=indGlo ;
1111        if (indGlo>maxK) maxK=indGlo ;
1112      } 
1113      if (maxK>=minK) { begin=minK ; n=maxK-minK+1 ; }
1114      else {begin=0; n=0 ;}
1115
1116    }
1117    else if (phasis==1) // receive the sent view from client to construct the full distributed full view on server
1118    {
1119      CContext* context = CContext::getCurrent();
1120      shared_ptr<CDistributedElement> elementFrom = make_shared<CDistributedElement>(event) ;
1121      elementFrom->addFullView() ;
1122      gathererConnector_ = make_shared<CGathererConnector>(elementFrom->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1123      gathererConnector_->computeConnector() ; 
1124    }
1125    else if (phasis==2)
1126    {
1127//      delete gathererConnector_ ;
1128      elementFrom_ = make_shared<CDistributedElement>(event) ;
1129      elementFrom_->addFullView() ;
1130//      gathererConnector_ =  make_shared<CGathererConnector>(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
1131//      gathererConnector_ -> computeConnector() ;
1132    }
1133    else if (phasis==3) // only for server -> client
1134    {
1135      elementTo_ = make_shared<CDistributedElement>(event) ;
1136      elementTo_->addFullView() ;
1137    }
1138  }
1139  CATCH
1140
1141  void CAxis::setServerMask(CArray<bool,1>& serverMask, CContextClient* client)
1142  TRY
1143  {
1144    CContext* context = CContext::getCurrent();
1145    localElement_->addView(CElementView::WORKFLOW, serverMask) ;
1146    mask.reference(serverMask.copy()) ;
1147 
1148    serverFromClientConnector_ = make_shared<CGathererConnector>(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW)) ;
1149    serverFromClientConnector_->computeConnector() ;
1150    elementFrom_.reset() ;
1151
1152    if (elementTo_)
1153    {
1154      serverToClientConnector_ = make_shared<CScattererConnector>(localElement_->getView(CElementView::WORKFLOW), elementTo_->getView(CElementView::FULL),
1155                                                                context->getIntraComm(), client->getRemoteSize()) ;
1156      serverToClientConnector_->computeConnector() ;
1157      elementTo_.reset() ;
1158    }
1159  }
1160  CATCH_DUMP_ATTR
1161
1162  void CAxis::sendDistributedAttributes(CContextClient* client, shared_ptr<CScattererConnector> scattererConnector, const string& axisId)
1163  {
1164    string serverAxisId = axisId.empty() ? this->getId() : axisId ;
1165    CContext* context = CContext::getCurrent();
1166
1167    if (hasValue_)
1168    {
1169      { // send level value
1170        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1171        CMessage message ;
1172        message<<serverAxisId<<string("value") ; 
1173        scattererConnector->transfer(value, client, event,message) ;
1174      }
1175    }
1176
1177    if (hasBounds_)
1178    {
1179      { // send bounds level value
1180        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1181        CMessage message ;
1182        message<<serverAxisId<<string("bounds") ; 
1183        scattererConnector->transfer(2, bounds, client, event,message) ;
1184      }
1185    }
1186
1187    if (hasLabel_)
1188    {
1189      { // send label
1190        // need to transform array of string (no fixed size for string) into array of array of char
1191        // to use connector to transfer
1192        // the strings must have fixed size which the maximum lenght over the string label. 
1193        int maxSize=0 ;
1194        for(int i=0; i<label.numElements();i++) 
1195          if (maxSize < label(i).size()) maxSize=label(i).size() ;
1196        MPI_Allreduce(MPI_IN_PLACE, &maxSize,1,MPI_INT,MPI_MAX, context->getIntraComm()) ;
1197        maxSize=maxSize+1 ;
1198        CArray<char,2> charArray(maxSize,label.numElements()) ;
1199        for(int j=0; j<label.numElements();j++) 
1200        {
1201          const char* str = label(j).c_str() ;
1202          int strSize=label(j).size()+1 ;
1203          for(int i=0; i<strSize; i++) charArray(i,j) = str[i] ;
1204        }
1205        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1206        CMessage message ;
1207        message<<serverAxisId<<string("label")<<maxSize ;
1208        scattererConnector->transfer(maxSize, charArray, client, event,message) ;
1209      }
1210    }
1211  }
1212
1213  void CAxis::recvDistributedAttributes(CEventServer& event)
1214  TRY
1215  {
1216    string axisId;
1217    string type ;
1218    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> axisId >> type ;
1219    get(axisId)->recvDistributedAttributes(event, type);
1220  }
1221  CATCH
1222
1223  void CAxis::recvDistributedAttributes(CEventServer& event, const string& type)
1224  TRY
1225  {
1226    if (type=="value") 
1227    {
1228      gathererConnector_->transfer(event, value, 0.); 
1229    }
1230    else if (type=="bounds")
1231    {
1232      CArray<double,1> value ;
1233      gathererConnector_->transfer(event, 2, value, 0.); 
1234      bounds.resize(2,n) ;
1235      if (bounds.numElements() > 0 ) bounds=CArray<double,2>(value.dataFirst(),shape(2,n),neverDeleteData) ; 
1236    }
1237    else if (type=="label")
1238    {
1239      int maxSize ;
1240      for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> maxSize ;
1241      CArray<char,1> value ;
1242      gathererConnector_->transfer(event, maxSize, value, '\0'); 
1243      CArray<char,2> charArray(maxSize,n) ;
1244      label.resize(n) ;
1245      if (n>0)
1246      {
1247        charArray=CArray<char,2>(value.dataFirst(),shape(maxSize,n),neverDeleteData) ;
1248        for(int j=0;j<n;j++)
1249        {
1250          int strSize ;
1251          for(int i=0;i<maxSize;i++) 
1252            if (charArray(i,j)=='\0') { strSize=i ; break; }
1253          string str(strSize,'\0') ;
1254          for(int i=0;i<strSize;i++) str[i]=charArray(i,j) ; 
1255          label(j)=str ;
1256        }
1257      } 
1258    }
1259  }
1260  CATCH
1261
1262  DEFINE_REF_FUNC(Axis,axis)
1263
1264   ///---------------------------------------------------------------
1265
1266} // namespace xios
Note: See TracBrowser for help on using the repository browser.