Salome HOME
WIP
[modules/yacs.git] / src / engine / OptimizerLoop.cxx
index 152b578f1c620d9dafb9698bbc1789373a84ae51..48fbf9abdc978081b130e494461704dd9d60a254 100644 (file)
@@ -1,9 +1,9 @@
-// Copyright (C) 2006-2012  CEA/DEN, EDF R&D
+// Copyright (C) 2006-2019  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -98,7 +98,7 @@ void FakeNodeForOptimizerLoop::finished()
 OptimizerLoop::OptimizerLoop(const std::string& name, const std::string& algLibWthOutExt,
                              const std::string& symbolNameToOptimizerAlgBaseInstanceFactory,
                              bool algInitOnFile,bool initAlgo, Proc * procForTypes):
-        DynParaLoop(name,Runtime::_tc_string),_algInitOnFile(algInitOnFile),_alglib(algLibWthOutExt),
+        DynParaLoop(name,Runtime::_tc_string,std::unique_ptr<NbBranchesAbstract>(new NbBranches(this))),_algInitOnFile(algInitOnFile),_alglib(algLibWthOutExt),
         _algoInitPort(NAME_OF_ALGO_INIT_PORT, this, Runtime::_tc_string, true),
         _loader(NULL),_alg(0),_convergenceReachedWithOtherCalc(false),
         _retPortForOutPool(NAME_OF_OUT_POOL_INPUT,this,Runtime::_tc_string),
@@ -117,6 +117,11 @@ OptimizerLoop::OptimizerLoop(const OptimizerLoop& other, ComposedNode *father, b
   _algoResultPort(other._algoResultPort, this)
 {
   //Don't call setAlgorithm here because it will be called several times if the class is derived. Call it in simpleClone for cloning
+  
+  // Create the links to evalResults port
+  set<OutPort *> fromPortsToReproduce=other._retPortForOutPool.edSetOutPort();
+  for(set<OutPort *>::iterator iter=fromPortsToReproduce.begin();iter!=fromPortsToReproduce.end();iter++)
+    edAddLink(getOutPort(other.getPortName(*iter)),&_retPortForOutPool);
 }
 
 OptimizerLoop::~OptimizerLoop()
@@ -170,7 +175,6 @@ void OptimizerLoop::exUpdateState()
 
           // Initialize and launch the algorithm
           _alg->initializeProxy(_algoInitPort.getValue());
-          _alg->startProxy();
           if (_alg->hasError()) {
             string error = _alg->getError();
             _alg->finishProxy();
@@ -179,7 +183,16 @@ void OptimizerLoop::exUpdateState()
 
           //internal graph update
           int i;
-          int nbOfBr=_nbOfBranches.getIntValue();
+          int nbOfBr=_nbOfBranches->getIntValue();
+          _alg->setNbOfBranches(nbOfBr);
+
+          _alg->startProxy();
+          if (_alg->hasError()) {
+            string error = _alg->getError();
+            _alg->finishProxy();
+            throw Exception(error);
+          }
+
           if(nbOfBr==0)
             {
               // A number of branches of 0 is acceptable if there are no output ports
@@ -232,6 +245,7 @@ void OptimizerLoop::exUpdateState()
               _nodeForSpecialCases = new FakeNodeForOptimizerLoop(this, normal,
                   string("The algorithm of OptimizerLoop with name ") + _name +
                   " returns no sample to launch");
+              _alg->finishProxy();
               return;
             }
           launchMaxOfSamples(true);
@@ -409,8 +423,8 @@ YACS::Event OptimizerLoop::finalize()
             (*iter)->setState(YACS::DONE);
         }
     }
-  _alg->finishProxy();
   _algoResultPort.put(_alg->getAlgoResultProxy());
+  _alg->finishProxy();
   if (_finalizeNode == NULL)
     {
       // No finalize node, we just finish OptimizerLoop at the end of exec nodes execution
@@ -421,7 +435,7 @@ YACS::Event OptimizerLoop::finalize()
     {
       // Run the finalize nodes, the OptimizerLoop will be done only when they all finish
       _unfinishedCounter = 0;  // This counter indicates how many branches are not finished
-      for (int i=0 ; i<_nbOfBranches.getIntValue() ; i++)
+      for (int i=0 ; i<_nbOfBranches->getIntValue() ; i++)
         if (_execIds[i] == NOT_RUNNING_BRANCH_ID)
           {
             DEBTRACE("Launching finalize node for branch " << i)
@@ -443,7 +457,7 @@ YACS::Event OptimizerLoop::finalize()
  *  \param node : the child node that has failed
  *  \return the state change
  */
-YACS::Event OptimizerLoop::updateStateOnFailedEventFrom(Node *node)
+YACS::Event OptimizerLoop::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
 {
   DEBTRACE("OptimizerLoop::updateStateOnFailedEventFrom " << node->getName());
   _alg->setError(string("Error during the execution of YACS node ") + node->getName() +
@@ -451,7 +465,7 @@ YACS::Event OptimizerLoop::updateStateOnFailedEventFrom(Node *node)
   _alg->finishProxy();
   _myPool.destroyAll();
   DEBTRACE("OptimizerLoop::updateStateOnFailedEventFrom: returned from error notification.");
-  return DynParaLoop::updateStateOnFailedEventFrom(node);
+  return DynParaLoop::updateStateOnFailedEventFrom(node,execInst);
 }
 
 void OptimizerLoop::checkNoCyclePassingThrough(Node *node) throw(YACS::Exception)
@@ -462,12 +476,27 @@ void OptimizerLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, cons
 {
   DynParaLoop::buildDelegateOf(port,initialStart,pointsOfView);
   if(port==&_retPortForOutPool)
-    throw Exception("OptimizerLoop::buildDelegateOf : uncorrect OptimizerLoop link : out pool port must be linked within the scope of OptimizerLoop node it belongs to.");
+  {
+    std::string linkName("(");
+    linkName += initialStart->getName()+" to "+port->getName()+")";
+    throw Exception(std::string("Illegal OptimizerLoop link: \
+The 'evalResults' port must be linked within the scope of the loop.")
+                    + linkName);
+  }
 }
 
 void OptimizerLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
 {
   DynParaLoop::buildDelegateOf(port,finalTarget,pointsOfView);
+  if(port.first != &_algoResultPort)
+  {
+    std::string linkName("(");
+    linkName += port.first->getName()+" to "+finalTarget->getName()+")";
+    throw Exception(std::string("Illegal OptimizerLoop link: \
+Only the algorithm result port can be linked to a port outside the scope of the loop.")
+                    + linkName);
+  }
+
   string typeOfPortInstance=(port.first)->getNameOfTypeOfCurrentInstance();
   if(typeOfPortInstance!=OutputPort::NAME)
     throw Exception("OptimizerLoop::buildDelegateOf : not implemented for DS because not specified ");
@@ -493,6 +522,29 @@ void OptimizerLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *
     DynParaLoop::checkCFLinks(starts,end,alreadyFed,direction,info);
 }
 
+void OptimizerLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
+                          InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
+{
+  DynParaLoop::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
+  std::string linkName("(");
+  linkName += start->getName()+" to "+end->getName()+")";
+
+  // Yes, it should be possible to link back the result port to any input port of the loop.
+  if(end == _nbOfBranches->getPort() || end == &_algoInitPort)
+    if(start != &_algoResultPort)
+      throw Exception(std::string("Illegal OptimizerLoop link.") + linkName);
+    else
+      return;
+
+  if(start == &_algoResultPort)
+    throw Exception(std::string("Illegal OptimizerLoop link: \
+The 'algoResult' port can't be linked within the scope of the loop.") + linkName);
+  
+  if(end == &_retPortForOutPool && isInMyDescendance(start->getNode())!=_node)
+    throw Exception(std::string("Illegal OptimizerLoop link: \
+The 'evalResults' port can only be linked to the working node.") + linkName);
+}
+
 void OptimizerLoop::cleanInterceptors()
 {
   // At this point all garanties taken let's clean all.