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

Last change on this file since 2291 was 2291, checked in by ymipsl, 2 years ago

Improve reduction transformation

  • make the difference between reduction over geometry or reduction between process.
  • geometrical reduction :

domain -> axis
axis -> scalar
domain -> scalar

  • reduction across processes for redondant geometrical cell :

axis -> axis
scalar -> scalar

Reduction can be local (only for the geometrical cell owned by current process) or global, using the "local" attribute (bool) over the reduction.

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