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

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

Manage hash values with size_t in hash tables of elements associated to output files

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