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