Salome HOME
Squeeze memory of process hosting YACS graph
[modules/yacs.git] / src / engine / DynParaLoop.cxx
1 // Copyright (C) 2006-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "DynParaLoop.hxx"
21 #include "LinkInfo.hxx"
22 #include "OutPort.hxx"
23 #include "Container.hxx"
24 #include "ComponentInstance.hxx"
25 #include "ServiceNode.hxx"
26 #include "InlineNode.hxx"
27 #include "ElementaryNode.hxx"
28 #include "Visitor.hxx"
29
30 #include <list>
31 #include <vector>
32
33 //#define _DEVDEBUG_
34 #include "YacsTrace.hxx"
35
36 using namespace std;
37 using namespace YACS::ENGINE;
38
39 const char DynParaLoop::NAME_OF_SPLITTED_SEQ_OUT[] = "evalSamples";
40 const char DynParaLoop::OLD_NAME_OF_SPLITTED_SEQ_OUT[] = "SmplPrt"; // For backward compatibility with 5.1.4
41
42 const char DynParaLoop::NAME_OF_NUMBER_OF_BRANCHES[]="nbBranches";
43
44 DynParaLoop::DynParaLoop(const std::string& name, TypeCode *typeOfDataSplitted)
45   : ComposedNode(name),_node(0),_initNode(0),_finalizeNode(0),_nbOfEltConsumed(0),
46     _nbOfBranches(NAME_OF_NUMBER_OF_BRANCHES,this,Runtime::_tc_int),
47     _splittedPort(NAME_OF_SPLITTED_SEQ_OUT,this,typeOfDataSplitted),_initializingCounter(0),_unfinishedCounter(0),_failedCounter(0),_weight(), _loopWeight(0)
48 {
49   _weight.setDefaultLoop();
50 }
51
52 DynParaLoop::~DynParaLoop()
53 {
54   delete _node;
55   delete _initNode;
56   delete _finalizeNode;
57 }
58
59 DynParaLoop::DynParaLoop(const DynParaLoop& other, ComposedNode *father, bool editionOnly)
60   : ComposedNode(other,father), _nbOfBranches(other._nbOfBranches,this),
61     _splittedPort(other._splittedPort,this), _node(0), _initNode(0), _finalizeNode(0),
62     _nbOfEltConsumed(0),_initializingCounter(0),_unfinishedCounter(0),_failedCounter(0),_weight(other._weight), _loopWeight(other._loopWeight)
63 {
64   if(other._node)
65     _node=other._node->clone(this,editionOnly);
66   if(other._initNode)
67     _initNode=other._initNode->clone(this,editionOnly);
68   if(other._finalizeNode)
69     _finalizeNode = other._finalizeNode->clone(this,editionOnly);
70   const AnyOutputPort& startOfLinksToReproduce=other._splittedPort;
71   set<InPort *> endsOfLinksToReproduce=startOfLinksToReproduce.edSetInPort();
72   for(set<InPort *>::iterator iter=endsOfLinksToReproduce.begin();iter!=endsOfLinksToReproduce.end();iter++)
73     edAddLink(&_splittedPort,getInPort(other.getPortName(*iter)));
74 }
75
76 Node *DynParaLoop::edSetNode(Node *node)
77 {
78   return checkConsistencyAndSetNode(_node, node);
79 }
80
81 //! This method is used to factorize methods edSetNode, edSetInitNode and edSetFinalizeNode
82 Node * DynParaLoop::checkConsistencyAndSetNode(Node* &nodeToReplace, Node* node)
83 {
84   if (node == NULL || nodeToReplace == node)
85     return 0;
86   if (node->_father)
87     throw Exception(string("Can't set node: node ") + node->getName() + " is not orphan.");
88   if (_node && _node != nodeToReplace && _node->getName() == node->getName())
89     throw Exception(string("Can't set node: node ") + node->getName() +
90                     " has the same name than exec node already in " + _name + ".");
91   if (_initNode && _initNode != nodeToReplace && _initNode->getName() == node->getName())
92     throw Exception(string("Can't set node: node ") + node->getName() +
93                     " has the same name than init node already in " + _name + ".");
94   if (_finalizeNode && _finalizeNode != nodeToReplace && _finalizeNode->getName() == node->getName())
95     throw Exception(string("Can't set node: node ") + node->getName() +
96                     " has the same name than finalize node already in " + _name + ".");
97   checkNoCrossHierachyWith(node);
98   ComposedNode::edRemoveChild(nodeToReplace);
99   Node * ret = nodeToReplace;
100   nodeToReplace = node;
101   nodeToReplace->_father = this;
102   // set _modified flag so that edUpdateState can refresh state
103   modified();
104   return ret;
105 }
106
107 void DynParaLoop::init(bool start)
108 {
109   ComposedNode::init(start);
110   if(!_node)
111     {
112       string what("DynParaLoop::init : no node specified for ForEachLoop with name "); what +=_name;
113       throw Exception(what);
114     }
115   _node->init(start);
116   if (_initNode) _initNode->init(start);
117   if (_finalizeNode) _finalizeNode->init(start);
118   _nbOfBranches.exInit(start);
119   _splittedPort.exInit();
120   _nbOfEltConsumed=0;
121   _failedCounter=0;
122 }
123
124 Node *DynParaLoop::edSetInitNode(Node *node)
125 {
126   return checkConsistencyAndSetNode(_initNode, node);
127 }
128
129 Node * DynParaLoop::edSetFinalizeNode(Node * node)
130 {
131   return checkConsistencyAndSetNode(_finalizeNode, node);
132 }
133
134 //! Connect an OutPort to an InPort and add control link if necessary
135 /*!
136  * Connect the ports with a data link (edAddLink)
137  * In a Loop don't add control flow link : use this only to add data back links
138  *
139  * \param start : the OutPort to connect
140  * \param end : the InPort to connect
141  * \return  true if a new link has been created, false otherwise.
142  */
143 bool DynParaLoop::edAddDFLink(OutPort *start, InPort *end) throw(YACS::Exception)
144 {
145   return edAddLink(start,end);
146 }
147
148 int DynParaLoop::getNumberOfInputPorts() const
149 {
150   return ComposedNode::getNumberOfInputPorts()+1;
151 }
152
153 int DynParaLoop::getNumberOfOutputPorts() const
154 {
155   return ComposedNode::getNumberOfOutputPorts()+1;
156 }
157
158 /*!
159  * DynParaLoop creates at runtime (exupdateState) clone of nodes. One clone per branch.
160  * This method returns the id of the branch given the node \a node.
161  * If \a node is not a dynamically created node in \a this -1 is returned.
162  */
163 int DynParaLoop::getBranchIDOfNode(Node *node) const
164 {
165   if(_node)
166     {
167       for(std::vector<Node *>::const_iterator it=_execNodes.begin();it!=_execNodes.end();it++)
168         if(node==*it)
169           return std::distance(_execNodes.begin(),it);
170     }
171   if(_finalizeNode)
172     {
173       for(std::vector<Node *>::const_iterator it=_execFinalizeNodes.begin();it!=_execFinalizeNodes.end();it++)
174         if(node==*it)
175           return std::distance(_execFinalizeNodes.begin(),it);
176     }
177   if(_initNode)
178     {
179       for(std::vector<Node *>::const_iterator it=_execInitNodes.begin();it!=_execInitNodes.end();it++)
180         if(node==*it)
181           return std::distance(_execInitNodes.begin(),it);
182     }
183   return -1;
184 }
185
186 std::list<OutputPort *> DynParaLoop::getSetOfOutputPort() const
187 {
188   list<OutputPort *> ret=ComposedNode::getSetOfOutputPort();
189   ret.push_back((OutputPort *)&_splittedPort);
190   return ret;
191 }
192
193 std::list<OutputPort *> DynParaLoop::getLocalOutputPorts() const
194 {
195   list<OutputPort *> ret=ComposedNode::getLocalOutputPorts();
196   ret.push_back((OutputPort *)&_splittedPort);
197   return ret;
198 }
199
200 OutPort *DynParaLoop::getOutPort(const std::string& name) const throw(YACS::Exception)
201 {
202   if (name == NAME_OF_SPLITTED_SEQ_OUT || name == OLD_NAME_OF_SPLITTED_SEQ_OUT)
203     return (OutPort *)&_splittedPort;
204   return ComposedNode::getOutPort(name);
205 }
206
207
208 OutputPort *DynParaLoop::getOutputPort(const std::string& name) const throw(YACS::Exception)
209 {
210   if (name == NAME_OF_SPLITTED_SEQ_OUT || name == OLD_NAME_OF_SPLITTED_SEQ_OUT)
211     return (OutputPort *)&_splittedPort;
212   return ComposedNode::getOutputPort(name);
213 }
214
215 bool DynParaLoop::isPlacementPredictableB4Run() const
216 {
217   return false;
218 }
219
220 Node *DynParaLoop::edRemoveNode()
221 {
222   return removeNode(_node);
223 }
224
225 //! This method is used to factorize methods edRemoveNode, edRemoveInitNode and edRemoveFinalizeNode
226 Node * DynParaLoop::removeNode(Node* &nodeToRemove)
227 {
228   if (!nodeToRemove)
229     return NULL;
230   ComposedNode::edRemoveChild(nodeToRemove);
231   Node * ret = nodeToRemove;
232   nodeToRemove = NULL;
233   modified();
234   return ret;
235 }
236
237 Node *DynParaLoop::edRemoveInitNode()
238 {
239   return removeNode(_initNode);
240 }
241
242 Node * DynParaLoop::edRemoveFinalizeNode()
243 {
244   return removeNode(_finalizeNode);
245 }
246
247 void DynParaLoop::edRemoveChild(Node *node) throw(YACS::Exception)
248 {
249   ComposedNode::edRemoveChild(node);
250   if(node==_node)
251     _node=0;
252   if(node==_initNode)
253     _initNode=0;
254   if(node==_finalizeNode)
255     _finalizeNode=0;
256   modified();
257 }
258
259 bool DynParaLoop::edAddChild(Node *DISOWNnode) throw(YACS::Exception)
260 {
261   return edSetNode(DISOWNnode);
262 }
263
264 std::list<Node *> DynParaLoop::edGetDirectDescendants() const
265 {
266   list<Node *> ret;
267   if(_node)
268     ret.push_back(_node);
269   if(_initNode)
270     ret.push_back(_initNode);
271   if(_finalizeNode)
272     ret.push_back(_finalizeNode);
273   return ret;
274 }
275
276 std::list<InputPort *> DynParaLoop::getSetOfInputPort() const
277 {
278   list<InputPort *> ret=ComposedNode::getSetOfInputPort();
279   ret.push_back((InputPort *)&_nbOfBranches);
280   return ret;
281 }
282
283 InputPort *DynParaLoop::getInputPort(const std::string& name) const throw(YACS::Exception)
284 {
285   if(name==NAME_OF_NUMBER_OF_BRANCHES)
286     return (InputPort *)&_nbOfBranches;
287   return ComposedNode::getInputPort(name);
288 }
289
290 std::list<InputPort *> DynParaLoop::getLocalInputPorts() const
291 {
292   list<InputPort *> ret=ComposedNode::getLocalInputPorts();
293   ret.push_back((InputPort *)&_nbOfBranches);
294   return ret;
295 }
296
297 unsigned DynParaLoop::getNumberOfBranchesCreatedDyn() const throw(YACS::Exception)
298 {
299   if(_execNodes.empty())
300     throw Exception("ForEachLoop::getNumberOfBranches : No branches created dynamically ! - ForEachLoop needs to run or to be runned to call getNumberOfBranches");
301   else
302     return _execNodes.size();
303 }
304
305 Node *DynParaLoop::getChildByShortName(const std::string& name) const throw(YACS::Exception)
306 {
307   if (_node && name == _node->getName())
308     return _node;
309   if (_initNode && name == _initNode->getName())
310     return  _initNode;
311   if (_finalizeNode && name == _finalizeNode->getName())
312     return  _finalizeNode;
313   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
314   throw Exception(what);
315 }
316
317 Node *DynParaLoop::getChildByNameExec(const std::string& name, unsigned id) const throw(YACS::Exception)
318 {
319   if(id>=getNumberOfBranchesCreatedDyn())
320     throw Exception("ForEachLoop::getChildByNameExec : invalid id - too large compared with dynamically created branches.");
321   if (_node && name == _node->getName())
322     return _execNodes[id];
323   if (_initNode && name == _initNode->getName())
324     return _execInitNodes[id];
325   if (_finalizeNode && name == _finalizeNode->getName())
326     return _execFinalizeNodes[id];
327   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
328   throw Exception(what);
329 }
330
331 void DynParaLoop::cleanDynGraph()
332 {
333   vector<Node *>::iterator iter;
334   for(iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
335     delete *iter;
336   _execNodes.clear();
337   for(iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
338     delete *iter;
339   _execInitNodes.clear();
340   for(iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
341     delete *iter;
342   _execFinalizeNodes.clear();
343 }
344
345 /*!
346  * This method applies on newly cloned on exec nodes (_execNodes/_execInitNodes)
347  * the setting of input ports coming from outside of 'this'
348  */
349 void DynParaLoop::prepareInputsFromOutOfScope(int branchNb)
350 {
351   set< InPort * > portsToSetVals=getAllInPortsComingFromOutsideOfCurrentScope();
352
353   // This tweak is to fix problems with nested dynamic loops where links are not cloned properly
354   list<InPort *> temp = getSetOfInPort();
355   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
356     {
357       if ((*iter2)->edSetOutPort().size() == 1 && *(*iter2)->edSetOutPort().begin() == NULL)
358         {
359           portsToSetVals.insert(*iter2);
360         }
361     }
362
363   // local input ports are not candidates for dynamically duplicated inport.
364   list<InputPort *> localPorts = getLocalInputPorts();
365   for(list<InputPort *>::iterator iter = localPorts.begin() ; iter != localPorts.end() ; iter++)
366     portsToSetVals.erase(*iter);
367   for(set< InPort * >::iterator iter=portsToSetVals.begin();iter!=portsToSetVals.end();iter++)
368     {
369       InputPort *curPortCasted=(InputPort *) *iter;//Cast granted by ForEachLoop::buildDelegateOf(InPort)
370       void *val=curPortCasted->get();
371       InputPort *portToSet=getDynInputPortByAbsName(branchNb,getInPortName(*iter),true);
372       if(portToSet)//portToSet==0 in case of portToSet==_splitterNode._dataPortToDispatch of ForEach
373         {
374           portToSet->put((const void *)val);
375           portToSet->edNotifyReferencedBy(nullptr,false);//This is to indicate that somewhere somebody deals with this inputport
376           //even if no direct physical link exists. This exclusively for _execNodes[branchNb]::init on the next turn of loop.
377           //false is put as 2nd parameter to tell to portToSet, do not touch to the data in case of squeezeMemory.
378         }
379     }
380 }
381
382 void DynParaLoop::putValueOnBranch(Any *val, unsigned branchId, bool first)
383 {
384   bool isDispatched = false;
385   set<InPort *> inPrtLkdWthSplttdPrt=_splittedPort.edSetInPort();
386   for(set<InPort *>::iterator iter=inPrtLkdWthSplttdPrt.begin();iter!=inPrtLkdWthSplttdPrt.end();iter++)
387     {
388       std::string portNameOnCurPrt=getPortName(*iter);
389       InputPort *portOnGivenBranch=getDynInputPortByAbsName(branchId,portNameOnCurPrt,first);//Cast granted because impossible to have cross protocol with _splittedPort
390       //see OptimizerLoop::buildDelegateOf
391       if(portOnGivenBranch)
392         {
393           if(first)
394             portOnGivenBranch->edNotifyReferencedBy(0);
395           InputPort *traducer=getRuntime()->adapt(portOnGivenBranch,
396                                                   Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME,_splittedPort.edGetType());
397           traducer->put((const void *)val);
398           isDispatched = true;
399           if(traducer!=portOnGivenBranch)
400             delete traducer;
401         }
402     }
403   if ( isDispatched )
404     {
405       Any *tmp=val->clone();
406       _splittedPort.setValue(tmp);
407       tmp->decrRef();
408     }
409 }
410
411 DynParaLoop::TypeOfNode DynParaLoop::getIdentityOfNotifyerNode(const Node *node, unsigned& id)
412 {
413   vector<Node *>::iterator iter;
414   id=0;
415   for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++,id++)
416     if (*iter==node)
417       return WORK_NODE;
418   id=0;
419   for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++,id++)
420     if (*iter==node)
421       return INIT_NODE;
422   id=0;
423   for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++,id++)
424     if (*iter==node)
425       return FINALIZE_NODE;
426 }
427
428 void DynParaLoop::setWeight(double loopWeight)
429 {
430   if(loopWeight<=0.)
431     throw Exception("DynParaLoop::setWeight : invalid input value !");
432   _loopWeight=loopWeight;
433 }
434
435 ComplexWeight* DynParaLoop::getWeight()
436 {
437   if (_loopWeight>0.)
438     _weight.setLoopWeight(_loopWeight, _node->getMaxLevelOfParallelism()); // not done in setWeight because _node can be null at that time
439   return &_weight;      
440 }
441
442 bool DynParaLoop::isMultiplicitySpecified(unsigned& value) const
443 {
444   if(_nbOfBranches.edIsManuallyInitialized())
445     if(_nbOfBranches.edGetNumberOfLinks()==0)
446       {
447         value=_nbOfBranches.getIntValue();
448         return true;
449       }
450   return false;
451 }
452
453 void DynParaLoop::forceMultiplicity(unsigned value)
454 {
455   _nbOfBranches.edRemoveAllLinksLinkedWithMe();
456   _nbOfBranches.edInit((int)value);
457 }
458
459 void DynParaLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
460 {
461   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
462   if(typeOfPortInstance!=InputPort::NAME)
463     throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop is not possible");
464 }
465
466 void DynParaLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
467 {
468   std::string linkName("(");
469   linkName += port.first->getName()+" to "+finalTarget->getName()+")";
470   if(_initNode)
471     if(isInMyDescendance(port.first->getNode())==_initNode)
472       throw Exception(std::string("Illegal link within a parallel loop: \
473 a link starting from the init node can't leave the scope of the loop.")
474                     + linkName);
475
476   if(_finalizeNode)
477     if(isInMyDescendance(port.first->getNode())==_finalizeNode)
478       throw Exception(std::string("Illegal link within a parallel loop: \
479 an output port of the finalize node can't be linked.")
480                     + linkName);
481
482   if(port.first==&_splittedPort)
483     throw Exception(std::string("Illegal link within a parallel loop: \
484 the 'evalSamples' port must be linked within the scope of the loop.")
485                     + linkName);
486 }
487
488 void DynParaLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
489 {
490   const char what[]="DynParaLoop::checkCFLinks : internal error.";
491   //First dealing checkCFLinks forwarding...
492   if(isInMyDescendance(end->getNode())==0)//no chance that _splittedPort is in starts due to buildDelegate.
493     solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
494   else
495     {//no forwarding here.
496       if(starts.size()!=1)
497         throw Exception(what);
498       //ASSERT(direction) : see DynParaLoop::checkControlDependancy only 'fw' filled.
499       if(alreadyFed==FREE_ST)
500         alreadyFed=FED_ST;
501       else if(alreadyFed==FED_ST)
502         {//Shame ! splittedPort fills a port already fed...
503           info.pushInfoLink(*(starts.begin()),end,I_USELESS);
504         }
505     }
506 }
507
508 /*!
509  * \param start : start port
510  * \param end : end port
511  * \param cross indicates if start -> end link is a DS link behind.
512  * \param fw out parameter.
513  * \param fwCross out parameter storing links where a cross has been detected.
514  * \param bw out parameter where backward links are stored.
515  * \param info : collected information
516  */
517 void DynParaLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
518                                          std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
519                                          std::vector<OutPort *>& fwCross,
520                                          std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
521                                          LinkInfo& info) const
522 {
523     fw[(ComposedNode *)this].push_back(start);
524 }
525
526 void DynParaLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
527                                 InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
528 {
529   ComposedNode::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
530   Node * startNode = isInMyDescendance(start->getNode());
531   Node * endNode = isInMyDescendance(end->getNode());
532   std::string linkName("(");
533   linkName += start->getName()+" to "+end->getName()+")";
534   
535   if(start == &_splittedPort && endNode != _node)
536     throw Exception(std::string("Illegal link within a parallel loop: \
537 the 'evalSamples' port can only be connected to the working node of the loop.")
538                     + linkName);
539   
540   if(_finalizeNode && _finalizeNode == startNode)
541     throw Exception(std::string("Illegal link within a parallel loop: \
542 the finalize node can't be the origin of a link.")
543                     + linkName);
544   
545   if(_initNode && _node == startNode && _initNode == endNode)
546     throw Exception(std::string("Illegal link within a parallel loop: \
547 can't make a link from the working node to the init node.")
548                     + linkName);
549   
550   if(_finalizeNode && _node == startNode && _finalizeNode == endNode)
551     throw Exception(std::string("Illegal link within a parallel loop: \
552 can't make a link from the working node to the finalize node.")
553                     + linkName);
554 }
555
556 /*!
557  * \note : For a given name 'name' of port in absolute form from this, returns the corresponding InputPort 
558  *         instance of the port for the branch # 'branchNb'. 
559  *         The port can be part of _node or _initNode if it exists (if 'initNodeAdmitted' is true).
560  *         \b WARNING : no check performed on  'branchNb' value to see if it is compatible with size of '_execNodes'.
561  *         This method is called to dispatch value on each InputPort linked to this->._splitterNode._splittedPort
562  */
563 InputPort *DynParaLoop::getDynInputPortByAbsName(int branchNb, const std::string& name, bool initNodeAdmitted)
564 {
565   string portName, nodeName;
566   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true);
567   Node *staticChild = getChildByName(nodeName);
568   Node *desc=isInMyDescendance(staticChild);
569   if(desc==_node)
570     {
571       splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
572       return _execNodes[branchNb]->getInputPort(portName);
573     }
574   else if(desc==_initNode)
575     if(initNodeAdmitted)
576       {
577         splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
578         return _execInitNodes[branchNb]->getInputPort(portName);
579       }
580   return 0;
581 }
582
583 void DynParaLoop::checkBasicConsistency() const throw(YACS::Exception)
584 {
585   DEBTRACE("DynParaLoop::checkBasicConsistency");
586   ComposedNode::checkBasicConsistency();
587   if(!_node)
588     throw Exception("For a dynamic loop, internal node is mandatory");
589 }
590
591 std::string DynParaLoop::getErrorReport()
592 {
593   DEBTRACE("DynParaLoop::getErrorReport: " << getName() << " " << _state);
594   YACS::StatesForNode effectiveState=getEffectiveState();
595
596   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
597     return "";
598
599   std::string report="<error node= " + getName();
600   switch(effectiveState)
601     {
602     case YACS::INVALID:
603       report=report+" state= INVALID";
604       break;
605     case YACS::ERROR:
606       report=report+" state= ERROR";
607       break;
608     case YACS::FAILED:
609       report=report+" state= FAILED";
610       break;
611     default:
612       break;
613     }
614   report=report + ">\n" ;
615   if(_errorDetails != "")
616     report=report+_errorDetails+"\n";
617
618   if(_execNodes.empty())
619     {
620       // edition node
621       list<Node *> constituents=edGetDirectDescendants();
622       for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
623         {
624           std::string rep=(*iter)->getErrorReport();
625           if(rep != "")
626             {
627               report=report+rep+"\n";
628             }
629         }
630     }
631   else
632     {
633       // execution nodes
634       for(vector<Node *>::iterator iter=_execInitNodes.begin();iter!=_execInitNodes.end();iter++)
635         {
636           std::string rep=(*iter)->getErrorReport();
637           if(rep != "")
638             {
639               report=report+rep+"\n";
640             }
641         }
642       for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
643         {
644           if(*iter)
645             {
646               std::string rep=(*iter)->getErrorReport();
647               if(rep != "")
648                 {
649                   report=report+rep+"\n";
650                 }
651             }
652         }
653       for(vector<Node *>::iterator iter=_execFinalizeNodes.begin();iter!=_execFinalizeNodes.end();iter++)
654         {
655           std::string rep=(*iter)->getErrorReport();
656           if(rep != "")
657             {
658               report=report+rep+"\n";
659             }
660         }
661     }
662
663   report=report+"</error>";
664   return report;
665 }
666
667 void DynParaLoop::forwardExecStateToOriginalBody(Node *execNode)
668 {
669   unsigned int id;
670   Node * origNode = NULL;
671   switch (getIdentityOfNotifyerNode(execNode,id))
672     {
673     case INIT_NODE:
674     {
675       origNode = _initNode;
676       break;
677     }
678     case WORK_NODE:
679     {
680       origNode = _node;
681       break;
682     }
683     case FINALIZE_NODE:
684     {
685       origNode = _finalizeNode;
686       break;
687     }
688     default:
689       YASSERT(false)
690     }
691
692   YASSERT(origNode != NULL)
693   origNode->setState(execNode->getState());
694   origNode->setErrorDetails(execNode->getErrorDetails());
695
696   ComposedNode* compNode = dynamic_cast<ComposedNode*>(origNode);
697   ComposedNode* compNodeExe = dynamic_cast<ComposedNode*>(execNode);
698   if (compNode && compNodeExe)
699     {
700       list<Node *> aChldn = compNodeExe->getAllRecursiveConstituents();
701       list<Node *>::iterator iter=aChldn.begin();
702       for(;iter!=aChldn.end();iter++)
703         {
704           Node* node=compNode->getChildByName(compNodeExe->getChildName(*iter));
705           node->setState((*iter)->getState());
706           node->setErrorDetails((*iter)->getErrorDetails());
707         }
708     }
709 }
710
711 //! Method used to notify the node that a child node has failed
712 /*!
713  * Update the current state and return the change state
714  *
715  *  \param node : the child node that has failed
716  *  \return the state change
717  */
718 YACS::Event DynParaLoop::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
719 {
720   DEBTRACE("DynParaLoop::updateStateOnFailedEventFrom " << node->getName());
721   setState(YACS::FAILED);
722   forwardExecStateToOriginalBody(node);
723   unsigned int id;
724   switch (getIdentityOfNotifyerNode(node,id))
725     {
726     case INIT_NODE:
727     {
728       _node->setState(YACS::FAILED);
729       if (_finalizeNode != NULL) _finalizeNode->setState(YACS::FAILED);
730       break;
731     }
732     case WORK_NODE:
733     {
734       if (_finalizeNode != NULL) _finalizeNode->setState(YACS::FAILED);
735       break;
736     }
737     }
738   return YACS::ABORT;
739 }
740
741 //! Clone nodes and make their placement consistent with the placement of the original ones.
742 /*!
743  *  For instance, if two original nodes are placed on a component comp1 in a container cont1
744  *  and a third one is placed on a component comp2 in the container cont1, the clones of the two
745  *  first nodes will be placed on a component comp3 in a container cont2 and the third clone
746  *  will be placed on a component comp4 in the container cont2.
747  */
748 vector<Node *> DynParaLoop::cloneAndPlaceNodesCoherently(const vector<Node *> & origNodes)
749 {
750   DEBTRACE("Begin cloneAndPlaceNodesCoherently")
751   vector<Node *> clones;
752   DeploymentTree treeToDup;
753   vector<list<ElementaryNode *> > origElemNodeList;
754   for (int i=0 ; i<origNodes.size() ; i++)
755     {
756       DEBTRACE("Cloning node " << i)
757       if (origNodes[i] == NULL)
758         {
759           DEBTRACE("Cloning node " << i << ", NULL" )
760           clones.push_back(NULL);
761           origElemNodeList.push_back(list<ElementaryNode *>());
762         }
763       else
764         {
765           DEBTRACE("Cloning node " << i << "," << origNodes[i]->getName())
766           clones.push_back(origNodes[i]->simpleClone(this, false));
767           list<ElementaryNode *> tasks = origNodes[i]->getRecursiveConstituents();
768           origElemNodeList.push_back(tasks);
769           for (list< ElementaryNode *>::iterator iter=tasks.begin() ; iter!=tasks.end() ; iter++)
770             treeToDup.appendTask(*iter, (*iter)->getDynClonerIfExists(this));
771         }
772     }
773   
774   // Build the links between clones.
775   // Only the links starting from initNode are possible.
776   if(_initNode)
777   {
778     std::vector< std::pair<OutPort *, InPort *> > outLinks = _initNode->getSetOfLinksLeavingCurrentScope();
779     std::vector< std::pair<OutPort *, InPort *> >::const_iterator it;
780     for(it=outLinks.begin(); it!=outLinks.end(); it++)
781     {
782       OutPort *startPort = it->first;
783       InPort *endPort = it->second;
784       Node* destNode = isInMyDescendance(endPort->getNode());
785       if(destNode == _node)
786         edAddLink(clones[0]->getOutPort(startPort->getName()),
787                   clones[1]->getInPort(endPort->getName()));
788       if(destNode == _finalizeNode)
789         edAddLink(clones[0]->getOutPort(startPort->getName()),
790                   clones[2]->getInPort(endPort->getName()));
791     }
792   }
793
794   DEBTRACE("Placing nodes...")
795   vector<Container *> conts=treeToDup.getAllContainers();
796
797   //iterate on all containers
798   for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
799     {
800       DEBTRACE("Container " << ((*iterCt)?(*iterCt)->getName():"NULL"))
801       vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
802       Container *contCloned=0;
803       if((*iterCt))
804         contCloned=(*iterCt)->clone();
805
806       //iterate on all component instances linked to the container
807       for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
808         {
809           DEBTRACE("Component " << (*iterCp)->getCompoName())
810           vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
811           ComponentInstance *curCloned=(*iterCp)->clone();
812           DEBTRACE("Assign container " << (*iterCp)->getCompoName())
813           curCloned->setContainer(contCloned);
814           for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
815             {
816               DEBTRACE("Task " << ((ElementaryNode *)(*iterT))->getName())
817               int i = 0;
818               ElementaryNode * origElemNode = NULL;
819               for (i=0 ; i<origNodes.size() ; i++)
820                 if (origNodes[i] != NULL)
821                   {
822                     DEBTRACE("Looking in original node " << i)
823                     list<ElementaryNode *>::iterator res=find(origElemNodeList[i].begin(),
824                                                               origElemNodeList[i].end(),
825                                                               (ElementaryNode *)(*iterT));
826                     if (res != origElemNodeList[i].end()) {
827                       origElemNode = *res;
828                       break;
829                     }
830                   }
831
832               YASSERT(origElemNode != NULL)
833               DEBTRACE("Found task in node " << i)
834               ServiceNode * nodeC = NULL;
835               if (origNodes[i] == origElemNode)
836                 nodeC = (ServiceNode *)clones[i];
837               else
838                 {
839                   string childName = ((ComposedNode *)origNodes[i])->getChildName(origElemNode);
840                   nodeC = (ServiceNode *)clones[i]->getChildByName(childName);
841                 }
842               DEBTRACE("Assign component: " << (*iterCp)->getCompoName() << "," << nodeC->getName())
843               nodeC->setComponent(curCloned);
844             }
845           curCloned->decrRef();
846         }
847
848       // iterate on all tasks linked to the container
849       vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
850       for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
851         {
852           DEBTRACE("Task " << ((ElementaryNode *)(*iterT))->getName())
853           int i = 0;
854           ElementaryNode * origElemNode = NULL;
855           for (i=0 ; i<origNodes.size() ; i++)
856             if (origNodes[i] != NULL)
857               {
858                 DEBTRACE("Looking in original node " << i)
859                 list<ElementaryNode *>::iterator res=find(origElemNodeList[i].begin(),
860                                                           origElemNodeList[i].end(),
861                                                           (ElementaryNode *)(*iterT));
862                 if (res != origElemNodeList[i].end()) 
863                   {
864                     origElemNode = *res;
865                     break;
866                   }
867               }
868           YASSERT(origElemNode != NULL)
869           DEBTRACE("Found task in node " << i)
870           InlineFuncNode * nodeC = NULL;
871           if (origNodes[i] == origElemNode)
872             {
873               nodeC = (InlineFuncNode *)clones[i];
874             }
875           else
876             {
877               string childName = ((ComposedNode *)origNodes[i])->getChildName(origElemNode);
878               nodeC = (InlineFuncNode *)clones[i]->getChildByName(childName);
879             }
880           DEBTRACE("Assign container " << nodeC->getName() << "," << contCloned->getName())
881           nodeC->setContainer(contCloned);
882         }
883
884       // ended with current container
885       if(contCloned)
886         contCloned->decrRef();
887     }
888
889   DEBTRACE("End cloneAndPlaceNodesCoherently")
890   return clones;
891 }
892
893 void DynParaLoop::accept(Visitor *visitor)
894 {
895   visitor->visitDynParaLoop(this);
896 }
897
898 Node * DynParaLoop::getInitNode()
899 {
900   return _initNode;
901 }
902
903 Node * DynParaLoop::getExecNode()
904 {
905   return _node;
906 }
907
908 Node * DynParaLoop::getFinalizeNode()
909 {
910   return _finalizeNode;
911 }
912
913 int DynParaLoop::getMaxLevelOfParallelism() const
914 {
915   return _nbOfBranches.getIntValue() * _node->getMaxLevelOfParallelism();
916 }
917
918 void DynParaLoop::partitionRegardingDPL(const PartDefinition *pd, std::map<ComposedNode *, YACS::BASES::AutoRefCnt<PartDefinition> >& zeMap)
919 {
920   YACS::BASES::AutoRefCnt<PartDefinition> pd2(pd->copy());
921   zeMap[this]=pd2;
922   if(_node)
923     _node->partitionRegardingDPL(pd,zeMap);
924 }
925
926 void DynParaLoop::shutdown(int level)
927 {
928   if(level==0)return;
929   if(!_node) return;
930
931   std::vector<Node *>::iterator iter;
932   for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
933     (*iter)->shutdown(level);
934   for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
935     (*iter)->shutdown(level);
936   for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
937     (*iter)->shutdown(level);
938 }