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

Last change on this file since 2247 was 2206, checked in by ymipsl, 3 years ago

New feature : when can now use the syntax :
fieldId:domainId[n], in domain reference inside the workflow (XML). Same for axis and scalar.

YM

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