source: XIOS3/branches/xios-3.0-beta/src/node/axis.cpp @ 2423

Last change on this file since 2423 was 2397, checked in by ymipsl, 22 months ago
  • Optimize remote connector computation in case of read (reverse way).
  • don't compute anymore clientFromServerConnector (and all intermediate computation) for non reading case.

YM

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