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

Last change on this file since 2386 was 2386, checked in by jderouillat, 2 years ago

Set the code structure to compute the hash value of an element based on its attributs, use for now before writing an element in a file

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