Salome HOME
Merge branch 'V8_0_0_BR'
[modules/yacs.git] / src / evalyfx / YACSEvalYFXPattern.cxx
1 // Copyright (C) 2012-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 // Author : Anthony Geay (EDF R&D)
20
21 #include "YACSEvalYFXPattern.hxx"
22 #include "YACSEvalResource.hxx"
23 #include "YACSEvalSeqAny.hxx"
24 #include "YACSEvalObserver.hxx"
25 #include "YACSEvalAutoPtr.hxx"
26
27 #include "ElementaryNode.hxx"
28 #include "RuntimeSALOME.hxx"
29 #include "Dispatcher.hxx"
30 #include "Executor.hxx"
31 #include "InputPort.hxx"
32 #include "LinkInfo.hxx"
33 #include "TypeCode.hxx"
34 #include "Proc.hxx"
35
36 #include "PythonPorts.hxx"
37 #include "ForEachLoop.hxx"
38 #include "PythonNode.hxx"
39 #include "InlineNode.hxx"
40 #include "ServiceNode.hxx"
41
42 #include "ResourcesManager.hxx"
43
44 #include <map>
45 #include <limits>
46 #include <numeric>
47 #include <sstream>
48 #include <iterator>
49
50 const char YACSEvalYFXPattern::DFT_PROC_NAME[]="YFX";
51
52 const char YACSEvalYFXPattern::ST_OK[]="ALL_OK";
53
54 const char YACSEvalYFXPattern::ST_FAILED[]="SOME_SAMPLES_FAILED_AND_ALL_OF_THEM_FAILED_DETERMINISTICALLY";
55
56 const char YACSEvalYFXPattern::ST_ERROR[]="SOME_SAMPLES_FAILED_BUT_IMPOSSIBLE_TO_CONCLUDE_ON_THEM";
57
58 const std::size_t YACSEvalYFXPattern::MAX_LGTH_OF_INP_DUMP=10000;
59
60 const char YACSEvalYFXRunOnlyPattern::FIRST_FE_SUBNODE_NAME[]="Bloc";
61
62 const char YACSEvalYFXRunOnlyPattern::GATHER_NODE_NAME[]="__gather__";
63
64 std::vector< YACSEvalInputPort *> YACSEvalYFXPattern::getFreeInputPorts() const
65 {
66   std::size_t sz(_inputs.size());
67   std::vector< YACSEvalInputPort *> ret;
68   std::vector< YACSEvalInputPort >::const_iterator it(_inputs.begin());
69   for(std::size_t i=0;i<sz;i++,it++)
70     ret.push_back(const_cast<YACSEvalInputPort *>(&(*it)));
71   return ret;
72 }
73
74 std::vector< YACSEvalOutputPort *> YACSEvalYFXPattern::getFreeOutputPorts() const
75 {
76   std::size_t sz(_outputs.size());
77   std::vector< YACSEvalOutputPort *> ret;
78   std::vector< YACSEvalOutputPort >::const_iterator it(_outputs.begin());
79   for(std::size_t i=0;i<sz;i++,it++)
80     ret.push_back(const_cast<YACSEvalOutputPort *>(&(*it)));
81   return ret;
82 }
83
84 YACSEvalYFXPattern *YACSEvalYFXPattern::FindPatternFrom(YACSEvalYFX *boss, YACS::ENGINE::Proc *scheme, bool ownScheme)
85 {
86   if(!scheme)
87     throw YACS::Exception("YACSEvalYFXPattern::FindPatternFrom : input scheme must be not null !");
88   {
89       YACS::ENGINE::ComposedNode *zeRunNode(0);
90       bool isMatchingRunOnlyPattern(YACSEvalYFXRunOnlyPattern::IsMatching(scheme,zeRunNode));
91       if(isMatchingRunOnlyPattern)
92         return new YACSEvalYFXRunOnlyPattern(boss,scheme,ownScheme,zeRunNode);
93   }
94   throw YACS::Exception("YACSEvalYFXPattern::FindPatternFrom : no pattern found for the input scheme !");
95 }
96
97 bool YACSEvalYFXPattern::isAlreadyComputedResources() const
98 {
99   return _res!=0;
100 }
101
102 void YACSEvalYFXPattern::checkNonAlreadyComputedResources() const
103 {
104   if(isAlreadyComputedResources())
105     throw YACS::Exception("checkNonAlreadyComputedResources : instance of computed resources already computed !");
106 }
107
108 void YACSEvalYFXPattern::checkAlreadyComputedResources() const
109 {
110   if(!isAlreadyComputedResources())
111     throw YACS::Exception("checkAlreadyComputedResources : instance of computed resources not already computed !");
112 }
113
114 void YACSEvalYFXPattern::checkLocked() const
115 {
116   if(!isLocked())
117     throw YACS::Exception("YACSEvalYFXPattern::checkLocked : Pattern is not locked !");
118 }
119
120 void YACSEvalYFXPattern::checkNonLocked() const
121 {
122   if(isLocked())
123     throw YACS::Exception("YACSEvalYFXPattern::checkNonLocked : Pattern is locked !");
124 }
125
126 void YACSEvalYFXPattern::CheckNodeIsOK(YACS::ENGINE::ComposedNode *node)
127 {
128   /*YACS::ENGINE::LinkInfo info(YACS::ENGINE::LinkInfo::WARN_ONLY_DONT_STOP);
129   try
130   {
131       node->checkConsistency(info);
132   }
133   catch(YACS::Exception& e)
134   {
135   }
136   if(info.getNumberOfErrLinks(YACS::ENGINE::E_ALL)!=0)
137     throw YACS::Exception("YACSEvalYFXPattern::CheckNodeIsOK : found node is not OK !");
138   std::list<YACS::ENGINE::ElementaryNode *> allNodes(node->getRecursiveConstituents());
139   for(std::list<YACS::ENGINE::ElementaryNode *>::const_iterator it=allNodes.begin();it!=allNodes.end();it++)
140     {
141       YACS::ENGINE::ServiceNode *node0(dynamic_cast<YACS::ENGINE::ServiceNode *>(*it));
142       YACS::ENGINE::InlineNode *node1(dynamic_cast<YACS::ENGINE::InlineNode *>(*it));
143       if(node0)
144         {
145           YACS::ENGINE::Container *cont(node0->getContainer());
146           YACS::ENGINE::ComponentInstance *comp(node0->getComponent());
147           if(!cont || !comp)
148             {
149               std::ostringstream oss; oss << "YACSEvalYFXPattern::CheckNodeIsOK : ServiceNode called \"" << node0->getName() << "\" is not correctly defined !";
150               throw YACS::Exception(oss.str());
151             }
152         }
153       if(node1)
154         {
155           YACS::ENGINE::Container *cont(node1->getContainer());
156           if(!cont && node1->getExecutionMode()==YACS::ENGINE::InlineNode::REMOTE_STR)
157             {
158               std::ostringstream oss; oss << "YACSEvalYFXPattern::CheckNodeIsOK : InlineNode called \"" << node1->getName() << "\" is not correctly defined !";
159               throw YACS::Exception(oss.str());
160             }
161         }
162     }*/
163 }
164
165 void YACSEvalYFXPattern::registerObserver(YACSEvalObserver *observer)
166 {
167   if(_observer==observer)
168     return ;
169   if(_observer)
170     _observer->decrRef();
171   _observer=observer;
172   if(_observer)
173     _observer->incrRef();
174 }
175
176 YACSEvalYFXPattern::YACSEvalYFXPattern(YACSEvalYFX *boss, YACS::ENGINE::Proc *scheme, bool ownScheme):_boss(boss),_scheme(scheme),_ownScheme(ownScheme),_parallelizeStatus(true),_rm(new ResourcesManager_cpp),_res(0),_observer(0)
177 {
178 }
179
180 YACS::ENGINE::TypeCode *YACSEvalYFXPattern::createSeqTypeCodeFrom(YACS::ENGINE::Proc *scheme, const std::string& zeType)
181 {
182   std::ostringstream oss; oss << "list[" << zeType << "]";
183   YACS::ENGINE::TypeCode *tc(scheme->getTypeCode(zeType));
184   return scheme->createSequenceTc(oss.str(),oss.str(),tc);
185 }
186
187 void YACSEvalYFXPattern::setResources(YACSEvalListOfResources *res)
188 {
189   checkNonAlreadyComputedResources();
190   if(res!=_res)
191     delete _res;
192   _res=res;
193 }
194
195 void YACSEvalYFXPattern::resetResources()
196 {
197   delete _res;
198   _res=0;
199 }
200
201 YACSEvalSeqAny *YACSEvalYFXPattern::BuildValueInPort(YACS::ENGINE::InputPyPort *port)
202 {
203   if(!port)
204     throw YACS::Exception("YACSEvalYFXPattern::GetValueInPort : null input port !");
205   PyObject *obj(port->getPyObj());
206   YACS::ENGINE::TypeCode *tc(port->edGetType());
207   YACS::ENGINE::TypeCodeSeq *tcc(dynamic_cast<YACS::ENGINE::TypeCodeSeq *>(tc));
208   if(!tcc)
209     {
210       std::ostringstream oss; oss << "YACSEvalYFXPattern::GetValueInPort : internal error for tc of input \"" << port->getName() << "\"";
211       throw YACS::Exception(oss.str());
212     }
213   const YACS::ENGINE::TypeCode *tcct(tcc->contentType());
214   if(!PyList_Check(obj))
215     throw YACS::Exception("YACSEvalYFXPattern::GetValueInPort : internal error 2 !");
216   std::size_t sz(PyList_Size(obj));
217   if(tcct->kind()==YACS::ENGINE::Double)
218     {
219       std::vector<double> eltCpp(sz);
220       for(std::size_t i=0;i<sz;i++)
221         {
222           PyObject *elt(PyList_GetItem(obj,i));
223           eltCpp[i]=PyFloat_AsDouble(elt);
224         }
225       YACS::AutoCppPtr<YACSEvalSeqAnyDouble> elt(new YACSEvalSeqAnyDouble(eltCpp));
226       return elt.dettach();
227     }
228   else if(tcct->kind()==YACS::ENGINE::Int)
229     {
230       std::vector<int> eltCpp(sz);
231       for(std::size_t i=0;i<sz;i++)
232         {
233           PyObject *elt(PyList_GetItem(obj,i));
234           eltCpp[i]=PyInt_AsLong(elt);
235         }
236       YACS::AutoCppPtr<YACSEvalSeqAnyInt> elt(new YACSEvalSeqAnyInt(eltCpp));
237       return elt.dettach();
238     }
239   else
240     throw YACS::Exception("YACSEvalYFXPattern::GetValueInPort : not implemented yet for other than Double and Int !");
241 }
242
243 YACSEvalSeqAny *YACSEvalYFXPattern::BuildValueFromEngineFrmt(YACS::ENGINE::SequenceAny *data)
244 {
245   unsigned int sz(data->size());
246   std::vector<double> eltCpp(sz);
247   for(unsigned int ii=0;ii<sz;ii++)
248     {
249       YACS::ENGINE::AnyPtr elt((*data)[ii]);
250       YACS::ENGINE::Any *eltPtr((YACS::ENGINE::Any *)elt);
251       YACS::ENGINE::AtomAny *eltPtr2(dynamic_cast<YACS::ENGINE::AtomAny *>(eltPtr));
252       if(!eltPtr2)
253         {
254           std::ostringstream oss; oss << "YACSEvalYFXPattern::BuildValueFromEngineFrmt : error at pos #" << ii << " ! It is not an AtomAny !";
255           throw YACS::Exception(oss.str());
256         }
257       eltCpp[ii]=eltPtr2->getDoubleValue();
258     }
259   return new YACSEvalSeqAnyDouble(eltCpp);
260 }
261
262 void YACSEvalYFXPattern::cleanScheme()
263 {
264   if(_ownScheme)
265     delete _scheme;
266   _scheme=0;
267 }
268
269 YACSEvalYFXPattern::~YACSEvalYFXPattern()
270 {
271   if(_observer)
272     _observer->decrRef();
273   delete _rm;
274   delete _res;
275 }
276
277 /////////////////////
278
279 class YACSEvalYFXRunOnlyPatternInternalObserver : public YACS::ENGINE::Observer
280 {
281 public:
282   YACSEvalYFXRunOnlyPatternInternalObserver(YACSEvalYFXRunOnlyPattern *boss):_boss(boss) { if(!_boss) throw YACS::Exception("YACSEvalYFXRunOnlyPatternInternalObserver constructor : null boss not supported :)"); }
283   void notifyObserver(YACS::ENGINE::Node *object, const std::string& event);
284 private:
285   YACSEvalYFXRunOnlyPattern *_boss;
286 };
287
288 void YACSEvalYFXRunOnlyPatternInternalObserver::notifyObserver(YACS::ENGINE::Node *object, const std::string& event)
289 {
290   YACS::ENGINE::ForEachLoop *object2(dynamic_cast<YACS::ENGINE::ForEachLoop *>(object));
291   if(!object2)
292     return ;
293   YACSEvalObserver *obs(_boss->getObserver());
294   if(!obs)
295     return ;
296   if(event=="progress")
297     obs->notifyNewNumberOfPassedItems(_boss->getBoss(),object2->getCurrentIndex());
298 }
299
300 /////////////////////
301
302 YACSEvalYFXRunOnlyPattern::YACSEvalYFXRunOnlyPattern(YACSEvalYFX *boss, YACS::ENGINE::Proc *scheme, bool ownScheme, YACS::ENGINE::ComposedNode *runNode):YACSEvalYFXPattern(boss,scheme,ownScheme),_runNode(runNode),_generatedGraph(0),_FEInGeneratedGraph(0),_obs(new YACSEvalYFXRunOnlyPatternInternalObserver(this))
303 {
304   if(!_runNode)
305     throw YACS::Exception("YACSEvalYFXRunOnlyPattern : internal run node must be not null !");
306   buildInputPorts();
307   buildOutputPorts();
308 }
309
310 YACSEvalYFXRunOnlyPattern::~YACSEvalYFXRunOnlyPattern()
311 {
312   delete _obs;
313 }
314
315 void YACSEvalYFXRunOnlyPattern::setOutPortsOfInterestForEvaluation(const std::vector<YACSEvalOutputPort *>& outputsOfInterest)
316 {
317   checkNonLocked();
318   _outputsOfInterest=outputsOfInterest;
319 }
320
321 void YACSEvalYFXRunOnlyPattern::resetOutputsOfInterest()
322 {
323   checkLocked();
324   _outputsOfInterest.clear();
325 }
326
327 void YACSEvalYFXRunOnlyPattern::generateGraph()
328 {
329   static const char LISTPYOBJ_STR[]="list[pyobj]";
330   if(_outputsOfInterest.empty())
331     return ;
332   YACS::ENGINE::RuntimeSALOME::setRuntime();
333   YACS::ENGINE::RuntimeSALOME *r(YACS::ENGINE::getSALOMERuntime());
334   _generatedGraph=r->createProc(DFT_PROC_NAME);
335   YACS::ENGINE::TypeCode *pyobjTC(_generatedGraph->createInterfaceTc("python:obj:1.0","pyobj",std::list<YACS::ENGINE::TypeCodeObjref *>()));
336   std::ostringstream oss; oss << "Loop_" << _runNode->getName();
337   _generatedGraph->createType(YACSEvalAnyDouble::TYPE_REPR,"double");
338   _generatedGraph->createType(YACSEvalAnyInt::TYPE_REPR,"int");
339   //
340   YACS::ENGINE::InlineNode *n0(r->createScriptNode(YACS::ENGINE::PythonNode::KIND,"__initializer__"));
341   _generatedGraph->edAddChild(n0);
342   YACS::ENGINE::TypeCode *listPyobjTC(_generatedGraph->createSequenceTc(LISTPYOBJ_STR,LISTPYOBJ_STR,pyobjTC));
343   YACS::ENGINE::OutputPort *sender(n0->edAddOutputPort("sender",listPyobjTC));
344   std::ostringstream var0;
345   for(std::vector< YACSEvalInputPort >::const_iterator it=_inputs.begin();it!=_inputs.end();it++)
346     {
347       if((*it).isRandomVar())
348         {
349           var0 << (*it).getName() << ",";
350           YACS::ENGINE::TypeCode *tc(createSeqTypeCodeFrom(_generatedGraph,(*it).getTypeOfData()));
351           YACS::ENGINE::InputPort *inp(n0->edAddInputPort((*it).getName(),tc));
352           YACS::ENGINE::InputPyPort *inpc(dynamic_cast<YACS::ENGINE::InputPyPort *>(inp));
353           if(!inpc)
354             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::generateGraph : internal error 1 !");
355           (*it).setUndergroundPortToBeSet(inpc);
356         }
357     }
358   std::ostringstream n0Script; n0Script << "sender=zip(" << var0.str() << ")\n";
359   n0->setScript(n0Script.str());
360   //
361   YACS::ENGINE::ForEachLoop *n1(r->createForEachLoop(oss.str(),pyobjTC));
362   _FEInGeneratedGraph=n1;
363   _generatedGraph->edAddChild(n1);
364   _generatedGraph->edAddCFLink(n0,n1);
365   _generatedGraph->edAddDFLink(sender,n1->edGetSeqOfSamplesPort());
366   YACS::ENGINE::InlineNode *n2(r->createScriptNode(YACS::ENGINE::PythonNode::KIND,GATHER_NODE_NAME));
367   _generatedGraph->edAddChild(n2);
368   _generatedGraph->edAddCFLink(n1,n2);
369   //
370   YACS::ENGINE::Bloc *n10(r->createBloc(FIRST_FE_SUBNODE_NAME));
371   n1->edAddChild(n10);
372   YACS::ENGINE::InlineNode *n100(r->createScriptNode(YACS::ENGINE::PythonNode::KIND,"__dispatch__"));
373   YACS::ENGINE::Node *n101(_runNode->cloneWithoutCompAndContDeepCpy(0,true));
374   n10->edAddChild(n100);
375   n10->edAddChild(n101);
376   YACS::ENGINE::InputPort *dispatchIn(n100->edAddInputPort("i0",pyobjTC));
377   n10->edAddCFLink(n100,n101);
378   n1->edAddDFLink(n1->edGetSamplePort(),dispatchIn);
379   std::ostringstream var1;
380   for(std::vector< YACSEvalInputPort >::const_iterator it=_inputs.begin();it!=_inputs.end();it++)
381     {
382       if((*it).isRandomVar())
383         {
384           var1 << (*it).getName() << ",";
385           YACS::ENGINE::OutputPort *myOut(n100->edAddOutputPort((*it).getName(),_generatedGraph->getTypeCode((*it).getTypeOfData())));
386           std::string tmpPortName(_runNode->getInPortName((*it).getUndergroundPtr()));
387           YACS::ENGINE::InputPort *myIn(n101->getInputPort(tmpPortName));
388           n10->edAddDFLink(myOut,myIn);
389         }
390     }
391   std::ostringstream n100Script;  n100Script << var1.str() << "=i0\n";
392   n100->setScript(n100Script.str());
393   for(std::vector< YACSEvalOutputPort * >::const_iterator it=_outputsOfInterest.begin();it!=_outputsOfInterest.end();it++)
394     {
395       YACS::ENGINE::TypeCode *tc(createSeqTypeCodeFrom(_generatedGraph,(*it)->getTypeOfData()));
396       YACS::ENGINE::InputPort *myIn(n2->edAddInputPort((*it)->getName(),tc));
397       std::string tmpPortName(_runNode->getOutPortName((*it)->getUndergroundPtr()));
398       YACS::ENGINE::OutputPort *myOut(n101->getOutputPort(tmpPortName));
399       _generatedGraph->edAddDFLink(myOut,myIn);
400     }
401   _generatedGraph->updateContainersAndComponents();
402 }
403
404 void YACSEvalYFXRunOnlyPattern::resetGeneratedGraph()
405 {
406   delete _generatedGraph;
407   _generatedGraph=0;
408   resetResources();
409 }
410
411 int YACSEvalYFXRunOnlyPattern::assignNbOfBranches()
412 {
413   checkAlreadyComputedResources();
414   if(!_generatedGraph)
415     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : the generated graph has not been created !");
416   std::list<YACS::ENGINE::Node *> nodes(_generatedGraph->getChildren());
417   YACS::ENGINE::ForEachLoop *zeMainNode(0);
418   for(std::list<YACS::ENGINE::Node *>::const_iterator it=nodes.begin();it!=nodes.end();it++)
419     {
420       YACS::ENGINE::ForEachLoop *isZeMainNode(dynamic_cast<YACS::ENGINE::ForEachLoop *>(*it));
421       if(isZeMainNode)
422         {
423           if(!zeMainNode)
424             zeMainNode=isZeMainNode;
425           else
426             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : internal error 1 !");
427         }
428     }
429   if(!zeMainNode)
430     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : internal error 2 !");
431   unsigned int nbProcsDeclared(getResourcesInternal()->getNumberOfProcsDeclared());
432   nbProcsDeclared=std::max(nbProcsDeclared,4u);
433   int nbOfBranch=1;
434   if(getParallelizeStatus())
435     {
436       nbOfBranch=(nbProcsDeclared/getResourcesInternal()->getMaxLevelOfParallelism());
437       nbOfBranch=std::max(nbOfBranch,1);
438     }
439   YACS::ENGINE::InputPort *zeInputToSet(zeMainNode->edGetNbOfBranchesPort());
440   YACS::ENGINE::AnyInputPort *zeInputToSetC(dynamic_cast<YACS::ENGINE::AnyInputPort *>(zeInputToSet));
441   if(!zeInputToSetC)
442     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : internal error 3 !");
443   YACS::ENGINE::Any *a(YACS::ENGINE::AtomAny::New(nbOfBranch));
444   zeInputToSetC->put(a);
445   zeInputToSetC->exSaveInit();
446   a->decrRef();
447   return nbOfBranch;
448 }
449
450 void YACSEvalYFXRunOnlyPattern::assignRandomVarsInputs()
451 {
452   std::size_t sz(std::numeric_limits<std::size_t>::max());
453   for(std::vector< YACSEvalInputPort >::const_iterator it=_inputs.begin();it!=_inputs.end();it++)
454     if((*it).isRandomVar())
455       {
456         std::size_t locSize((*it).initializeUndergroundWithSeq());
457         if(sz==std::numeric_limits<std::size_t>::max())
458           sz=locSize;
459         else
460           if(sz!=locSize)
461             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignRandomVarsInputs : length of sequences in random vars must be the same !");
462       }
463 }
464
465 bool YACSEvalYFXRunOnlyPattern::isLocked() const
466 {
467   return _generatedGraph!=0;
468 }
469
470 YACSEvalListOfResources *YACSEvalYFXRunOnlyPattern::giveResources()
471 {
472   checkLocked();
473   if(!isAlreadyComputedResources())
474     {
475       YACS::ENGINE::DeploymentTree dt(_runNode->getDeploymentTree());
476       _runNode->removeRecursivelyRedundantCL();
477       YACSEvalListOfResources *res(new YACSEvalListOfResources(_runNode->getMaxLevelOfParallelism(),getCatalogInAppli(),dt));
478       setResources(res);
479     }
480   return getResourcesInternal();
481 }
482
483 YACS::ENGINE::Proc *YACSEvalYFXRunOnlyPattern::getUndergroundGeneratedGraph() const
484 {
485   return _generatedGraph;
486 }
487
488 std::string YACSEvalYFXRunOnlyPattern::getErrorDetailsInCaseOfFailure() const
489 {
490   std::string st(getStatusOfRunStr());//test if a run has occurred.
491   if(st==ST_OK)
492     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getErrorDetailsInCaseOfFailure : The execution of scheme has been carried out to the end without any problem !");
493   // All the problem can only comes from foreach -> scan it
494   YACS::ENGINE::ForEachLoop *fe(findTopForEach());
495   YACS::ENGINE::NodeStateNameMap nsm;
496   unsigned nbB(fe->getNumberOfBranchesCreatedDyn());
497   std::ostringstream oss;
498   for(unsigned j=0;j<nbB;j++)
499     {
500       YACS::ENGINE::Node *nn(fe->getChildByNameExec(FIRST_FE_SUBNODE_NAME,j));
501       YACS::ENGINE::Bloc *nnc(dynamic_cast<YACS::ENGINE::Bloc *>(nn));
502       if(!nnc)
503         throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getErrorDetailsInCaseOfFailure : internal error 1 ! The direct son of main foreach is expected to be a Bloc !");
504       if(nnc->getState()==YACS::DONE)
505         continue;
506       std::list< YACS::ENGINE::ElementaryNode *> fec(nnc->getRecursiveConstituents());
507       for(std::list< YACS::ENGINE::ElementaryNode *>::reverse_iterator it=fec.rbegin();it!=fec.rend();it++)
508         {
509           YACS::StatesForNode st0((*it)->getState());
510           if(st0!=YACS::DONE)
511             {
512               oss << "NODE = " << nnc->getChildName(*it) << std::endl;
513               oss << "STATUS = " << nsm[st0] << std::endl;
514               oss << "BRANCH ID = " << j << std::endl;
515               std::list<YACS::ENGINE::InputPort *> inps((*it)->getSetOfInputPort());
516               for(std::list<YACS::ENGINE::InputPort *>::const_iterator it=inps.begin();it!=inps.end();it++)
517                 {
518                   std::string d((*it)->getHumanRepr());
519                   if(d.size()>10000)
520                     d=d.substr(0,MAX_LGTH_OF_INP_DUMP);
521                   oss << "INPUT \"" << (*it)->getName() << "\" = " << d << std::endl;
522                 }
523               oss << "DETAILS = " << std::endl;
524               oss << (*it)->getErrorDetails();
525             }
526         }
527     }
528   return oss.str();
529 }
530
531 std::string YACSEvalYFXRunOnlyPattern::getStatusOfRunStr() const
532 {
533   YACS::StatesForNode st(_generatedGraph->getState());
534   switch(st)
535     {
536     case YACS::READY:
537     case YACS::TOLOAD:
538     case YACS::LOADED:
539     case YACS::TOACTIVATE:
540     case YACS::ACTIVATED:
541     case YACS::SUSPENDED:
542     case YACS::PAUSE:
543     case YACS::DISABLED:
544     case YACS::DESACTIVATED:
545       {
546         std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::getStatusOfRunStr : Unexpected state \"" << YACS::ENGINE::Node::getStateName(st) << "\" ! Did you invoke run ?";
547         throw YACS::Exception(oss.str());
548       }
549     case YACS::LOADFAILED:
550     case YACS::EXECFAILED:
551     case YACS::ERROR:
552     case YACS::INTERNALERR:
553       return std::string(ST_ERROR);
554     case YACS::FAILED:
555       return std::string(ST_FAILED);
556     case YACS::DONE:
557       return std::string(ST_OK);
558     default:
559       {
560         std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::getStatusOfRunStr : unrecognized and managed state \"" << YACS::ENGINE::Node::getStateName(st) << "\" !";
561         throw YACS::Exception(oss.str());
562       }
563     }
564 }
565
566 std::vector<YACSEvalSeqAny *> YACSEvalYFXRunOnlyPattern::getResults() const
567 {
568   if(_generatedGraph->getState()!=YACS::DONE)
569     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getResults : the execution did not finished correctly ! getResults should not be called !");
570   std::vector<YACSEvalSeqAny *> ret(_outputsOfInterest.size());
571   YACS::ENGINE::Node *node(_generatedGraph->getChildByName(GATHER_NODE_NAME));
572   YACS::ENGINE::PythonNode *nodeC(dynamic_cast<YACS::ENGINE::PythonNode *>(node));
573   if(!nodeC)
574     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getResults : internal error !");
575   std::size_t ii(0);
576   for(std::vector< YACSEvalOutputPort * >::const_iterator it=_outputsOfInterest.begin();it!=_outputsOfInterest.end();it++,ii++)
577     {
578       YACS::ENGINE::InPort *input(nodeC->getInPort((*it)->getName()));
579       YACS::ENGINE::InputPyPort *inputC(dynamic_cast<YACS::ENGINE::InputPyPort *>(input));
580       if(!inputC)
581         {
582           std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::getResults : internal error for input \"" << (*it)->getName() << "\"";
583           throw YACS::Exception(oss.str());
584         }
585       ret[ii]=BuildValueInPort(inputC);
586     }
587   return ret;
588 }
589
590 /*!
591  * This method works if run succeeded (true return) and also if graph has failed. Graph failed means soft error of evaluation due to error in evaluation (example 1/0 or a normal throw from one node)
592  * If a more serious error occured (SIGSEGV of a server or internal error in YACS engine, cluster error, loose of connection...) this method will throw an exception to warn the caller that the results may be 
593  */
594 std::vector<YACSEvalSeqAny *> YACSEvalYFXRunOnlyPattern::getResultsInCaseOfFailure(std::vector<unsigned int>& passedIds) const
595 {
596   YACS::StatesForNode st(_generatedGraph->getState());
597   if(st==YACS::DONE)
598     {
599       passedIds.clear();
600       std::vector<YACSEvalSeqAny *> ret(getResults());
601       if(!ret.empty())
602         {
603           if(!ret[0])
604             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getResultsInCaseOfFailure : internal error ! The returned vector has a null pointer at pos #0 !");
605           std::size_t sz(ret[0]->size());
606           passedIds.resize(sz);
607           for(std::size_t i=0;i<sz;i++)
608             passedIds[i]=i;
609         }
610       return ret;
611     }
612   getStatusOfRunStr();// To check that the status is recognized.
613   std::list<YACS::ENGINE::Node *> lns(_generatedGraph->edGetDirectDescendants());
614   YACS::ENGINE::ForEachLoop *fe(findTopForEach());
615   //
616   YACS::ENGINE::Executor exe;
617   std::vector<YACS::ENGINE::SequenceAny *> outputs;
618   std::vector<std::string> nameOfOutputs;
619   passedIds=fe->getPassedResults(&exe,outputs,nameOfOutputs);//<- the key invokation is here.
620   std::size_t sz(passedIds.size()),ii(0);
621   std::vector<YACSEvalSeqAny *> ret(_outputsOfInterest.size());
622   for(std::vector<YACSEvalOutputPort *>::const_iterator it=_outputsOfInterest.begin();it!=_outputsOfInterest.end();it++,ii++)
623     {
624       YACS::ENGINE::OutputPort *p((*it)->getUndergroundPtr());
625       std::string st(_runNode->getOutPortName(p));
626       std::ostringstream oss; oss << FIRST_FE_SUBNODE_NAME << '.' << _runNode->getName() << '.' << st;
627       st=oss.str();
628       YACS::ENGINE::ForEachLoop::InterceptorizeNameOfPort(st);
629       std::vector<std::string>::iterator it(std::find(nameOfOutputs.begin(),nameOfOutputs.end(),st));
630       if(it==nameOfOutputs.end())
631         {
632           std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::getResultsInCaseOfFailure : internal error 3 ! Unable to locate interceptor with name " << st << " ! Possibilities are : ";
633           std::copy(nameOfOutputs.begin(),nameOfOutputs.end(),std::ostream_iterator<std::string>(oss," "));
634           oss << " !";
635           throw YACS::Exception(oss.str());
636         }
637       std::size_t pos(std::distance(nameOfOutputs.begin(),it));
638       ret[ii]=BuildValueFromEngineFrmt(outputs[pos]);
639     }
640   return ret;
641 }
642
643 void YACSEvalYFXRunOnlyPattern::emitStart() const
644 {
645   YACSEvalObserver *obs(getObserver());
646   if(!obs)
647     return ;
648   obs->notifyNumberOfSamplesToEval(getBoss(),_FEInGeneratedGraph->getNbOfElementsToBeProcessed());
649 }
650
651 bool YACSEvalYFXRunOnlyPattern::IsMatching(YACS::ENGINE::Proc *scheme, YACS::ENGINE::ComposedNode *& runNode)
652 {
653   std::list<YACS::ENGINE::Node *> nodes(scheme->getChildren());
654   if(nodes.empty())
655     return false;
656   bool areAllElementary(true);
657   for(std::list<YACS::ENGINE::Node *>::const_iterator it=nodes.begin();it!=nodes.end() && areAllElementary;it++)
658     if(!dynamic_cast<YACS::ENGINE::ElementaryNode *>(*it))
659       areAllElementary=false;
660   if(areAllElementary)
661     {
662       if(scheme)
663         CheckNodeIsOK(scheme);
664       runNode=scheme;
665       return true;
666     }
667   if(nodes.size()!=1)
668     return false;
669   YACS::ENGINE::ComposedNode *candidate(dynamic_cast<YACS::ENGINE::ComposedNode *>(nodes.front()));
670   runNode=candidate;
671   if(candidate)
672     CheckNodeIsOK(candidate);
673   return candidate!=0;
674 }
675
676 void YACSEvalYFXRunOnlyPattern::buildInputPorts()
677 {
678   _inputs.clear();
679   std::list< YACS::ENGINE::InputPort *> allInputPorts(_runNode->getSetOfInputPort());
680   std::vector<std::string> allNames;
681   for(std::list< YACS::ENGINE::InputPort *>::const_iterator it=allInputPorts.begin();it!=allInputPorts.end();it++)
682     {
683       YACS::ENGINE::InputPort *elt(*it);
684       if(!elt)
685         throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildInputPorts : presence of null input !");
686       std::set<YACS::ENGINE::OutPort *> bls(elt->edSetOutPort());
687       if(bls.empty())
688         {
689           if(YACSEvalPort::IsInputPortPublishable(elt))
690             {
691               std::string inpName(elt->getName());
692               if(inpName.empty())
693                 throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildInputPorts : an input has empty name ! Should not !");
694               _inputs.push_back(YACSEvalInputPort(elt));
695               if(std::find(allNames.begin(),allNames.end(),inpName)!=allNames.end())
696                 {
697                   std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::buildInputPorts : input name \"" << inpName << "\" appears more than once !";
698                   throw YACS::Exception(oss.str());
699                 }
700               allNames.push_back(inpName);
701             }
702         }
703     }
704 }
705
706 void YACSEvalYFXRunOnlyPattern::buildOutputPorts()
707 {
708   _outputs.clear();
709   std::list< YACS::ENGINE::OutputPort *> allOutputPorts(_runNode->getSetOfOutputPort());
710   std::vector<std::string> allNames;
711   for(std::list< YACS::ENGINE::OutputPort *>::const_iterator it=allOutputPorts.begin();it!=allOutputPorts.end();it++)
712     {
713       YACS::ENGINE::OutputPort *elt(*it);
714       if(YACSEvalPort::IsOutputPortPublishable(elt))
715         {
716           if(!elt)
717             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildOutputPorts : presence of null output !");
718           std::string outpName(elt->getName());
719           if(outpName.empty())
720             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildOutputPorts : an output has empty name ! Should not !");
721           if(std::find(allNames.begin(),allNames.end(),outpName)!=allNames.end())
722             {
723               std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::buildOutputPorts : output name \"" << outpName << "\" appears more than once !";
724               throw YACS::Exception(oss.str());
725             }
726           _outputs.push_back(YACSEvalOutputPort(*it));
727         }
728     }
729 }
730
731 YACS::ENGINE::ForEachLoop *YACSEvalYFXRunOnlyPattern::findTopForEach() const
732 {
733   std::list<YACS::ENGINE::Node *> lns(_generatedGraph->edGetDirectDescendants());
734   YACS::ENGINE::ForEachLoop *fe(0);
735   for(std::list<YACS::ENGINE::Node *>::const_iterator it=lns.begin();it!=lns.end();it++)
736     {
737       fe=dynamic_cast<YACS::ENGINE::ForEachLoop *>(*it);
738       if(fe)
739         break;
740     }
741   if(!fe)
742     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::findTopForEach : internal error 2 ! ForEach is not accessible !");
743   return fe;
744 }