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