Salome HOME
Small addon to support non //sable components.
[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 "InputPort.hxx"
31 #include "LinkInfo.hxx"
32 #include "TypeCode.hxx"
33 #include "Proc.hxx"
34
35 #include "PythonPorts.hxx"
36 #include "ForEachLoop.hxx"
37 #include "PythonNode.hxx"
38 #include "InlineNode.hxx"
39 #include "ServiceNode.hxx"
40
41 #include "ResourcesManager.hxx"
42
43 #include <map>
44 #include <limits>
45 #include <numeric>
46 #include <sstream>
47
48 const char YACSEvalYFXPattern::DFT_PROC_NAME[]="YFX";
49
50 const char YACSEvalYFXRunOnlyPattern::GATHER_NODE_NAME[]="__gather__";
51
52 std::vector< YACSEvalInputPort *> YACSEvalYFXPattern::getFreeInputPorts() const
53 {
54   std::size_t sz(_inputs.size());
55   std::vector< YACSEvalInputPort *> ret;
56   std::vector< YACSEvalInputPort >::const_iterator it(_inputs.begin());
57   for(std::size_t i=0;i<sz;i++,it++)
58     ret.push_back(const_cast<YACSEvalInputPort *>(&(*it)));
59   return ret;
60 }
61
62 std::vector< YACSEvalOutputPort *> YACSEvalYFXPattern::getFreeOutputPorts() const
63 {
64   std::size_t sz(_outputs.size());
65   std::vector< YACSEvalOutputPort *> ret;
66   std::vector< YACSEvalOutputPort >::const_iterator it(_outputs.begin());
67   for(std::size_t i=0;i<sz;i++,it++)
68     ret.push_back(const_cast<YACSEvalOutputPort *>(&(*it)));
69   return ret;
70 }
71
72 YACSEvalYFXPattern *YACSEvalYFXPattern::FindPatternFrom(YACSEvalYFX *boss, YACS::ENGINE::Proc *scheme, bool ownScheme)
73 {
74   if(!scheme)
75     throw YACS::Exception("YACSEvalYFXPattern::FindPatternFrom : input scheme must be not null !");
76   {
77       YACS::ENGINE::ComposedNode *zeRunNode(0);
78       bool isMatchingRunOnlyPattern(YACSEvalYFXRunOnlyPattern::IsMatching(scheme,zeRunNode));
79       if(isMatchingRunOnlyPattern)
80         return new YACSEvalYFXRunOnlyPattern(boss,scheme,ownScheme,zeRunNode);
81   }
82   throw YACS::Exception("YACSEvalYFXPattern::FindPatternFrom : no pattern found for the input scheme !");
83 }
84
85 bool YACSEvalYFXPattern::isAlreadyComputedResources() const
86 {
87   return _res!=0;
88 }
89
90 void YACSEvalYFXPattern::checkNonAlreadyComputedResources() const
91 {
92   if(isAlreadyComputedResources())
93     throw YACS::Exception("checkNonAlreadyComputedResources : instance of computed resources already computed !");
94 }
95
96 void YACSEvalYFXPattern::checkAlreadyComputedResources() const
97 {
98   if(!isAlreadyComputedResources())
99     throw YACS::Exception("checkAlreadyComputedResources : instance of computed resources not already computed !");
100 }
101
102 void YACSEvalYFXPattern::checkLocked() const
103 {
104   if(!isLocked())
105     throw YACS::Exception("YACSEvalYFXPattern::checkLocked : Pattern is not locked !");
106 }
107
108 void YACSEvalYFXPattern::checkNonLocked() const
109 {
110   if(isLocked())
111     throw YACS::Exception("YACSEvalYFXPattern::checkNonLocked : Pattern is locked !");
112 }
113
114 void YACSEvalYFXPattern::CheckNodeIsOK(YACS::ENGINE::ComposedNode *node)
115 {
116   /*YACS::ENGINE::LinkInfo info(YACS::ENGINE::LinkInfo::WARN_ONLY_DONT_STOP);
117   try
118   {
119       node->checkConsistency(info);
120   }
121   catch(YACS::Exception& e)
122   {
123   }
124   if(info.getNumberOfErrLinks(YACS::ENGINE::E_ALL)!=0)
125     throw YACS::Exception("YACSEvalYFXPattern::CheckNodeIsOK : found node is not OK !");
126   std::list<YACS::ENGINE::ElementaryNode *> allNodes(node->getRecursiveConstituents());
127   for(std::list<YACS::ENGINE::ElementaryNode *>::const_iterator it=allNodes.begin();it!=allNodes.end();it++)
128     {
129       YACS::ENGINE::ServiceNode *node0(dynamic_cast<YACS::ENGINE::ServiceNode *>(*it));
130       YACS::ENGINE::InlineNode *node1(dynamic_cast<YACS::ENGINE::InlineNode *>(*it));
131       if(node0)
132         {
133           YACS::ENGINE::Container *cont(node0->getContainer());
134           YACS::ENGINE::ComponentInstance *comp(node0->getComponent());
135           if(!cont || !comp)
136             {
137               std::ostringstream oss; oss << "YACSEvalYFXPattern::CheckNodeIsOK : ServiceNode called \"" << node0->getName() << "\" is not correctly defined !";
138               throw YACS::Exception(oss.str());
139             }
140         }
141       if(node1)
142         {
143           YACS::ENGINE::Container *cont(node1->getContainer());
144           if(!cont && node1->getExecutionMode()==YACS::ENGINE::InlineNode::REMOTE_STR)
145             {
146               std::ostringstream oss; oss << "YACSEvalYFXPattern::CheckNodeIsOK : InlineNode called \"" << node1->getName() << "\" is not correctly defined !";
147               throw YACS::Exception(oss.str());
148             }
149         }
150     }*/
151 }
152
153 void YACSEvalYFXPattern::registerObserver(YACSEvalObserver *observer)
154 {
155   if(_observer==observer)
156     return ;
157   if(_observer)
158     _observer->decrRef();
159   _observer=observer;
160   if(_observer)
161     _observer->incrRef();
162 }
163
164 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)
165 {
166 }
167
168 YACS::ENGINE::TypeCode *YACSEvalYFXPattern::createSeqTypeCodeFrom(YACS::ENGINE::Proc *scheme, const std::string& zeType)
169 {
170   std::ostringstream oss; oss << "list[" << zeType << "]";
171   YACS::ENGINE::TypeCode *tc(scheme->getTypeCode(zeType));
172   return scheme->createSequenceTc(oss.str(),oss.str(),tc);
173 }
174
175 void YACSEvalYFXPattern::setResources(YACSEvalListOfResources *res)
176 {
177   checkNonAlreadyComputedResources();
178   if(res!=_res)
179     delete _res;
180   _res=res;
181 }
182
183 void YACSEvalYFXPattern::resetResources()
184 {
185   delete _res;
186   _res=0;
187 }
188
189 YACSEvalSeqAny *YACSEvalYFXPattern::BuildValueInPort(YACS::ENGINE::InputPyPort *port)
190 {
191   if(!port)
192     throw YACS::Exception("YACSEvalYFXPattern::GetValueInPort : null input port !");
193   PyObject *obj(port->getPyObj());
194   YACS::ENGINE::TypeCode *tc(port->edGetType());
195   YACS::ENGINE::TypeCodeSeq *tcc(dynamic_cast<YACS::ENGINE::TypeCodeSeq *>(tc));
196   if(!tcc)
197     {
198       std::ostringstream oss; oss << "YACSEvalYFXPattern::GetValueInPort : internal error for tc of input \"" << port->getName() << "\"";
199       throw YACS::Exception(oss.str());
200     }
201   const YACS::ENGINE::TypeCode *tcct(tcc->contentType());
202   if(!PyList_Check(obj))
203     throw YACS::Exception("YACSEvalYFXPattern::GetValueInPort : internal error 2 !");
204   std::size_t sz(PyList_Size(obj));
205   if(tcct->kind()==YACS::ENGINE::Double)
206     {
207       std::vector<double> eltCpp(sz);
208       for(std::size_t i=0;i<sz;i++)
209         {
210           PyObject *elt(PyList_GetItem(obj,i));
211           eltCpp[i]=PyFloat_AsDouble(elt);
212         }
213       YACS::AutoCppPtr<YACSEvalSeqAnyDouble> elt(new YACSEvalSeqAnyDouble(eltCpp));
214       return elt.dettach();
215     }
216   else if(tcct->kind()==YACS::ENGINE::Int)
217     {
218       std::vector<int> eltCpp(sz);
219       for(std::size_t i=0;i<sz;i++)
220         {
221           PyObject *elt(PyList_GetItem(obj,i));
222           eltCpp[i]=PyInt_AsLong(elt);
223         }
224       YACS::AutoCppPtr<YACSEvalSeqAnyInt> elt(new YACSEvalSeqAnyInt(eltCpp));
225       return elt.dettach();
226     }
227   else
228     throw YACS::Exception("YACSEvalYFXPattern::GetValueInPort : not implemented yet for other than Double and Int !");
229 }
230
231 void YACSEvalYFXPattern::cleanScheme()
232 {
233   if(_ownScheme)
234     delete _scheme;
235   _scheme=0;
236 }
237
238 YACSEvalYFXPattern::~YACSEvalYFXPattern()
239 {
240   if(_observer)
241     _observer->decrRef();
242   delete _rm;
243   delete _res;
244 }
245
246 /////////////////////
247
248 class YACSEvalYFXRunOnlyPatternInternalObserver : public YACS::ENGINE::Observer
249 {
250 public:
251   YACSEvalYFXRunOnlyPatternInternalObserver(YACSEvalYFXRunOnlyPattern *boss):_boss(boss) { if(!_boss) throw YACS::Exception("YACSEvalYFXRunOnlyPatternInternalObserver constructor : null boss not supported :)"); }
252   void notifyObserver(YACS::ENGINE::Node *object, const std::string& event);
253 private:
254   YACSEvalYFXRunOnlyPattern *_boss;
255 };
256
257 void YACSEvalYFXRunOnlyPatternInternalObserver::notifyObserver(YACS::ENGINE::Node *object, const std::string& event)
258 {
259   YACS::ENGINE::ForEachLoop *object2(dynamic_cast<YACS::ENGINE::ForEachLoop *>(object));
260   if(!object2)
261     return ;
262   YACSEvalObserver *obs(_boss->getObserver());
263   if(!obs)
264     return ;
265   if(event=="progress")
266     obs->notifyNewNumberOfPassedItems(_boss->getBoss(),object2->getCurrentIndex());
267 }
268
269 /////////////////////
270
271 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))
272 {
273   if(!_runNode)
274     throw YACS::Exception("YACSEvalYFXRunOnlyPattern : internal run node must be not null !");
275   buildInputPorts();
276   buildOutputPorts();
277 }
278
279 YACSEvalYFXRunOnlyPattern::~YACSEvalYFXRunOnlyPattern()
280 {
281   delete _obs;
282 }
283
284 void YACSEvalYFXRunOnlyPattern::setOutPortsOfInterestForEvaluation(const std::vector<YACSEvalOutputPort *>& outputsOfInterest)
285 {
286   checkNonLocked();
287   _outputsOfInterest=outputsOfInterest;
288 }
289
290 void YACSEvalYFXRunOnlyPattern::resetOutputsOfInterest()
291 {
292   checkLocked();
293   _outputsOfInterest.clear();
294 }
295
296 void YACSEvalYFXRunOnlyPattern::generateGraph()
297 {
298   static const char LISTPYOBJ_STR[]="list[pyobj]";
299   if(_outputsOfInterest.empty())
300     return ;
301   YACS::ENGINE::RuntimeSALOME::setRuntime();
302   YACS::ENGINE::RuntimeSALOME *r(YACS::ENGINE::getSALOMERuntime());
303   _generatedGraph=r->createProc(DFT_PROC_NAME);
304   YACS::ENGINE::TypeCode *pyobjTC(_generatedGraph->createInterfaceTc("python:obj:1.0","pyobj",std::list<YACS::ENGINE::TypeCodeObjref *>()));
305   std::ostringstream oss; oss << "Loop_" << _runNode->getName();
306   _generatedGraph->createType(YACSEvalAnyDouble::TYPE_REPR,"double");
307   _generatedGraph->createType(YACSEvalAnyInt::TYPE_REPR,"int");
308   //
309   YACS::ENGINE::InlineNode *n0(r->createScriptNode(YACS::ENGINE::PythonNode::KIND,"__initializer__"));
310   _generatedGraph->edAddChild(n0);
311   YACS::ENGINE::TypeCode *listPyobjTC(_generatedGraph->createSequenceTc(LISTPYOBJ_STR,LISTPYOBJ_STR,pyobjTC));
312   YACS::ENGINE::OutputPort *sender(n0->edAddOutputPort("sender",listPyobjTC));
313   std::ostringstream var0;
314   for(std::vector< YACSEvalInputPort >::const_iterator it=_inputs.begin();it!=_inputs.end();it++)
315     {
316       if((*it).isRandomVar())
317         {
318           var0 << (*it).getName() << ",";
319           YACS::ENGINE::TypeCode *tc(createSeqTypeCodeFrom(_generatedGraph,(*it).getTypeOfData()));
320           YACS::ENGINE::InputPort *inp(n0->edAddInputPort((*it).getName(),tc));
321           YACS::ENGINE::InputPyPort *inpc(dynamic_cast<YACS::ENGINE::InputPyPort *>(inp));
322           if(!inpc)
323             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::generateGraph : internal error 1 !");
324           (*it).setUndergroundPortToBeSet(inpc);
325         }
326     }
327   std::ostringstream n0Script; n0Script << "sender=zip(" << var0.str() << ")\n";
328   n0->setScript(n0Script.str());
329   //
330   YACS::ENGINE::ForEachLoop *n1(r->createForEachLoop(oss.str(),pyobjTC));
331   _FEInGeneratedGraph=n1;
332   _generatedGraph->edAddChild(n1);
333   _generatedGraph->edAddCFLink(n0,n1);
334   _generatedGraph->edAddDFLink(sender,n1->edGetSeqOfSamplesPort());
335   YACS::ENGINE::InlineNode *n2(r->createScriptNode(YACS::ENGINE::PythonNode::KIND,GATHER_NODE_NAME));
336   _generatedGraph->edAddChild(n2);
337   _generatedGraph->edAddCFLink(n1,n2);
338   //
339   YACS::ENGINE::Bloc *n10(r->createBloc("Bloc"));
340   n1->edAddChild(n10);
341   YACS::ENGINE::InlineNode *n100(r->createScriptNode(YACS::ENGINE::PythonNode::KIND,"__dispatch__"));
342   YACS::ENGINE::Node *n101(_runNode->cloneWithoutCompAndContDeepCpy(0,true));
343   n10->edAddChild(n100);
344   n10->edAddChild(n101);
345   YACS::ENGINE::InputPort *dispatchIn(n100->edAddInputPort("i0",pyobjTC));
346   n10->edAddCFLink(n100,n101);
347   n1->edAddDFLink(n1->edGetSamplePort(),dispatchIn);
348   std::ostringstream var1;
349   for(std::vector< YACSEvalInputPort >::const_iterator it=_inputs.begin();it!=_inputs.end();it++)
350     {
351       if((*it).isRandomVar())
352         {
353           var1 << (*it).getName() << ",";
354           YACS::ENGINE::OutputPort *myOut(n100->edAddOutputPort((*it).getName(),_generatedGraph->getTypeCode((*it).getTypeOfData())));
355           std::string tmpPortName(_runNode->getInPortName((*it).getUndergroundPtr()));
356           YACS::ENGINE::InputPort *myIn(n101->getInputPort(tmpPortName));
357           n10->edAddDFLink(myOut,myIn);
358         }
359     }
360   std::ostringstream n100Script;  n100Script << var1.str() << "=i0\n";
361   n100->setScript(n100Script.str());
362   for(std::vector< YACSEvalOutputPort * >::const_iterator it=_outputsOfInterest.begin();it!=_outputsOfInterest.end();it++)
363     {
364       YACS::ENGINE::TypeCode *tc(createSeqTypeCodeFrom(_generatedGraph,(*it)->getTypeOfData()));
365       YACS::ENGINE::InputPort *myIn(n2->edAddInputPort((*it)->getName(),tc));
366       std::string tmpPortName(_runNode->getOutPortName((*it)->getUndergroundPtr()));
367       YACS::ENGINE::OutputPort *myOut(n101->getOutputPort(tmpPortName));
368       _generatedGraph->edAddDFLink(myOut,myIn);
369     }
370   _generatedGraph->updateContainersAndComponents();
371 }
372
373 void YACSEvalYFXRunOnlyPattern::resetGeneratedGraph()
374 {
375   delete _generatedGraph;
376   _generatedGraph=0;
377   resetResources();
378 }
379
380 int YACSEvalYFXRunOnlyPattern::assignNbOfBranches()
381 {
382   checkAlreadyComputedResources();
383   if(!_generatedGraph)
384     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : the generated graph has not been created !");
385   std::list<YACS::ENGINE::Node *> nodes(_generatedGraph->getChildren());
386   YACS::ENGINE::ForEachLoop *zeMainNode(0);
387   for(std::list<YACS::ENGINE::Node *>::const_iterator it=nodes.begin();it!=nodes.end();it++)
388     {
389       YACS::ENGINE::ForEachLoop *isZeMainNode(dynamic_cast<YACS::ENGINE::ForEachLoop *>(*it));
390       if(isZeMainNode)
391         {
392           if(!zeMainNode)
393             zeMainNode=isZeMainNode;
394           else
395             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : internal error 1 !");
396         }
397     }
398   if(!zeMainNode)
399     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : internal error 2 !");
400   unsigned int nbProcsDeclared(getResourcesInternal()->getNumberOfProcsDeclared());
401   nbProcsDeclared=std::max(nbProcsDeclared,4u);
402   int nbOfBranch=1;
403   if(getParallelizeStatus())
404     {
405       nbOfBranch=(nbProcsDeclared/getResourcesInternal()->getMaxLevelOfParallelism());
406       nbOfBranch=std::max(nbOfBranch,1);
407     }
408   YACS::ENGINE::InputPort *zeInputToSet(zeMainNode->edGetNbOfBranchesPort());
409   YACS::ENGINE::AnyInputPort *zeInputToSetC(dynamic_cast<YACS::ENGINE::AnyInputPort *>(zeInputToSet));
410   if(!zeInputToSetC)
411     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignNbOfBranches : internal error 3 !");
412   YACS::ENGINE::Any *a(YACS::ENGINE::AtomAny::New(nbOfBranch));
413   zeInputToSetC->put(a);
414   zeInputToSetC->exSaveInit();
415   a->decrRef();
416   return nbOfBranch;
417 }
418
419 void YACSEvalYFXRunOnlyPattern::assignRandomVarsInputs()
420 {
421   std::size_t sz(std::numeric_limits<std::size_t>::max());
422   for(std::vector< YACSEvalInputPort >::const_iterator it=_inputs.begin();it!=_inputs.end();it++)
423     if((*it).isRandomVar())
424       {
425         std::size_t locSize((*it).initializeUndergroundWithSeq());
426         if(sz==std::numeric_limits<std::size_t>::max())
427           sz=locSize;
428         else
429           if(sz!=locSize)
430             throw YACS::Exception("YACSEvalYFXRunOnlyPattern::assignRandomVarsInputs : length of sequences in random vars must be the same !");
431       }
432 }
433
434 bool YACSEvalYFXRunOnlyPattern::isLocked() const
435 {
436   return _generatedGraph!=0;
437 }
438
439 YACSEvalListOfResources *YACSEvalYFXRunOnlyPattern::giveResources()
440 {
441   checkLocked();
442   if(!isAlreadyComputedResources())
443     {
444       YACS::ENGINE::DeploymentTree dt(_runNode->getDeploymentTree());
445       YACSEvalListOfResources *res(new YACSEvalListOfResources(_runNode->getMaxLevelOfParallelism(),getCatalogInAppli(),dt));
446       setResources(res);
447     }
448   return getResourcesInternal();
449 }
450
451 YACS::ENGINE::Proc *YACSEvalYFXRunOnlyPattern::getUndergroundGeneratedGraph() const
452 {
453   return _generatedGraph;
454 }
455
456 std::vector<YACSEvalSeqAny *> YACSEvalYFXRunOnlyPattern::getResults() const
457 {
458   if(_generatedGraph->getState()!=YACS::DONE)
459     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getResults : the execution did not finished correctly ! getResults should not be called !");
460   std::vector<YACSEvalSeqAny *> ret(_outputsOfInterest.size());
461   YACS::ENGINE::Node *node(_generatedGraph->getChildByName(GATHER_NODE_NAME));
462   YACS::ENGINE::PythonNode *nodeC(dynamic_cast<YACS::ENGINE::PythonNode *>(node));
463   if(!nodeC)
464     throw YACS::Exception("YACSEvalYFXRunOnlyPattern::getResults : internal error !");
465   std::size_t ii(0);
466   for(std::vector< YACSEvalOutputPort * >::const_iterator it=_outputsOfInterest.begin();it!=_outputsOfInterest.end();it++,ii++)
467     {
468       YACS::ENGINE::InPort *input(nodeC->getInPort((*it)->getName()));
469       YACS::ENGINE::InputPyPort *inputC(dynamic_cast<YACS::ENGINE::InputPyPort *>(input));
470       if(!inputC)
471         {
472           std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::getResults : internal error for input \"" << (*it)->getName() << "\"";
473           throw YACS::Exception(oss.str());
474         }
475       ret[ii]=BuildValueInPort(inputC);
476     }
477   return ret;
478 }
479
480 void YACSEvalYFXRunOnlyPattern::emitStart() const
481 {
482   YACSEvalObserver *obs(getObserver());
483   if(!obs)
484     return ;
485   obs->notifyNumberOfSamplesToEval(getBoss(),_FEInGeneratedGraph->getNbOfElementsToBeProcessed());
486 }
487
488 bool YACSEvalYFXRunOnlyPattern::IsMatching(YACS::ENGINE::Proc *scheme, YACS::ENGINE::ComposedNode *& runNode)
489 {
490   std::list<YACS::ENGINE::Node *> nodes(scheme->getChildren());
491   if(nodes.empty())
492     return false;
493   bool areAllElementary(true);
494   for(std::list<YACS::ENGINE::Node *>::const_iterator it=nodes.begin();it!=nodes.end() && areAllElementary;it++)
495     if(!dynamic_cast<YACS::ENGINE::ElementaryNode *>(*it))
496       areAllElementary=false;
497   if(areAllElementary)
498     {
499       if(scheme)
500         CheckNodeIsOK(scheme);
501       runNode=scheme;
502       return true;
503     }
504   if(nodes.size()!=1)
505     return false;
506   YACS::ENGINE::ComposedNode *candidate(dynamic_cast<YACS::ENGINE::ComposedNode *>(nodes.front()));
507   runNode=candidate;
508   if(candidate)
509     CheckNodeIsOK(candidate);
510   return candidate!=0;
511 }
512
513 void YACSEvalYFXRunOnlyPattern::buildInputPorts()
514 {
515   _inputs.clear();
516   std::list< YACS::ENGINE::InputPort *> allInputPorts(_runNode->getSetOfInputPort());
517   std::vector<std::string> allNames;
518   for(std::list< YACS::ENGINE::InputPort *>::const_iterator it=allInputPorts.begin();it!=allInputPorts.end();it++)
519     {
520       YACS::ENGINE::InputPort *elt(*it);
521       if(!elt)
522         throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildInputPorts : presence of null input !");
523       std::set<YACS::ENGINE::OutPort *> bls(elt->edSetOutPort());
524       if(bls.empty())
525         {
526           if(YACSEvalPort::IsInputPortPublishable(elt))
527             {
528               std::string inpName(elt->getName());
529               if(inpName.empty())
530                 throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildInputPorts : an input has empty name ! Should not !");
531               _inputs.push_back(YACSEvalInputPort(elt));
532               if(std::find(allNames.begin(),allNames.end(),inpName)!=allNames.end())
533                 {
534                   std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::buildInputPorts : input name \"" << inpName << "\" appears more than once !";
535                   throw YACS::Exception(oss.str());
536                 }
537               allNames.push_back(inpName);
538             }
539         }
540     }
541 }
542
543 void YACSEvalYFXRunOnlyPattern::buildOutputPorts()
544 {
545   _outputs.clear();
546   std::list< YACS::ENGINE::OutputPort *> allOutputPorts(_runNode->getSetOfOutputPort());
547   std::vector<std::string> allNames;
548   for(std::list< YACS::ENGINE::OutputPort *>::const_iterator it=allOutputPorts.begin();it!=allOutputPorts.end();it++)
549     {
550       YACS::ENGINE::OutputPort *elt(*it);
551       if(!elt)
552         throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildOutputPorts : presence of null output !");
553       std::string outpName(elt->getName());
554       if(outpName.empty())
555         throw YACS::Exception("YACSEvalYFXRunOnlyPattern::buildOutputPorts : an output has empty name ! Should not !");
556       if(std::find(allNames.begin(),allNames.end(),outpName)!=allNames.end())
557         {
558           std::ostringstream oss; oss << "YACSEvalYFXRunOnlyPattern::buildOutputPorts : output name \"" << outpName << "\" appears more than once !";
559           throw YACS::Exception(oss.str());
560         }
561       _outputs.push_back(YACSEvalOutputPort(*it));
562     }
563 }
564