From 897d4e5a488f58dfcd70ba82277bb715c5262f85 Mon Sep 17 00:00:00 2001 From: Ovidiu Mircescu Date: Mon, 24 Aug 2015 15:33:30 +0200 Subject: [PATCH] More verifications on links in parallel loops. --- src/engine/ComposedNode.cxx | 2 +- src/engine/DynParaLoop.cxx | 74 ++++++++- src/engine/DynParaLoop.hxx | 2 + src/engine/ForEachLoop.cxx | 11 +- src/engine/OptimizerLoop.cxx | 40 ++++- src/engine/OptimizerLoop.hxx | 2 + src/engine/Test/PluginOptEvTest1.cxx | 10 ++ src/engine/Test/PluginOptEvTest1.hxx | 2 + src/engine/Test/engineIntegrationTest.cxx | 48 +++++- src/engine/Test/engineIntegrationTest.hxx | 2 + src/yacsloader/Test/CMakeLists.txt | 2 + src/yacsloader/Test/YacsLoaderTest.cxx | 32 +++- src/yacsloader/Test/optim_plugin.py | 73 +++++++++ src/yacsloader/samples/foreach_init2fin.xml | 100 ++++++++++++ src/yacsloader/samples/foreach_init2work.xml | 91 +++++++++++ src/yacsloader/samples/optimizer_retro.xml | 73 +++++++++ src/yacsloader_swig/Test/CMakeLists.txt | 2 + src/yacsloader_swig/Test/optim_plugin.py | 73 +++++++++ .../Test/testValidationChecks.py | 152 ++++++++++++++++++ 19 files changed, 769 insertions(+), 22 deletions(-) create mode 100644 src/yacsloader/Test/optim_plugin.py create mode 100644 src/yacsloader/samples/foreach_init2fin.xml create mode 100644 src/yacsloader/samples/foreach_init2work.xml create mode 100644 src/yacsloader/samples/optimizer_retro.xml create mode 100644 src/yacsloader_swig/Test/optim_plugin.py create mode 100644 src/yacsloader_swig/Test/testValidationChecks.py diff --git a/src/engine/ComposedNode.cxx b/src/engine/ComposedNode.cxx index 39fa5bef8..1a4ce93ca 100644 --- a/src/engine/ComposedNode.cxx +++ b/src/engine/ComposedNode.cxx @@ -1045,7 +1045,7 @@ void ComposedNode::checkInMyDescendance(Node *nodeToTest) const throw(YACS::Exce */ ComposedNode *ComposedNode::getLowestCommonAncestor(Node *node1, Node *node2) throw(YACS::Exception) { - const char what[]="2 nodes does not share the same genealogy"; + const char what[]="The two nodes do not share the same genealogy"; if(node1==0 || node2==0) throw Exception(what); ComposedNode *temp; diff --git a/src/engine/DynParaLoop.cxx b/src/engine/DynParaLoop.cxx index ac42a27d2..e94638190 100644 --- a/src/engine/DynParaLoop.cxx +++ b/src/engine/DynParaLoop.cxx @@ -416,16 +416,29 @@ void DynParaLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const { string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance(); if(typeOfPortInstance!=InputPort::NAME) - throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop this is not possible"); + throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop is not possible"); } void DynParaLoop::buildDelegateOf(std::pair& port, InPort *finalTarget, const std::list& pointsOfView) { + std::string linkName("("); + linkName += port.first->getName()+" to "+finalTarget->getName()+")"; if(_initNode) if(isInMyDescendance(port.first->getNode())==_initNode) - throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : a link starting from init node can't leave the scope of ForEachLoop node it belongs to."); + throw Exception(std::string("Illegal link within a parallel loop: \ +a link starting from the init node can't leave the scope of the loop.") + + linkName); + + if(_finalizeNode) + if(isInMyDescendance(port.first->getNode())==_finalizeNode) + throw Exception(std::string("Illegal link within a parallel loop: \ +an output port of the finalize node can't be linked.") + + linkName); + if(port.first==&_splittedPort) - throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : splitted port must be link within the scope of ForEachLoop node it belongs to."); + throw Exception(std::string("Illegal link within a parallel loop: \ +the 'evalSamples' port must be linked within the scope of the loop.") + + linkName); } void DynParaLoop::checkCFLinks(const std::list& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const @@ -439,8 +452,6 @@ void DynParaLoop::checkCFLinks(const std::list& starts, InputPort *en if(starts.size()!=1) throw Exception(what); //ASSERT(direction) : see DynParaLoop::checkControlDependancy only 'fw' filled. - if(*(starts.begin())!=&_splittedPort) - throw Exception(what); if(alreadyFed==FREE_ST) alreadyFed=FED_ST; else if(alreadyFed==FED_ST) @@ -465,10 +476,37 @@ void DynParaLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw, LinkInfo& info) const { - if(start==&_splittedPort) fw[(ComposedNode *)this].push_back(start); - else - throw Exception("DynParaLoop::checkControlDependancy : Internal error occured - should never been called !"); +} + +void DynParaLoop::checkLinkPossibility(OutPort *start, const std::list& pointsOfViewStart, + InPort *end, const std::list& pointsOfViewEnd) throw(Exception) +{ + ComposedNode::checkLinkPossibility(start, pointsOfViewStart, end, pointsOfViewEnd); + Node * startNode = isInMyDescendance(start->getNode()); + Node * endNode = isInMyDescendance(end->getNode()); + std::string linkName("("); + linkName += start->getName()+" to "+end->getName()+")"; + + if(start == &_splittedPort && endNode != _node) + throw Exception(std::string("Illegal link within a parallel loop: \ +the 'evalSamples' port can only be connected to the working node of the loop.") + + linkName); + + if(_finalizeNode && _finalizeNode == startNode) + throw Exception(std::string("Illegal link within a parallel loop: \ +the finalize node can't be the origin of a link.") + + linkName); + + if(_initNode && _node == startNode && _initNode == endNode) + throw Exception(std::string("Illegal link within a parallel loop: \ +can't make a link from the working node to the init node.") + + linkName); + + if(_finalizeNode && _node == startNode && _finalizeNode == endNode) + throw Exception(std::string("Illegal link within a parallel loop: \ +can't make a link from the working node to the finalize node.") + + linkName); } /*! @@ -685,6 +723,26 @@ vector DynParaLoop::cloneAndPlaceNodesCoherently(const vector & treeToDup.appendTask(*iter, (*iter)->getDynClonerIfExists(this)); } } + + // Build the links between clones. + // Only the links starting from initNode are possible. + if(_initNode) + { + std::vector< std::pair > outLinks = _initNode->getSetOfLinksLeavingCurrentScope(); + std::vector< std::pair >::const_iterator it; + for(it=outLinks.begin(); it!=outLinks.end(); it++) + { + OutPort *startPort = it->first; + InPort *endPort = it->second; + Node* destNode = isInMyDescendance(endPort->getNode()); + if(destNode == _node) + edAddLink(clones[0]->getOutPort(startPort->getName()), + clones[1]->getInPort(endPort->getName())); + if(destNode == _finalizeNode) + edAddLink(clones[0]->getOutPort(startPort->getName()), + clones[2]->getInPort(endPort->getName())); + } + } DEBTRACE("Placing nodes...") vector conts=treeToDup.getAllContainers(); diff --git a/src/engine/DynParaLoop.hxx b/src/engine/DynParaLoop.hxx index 14db8b2f9..eabcec736 100644 --- a/src/engine/DynParaLoop.hxx +++ b/src/engine/DynParaLoop.hxx @@ -114,6 +114,8 @@ namespace YACS std::vector& fwCross, std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw, LinkInfo& info) const; + virtual void checkLinkPossibility(OutPort *start, const std::list& pointsOfViewStart, + InPort *end, const std::list& pointsOfViewEnd) throw(Exception); protected: void cleanDynGraph(); void prepareInputsFromOutOfScope(int branchNb); diff --git a/src/engine/ForEachLoop.cxx b/src/engine/ForEachLoop.cxx index ec235621c..b753f22e6 100644 --- a/src/engine/ForEachLoop.cxx +++ b/src/engine/ForEachLoop.cxx @@ -900,7 +900,7 @@ void ForEachLoop::buildDelegateOf(std::pair& port, InPort { TypeCodeSeq *newTc=(TypeCodeSeq *)TypeCode::sequenceTc("","",port.first->edGetType()); // The out going ports belong to the ForEachLoop, whereas - // the delegated port belong to a node child of the ForEachLoop. + // 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); @@ -1040,8 +1040,13 @@ void ForEachLoop::createOutputOutOfScopeInterceptors(int branchNb) void ForEachLoop::checkLinkPossibility(OutPort *start, const std::list& pointsOfViewStart, InPort *end, const std::list& 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 ForEachLoop::getLocalOutputPorts() const diff --git a/src/engine/OptimizerLoop.cxx b/src/engine/OptimizerLoop.cxx index ca4e27f27..df634a0fb 100644 --- a/src/engine/OptimizerLoop.cxx +++ b/src/engine/OptimizerLoop.cxx @@ -475,12 +475,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& port, InPort *finalTarget, const std::list& 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 "); @@ -506,6 +521,29 @@ void OptimizerLoop::checkCFLinks(const std::list& starts, InputPort * DynParaLoop::checkCFLinks(starts,end,alreadyFed,direction,info); } +void OptimizerLoop::checkLinkPossibility(OutPort *start, const std::list& pointsOfViewStart, + InPort *end, const std::list& pointsOfViewEnd) throw(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 or 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 and 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. diff --git a/src/engine/OptimizerLoop.hxx b/src/engine/OptimizerLoop.hxx index 21402982c..b489ee576 100644 --- a/src/engine/OptimizerLoop.hxx +++ b/src/engine/OptimizerLoop.hxx @@ -116,6 +116,8 @@ namespace YACS std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw, LinkInfo& info) const; void checkCFLinks(const std::list& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const; + void checkLinkPossibility(OutPort *start, const std::list& pointsOfViewStart, + InPort *end, const std::list& pointsOfViewEnd) throw(Exception); protected: void cleanInterceptors(); void launchMaxOfSamples(bool first); diff --git a/src/engine/Test/PluginOptEvTest1.cxx b/src/engine/Test/PluginOptEvTest1.cxx index 861f6a532..1d8233a38 100644 --- a/src/engine/Test/PluginOptEvTest1.cxx +++ b/src/engine/Test/PluginOptEvTest1.cxx @@ -47,6 +47,16 @@ TypeCode *PluginOptEvTest1::getTCForOut() const return _tcOut; } +TypeCode *PluginOptEvTest1::getTCForAlgoResult() const +{ + return _tcIn; +} + +Any * PluginOptEvTest1::getAlgoResult() +{ + return AtomAny::New(45.6); +} + void PluginOptEvTest1::parseFileToInit(const std::string& fileName) { } diff --git a/src/engine/Test/PluginOptEvTest1.hxx b/src/engine/Test/PluginOptEvTest1.hxx index 722d04338..4953a3e53 100644 --- a/src/engine/Test/PluginOptEvTest1.hxx +++ b/src/engine/Test/PluginOptEvTest1.hxx @@ -42,6 +42,8 @@ namespace YACS virtual ~PluginOptEvTest1(); TypeCode *getTCForIn() const; TypeCode *getTCForOut() const; + TypeCode *getTCForAlgoResult() const; + Any * getAlgoResult(); void parseFileToInit(const std::string& fileName); void start(); void takeDecision(); diff --git a/src/engine/Test/engineIntegrationTest.cxx b/src/engine/Test/engineIntegrationTest.cxx index 79350f50e..801384cd6 100644 --- a/src/engine/Test/engineIntegrationTest.cxx +++ b/src/engine/Test/engineIntegrationTest.cxx @@ -2583,9 +2583,9 @@ void EngineIntegrationTest::testForOptimizerLoop1() InputPort *i1=n1->edAddInputPort("i1",Runtime::_tc_double); OutputPort *o1=n1->edAddOutputPort("o1",Runtime::_tc_double); graph->edAddLink(opt->edGetSamplePort(),i1); - InputPort *i2=n2->edAddInputPort("i2",Runtime::_tc_double); + InputPort *i2=n2->edAddInputPort("i2",opt->edGetAlgoResultPort()->edGetType()); OutputPort *o2_1=n2->edAddOutputPort("o1",Runtime::_tc_double); - graph->edAddLink(o1,i2); + graph->edAddLink(opt->edGetAlgoResultPort(),i2); graph->edAddLink(n1->edGetNbOfInputsOutputPort(),opt->edGetPortForOutPool()); opt->edGetNbOfBranchesPort()->edInit(2); opt->edGetAlgoInitPort()->edInit("toto"); @@ -2635,9 +2635,9 @@ void EngineIntegrationTest::testForOptimizerLoop2() InputPort *i1=n1->edAddInputPort("i1",Runtime::_tc_double); OutputPort *o1=n1->edAddOutputPort("o1",Runtime::_tc_double); graph->edAddLink(opt->edGetSamplePort(),i1); - InputPort *i2=n2->edAddInputPort("i2",Runtime::_tc_double); + InputPort *i2=n2->edAddInputPort("i2",opt->edGetAlgoResultPort()->edGetType()); OutputPort *o2_1=n2->edAddOutputPort("o1",Runtime::_tc_double); - graph->edAddLink(o1,i2); + graph->edAddLink(opt->edGetAlgoResultPort(),i2); graph->edAddLink(n1->edGetNbOfInputsOutputPort(),opt->edGetPortForOutPool()); opt->edGetNbOfBranchesPort()->edInit(2); opt->edGetAlgoInitPort()->edInit("toto"); @@ -2667,6 +2667,46 @@ void EngineIntegrationTest::testForOptimizerLoop2() delete clone; } +/*! + * Test of illegal links within an OptimizerLoop. + */ +void EngineIntegrationTest::testForOptimizerLoop3() +{ + LinkInfo info(LinkInfo::ALL_DONT_STOP); + Bloc *graph=new Bloc("Global"); + OptimizerLoop *opt=new OptimizerLoop("myOptWthAlgSync","libPluginOptEvTest1","PluginOptEvTest1Factory",true); + graph->edAddChild(opt); + ToyNode *n1=new ToyNode("T1"); + ToyNode *n2=new ToyNode("T2"); + Bloc *bloc=new Bloc("Bloc"); + graph->edAddChild(n2); + graph->edAddCFLink(opt,n2); + opt->edSetNode(bloc); + bloc->edAddChild(n1); + InputPort *i1=n1->edAddInputPort("i1",Runtime::_tc_double); + OutputPort *o1=n1->edAddOutputPort("o1",Runtime::_tc_double); + InputPort *i2=n2->edAddInputPort("i2",opt->edGetAlgoResultPort()->edGetType()); + try + { + graph->edAddLink(opt->edGetAlgoResultPort(),i1); + CPPUNIT_FAIL("Construction of an illegal link: the result port linked to a node inside the OptimizerLoop."); + } + catch(Exception& e) + { + } + + try + { + graph->edAddLink(o1,i2); + CPPUNIT_FAIL("Construction of an illegal link: a node inside the loop linked to a node outside the OptimizerLoop."); + } + catch(Exception& e) + { + } + + delete graph; +} + /*! * Test to check that in for compil-time known connectivity of a graph, deployment calculation is OK. */ diff --git a/src/engine/Test/engineIntegrationTest.hxx b/src/engine/Test/engineIntegrationTest.hxx index 75030cb6f..b075d6248 100644 --- a/src/engine/Test/engineIntegrationTest.hxx +++ b/src/engine/Test/engineIntegrationTest.hxx @@ -62,6 +62,7 @@ namespace YACS CPPUNIT_TEST( testForEachLoop5 ); CPPUNIT_TEST( testForOptimizerLoop1 ); CPPUNIT_TEST( testForOptimizerLoop2 ); + CPPUNIT_TEST( testForOptimizerLoop3 ); CPPUNIT_TEST( testForDeployment1 ); CPPUNIT_TEST( testForDeployment2 ); CPPUNIT_TEST( testForCheckConsistency1 ); @@ -103,6 +104,7 @@ namespace YACS void testForEachLoop5(); void testForOptimizerLoop1(); void testForOptimizerLoop2(); + void testForOptimizerLoop3(); void testForDeployment1(); void testForDeployment2(); void testForCheckConsistency1(); diff --git a/src/yacsloader/Test/CMakeLists.txt b/src/yacsloader/Test/CMakeLists.txt index 21dbcdb23..8c5f73d14 100644 --- a/src/yacsloader/Test/CMakeLists.txt +++ b/src/yacsloader/Test/CMakeLists.txt @@ -131,6 +131,8 @@ IF(NOT WIN32) INSTALL(FILES CTestTestfileInstall.cmake DESTINATION ${LOCAL_TEST_DIR} RENAME CTestTestfile.cmake) + INSTALL(FILES optim_plugin.py + DESTINATION ${LOCAL_TEST_DIR}) INSTALL(PROGRAMS runYacsLoaderTest.sh ${CMAKE_CURRENT_BINARY_DIR}/xmlrun.sh DESTINATION ${LOCAL_TEST_DIR}) INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E create_symlink diff --git a/src/yacsloader/Test/YacsLoaderTest.cxx b/src/yacsloader/Test/YacsLoaderTest.cxx index 115030034..0b9890899 100644 --- a/src/yacsloader/Test/YacsLoaderTest.cxx +++ b/src/yacsloader/Test/YacsLoaderTest.cxx @@ -647,33 +647,50 @@ void YacsLoaderTest::foreachs() ret = driverTest(p, "samples/foreach1.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach1.xml", ret == 0); CPPUNIT_ASSERT_MESSAGE("Schema: foreach1.xml", p->getEffectiveState() == YACS::DONE); + delete p; ret = driverTest(p, "samples/foreach2.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach2.xml", ret == 0); CPPUNIT_ASSERT_MESSAGE("Schema: foreach2.xml", p->getEffectiveState() == YACS::DONE ); + delete p; ret = driverTest(p, "samples/foreach3.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach3.xml", ret == 1); + delete p; ret = driverTest(p, "samples/foreach4.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach4.xml", ret == 0); CPPUNIT_ASSERT_MESSAGE("Schema: foreach4.xml", p->getEffectiveState() == YACS::DONE ); + delete p; ret = driverTest(p, "samples/foreach5.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach5.xml", ret == 0); CPPUNIT_ASSERT_MESSAGE("Schema: foreach5.xml", p->getEffectiveState() == YACS::DONE ); + delete p; ret = driverTest(p, "samples/foreach6.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach6.xml", ret == 0); CPPUNIT_ASSERT_MESSAGE("Schema: foreach6.xml", p->getEffectiveState() == YACS::DONE ); + delete p; ret = driverTest(p, "samples/foreach8.xml"); CPPUNIT_ASSERT_MESSAGE("Schema: foreach8.xml", ret == 0); CPPUNIT_ASSERT_MESSAGE("Schema: foreach8.xml", p->getEffectiveState() == YACS::DONE ); + delete p; + ret = driverTest(p, "samples/foreach_init2fin.xml"); + CPPUNIT_ASSERT_MESSAGE("Schema: foreach_init2fin.xml", ret == 0); + CPPUNIT_ASSERT_MESSAGE("Schema: foreach_init2fin.xml", p->getEffectiveState() == YACS::DONE ); + delete p; + ret = driverTest(p, "samples/foreach_init2work.xml"); + CPPUNIT_ASSERT_MESSAGE("Schema: foreach_init2work.xml", ret == 0); + CPPUNIT_ASSERT_MESSAGE("Schema: foreach_init2work.xml", p->getEffectiveState() == YACS::DONE ); + CPPUNIT_ASSERT_EQUAL(p->getOutputPort("PostProc.r")->getAsString(), std::string("108")); + delete p; if(getenv("GEOM_ROOT_DIR")) { std::string geomdir(getenv("GEOM_ROOT_DIR")); geomdir=geomdir+"/share/salome/resources/geom"; if(access(geomdir.c_str(),F_OK) == 0) - { - ret = driverTest(p, "samples/foreach7.xml"); //needs GEOM_Superv component - CPPUNIT_ASSERT_MESSAGE("Schema: foreach7.xml", ret == 0); - CPPUNIT_ASSERT_MESSAGE("Schema: foreach7.xml", p->getEffectiveState() == YACS::DONE ); - } + { + ret = driverTest(p, "samples/foreach7.xml"); //needs GEOM_Superv component + CPPUNIT_ASSERT_MESSAGE("Schema: foreach7.xml", ret == 0); + CPPUNIT_ASSERT_MESSAGE("Schema: foreach7.xml", p->getEffectiveState() == YACS::DONE ); + delete p; + } } } @@ -806,6 +823,11 @@ void YacsLoaderTest::optimizers() CPPUNIT_ASSERT(ret == 0); CPPUNIT_ASSERT(p->getEffectiveState() == YACS::DONE ); delete p; + + ret = driverTest(p, "samples/optimizer_retro.xml"); + CPPUNIT_ASSERT(ret == 0); + CPPUNIT_ASSERT(p->getEffectiveState() == YACS::DONE ); + delete p; } void YacsLoaderTest::pyremotes() diff --git a/src/yacsloader/Test/optim_plugin.py b/src/yacsloader/Test/optim_plugin.py new file mode 100644 index 000000000..d43d070b3 --- /dev/null +++ b/src/yacsloader/Test/optim_plugin.py @@ -0,0 +1,73 @@ +import SALOMERuntime + +class myalgosync(SALOMERuntime.OptimizerAlgSync): + def __init__(self): + SALOMERuntime.OptimizerAlgSync.__init__(self, None) + r=SALOMERuntime.getSALOMERuntime() + self.tin=r.getTypeCode("int") + self.tout=r.getTypeCode("int") + self.tAlgoInit=r.getTypeCode("int") + self.tAlgoResult=r.getTypeCode("int") + + def setPool(self,pool): + """Must be implemented to set the pool""" + self.pool=pool + + def getTCForIn(self): + """return typecode of type expected as Input the internal node """ + return self.tin + + def getTCForOut(self): + """return typecode of type expected as Output the internal node""" + return self.tout + + def getTCForAlgoInit(self): + """return typecode of type expected as input for initialize """ + return self.tAlgoInit + + def getTCForAlgoResult(self): + """return typecode of type expected as output of the algorithm """ + return self.tAlgoResult + + def initialize(self,input): + """Optional method called on initialization. + The type of "input" is returned by "getTCForAlgoInit" + """ + print "Algo initialize, input = ", input.getIntValue() + + def start(self): + """Start to fill the pool with samples to evaluate.""" + print "Algo start " + self.iter=0 + # pushInSample(id, value) + self.pool.pushInSample(self.iter, 1) + + def takeDecision(self): + """ This method is called each time a sample has been evaluated. It can + either add new samples to evaluate in the pool, do nothing (wait for + more samples), or empty the pool to finish the evaluation. + """ + currentId=self.pool.getCurrentId() + valIn = self.pool.getCurrentInSample().getIntValue() + valOut = self.pool.getCurrentOutSample().getIntValue() + print "Algo takeDecision currentId=%s, valIn=%s, valOut=%s" % (currentId, valIn, valOut) + + self.iter=self.iter+1 + if self.iter < 3: + # continue + nextSample = valIn + 1 + self.pool.pushInSample(self.iter, nextSample) + + def finish(self): + """Optional method called when the algorithm has finished, successfully + or not, to perform any necessary clean up.""" + print "Algo finish" + self.pool.destroyAll() + + def getAlgoResult(self): + """return the result of the algorithm. + The object returned is of type indicated by getTCForAlgoResult. + """ + return 42 + + diff --git a/src/yacsloader/samples/foreach_init2fin.xml b/src/yacsloader/samples/foreach_init2fin.xml new file mode 100644 index 000000000..42fcd80d5 --- /dev/null +++ b/src/yacsloader/samples/foreach_init2fin.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + initScript o1 + finalizeScript i2 + + + + + + + + ForEachLoop PostProc + + ForEachLoop evalSamples + ForEachLoop.Work elem + + + ForEachLoop.Work res + PostProc i5 + + + ForEachLoopnbBranches + 4 + + + ForEachLoopSmplsCollection + +1 +2 +3 +4 +5 +6 +7 +8 +9 + + + diff --git a/src/yacsloader/samples/foreach_init2work.xml b/src/yacsloader/samples/foreach_init2work.xml new file mode 100644 index 000000000..2d6c36740 --- /dev/null +++ b/src/yacsloader/samples/foreach_init2work.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + initScript o1 + work i3 + + + + + + + + + ForEachLoop PostProc + + ForEachLoop evalSamples + ForEachLoop.work i1 + + + ForEachLoop.work o2 + PostProc i5 + + + ForEachLoopnbBranches + 4 + + + ForEachLoopSmplsCollection + +1 +2 +3 +4 +5 +6 +7 +8 +9 + + + diff --git a/src/yacsloader/samples/optimizer_retro.xml b/src/yacsloader/samples/optimizer_retro.xml new file mode 100644 index 000000000..22a825533 --- /dev/null +++ b/src/yacsloader/samples/optimizer_retro.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OptimizerLoop2 evalSamples + OptimizerLoop2.PyScript3 i5 + + + OptimizerLoop2 algoResults + OptimizerLoop2 algoInit + + + OptimizerLoop2.PyScript3 o4 + OptimizerLoop2 evalResults + + + + + + + + PyScript0 ForLoop1 + + PyScript0 o1 + ForLoop1.OptimizerLoop2 algoInit + + + ForLoop1nsteps + 2 + + + ForLoop1.OptimizerLoop2nbBranches + 3 + + diff --git a/src/yacsloader_swig/Test/CMakeLists.txt b/src/yacsloader_swig/Test/CMakeLists.txt index 6ac0e5552..4af457d6f 100644 --- a/src/yacsloader_swig/Test/CMakeLists.txt +++ b/src/yacsloader_swig/Test/CMakeLists.txt @@ -41,6 +41,8 @@ IF(NOT WIN32) testResume.py testSave.py testSaveLoadRun.py + optim_plugin.py + testValidationChecks.py ) INSTALL(FILES ${LOCAL_TEST_FILES} DESTINATION ${LOCAL_TEST_DIR}) diff --git a/src/yacsloader_swig/Test/optim_plugin.py b/src/yacsloader_swig/Test/optim_plugin.py new file mode 100644 index 000000000..d43d070b3 --- /dev/null +++ b/src/yacsloader_swig/Test/optim_plugin.py @@ -0,0 +1,73 @@ +import SALOMERuntime + +class myalgosync(SALOMERuntime.OptimizerAlgSync): + def __init__(self): + SALOMERuntime.OptimizerAlgSync.__init__(self, None) + r=SALOMERuntime.getSALOMERuntime() + self.tin=r.getTypeCode("int") + self.tout=r.getTypeCode("int") + self.tAlgoInit=r.getTypeCode("int") + self.tAlgoResult=r.getTypeCode("int") + + def setPool(self,pool): + """Must be implemented to set the pool""" + self.pool=pool + + def getTCForIn(self): + """return typecode of type expected as Input the internal node """ + return self.tin + + def getTCForOut(self): + """return typecode of type expected as Output the internal node""" + return self.tout + + def getTCForAlgoInit(self): + """return typecode of type expected as input for initialize """ + return self.tAlgoInit + + def getTCForAlgoResult(self): + """return typecode of type expected as output of the algorithm """ + return self.tAlgoResult + + def initialize(self,input): + """Optional method called on initialization. + The type of "input" is returned by "getTCForAlgoInit" + """ + print "Algo initialize, input = ", input.getIntValue() + + def start(self): + """Start to fill the pool with samples to evaluate.""" + print "Algo start " + self.iter=0 + # pushInSample(id, value) + self.pool.pushInSample(self.iter, 1) + + def takeDecision(self): + """ This method is called each time a sample has been evaluated. It can + either add new samples to evaluate in the pool, do nothing (wait for + more samples), or empty the pool to finish the evaluation. + """ + currentId=self.pool.getCurrentId() + valIn = self.pool.getCurrentInSample().getIntValue() + valOut = self.pool.getCurrentOutSample().getIntValue() + print "Algo takeDecision currentId=%s, valIn=%s, valOut=%s" % (currentId, valIn, valOut) + + self.iter=self.iter+1 + if self.iter < 3: + # continue + nextSample = valIn + 1 + self.pool.pushInSample(self.iter, nextSample) + + def finish(self): + """Optional method called when the algorithm has finished, successfully + or not, to perform any necessary clean up.""" + print "Algo finish" + self.pool.destroyAll() + + def getAlgoResult(self): + """return the result of the algorithm. + The object returned is of type indicated by getTCForAlgoResult. + """ + return 42 + + diff --git a/src/yacsloader_swig/Test/testValidationChecks.py b/src/yacsloader_swig/Test/testValidationChecks.py new file mode 100644 index 000000000..c0eba53d2 --- /dev/null +++ b/src/yacsloader_swig/Test/testValidationChecks.py @@ -0,0 +1,152 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest +import os +import sys +import pilot +import SALOMERuntime + +class TestValidationChecks(unittest.TestCase): + def test_foreach_links(self): + """ Test tha add of illegal links within a foreach loop. + """ + SALOMERuntime.RuntimeSALOME_setRuntime() + runtime = pilot.getRuntime() + + schema = runtime.createProc("schema") + ti=schema.getTypeCode("int") + tiset = schema.createSequenceTc("", "seqint", ti) + + nw = runtime.createScriptNode("", "Worker") + nw.edAddInputPort("i1", ti) + nw.edAddInputPort("i2", ti) + nw.edAddOutputPort("o1", ti) + nw.setScript("o1=i1+i2") + + ni = runtime.createScriptNode("", "Init") + ni.edAddInputPort("ii", ti) + ni.edAddOutputPort("oi", ti) + ni.setScript("o1=ii") + + nf = runtime.createScriptNode("", "Fin") + nf.edAddInputPort("ifin", ti) + nf.edAddOutputPort("ofin", ti) + nf.setScript("ofin=ifin") + + npre = runtime.createScriptNode("", "PreProc") + npre.edAddOutputPort("opre", ti) + npre.setScript("opre=5") + + npost = runtime.createScriptNode("", "PostProc") + npost.edAddInputPort("ipost", ti) + + fe = runtime.createForEachLoop("ForEach", ti) + fe.getInputPort("nbBranches").edInitPy(2) + fe.getInputPort("SmplsCollection").edInitPy([1, 2, 3, 4]) + fe.edSetNode(nw) + fe.edSetInitNode(ni) + fe.edSetFinalizeNode(nf) + + schema.edAddChild(fe) + schema.edAddChild(npost) + + def excpTest(op, ip): + self.assertRaises(ValueError, schema.edAddLink, op, ip) + pass + + # ForEachLoop tests + excpTest(fe.getOutputPort("evalSamples"), npost.getInputPort("ipost")) + excpTest(fe.getOutputPort("evalSamples"), ni.getInputPort("ii")) + excpTest(fe.getOutputPort("evalSamples"), nf.getInputPort("ifin")) + excpTest(fe.getOutputPort("evalSamples"), fe.getInputPort("nbBranches")) + excpTest(ni.getOutputPort("oi"), fe.getInputPort("nbBranches")) + excpTest(nw.getOutputPort("o1"), fe.getInputPort("nbBranches")) + excpTest(nf.getOutputPort("ofin"), fe.getInputPort("nbBranches")) + excpTest(fe.getOutputPort("evalSamples"), fe.getInputPort("SmplsCollection")) + excpTest(ni.getOutputPort("oi"), fe.getInputPort("SmplsCollection")) + excpTest(nw.getOutputPort("o1"), fe.getInputPort("SmplsCollection")) + excpTest(nf.getOutputPort("ofin"), fe.getInputPort("SmplsCollection")) + excpTest(nw.getOutputPort("o1"), nf.getInputPort("ifin")) + excpTest(nw.getOutputPort("o1"), ni.getInputPort("ii")) + excpTest(ni.getOutputPort("oi"), npost.getInputPort("ipost")) + excpTest(nf.getOutputPort("ofin"), npost.getInputPort("ipost")) + excpTest(nf.getOutputPort("ofin"), ni.getInputPort("ii")) + + def test_optim_links(self): + """ Test tha add of illegal links within an optimization loop. + """ + SALOMERuntime.RuntimeSALOME_setRuntime() + runtime = pilot.getRuntime() + # + schema = runtime.createProc("schema") + ti=schema.getTypeCode("int") + # + nw = runtime.createScriptNode("", "Worker") + nw.edAddInputPort("i1", ti) + nw.edAddInputPort("i2", ti) + nw.edAddOutputPort("o1", ti) + nw.setScript("o1=i1+i2") + # + ni = runtime.createScriptNode("", "Init") + ni.edAddInputPort("ii", ti) + ni.edAddOutputPort("oi", ti) + ni.setScript("o1=ii") + # + nf = runtime.createScriptNode("", "Fin") + nf.edAddInputPort("ifin", ti) + nf.edAddOutputPort("ofin", ti) + nf.setScript("ofin=ifin") + # + npre = runtime.createScriptNode("", "PreProc") + npre.edAddOutputPort("opre", ti) + npre.setScript("opre=5") + # + npost = runtime.createScriptNode("", "PostProc") + npost.edAddInputPort("ipost", ti) + # + fe = runtime.createOptimizerLoop("OptLoop", "optim_plugin.py","myalgosync",True) + fe.getInputPort("nbBranches").edInitPy(2) + fe.getInputPort("algoInit").edInitPy(7) + fe.edSetNode(nw) + fe.edSetInitNode(ni) + fe.edSetFinalizeNode(nf) + # + schema.edAddChild(fe) + schema.edAddChild(npost) + schema.edAddChild(npre) + + def excpTest(op, ip): + self.assertRaises(ValueError, schema.edAddLink, op, ip) + pass + + # ForEachLoop tests + excpTest(fe.getOutputPort("evalSamples"), npost.getInputPort("ipost")) + excpTest(fe.getOutputPort("evalSamples"), ni.getInputPort("ii")) + excpTest(fe.getOutputPort("evalSamples"), nf.getInputPort("ifin")) + excpTest(fe.getOutputPort("evalSamples"), fe.getInputPort("nbBranches")) + excpTest(nw.getOutputPort("o1"), nf.getInputPort("ifin")) + excpTest(nw.getOutputPort("o1"), ni.getInputPort("ii")) + excpTest(ni.getOutputPort("oi"), npost.getInputPort("ipost")) + excpTest(nf.getOutputPort("ofin"), npost.getInputPort("ipost")) + excpTest(nf.getOutputPort("ofin"), ni.getInputPort("ii")) + # Specific OptimizerLoop tests + excpTest(nw.getOutputPort("o1"), fe.getInputPort("nbBranches")) + excpTest(ni.getOutputPort("oi"), fe.getInputPort("nbBranches")) + excpTest(nf.getOutputPort("ofin"), fe.getInputPort("nbBranches")) + excpTest(nw.getOutputPort("o1"), fe.getInputPort("algoInit")) + excpTest(ni.getOutputPort("oi"), fe.getInputPort("algoInit")) + excpTest(nf.getOutputPort("ofin"), fe.getInputPort("algoInit")) + excpTest(ni.getOutputPort("oi"), fe.getInputPort("evalResults")) + excpTest(nf.getOutputPort("ofin"), fe.getInputPort("evalResults")) + excpTest(npre.getOutputPort("opre"), fe.getInputPort("evalResults")) + excpTest(fe.getOutputPort("evalSamples"), fe.getInputPort("algoInit")) + excpTest(fe.getOutputPort("algoResults"), nw.getInputPort("i1")) + excpTest(fe.getOutputPort("algoResults"), ni.getInputPort("ii")) + excpTest(fe.getOutputPort("algoResults"), nf.getInputPort("ifin")) + excpTest(nw.getOutputPort("o1"), npost.getInputPort("ipost")) + excpTest(ni.getOutputPort("oi"), npost.getInputPort("ipost")) + excpTest(nf.getOutputPort("ofin"), npost.getInputPort("ipost")) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file -- 2.39.2