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
Line 
1#include "axis.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "message.hpp"
7#include "type.hpp"
8#include "context.hpp"
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "xios_spl.hpp"
12#include "server_distribution_description.hpp"
13#include "client_server_mapping_distributed.hpp"
14#include "distribution_client.hpp"
15
16#include <algorithm>
17#include <regex>
18
19namespace xios {
20
21   /// ////////////////////// Definitions ////////////////////// ///
22
23   CAxis::CAxis(void)
24      : CObjectTemplate<CAxis>()
25      , CAxisAttributes(), isChecked(false), relFiles()
26      , hasBounds(false), isCompressible_(false)
27      , transformationMap_(), hasValue(false), hasLabel(false)
28      , clients()
29   {
30   }
31
32   CAxis::CAxis(const StdString & id)
33      : CObjectTemplate<CAxis>(id)
34      , CAxisAttributes(), isChecked(false), relFiles()
35      , hasBounds(false), isCompressible_(false)
36      , transformationMap_(), hasValue(false), hasLabel(false)
37      , clients()
38   {
39   }
40
41   CAxis::~CAxis(void)
42   { /* Ne rien faire de plus */ }
43
44   std::map<StdString, ETranformationType> CAxis::transformationMapList_ = std::map<StdString, ETranformationType>();
45   bool CAxis::dummyTransformationMapList_ = CAxis::initializeTransformationMap(CAxis::transformationMapList_);
46   bool CAxis::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
47   TRY
48   {
49     m["zoom_axis"] = TRANS_ZOOM_AXIS;
50     m["interpolate_axis"] = TRANS_INTERPOLATE_AXIS;
51     m["extract_axis"] = TRANS_EXTRACT_AXIS;
52     m["inverse_axis"] = TRANS_INVERSE_AXIS;
53     m["reduce_domain"] = TRANS_REDUCE_DOMAIN_TO_AXIS;
54     m["reduce_axis"] = TRANS_REDUCE_AXIS_TO_AXIS;
55     m["extract_domain"] = TRANS_EXTRACT_DOMAIN_TO_AXIS;
56     m["temporal_splitting"] = TRANS_TEMPORAL_SPLITTING;
57     m["duplicate_scalar"] = TRANS_DUPLICATE_SCALAR_TO_AXIS;
58     return true;
59   }
60   CATCH
61
62   ///---------------------------------------------------------------
63
64   const std::set<StdString> & CAxis::getRelFiles(void) const
65   TRY
66   {
67      return (this->relFiles);
68   }
69   CATCH
70
71   bool CAxis::IsWritten(const StdString & filename) const
72   TRY
73   {
74      return (this->relFiles.find(filename) != this->relFiles.end());
75   }
76   CATCH
77
78   bool CAxis::isWrittenCompressed(const StdString& filename) const
79   TRY
80   {
81      return (this->relFilesCompressed.find(filename) != this->relFilesCompressed.end());
82   }
83   CATCH
84
85   bool CAxis::isDistributed(void) const
86   TRY
87   {
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));
90      // A condition to make sure that if there is only one client, axis
91      // should be considered to be distributed. This should be a temporary solution     
92      distributed |= (1 == CContext::getCurrent()->intraCommSize_);
93      return distributed;
94   }
95   CATCH
96
97   /*!
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.
102    */
103   void CAxis::computeIsCompressible(void)
104   TRY
105   {
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 ;
113   }
114   CATCH
115
116   void CAxis::addRelFile(const StdString & filename)
117   TRY
118   {
119      this->relFiles.insert(filename);
120   }
121   CATCH_DUMP_ATTR
122
123   void CAxis::addRelFileCompressed(const StdString& filename)
124   TRY
125   {
126      this->relFilesCompressed.insert(filename);
127   }
128   CATCH_DUMP_ATTR
129
130    //----------------------------------------------------------------
131
132   /*!
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    */
137   std::map<int, StdSize> CAxis::getAttributesBufferSize(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid,
138                                                         CServerDistributionDescription::ServerDistributionType distType)
139   TRY
140   {
141
142     std::map<int, StdSize> attributesSizes = getMinimumBufferSizeForAttributes(client);
143
144//     bool isNonDistributed = (n_glo == n);
145     bool isDistributed = (orderPositionInGrid == CServerDistributionDescription::defaultDistributedDimension(globalDim.size(), distType))
146                                 || (index.numElements() != n_glo);
147
148     if (client->isServerLeader())
149     {
150       // size estimation for sendServerAttribut
151       size_t size = 6 * sizeof(size_t);
152       // size estimation for sendNonDistributedValue
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       }
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       }
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
180     }
181
182     if (isDistributed)
183     {
184       // size estimation for sendDistributedValue
185       std::unordered_map<int, vector<size_t> >::const_iterator it, ite = indSrv_[client->serverSize].end();
186       for (it = indSrv_[client->serverSize].begin(); it != ite; ++it)
187       {
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());
193         if (hasBounds)
194           size += CArray<double,2>::size(2 * it->second.size());
195         if (hasLabel)
196           size += CArray<StdString,1>::size(it->second.size());
197
198         size += CEventClient::headerSize + getId().size() + sizeof(size_t);
199         if (size > attributesSizes[it->first])
200           attributesSizes[it->first] = size;
201       }
202     }
203     return attributesSizes;
204   }
205   CATCH_DUMP_ATTR
206
207   //----------------------------------------------------------------
208
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
215   CAxis* CAxis::createAxis()
216   TRY
217   {
218     CAxis* axis = CAxisGroup::get("axis_definition")->createChild();
219     return axis;
220   }
221   CATCH
222
223   CAxis* CAxis::get(const string& id, bool noError)
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() ;
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");
236        CField* field=CField::get(fieldId) ;
237        return field->getAssociatedAxis(suffix, noError) ;
238     }
239     {
240       if (noError) if(!CObjectFactory::HasObject<CAxis>(id)) return nullptr ;
241       return CObjectFactory::GetObject<CAxis>(id).get();
242     }
243   }
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   }
266
267   /*!
268     Check common attributes of an axis.
269     This check should be done in the very beginning of work flow
270   */
271   void CAxis::checkAttributes(void)
272   TRY
273   {
274     if (checkAttributes_done_) return ;
275
276     CContext* context=CContext::getCurrent();
277
278     if (this->n_glo.isEmpty())
279        ERROR("CAxis::checkAttributes(void)",
280              << "[ id = '" << getId() << "' , context = '" << CObjectFactory::GetCurrentContextId() << "' ] "
281              << "The axis is wrongly defined, attribute 'n_glo' must be specified");
282      StdSize size = this->n_glo.getValue();
283
284      if (!this->index.isEmpty())
285      {
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);         
291      }
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);
302
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        }
316      }
317
318      if (!this->value.isEmpty())
319      {
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() << ").");
326        this->hasValue = true;
327      }
328
329      this->checkBounds();
330      this->checkMask();
331      this->checkData();
332      this->checkLabel();
333      initializeLocalElement() ;
334      addFullView() ;
335      addWorkflowView() ;
336      addModelView() ;
337
338      checkAttributes_done_ = true ;
339   }
340   CATCH_DUMP_ATTR
341
342
343
344   /*!
345      Check the validity of data, fill in values if any, and apply mask.
346   */
347   void CAxis::checkData()
348   TRY
349   {
350      if (data_begin.isEmpty()) data_begin.setValue(0);
351
352      if (data_n.isEmpty())
353      {
354        data_n.setValue(n);
355      }
356      else if (data_n.getValue() < 0)
357      {
358        ERROR("CAxis::checkData(void)",
359              << "[ id = " << this->getId() << " , context = '" << CObjectFactory::GetCurrentContextId() << " ] "
360              << "The data size should be strictly positive ('data_n' = " << data_n.getValue() << ").");
361      }
362
363      if (data_index.isEmpty())
364      {
365        data_index.resize(data_n);
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        }
378      }
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        {
389           if (data_index(i) >= 0 && data_index(i)<n)
390             if (!mask(data_index(i))) data_index(i) = -1;
391        }
392      }
393
394   }
395   CATCH_DUMP_ATTR
396
397    size_t CAxis::getGlobalWrittenSize(void)
398    {
399      return n_glo ;
400    }
401
402   /*!
403     Check validity of mask info and fill in values if any.
404   */
405   void CAxis::checkMask()
406   TRY
407   {
408      if (!mask.isEmpty())
409      {
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        }
418      }
419      else
420      {
421        mask.resize(n);
422        mask = true;
423      }
424   }
425   CATCH_DUMP_ATTR
426
427   /*!
428     Check validity of bounds info and fill in values if any.
429   */
430   void CAxis::checkBounds()
431   TRY
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) << ".");
440       hasBounds = true;
441     }
442     else hasBounds = false;
443   }
444   CATCH_DUMP_ATTR
445
446  void CAxis::checkLabel()
447  TRY
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  }
460  CATCH_DUMP_ATTR
461
462 
463  /*!
464    Dispatch event from the lower communication layer then process event according to its type
465  */
466  bool CAxis::dispatchEvent(CEventServer& event)
467  TRY
468  {
469     if (SuperClass::dispatchEvent(event)) return true;
470     else
471     {
472       switch(event.type)
473       {
474         case EVENT_ID_AXIS_DISTRIBUTION:
475           recvAxisDistribution(event);
476           return true;
477           break;
478         case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
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  }
489  CATCH
490
491   /* to remove later when reimplementing coupling */
492   void CAxis::sendAxisToCouplerOut(CContextClient* client, const std::vector<int>& globalDim, int orderPositionInGrid, const string& fieldId, int posInGrid)
493   {
494     if (sendAxisToCouplerOut_done_.count(client)!=0) return ;
495     else sendAxisToCouplerOut_done_.insert(client) ;
496     
497     string axisId="_axis["+std::to_string(posInGrid)+"]_of_"+fieldId ;
498
499    }
500
501  string CAxis::getCouplingAlias(const string& fieldId, int posInGrid)
502  {
503    return "_axis["+std::to_string(posInGrid)+"]_of_"+fieldId ;
504  }
505
506  void CAxis::makeAliasForCoupling(const string& fieldId, int posInGrid)
507  {
508    const string axisId = getCouplingAlias(fieldId,posInGrid)  ;
509    this->createAlias(axisId) ;
510  }
511
512 
513  /*!
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)
521  TRY
522  {
523    vector<StdString> excludedAttr;
524    excludedAttr.push_back("axis_ref");
525
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  }
545  CATCH_DUMP_ATTR
546
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  */
552  CTransformation<CAxis>* CAxis::addTransformation(ETranformationType transType, const StdString& id)
553  TRY
554  {
555    transformationMap_.push_back(std::make_pair(transType, CTransformation<CAxis>::createTransformation(transType,id)));
556    return transformationMap_.back().second;
557  }
558  CATCH_DUMP_ATTR
559
560  /*
561    Check whether an axis has (spatial) transformation
562  */
563  bool CAxis::hasTransformation()
564  TRY
565  {
566    return (!transformationMap_.empty());
567  }
568  CATCH_DUMP_ATTR
569
570  /*
571    Set transformation
572    \param [in] axisTrans transformation to set
573  */
574  void CAxis::setTransformations(const TransMapTypes& axisTrans)
575  TRY
576  {
577    transformationMap_ = axisTrans;
578  }
579  CATCH_DUMP_ATTR
580
581  /*
582    Return all transformation held by the axis
583    \return transformation the axis has
584  */
585  CAxis::TransMapTypes CAxis::getAllTransformations(void)
586  TRY
587  {
588    return transformationMap_;
589  }
590  CATCH_DUMP_ATTR
591
592  /*
593    Duplicate transformation of another axis
594    \param [in] src axis whose transformations are copied
595  */
596  void CAxis::duplicateTransformation(CAxis* src)
597  TRY
598  {
599    if (src->hasTransformation())
600    {
601      this->setTransformations(src->getAllTransformations());
602    }
603  }
604  CATCH_DUMP_ATTR
605
606  /*!
607   * Go through the hierarchy to find the axis from which the transformations must be inherited
608   */
609  void CAxis::solveInheritanceTransformation_old()
610  TRY
611  {
612    if (hasTransformation() || !hasDirectAxisReference())
613      return;
614
615    CAxis* axis = this;
616    std::vector<CAxis*> refAxis;
617    while (!axis->hasTransformation() && axis->hasDirectAxisReference())
618    {
619      refAxis.push_back(axis);
620      axis = axis->getDirectAxisReference();
621    }
622
623    if (axis->hasTransformation())
624      for (size_t i = 0; i < refAxis.size(); ++i)
625        refAxis[i]->setTransformations(axis->getAllTransformations());
626  }
627  CATCH_DUMP_ATTR
628
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
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
691  void CAxis::setContextClient(CContextClient* contextClient)
692  TRY
693  {
694    if (clientsSet.find(contextClient)==clientsSet.end())
695    {
696      clients.push_back(contextClient) ;
697      clientsSet.insert(contextClient);
698    }
699  }
700  CATCH_DUMP_ATTR
701
702  void CAxis::parse(xml::CXMLNode & node)
703  TRY
704  {
705    SuperClass::parse(node);
706
707    if (node.goToChildElement())
708    {
709      StdString nodeElementName;
710      do
711      {
712        StdString nodeId("");
713        if (node.getAttributes().end() != node.getAttributes().find("id"))
714        { nodeId = node.getAttributes()["id"]; }
715
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)));
724        }
725        else
726        {
727          ERROR("void CAxis::parse(xml::CXMLNode & node)",
728                << "The transformation " << nodeElementName << " has not been supported yet.");
729        }
730      } while (node.goToNextElement()) ;
731      node.goToParentElement();
732    }
733  }
734  CATCH_DUMP_ATTR
735
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 ;
834      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer].reference(indGlo.copy()); 
835    }
836    remoteElement_[client] = new CDistributedElement(n_glo, globalIndex) ;
837    remoteElement_[client]->addFullView() ;
838  }
839 
840  void CAxis::distributeToServer(CContextClient* client, std::map<int, CArray<size_t,1>>& globalIndex, 
841                                 CScattererConnector* &scattererConnector, const string& axisId)
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() ;
850    scattererConnector = new CScattererConnector(localElement_->getView(CElementView::FULL), scatteredElement.getView(CElementView::FULL), 
851                                                 context->getIntraComm(), client->getRemoteSize()) ;
852    scattererConnector->computeConnector() ;
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() ; 
866    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
867
868    sendDistributedAttributes(client, *scattererConnector, axisId) ;
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 ; 
881    scattererConnector->transfer(maskOut, maskOut2) ;
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) ; 
891    clientToServerConnector_[client] = new CScattererConnector(localElement_->getView(CElementView::WORKFLOW), clientToServerElement.getView(CElementView::FULL), 
892                                                              context->getIntraComm(), client->getRemoteSize()) ;
893    clientToServerConnector_[client]->computeConnector() ;
894
895    clientFromServerConnector_[client] = new CGathererConnector(clientToServerElement.getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
896    clientFromServerConnector_[client]->computeConnector() ;
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    {
946//      delete gathererConnector_ ;
947      elementFrom_ = new  CDistributedElement(event) ;
948      elementFrom_->addFullView() ;
949//      gathererConnector_ =  new CGathererConnector(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
950//      gathererConnector_ -> computeConnector() ;
951    }
952 
953  }
954  CATCH
955
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
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
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        }
1015        CEventClient event(getType(), EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE);
1016        CMessage message ;
1017        message<<serverAxisId<<string("label")<<maxSize ;
1018        scattererConnector.transfer(maxSize, charArray, client, event,message) ;
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) ;
1045      if (bounds.numElements() > 0 ) bounds=CArray<double,2>(value.dataFirst(),shape(2,n),neverDeleteData) ; 
1046    }
1047    else if (type=="label")
1048    {
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      } 
1068    }
1069  }
1070  CATCH
1071
1072  DEFINE_REF_FUNC(Axis,axis)
1073
1074   ///---------------------------------------------------------------
1075
1076} // namespace xios
Note: See TracBrowser for help on using the repository browser.