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

Last change on this file since 2258 was 2206, checked in by ymipsl, 3 years ago

New feature : when can now use the syntax :
fieldId:domainId[n], in domain reference inside the workflow (XML). Same for axis and scalar.

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