Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/yacs.git] / src / engine / ElementaryNode.cxx
index f1869255d46d9e9cb859b64acfb0b29cbca2e386..1aa6ae7fa6e70c5bf0e248aad686d6c52da0f4ab 100644 (file)
@@ -1,21 +1,22 @@
-//  Copyright (C) 2006-2008  CEA/DEN, EDF R&D
+// Copyright (C) 2006-2012  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.
+// 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.
 //
-//  This library is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-//  Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
 //
-//  You should have received a copy of the GNU Lesser General Public
-//  License along with this library; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+
 #include "ElementaryNode.hxx"
 #include "Runtime.hxx"
 #include "InputPort.hxx"
 #include "InputDataStreamPort.hxx"
 #include "OutputDataStreamPort.hxx"
 #include "Visitor.hxx"
+#include "Proc.hxx"
+#include "Container.hxx"
 #include <iostream>
+#include <sstream>
 
 //#define _DEVDEBUG_
 #include "YacsTrace.hxx"
 using namespace YACS::ENGINE;
 using namespace std;
 
-ElementaryNode::ElementaryNode(const std::string& name):Node(name)
+/*! \class YACS::ENGINE::ElementaryNode
+ *  \brief Base class for all calculation nodes.
+ *
+ * This is an abstract class that must be specialized.
+ *
+ *  \ingroup Nodes
+ */
+
+ElementaryNode::ElementaryNode(const std::string& name):
+  Node(name),
+  _createDatastreamPorts(false),
+  _multi_port_node(false)
 {
 }
 
 ElementaryNode::ElementaryNode(const ElementaryNode& other, ComposedNode *father):Node(other,father)
 {
+  _createDatastreamPorts = other._createDatastreamPorts;
+  _multi_port_node = other._multi_port_node;
   for(list<InputPort *>::const_iterator iter1=other._setOfInputPort.begin();iter1!=other._setOfInputPort.end();iter1++)
     _setOfInputPort.push_back((InputPort *)(*iter1)->clone(this));
   for(list<OutputPort *>::const_iterator iter2=other._setOfOutputPort.begin();iter2!=other._setOfOutputPort.end();iter2++)
@@ -66,6 +83,8 @@ ElementaryNode::~ElementaryNode()
 
 void ElementaryNode::init(bool start)
 {
+  DEBTRACE("ElementaryNode::init " << getName() << " " << start << " " << _state);
+
   for(list<OutputPort *>::iterator iter=_setOfOutputPort.begin();iter!=_setOfOutputPort.end();iter++)
     (*iter)->exInit();
   for(list<InputPort *>::iterator iter2=_setOfInputPort.begin();iter2!=_setOfInputPort.end();iter2++)
@@ -78,8 +97,8 @@ void ElementaryNode::init(bool start)
     }
   if(start) //complete initialization
     setState(YACS::READY);
-  else //partial initialization (inside a loop)
-    setState(YACS::LOADED);
+  else if(_state > YACS::LOADED)//partial initialization (inside a loop)
+    setState(YACS::TORECONNECT);
 }
 
 bool ElementaryNode::isDeployable() const
@@ -92,6 +111,11 @@ ComponentInstance *ElementaryNode::getComponent()
   return 0;
 }
 
+Container *ElementaryNode::getContainer()
+{
+  return 0;
+}
+
 YACS::StatesForNode ElementaryNode::getState() const
 {
   return Node::getState();
@@ -129,12 +153,16 @@ int ElementaryNode::getNumberOfOutputPorts() const
   return _setOfOutputPort.size();
 }
 
-InputPort *ElementaryNode::getInputPort(const std::string& name) const throw(Exception)
+InputPort *ElementaryNode::getInputPort(const std::string& name) const throw(YACS::Exception)
 {
+  try {
+    return Node::getInputPort(name);
+  }
+  catch(Exception& e) {}
   return getPort<InputPort>(name,_setOfInputPort);
 }
 
-OutputPort *ElementaryNode::getOutputPort(const std::string& name) const throw(Exception)
+OutputPort *ElementaryNode::getOutputPort(const std::string& name) const throw(YACS::Exception)
 {
   return getPort<OutputPort>(name,_setOfOutputPort);
 }
@@ -186,17 +214,22 @@ std::vector< std::pair<InPort *, OutPort *> > ElementaryNode::getSetOfLinksComin
     {
       set<OutPort *> temp2=(*iter2)->edSetOutPort();
       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
-        ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter3));
+        {
+          std::set<OutPort *> trueOutPorts;
+          (*iter3)->getAllRepresented(trueOutPorts);
+          for(std::set<OutPort *>::iterator iter4=trueOutPorts.begin();iter4!=trueOutPorts.end();++iter4)
+            ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter4));
+        }
     }
   return ret;
 }
 
-InputDataStreamPort *ElementaryNode::getInputDataStreamPort(const std::string& name) const throw(Exception)
+InputDataStreamPort *ElementaryNode::getInputDataStreamPort(const std::string& name) const throw(YACS::Exception)
 {
   return getPort<InputDataStreamPort>(name,_setOfInputDataStreamPort);
 }
 
-OutputDataStreamPort *ElementaryNode::getOutputDataStreamPort(const std::string& name) const throw(Exception)
+OutputDataStreamPort *ElementaryNode::getOutputDataStreamPort(const std::string& name) const throw(YACS::Exception)
 {
   return getPort<OutputDataStreamPort>(name,_setOfOutputDataStreamPort);
 }
@@ -237,6 +270,79 @@ bool ElementaryNode::areAllInputPortsValid() const
   return ret;
 }
 
+/*
+  This method is used by the "multi" property of ElementaryNode to create
+  to create duplicated input and ouput datastream ports.
+*/
+void
+ElementaryNode::createMultiDatastreamPorts()
+{
+  if (!_createDatastreamPorts)
+  {
+    _createDatastreamPorts = true;
+    for(list<InputDataStreamPort *>::const_iterator iter3 = _setOfInputDataStreamPort.begin(); iter3!=_setOfInputDataStreamPort.end();iter3++)
+    {
+      InputDataStreamPort * port = *iter3;
+      std::string port_name = port->getName();
+      std::map<std::string,std::string>::iterator it=_propertyMap.find(port_name);
+      int multi = 1;
+      if(it != _propertyMap.end())
+      {
+        std::string multi_str = it->second;
+        std::istringstream iss(multi_str);
+        if (!(iss >> multi))
+          throw Exception("Property multi port should be set with a stringified int not an: " + multi_str);
+      }
+
+      if (multi > 1)
+      {
+        addDatastreamPortToInitMultiService(port_name, multi);
+        // Change name of first port
+        port->setName(port_name + "_0");
+        for (int i = 2; i <= multi; i++)
+        {
+          InputDataStreamPort * new_port = port->clone(this);
+          std::ostringstream number;
+          number << i-1;
+          new_port->setName(port_name + "_" + number.str());
+          _setOfInputDataStreamPort.push_back(new_port);
+          _multi_port_node = true;
+        }
+      }
+    }
+    for(list<OutputDataStreamPort *>::const_iterator iter4 = _setOfOutputDataStreamPort.begin(); iter4!=_setOfOutputDataStreamPort.end();iter4++)
+    {
+      OutputDataStreamPort * port = *iter4;
+      std::string port_name = port->getName();
+      std::map<std::string,std::string>::iterator it=_propertyMap.find(port_name);
+      int multi = 1;
+      if(it != _propertyMap.end())
+      {
+        std::string multi_str = it->second;
+        std::istringstream iss(multi_str);
+        if (!(iss >> multi))
+          throw Exception("Property multi port should be set with a stringified int not an: " + multi_str);
+      }
+
+      if (multi > 1)
+      {
+        addDatastreamPortToInitMultiService(port_name, multi);
+        // Change name of first port
+        port->setName(port_name + "_0");
+        for (int i = 2; i <= multi; i++)
+        {
+          OutputDataStreamPort * new_port = port->clone(this);
+          std::ostringstream number;
+          number << i-1;
+          new_port->setName(port_name + "_" + number.str());
+          _setOfOutputDataStreamPort.push_back(new_port);
+          _multi_port_node = true;
+        }
+      }
+    }
+  }
+}
+
 /**
  * add this node task to a given set of ready tasks, if this task is ready to activate
  */
@@ -244,15 +350,165 @@ bool ElementaryNode::areAllInputPortsValid() const
 void ElementaryNode::getReadyTasks(std::vector<Task *>& tasks)
 {
   DEBTRACE("ElementaryNode::getReadyTasks: " << getName() << " " << _state);
-  if(_state==YACS::TOACTIVATE or _state==YACS::TOLOAD)
-    tasks.push_back(this);
+
+  int multi = 1;
+  std::map<std::string,std::string>::iterator it=_propertyMap.find("multi");
+  if(it != _propertyMap.end())
+  {
+    std::string multi_str = it->second;
+    std::istringstream iss(multi_str);
+    if (!(iss >> multi))
+      throw Exception("Property multi should be set with a stringified int not an: " + multi_str);
+  }
+
+  if(_state==YACS::TOACTIVATE || _state==YACS::TOLOAD || _state==YACS::TORECONNECT)
+  {
+    if (multi == 1)
+    {
+      std::map<std::string,std::string>::iterator it=_propertyMap.find("multi_working_dir");
+      if(it != _propertyMap.end())
+      {
+        std::string working_dir_base = it->second;
+        std::ostringstream working_dir_stream;
+        working_dir_stream << working_dir_base;
+        working_dir_stream << 1;
+        this->getContainer()->setProperty("workingdir", working_dir_stream.str());
+      }
+      tasks.push_back(this);
+    }
+    else
+    {
+
+      // Check output port -> cannot clone an Elementary Node with Output Ports connected
+      std::list<OutputPort *>::iterator it_output = _setOfOutputPort.begin();
+      for (;it_output != _setOfOutputPort.end(); it_output++)
+      {
+        if ((*it_output)->isConnected())
+        {
+          throw Exception("Property multi cannot be set on nodes with dataflow output ports connected");
+        }
+      }
+
+      // Add my instance
+      std::map<std::string,std::string>::iterator it=_propertyMap.find("multi_working_dir");
+      if(it != _propertyMap.end())
+      {
+        std::string working_dir_base = it->second;
+        std::ostringstream working_dir_stream;
+        working_dir_stream << working_dir_base;
+        working_dir_stream << 1;
+        this->getContainer()->setProperty("workingdir", working_dir_stream.str());
+      }
+      tasks.push_back(this);
+
+      // Step 1: Create clones
+      for (int i = 1; i < multi; i++)
+      {
+        // Clone
+        YACS::ENGINE::ElementaryNode * new_node = static_cast<YACS::ENGINE::ElementaryNode *>(clone(_father, false));
+        new_node->createMultiDatastreamPorts();
+
+        // Change name
+        std::string iname;
+        std::stringstream inamess;
+        inamess << getName() << "_" << i;
+        iname=inamess.str();
+        DEBTRACE("Create clone "<< iname << " of node " << getName());
+        new_node->setName(iname);
+
+        // For each input port connect it with the original output port
+        std::list<InputPort *> clone_list_inputPorts = new_node->getSetOfInputPort();
+        for(list<InputPort *>::const_iterator iter1=clone_list_inputPorts.begin(); iter1!=clone_list_inputPorts.end(); iter1++)
+        {
+          std::string input_port_name = (*iter1)->getName();
+          // Get Port Name in master node
+          InputPort * master_port = getInputPort(input_port_name);
+          for (std::set<OutPort *>::const_iterator itt=master_port->_backLinks.begin(); itt!=master_port->_backLinks.end();itt++)
+          {
+            // Connect dataflow
+            getProc()->edAddDFLink((*itt),(*iter1));
+          }
+        }
+
+        // InputDataStreamPort connections
+        std::list<InputDataStreamPort *> clone_list_inputDatastreamPorts = new_node->getSetOfInputDataStreamPort();
+        for(list<InputDataStreamPort *>::iterator iter = clone_list_inputDatastreamPorts.begin(); iter != clone_list_inputDatastreamPorts.end(); iter++)
+        {
+          std::string port_name = (*iter)->getName();
+          InputDataStreamPort * orig_port = getInputDataStreamPort(port_name);
+
+          std::set<OutputDataStreamPort *> connected_ports = orig_port->getConnectedOutputDataStreamPort();
+
+          // Create datastream ports if not created
+          std::set<OutputDataStreamPort *>::const_iterator iter3;
+          for(iter3=connected_ports.begin();iter3!=connected_ports.end();iter3++)
+          {
+            ElementaryNode * node = (ElementaryNode *) (*iter3)->getNode();
+            node->createMultiDatastreamPorts();
+
+            std::string good_port_name;
+            std::stringstream temp_name;
+            std::string out_name = (*iter3)->getName();
+            out_name.erase(out_name.end()-1);
+            temp_name << out_name << i;
+            good_port_name = temp_name.str();
+            getProc()->edAddLink(node->getOutputDataStreamPort(good_port_name), (*iter));
+          }
+        }
+
+        // OutputDataStreamPort connections
+        std::list<OutputDataStreamPort *> clone_list_outputDatastreamPorts = new_node->getSetOfOutputDataStreamPort();
+        for(list<OutputDataStreamPort *>::iterator iter = clone_list_outputDatastreamPorts.begin(); iter != clone_list_outputDatastreamPorts.end(); iter++)
+        {
+          std::string port_name = (*iter)->getName();
+          OutputDataStreamPort * orig_port = getOutputDataStreamPort(port_name);
+          std::set<InputDataStreamPort *> dest_input_port = orig_port->_setOfInputDataStreamPort;
+          for(set<InputDataStreamPort *>::iterator dest_port = dest_input_port.begin(); dest_port != dest_input_port.end(); dest_port++)
+          {
+            ElementaryNode * dest_node = (ElementaryNode *)(*dest_port)->getNode();
+            // Add InputPort to dest node
+            dest_node->createMultiDatastreamPorts();
+
+            std::string good_port_name;
+            std::stringstream temp_name;
+            std::string in_name = (*dest_port)->getName();
+            in_name.erase(in_name.end()-1);
+            temp_name << in_name << i;
+            good_port_name = temp_name.str();
+            getProc()->edAddLink((*iter), dest_node->getInputDataStreamPort(good_port_name));
+          }
+        }
+
+        // Init node
+        new_node->init(false);
+        new_node->exUpdateState();
+
+        // Set Control Link to done
+        std::list<OutGate *> clone_cl_back = new_node->getInGate()->getBackLinks();
+        for(std::list<OutGate *>::const_iterator iter=clone_cl_back.begin(); iter!=clone_cl_back.end(); iter++)
+          new_node->getInGate()->exNotifyFromPrecursor((*iter));
+
+        // Add clone
+        std::map<std::string,std::string>::iterator it=_propertyMap.find("multi_working_dir");
+        if(it != _propertyMap.end())
+        {
+          std::string working_dir_base = it->second;
+          std::ostringstream working_dir_stream;
+          working_dir_stream << working_dir_base;
+          working_dir_stream << i+1;
+          new_node->getContainer()->setProperty("workingdir", working_dir_stream.str());
+        }
+        tasks.push_back(new_node);
+      }
+    }
+  }
 }
 
 /**
  * remove port from node at edition. Ports are typed.
  */
 
-void ElementaryNode::edRemovePort(Port *port) throw(Exception)
+void ElementaryNode::edRemovePort(Port *port) throw(YACS::Exception)
 {
   DEBTRACE("ElementaryNode::edRemovePort ");
   if(port->getNode()!=this)
@@ -282,13 +538,13 @@ list<ElementaryNode *> ElementaryNode::getRecursiveConstituents() const
   return ret;
 }
 
-Node *ElementaryNode::getChildByName(const std::string& name) const throw(Exception)
+Node *ElementaryNode::getChildByName(const std::string& name) const throw(YACS::Exception)
 {
   string what("ElementaryNode does not agregate any nodes particullary node with name "); what+=name;
   throw Exception(what);
 }
 
-void ElementaryNode::checkBasicConsistency() const throw(Exception)
+void ElementaryNode::checkBasicConsistency() const throw(YACS::Exception)
 {
   DEBTRACE("ElementaryNode::checkBasicConsistency");
   list<InputPort *>::const_iterator iter;
@@ -314,8 +570,16 @@ InputPort *ElementaryNode::createInputPort(const std::string& inputPortName, Typ
  * WARNING: CHECK CASE OF BLOC: ONLY INPUT PORTS NOT INTERNALLY CONNECTED MUST BE VISIBLE.
  */
 
-InputPort *ElementaryNode::edAddInputPort(const std::string& inputPortName, TypeCode* type) throw(Exception)
+InputPort *ElementaryNode::edAddInputPort(const std::string& inputPortName, TypeCode* type) throw(YACS::Exception)
 {
+
+  // Cannot create an InputPort defined with InPropertyPort name.
+  if (inputPortName == "__InPropertyPort__Node__YACS_")
+  {
+    string what("ElementaryNode::edAddInputPort: it is forbidden to add an InputPort with the name __InPropertyPort__Node__YACS_\"");
+    throw Exception(what);
+  }
+
   InputPort *ret = 0;
   if (edCheckAddPort<InputPort, TypeCode*>(inputPortName,_setOfInputPort,type))
     {
@@ -375,7 +639,7 @@ OutputPort *ElementaryNode::createOutputPort(const std::string& outputPortName,
  * for now, publication is done the same way as input ports
  */ 
 
-OutputPort *ElementaryNode::edAddOutputPort(const std::string& outputPortName, TypeCode* type) throw(Exception)
+OutputPort *ElementaryNode::edAddOutputPort(const std::string& outputPortName, TypeCode* type) throw(YACS::Exception)
 {
   OutputPort *ret =0;
   if (edCheckAddPort<OutputPort, TypeCode*>(outputPortName,_setOfOutputPort,type))
@@ -397,7 +661,7 @@ InputDataStreamPort *ElementaryNode::createInputDataStreamPort(const std::string
   return getRuntime()->createInputDataStreamPort(inputPortDSName, this, type);
 }
 
-InputDataStreamPort *ElementaryNode::edAddInputDataStreamPort(const std::string& inputPortDSName, TypeCode* type) throw(Exception)
+InputDataStreamPort *ElementaryNode::edAddInputDataStreamPort(const std::string& inputPortDSName, TypeCode* type) throw(YACS::Exception)
 {
   InputDataStreamPort *ret = 0;
   if (edCheckAddPort<InputDataStreamPort, TypeCode*>(inputPortDSName,_setOfInputDataStreamPort,type))
@@ -414,7 +678,7 @@ OutputDataStreamPort *ElementaryNode::createOutputDataStreamPort(const std::stri
   return getRuntime()->createOutputDataStreamPort(outputPortDSName, this, type);
 }
 
-OutputDataStreamPort *ElementaryNode::edAddOutputDataStreamPort(const std::string& outputPortDSName, TypeCode* type) throw(Exception)
+OutputDataStreamPort *ElementaryNode::edAddOutputDataStreamPort(const std::string& outputPortDSName, TypeCode* type) throw(YACS::Exception)
 {
   OutputDataStreamPort *ret = 0;
   if (edCheckAddPort<OutputDataStreamPort, TypeCode*>(outputPortDSName,_setOfOutputDataStreamPort,type))
@@ -430,7 +694,7 @@ OutputDataStreamPort *ElementaryNode::edAddOutputDataStreamPort(const std::strin
  * get the input port name used by the current node (see composed nodes)
  */
 
-string ElementaryNode::getInPortName(const InPort * inPort) const throw (Exception)
+string ElementaryNode::getInPortName(const InPort * inPort) const throw(YACS::Exception)
 {
   Node *node = inPort->getNode();
   if ( node != this ) 
@@ -441,7 +705,7 @@ string ElementaryNode::getInPortName(const InPort * inPort) const throw (Excepti
   return inPort->getName();
 }
 
-string ElementaryNode::getOutPortName(const OutPort *outPort) const throw (Exception)
+string ElementaryNode::getOutPortName(const OutPort *outPort) const throw(YACS::Exception)
 {
   Node *node = outPort->getNode();
   if ( node != this ) 
@@ -572,3 +836,31 @@ void ElementaryNode::ensureLoading()
         }
     }
 }
+
+//! Calls getCoupledNodes for Task interface
+void ElementaryNode::getCoupledTasks(std::set<Task*>& coupledSet)
+{
+  getCoupledNodes(coupledSet);
+}
+
+//! Put all nodes that are coupled to this node in coupledSet
+void ElementaryNode::getCoupledNodes(std::set<Task*>& coupledSet)
+{
+  if(coupledSet.find(this) != coupledSet.end())return;
+
+  coupledSet.insert(this);
+
+  std::list<OutputDataStreamPort *>::iterator iterout;
+  for(iterout = _setOfOutputDataStreamPort.begin(); iterout != _setOfOutputDataStreamPort.end(); iterout++)
+    {
+      OutputDataStreamPort *port=(OutputDataStreamPort *)*iterout;
+      std::set<InPort *> ports=port->edSetInPort();
+      std::set<InPort *>::iterator iter;
+      for(iter=ports.begin();iter != ports.end(); iter++)
+        {
+          Node* node= (*iter)->getNode();
+          node->getCoupledNodes(coupledSet);
+        }
+    }
+}
+