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