Salome HOME
9f277975fe3e8ef3bd88a5275e48a5c04d582ab8
[modules/yacs.git] / src / engine / ForEachLoop.cxx
1 // Copyright (C) 2006-2013  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.
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 "ForEachLoop.hxx"
21 #include "TypeCode.hxx"
22 #include "Visitor.hxx"
23 #include "ComposedNode.hxx"
24 #include <iostream>
25 #include <sstream>
26
27 //#define _DEVDEBUG_
28 #include "YacsTrace.hxx"
29
30 using namespace YACS::ENGINE;
31 using namespace std;
32
33 /*! \class YACS::ENGINE::ForEachLoop
34  *  \brief Loop node for parametric calculation
35  *
36  *  \ingroup Nodes
37  */
38
39 const char FakeNodeForForEachLoop::NAME[]="thisIsAFakeNode";
40
41 const char SplitterNode::NAME_OF_SEQUENCE_INPUT[]="SmplsCollection";
42
43 const char ForEachLoop::NAME_OF_SPLITTERNODE[]="splitter";
44
45 const int ForEachLoop::NOT_RUNNING_BRANCH_ID=-1;
46
47 InterceptorInputPort::InterceptorInputPort(const std::string& name, Node *node, TypeCode* type):AnyInputPort(name,node,type),
48                                                                                                 DataPort(name,node,type),Port(node),
49                                                                                                 _repr(0)
50 {
51 }
52
53 InterceptorInputPort::InterceptorInputPort(const  InterceptorInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),
54                                                                                                 Port(other,newHelder),
55                                                                                                 _repr(0)
56 {
57 }
58
59 void InterceptorInputPort::getAllRepresentants(std::set<InPort *>& repr) const
60 {
61   set<InPort *> ports=_repr->edSetInPort();
62   for(set<InPort *>::iterator iter=ports.begin();iter!=ports.end();iter++)
63     (*iter)->getAllRepresentants(repr);
64 }
65
66 InputPort *InterceptorInputPort::clone(Node *newHelder) const
67 {
68   return new InterceptorInputPort(*this,newHelder);
69 }
70
71 void InterceptorInputPort::setRepr(AnySplitOutputPort *repr)
72 {
73   _repr=repr;
74 }
75
76 bool AnySplitOutputPort::decrRef()
77 {
78   return (--_cnt==0);
79 }
80
81 void AnySplitOutputPort::incrRef() const
82 {
83   _cnt++;
84 }
85
86 AnySplitOutputPort::AnySplitOutputPort(const std::string& name, Node *node, TypeCode *type):OutputPort(name,node,type),
87                                                                                             DataPort(name,node,type),Port(node),
88                                                                                             _repr(0),_intercptr(0),_cnt(1)
89 {
90 }
91
92 AnySplitOutputPort::AnySplitOutputPort(const AnySplitOutputPort& other, Node *newHelder):OutputPort(other,newHelder),
93                                                                                          DataPort(other,newHelder),
94                                                                                          Port(other,newHelder),
95                                                                                          _repr(0),_intercptr(0),_cnt(1)
96 {
97 }
98
99 bool AnySplitOutputPort::addInPort(InPort *inPort) throw(YACS::Exception)
100 {
101   bool ret=OutputPort::addInPort(inPort);
102   if(_repr)
103     _repr->addInPort(_intercptr);
104   return ret;
105 }
106
107 void AnySplitOutputPort::getAllRepresented(std::set<OutPort *>& represented) const
108 {
109   if(!_repr)
110     OutPort::getAllRepresented(represented);
111   else
112     _repr->getAllRepresented(represented);
113 }
114
115 int AnySplitOutputPort::removeInPort(InPort *inPort, bool forward) throw(YACS::Exception)
116 {
117   bool ret=OutputPort::removeInPort(inPort,forward);
118   if(_repr)
119     if(_setOfInputPort.empty())
120       _repr->removeInPort(_intercptr,forward);
121   return ret;
122 }
123
124 void AnySplitOutputPort::addRepr(OutPort *repr, InterceptorInputPort *intercptr)
125 {
126   _repr=repr;
127   _intercptr=intercptr;
128 }
129
130 OutputPort *AnySplitOutputPort::clone(Node *newHelder) const
131 {
132   return new AnySplitOutputPort(*this,newHelder);
133 }
134
135 SeqAnyInputPort::SeqAnyInputPort(const std::string& name, Node *node, TypeCodeSeq* type):AnyInputPort(name,node,type),DataPort(name,node,type),Port(node)
136 {
137   _type->decrRef();
138 }
139
140 SeqAnyInputPort::SeqAnyInputPort(const  SeqAnyInputPort& other, Node *newHelder):AnyInputPort(other,newHelder),DataPort(other,newHelder),Port(other,newHelder)
141 {
142 }
143
144 InputPort *SeqAnyInputPort::clone(Node *newHelder) const
145 {
146   return new SeqAnyInputPort(*this,newHelder);
147 }
148
149 unsigned SeqAnyInputPort::getNumberOfElements() const
150 {
151   const SequenceAny * valCsted=(const SequenceAny *) _value;
152   if (valCsted) return valCsted->size();
153   return 0;
154 }
155
156 Any *SeqAnyInputPort::getValueAtRank(int i) const
157 {
158   const SequenceAny * valCsted=(const SequenceAny *) _value;
159   AnyPtr ret=(*valCsted)[i];
160   ret->incrRef();
161   return ret;
162 }
163
164 std::string SeqAnyInputPort::dump()
165 {
166   stringstream xmldump;
167   int nbElem = getNumberOfElements();
168   xmldump << "<value><array><data>" << endl;
169   for (int i = 0; i < nbElem; i++)
170     {
171       Any *val = getValueAtRank(i);
172       switch (val->getType()->kind())
173         {
174         case Double:
175           xmldump << "<value><double>" << val->getDoubleValue() << "</double></value>" << endl;
176           break;
177         case Int:
178           xmldump << "<value><int>" << val->getIntValue() << "</int></value>" << endl;
179           break;
180         case Bool:
181           xmldump << "<value><boolean>" << val->getBoolValue() << "</boolean></value>" << endl;
182           break;
183         case String:
184           xmldump << "<value><string>" << val->getStringValue() << "</string></value>" << endl;
185           break;
186         case Objref:
187           xmldump << "<value><objref>" << val->getStringValue() << "</objref></value>" << endl;
188           break;
189         default:
190           xmldump << "<value><error> NO_SERIALISATION_AVAILABLE </error></value>" << endl;
191           break;
192         }
193     }
194   xmldump << "</data></array></value>" << endl;
195   return xmldump.str();
196 }
197
198 SplitterNode::SplitterNode(const std::string& name, TypeCode *typeOfData, 
199                            ForEachLoop *father):ElementaryNode(name),
200                                                 _dataPortToDispatch(NAME_OF_SEQUENCE_INPUT,
201                                                                     this,(TypeCodeSeq *)TypeCode::sequenceTc("","",typeOfData))
202 {
203   _father=father;
204 }
205
206 SplitterNode::SplitterNode(const SplitterNode& other, ForEachLoop *father):ElementaryNode(other,father),
207                                                                            _dataPortToDispatch(other._dataPortToDispatch,this)
208 {
209 }
210
211 InputPort *SplitterNode::getInputPort(const std::string& name) const throw(YACS::Exception)
212 {
213   if(name==NAME_OF_SEQUENCE_INPUT)
214     return (InputPort *)&_dataPortToDispatch;
215   else
216     return ElementaryNode::getInputPort(name);
217 }
218
219 Node *SplitterNode::simpleClone(ComposedNode *father, bool editionOnly) const
220 {
221   return new SplitterNode(*this,(ForEachLoop *)father);
222 }
223
224 unsigned SplitterNode::getNumberOfElements() const
225 {
226   return _dataPortToDispatch.getNumberOfElements();
227 }
228
229 void SplitterNode::execute()
230 {
231   //Nothing : should never been called elsewhere big problem...
232 }
233
234 void SplitterNode::init(bool start)
235 {
236   ElementaryNode::init(start);
237   _dataPortToDispatch.exInit(start);
238 }
239
240 void SplitterNode::putSplittedValueOnRankTo(int rankInSeq, int branch, bool first)
241 {
242   Any *valueToDispatch=_dataPortToDispatch.getValueAtRank(rankInSeq);
243   ForEachLoop *fatherTyped=(ForEachLoop *)_father;
244   fatherTyped->putValueOnBranch(valueToDispatch,branch,first);
245   valueToDispatch->decrRef();
246 }
247
248 FakeNodeForForEachLoop::FakeNodeForForEachLoop(ForEachLoop *loop, bool normalFinish):ElementaryNode(NAME),
249                                                                                      _loop(loop),
250                                                                                      _normalFinish(normalFinish)
251 {
252   _state=YACS::TOACTIVATE;
253   _father=_loop->getFather();
254 }
255
256 FakeNodeForForEachLoop::FakeNodeForForEachLoop(const FakeNodeForForEachLoop& other):ElementaryNode(other),_loop(0),
257                                                                                     _normalFinish(false)
258 {
259 }
260
261 Node *FakeNodeForForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
262 {
263   return new FakeNodeForForEachLoop(*this);
264 }
265
266 void FakeNodeForForEachLoop::exForwardFailed()
267 {
268   _loop->exForwardFailed();
269 }
270
271 void FakeNodeForForEachLoop::exForwardFinished()
272
273   _loop->exForwardFinished();
274 }
275
276 void FakeNodeForForEachLoop::execute()
277 {
278   if(!_normalFinish)
279     throw Exception("");//only to trigger ABORT on Executor
280   else
281     _loop->pushAllSequenceValues();
282 }
283
284 void FakeNodeForForEachLoop::aborted()
285 {
286   _loop->setState(YACS::ERROR);
287 }
288
289 void FakeNodeForForEachLoop::finished()
290 {
291   _loop->setState(YACS::DONE);
292 }
293
294 ForEachLoop::ForEachLoop(const std::string& name, TypeCode *typeOfDataSplitted):DynParaLoop(name,typeOfDataSplitted),
295                                                                                 _splitterNode(NAME_OF_SPLITTERNODE,typeOfDataSplitted,this),
296                                                                                 _execCurrentId(0),_nodeForSpecialCases(0),_currentIndex(0)
297 {
298 }
299
300 ForEachLoop::ForEachLoop(const ForEachLoop& other, ComposedNode *father, bool editionOnly):DynParaLoop(other,father,editionOnly),
301                                                                                            _splitterNode(other._splitterNode,this),
302                                                                                            _execCurrentId(0),_nodeForSpecialCases(0),_currentIndex(0)
303 {
304   int i=0;
305   if(!editionOnly)
306     for(vector<AnySplitOutputPort *>::const_iterator iter2=other._outGoingPorts.begin();iter2!=other._outGoingPorts.end();iter2++,i++)
307       {
308         AnySplitOutputPort *temp=new AnySplitOutputPort(*(*iter2),this);
309         InterceptorInputPort *interc=new InterceptorInputPort(*other._intecptrsForOutGoingPorts[i],this);
310         temp->addRepr(getOutPort((*iter2)->getName()),interc);
311         interc->setRepr(temp);
312         _outGoingPorts.push_back(temp);
313         _intecptrsForOutGoingPorts.push_back(interc);
314       }
315 }
316
317 Node *ForEachLoop::simpleClone(ComposedNode *father, bool editionOnly) const
318 {
319   return new ForEachLoop(*this,father,editionOnly);
320 }
321
322 ForEachLoop::~ForEachLoop()
323 {
324   cleanDynGraph();
325   for(vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
326     delete *iter;
327   for(vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();iter2!=_intecptrsForOutGoingPorts.end();iter2++)
328     delete *iter2;
329 }
330
331 void ForEachLoop::init(bool start)
332 {
333   DynParaLoop::init(start);
334   _splitterNode.init(start);
335   _execCurrentId=0;
336   cleanDynGraph();
337   _currentIndex = 0;
338   exUpdateProgress();
339 }
340
341 void ForEachLoop::exUpdateState()
342 {
343   DEBTRACE("ForEachLoop::exUpdateState");
344   if(_state == YACS::DISABLED)
345     return;
346   if(_inGate.exIsReady())
347     {
348       //internal graph update
349       int i;
350       int nbOfBr=_nbOfBranches.getIntValue();
351       int nbOfElts=_splitterNode.getNumberOfElements();
352
353       DEBTRACE("nbOfElts=" << nbOfElts);
354       DEBTRACE("nbOfBr=" << nbOfBr);
355
356       if(nbOfElts==0)
357         {
358           prepareSequenceValues(0);
359           delete _nodeForSpecialCases;
360           _nodeForSpecialCases=new FakeNodeForForEachLoop(this,true);
361           setState(YACS::ACTIVATED);
362           return ;
363         }
364       if(nbOfBr<=0)
365         {
366           delete _nodeForSpecialCases;
367           _nodeForSpecialCases=new FakeNodeForForEachLoop(this,getAllOutPortsLeavingCurrentScope().empty());
368           setState(YACS::ACTIVATED);
369           return ;
370         }
371       if(nbOfBr>nbOfElts)
372         nbOfBr=nbOfElts;
373       _execNodes.resize(nbOfBr);
374       _execIds.resize(nbOfBr);
375       _execOutGoingPorts.resize(nbOfBr);
376       prepareSequenceValues(nbOfElts);
377       if(_initNode)
378         _execInitNodes.resize(nbOfBr);
379       _initializingCounter = 0;
380       if (_finalizeNode)
381         _execFinalizeNodes.resize(nbOfBr);
382
383       vector<Node *> origNodes;
384       origNodes.push_back(_initNode);
385       origNodes.push_back(_node);
386       origNodes.push_back(_finalizeNode);
387
388       //Conversion exceptions can be thrown by createOutputOutOfScopeInterceptors 
389       //so catch them to control errors
390       try
391         {
392           for(i=0;i<nbOfBr;i++)
393             {
394               DEBTRACE( "-------------- 1 " << i << " " << _execCurrentId);
395               _execIds[i]=_execCurrentId;
396               DEBTRACE( "-------------- 2" );
397               vector<Node *> clonedNodes = cloneAndPlaceNodesCoherently(origNodes);
398               if(_initNode)
399                 _execInitNodes[i] = clonedNodes[0];
400               _execNodes[i] = clonedNodes[1];
401               if(_finalizeNode)
402                 _execFinalizeNodes[i] = clonedNodes[2];
403               DEBTRACE( "-------------- 4" );
404               prepareInputsFromOutOfScope(i);
405               DEBTRACE( "-------------- 5" );
406               createOutputOutOfScopeInterceptors(i);
407               DEBTRACE( "-------------- 6" );
408               _splitterNode.putSplittedValueOnRankTo(_execCurrentId++,i,true);
409               DEBTRACE( "-------------- 7" );
410             } 
411         }
412       catch(YACS::Exception& ex)
413         {
414           //ForEachLoop must be put in error and the exception rethrown to notify the caller
415           DEBTRACE( "ForEachLoop::exUpdateState: " << ex.what() );
416           setState(YACS::ERROR);
417           exForwardFailed();
418           throw;
419         }
420
421       setState(YACS::ACTIVATED); // move the calling of setState method there for adding observers for clone nodes in GUI part
422
423       //let's go
424       for(i=0;i<nbOfBr;i++)
425         if(_initNode)
426           {
427             _execInitNodes[i]->exUpdateState();
428             _initializingCounter++;
429           }
430         else
431           {
432             _nbOfEltConsumed++;
433             _execNodes[i]->exUpdateState();
434           }
435
436       forwardExecStateToOriginalBody(_execNodes[nbOfBr-1]);
437     }
438 }
439
440 void ForEachLoop::exUpdateProgress()
441 {
442   // emit notification to all observers registered with the dispatcher on any change of the node's state
443   sendEvent("progress");
444 }
445
446 void ForEachLoop::getReadyTasks(std::vector<Task *>& tasks)
447 {
448   if(!_node)
449     return;
450   if(_state==YACS::TOACTIVATE) setState(YACS::ACTIVATED);
451   if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
452     {
453       if(_nodeForSpecialCases)
454         {
455           _nodeForSpecialCases->getReadyTasks(tasks);
456           return ;
457         }
458       vector<Node *>::iterator iter;
459       for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
460         (*iter)->getReadyTasks(tasks);
461       for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
462         (*iter)->getReadyTasks(tasks);
463       for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
464         (*iter)->getReadyTasks(tasks);
465     }
466 }
467
468 int ForEachLoop::getNumberOfInputPorts() const
469 {
470   return DynParaLoop::getNumberOfInputPorts()+1;
471 }
472
473 void ForEachLoop::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
474 {
475   //TO DO
476 }
477
478 void ForEachLoop::selectRunnableTasks(std::vector<Task *>& tasks)
479 {
480 }
481
482 std::list<InputPort *> ForEachLoop::getSetOfInputPort() const
483 {
484   list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
485   ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
486   return ret;
487 }
488
489 std::list<InputPort *> ForEachLoop::getLocalInputPorts() const
490 {
491   list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
492   ret.push_back((InputPort *)&_splitterNode._dataPortToDispatch);
493   return ret;
494 }
495
496 InputPort *ForEachLoop::getInputPort(const std::string& name) const throw(YACS::Exception)
497 {
498   if(name==SplitterNode::NAME_OF_SEQUENCE_INPUT)
499     return (InputPort *)&_splitterNode._dataPortToDispatch;
500   else
501     return DynParaLoop::getInputPort(name);
502 }
503
504 OutputPort *ForEachLoop::getOutputPort(const std::string& name) const throw(YACS::Exception)
505 {
506   for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
507     {
508       if(name==(*iter)->getName())
509         return (OutputPort *)(*iter);
510     }
511   return DynParaLoop::getOutputPort(name);
512 }
513
514 OutPort *ForEachLoop::getOutPort(const std::string& name) const throw(YACS::Exception)
515 {
516   for(vector<AnySplitOutputPort *>::const_iterator iter=_outGoingPorts.begin();iter!=_outGoingPorts.end();iter++)
517     {
518       if(name==(*iter)->getName())
519         return (OutPort *)(*iter);
520     }
521   return DynParaLoop::getOutPort(name);
522 }
523
524 Node *ForEachLoop::getChildByShortName(const std::string& name) const throw(YACS::Exception)
525 {
526   if(name==NAME_OF_SPLITTERNODE)
527     return (Node *)&_splitterNode;
528   else
529     return DynParaLoop::getChildByShortName(name);
530 }
531
532 //! Method used to notify the node that a child node has finished
533 /*!
534  * Update the current state and return the change state
535  *
536  *  \param node : the child node that has finished
537  *  \return the state change
538  */
539 YACS::Event ForEachLoop::updateStateOnFinishedEventFrom(Node *node)
540 {
541   DEBTRACE("updateStateOnFinishedEventFrom " << node->getName() << " " << node->getState());
542   unsigned int id;
543   switch(getIdentityOfNotifyerNode(node,id))
544     {
545     case INIT_NODE:
546       _execNodes[id]->exUpdateState();
547       _nbOfEltConsumed++;
548       _initializingCounter--;
549       if (_initializingCounter == 0) _initNode->setState(DONE);
550       break;
551     case WORK_NODE:
552       _currentIndex++;
553       exUpdateProgress();
554       storeOutValsInSeqForOutOfScopeUse(_execIds[id],id);
555       if(_execCurrentId==_splitterNode.getNumberOfElements())
556         {//No more elements of _dataPortToDispatch to treat
557           _execIds[id]=NOT_RUNNING_BRANCH_ID;
558           //analyzing if some samples are still on treatment on other branches.
559           bool isFinished=true;
560           for(int i=0;i<_execIds.size() && isFinished;i++)
561             isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID);
562           if(isFinished)
563             {
564               try 
565                 {
566                   pushAllSequenceValues();
567   
568                   if (_node)
569                     {
570                       _node->setState(YACS::DONE);
571      
572                       ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
573                       if (compNode)
574                         {
575                           std::list<Node *> aChldn = compNode->getAllRecursiveConstituents();
576                           std::list<Node *>::iterator iter=aChldn.begin();
577                           for(;iter!=aChldn.end();iter++)
578                             (*iter)->setState(YACS::DONE);
579                         }
580                     }
581
582                   if (_finalizeNode == NULL)
583                     {
584                       // No finalize node, we just finish the loop at the end of exec nodes execution
585                       setState(YACS::DONE);
586                       return YACS::FINISH;
587                     }
588                   else
589                     {
590                       // Run the finalize nodes, the loop will be done only when they all finish
591                       _unfinishedCounter = 0;  // This counter indicates how many branches are not finished
592                       for (int i=0 ; i<_execIds.size() ; i++)
593                         {
594                           YASSERT(_execIds[i] == NOT_RUNNING_BRANCH_ID);
595                           DEBTRACE("Launching finalize node for branch " << i);
596                           _execFinalizeNodes[i]->exUpdateState();
597                           _unfinishedCounter++;
598                         }
599                       return YACS::NOEVENT;
600                     }
601                 }
602               catch(YACS::Exception& ex)
603                 {
604                   DEBTRACE("ForEachLoop::updateStateOnFinishedEventFrom: "<<ex.what());
605                   //no way to push results : put following nodes in FAILED state
606                   //TODO could be more fine grain : put only concerned nodes in FAILED state
607                   exForwardFailed();
608                   setState(YACS::ERROR);
609                   return YACS::ABORT;
610                 }
611             }
612         }
613       else if(_state == YACS::ACTIVATED)
614         {//more elements to do and loop still activated
615           _execIds[id]=_execCurrentId;
616           node->init(false);
617           _splitterNode.putSplittedValueOnRankTo(_execCurrentId++,id,false);
618           node->exUpdateState();
619           forwardExecStateToOriginalBody(node);
620           _nbOfEltConsumed++;
621         }
622       else
623         {//elements to process and loop no more activated
624           DEBTRACE("foreach loop state " << _state);
625         }
626       break;
627     case FINALIZE_NODE:
628     {
629       DEBTRACE("Finalize node finished on branch " << id);
630       _unfinishedCounter--;
631       _currentIndex++;
632       exUpdateProgress();
633       DEBTRACE(_unfinishedCounter << " finalize nodes still running");
634       if (_unfinishedCounter == 0)
635         {
636           _finalizeNode->setState(YACS::DONE);
637           setState(YACS::DONE);
638           return YACS::FINISH;
639         }
640       else
641         return YACS::NOEVENT;
642       break;
643     }
644     default:
645       YASSERT(false);
646     }
647   return YACS::NOEVENT;
648 }
649
650 void ForEachLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
651 {
652   DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
653   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
654   if(typeOfPortInstance==OutputPort::NAME)
655     {
656       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
657       int i=0;
658       for(;iter!=_outGoingPorts.end();iter++,i++)
659         if((*iter)->getRepr()==port.first)
660           break;
661       if(iter!=_outGoingPorts.end())
662         {
663           (*iter)->incrRef();
664           (*iter)->addRepr(port.first,_intecptrsForOutGoingPorts[i]);
665           port.first=*iter;
666         }
667       else
668         {
669           TypeCodeSeq *newTc=(TypeCodeSeq *)TypeCode::sequenceTc("","",port.first->edGetType());
670           AnySplitOutputPort *newPort=new AnySplitOutputPort(getPortName(port.first),this,newTc);
671           InterceptorInputPort *intercptor=new InterceptorInputPort(string("intercptr for ")+getPortName(port.first),this,port.first->edGetType());
672           intercptor->setRepr(newPort);
673           newTc->decrRef();
674           newPort->addRepr(port.first,intercptor);
675           _outGoingPorts.push_back(newPort);
676           _intecptrsForOutGoingPorts.push_back(intercptor);
677           port.first=newPort;
678         }
679     }
680   else
681     throw Exception("ForEachLoop::buildDelegateOf : not implemented for DS because not specified");
682 }
683
684 void ForEachLoop::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
685 {
686   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
687   if(typeOfPortInstance==OutputPort::NAME)
688     {
689       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
690       for(;iter!=_outGoingPorts.end();iter++)
691         if((*iter)->getRepr()==port.first)
692           break;
693       if(iter==_outGoingPorts.end())
694         {
695           string what("ForEachLoop::getDelegateOf : Port with name "); what+=port.first->getName(); what+=" not exported by ForEachLoop "; what+=_name; 
696           throw Exception(what);
697         }
698       else
699         port.first=(*iter);
700     }
701   else
702     throw Exception("ForEachLoop::getDelegateOf : not implemented because not specified");
703 }
704
705 void ForEachLoop::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
706 {
707   string typeOfPortInstance=portDwn->getNameOfTypeOfCurrentInstance();
708   if(typeOfPortInstance==OutputPort::NAME)
709     {
710       vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
711       vector<InterceptorInputPort *>::iterator iter2=_intecptrsForOutGoingPorts.begin();
712       for(;iter!=_outGoingPorts.end();iter++,iter2++)
713         if((*iter)->getRepr()==portDwn)
714           break;
715       //ASSERT(portUp==*iter.second)
716       if((*iter)->decrRef())
717         {
718           AnySplitOutputPort *p=*iter;
719           _outGoingPorts.erase(iter);
720           delete p;
721           InterceptorInputPort *ip=*iter2;
722           _intecptrsForOutGoingPorts.erase(iter2);
723           delete ip;
724         }
725     }
726 }
727
728 OutPort *ForEachLoop::getDynOutPortByAbsName(int branchNb, const std::string& name)
729 {
730   string portName, nodeName;
731   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
732   Node *staticChild = getChildByName(nodeName);
733   return _execNodes[branchNb]->getOutPort(portName);//It's impossible(garanteed by YACS::ENGINE::ForEachLoop::buildDelegateOf)
734   //that a link starting from _initNode goes out of scope of 'this'.
735 }
736
737 void ForEachLoop::cleanDynGraph()
738 {
739   DynParaLoop::cleanDynGraph();
740   for(vector< SequenceAny *>::iterator iter3=_execVals.begin();iter3!=_execVals.end();iter3++)
741     (*iter3)->decrRef();
742   _execVals.clear();
743   for(vector< vector<AnyInputPort *> >::iterator iter4=_execOutGoingPorts.begin();iter4!=_execOutGoingPorts.end();iter4++)
744     for(vector<AnyInputPort *>::iterator iter5=(*iter4).begin();iter5!=(*iter4).end();iter5++)
745       delete *iter5;
746   _execOutGoingPorts.clear();
747 }
748
749 void ForEachLoop::storeOutValsInSeqForOutOfScopeUse(int rank, int branchNb)
750 {
751   vector<AnyInputPort *>::iterator iter;
752   int i=0;
753   for(iter=_execOutGoingPorts[branchNb].begin();iter!=_execOutGoingPorts[branchNb].end();iter++,i++)
754     {
755       Any *val=(Any *)(*iter)->getValue();
756       _execVals[i]->setEltAtRank(rank,val);
757     }
758 }
759
760 void ForEachLoop::prepareSequenceValues(int sizeOfSamples)
761 {
762   _execVals.resize(_outGoingPorts.size());
763   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
764   for(int i=0;iter!=_outGoingPorts.end();iter++,i++)
765     _execVals[i]=SequenceAny::New((*iter)->edGetType()->contentType(),sizeOfSamples);
766 }
767
768 void ForEachLoop::pushAllSequenceValues()
769 {
770   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
771   int i=0;
772   for(;iter!=_outGoingPorts.end();iter++,i++)
773     (*iter)->put((const void *)_execVals[i]);
774 }
775
776 void ForEachLoop::createOutputOutOfScopeInterceptors(int branchNb)
777 {
778   vector<AnySplitOutputPort *>::iterator iter=_outGoingPorts.begin();
779   int i=0;
780   for(;iter!=_outGoingPorts.end();iter++,i++)
781     {
782       DEBTRACE( (*iter)->getName() << " " << (*iter)->edGetType()->kind() );
783       //AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,(*iter)->edGetType());
784       OutPort *portOut=getDynOutPortByAbsName(branchNb,getOutPortName(((*iter)->getRepr())));
785       DEBTRACE( portOut->getName() );
786       AnyInputPort *interceptor=new AnyInputPort((*iter)->getName(),this,portOut->edGetType());
787       portOut->addInPort(interceptor);
788       _execOutGoingPorts[branchNb].push_back(interceptor);
789     }
790 }
791
792 void ForEachLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
793                                        InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
794 {
795   if(isInMyDescendance(start->getNode())==_node)
796     throw Exception("ForEachLoop::checkLinkPossibility : A link from work node to init node not permitted");
797 }
798
799 std::list<OutputPort *> ForEachLoop::getLocalOutputPorts() const
800 {
801   list<OutputPort *> ret;
802   ret.push_back(getOutputPort(NAME_OF_SPLITTED_SEQ_OUT)); 
803   return ret;
804 }
805
806 void ForEachLoop::accept(Visitor *visitor)
807 {
808   visitor->visitForEachLoop(this);
809 }
810
811 //! Dump the node state to a stream
812 /*!
813  * \param os : the output stream
814  */
815 void ForEachLoop::writeDot(std::ostream &os) const
816 {
817   os << "  subgraph cluster_" << getId() << "  {\n" ;
818   //only one node in a loop
819   if(_node)
820     {
821       _node->writeDot(os);
822       os << getId() << " -> " << _node->getId() << ";\n";
823     }
824   os << "}\n" ;
825   os << getId() << "[fillcolor=\"" ;
826   YACS::StatesForNode state=getEffectiveState();
827   os << getColorState(state);
828   os << "\" label=\"" << "Loop:" ;
829   os << getName() <<"\"];\n";
830 }
831
832 //! Reset the state of the node and its children depending on the parameter level
833 void ForEachLoop::resetState(int level)
834 {
835   if(level==0)return;
836   DynParaLoop::resetState(level);
837   _execCurrentId=0;
838   //Note: cleanDynGraph is not a virtual method (must be called from ForEachLoop object) 
839   cleanDynGraph();
840 }
841
842 std::string ForEachLoop::getProgress() const
843 {
844   int nbElems = _splitterNode.getNumberOfElements();
845   char* aProgress = new char[];
846   if (nbElems > 0)
847     sprintf(aProgress, "%i/%i", _currentIndex, nbElems);
848   else
849     sprintf(aProgress, "0");
850   return aProgress;
851 }