1 // Copyright (C) 2006-2016 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "OptimizerLoop.hxx"
21 #include "OutputPort.hxx"
22 #include "Visitor.hxx"
27 #include "YacsTrace.hxx"
29 using namespace YACS::ENGINE;
32 const char FakeNodeForOptimizerLoop::NAME[]="thisIsAFakeNode";
34 const int OptimizerLoop::NOT_RUNNING_BRANCH_ID=-1973012217;
35 const int OptimizerLoop::NOT_INITIALIZED_BRANCH_ID=-1973;
37 const char OptimizerLoop::NAME_OF_ALGO_INIT_PORT[] = "algoInit";
38 const char OptimizerLoop::NAME_OF_OUT_POOL_INPUT[] = "evalResults";
39 const char OptimizerLoop::NAME_OF_ALGO_RESULT_PORT[] = "algoResults";
42 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(OptimizerLoop *loop, bool normal, std::string message)
43 : ElementaryNode(NAME), _loop(loop), _normal(normal), _message(message)
45 _state=YACS::TOACTIVATE;
46 _father=_loop->getFather();
49 FakeNodeForOptimizerLoop::FakeNodeForOptimizerLoop(const FakeNodeForOptimizerLoop& other)
50 : ElementaryNode(other), _loop(0), _normal(other._normal), _message(other._message)
54 Node *FakeNodeForOptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
56 return new FakeNodeForOptimizerLoop(*this);
59 void FakeNodeForOptimizerLoop::exForwardFailed()
61 _loop->exForwardFailed();
64 void FakeNodeForOptimizerLoop::exForwardFinished()
66 _loop->exForwardFinished();
69 void FakeNodeForOptimizerLoop::execute()
71 DEBTRACE("FakeNodeForOptimizerLoop::execute: " << _message)
73 _loop->_errorDetails = _message;
74 throw Exception(_message);
78 _loop->_algoResultPort.put(_loop->_alg->getAlgoResultProxy());
82 void FakeNodeForOptimizerLoop::aborted()
84 _loop->setState(YACS::ERROR);
87 void FakeNodeForOptimizerLoop::finished()
89 _loop->setState(YACS::DONE);
92 /*! \class YACS::ENGINE::OptimizerLoop
93 * \brief class to build optimization loops
95 * \ingroup ComposedNodes
98 OptimizerLoop::OptimizerLoop(const std::string& name, const std::string& algLibWthOutExt,
99 const std::string& symbolNameToOptimizerAlgBaseInstanceFactory,
100 bool algInitOnFile,bool initAlgo, Proc * procForTypes):
101 DynParaLoop(name,Runtime::_tc_string),_algInitOnFile(algInitOnFile),_alglib(algLibWthOutExt),
102 _algoInitPort(NAME_OF_ALGO_INIT_PORT, this, Runtime::_tc_string, true),
103 _loader(NULL),_alg(0),_convergenceReachedWithOtherCalc(false),
104 _retPortForOutPool(NAME_OF_OUT_POOL_INPUT,this,Runtime::_tc_string),
105 _nodeForSpecialCases(0), _algoResultPort(NAME_OF_ALGO_RESULT_PORT, this, Runtime::_tc_string)
107 //We need this because calling a virtual method in a constructor does not call the most derived method but the method of the class
108 //A derived class must take care to manage that
110 setAlgorithm(algLibWthOutExt,symbolNameToOptimizerAlgBaseInstanceFactory, procForTypes);
113 OptimizerLoop::OptimizerLoop(const OptimizerLoop& other, ComposedNode *father, bool editionOnly):
114 DynParaLoop(other,father,editionOnly),_algInitOnFile(other._algInitOnFile),_alglib(other._alglib),
115 _convergenceReachedWithOtherCalc(false),_loader(NULL),_alg(0),_algoInitPort(other._algoInitPort,this),
116 _retPortForOutPool(other._retPortForOutPool,this),_nodeForSpecialCases(0),
117 _algoResultPort(other._algoResultPort, this)
119 //Don't call setAlgorithm here because it will be called several times if the class is derived. Call it in simpleClone for cloning
121 // Create the links to evalResults port
122 set<OutPort *> fromPortsToReproduce=other._retPortForOutPool.edSetOutPort();
123 for(set<OutPort *>::iterator iter=fromPortsToReproduce.begin();iter!=fromPortsToReproduce.end();iter++)
124 edAddLink(getOutPort(other.getPortName(*iter)),&_retPortForOutPool);
127 OptimizerLoop::~OptimizerLoop()
134 delete _nodeForSpecialCases;
137 Node *OptimizerLoop::simpleClone(ComposedNode *father, bool editionOnly) const
139 OptimizerLoop* ol=new OptimizerLoop(*this,father,editionOnly);
140 // TODO: Remove this const_cast (find a better design to get the type codes from the original node)
141 Proc * procForTypes = ol->getProc();
142 if (procForTypes == NULL) {
143 const Proc * origProc = getProc();
144 procForTypes = const_cast<Proc *>(origProc);
146 ol->setAlgorithm(_alglib, _symbol, false, procForTypes);
150 void OptimizerLoop::init(bool start)
152 DynParaLoop::init(start);
153 _algoInitPort.exInit(start);
154 _retPortForOutPool.exInit(start);
155 _algoResultPort.exInit();
156 _convergenceReachedWithOtherCalc=false;
161 void OptimizerLoop::exUpdateState()
163 if(_state == YACS::DISABLED)
165 delete _nodeForSpecialCases;
166 _nodeForSpecialCases = NULL;
169 if(_inGate.exIsReady())
171 setState(YACS::TOACTIVATE);
172 // Force termination in case the previous algorithm did not finish properly (manual stop)
174 _myPool.destroyAll();
176 // Initialize and launch the algorithm
177 _alg->initializeProxy(_algoInitPort.getValue());
178 if (_alg->hasError()) {
179 string error = _alg->getError();
181 throw Exception(error);
184 //internal graph update
186 int nbOfBr=_nbOfBranches.getIntValue();
187 _alg->setNbOfBranches(nbOfBr);
190 if (_alg->hasError()) {
191 string error = _alg->getError();
193 throw Exception(error);
198 // A number of branches of 0 is acceptable if there are no output ports
199 // leaving OptimizerLoop
200 bool normal = getAllOutPortsLeavingCurrentScope().empty();
201 _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, normal,
202 "OptimizerLoop has no branch to run the internal node(s)");
205 _execNodes.resize(nbOfBr);
206 _execIds.resize(nbOfBr);
209 _execInitNodes.resize(nbOfBr);
210 _initNodeUpdated.resize(nbOfBr);
211 for(i=0;i<nbOfBr;i++)
212 _initNodeUpdated[i]=false;
214 _initializingCounter = 0;
216 _execFinalizeNodes.resize(nbOfBr);
217 vector<Node *> origNodes;
218 origNodes.push_back(_initNode);
219 origNodes.push_back(_node);
220 origNodes.push_back(_finalizeNode);
221 for(i=0;i<nbOfBr;i++)
223 _execIds[i]=NOT_INITIALIZED_BRANCH_ID;
224 vector<Node *> clonedNodes = cloneAndPlaceNodesCoherently(origNodes);
226 _execInitNodes[i] = clonedNodes[0];
227 _execNodes[i] = clonedNodes[1];
229 _execFinalizeNodes[i] = clonedNodes[2];
230 prepareInputsFromOutOfScope(i);
232 initInterceptors(nbOfBr);
234 unsigned char priority;
235 Any *val=_myPool.getNextSampleWithHighestPriority(id,priority);
238 // It is acceptable to have no sample to launch if there are no output ports
239 // leaving OptimizerLoop
240 std::set<OutPort *> setOutPort = getAllOutPortsLeavingCurrentScope();
241 // Special in the special
242 // We do not check algoResult
243 setOutPort.erase(&_algoResultPort);
244 bool normal = setOutPort.empty();
245 _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, normal,
246 string("The algorithm of OptimizerLoop with name ") + _name +
247 " returns no sample to launch");
250 launchMaxOfSamples(true);
253 catch (const exception & e)
255 _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, false,
256 string("An error happened in the control algorithm of OptimizerLoop \"") + _name +
261 int OptimizerLoop::getNumberOfInputPorts() const
263 return DynParaLoop::getNumberOfInputPorts()+2;
266 InputPort *OptimizerLoop::getInputPort(const std::string& name) const throw(YACS::Exception)
268 if (name == NAME_OF_ALGO_INIT_PORT)
269 return (InputPort *)&_algoInitPort;
270 else if (name == NAME_OF_OUT_POOL_INPUT)
271 return (InputPort *)&_retPortForOutPool;
273 return DynParaLoop::getInputPort(name);
276 std::list<InputPort *> OptimizerLoop::getSetOfInputPort() const
278 list<InputPort *> ret=DynParaLoop::getSetOfInputPort();
279 ret.push_back((InputPort *)&_algoInitPort);
280 ret.push_back((InputPort *)&_retPortForOutPool);
284 std::list<InputPort *> OptimizerLoop::getLocalInputPorts() const
286 list<InputPort *> ret=DynParaLoop::getLocalInputPorts();
287 ret.push_back((InputPort *)&_algoInitPort);
288 ret.push_back((InputPort *)&_retPortForOutPool);
292 void OptimizerLoop::selectRunnableTasks(std::vector<Task *>& tasks)
296 void OptimizerLoop::getReadyTasks(std::vector<Task *>& tasks)
300 if(_state==YACS::TOACTIVATE || _state==YACS::ACTIVATED)
302 if(_nodeForSpecialCases)
304 _nodeForSpecialCases->getReadyTasks(tasks);
307 vector<Node *>::iterator iter;
308 for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
309 (*iter)->getReadyTasks(tasks);
310 for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
311 (*iter)->getReadyTasks(tasks);
312 for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
313 (*iter)->getReadyTasks(tasks);
317 YACS::Event OptimizerLoop::updateStateOnFinishedEventFrom(Node *node)
319 if (getState() == YACS::FAILED)
321 // This happens when a valid computation on a branch finishes after an error on another branch.
322 // In this case we just ignore the new result because the algorithm has already been terminated.
323 return YACS::NOEVENT;
326 switch(getIdentityOfNotifyerNode(node,id))
330 _execNodes[id]->exUpdateState();
332 _initializingCounter--;
333 if (_initializingCounter == 0) _initNode->setState(DONE);
338 if(_convergenceReachedWithOtherCalc)
339 { //This case happens when alg has reached its convergence whereas other calculations still compute
340 _execIds[id]=NOT_RUNNING_BRANCH_ID;
342 return YACS::NOEVENT;
346 _myPool.putOutSampleAt(_execIds[id],_interceptorsForOutPool[id]->getValue());
347 _myPool.setCurrentId(_execIds[id]);
348 _alg->takeDecisionProxy();
349 if (_alg->hasError()) {
350 _errorDetails = string("An error happened in the control algorithm of optimizer loop: ") +
353 setState(YACS::FAILED);
357 _myPool.destroyCurrentCase();
360 pushValueOutOfScopeForCase(id);
361 _execIds[id]=NOT_RUNNING_BRANCH_ID;
363 {// This case happens when the hand is returned to continue, whereas some other are working in parallel for nothing.
364 _convergenceReachedWithOtherCalc=true;
365 return YACS::NOEVENT;
369 _execIds[id]=NOT_RUNNING_BRANCH_ID;
371 unsigned char priority;
372 Any *val=_myPool.getNextSampleWithHighestPriority(newId, priority);
375 bool isFinished=true;
376 for(int i=0;i<_execIds.size() && isFinished;i++)
377 isFinished=(_execIds[i]==NOT_RUNNING_BRANCH_ID || _execIds[i]==NOT_INITIALIZED_BRANCH_ID);
380 std::cerr <<"OptimizerLoop::updateStateOnFinishedEventFrom: Alg has not inserted more cases whereas last element has been calculated !" << std::endl;
381 setState(YACS::ERROR);
386 return YACS::NOEVENT;
388 launchMaxOfSamples(false);
393 _unfinishedCounter--;
394 if (_unfinishedCounter == 0)
396 _finalizeNode->setState(YACS::DONE);
397 setState(YACS::DONE);
401 return YACS::NOEVENT;
407 return YACS::NOEVENT;
410 YACS::Event OptimizerLoop::finalize()
412 //update internal node (definition node) state
415 _node->setState(YACS::DONE);
416 ComposedNode* compNode = dynamic_cast<ComposedNode*>(_node);
419 std::list<Node *> aChldn = compNode->getAllRecursiveConstituents();
420 std::list<Node *>::iterator iter=aChldn.begin();
421 for(;iter!=aChldn.end();iter++)
422 (*iter)->setState(YACS::DONE);
426 _algoResultPort.put(_alg->getAlgoResultProxy());
427 if (_finalizeNode == NULL)
429 // No finalize node, we just finish OptimizerLoop at the end of exec nodes execution
430 setState(YACS::DONE);
435 // Run the finalize nodes, the OptimizerLoop will be done only when they all finish
436 _unfinishedCounter = 0; // This counter indicates how many branches are not finished
437 for (int i=0 ; i<_nbOfBranches.getIntValue() ; i++)
438 if (_execIds[i] == NOT_RUNNING_BRANCH_ID)
440 DEBTRACE("Launching finalize node for branch " << i)
441 _execFinalizeNodes[i]->exUpdateState();
442 _unfinishedCounter++;
445 // There should not be any running branch at this point
446 YASSERT(_execIds[i] == NOT_INITIALIZED_BRANCH_ID)
447 return YACS::NOEVENT;
451 //! Method used to notify the node that a child node has failed
453 * Notify the slave thread of the error, update the current state and
454 * return the change state
456 * \param node : the child node that has failed
457 * \return the state change
459 YACS::Event OptimizerLoop::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
461 DEBTRACE("OptimizerLoop::updateStateOnFailedEventFrom " << node->getName());
462 _alg->setError(string("Error during the execution of YACS node ") + node->getName() +
463 ": " + node->getErrorReport());
465 _myPool.destroyAll();
466 DEBTRACE("OptimizerLoop::updateStateOnFailedEventFrom: returned from error notification.");
467 return DynParaLoop::updateStateOnFailedEventFrom(node,execInst);
470 void OptimizerLoop::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
474 void OptimizerLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
476 DynParaLoop::buildDelegateOf(port,initialStart,pointsOfView);
477 if(port==&_retPortForOutPool)
479 std::string linkName("(");
480 linkName += initialStart->getName()+" to "+port->getName()+")";
481 throw Exception(std::string("Illegal OptimizerLoop link: \
482 The 'evalResults' port must be linked within the scope of the loop.")
487 void OptimizerLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
489 DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
490 if(port.first != &_algoResultPort)
492 std::string linkName("(");
493 linkName += port.first->getName()+" to "+finalTarget->getName()+")";
494 throw Exception(std::string("Illegal OptimizerLoop link: \
495 Only the algorithm result port can be linked to a port outside the scope of the loop.")
499 string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
500 if(typeOfPortInstance!=OutputPort::NAME)
501 throw Exception("OptimizerLoop::buildDelegateOf : not implemented for DS because not specified ");
504 void OptimizerLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
505 std::map < ComposedNode *, std::list < OutPort * >, SortHierarc >& fw,
506 std::vector<OutPort *>& fwCross,
507 std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
508 LinkInfo& info) const
510 if(end==&_retPortForOutPool)
511 fw[(ComposedNode *)this].push_back(start);
513 DynParaLoop::checkControlDependancy(start,end,cross,fw,fwCross,bw,info);
516 void OptimizerLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
518 if(end==&_retPortForOutPool)
519 solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
521 DynParaLoop::checkCFLinks(starts,end,alreadyFed,direction,info);
524 void OptimizerLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
525 InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
527 DynParaLoop::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
528 std::string linkName("(");
529 linkName += start->getName()+" to "+end->getName()+")";
531 // Yes, it should be possible to link back the result port to any input port of the loop.
532 if(end == &_nbOfBranches || end == &_algoInitPort)
533 if(start != &_algoResultPort)
534 throw Exception(std::string("Illegal OptimizerLoop link.") + linkName);
538 if(start == &_algoResultPort)
539 throw Exception(std::string("Illegal OptimizerLoop link: \
540 The 'algoResult' port can't be linked within the scope of the loop.") + linkName);
542 if(end == &_retPortForOutPool && isInMyDescendance(start->getNode())!=_node)
543 throw Exception(std::string("Illegal OptimizerLoop link: \
544 The 'evalResults' port can only be linked to the working node.") + linkName);
547 void OptimizerLoop::cleanInterceptors()
549 // At this point all garanties taken let's clean all.
550 map<InputPort *,vector<InputPort *> >::iterator iter=_interceptors.begin();
551 for(;iter!=_interceptors.end();iter++)
552 for(vector<InputPort *>::iterator iter2=(*iter).second.begin();iter2!=(*iter).second.end();iter2++)
554 _interceptors.clear();
555 for(vector<AnyInputPort *>::iterator iter3=_interceptorsForOutPool.begin();iter3!=_interceptorsForOutPool.end();iter3++)
557 _interceptorsForOutPool.clear();
560 void OptimizerLoop::launchMaxOfSamples(bool first)
563 unsigned char priority;
566 for (val = _myPool.getNextSampleWithHighestPriority(id, priority);
567 !isFullyBusy(i) && val;
568 val = _myPool.getNextSampleWithHighestPriority(id, priority))
570 if(_execIds[i] == NOT_INITIALIZED_BRANCH_ID)
571 first=true; // node is not initialized (first pass)
573 first=false; // node is initialized (second pass)
575 _myPool.markIdAsInUse(id);
576 if(_initNode && !_initNodeUpdated[i])
578 putValueOnBranch(val,i,first);
579 _execInitNodes[i]->exUpdateState();
580 _initNodeUpdated[i]=true;
581 _initializingCounter++;
586 _execNodes[i]->init(first);
587 putValueOnBranch(val,i,first);
588 _execNodes[i]->exUpdateState();
594 bool OptimizerLoop::isFullyLazy() const
597 for(unsigned i=0;i<_execIds.size() && isLazy;i++)
598 isLazy=(_execIds[i]==NOT_RUNNING_BRANCH_ID || _execIds[i]==NOT_INITIALIZED_BRANCH_ID);
603 * Returns if a dynamic branch is available.
604 * \param branchId Out param. Only usable if returned value is equal to \b false.
606 bool OptimizerLoop::isFullyBusy(unsigned& branchId) const
608 bool isFinished=true;
610 for(i=0;i<_execIds.size() && isFinished;i++)
611 isFinished=(_execIds[i]!=NOT_RUNNING_BRANCH_ID && _execIds[i]!=NOT_INITIALIZED_BRANCH_ID);
618 * Perform initialization of interceptors. \b WARNING _execNodes have to be created before.
620 void OptimizerLoop::initInterceptors(unsigned nbOfBr)
622 //For all classical outputports leaving 'this'
623 set<OutPort *> portsToIntercept=getAllOutPortsLeavingCurrentScope();
624 portsToIntercept.erase(&_algoResultPort);
625 for(set<OutPort *>::iterator iter=portsToIntercept.begin();iter!=portsToIntercept.end();iter++)
627 OutputPort *portC=(OutputPort *)(*iter);//Warrantied by OptimizerLoop::buildDelegateOf
628 const set<InputPort *>& links=portC->getSetOfPhyLinks();
629 for(set<InputPort *>::const_iterator iter2=links.begin();iter2!=links.end();iter2++)
632 InputPort *reprCur=dynamic_cast<InputPort *>((*iter2)->getPublicRepresentant());
634 InputPort *reprCur=(*iter2)->getPublicRepresentant();
636 if(!isInMyDescendance(reprCur->getNode()))
637 {//here we've got an out of scope link : Let's intercept it
638 if(_interceptors.find(reprCur)==_interceptors.end())
640 _interceptors[reprCur].resize(nbOfBr);
641 for(unsigned i=0;i<nbOfBr;i++)
643 OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
644 InputPort *clone=reprCur->clone(0);
645 _interceptors[reprCur][i]=clone;
646 portExecC->edAddInputPort(clone);
651 for(unsigned i=0;i<nbOfBr;i++)
653 OutputPort *portExecC=(OutputPort *)_execNodes[i]->getOutputPort(_node->getOutPortName(portC));
654 portExecC->edAddInputPort(_interceptors[reprCur][i]);
661 _interceptorsForOutPool.resize(nbOfBr);
662 set< OutPort * > links=_retPortForOutPool.edSetOutPort();
663 for(unsigned i=0;i<nbOfBr;i++)
664 _interceptorsForOutPool[i]=(AnyInputPort *)_retPortForOutPool.clone(this);
665 for(set<OutPort *>::iterator iter2=links.begin();iter2!=links.end();iter2++)
666 for(unsigned j=0;j<nbOfBr;j++)
669 Node *whatType=isInMyDescendance((*iter2)->getNode());
672 portExec=_execNodes[j]->getOutPort(_node->getOutPortName(*iter2));
673 portExec->addInPort(_interceptorsForOutPool[j]);
675 else if(whatType==_initNode && whatType!=0)//This case should never happend. Useless !
677 portExec=_execInitNodes[j]->getOutPort(_node->getOutPortName(*iter2));
678 portExec->addInPort(_interceptorsForOutPool[j]);
684 * Typically called when _alg has decided that convergence has been reached. In this case the links leaving the current scope are activated and filled
685 * with value of the branch specified by 'branchId' that is the branch in which the convergence has been reached.
687 void OptimizerLoop::pushValueOutOfScopeForCase(unsigned branchId)
689 map<InputPort *, std::vector<InputPort *> >::iterator iter;
690 for(iter=_interceptors.begin();iter!=_interceptors.end();iter++)
691 (*iter).first->put((*iter).second[branchId]->get());
694 void OptimizerLoop::accept(Visitor *visitor)
696 visitor->visitOptimizerLoop(this);
699 //! Set the algorithm library name and factory name (symbol in library) to create the algorithm and change it if the node is not connected
701 * throw an exception if the node is connected
703 void OptimizerLoop::setAlgorithm(const std::string& alglib, const std::string& symbol,
704 bool checkLinks, Proc * procForTypes)
708 if (_splittedPort.edGetNumberOfOutLinks() != 0 ||
709 _retPortForOutPool.edGetNumberOfLinks() != 0 ||
710 _algoInitPort.edGetNumberOfLinks() != 0 ||
711 _algoResultPort.edGetNumberOfOutLinks() != 0)
712 throw Exception("The OptimizerLoop node must be disconnected before setting the algorithm");
727 _alg->setProc((procForTypes == NULL) ? getProc() : procForTypes);
729 // Delete the values in the input ports if they were initialized
730 _retPortForOutPool.put((Any *)NULL);
731 _algoInitPort.put((Any *)NULL);
733 // Change the type of the ports
734 _splittedPort.edSetType(checkTypeCode(_alg->getTCForInProxy(), NAME_OF_SPLITTED_SEQ_OUT));
735 _retPortForOutPool.edSetType(checkTypeCode(_alg->getTCForOutProxy(), NAME_OF_OUT_POOL_INPUT));
736 _algoInitPort.edSetType(checkTypeCode(_alg->getTCForAlgoInitProxy(), NAME_OF_ALGO_INIT_PORT));
737 _algoResultPort.edSetType(checkTypeCode(_alg->getTCForAlgoResultProxy(), NAME_OF_ALGO_RESULT_PORT));
743 TypeCode * OptimizerLoop::checkTypeCode(TypeCode * tc, const char * portName)
746 ostringstream errorMsg;
747 errorMsg << "The algorithm specified for OptimizerLoop node \"" << getName() <<
748 "\" provided an invalid type for port \"" << portName << "\"";
749 throw Exception(errorMsg.str());
754 //! Load the algorithm from the dynamic library
758 void OptimizerLoop::loadAlgorithm()
760 YASSERT(_alg == NULL)
762 if (_loader != NULL) {
766 _loader = new YACS::BASES::DynLibLoader(_alglib);
767 OptimizerAlgBaseFactory algFactory = NULL;
769 if (_alglib != "" && _symbol != "")
774 algFactory = (OptimizerAlgBaseFactory)_loader->getHandleOnSymbolWithName(_symbol);
776 catch (YACS::Exception& e)
778 _errorDetails = e.what();
784 if (algFactory != NULL)
785 _alg = algFactory(&_myPool);
788 //! Return the name of the algorithm library
792 std::string OptimizerLoop::getAlgLib() const
797 //! Check validity for the node.
799 * Throw an exception if the node is not valid
801 void OptimizerLoop::checkBasicConsistency() const throw(YACS::Exception)
803 DEBTRACE("OptimizerLoop::checkBasicConsistency");
805 throw Exception("No library specified for the OptimizerLoop control algorithm");
807 throw Exception("No symbol specified for the OptimizerLoop control algorithm");
809 throw YACS::Exception("Problem during library loading: "+_errorDetails);
811 DynParaLoop::checkBasicConsistency();
814 int OptimizerLoop::getNumberOfOutputPorts() const
816 return DynParaLoop::getNumberOfOutputPorts() + 1;
819 std::list<OutputPort *> OptimizerLoop::getSetOfOutputPort() const
821 list<OutputPort *> ret = DynParaLoop::getSetOfOutputPort();
822 ret.push_back((OutputPort *)&_algoResultPort);
826 std::list<OutputPort *> OptimizerLoop::getLocalOutputPorts() const
828 list<OutputPort *> ret = DynParaLoop::getLocalOutputPorts();
829 ret.push_front((OutputPort *)&_algoResultPort);
833 OutPort * OptimizerLoop::getOutPort(const std::string& name) const throw(YACS::Exception)
835 return (name == NAME_OF_ALGO_RESULT_PORT) ? (OutPort *)&_algoResultPort :
836 DynParaLoop::getOutPort(name);
840 OutputPort * OptimizerLoop::getOutputPort(const std::string& name) const throw(YACS::Exception)
842 return (name == NAME_OF_ALGO_RESULT_PORT) ? (OutputPort *)&_algoResultPort :
843 DynParaLoop::getOutputPort(name);