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

Last change on this file since 2546 was 2546, checked in by ymipsl, 10 months ago

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