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