Salome HOME
Manage initnode and finalizenode in the foreachloop progress bar.
[modules/yacs.git] / src / engine / ForEachLoop.cxx
index 46e16e5a4b3858953fbe9a1246f6c2a46a0bee90..3b9dec62cb8baa4e7fe63f4971cda31e067cb6ab 100644 (file)
@@ -25,7 +25,9 @@
 #include "AutoLocker.hxx"
 
 #include <iostream>
+#include <iomanip>
 #include <sstream>
+#include <algorithm>    // std::replace_if
 
 //#define _DEVDEBUG_
 #include "YacsTrace.hxx"
@@ -175,7 +177,7 @@ std::string SeqAnyInputPort::dump()
       switch (val->getType()->kind())
         {
         case Double:
-          xmldump << "<value><double>" << val->getDoubleValue() << "</double></value>" << endl;
+          xmldump << "<value><double>" << setprecision(16) << val->getDoubleValue() << "</double></value>" << endl;
           break;
         case Int:
           xmldump << "<value><int>" << val->getIntValue() << "</int></value>" << endl;
@@ -407,7 +409,7 @@ int ForEachLoopPassedData::toAbsId(int localId) const
 int ForEachLoopPassedData::toAbsIdNot(int localId) const
 {
   if(localId<0)
-    throw YACS::Exception("ForEachLoopPassedData::toAbsId : local pos must be >= 0 !");
+    throw YACS::Exception("ForEachLoopPassedData::toAbsIdNot : local pos must be >= 0 !");
   int ret(0),curLocId(0);
   for(std::vector<bool>::const_iterator it=_flagsIds.begin();it!=_flagsIds.end();it++,ret++)
     {
@@ -418,7 +420,7 @@ int ForEachLoopPassedData::toAbsIdNot(int localId) const
           curLocId++;
         }
     }
-  throw YACS::Exception("ForEachLoopPassedData::toAbsId : not referenced Id !");
+  throw YACS::Exception("ForEachLoopPassedData::toAbsIdNot : not referenced Id !");
 }
 
 int ForEachLoopPassedData::getNumberOfElementsToDo() const
@@ -465,7 +467,7 @@ ForEachLoop::ForEachLoop(const ForEachLoop& other, ComposedNode *father, bool ed
       {
         AnySplitOutputPort *temp=new AnySplitOutputPort(*(*iter2),this);
         InterceptorInputPort *interc=new InterceptorInputPort(*other._intecptrsForOutGoingPorts[i],this);
-        temp->addRepr(getOutPort((*iter2)->getName()),interc);
+        temp->addRepr(getOutPort(other.getOutPortName((*iter2)->getRepr())),interc);
         interc->setRepr(temp);
         _outGoingPorts.push_back(temp);
         _intecptrsForOutGoingPorts.push_back(interc);
@@ -504,6 +506,8 @@ void ForEachLoop::exUpdateState()
   DEBTRACE("ForEachLoop::exUpdateState");
   if(_state == YACS::DISABLED)
     return;
+  if(_state == YACS::DONE)
+    return;
   if(_inGate.exIsReady())
     {
       //internal graph update
@@ -737,6 +741,7 @@ YACS::Event ForEachLoop::updateStateForInitNodeOnFinishedEventFrom(Node *node, u
   _execNodes[id]->exUpdateState();
   _nbOfEltConsumed++;
   _initializingCounter--;
+  _currentIndex++;
   if (_initializingCounter == 0)
     _initNode->setState(DONE);
   return YACS::NOEVENT;
@@ -895,8 +900,16 @@ void ForEachLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort
       else
         {
           TypeCodeSeq *newTc=(TypeCodeSeq *)TypeCode::sequenceTc("","",port.first->edGetType());
-          AnySplitOutputPort *newPort=new AnySplitOutputPort(getPortName(port.first),this,newTc);
-          InterceptorInputPort *intercptor=new InterceptorInputPort(string("intercptr for ")+getPortName(port.first),this,port.first->edGetType());
+          // The out going ports belong to the ForEachLoop, whereas
+          // the delegated port belongs to a node child of the ForEachLoop.
+          // The name of the delegated port contains dots (bloc.node.outport),
+          // whereas the name of the out going port shouldn't do.
+          std::string outputPortName = getPortName(port.first);
+          std::replace_if (outputPortName.begin(), outputPortName.end(),
+                           std::bind1st(std::equal_to<char>(), '.'), '_');
+          outputPortName += "_interceptor";
+          AnySplitOutputPort *newPort=new AnySplitOutputPort(outputPortName,this,newTc);
+          InterceptorInputPort *intercptor=new InterceptorInputPort(outputPortName + "_in",this,port.first->edGetType());
           intercptor->setRepr(newPort);
           newTc->decrRef();
           newPort->addRepr(port.first,intercptor);
@@ -1028,8 +1041,13 @@ void ForEachLoop::createOutputOutOfScopeInterceptors(int branchNb)
 void ForEachLoop::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
                                        InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
 {
-  if(isInMyDescendance(start->getNode())==_node)
-    throw Exception("ForEachLoop::checkLinkPossibility : A link from work node to init node not permitted");
+  DynParaLoop::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd);
+  if(end->getNode() == &_splitterNode)
+    throw Exception("Illegal link within a foreach loop: \
+the 'SmplsCollection' port cannot be linked within the scope of the loop.");
+  if(end == &_nbOfBranches)
+    throw Exception("Illegal link within a foreach loop: \
+the 'nbBranches' port cannot be linked within the scope of the loop.");
 }
 
 std::list<OutputPort *> ForEachLoop::getLocalOutputPorts() const
@@ -1077,7 +1095,7 @@ void ForEachLoop::resetState(int level)
 
 std::string ForEachLoop::getProgress() const
 {
-  int nbElems = _splitterNode.getNumberOfElements();
+  int nbElems(getNbOfElementsToBeProcessed());
   std::stringstream aProgress;
   if (nbElems > 0)
     aProgress << _currentIndex << "/" << nbElems;
@@ -1086,6 +1104,38 @@ std::string ForEachLoop::getProgress() const
   return aProgress.str();
 }
 
+//! Get the progress weight for all elementary nodes
+/*!
+ * Only elementary nodes have weight. For each node in the loop, the weight done is multiplied
+ * by the number of elements done and the weight total by the number total of elements
+ */
+list<ProgressWeight> ForEachLoop::getProgressWeight() const
+{
+  list<ProgressWeight> ret;
+  list<Node *> setOfNode=edGetDirectDescendants();
+  int elemDone=getCurrentIndex();
+  int elemTotal=getNbOfElementsToBeProcessed();
+  for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
+    {
+      list<ProgressWeight> myCurrentSet=(*iter)->getProgressWeight();
+      for(list<ProgressWeight>::iterator iter=myCurrentSet.begin();iter!=myCurrentSet.end();iter++)
+        {
+          (*iter).weightDone=((*iter).weightTotal) * elemDone;
+          (*iter).weightTotal*=elemTotal;
+        }
+      ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
+    }
+  return ret;
+}
+
+int ForEachLoop::getNbOfElementsToBeProcessed() const
+{
+  int nbBranches = _nbOfBranches.getIntValue();
+  return _splitterNode.getNumberOfElements()
+         + (_initNode ? nbBranches:0)
+         + (_finalizeNode ? nbBranches:0) ;
+}
+
 /*!
  * This method allows to retrieve the state of \a this during execution or after. This method works even if this is \b NOT complete, or during execution or after a failure in \a this.
  * The typical usage of this method is to retrieve the results of items that passed successfully to avoid to lose all of them if only one fails.
@@ -1124,6 +1174,7 @@ std::vector<unsigned int> ForEachLoop::getPassedResults(Executor *execut, std::v
 void ForEachLoop::assignPassedResults(const std::vector<unsigned int>& passedIds, const std::vector<SequenceAny *>& passedOutputs, const std::vector<std::string>& nameOfOutputs)
 {
   delete _passedData;
+  _failedCounter=0;
   _passedData=new ForEachLoopPassedData(passedIds,passedOutputs,nameOfOutputs);
 }