source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/scalar.cpp @ 2284

Last change on this file since 2284 was 2274, checked in by ymipsl, 3 years ago

Tracking memory leak : release memory statically alocated

YM

File size: 20.5 KB
Line 
1#include "scalar.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "xios_spl.hpp"
8#include "type.hpp"
9#include "context.hpp"
10
11#include <algorithm>
12#include <regex>
13
14namespace xios
15{
16
17  /// ////////////////////// Définitions ////////////////////// ///
18
19  CScalar::CScalar(void)
20     : CObjectTemplate<CScalar>()
21     , CScalarAttributes()
22     , relFiles()
23  { /* Ne rien faire de plus */ }
24
25  CScalar::CScalar(const StdString & id)
26     : CObjectTemplate<CScalar>(id)
27     , CScalarAttributes()
28     , relFiles()
29  { /* Ne rien faire de plus */ }
30
31  CScalar::~CScalar(void)
32  { /* Ne rien faire de plus */ }
33
34  void CScalar::releaseStaticAllocation(void)
35  {
36    transformationMapList_.clear() ;
37    CTransformation<CScalar>::unregisterAllTransformations() ;
38    CGridTransformationFactory<CScalar>::unregisterAllTransformations() ;
39  }
40 
41  std::map<StdString, ETranformationType> CScalar::transformationMapList_ = std::map<StdString, ETranformationType>();
42  bool CScalar::dummyTransformationMapList_ = CScalar::initializeTransformationMap(CScalar::transformationMapList_);
43  bool CScalar::initializeTransformationMap(std::map<StdString, ETranformationType>& m)
44  {
45    m["reduce_axis"]   = TRANS_REDUCE_AXIS_TO_SCALAR;
46    m["extract_axis"]  = TRANS_EXTRACT_AXIS_TO_SCALAR;
47    m["reduce_domain"] = TRANS_REDUCE_DOMAIN_TO_SCALAR;
48    m["reduce_scalar"] = TRANS_REDUCE_SCALAR_TO_SCALAR;
49    return true;
50  }
51
52  StdString CScalar::GetName(void)   { return (StdString("scalar")); }
53  StdString CScalar::GetDefName(void){ return (CScalar::GetName()); }
54  ENodeType CScalar::GetType(void)   { return (eScalar); }
55
56  CScalar* CScalar::createScalar()
57  {
58    CScalar* scalar = CScalarGroup::get("scalar_definition")->createChild();
59    return scalar;
60  }
61
62  CScalar* CScalar::get(const string& id, bool noError)
63  {
64    const regex r("::");
65    smatch m;
66    if (regex_search(id, m, r))
67    {
68      if (m.size()!=1) ERROR("CScalar* CScalar::get(string& id)", <<" id = "<<id<< "  -> bad format id, separator :: append more than one time");
69      string fieldId=m.prefix() ;
70      if (fieldId.empty()) ERROR("CScalar* CScalar::get(string& id)", <<" id = "<<id<< "  -> bad format id, field name is empty");
71      string suffix=m.suffix() ;
72      if (!CField::has(fieldId)) 
73          if (noError)  return nullptr ;
74          else ERROR("CScalar* CScalar::get(const string& id, bool noError)", <<" id = "<<id<< "  -> field Id : < "<<fieldId<<" > doesn't exist");
75      CField* field=CField::get(fieldId) ;
76      return field->getAssociatedScalar(suffix, noError) ;
77    }
78    else
79    {
80       if (noError) if(!CObjectFactory::HasObject<CScalar>(id)) return nullptr ;
81       return CObjectFactory::GetObject<CScalar>(id).get();
82     }
83   }
84
85   bool CScalar::has(const string& id)
86   {
87     if (CScalar::get(id,true)==nullptr) return false ;
88     else return true ;
89   }
90   
91   CField* CScalar::getFieldFromId(const string& id)
92   {
93     const regex r("::");
94     smatch m;
95     if (regex_search(id, m, r))
96     {
97        if (m.size()!=1) ERROR("CField* CScalar::getFieldFromId(const string& id)", <<" id = "<<id<< "  -> bad format id, separator :: append more than one time");
98        string fieldId=m.prefix() ;
99        if (fieldId.empty()) ERROR("CField* CScalar::getFieldFromId(const string& id)", <<" id = "<<id<< "  -> bad format id, field name is empty");
100        string suffix=m.suffix() ;
101        CField* field=CField::get(fieldId) ;
102        return field ;
103     }
104     else return nullptr;
105   }
106
107  bool CScalar::IsWritten(const StdString & filename) const
108  {
109    return (this->relFiles.find(filename) != this->relFiles.end());
110  }
111
112  void CScalar::addRelFile(const StdString& filename)
113  {
114      this->relFiles.insert(filename);
115  }
116
117  void CScalar::checkAttributes(void)
118  {
119    if (checkAttributes_done_) return ;
120    checkAttributes_done_ = true ; 
121   
122    if (n.isEmpty()) n=1 ;
123    if (mask.isEmpty()) mask=true ;
124
125    initializeLocalElement() ;
126    addFullView() ;
127    addWorkflowView() ;
128    addModelView() ;
129  }
130
131  /*!
132    Compare two scalar objects.
133    They are equal if only if they have identical attributes as well as their values.
134    Moreover, they must have the same transformations.
135  \param [in] scalar Compared scalar
136  \return result of the comparison
137  */
138  bool CScalar::isEqual(CScalar* obj)
139  {
140    vector<StdString> excludedAttr;
141    excludedAttr.push_back("scalar_ref");
142    bool objEqual = SuperClass::isEqual(obj, excludedAttr);
143    if (!objEqual) return objEqual;
144
145    TransMapTypes thisTrans = this->getAllTransformations();
146    TransMapTypes objTrans  = obj->getAllTransformations();
147
148    TransMapTypes::const_iterator it, itb, ite;
149    std::vector<ETranformationType> thisTransType, objTransType;
150    for (it = thisTrans.begin(); it != thisTrans.end(); ++it)
151      thisTransType.push_back(it->first);
152    for (it = objTrans.begin(); it != objTrans.end(); ++it)
153      objTransType.push_back(it->first);
154
155    if (thisTransType.size() != objTransType.size()) return false;
156    for (int idx = 0; idx < thisTransType.size(); ++idx)
157      objEqual &= (thisTransType[idx] == objTransType[idx]);
158
159    return objEqual;
160  }
161
162  CTransformation<CScalar>* CScalar::addTransformation(ETranformationType transType, const StdString& id)
163  {
164    transformationMap_.push_back(std::make_pair(transType, CTransformation<CScalar>::createTransformation(transType,id)));
165    return transformationMap_.back().second;
166  }
167
168  bool CScalar::hasTransformation()
169  {
170    return (!transformationMap_.empty());
171  }
172
173  void CScalar::setTransformations(const TransMapTypes& scalarTrans)
174  {
175    transformationMap_ = scalarTrans;
176  }
177
178  CScalar::TransMapTypes CScalar::getAllTransformations(void)
179  {
180    return transformationMap_;
181  }
182
183  void CScalar::duplicateTransformation(CScalar* src)
184  {
185    if (src->hasTransformation())
186    {
187      this->setTransformations(src->getAllTransformations());
188    }
189  }
190
191  /*!
192   * Go through the hierarchy to find the scalar from which the transformations must be inherited
193   */
194  void CScalar::solveInheritanceTransformation_old()
195  {
196    if (hasTransformation() || !hasDirectScalarReference())
197      return;
198
199    CScalar* scalar = this;
200    std::vector<CScalar*> refScalar;
201    while (!scalar->hasTransformation() && scalar->hasDirectScalarReference())
202    {
203      refScalar.push_back(scalar);
204      scalar = scalar->getDirectScalarReference();
205    }
206
207    if (scalar->hasTransformation())
208      for (size_t i = 0; i < refScalar.size(); ++i)
209        refScalar[i]->setTransformations(scalar->getAllTransformations());
210  }
211 
212  void CScalar::solveInheritanceTransformation()
213  TRY
214  {
215    if (solveInheritanceTransformation_done_) return;
216    else solveInheritanceTransformation_done_=true ;
217
218    CScalar* scalar = this;
219    CScalar* Lastscalar ;
220    std::list<CScalar*> refScalars;
221    bool out=false ;
222    vector<StdString> excludedAttr;
223    excludedAttr.push_back("scalar_ref");
224   
225    refScalars.push_front(scalar) ;
226    while (scalar->hasDirectScalarReference() && !out)
227    {
228      CScalar* lastScalar=scalar ;
229      scalar = scalar->getDirectScalarReference();
230      scalar->solveRefInheritance() ;
231      if (!scalar->SuperClass::isEqual(lastScalar,excludedAttr)) out=true ;
232      refScalars.push_front(scalar) ;
233    }
234
235    CTransformationPaths::TPath path ;
236    auto& pathList = std::get<2>(path) ;
237    std::get<0>(path) = EElement::SCALAR ;
238    std::get<1>(path) = refScalars.front()->getId() ;
239    for (auto& scalar : refScalars)
240    {
241      CScalar::TransMapTypes transformations = scalar->getAllTransformations();
242      for(auto& transformation : transformations) pathList.push_back({transformation.second->getTransformationType(), 
243                                                                      transformation.second->getId()}) ;
244    }
245    transformationPaths_.addPath(path) ;
246
247  }
248  CATCH_DUMP_ATTR
249
250  bool CScalar::activateFieldWorkflow(CGarbageCollector& gc)
251  TRY
252  {
253    if (!scalar_ref.isEmpty())
254    {
255      CField* field=getFieldFromId(scalar_ref) ;
256      if (field!=nullptr)
257      {
258        bool ret = field->buildWorkflowGraph(gc) ;
259        if (!ret) return false ; // cannot build workflow graph at this state
260      }
261      else 
262      {
263        CScalar* scalar = get(scalar_ref) ;
264        bool ret = scalar->activateFieldWorkflow(gc) ;
265        if (!ret) return false ; // cannot build workflow graph at this state
266        scalar_ref=scalar->getId() ; // replace domain_ref by solved reference
267      }
268    }
269    activateFieldWorkflow_done_=true ;
270    return true ;
271  }
272  CATCH_DUMP_ATTR
273
274
275  /* obsolete, to remove after reimplementing coupling */
276  void CScalar::sendScalarToCouplerOut(CContextClient* client, const string& fieldId, int posInGrid)
277  {
278    if (sendScalarToCouplerOut_done_.count(client)!=0) return ;
279    else sendScalarToCouplerOut_done_.insert(client) ;
280
281    string scalarId = getCouplingAlias(fieldId, posInGrid) ;
282
283    this->sendAllAttributesToServer(client, scalarId);
284  } 
285
286  string CScalar::getCouplingAlias(const string& fieldId, int posInGrid)
287  {
288    return "_scalar["+std::to_string(posInGrid)+"]_of_"+fieldId ;
289  }
290
291  void CScalar::makeAliasForCoupling(const string& fieldId, int posInGrid)
292  {
293    const string scalarId = getCouplingAlias(fieldId, posInGrid) ;
294    this->createAlias(scalarId) ;
295  }
296
297  void CScalar::setContextClient(CContextClient* contextClient)
298  TRY
299  {
300    if (clientsSet.find(contextClient)==clientsSet.end())
301    {
302      clients.push_back(contextClient) ;
303      clientsSet.insert(contextClient);
304    }
305  }
306  CATCH_DUMP_ATTR
307  /*!
308    Parse children nodes of a scalar in xml file.
309    \param node child node to process
310  */
311  void CScalar::parse(xml::CXMLNode & node)
312  {
313    SuperClass::parse(node);
314
315    if (node.goToChildElement())
316    {
317      StdString nodeElementName;
318      do
319      {
320        StdString nodeId("");
321        if (node.getAttributes().end() != node.getAttributes().find("id"))
322        { nodeId = node.getAttributes()["id"]; }
323
324        nodeElementName = node.getElementName();
325        std::map<StdString, ETranformationType>::const_iterator ite = transformationMapList_.end(), it;
326        it = transformationMapList_.find(nodeElementName);
327        if (ite != it)
328        {
329          transformationMap_.push_back(std::make_pair(it->second, CTransformation<CScalar>::createTransformation(it->second,
330                                                                                                                 nodeId,
331                                                                                                                 &node)));
332        }
333        else
334        {
335          ERROR("void CScalar::parse(xml::CXMLNode & node)",
336                << "The transformation " << nodeElementName << " has not been supported yet.");
337        }
338      } while (node.goToNextElement()) ;
339      node.goToParentElement();
340    }
341  }
342
343   //////////////////////////////////////////////////////////////////////////////////////
344   //  this part is related to distribution, element definition, views and connectors  //
345   //////////////////////////////////////////////////////////////////////////////////////
346
347   void CScalar::initializeLocalElement(void)
348   {
349      // after checkAttribute index of size n
350      int rank = CContext::getCurrent()->getIntraCommRank() ;
351     
352     
353      CArray<size_t,1> index(n) ;
354      if (n==1) index(0)=0 ;
355      localElement_ = make_shared<CLocalElement>(rank, 1, index) ;
356   }
357
358   void CScalar::addFullView(void)
359   {
360      CArray<int,1> index(n) ;
361      if (n==1) index(0)=0 ;
362      localElement_ -> addView(CElementView::FULL, index) ;
363   }
364
365   void CScalar::addWorkflowView(void)
366   {
367      CArray<int,1> index ;
368      if (mask && n==1)
369      {
370        index.resize(1) ;
371        index(0)=0 ;
372      }
373      else index.resize(0) ;
374      localElement_ -> addView(CElementView::WORKFLOW, index) ;
375   }
376
377   void CScalar::addModelView(void)
378   {
379     CArray<int,1> index(1) ;
380     for(int i=0; i<1 ; i++) index(0)=0 ;
381     localElement_->addView(CElementView::MODEL, index) ;
382   }
383
384   void CScalar::computeModelToWorkflowConnector(void)
385   { 
386     shared_ptr<CLocalView> srcView=getLocalView(CElementView::MODEL) ;
387     shared_ptr<CLocalView> dstView=getLocalView(CElementView::WORKFLOW) ;
388     modelToWorkflowConnector_ = make_shared<CLocalConnector>(srcView, dstView); 
389     modelToWorkflowConnector_->computeConnector() ;
390   }
391
392
393  void CScalar::computeRemoteElement(CContextClient* client, EDistributionType type)
394  {
395    CContext* context = CContext::getCurrent();
396    map<int, CArray<size_t,1>> globalIndex ;
397    size_t nglo=1 ;
398
399    if (type==EDistributionType::ROOT) // Bands distribution to send to file server
400    {
401      for (auto& rankServer : client->getRanksServerLeader())
402      {
403        auto& globalInd =  globalIndex[rankServer] ;
404        if (rankServer==0) 
405        {
406          globalInd.resize(1) ;
407          globalInd(0)=0 ;
408        }
409      }
410    }
411    else if (type==EDistributionType::NONE) // domain is not distributed ie all servers get the same local domain
412    {
413      int nbServer = client->serverSize;
414      CArray<size_t,1> indGlo(nglo) ;
415      for(size_t i=0;i<nglo;i++) indGlo(i) = i ;
416      for (auto& rankServer : client->getRanksServerLeader()) globalIndex[rankServer].reference(indGlo.copy()) ; 
417    }
418    remoteElement_[client] = make_shared<CDistributedElement>(nglo, globalIndex) ;
419    remoteElement_[client]->addFullView() ;
420  }
421 
422  void CScalar::distributeToServer(CContextClient* client, std::map<int, CArray<size_t,1>>& globalIndex, 
423                                   shared_ptr<CScattererConnector> &scattererConnector, const string& scalarId)
424  {
425    string serverScalarId = scalarId.empty() ? this->getId() : scalarId ;
426    CContext* context = CContext::getCurrent();
427
428    this->sendAllAttributesToServer(client, serverScalarId)  ;
429
430    auto scatteredElement = make_shared<CDistributedElement>(1,globalIndex) ;
431    scatteredElement->addFullView() ;
432    scattererConnector = make_shared<CScattererConnector>(localElement_->getView(CElementView::FULL), scatteredElement->getView(CElementView::FULL), 
433                                                          context->getIntraComm(), client->getRemoteSize()) ;
434    scattererConnector->computeConnector() ;
435   
436    // phase 0
437    // send remote element to construct the full view on server, ie without hole
438    CEventClient event0(getType(), EVENT_ID_SCALAR_DISTRIBUTION);
439    CMessage message0 ;
440    message0<<serverScalarId<<0 ; 
441    remoteElement_[client]->sendToServer(client,event0,message0) ; 
442   
443    // phase 1
444    // send the full view of element to construct the connector which connect distributed data coming from client to the full local view
445    CEventClient event1(getType(), EVENT_ID_SCALAR_DISTRIBUTION);
446    CMessage message1 ;
447    message1<<serverScalarId<<1<<localElement_->getView(CElementView::FULL)->getGlobalSize() ; 
448    scattererConnector->transfer(localElement_->getView(CElementView::FULL)->getGlobalIndex(),client,event1,message1) ;
449
450    sendDistributedAttributes(client, scattererConnector, scalarId) ;
451 
452    // phase 2 send the mask : data index + mask2D
453    CArray<bool,1> maskIn(localElement_->getView(CElementView::WORKFLOW)->getSize());
454    CArray<bool,1> maskOut ;
455    auto workflowToFull = make_shared<CLocalConnector>(localElement_->getView(CElementView::WORKFLOW), localElement_->getView(CElementView::FULL)) ;
456    workflowToFull->computeConnector() ;
457    maskIn=true ;
458    workflowToFull->transfer(maskIn,maskOut,false) ;
459
460    // phase 3 : prepare grid scatterer connector to send data from client to server
461    map<int,CArray<size_t,1>> workflowGlobalIndex ;
462    map<int,CArray<bool,1>> maskOut2 ; 
463    scattererConnector->transfer(maskOut, maskOut2) ;
464    scatteredElement->addView(CElementView::WORKFLOW, maskOut2) ;
465    scatteredElement->getView(CElementView::WORKFLOW)->getGlobalIndexView(workflowGlobalIndex) ;
466    // create new workflow view for scattered element
467    auto clientToServerElement = make_shared<CDistributedElement>(scatteredElement->getGlobalSize(), workflowGlobalIndex) ;
468    clientToServerElement->addFullView() ;
469    CEventClient event2(getType(), EVENT_ID_SCALAR_DISTRIBUTION);
470    CMessage message2 ;
471    message2<<serverScalarId<<2 ; 
472    clientToServerElement->sendToServer(client, event2, message2) ; 
473    clientToServerConnector_[client] = make_shared<CScattererConnector>(localElement_->getView(CElementView::WORKFLOW), clientToServerElement->getView(CElementView::FULL),
474                                                                        context->getIntraComm(), client->getRemoteSize()) ;
475    clientToServerConnector_[client]->computeConnector() ;
476
477    clientFromServerConnector_[client] = make_shared<CGathererConnector>(clientToServerElement->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW));
478    clientFromServerConnector_[client]->computeConnector() ;
479
480  }
481 
482  void CScalar::recvScalarDistribution(CEventServer& event)
483  TRY
484  {
485    string scalarId;
486    int phasis ;
487    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> scalarId >> phasis ;
488    get(scalarId)->receivedScalarDistribution(event, phasis);
489  }
490  CATCH
491 
492  void CScalar::receivedScalarDistribution(CEventServer& event, int phasis)
493  TRY
494  {
495    CContext* context = CContext::getCurrent();
496    if (phasis==0) // receive the remote element to construct the full view
497    {
498      localElement_ = make_shared<CLocalElement>(context->getIntraCommRank(),event) ;
499      localElement_->addFullView() ;
500      // construct the local dimension and indexes
501      auto& globalIndex=localElement_->getGlobalIndex() ;
502      n=globalIndex.numElements() ;
503      // no distribution for scalar => nk ==1 or maybe 0 ?
504    }
505    else if (phasis==1) // receive the sent view from client to construct the full distributed full view on server
506    {
507      CContext* context = CContext::getCurrent();
508      shared_ptr<CDistributedElement> elementFrom = make_shared<CDistributedElement>(event) ;
509      elementFrom->addFullView() ;
510      gathererConnector_ = make_shared<CGathererConnector>(elementFrom->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
511      gathererConnector_->computeConnector() ; 
512    }
513    else if (phasis==2)
514    {
515//      delete gathererConnector_ ;
516      elementFrom_ = make_shared<CDistributedElement>(event) ;
517      elementFrom_->addFullView() ;
518//      gathererConnector_ =  make_shared<CGathererConnector>(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::FULL)) ;
519//      gathererConnector_ -> computeConnector() ;
520    }
521  }
522  CATCH
523
524  void CScalar::setServerMask(CArray<bool,1>& serverMask, CContextClient* client)
525  TRY
526  {
527    CContext* context = CContext::getCurrent();
528    localElement_->addView(CElementView::WORKFLOW, serverMask) ;
529    if (serverMask.numElements()==1) mask = serverMask(0) ;
530 
531    serverFromClientConnector_ = make_shared<CGathererConnector>(elementFrom_->getView(CElementView::FULL), localElement_->getView(CElementView::WORKFLOW)) ;
532    serverFromClientConnector_->computeConnector() ;
533     
534    serverToClientConnector_ = make_shared<CScattererConnector>(localElement_->getView(CElementView::WORKFLOW), elementFrom_->getView(CElementView::FULL),
535                                                                context->getIntraComm(), client->getRemoteSize()) ;
536    serverToClientConnector_->computeConnector() ;
537  }
538  CATCH_DUMP_ATTR
539
540  void CScalar::sendDistributedAttributes(CContextClient* client, shared_ptr<CScattererConnector> scattererConnector, const string& scalarId)
541  {
542    string serverScalarId = scalarId.empty() ? this->getId() : scalarId ;
543    CContext* context = CContext::getCurrent();
544
545    // nothing for now
546  }
547
548  void CScalar::recvDistributedAttributes(CEventServer& event)
549  TRY
550  {
551    string scalarId;
552    string type ;
553    for (auto& subEvent : event.subEvents) (*subEvent.buffer) >> scalarId >> type ;
554    get(scalarId)->recvDistributedAttributes(event, type);
555  }
556  CATCH
557
558  void CScalar::recvDistributedAttributes(CEventServer& event, const string& type)
559  TRY
560  {
561    // nothing for now
562  }
563  CATCH 
564
565  bool CScalar::dispatchEvent(CEventServer& event)
566  TRY
567  {
568     if (SuperClass::dispatchEvent(event)) return true;
569     else
570     {
571       switch(event.type)
572       {
573          case EVENT_ID_SCALAR_DISTRIBUTION:
574            recvScalarDistribution(event);
575            return true;
576            break;
577          case EVENT_ID_SEND_DISTRIBUTED_ATTRIBUTE:
578            recvDistributedAttributes(event);
579            return true;
580            break;
581          default :
582            ERROR("bool CScalar::dispatchEvent(CEventServer& event)",
583                   << "Unknown Event");
584          return false;
585        }
586     }
587  }
588  CATCH
589
590
591  // Definition of some macros
592  DEFINE_REF_FUNC(Scalar,scalar)
593
594} // namespace xios
Note: See TracBrowser for help on using the repository browser.