--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(idefix)
+
+SET (CMAKE_CXX_STANDARD 11)
+ENABLE_TESTING()
+SET(BUILD_SHARED_LIBS TRUE)
+
+SET(CONFIGURATION_ROOT_DIR $ENV{CONFIGURATION_ROOT_DIR} CACHE PATH "Path to the Salome CMake configuration files")
+IF(EXISTS ${CONFIGURATION_ROOT_DIR})
+ LIST(APPEND CMAKE_MODULE_PATH "${CONFIGURATION_ROOT_DIR}/cmake")
+ INCLUDE(SalomeMacros)
+ELSE()
+ MESSAGE(FATAL_ERROR "We absolutely need the Salome CMake configuration files, please define CONFIGURATION_ROOT_DIR !"
+)
+ENDIF()
+
+SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to Salome KERNEL")
+IF( EXISTS ${KERNEL_ROOT_DIR} )
+ LIST(APPEND CMAKE_MODULE_PATH "${KERNEL_ROOT_DIR}/salome_adm/cmake_files")
+ELSE()
+ MESSAGE(FATAL_ERROR "We absolutely need Salome KERNEL, please define KERNEL_ROOT_DIR")
+ENDIF()
+FIND_PACKAGE(SalomeKERNEL REQUIRED)
+ADD_DEFINITIONS(${KERNEL_DEFINITIONS} )
+INCLUDE_DIRECTORIES(${KERNEL_INCLUDE_DIRS})
+
+SET(YACS_ROOT_DIR $ENV{YACS_ROOT_DIR} CACHE PATH "Path to Salome YACS")
+IF( EXISTS ${YACS_ROOT_DIR} )
+ LIST(APPEND CMAKE_MODULE_PATH "${YACS_ROOT_DIR}/salome_adm/cmake_files")
+ELSE()
+ MESSAGE(FATAL_ERROR "We absolutely need Salome YACS, please define YACS_ROOT_DIR")
+ENDIF()
+FIND_PACKAGE(SalomeYACS REQUIRED)
+ADD_DEFINITIONS(${YACS_DEFINITIONS})
+INCLUDE_DIRECTORIES(${YACS_INCLUDE_DIRS})
+
+SET(PY2CPP_ROOT_DIR $ENV{PY2CPP_ROOT_DIR} CACHE PATH "Path to py2cpp")
+IF( EXISTS ${PY2CPP_ROOT_DIR} )
+ LIST(APPEND CMAKE_MODULE_PATH "${PY2CPP_ROOT_DIR}/lib/cmake/py2cpp")
+ELSE()
+ MESSAGE(FATAL_ERROR "We absolutely need py2cpp, please define PY2CPP_ROOT_DIR")
+ENDIF()
+FIND_PACKAGE(Py2cpp REQUIRED)
+
+SET(SALOME_INSTALL_PYTHON "${SALOME_INSTALL_PYTHON}" CACHE PATH "Install Python files")
+
+ADD_SUBDIRECTORY(src)
--- /dev/null
+ADD_SUBDIRECTORY(cpp)
+ADD_SUBDIRECTORY(pydefx)
--- /dev/null
+ADD_DEFINITIONS(${YACS_DEFINITIONS})
+INCLUDE_DIRECTORIES(${YACS_INCLUDE_DIRS})
+
+SET(ydefx_SOURCES
+ PyStudyFunction.cxx
+ JobParametersProxy.cxx
+ Exceptions.cxx
+ MonoPyJob.cxx
+)
+
+SET(ydefx_HEADERS
+ PyStudyFunction.hxx
+ StudyFunction.hxx
+ JobParametersProxy.hxx
+ Sample.hxx
+ SamplePyConversions.hxx
+ Exceptions.hxx
+ MonoPyJob.hxx
+ TMonoPyJob.hxx
+ Job.hxx
+ Launcher.hxx
+)
+
+SET(ydefx_LINK
+ py2yacslib
+ py2cpp
+)
+
+ADD_LIBRARY(ydefx ${ydefx_SOURCES})
+TARGET_LINK_LIBRARIES(ydefx ${ydefx_LINK})
+TARGET_INCLUDE_DIRECTORIES(ydefx PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+ $<INSTALL_INTERFACE:include>)
+
+INSTALL(TARGETS ydefx DESTINATION lib)
+INSTALL(TARGETS ydefx EXPORT Findydefx LIBRARY DESTINATION lib)
+INSTALL(FILES ${ydefx_HEADERS} DESTINATION include/ydefx)
+INSTALL(EXPORT Findydefx DESTINATION lib/cmake/ydefx)
+
+ADD_SUBDIRECTORY(Test)
--- /dev/null
+#include "Exceptions.hxx"
+
+namespace ydefx
+{
+
+Exception::Exception(const std::string& message)
+: std::exception()
+, _message(message)
+{
+}
+
+const char* Exception::what() const noexcept
+{
+ return _message.c_str();
+}
+}
--- /dev/null
+#ifndef YDEFX_EXCEPTIONS_HXX
+#define YDEFX_EXCEPTIONS_HXX
+#include <string>
+
+namespace ydefx
+{
+class Exception:public std::exception
+{
+public:
+ Exception(const std::string& message);
+ virtual const char* what() const noexcept;
+private:
+ std::string _message;
+};
+
+}
+
+#endif // YDEFX_EXCEPTIONS_HXX
--- /dev/null
+#ifndef YDEFX_JOB_H
+#define YDEFX_JOB_H
+#include <string>
+
+namespace ydefx
+{
+
+class Job
+{
+public:
+ virtual ~Job(){}
+ virtual std::string state()=0;
+ virtual double progress()=0;
+ virtual std::string dump()=0;
+ virtual bool launch()=0; // return false when it fails
+ virtual bool fetch()=0; // return false when it fails
+ virtual const std::string& lastError()=0;
+ virtual bool wait()=0; // Wait for the end of the job. Return false when it fails.
+ virtual void configureWaitDelay(int seconds)=0;
+};
+}
+#endif // YDEFX_JOB_H
--- /dev/null
+#include "JobParametersProxy.hxx"
+#include "Exceptions.hxx"
+#include <py2cpp/py2cpp.hxx>
+
+PyObject * py2cpp::toPy(const ydefx::JobParametersProxy& jp)
+{
+ PyObject * result = jp._pyParameters.get();
+ Py_IncRef(result);
+ return result;
+}
+
+namespace ydefx
+{
+
+JobParametersProxy::JobParametersProxy()
+: _pyParameters(nullptr)
+{
+ py2cpp::PyFunction objConstructor;
+ objConstructor.loadExp("pydefx", "Parameters");
+ _pyParameters = objConstructor();
+}
+
+
+std::string
+JobParametersProxy::getAttrString(const std::string& attributeName)const
+{
+ std::string result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("salome_parameters")
+ .getAttr(attributeName);
+ return result;
+}
+
+void
+JobParametersProxy::setAttr(const std::string& attributeName,
+ const std::string& value)
+{
+ _pyParameters.getAttr("salome_parameters")
+ .setAttr(attributeName, py2cpp::toPyPtr(value));
+}
+
+int JobParametersProxy::getResAttr(const std::string& attributeName)const
+{
+ int result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("salome_parameters")
+ .getAttr("resource_required")
+ .getAttr(attributeName);
+ return result;
+}
+
+void JobParametersProxy::setResAttr(const std::string& attributeName, int value)
+{
+ _pyParameters.getAttr("salome_parameters")
+ .getAttr("resource_required")
+ .setAttr(attributeName, py2cpp::toPyPtr(value));
+}
+
+std::string JobParametersProxy::job_name()const
+{
+ return getAttrString("job_name");
+}
+
+void JobParametersProxy::job_name(const std::string& v)
+{
+ setAttr("job_name", v);
+}
+
+std::string JobParametersProxy::job_type()const
+{
+ return getAttrString("job_type");
+}
+
+void JobParametersProxy::job_type(const std::string& v)
+{
+ setAttr("job_type", v);
+}
+
+std::string JobParametersProxy::job_file()const
+{
+ return getAttrString("job_file");
+}
+
+void JobParametersProxy::job_file(const std::string& v)
+{
+ setAttr("job_file", v);
+}
+
+std::string JobParametersProxy::pre_command()const
+{
+ return getAttrString("pre_command");
+}
+
+void JobParametersProxy::pre_command(const std::string& v)
+{
+ setAttr("pre_command", v);
+}
+
+std::string JobParametersProxy::env_file()const
+{
+ return getAttrString("env_file");
+}
+
+void JobParametersProxy::env_file(const std::string& v)
+{
+ setAttr("env_file", v);
+}
+
+std::list<std::string> JobParametersProxy::in_files()const
+{
+ std::list<std::string> result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("salome_parameters")
+ .getAttr("in_files");
+ return result;
+}
+
+void JobParametersProxy::add_in_files(const std::list<std::string>& pathList)
+{
+ std::list<std::string> newList = in_files();
+ newList.insert(newList.end(), pathList.begin(), pathList.end());
+ in_files(newList);
+}
+
+void JobParametersProxy::in_files(const std::list<std::string>& pathList)
+{
+ _pyParameters.getAttr("salome_parameters")
+ .setAttr("in_files", py2cpp::toPyPtr(pathList));
+}
+
+std::string JobParametersProxy::work_directory()const
+{
+ return getAttrString("work_directory");
+}
+
+void JobParametersProxy::work_directory(const std::string& v)
+{
+ setAttr("work_directory", v);
+}
+
+std::string JobParametersProxy::local_directory()const
+{
+ return getAttrString("local_directory");
+}
+
+void JobParametersProxy::local_directory(const std::string& v)
+{
+ setAttr("local_directory", v);
+}
+
+std::string JobParametersProxy::result_directory()const
+{
+ return getAttrString("result_directory");
+}
+
+void JobParametersProxy::result_directory(const std::string& v)
+{
+ setAttr("result_directory", v);
+}
+
+std::string JobParametersProxy::maximum_duration()const
+{
+ return getAttrString("maximum_duration");
+}
+
+void JobParametersProxy::maximum_duration(const std::string& v)
+{
+ setAttr("maximum_duration", v);
+}
+
+// ResourceParameters
+std::string JobParametersProxy::resource_name()const
+{
+ std::string result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("salome_parameters")
+ .getAttr("resource_required")
+ .getAttr("name");
+ return result;
+}
+
+void JobParametersProxy::resource_name(const std::string& name)
+{
+ _pyParameters.getAttr("salome_parameters")
+ .getAttr("resource_required")
+ .setAttr("name", py2cpp::toPyPtr(name));
+}
+
+int JobParametersProxy::nb_proc()const
+{
+ return getResAttr("nb_proc");
+}
+
+void JobParametersProxy::nb_proc(int v)
+{
+ setResAttr("nb_proc", v);
+}
+
+int JobParametersProxy::mem_mb()const
+{
+ return getResAttr("mem_mb");
+}
+
+void JobParametersProxy::mem_mb(int v)
+{
+ setResAttr("mem_mb", v);
+}
+
+int JobParametersProxy::nb_node()const
+{
+ return getResAttr("nb_node");
+}
+
+void JobParametersProxy::nb_node(int v)
+{
+ setResAttr("nb_node", v);
+}
+
+int JobParametersProxy::nb_proc_per_node()const
+{
+ return getResAttr("nb_proc_per_node");
+}
+
+void JobParametersProxy::nb_proc_per_node(int v)
+{
+ setResAttr("nb_proc_per_node", v);
+}
+
+std::string JobParametersProxy::queue()const
+{
+ return getAttrString("queue");
+}
+
+void JobParametersProxy::queue(const std::string& v)
+{
+ setAttr("queue", v);
+}
+
+std::string JobParametersProxy::partition()const
+{
+ return getAttrString("partition");
+}
+
+void JobParametersProxy::partition(const std::string& v)
+{
+ setAttr("partition", v);
+}
+
+bool JobParametersProxy::exclusive()const
+{
+ bool result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("salome_parameters")
+ .getAttr("exclusive");
+ return result;
+}
+
+void JobParametersProxy::exclusive(bool v)
+{
+ _pyParameters.getAttr("salome_parameters")
+ .setAttr("exclusive", py2cpp::toPyPtr(v));
+}
+
+unsigned int JobParametersProxy::mem_per_cpu()const
+{
+ int result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("salome_parameters")
+ .getAttr("mem_per_cpu");
+ if(result < 0)
+ result = 0;
+ return result;
+}
+
+void JobParametersProxy::mem_per_cpu(unsigned int v)
+{
+ _pyParameters.getAttr("salome_parameters")
+ .setAttr("mem_per_cpu", py2cpp::toPyPtr(v));
+}
+
+std::string JobParametersProxy::wckey()const
+{
+ return getAttrString("wckey");
+}
+
+void JobParametersProxy::wckey(const std::string& v)
+{
+ setAttr("wckey", v);
+}
+
+std::string JobParametersProxy::extra_params()const
+{
+ return getAttrString("extra_params");
+}
+
+void JobParametersProxy::extra_params(const std::string& v)
+{
+ setAttr("extra_params", v);
+}
+
+
+unsigned int JobParametersProxy::nb_branches()const
+{
+ unsigned int result;
+ py2cpp::pyResult(result) = _pyParameters.getAttr("nb_branches");
+ return result;
+}
+
+void JobParametersProxy::nb_branches(unsigned int v)
+{
+ _pyParameters.setAttr("nb_branches", py2cpp::toPyPtr(v));
+}
+
+void JobParametersProxy::configureResource(const std::string& resourceName)
+{
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyParameters, "configureResource");
+ pyFn(resourceName);
+}
+
+void JobParametersProxy::createResultDirectory(const std::string& basePath)
+{
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyParameters, "createResultDirectory");
+ pyFn(basePath);
+}
+
+}
--- /dev/null
+#ifndef YDEFX_JOBPARAMETERSPROXY_H
+#define YDEFX_JOBPARAMETERSPROXY_H
+#include <py2cpp/PyPtr.hxx>
+#include <string>
+#include <list>
+#include <map>
+
+namespace ydefx
+{
+class JobParametersProxy;
+}
+namespace py2cpp
+{
+PyObject * toPy(const ydefx::JobParametersProxy& jp);
+}
+
+#include <py2cpp/py2cpp.hxx>
+
+namespace ydefx
+{
+class JobParametersProxy
+{
+public:
+ JobParametersProxy();
+
+ std::string job_name()const;
+ void job_name(const std::string& v);
+
+ std::string job_type()const;
+ void job_type(const std::string& v);
+
+ std::string job_file()const;
+ void job_file(const std::string& v);
+
+ std::string pre_command()const;
+ void pre_command(const std::string& v);
+
+ std::string env_file()const;
+ void env_file(const std::string& v);
+
+ std::list<std::string> in_files()const;
+ void add_in_files(const std::list<std::string>& pathList);
+ void in_files(const std::list<std::string>& pathList);
+
+ std::string work_directory()const;
+ void work_directory(const std::string& v);
+
+ std::string local_directory()const;
+ void local_directory(const std::string& v);
+
+ std::string result_directory()const;
+ void result_directory(const std::string& v);
+
+ std::string maximum_duration()const;
+ void maximum_duration(const std::string& v);
+
+ // ResourceParameters
+ std::string resource_name()const;
+ void resource_name(const std::string& name);
+
+ int nb_proc()const;
+ void nb_proc(int v);
+
+ int mem_mb()const;
+ void mem_mb(int v);
+
+ int nb_node()const;
+ void nb_node(int v);
+
+ int nb_proc_per_node()const;
+ void nb_proc_per_node(int v);
+
+ std::string queue()const;
+ void queue(const std::string& v);
+
+ std::string partition()const;
+ void partition(const std::string& v);
+
+ bool exclusive()const;
+ void exclusive(bool v);
+
+ unsigned int mem_per_cpu()const;
+ void mem_per_cpu(unsigned int v);
+
+ std::string wckey()const;
+ void wckey(const std::string& v);
+
+ std::string extra_params()const;
+ void extra_params(const std::string& v);
+
+ unsigned int nb_branches()const;
+ void nb_branches(unsigned int v);
+
+ /*!
+ * Set the resource and the default values associated with that resource:
+ * work_directory, nb_branches, nb_proc and wckey.
+ */
+ void configureResource(const std::string& resourceName);
+ //! create a new result directory as a subdirectory of the given path.
+ void createResultDirectory(const std::string& basePath);
+ friend PyObject * py2cpp::toPy(const JobParametersProxy& jp);
+
+private:
+ py2cpp::PyPtr _pyParameters;
+private:
+ std::string getAttrString(const std::string& attributeName)const;
+ void setAttr(const std::string& attributeName, const std::string& value);
+ int getResAttr(const std::string& attributeName)const;
+ void setResAttr(const std::string& attributeName, int value);
+};
+}
+#endif // YDEFX_JOBPARAMETERSPROXY_H
--- /dev/null
+#ifndef YDEFX_LAUNCHER_H
+#define YDEFX_LAUNCHER_H
+
+#include "TMonoPyJob.hxx"
+
+namespace ydefx
+{
+class Job;
+class Launcher
+{
+public:
+ Launcher():_lastError(){}
+ const std::string& lastError()const{return _lastError;}
+
+ /*!
+ * Create and submit a new job.
+ * Return nullptr in case of failure. Check the error with lastError().
+ */
+ template <class ...Ts>
+ Job* submitMonoPyJob(const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params);
+
+ /*!
+ * Connect to an already created job.
+ * Return nullptr in case of failure. Check the error with lastError().
+ */
+ template <class ...Ts>
+ Job* connectJob(const std::string& jobDump, Sample<Ts...>& sample);
+
+ template <class ...Ts>
+ Job* submitMultiPyJob(const PyStudyFunction& fn,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params);
+
+private:
+ std::string _lastError;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Template implementations
+////////////////////////////////////////////////////////////////////////////////
+
+template <class ...Ts>
+Job* Launcher::submitMonoPyJob(const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params)
+{
+ Job* result = nullptr;
+ _lastError = "";
+ try
+ {
+ result = new TMonoPyJob<Ts...>(fnScript, sample, params);
+ }
+ catch(std::exception& e)
+ {
+ if(result != nullptr)
+ delete result;
+ result = nullptr;
+ _lastError = e.what();
+ return result;
+ }
+
+ if(!result->launch())
+ {
+ _lastError = "Failed to submit job.\n";
+ _lastError += result->lastError();
+ delete result;
+ result = nullptr;
+ }
+ return result;
+}
+
+template <class ...Ts>
+Job* Launcher::connectJob(const std::string& jobDump,
+ Sample<Ts...>& sample)
+{
+ Job* result = nullptr;
+ _lastError = "";
+ try
+ {
+ result = new TMonoPyJob<Ts...>(jobDump, sample);
+ }
+ catch(std::exception& e)
+ {
+ if(result != nullptr)
+ delete result;
+ result = nullptr;
+ _lastError = e.what();
+ }
+
+ return result;
+}
+
+template <class ...Ts>
+Job* Launcher::submitMultiPyJob(const PyStudyFunction& fn,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params)
+{
+ // TODO
+ _lastError = "Not implemented!";
+ return nullptr;
+}
+
+}
+#endif // YDEFX_LAUNCHER_H
--- /dev/null
+#include "MonoPyJob.hxx"
+#include <py2cpp/py2cpp.hxx>
+
+namespace ydefx
+{
+MonoPyJob::MonoPyJob()
+: _pyStudy()
+, _lastError()
+, _waitDelay(10)
+{
+ py2cpp::PyFunction objConstructor;
+ objConstructor.loadExp("pydefx", "PyStudy");
+ _pyStudy = objConstructor();
+}
+
+MonoPyJob::~MonoPyJob()
+{
+}
+
+std::string MonoPyJob::state()
+{
+ std::string result;
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "getJobState");
+ py2cpp::pyResult(result) = pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while retrieving job's state.\n";
+ _lastError += e.what();
+ }
+ return result;
+}
+
+double MonoPyJob::progress()
+{
+ double result;
+ py2cpp::PyFunction pyFn;
+ _lastError = "";
+ try
+ {
+ pyFn.loadExp(_pyStudy, "getProgress");
+ py2cpp::pyResult(result) = pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while retrieving job's progress.\n";
+ _lastError += e.what();
+ }
+ return result;
+}
+
+std::string MonoPyJob::dump()
+{
+ std::string result;
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "dump");
+ py2cpp::pyResult(result) = pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while dumping the job.\n";
+ _lastError += e.what();
+ }
+ return result;
+}
+
+bool MonoPyJob::launch()
+{
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "launch");
+ pyFn();
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while launching the job.\n";
+ _lastError += e.what();
+ }
+ return _lastError.empty();
+}
+
+const std::string& MonoPyJob::lastError()
+{
+ return _lastError;
+}
+
+bool MonoPyJob::wait()
+{
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "wait");
+ pyFn(_waitDelay);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while waiting the end of the job.\n";
+ _lastError += e.what();
+ }
+ return _lastError.empty();
+}
+
+void MonoPyJob::configureWaitDelay(int seconds)
+{
+ _waitDelay = seconds;
+}
+
+}
--- /dev/null
+#ifndef YDEFX_MONOPYJOB_HXX
+#define YDEFX_MONOPYJOB_HXX
+#include "Job.hxx"
+#include <py2cpp/PyPtr.hxx>
+
+namespace ydefx
+{
+class MonoPyJob : public Job
+{
+public:
+ MonoPyJob();
+ virtual ~MonoPyJob();
+ virtual std::string state();
+ virtual double progress();
+ virtual std::string dump();
+ virtual bool launch(); // return false when it fails
+ virtual bool fetch()=0; // return false when it fails
+ virtual const std::string& lastError();
+ virtual bool wait(); // Wait for the end of the job. Return false when it fails.
+ virtual void configureWaitDelay(int seconds);
+protected:
+ py2cpp::PyPtr _pyStudy;
+ std::string _lastError;
+ int _waitDelay;
+};
+
+}
+
+#endif //YDEFX_MONOPYJOB_HXX
--- /dev/null
+#include "PyStudyFunction.hxx"
+#include <fstream>
+#include <sstream>
+#include <py2yacs.hxx>
+
+namespace ydefx
+{
+PyStudyFunction::PyStudyFunction()
+: _content()
+, _input()
+, _output()
+, _errors()
+{
+ _errors.push_back("Function \"_exec\" not found!");
+}
+
+PyStudyFunction::~PyStudyFunction(){}
+
+void PyStudyFunction::loadFile(const std::string& path)
+{
+ std::ifstream infile(path.c_str());
+ std::stringstream buffer;
+ buffer << infile.rdbuf();
+ loadString(buffer.str());
+}
+
+void PyStudyFunction::loadString(const std::string& value)
+{
+ _content = value;
+ _input.clear();
+ _output.clear();
+ _errors.clear();
+ // TODO: use py2yacs
+ Py2yacs p2y;
+ p2y.load(value);
+ if(p2y.getGlobalErrors().size() == 0)
+ {
+ const std::list<FunctionProperties>& fn_prop = p2y.getFunctionProperties();
+ std::list<FunctionProperties>::const_iterator prop_it = fn_prop.begin();
+ while(prop_it != fn_prop.end() && prop_it->_name != "_exec")
+ ++ prop_it;
+ if(prop_it != fn_prop.end() && prop_it->_errors.empty())
+ {
+ for(const std::string& name: prop_it->_input_ports)
+ _input.push_back(name);
+ for(const std::string& name: prop_it->_output_ports)
+ _output.push_back(name);
+ }
+ }
+ // TODO: deal with the errors
+}
+
+void PyStudyFunction::save(const std::string& path)
+{
+ std::ofstream outfile(path.c_str());
+ outfile << _content;
+}
+
+const std::string& PyStudyFunction::content()const
+{
+ return _content;
+}
+
+const std::list<std::string>& PyStudyFunction::inputNames()const
+{
+ return _input;
+}
+
+const std::list<std::string>& PyStudyFunction::outputNames()const
+{
+ return _output;
+}
+
+const std::list<std::string>& PyStudyFunction::errors()const
+{
+ return _errors;
+}
+
+}
--- /dev/null
+#ifndef YDEFX_PYSTUDYFUNCTION_H
+#define YDEFX_PYSTUDYFUNCTION_H
+#include "StudyFunction.hxx"
+namespace ydefx
+{
+class PyStudyFunction : StudyFunction
+{
+public:
+ PyStudyFunction();
+ virtual ~PyStudyFunction();
+ virtual void loadFile(const std::string& path);
+ virtual void loadString(const std::string&);
+ virtual void save(const std::string& path);
+ virtual const std::string& content()const;
+ virtual const std::list<std::string>& inputNames()const;
+ virtual const std::list<std::string>& outputNames()const;
+ virtual const std::list<std::string>& errors()const;
+private:
+ std::string _content;
+ std::list<std::string> _input;
+ std::list<std::string> _output;
+ std::list<std::string> _errors;
+};
+}
+#endif // YDEFX_PYSTUDYFUNCTION_H
--- /dev/null
+#ifndef YDEFX_SAMPLE_H\r
+#define YDEFX_SAMPLE_H\r
+\r
+#include <vector>\r
+#include <string>\r
+#include <list>\r
+#include <map>\r
+\r
+namespace ydefx\r
+{\r
+\r
+template <class T>\r
+class VariablesGroup\r
+{\r
+public:\r
+ VariablesGroup();\r
+ VariablesGroup( const T& defaultValue);\r
+ std::list<std::string> names()const;\r
+ bool isSet(const std::string& name, std::size_t index)const;\r
+ /*! Get the values for a variable name.\r
+ * Pay attention to default values. Use isSet function in order to know\r
+ * if the value has been set.\r
+ */\r
+ const std::vector<T>& get(const std::string& name)const;\r
+ const T& get(const std::string& name, std::size_t index)const;\r
+ void set(const std::string& name, const std::vector<T>& values);\r
+ void set(const std::string& name, std::size_t index, const T& value);\r
+ void clear(); //! names and values are cleared.\r
+ void clearValues(); //! values are cleared, but names are kept.\r
+ void resetNames(const std::list<std::string>& names);\r
+ void removeName(const std::string& name);\r
+ void addName(const std::string& name);\r
+ void unset(const std::string& name, std::size_t index);\r
+ bool isPointSet(std::size_t index)const; //! every variable is set\r
+ void setDefault(const T& defaultValue) {_defaultValue = defaultValue;}\r
+ std::size_t maxSize()const;\r
+private:\r
+ std::map<std::string, std::vector<T> > _variables;\r
+ std::map<std::string, std::vector<bool> > _status;\r
+ T _defaultValue;\r
+};\r
+\r
+enum class ExecutionState {NOTEXECUTED, DONE, ERROR};\r
+\r
+template <class T>\r
+class OneTypeSample\r
+{\r
+public:\r
+ const VariablesGroup<T>& inputs()const;\r
+ VariablesGroup<T>& inputs();\r
+ const VariablesGroup<T>& outputs()const;\r
+ VariablesGroup<T>& outputs();\r
+protected:\r
+ bool isPointSet(int index);\r
+ void unset(const std::string& name, std::size_t index);\r
+private:\r
+ VariablesGroup<T> _inputs;\r
+ VariablesGroup<T> _outputs;\r
+};\r
+\r
+template <class... Ts> class Sample;\r
+\r
+// no type sample\r
+template <>\r
+class Sample<>\r
+{\r
+public:\r
+ const std::vector<std::string>& errors()const{return _errors;}\r
+ std::vector<std::string>& errors(){return _errors;}\r
+ void clearErrors(){_errors.clear();}\r
+ void setError(std::size_t index, const std::string& message)\r
+ {\r
+ if(index >= _errors.size())\r
+ _errors.resize(index+1);\r
+ _errors[index] = message;\r
+ }\r
+ \r
+ std::string getError(std::size_t index)const\r
+ {\r
+ std::string result("");\r
+ if(index < _errors.size())\r
+ result = _errors[index];\r
+ return result;\r
+ }\r
+\r
+ virtual ExecutionState pointState(int index)\r
+ {\r
+ ExecutionState result = ExecutionState::DONE;\r
+ if(index < _errors.size())\r
+ if(!_errors[index].empty())\r
+ result = ExecutionState::ERROR;\r
+ return result;\r
+ }\r
+ virtual void clear(){_errors.clear();}\r
+ virtual void clearInputValues(){}\r
+ virtual void clearOutputValues(){_errors.clear();}\r
+\r
+ virtual std::list<std::string> allInputNames()const\r
+ {return std::list<std::string>();}\r
+\r
+ virtual std::list<std::string> allOutputNames()const\r
+ {return std::list<std::string>();}\r
+\r
+ virtual void unset(const std::string& name, std::size_t index){}\r
+ virtual std::size_t maxSize()const {return 0;}\r
+ \r
+private:\r
+ std::vector<std::string> _errors;\r
+};\r
+\r
+// multi type sample\r
+template <class T, class... Ts>\r
+class Sample<T, Ts...> : public OneTypeSample<T>, public Sample<Ts...>\r
+{\r
+public:\r
+ virtual ExecutionState pointState(int index);\r
+ virtual void clear(); //! names and values are cleared.\r
+ virtual void clearInputValues(); //! values are cleared, but names are kept.\r
+ virtual void clearOutputValues(); //! values are cleared, but names are kept.\r
+ virtual std::list<std::string> allInputNames()const;\r
+ virtual std::list<std::string> allOutputNames()const;\r
+ virtual void unset(const std::string& name, std::size_t index);\r
+ virtual std::size_t maxSize()const; //! outputs ignored!\r
+\r
+ template <class NT>\r
+ const VariablesGroup<NT>& inputs()const\r
+ {return OneTypeSample<NT>::inputs();}\r
+\r
+ template <class NT>\r
+ VariablesGroup<NT>& inputs()\r
+ {return OneTypeSample<NT>::inputs();}\r
+\r
+ template <class NT>\r
+ const VariablesGroup<NT>& outputs()const\r
+ {return OneTypeSample<NT>::outputs();}\r
+\r
+ template <class NT>\r
+ VariablesGroup<NT>& outputs()\r
+ {return OneTypeSample<NT>::outputs();}\r
+\r
+};\r
+\r
+// Sample<T, Ts...>\r
+template <class T, class... Ts>\r
+ExecutionState Sample<T, Ts...>::pointState(int index)\r
+{\r
+ ExecutionState result = Sample<Ts...>::pointState(index);\r
+ if(result == ExecutionState::DONE)\r
+ if(!OneTypeSample<T>::isPointSet(index))\r
+ result = ExecutionState::NOTEXECUTED;\r
+ return result;\r
+}\r
+\r
+template <class T, class... Ts>\r
+void Sample<T, Ts...>::clear()\r
+{\r
+ OneTypeSample<T>::inputs().clear();\r
+ OneTypeSample<T>::outputs().clear();\r
+ Sample<Ts...>::clear();\r
+}\r
+\r
+template <class T, class... Ts>\r
+void Sample<T, Ts...>::clearInputValues()\r
+{\r
+ OneTypeSample<T>::inputs().clearValues();\r
+ Sample<Ts...>::clearInputValues();\r
+}\r
+\r
+template <class T, class... Ts>\r
+void Sample<T, Ts...>::clearOutputValues()\r
+{\r
+ OneTypeSample<T>::outputs().clearValues();\r
+ Sample<Ts...>::clearOutputValues();\r
+}\r
+\r
+template <class T, class... Ts>\r
+std::list<std::string> Sample<T, Ts...>::allInputNames()const\r
+{\r
+ std::list<std::string> result = OneTypeSample<T>::inputs().names();\r
+ result.splice(result.end(), Sample<Ts...>::allInputNames());\r
+ return result;\r
+}\r
+\r
+template <class T, class... Ts>\r
+std::list<std::string> Sample<T, Ts...>::allOutputNames()const\r
+{\r
+ std::list<std::string> result = OneTypeSample<T>::outputs().names();\r
+ result.splice(result.end(),Sample<Ts...>::allOutputNames());\r
+ return result;\r
+}\r
+\r
+template <class T, class... Ts>\r
+void Sample<T, Ts...>::unset(const std::string& name, std::size_t index)\r
+{\r
+ OneTypeSample<T>::unset(name, index);\r
+ Sample<Ts...>::unset(name, index);\r
+}\r
+\r
+template <class T, class... Ts>\r
+std::size_t Sample<T, Ts...>::maxSize()const\r
+{\r
+ std::size_t result=OneTypeSample<T>::inputs().maxSize();\r
+ std::size_t superR=Sample<Ts...>::maxSize();\r
+ if(superR > result)\r
+ result = superR;\r
+ return result;\r
+}\r
+\r
+// VariablesGroup\r
+\r
+template <class T>\r
+VariablesGroup<T>::VariablesGroup( )\r
+: _variables()\r
+, _status()\r
+, _defaultValue(T())\r
+{\r
+}\r
+\r
+template <class T>\r
+VariablesGroup<T>::VariablesGroup( const T& defaultValue)\r
+: _variables()\r
+, _status()\r
+, _defaultValue(defaultValue)\r
+{\r
+}\r
+\r
+template <class T>\r
+std::list<std::string> VariablesGroup<T>::names()const\r
+{\r
+ std::list<std::string> result;\r
+ for(const auto& it : _variables)\r
+ result.push_back(it.first);\r
+ return result;\r
+}\r
+\r
+template <class T>\r
+bool VariablesGroup<T>::isSet(const std::string& name, std::size_t index)const\r
+{\r
+ bool result = false;\r
+ auto it = _status.find(name);\r
+ if(it != _status.end())\r
+ if(index < it->second.size())\r
+ result = it->second[index];\r
+ return result;\r
+}\r
+\r
+template <class T>\r
+bool VariablesGroup<T>::isPointSet(std::size_t index)const\r
+{\r
+ bool allSet = true;\r
+ std::map<std::string, std::vector<bool> >::const_iterator it;\r
+ for( it = _status.begin(); it != _status.end() && allSet; it++)\r
+ allSet = index < it->second.size() && it->second[index];\r
+ return allSet;\r
+}\r
+\r
+template <class T>\r
+std::size_t VariablesGroup<T>::maxSize()const\r
+{\r
+ std::size_t result = 0;\r
+ for(const auto& it : _variables)\r
+ if(result < it.second.size())\r
+ result = it.second.size();\r
+ return result;\r
+}\r
+\r
+template <class T>\r
+const std::vector<T>& VariablesGroup<T>::get(const std::string& name)const\r
+{\r
+ static const std::vector<T> emptyVector;\r
+ auto it = _variables.find(name);\r
+ if(it != _variables.end())\r
+ return it->second;\r
+ else\r
+ return emptyVector;\r
+}\r
+\r
+template <class T>\r
+const T& VariablesGroup<T>::get(const std::string& name, std::size_t index)const\r
+{\r
+ auto it = _variables.find(name);\r
+ if(it != _variables.end())\r
+ if(index < it->second.size())\r
+ return it->second[index];\r
+ return _defaultValue;\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::set(const std::string& name, const std::vector<T>& values)\r
+{\r
+ _variables[name] = values;\r
+ std::vector<bool>& status = _status[name];\r
+ status.clear();\r
+ status.insert(status.begin(), values.size(), true);\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::set(const std::string& name, std::size_t index, const T& value)\r
+{\r
+ std::vector<T>& values = _variables[name];\r
+ std::vector<bool>& status = _status[name];\r
+ if(index >= values.size())\r
+ {\r
+ values.resize(index+1, _defaultValue);\r
+ status.resize(index+1, false);\r
+ }\r
+ values[index] = value;\r
+ status[index] = true;\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::clear()\r
+{\r
+ _variables.clear();\r
+ _status.clear();\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::clearValues()\r
+{\r
+ for(auto& it : _variables)\r
+ {\r
+ it.second.clear();\r
+ }\r
+ for(auto& it : _status)\r
+ {\r
+ it.second.clear();\r
+ }\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::resetNames(const std::list<std::string>& names)\r
+{\r
+ clear();\r
+ for(const auto& it : names)\r
+ {\r
+ _variables[it].clear();\r
+ _status[it].clear();\r
+ }\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::removeName(const std::string& name)\r
+{\r
+ _variables.erase(name);\r
+ _status.erase(name);\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::addName(const std::string& name)\r
+{\r
+ _variables[name];\r
+ _status[name];\r
+}\r
+\r
+template <class T>\r
+void VariablesGroup<T>::unset(const std::string& name, std::size_t index)\r
+{\r
+ auto it = _status.find(name);\r
+ if(it != _status.end())\r
+ if(index < it->second.size())\r
+ {\r
+ it->second[index] = false;\r
+ if(index+1 == it->second.size())\r
+ {\r
+ // remove all the unset values at the end of the list\r
+ while(index>0 && !it->second[index])\r
+ --index;\r
+ it->second.resize(index);\r
+ _variables[name].resize(index);\r
+ }\r
+ }\r
+}\r
+ \r
+// OneTypeSample\r
+template <class T>\r
+const VariablesGroup<T>& OneTypeSample<T>::inputs()const\r
+{\r
+ return _inputs;\r
+}\r
+\r
+template <class T>\r
+VariablesGroup<T>& OneTypeSample<T>::inputs()\r
+{\r
+ return _inputs;\r
+}\r
+\r
+template <class T>\r
+const VariablesGroup<T>& OneTypeSample<T>::outputs()const\r
+{\r
+ return _outputs;\r
+}\r
+\r
+template <class T>\r
+VariablesGroup<T>& OneTypeSample<T>::outputs()\r
+{\r
+ return _outputs;\r
+}\r
+\r
+template <class T>\r
+bool OneTypeSample<T>::isPointSet(int index)\r
+{\r
+ return _inputs.isPointSet(index) && _outputs.isPointSet(index);\r
+}\r
+\r
+template <class T>\r
+void OneTypeSample<T>::unset(const std::string& name, std::size_t index)\r
+{\r
+ _outputs.unset(name, index);\r
+}\r
+\r
+}//namespace ydefx\r
+#endif // YDEFX_SAMPLE_H\r
--- /dev/null
+#ifndef YDEFX_SAMPLEPYCONVERSIONS_HXX
+#define YDEFX_SAMPLEPYCONVERSIONS_HXX
+
+#include <py2cpp/py2cpp.hxx>
+#include "Sample.hxx"
+#include "Exceptions.hxx"
+
+namespace ydefx
+{
+/*!
+ * The goal of this class is to iterate over the types of a sample.
+ * S : template type of the sample.
+ * For the highest level call, this is Sample<Ts...>.
+ * Ts : list of types managed by this converter. This list is included in the
+ * list of sample types.
+ */
+template <class S, class... Ts>
+class SamplePyConverter;
+
+/*!
+ * Convert input variables of a sample to a python dictionary.
+ * All input variables should have the same size. No verification is done here.
+ * The returned value is NULL in case of error.
+ */
+template <class ...Ts>
+PyObject* inputToPy(const Sample<Ts...>& sample);
+
+/*!
+ * Fill the input values of the sample from a python dictionary.
+ * The sample should already contain the names of the input values.
+ * For each type in the sample, for each variable name of the iterated type,
+ * fetch the values from the python dictionary and put them in the c++
+ * container. The old input values of the sample are cleared.
+ * The returned value contains the conversion errors if they exist.
+ * Keys from the python dictionary that do not exist in the sample are ignored.
+ */
+template <class ...Ts>
+py2cpp::ConversionCheck inputFromPy(PyObject* obj, Sample<Ts...>& sample);
+
+/*!
+ * Convert output variables of a sample to a python dictionary.
+ * Some points could have unset output values. The python dictionary will have
+ * None values for the unset points.
+ * The size of the lists of values in the python dictionary will be the same for
+ * every variable name. It will be sample.maxSize().
+ * The returned value is NULL in case of error.
+ */
+template <class ...Ts>
+PyObject* outputToPy(const Sample<Ts...>& sample);
+
+/*!
+ * Fill the output values of a sample from a python dictionary.
+ * The sample should already contain the keys (variable names) of the output
+ * values. The python dictionary may contain None values. A None value means the
+ * value is not set.
+ * Keys of the python dictionary which do not exist in the c++ sample are
+ * ignored.
+ */
+template <class ...Ts>
+py2cpp::ConversionCheck outputFromPy(PyObject* obj, Sample<Ts...>& sample);
+
+/*!
+ * Fill the error values of a sample from a python list of strings.
+ * The python list may contain None values which are translated to empty
+ * strings.
+ */
+template <class ...Ts>
+py2cpp::ConversionCheck errorsFromPy(PyObject* obj, Sample<Ts...>& sample);
+
+/*!
+ * A python sample object is created and it contains input and output names of
+ * variables. It also contains input values, but output values and errors are
+ * not copied.
+ */
+template <class ...Ts>
+py2cpp::PyPtr createPySample(const Sample<Ts...>& sample);
+
+/*!
+ * Fetch output values and errors from the python objet.
+ * The c++ sample should already contain the names of variables when this
+ * function is called.
+ */
+template <class ...Ts>
+py2cpp::ConversionCheck fetchResults(PyObject* obj, Sample<Ts...>& sample);
+
+////////////////////////////////////////////////////////////////////////////////
+// Template implementations
+////////////////////////////////////////////////////////////////////////////////
+
+template <class S>
+class SamplePyConverter<S>
+{
+public:
+ bool inputToPy(const S& sample, PyObject* result){return true;}
+ py2cpp::ConversionCheck inputFromPy(PyObject* obj, S& sample)
+ { return py2cpp::ConversionCheck();}
+ bool outputToPy(const S& sample, PyObject* result){return true;}
+ py2cpp::ConversionCheck outputFromPy(PyObject* obj, S& sample)
+ { return py2cpp::ConversionCheck();}
+};
+
+template <class S, class T, class... Ts>
+class SamplePyConverter<S,T, Ts...> : public SamplePyConverter<S, Ts...>
+{
+public:
+ /*! Add sample.inputs<T> to result.
+ * result should be a python dictionary.
+ */
+ bool inputToPy(const S& sample, PyObject* result)
+ {
+ bool ok = true;
+ std::list<std::string> names = sample.OneTypeSample<T>::inputs().names();
+ for(const std::string& name : names)
+ {
+ const std::vector<T>& values = sample.OneTypeSample<T>::inputs().get(name);
+ py2cpp::PyPtr pyValue(py2cpp::toPy(values));
+ ok = PyDict_SetItemString(result, name.c_str(), pyValue.get()) == 0;
+ if(!ok)
+ break;
+ }
+ if(ok)
+ ok = SamplePyConverter<S, Ts...>::inputToPy(sample, result);
+ return ok;
+ }
+
+ py2cpp::ConversionCheck inputFromPy(PyObject* obj, S& sample)
+ {
+ py2cpp::ConversionCheck check;
+ std::list<std::string> names = sample.OneTypeSample<T>::inputs().names();
+ for(const std::string& name : names)
+ {
+ PyObject* pyValues = PyDict_GetItemString(obj, name.c_str());
+ if(!pyValues)
+ {
+ std::string error = "The key '";
+ error += name;
+ error += "' was not found in the python object.\n";
+ check.addErrorMessage(error);
+ }
+ else if(PyList_Check(pyValues))
+ {
+ std::size_t size = PyList_Size(pyValues);
+ std::size_t i=size;
+ // We prefer to fill the values from highest index to 0 in order
+ // to avoid the resize of the vector when the index grows.
+ bool stop = (i == 0) || !check;
+ while(!stop)
+ {
+ i--;
+ T value;
+ PyObject* pyVal = PyList_GetItem(pyValues, i);
+ check.addError(py2cpp::fromPy(pyVal, value));
+ if(check)
+ sample.OneTypeSample<T>::inputs().set(name, i, value);
+ stop = (i == 0) || !check;
+ }
+ }
+ else
+ check.addError("sample input list", obj);
+ }
+ if(check)
+ check = SamplePyConverter<S, Ts...>::inputFromPy(obj, sample);
+ return check;
+ }
+
+ bool outputToPy(const S& sample, PyObject* result)
+ {
+ bool ok = true;
+ std::size_t maxsize = sample.maxSize();
+ std::list<std::string> names = sample.OneTypeSample<T>::outputs().names();
+ for(const std::string& name : names)
+ {
+ py2cpp::PyPtr newList( PyList_New(maxsize));
+ if(newList == nullptr)
+ {
+ ok = false;
+ break;
+ }
+ for(std::size_t i=0; i<maxsize; i++)
+ {
+ if(sample.OneTypeSample<T>::outputs().isSet(name, i))
+ {
+ const T& cppValue = sample.OneTypeSample<T>::outputs().get(name,i);
+ PyObject * pyValue = py2cpp::toPy(cppValue);
+ PyList_SetItem(newList.get(), i, pyValue);
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ PyList_SetItem(newList.get(), i, Py_None);
+ }
+ }
+ ok = PyDict_SetItemString(result, name.c_str(), newList.get()) == 0;
+ if(!ok)
+ break;
+ }
+ if(ok)
+ ok = SamplePyConverter<S, Ts...>::outputToPy(sample, result);
+ return ok;
+ }
+
+ py2cpp::ConversionCheck outputFromPy(PyObject* obj, S& sample)
+ {
+ py2cpp::ConversionCheck check;
+ std::list<std::string> names = sample.OneTypeSample<T>::outputs().names();
+ for(const std::string& name : names)
+ {
+ PyObject* pyValues = PyDict_GetItemString(obj, name.c_str());
+ if(!pyValues)
+ {
+ std::string error = "The key '";
+ error += name;
+ error += "' was not found in the python object.\n";
+ check.addErrorMessage(error);
+ }
+ else if(PyList_Check(pyValues))
+ {
+ std::size_t size = PyList_Size(pyValues);
+ std::size_t i=size;
+ // We prefer to fill the values from highest index to 0 in order
+ // to avoid the resize of the vector when the index grows.
+ bool stop = (i == 0) || !check;
+ while(!stop)
+ {
+ i--;
+ PyObject* pyVal = PyList_GetItem(pyValues, i);
+ if(Py_None == pyVal)
+ {
+ sample.OneTypeSample<T>::outputs().unset(name, i);
+ }
+ else
+ {
+ T value;
+ check.addError(py2cpp::fromPy(pyVal, value));
+ if(check)
+ sample.OneTypeSample<T>::outputs().set(name, i, value);
+ }
+ stop = (i == 0) || !check;
+ }
+ }
+ else
+ check.addError("sample input list", obj);
+ }
+ if(check)
+ check = SamplePyConverter<S, Ts...>::outputFromPy(obj, sample);
+ return check;
+ }
+};
+
+template <class ...Ts>
+PyObject* inputToPy(const Sample<Ts...>& sample)
+{
+ PyObject * result = PyDict_New();
+ if(result)
+ {
+ SamplePyConverter<Sample<Ts...>, Ts...> converter;
+ if(! converter.inputToPy(sample, result))
+ {
+ Py_XDECREF(result);
+ result = nullptr;
+ }
+ }
+ // TODO: errors
+ return result;
+}
+
+template <class ...Ts>
+py2cpp::ConversionCheck inputFromPy(PyObject* obj, Sample<Ts...>& sample)
+{
+ py2cpp::ConversionCheck check;
+ if(PyDict_Check(obj))
+ {
+ sample.clearInputValues();
+ SamplePyConverter<Sample<Ts...>, Ts...> converter;
+ check.addError(converter.inputFromPy(obj,sample));
+ }
+ else
+ check.addError("Sample input", obj);
+
+ return check;
+}
+
+template <class ...Ts>
+PyObject* outputToPy(const Sample<Ts...>& sample)
+{
+ PyObject * result = PyDict_New();
+ if(result)
+ {
+ SamplePyConverter<Sample<Ts...>, Ts...> converter;
+ if(! converter.outputToPy(sample, result))
+ {
+ Py_XDECREF(result);
+ result = nullptr;
+ }
+ }
+ return result;
+}
+
+template <class ...Ts>
+py2cpp::ConversionCheck outputFromPy(PyObject* obj, Sample<Ts...>& sample)
+{
+ py2cpp::ConversionCheck check;
+ if(PyDict_Check(obj))
+ {
+ sample.clearOutputValues();
+ SamplePyConverter<Sample<Ts...>, Ts...> converter;
+ check.addError(converter.outputFromPy(obj,sample));
+ }
+ else
+ check.addError("Sample output", obj);
+ return check;
+}
+
+template <class ...Ts>
+py2cpp::ConversionCheck errorsFromPy(PyObject* obj, Sample<Ts...>& sample)
+{
+ py2cpp::ConversionCheck check;
+ if(PyList_Check(obj))
+ {
+ sample.clearErrors();
+ std::size_t size = PyList_Size(obj);
+ sample.errors().resize(size);
+ for(std::size_t i=0; i < size && check; i++)
+ {
+ PyObject* pyValue = PyList_GetItem(obj, i);
+ // Py_None values are translated to empty strings in c++.
+ std::string cppValue("");
+ if(Py_None != pyValue)
+ check.addError(py2cpp::fromPy(pyValue, cppValue));
+ if(check)
+ sample.errors().push_back(cppValue);
+ }
+ }
+ else
+ check.addError("Sample error", obj);
+ return check;
+}
+
+template <class ...Ts>
+py2cpp::PyPtr createPySample(const Sample<Ts...>& sample)
+{
+ py2cpp::PyFunction sampleConstructor;
+ sampleConstructor.loadExp("pydefx", "Sample");
+ py2cpp::PyPtr result = sampleConstructor(sample.allInputNames(),
+ sample.allOutputNames());
+
+ py2cpp::PyFunction setInputValues;
+ setInputValues.loadExp(result, "setInputValues");
+ setInputValues(inputToPy(sample));
+
+ return result;
+}
+
+template <class ...Ts>
+py2cpp::ConversionCheck fetchResults(const py2cpp::PyPtr& obj, Sample<Ts...>& sample)
+{
+ py2cpp::ConversionCheck check;
+ check.addError(outputFromPy(obj.getAttr("_output").get(), sample));
+ check.addError(errorsFromPy(obj.getAttr("_messages").get(), sample));
+ return check;
+}
+
+}
+#endif //YDEFX_SAMPLEPYCONVERSIONS_HXX
--- /dev/null
+#ifndef YDEFX_STUDYFUNCTION_H
+#define YDEFX_STUDYFUNCTION_H
+#include <string>
+#include <list>
+
+namespace ydefx
+{
+class StudyFunction
+{
+public:
+ virtual ~StudyFunction(){}
+ virtual void loadFile(const std::string& path)=0;
+ virtual void loadString(const std::string&)=0;
+ virtual void save(const std::string& path)=0;
+ virtual const std::string& content()const=0;
+ virtual const std::list<std::string>& inputNames()const=0;
+ virtual const std::list<std::string>& outputNames()const=0;
+ virtual const std::list<std::string>& errors()const=0;
+ std::list<std::string> datafiles;
+};
+}
+#endif // YDEFX_STUDYFUNCTION_H
--- /dev/null
+#ifndef YDEFX_TMONOPYJOB_HXX
+#define YDEFX_TMONOPYJOB_HXX
+#include "JobParametersProxy.hxx"
+#include "MonoPyJob.hxx"
+#include "Sample.hxx"
+#include "SamplePyConversions.hxx"
+#include "PyStudyFunction.hxx"
+#include <py2cpp/py2cpp.hxx>
+
+namespace ydefx
+{
+template <class ...Ts>
+class TMonoPyJob : public MonoPyJob
+{
+public:
+ //! Create a new job.
+ TMonoPyJob(const PyStudyFunction& fnScript,
+ Sample<Ts...>& sample,
+ const JobParametersProxy& params)
+ : MonoPyJob()
+ , _sample(sample)
+ {
+ if(_lastError.empty()) // no errors during parent contruction
+ {
+ try
+ {
+ py2cpp::PyPtr pySample = createPySample(sample);
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "createNewJob");
+ pyFn(fnScript.content(), pySample, params);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while creating the job.\n";
+ _lastError += e.what();
+ }
+ }
+ }
+
+ //! Connect to an existing job.
+ TMonoPyJob(const std::string& jobDump, Sample<Ts...>& sample)
+ : MonoPyJob()
+ , _sample(sample)
+ {
+ if(_lastError.empty()) // no errors during parent contruction
+ {
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "loadFromString");
+ pyFn(jobDump);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while creating the job.\n";
+ _lastError += e.what();
+ }
+ }
+ }
+
+ virtual ~TMonoPyJob(){}
+ virtual bool fetch()
+ {
+ _lastError = "";
+ try
+ {
+ py2cpp::PyFunction pyFn;
+ pyFn.loadExp(_pyStudy, "getResult");
+ fetchResults(_pyStudy.getAttr("sample"), _sample);
+ }
+ catch(std::exception& e)
+ {
+ _lastError = "An error occured while fetching the results.\n";
+ _lastError += e.what();
+ }
+ return _lastError.empty();
+ }
+
+ const Sample<Ts...>& getSample()const{return _sample;}
+
+private:
+ Sample<Ts...>& _sample;
+};
+
+}
+
+#endif //YDEFX_TMONOPYJOB_HXX
--- /dev/null
+FIND_PACKAGE(CppUnit REQUIRED)
+
+# additional include directories
+INCLUDE_DIRECTORIES(
+ ${CPPUNIT_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+
+# libraries to link to
+SET(_link_LIBRARIES
+ ${CPPUNIT_LIBRARIES}
+ py2cpp
+ ydefx
+)
+
+SET(Test_SOURCES
+ SampleTest.cxx
+)
+
+ADD_EXECUTABLE(SampleTest ${Test_SOURCES})
+TARGET_LINK_LIBRARIES(SampleTest ${_link_LIBRARIES})
+ADD_TEST(YdefxSampleTest SampleTest)
+SET_TESTS_PROPERTIES(YdefxSampleTest PROPERTIES ENVIRONMENT
+ "PYTHONPATH=${CMAKE_SOURCE_DIR}/src:$ENV{PYTHONPATH}")
+
+ADD_EXECUTABLE(StudyGeneralTest StudyGeneralTest.cxx)
+TARGET_LINK_LIBRARIES(StudyGeneralTest ${_link_LIBRARIES})
+ADD_TEST(YdefxStudyGeneralTest StudyGeneralTest)
+SET_TESTS_PROPERTIES(YdefxStudyGeneralTest PROPERTIES ENVIRONMENT
+ "PYTHONPATH=${CMAKE_SOURCE_DIR}/src:$ENV{PYTHONPATH}")
+
+ADD_EXECUTABLE(StudyRestartTest StudyRestartTest.cxx)
+TARGET_LINK_LIBRARIES(StudyRestartTest ${_link_LIBRARIES})
+ADD_TEST(YdefxStudyRestartTest StudyRestartTest)
+SET_TESTS_PROPERTIES(YdefxStudyRestartTest PROPERTIES ENVIRONMENT
+ "PYTHONPATH=${CMAKE_SOURCE_DIR}/src:$ENV{PYTHONPATH}")
--- /dev/null
+#include "SampleTest.hxx"
+#include "../Launcher.hxx" // possible conflict with KERNEL/Launcher/Launcher.hxx
+#include <algorithm>
+
+void SampleTest::setUp()
+{
+}
+
+void SampleTest::tearDown()
+{
+}
+
+void SampleTest::cleanUp()
+{
+}
+
+void SampleTest::pointState()
+{
+ ydefx::Sample<double, int> mySample;
+ CPPUNIT_ASSERT(mySample.maxSize() == 0);
+ std::vector<int> int_vals = {1, 7, 42};
+ mySample.inputs<int>().set("toto", int_vals);
+ mySample.outputs<double>().addName("lili");
+ for(unsigned int i = 0; i < 5; ++i)
+ CPPUNIT_ASSERT(mySample.pointState(i)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.maxSize() == 3);
+ mySample.errors().resize(3);
+ mySample.errors()[1] = "Error detected!";
+ CPPUNIT_ASSERT(mySample.pointState(0)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(1)==ydefx::ExecutionState::ERROR);
+ CPPUNIT_ASSERT(mySample.pointState(2)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(3)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.maxSize() == 3);
+
+ mySample.outputs<double>().set("lili", 0, 4.5);
+ CPPUNIT_ASSERT(mySample.pointState(0)==ydefx::ExecutionState::DONE);
+ CPPUNIT_ASSERT(mySample.pointState(1)==ydefx::ExecutionState::ERROR);
+ CPPUNIT_ASSERT(mySample.pointState(2)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(3)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.maxSize() == 3);
+
+ mySample.outputs<double>().set("lili", 5, 42.3);
+ CPPUNIT_ASSERT(mySample.pointState(0)==ydefx::ExecutionState::DONE);
+ CPPUNIT_ASSERT(mySample.pointState(1)==ydefx::ExecutionState::ERROR);
+ CPPUNIT_ASSERT(mySample.pointState(2)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(3)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(4)==ydefx::ExecutionState::NOTEXECUTED);
+ // no input defined for n°5 => not executed
+ // TODO: add a new state: incomplete
+ CPPUNIT_ASSERT(mySample.pointState(5)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.maxSize() == 3);
+
+ mySample.inputs<int>().set("toto", 5, 7);
+ CPPUNIT_ASSERT(mySample.pointState(4)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(5)==ydefx::ExecutionState::DONE);
+ CPPUNIT_ASSERT(mySample.maxSize() == 6);
+
+ mySample.outputs<double>().set("lili", 4, 23.5);
+ CPPUNIT_ASSERT(mySample.pointState(4)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.maxSize() == 6);
+
+ mySample.unset("lili", 5);
+ CPPUNIT_ASSERT(mySample.pointState(0)==ydefx::ExecutionState::DONE);
+ CPPUNIT_ASSERT(mySample.pointState(1)==ydefx::ExecutionState::ERROR);
+ CPPUNIT_ASSERT(mySample.pointState(2)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(3)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(4)==ydefx::ExecutionState::NOTEXECUTED);
+ CPPUNIT_ASSERT(mySample.pointState(5)==ydefx::ExecutionState::NOTEXECUTED);
+
+ CPPUNIT_ASSERT(mySample.outputs<double>().maxSize() == 4);
+}
+
+void SampleTest::pyConversions()
+{
+ ydefx::Sample<double, int, std::string> mySample;
+ std::vector<int> int_vals = {1, 7, 42};
+ Py_Initialize();
+ {
+ // Test inputs
+ py2cpp::PyPtr pyObj(inputToPy(mySample));
+ CPPUNIT_ASSERT(pyObj.repr() == "{}");
+ mySample.inputs<int>().set("toto", int_vals);
+ pyObj.reset(inputToPy(mySample));
+ CPPUNIT_ASSERT(pyObj.repr() == "{'toto': [1, 7, 42]}");
+ std::vector<double> double_vals = {1.5, 3.2, 7.5};
+ mySample.inputs<double>().set("dval", double_vals);
+ pyObj.reset(inputToPy(mySample));
+ ydefx::Sample<double, int, std::string> frompySample;
+ frompySample.inputs<int>().addName("toto");
+ frompySample.inputs<double>().addName("dval");
+ py2cpp::ConversionCheck check(inputFromPy(pyObj.get(), frompySample));
+ CPPUNIT_ASSERT(check);
+ CPPUNIT_ASSERT(double_vals == frompySample.inputs<double>().get("dval"));
+ CPPUNIT_ASSERT(int_vals == frompySample.inputs<int>().get("toto"));
+
+ // Test outputs
+ pyObj.reset(outputToPy(mySample));
+ CPPUNIT_ASSERT(pyObj.repr() == "{}");
+ check.reset();
+ check.addError(outputFromPy(pyObj.get(), frompySample));
+ CPPUNIT_ASSERT(check);
+ CPPUNIT_ASSERT(0 == frompySample.allOutputNames().size());
+ CPPUNIT_ASSERT(double_vals == frompySample.inputs<double>().get("dval"));
+ CPPUNIT_ASSERT(int_vals == frompySample.inputs<int>().get("toto"));
+ mySample.outputs<double>().addName("dout");
+ mySample.outputs<double>().set("dout", 1, 1.5);
+ pyObj.reset(outputToPy(mySample));
+ frompySample.outputs<double>().addName("dout");
+ check.addError(outputFromPy(pyObj.get(), frompySample));
+ CPPUNIT_ASSERT(check);
+ CPPUNIT_ASSERT(1.5 == frompySample.outputs<double>().get("dout", 1));
+ CPPUNIT_ASSERT(frompySample.outputs<double>().isSet("dout",1));
+ CPPUNIT_ASSERT(!frompySample.outputs<double>().isSet("dout",0));
+ CPPUNIT_ASSERT(!frompySample.outputs<double>().isSet("dout",2));
+
+ mySample.outputs<std::string>().addName("strout");
+ mySample.outputs<std::string>().set("strout", 1, "myvalue");
+ pyObj.reset(outputToPy(mySample));
+ frompySample.outputs<std::string>().addName("strout");
+ check.addError(outputFromPy(pyObj.get(), frompySample));
+ CPPUNIT_ASSERT(check);
+ CPPUNIT_ASSERT(1.5 == frompySample.outputs<double>().get("dout", 1));
+ CPPUNIT_ASSERT(frompySample.outputs<double>().isSet("dout",1));
+ CPPUNIT_ASSERT(!frompySample.outputs<double>().isSet("dout",0));
+ CPPUNIT_ASSERT(!frompySample.outputs<double>().isSet("dout",2));
+ CPPUNIT_ASSERT(frompySample.outputs<std::string>().get("strout", 1)
+ == "myvalue");
+ CPPUNIT_ASSERT(frompySample.outputs<std::string>().isSet("strout",1));
+ CPPUNIT_ASSERT(!frompySample.outputs<std::string>().isSet("strout",0));
+ CPPUNIT_ASSERT(!frompySample.outputs<std::string>().isSet("strout",2));
+ }
+ Py_Finalize();
+}
+
+void SampleTest::pyConversionsErrors()
+{
+ Py_Initialize();
+ {
+ ydefx::Sample<double> resultSample;
+ std::vector<double> double_vals = {1.5, 3.2, 7.5};
+ ydefx::Sample<std::vector<double> > vectSample;
+ // errors on input variables
+ vectSample.inputs<std::vector<double> >().addName("p1");
+ vectSample.inputs<std::vector<double> >().set("p1", 0, double_vals);
+ py2cpp::PyPtr pyObj(inputToPy(vectSample));
+ resultSample.inputs<double>().addName("noname");
+ py2cpp::ConversionCheck check;
+ check.addError(inputFromPy(pyObj.get(), resultSample));
+ // The error contains the name of the unfound key.
+ CPPUNIT_ASSERT(check.getMessage().find("noname")!= std::string::npos);
+ resultSample.clear();
+ resultSample.inputs<double>().addName("p1");
+ check.reset();
+ check.addError(inputFromPy(pyObj.get(), resultSample));
+ // The error contains the name of the type "double" which fails to be
+ // converted.
+ CPPUNIT_ASSERT(check.getMessage().find("double")!= std::string::npos);
+ ydefx::Sample<std::vector<int> > vectIntSample;
+ vectIntSample.inputs<std::vector<int> >().addName("p1");
+ check.reset();
+ check.addError(inputFromPy(pyObj.get(), vectIntSample));
+ CPPUNIT_ASSERT(check.getMessage().find("int")!= std::string::npos);
+ CPPUNIT_ASSERT(check.getMessage().find("std::vector")!= std::string::npos);
+ py2cpp::PyPtr notADict(py2cpp::toPy(42));
+ check.reset();
+ check.addError(inputFromPy(notADict.get(), vectIntSample));
+ CPPUNIT_ASSERT(check.getMessage().find("Sample input")!= std::string::npos);
+
+ // errors on output variables
+ resultSample.outputs<double>().addName("o1");
+ check.reset();
+ check.addError(outputFromPy(pyObj.get(), resultSample));
+ CPPUNIT_ASSERT(check.getMessage().find("o1")!= std::string::npos);
+
+ vectSample.outputs<std::vector<double> >().addName("o1");
+ vectSample.outputs<std::vector<double> >().set("o1", 0, double_vals);
+ pyObj.reset(outputToPy(vectSample));
+ check.reset();
+ check.addError(outputFromPy(pyObj.get(), resultSample));
+ CPPUNIT_ASSERT(check.getMessage().find("double")!= std::string::npos);
+
+ check.reset();
+ check.addError(outputFromPy(notADict.get(), resultSample));
+ CPPUNIT_ASSERT(check.getMessage().find("Sample output")!= std::string::npos);
+ }
+ Py_Finalize();
+}
+
+void SampleTest::params()
+{
+ Py_Initialize();
+ {
+ try
+ {
+ ydefx::JobParametersProxy jpp;
+ CPPUNIT_ASSERT(jpp.resource_name() == "localhost");
+ CPPUNIT_ASSERT(jpp.job_type() == "yacs_file");
+ std::list<std::string> testList = {"toto", "titi","tata"};
+ jpp.in_files(testList);
+ CPPUNIT_ASSERT(jpp.in_files() == testList);
+ std::list<std::string> addList = {"zozo", "zizi"};
+ jpp.add_in_files(addList);
+ CPPUNIT_ASSERT(jpp.in_files() == std::list<std::string>({"toto", "titi",
+ "tata", "zozo", "zizi"}));
+ jpp.env_file("a");
+ jpp.exclusive(true);
+ jpp.extra_params("b");
+ jpp.job_file("c");
+ jpp.job_name("d");
+ jpp.job_type("e");
+ jpp.local_directory("fi");
+ jpp.maximum_duration("dur");
+ jpp.mem_mb(5);
+ jpp.mem_per_cpu(42);
+ jpp.nb_branches(18);
+ jpp.nb_node(15);
+ jpp.nb_proc(13);
+ jpp.nb_proc_per_node(12);
+ jpp.partition("gg");
+ jpp.pre_command("pc");
+ jpp.queue("qq");
+ jpp.resource_name("rn");
+ jpp.result_directory("rd");
+ jpp.wckey("wk");
+ jpp.work_directory("wd");
+ CPPUNIT_ASSERT(jpp.env_file() == "a");
+ CPPUNIT_ASSERT(jpp.exclusive());
+ CPPUNIT_ASSERT(jpp.extra_params() == "b");
+ CPPUNIT_ASSERT(jpp.job_file() == "c");
+ CPPUNIT_ASSERT(jpp.job_name() == "d");
+ CPPUNIT_ASSERT(jpp.job_type() == "e");
+ CPPUNIT_ASSERT(jpp.local_directory() == "fi");
+ CPPUNIT_ASSERT(jpp.maximum_duration() == "dur");
+ CPPUNIT_ASSERT(jpp.mem_mb() == 5);
+ CPPUNIT_ASSERT(jpp.mem_per_cpu() == 42);
+ CPPUNIT_ASSERT(jpp.nb_branches() == 18);
+ CPPUNIT_ASSERT(jpp.nb_node() == 15);
+ CPPUNIT_ASSERT(jpp.nb_proc() == 13);
+ CPPUNIT_ASSERT(jpp.nb_proc_per_node() == 12);
+ CPPUNIT_ASSERT(jpp.partition() == "gg");
+ CPPUNIT_ASSERT(jpp.pre_command() == "pc");
+ CPPUNIT_ASSERT(jpp.queue() == "qq");
+ CPPUNIT_ASSERT(jpp.resource_name() == "rn");
+ CPPUNIT_ASSERT(jpp.result_directory() == "rd");
+ CPPUNIT_ASSERT(jpp.wckey() == "wk");
+ CPPUNIT_ASSERT(jpp.work_directory() == "wd");
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what();
+ CPPUNIT_FAIL("Unexpected exception!");
+ }
+ }
+ Py_Finalize();
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( SampleTest );
+#include "TestMain.cxx"
--- /dev/null
+// Copyright (C) 2018 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, 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
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef YDEFX_SAMPLETEST_HXX
+#define YDEFX_SAMPLETEST_HXX
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SampleTest: public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(SampleTest);
+ CPPUNIT_TEST(pointState);
+ CPPUNIT_TEST(pyConversions);
+ CPPUNIT_TEST(pyConversionsErrors);
+ CPPUNIT_TEST(params);
+ CPPUNIT_TEST_SUITE_END();
+public:
+ void setUp();
+ void tearDown();
+ void cleanUp();
+ void pointState();
+ void pyConversions();
+ void pyConversionsErrors();
+ void params();
+};
+
+#endif // YDEFX_SAMPLETEST_HXX
--- /dev/null
+#include "StudyGeneralTest.hxx"
+#include "../Launcher.hxx" // possible conflict with KERNEL/Launcher/Launcher.hxx
+#include <algorithm>
+
+void SampleTest::setUp()
+{
+}
+
+void SampleTest::tearDown()
+{
+}
+
+void SampleTest::cleanUp()
+{
+}
+
+void SampleTest::fullStudy()
+{
+ Py_Initialize();
+ {
+ ydefx::JobParametersProxy jobParams;
+ jobParams.configureResource("localhost");
+ jobParams.createResultDirectory("/tmp");
+ std::string pyScript =
+"def _exec(a, b):\n"
+" d = a / b\n"
+" return d\n";
+
+ ydefx::PyStudyFunction studyFunction;
+ studyFunction.loadString(pyScript);
+ CPPUNIT_ASSERT(studyFunction.errors().empty());
+ const std::list<std::string>& inputs = studyFunction.inputNames();
+ CPPUNIT_ASSERT(std::find(inputs.begin(), inputs.end(), "a")!=inputs.end());
+ CPPUNIT_ASSERT(std::find(inputs.begin(), inputs.end(), "b")!=inputs.end());
+ const std::list<std::string>& outputs = studyFunction.outputNames();
+ CPPUNIT_ASSERT(std::find(outputs.begin(), outputs.end(), "d")
+ != outputs.end());
+
+ ydefx::Sample<double> sample;
+ std::vector<double> a_vals = {1.1, 2.2, 3.4, 5.5};
+ std::vector<double> b_vals = {2.2, 4.4, 6.8, 11};
+ sample.inputs<double>().set("a", a_vals);
+ sample.inputs<double>().set("b", b_vals);
+ sample.outputs<double>().addName("d");
+
+ ydefx::Launcher l;
+ ydefx::Job* myJob = l.submitMonoPyJob(studyFunction, sample, jobParams);
+ CPPUNIT_ASSERT(myJob);
+ CPPUNIT_ASSERT(l.lastError().empty());
+ std::string jobDump = myJob->dump();
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ std::string jobState = myJob->state();
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ CPPUNIT_ASSERT(jobState == "QUEUED" || jobState == "RUNNING"
+ || jobState == "FINISHED");
+ double progress = myJob->progress();
+ CPPUNIT_ASSERT(progress >= 0.0 && progress <= 1.0 );
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ bool ok = myJob->wait();
+ CPPUNIT_ASSERT(ok);
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ jobState = myJob->state();
+ CPPUNIT_ASSERT(jobState == "FINISHED");
+ progress = myJob->progress();
+ CPPUNIT_ASSERT(progress == 1.0);
+ ok = myJob->fetch();
+ CPPUNIT_ASSERT(ok);
+ CPPUNIT_ASSERT(myJob->lastError().empty());
+ std::vector<double> expectedResult = {0.5, 0.5, 0.5, 0.5};
+ const std::vector<double>& result = sample.outputs<double>().get("d");
+ CPPUNIT_ASSERT(expectedResult == result);
+ delete myJob;
+ }
+ Py_Finalize();
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( SampleTest );
+#include "TestMain.cxx"
--- /dev/null
+// Copyright (C) 2018 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, 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
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef YDEFX_SAMPLETEST_HXX
+#define YDEFX_SAMPLETEST_HXX
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SampleTest: public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(SampleTest);
+ CPPUNIT_TEST(fullStudy);
+ CPPUNIT_TEST_SUITE_END();
+public:
+ void setUp();
+ void tearDown();
+ void cleanUp();
+ void fullStudy();
+};
+
+#endif // YDEFX_SAMPLETEST_HXX
--- /dev/null
+#include "StudyRestartTest.hxx"
+#include "../Launcher.hxx" // possible conflict with KERNEL/Launcher/Launcher.hxx
+#include <algorithm>
+
+void SampleTest::setUp()
+{
+}
+
+void SampleTest::tearDown()
+{
+}
+
+void SampleTest::cleanUp()
+{
+}
+
+void SampleTest::studyTest()
+{
+ Py_Initialize();
+ {
+ ydefx::JobParametersProxy jobParams;
+ jobParams.configureResource("localhost");
+ jobParams.createResultDirectory("/tmp");
+
+ std::string pyScript =
+"def _exec(a, b):\n"
+" d = a / b\n"
+" return d\n";
+ ydefx::PyStudyFunction studyFunction;
+ studyFunction.loadString(pyScript);
+
+ ydefx::Sample<double> sample;
+ std::vector<double> a_vals = {1.1, 2.2, 3.4, 5.5};
+ std::vector<double> b_vals = {2.2, 4.4, 6.8, 11};
+ sample.inputs<double>().set("a", a_vals);
+ sample.inputs<double>().set("b", b_vals);
+ sample.outputs<double>().addName("d");
+
+ ydefx::Launcher l;
+ ydefx::Job* myJob = l.submitMonoPyJob(studyFunction, sample, jobParams);
+ std::string jobDump = myJob->dump();
+ delete myJob;
+
+ ydefx::Job* restoredJob = l.connectJob(jobDump, sample);
+ CPPUNIT_ASSERT(restoredJob);
+ CPPUNIT_ASSERT(l.lastError().empty());
+ bool ok = restoredJob->wait();
+ CPPUNIT_ASSERT(ok);
+ double progress = restoredJob->progress();
+ CPPUNIT_ASSERT(progress == 1.0);
+ ok = restoredJob->fetch();
+ CPPUNIT_ASSERT(ok);
+ std::vector<double> expectedResult = {0.5, 0.5, 0.5, 0.5};
+ const std::vector<double>& result = sample.outputs<double>().get("d");
+ CPPUNIT_ASSERT(expectedResult == result);
+ CPPUNIT_ASSERT(restoredJob->lastError().empty());
+ delete restoredJob;
+ }
+ Py_Finalize();
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( SampleTest );
+#include "TestMain.cxx"
--- /dev/null
+// Copyright (C) 2018 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, 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
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef YDEFX_SAMPLETEST_HXX
+#define YDEFX_SAMPLETEST_HXX
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class SampleTest: public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(SampleTest);
+ CPPUNIT_TEST(studyTest);
+ CPPUNIT_TEST_SUITE_END();
+public:
+ void setUp();
+ void tearDown();
+ void cleanUp();
+ void studyTest();
+};
+
+#endif // YDEFX_SAMPLETEST_HXX
--- /dev/null
+// Copyright (C) 2018 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, 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
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TextTestProgressListener.h>
+#include <cppunit/BriefTestProgressListener.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/TestRunner.h>
+#include <cppunit/TextTestRunner.h>
+#include <stdexcept>
+
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+
+// ============================================================================
+/*!
+ * Main program source for Unit Tests with cppunit package does not depend
+ * on actual tests, so we use the same for all partial unit tests.
+ */
+// ============================================================================
+
+int main(int argc, char* argv[])
+{
+ // --- Create the event manager and test controller
+ CPPUNIT_NS::TestResult controller;
+
+ // --- Add a listener that collects test result
+ CPPUNIT_NS::TestResultCollector result;
+ controller.addListener( &result );
+
+ // --- Add a listener that print dots as test run.
+#ifdef WIN32
+ CPPUNIT_NS::TextTestProgressListener progress;
+#else
+ CPPUNIT_NS::BriefTestProgressListener progress;
+#endif
+ controller.addListener( &progress );
+
+ // --- Get the top level suite from the registry
+
+ CPPUNIT_NS::Test *suite =
+ CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest();
+
+ // --- Adds the test to the list of test to run
+
+ CPPUNIT_NS::TestRunner runner;
+ runner.addTest( suite );
+ runner.run( controller);
+
+ // --- Print test in a compiler compatible format.
+ std::ofstream testFile;
+ testFile.open("test.log", std::ios::out | std::ios::app);
+ testFile << "------ Idefix test log:" << std::endl;
+ CPPUNIT_NS::CompilerOutputter outputter( &result, testFile );
+ outputter.write();
+
+ // --- Run the tests.
+
+ bool wasSucessful = result.wasSuccessful();
+ testFile.close();
+
+ // --- Return error code 1 if the one of test failed.
+
+ return wasSucessful ? 0 : 1;
+}
--- /dev/null
+#include "YacsStudyFunction.hxx"
+#include <fstream>
+#include <sstream>
+namespace ydefx
+{
+YacsStudyFunction::YacsStudyFunction()
+: _content()
+, _input()
+, _output()
+, _errors()
+{
+ _errors.push_back("Function \"_exec\" not found!");
+}
+
+YacsStudyFunction::~YacsStudyFunction(){}
+
+void YacsStudyFunction::loadFile(const std::string& path)
+{
+ std::ifstream infile(path.c_str());
+ std::stringstream buffer;
+ buffer << infile.rdbuf();
+ loadString(buffer.str());
+}
+
+void YacsStudyFunction::loadString(const std::string& value)
+{
+ _content = value;
+ _input.clear();
+ _output.clear();
+ _errors.clear();
+ // TODO: use YACS
+}
+
+void YacsStudyFunction::save(const std::string& path)
+{
+ std::ofstream outfile(path.c_str());
+ outfile << _content;
+}
+
+const std::string& YacsStudyFunction::content()const
+{
+ return _content;
+}
+
+const std::list<std::string>& YacsStudyFunction::inputNames()const
+{
+ return _input;
+}
+
+const std::list<std::string>& YacsStudyFunction::outputNames()const
+{
+ return _output;
+}
+
+const std::list<std::string>& YacsStudyFunction::errors()const
+{
+ return _errors;
+}
+
+}
--- /dev/null
+#ifndef YDEFX_YACSSTUDYFUNCTION_H
+#define YDEFX_YACSSTUDYFUNCTION_H
+#include "StudyFunction.hxx"
+namespace ydefx
+{
+//TODO not implemented!
+class YacsStudyFunction : StudyFunction
+{
+public:
+ YacsStudyFunction();
+ virtual ~YacsStudyFunction();
+ virtual void loadFile(const std::string& path);
+ virtual void loadString(const std::string&);
+ virtual void save(const std::string& path);
+ virtual const std::string& content()const;
+ virtual const std::list<std::string>& inputNames()const;
+ virtual const std::list<std::string>& outputNames()const;
+ virtual const std::list<std::string>& errors()const;
+private:
+ std::string _content;
+ std::list<std::string> _input;
+ std::list<std::string> _output;
+ std::list<std::string> _errors;
+};
+}
+#endif // YDEFX_YACSSTUDYFUNCTION_H
--- /dev/null
+SET(SCRIPTS
+ __init__.py
+ configuration.py
+ parameters.py
+ pyscript.py
+ pystudy.py
+ sample.py
+ samplecsviterator.py
+ samplecsvmanager.py
+ )
+
+INSTALL(FILES ${SCRIPTS} DESTINATION ${SALOME_INSTALL_PYTHON}/pydefx)
+ADD_SUBDIRECTORY(schemas)
--- /dev/null
+from .parameters import Parameters
+from .pyscript import PyScript
+from .pystudy import PyStudy
+from .sample import Sample
+
+import salome
+salome.salome_init()
--- /dev/null
+import salome
+import tempfile
+import pathlib
+
+def defaultWorkingDir(resource):
+ resManager= salome.lcc.getResourcesManager()
+ resource_definition = resManager.GetResourceDefinition(resource)
+ return resource_definition.working_directory
+
+def defaultNbBranches(resource):
+ resManager= salome.lcc.getResourcesManager()
+ resource_definition = resManager.GetResourceDefinition(resource)
+ ret = resource_definition.nb_node
+ if ret < 1:
+ ret = 1
+ return ret
+
+def defaultBaseDirectory():
+ """Return the default path to the root of any new result directory."""
+ return str(pathlib.Path.home())
+
+def newResultDirectory(basedir=None):
+ """ A new directory is created and the path is returned."""
+ if basedir is None :
+ basedir = defaultBaseDirectory()
+ return tempfile.mkdtemp(prefix='idefix',dir=basedir)
+
+def defaultWckey(resource="localhost"):
+ result = ""
+ if resource != "localhost":
+ result = "P11U5:CARBONES"
+ return result
+
--- /dev/null
+# -*- coding: utf-8 -*-
+import salome
+from . import configuration
+
+class Parameters:
+ def __init__(self, resource="localhost",
+ nb_branches=None, salome_parameters=None):
+ if salome_parameters is None :
+ job_params = salome.JobParameters()
+ job_params.job_type = "yacs_file"
+ job_params.resource_required = salome.ResourceParameters()
+ job_params.resource_required.name = resource
+ job_params.job_name = "idefix_job"
+ job_params.wckey = configuration.defaultWckey(resource)
+ job_params.work_directory = configuration.defaultWorkingDir(resource)
+ if nb_branches is None:
+ nb_branches = configuration.defaultNbBranches(resource)
+ job_params.resource_required.nb_proc = nb_branches
+ self.nb_branches = nb_branches
+ self.salome_parameters = job_params
+ else:
+ if nb_branches is None:
+ nb_branches = salome_parameters.resource_required.nb_proc
+ self.nb_branches = nb_branches
+ self.salome_parameters = salome_parameters
+
+ def configureResource(self, resource):
+ self.salome_parameters.resource_required.name = resource
+ self.salome_parameters.work_directory = configuration.defaultWorkingDir(
+ resource)
+ nb_branches = configuration.defaultNbBranches(resource)
+ self.salome_parameters.resource_required.nb_proc = nb_branches
+ self.nb_branches = nb_branches
+ self.salome_parameters.wckey = configuration.defaultWckey(resource)
+
+ def createResultDirectory(self, result_base_dir):
+ self.salome_parameters.result_directory = configuration.newResultDirectory(result_base_dir)
--- /dev/null
+# -*- coding: utf-8 -*-
+from . import sample
+
+class PyScriptException(Exception):
+ pass
+
+class PyScript:
+ def __init__(self):
+ self.script = ""
+
+ def loadFile(self,path):
+ with open(path, "r") as f:
+ self.script = f.read()
+
+ def loadString(self, script):
+ self.script = script
+
+ def saveFile(self, path):
+ with open(path, "w") as f:
+ f.write(self.script)
+
+ def getAllProperties(self):
+ """
+ functions,errors = myscript.getAllProperties()
+ print(errors) # list of syntax errors in the script
+ for f in functions:
+ print(f.name) # function name
+ print(f.inputs) # list of input variable names
+ print(f.outputs) # list of output variable names
+ print(f.errors) # list of py2yacs errors in the function
+ print(f.imports) # list of import statements in the function
+ """
+ import py2yacs
+ return py2yacs.get_properties(self.script)
+
+ def getFunctionProperties(self, fname):
+ """
+ Properties of the _exec function:
+ fn_properties, errors = myscript.getExecProperties("_exec")
+ fn_properties.name : "_exec"
+ fn_properties.inputs : list of input variable names
+ fn_properties.outputs : list of output variable names
+ fn_properties.errors : list of py2yacs errors in the function
+ fn_properties.imports : list of import statements in the function
+ errors : list of syntax errors in the script
+ fn_properties is None if the "_exec" function does not exist.
+ """
+ functions,errors = self.getAllProperties()
+ fn_properties = next((f for f in functions if f.name == fname), None)
+ return fn_properties, errors
+
+ def CreateEmptySample(self):
+ """
+ Create a sample with input and output variable names set.
+ """
+ fn = "_exec"
+ fn_properties, errors = self.getFunctionProperties(fn)
+ if len(errors) > 0:
+ error_string = "global errors:\n"
+ error_string += '\n'.join(errors)
+ raise PyScriptException(error_string)
+ if fn_properties is None:
+ raise PyScriptException("Function {} not found!".format(fn))
+ if len(fn_properties.errors) > 0:
+ error_string = "Errors in function {}:\n".format(fn)
+ error_string += '\n'.join(fn_properties.errors)
+ raise PyScriptException(error_string)
+ return sample.Sample(fn_properties.inputs, fn_properties.outputs)
+
--- /dev/null
+# -*- coding: utf-8 -*-
+import inspect
+import pathlib
+import tempfile
+import os
+import salome
+import json
+from . import samplecsvmanager
+from . import parameters
+from . import configuration
+
+def defaultSampleManager():
+ return samplecsvmanager.SampleManager()
+
+def prepareDirectoryForLaunch(sample, result_directory, nb_branches, script,
+ sampleManager=None):
+ """
+ sample : Sample type
+ result_directory : path to a result working directory.
+ nb_branches : int
+ script : string
+ return:
+ extra_in_files: list of files to add to salome_parameters.in_files
+ yacs_schema_path: path to the yacs schema (xml file).
+ """
+ if sampleManager is None:
+ sampleManager = defaultSampleManager()
+ # export sample to result_directory
+ inputFiles = sampleManager.prepareRun(sample, result_directory)
+ # export nbbranches
+ configpath = os.path.join(result_directory, "idefixconfig.json")
+ dicconfig = {}
+ dicconfig["nbbranches"] = nb_branches
+ dicconfig["studymodule"] = "idefixstudy"
+ dicconfig["sampleIterator"] = sampleManager.getModuleName()
+ with open(configpath, "w") as f:
+ json.dump(dicconfig, f, indent=2)
+ studypath = os.path.join(result_directory, "idefixstudy.py")
+ with open(studypath, "w") as f:
+ f.write(script)
+ # find generic schema
+ filename = inspect.getframeinfo(inspect.currentframe()).filename
+ install_directory = pathlib.Path(filename).resolve().parent
+ yacs_schema_path = os.path.join(install_directory, "schemas",
+ "idefix_pyschema.xml")
+ plugin_path = os.path.join(install_directory, "schemas", "plugin.py")
+ # create salome params
+ extra_in_files = []
+ extra_in_files.extend([configpath, studypath, plugin_path])
+ extra_in_files.extend(inputFiles)
+ return extra_in_files, yacs_schema_path
+
+class PyStudy:
+ JOB_DUMP_NAME = "jobDump.xml"
+ def __init__(self):
+ self.job_id = -1
+
+ # Study creation functions
+ def createNewJob(self, script, sample, params, sampleManager=None):
+ """
+ Create a new job out of those parameters:
+ script : string
+ sample : sample to be evaluated (Sample class)
+ params : job submission parameters (Parameters class)
+ The result directory will contain all the files needed for a launch and a
+ job is created but not launched.
+ """
+ self.sample = sample
+ self.params = params
+ self.params.salome_parameters.job_type = self.jobType()
+ if sampleManager is None:
+ self.sampleManager = defaultSampleManager()
+ else:
+ self.sampleManager = sampleManager
+ tmp_workdir = self.params.salome_parameters.result_directory
+ extra_in_files, yacs_schema_path = prepareDirectoryForLaunch(self.sample,
+ tmp_workdir,
+ self.params.nb_branches,
+ script,
+ self.sampleManager)
+ self.params.salome_parameters.in_files.extend(extra_in_files)
+ self.params.salome_parameters.job_file = yacs_schema_path
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ self.job_id = launcher.createJob(self.params.salome_parameters)
+ return self.job_id
+
+ def loadFromDirectory(self, path, sampleManager=None):
+ """
+ Recover a study from a result directory where a previous study was launched.
+ """
+ if sampleManager is None:
+ sampleManager = defaultSampleManager()
+ self.sampleManager = sampleManager
+ self.sample = sampleManager.loadSample(path)
+ job_string = loadJobString(path)
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ self.job_id = launcher.restoreJob(job_string)
+ if job_id >= 0:
+ salome_params = launcher.getJobParameters(job_id)
+ self.params = parameters.Parameters(salome_parameters=salome_params)
+ self.getResult()
+ return self.job_id
+
+ def loadFromString(self, jobstring, sampleManager=None):
+ """
+ Recover a study from a string which contains the description of the job.
+ This string can be obtained by launcher.dumpJob.
+ """
+ if sampleManager is None:
+ sampleManager = defaultSampleManager()
+ self.sampleManager = sampleManager
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ self.job_id = launcher.restoreJob(jobstring)
+ self.params = None
+ self.sample = None
+ if self.job_id >= 0:
+ salome_params = launcher.getJobParameters(self.job_id)
+ self.params = parameters.Parameters(salome_parameters=salome_params)
+ self.sample = sampleManager.loadSample(salome_params.result_directory)
+ self.getResult()
+ else:
+ raise Exception("Failed to restore the job.")
+
+ def loadFromId(self, jobid, sampleManager=None):
+ """
+ Connect the study to an already created job.
+ The result directory of the job must be already prepared for launch.
+ """
+ if jobid < 0:
+ return
+ if sampleManager is None:
+ sampleManager = defaultSampleManager()
+ self.sampleManager = sampleManager
+ self.job_id = jobid
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ salome_params = launcher.getJobParameters(job_id)
+ self.params = parameters.Parameters(salome_parameters=salome_params)
+ self.sample = sampleManager.loadSample(salome_params.result_directory)
+ self.script = None
+ return
+
+ # launch parameters functions
+ def jobType(self):
+ return "yacs_file"
+
+ # TODO: may be deprecated
+ def createDefaultParameters(self, resource="localhost",
+ nb_branches=None,
+ result_base_dir=None):
+ """
+ Create the Parameters structure and the result directory.
+ The result directory created here is needed by the job.
+ """
+ newParams = parameters.Parameters(resource, nb_branches)
+ newParams.salome_parameters.job_type = self.jobType()
+ newParams.salome_parameters.job_name = "idefix_job"
+ newParams.salome_parameters.result_directory = configuration.newResultDirectory(result_base_dir)
+ return newParams
+
+ # Job management functions
+ def launch(self):
+ """
+ The job should have been already created.
+ """
+ if self.job_id < 0 :
+ raise Exception("Nothing to launch! Job is not created!")
+ tmp_workdir = self.params.salome_parameters.result_directory
+ # run the job
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ launcher.launchJob(self.job_id)
+ #save the job
+ job_string = launcher.dumpJob(self.job_id)
+ jobDumpPath = os.path.join(tmp_workdir, PyStudy.JOB_DUMP_NAME)
+ with open(jobDumpPath, "w") as f:
+ f.write(job_string)
+
+ def getResult(self):
+ if self.job_id < 0 :
+ raise Exception("Cannot get the results if the job is not created!")
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ state = launcher.getJobState(self.job_id)
+ if state == "CREATED" :
+ raise Exception("Cannot get the results if the job is not launched!")
+ tmp_workdir = self.params.salome_parameters.result_directory
+ if 1 == launcher.getJobWorkFile(self.job_id,
+ self.sampleManager.getResultFileName(),
+ tmp_workdir):
+ self.sampleManager.loadResult(self.sample, tmp_workdir)
+ return self.sample
+
+ def getJobState(self):
+ if self.job_id < 0:
+ return "NOT_CREATED"
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ return launcher.getJobState(self.job_id)
+
+ def getProgress(self):
+ if self.job_id < 0:
+ return 0.0
+ state = self.getJobState()
+ if state == "CREATED" or state == "QUEUED" :
+ return 0.0
+ self.getResult();
+ return self.sample.progressRate()
+
+ def dump(self):
+ if self.job_id < 0 :
+ raise Exception("Cannot dump the job if it is not created!")
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ return launcher.dumpJob(self.job_id)
+
+ def wait(self, sleep_delay=10):
+ """ Wait for the end of the job """
+ launcher = salome.naming_service.Resolve('/SalomeLauncher')
+ job_id = self.job_id
+ jobState = launcher.getJobState(job_id)
+ import time
+ while jobState=="QUEUED" or jobState=="IN_PROCESS" or jobState=="RUNNING" :
+ time.sleep(sleep_delay)
+ jobState = launcher.getJobState(job_id)
+
+
+### Deprecated!!!!
+def dumpJob(result_directory, jobString):
+ """
+ Save the jobString to a file into result_directory.
+ result_directory is a string representing a path to a directory.
+ jobString is a string representing the serialization of a job.
+ Use loadJobString for reloading the string saved here.
+ """
+ jobDumpPath = os.path.join(result_directory, PyStudy.JOB_DUMP_NAME)
+ with open(jobDumpPath, "w") as f:
+ f.write(job_string)
+
+def loadJobString(result_directory):
+ """
+ Return the jobString saved by the dumpJob function into a directory.
+ Use dumpJob for saving a the string.
+ """
+ jobDumpPath = os.path.join(result_directory, PyStudy.JOB_DUMP_NAME)
+ with open(jobDumpPath, "r") as f:
+ job_string = f.read()
+ return job_string
+
--- /dev/null
+# -*- coding: utf-8 -*-
+import csv
+from enum import Enum
+
+class SampleException(Exception):
+ pass
+
+class PointState(Enum):
+ """
+ Is the point evaluated?
+ """
+ NO = 1
+ YES = 2
+ ERROR = 3
+
+class Sample:
+ def __init__(self, input_names, output_names):
+ """
+ input_names : gives the names and the order of input variables
+ output_names : gives the names and the order of output variables
+ """
+ if len(input_names) < 1 :
+ SampleException("A sample should have at least one input variable.")
+ self._input_names = input_names
+ self._output_names = output_names
+ self._input={}
+ self._output={} # {output_name:[output_values]}
+ self._messages=[] # list. Possible values in the list:
+ # None = point not evaluated,
+ # "" = results available, no error
+ # "any string"= error message for that index.
+
+ def __iter__(self):
+ return Dico_iter(self._input)
+
+ def inputIterator(self):
+ """
+ Iterate over input values.
+ """
+ return Dico_iter(self._input)
+
+ def setInputValues(self, inputDict):
+ if len(inputDict) != len(self._input_names):
+ raise SampleException("Incorrect number of keys!")
+ size = None
+ for name in self._input_names:
+ if size is None:
+ size = len(inputDict[name])
+ else:
+ if size != len(inputDict[name]):
+ raise SampleException("Inconsistency in input variable sizes!")
+ self._input = inputDict
+ # Fill all results with None
+ self._messages = [ None for i in range(size)]
+ self._output.clear()
+ for name in self._output_names :
+ self._output[name] = [ None for i in range(size)]
+
+ def addResult(self, index, out_values, message):
+ """
+ Add results for index.
+ """
+ if message is None:
+ message = ""
+ if message :
+ # case of error
+ for name in self._output_names :
+ self._output[name][index] = None
+ else:
+ for name in self._output_names :
+ self._output[name][index] = out_values[name]
+
+ self._messages[index] = message
+
+ def getPointState(self, index):
+ message = self._messages[index]
+ if message is None:
+ return PointState.NO
+ elif message:
+ return PointState.ERROR
+ else:
+ return PointState.YES
+
+ def findFirstId(self, in_values):
+ """
+ Find the index of the first point in the sample which contains exactly the
+ same input values as in in_values.
+ in_values is a dictionary with {name : value} of input variables in one
+ point.
+ """
+ if self._input_names is None or len(self._input_names) == 0 :
+ raise SampleException("List of input variables not defined.")
+ firstName = self._input_names[0]
+ maxSize = len(self._input[firstName])
+ curId = 0
+ foundId = -1
+ for curId in range(maxSize):
+ if self.isValidId(self, curId, in_values) :
+ foundId = curId
+ break
+ return foundId
+
+
+ def isValidId(self, idToCheck, inputToCheck):
+ """
+ Verify the input values at the idToCheck position are exactly the same as
+ the values in inputToCheck. Return True or False.
+ """
+ ok = True
+ try:
+ for name in self._input_names:
+ if self._input[name][idToCheck] != inputToCheck[name] :
+ ok = False
+ break
+ except:
+ ok = False
+ return ok
+
+ def checkId(self, idToCheck, inputToCheck):
+ """
+ Verify the input values at the idToCheck position are exactly the same as
+ the values in inputToCheck. Raise SampleException if it is not the case.
+ """
+ for name in self._input_names:
+ if not name in self._input:
+ raise SampleException(
+ "Variable name {} expected and not found ".format(name))
+ if self._input[name][idToCheck] != inputToCheck[name] :
+ raise SampleException(
+ "Expected value for variable {} is {} and found {}".format(name,
+ self._input[name][idToCheck],
+ inputToCheck[name]))
+
+ def getInputNames(self):
+ return self._input_names
+
+ def getOutputNames(self):
+ return self._output_names
+
+ def progressRate(self):
+ numberOfPoints = len(self._messages)
+ unevaluatedPoints = self._messages.count(None)
+ result = 0.0
+ if(numberOfPoints > 0):
+ result = 1.0 - unevaluatedPoints / numberOfPoints
+ return result
+
+ def __str__(self):
+ result = ""
+ for name in self._input_names:
+ result += name+","
+ for name in self._output_names:
+ result += name+","
+ result += "messages\n"
+ for i in range(len(self._messages)):
+ for name in self._input_names:
+ result += repr(self._input[name][i]) +","
+ for name in self._output_names:
+ result += repr(self._output[name][i]) +","
+ result += str(self._messages[i])+"\n"
+ return result
+
+class Dico_iter:
+ """
+ >>> si=Dico_iter({"x":[1,2,3], "y":["a","b","c"]})
+ >>> for i in si:
+ >>> print(i)
+ {'x': 1, 'y': 'a'}
+ {'x': 2, 'y': 'b'}
+ {'x': 3, 'y': 'c'}
+ """
+ def __init__(self, s):
+ self.iters={}
+ for k, v in s.items():
+ self.iters[k] = iter(v)
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ result = {}
+ for k,v in self.iters.items():
+ result[k] = next(v)
+ return result
--- /dev/null
+import csv
+import os
+
+def tofile(t):
+ result = {}
+ for k,v in t:
+ if isinstance(v, (int, float)):
+ result[k]=v
+ else:
+ result[k] = repr(e)
+ return result
+
+def fromfile(t):
+ result = {}
+ for k,v in t:
+ if isinstance(v, str):
+ result[k] = eval(e)
+ else:
+ result[k] = e
+ return result
+
+class SampleIterator:
+ DATAFILE = "idefixdata.csv"
+ OUTPUTNAMESFILE = "idefixoutputnames.csv"
+ RESULTFILE = "idefixresult.csv"
+ ERRORCOLUMN = "idefix_error"
+ IDCOLUMN ="idefix_id"
+ def __init__(self, directory=None):
+ if directory:
+ datapath = os.path.join(directory, SampleIterator.DATAFILE)
+ outputnamespath = os.path.join(directory, SampleIterator.OUTPUTNAMESFILE)
+ resultpath = os.path.join(directory, SampleIterator.RESULTFILE)
+ else:
+ datapath = SampleIterator.DATAFILE
+ outputnamespath = SampleIterator.OUTPUTNAMESFILE
+ resultpath = SampleIterator.RESULTFILE
+
+ self.iterNb = -1
+ self.datafile = open(datapath, newline='')
+ self.data = csv.DictReader(self.datafile, quoting=csv.QUOTE_NONNUMERIC)
+ result_columns = [SampleIterator.IDCOLUMN]
+ result_columns.extend(self.data.fieldnames)
+ self.outputnames = _loadOutputNames(outputnamespath)
+ result_columns.extend(self.outputnames)
+ result_columns.append(SampleIterator.ERRORCOLUMN)
+ self.result_file = open(resultpath, 'w', newline='')
+ self.result_csv = csv.DictWriter( self.result_file,
+ fieldnames=result_columns,
+ quoting=csv.QUOTE_NONNUMERIC )
+ self.result_csv.writeheader()
+ self.result_file.flush()
+
+ def addResult(self, currentId, currentInput, currentOutput, currentError):
+ """
+ currentId : int value
+ currentInput : dictionary {"input name":value}
+ currentOutput : result returned by _exec. Can be a tuple, a simple value or
+ None in case of error.
+ currentError : string or None if no error
+ """
+ currentRecord = {}
+ currentRecord[SampleIterator.IDCOLUMN] = currentId
+ for name in self.data.fieldnames:
+ currentRecord[name] = currentInput[name]
+ if currentError is None:
+ if len(self.outputnames) == 1 :
+ outputname = self.outputnames[0]
+ currentRecord[outputname] = currentOutput
+ elif len(self.outputnames) > 1 :
+ outputIter = iter(currentOutput)
+ for name in self.outputnames:
+ currentRecord[name] = next(outputIter)
+ else:
+ for name in self.outputnames:
+ currentRecord[name] = None
+ currentRecord[SampleIterator.ERRORCOLUMN] = currentError
+ self.result_csv.writerow(currentRecord)
+ self.result_file.flush()
+
+ def __next__(self):
+ self.iterNb += 1
+ return self.iterNb, next(self.data)
+ #TODO: we need to close the files somewhere, but we cannot do it here
+
+ def __iter__(self):
+ return self
+
+# Private functions
+def _loadOutputNames(filepath):
+ outputnames = []
+ with open(filepath, "r") as namesfile:
+ for line in namesfile:
+ line = line.rstrip() # remove whitespaces at the end
+ outputnames.append(line)
+ return outputnames
--- /dev/null
+import csv
+import inspect
+import os
+import pathlib
+from .samplecsviterator import SampleIterator
+from . import samplecsviterator
+from . import sample
+
+class SampleManager:
+ def __init__(self):
+ pass
+
+ def prepareRun(self, sample, directory):
+ """
+ Create a dump of the sample in the given directory.
+ Return a list of files to add to the input files list of the job.
+ """
+ datapath = os.path.join(directory, SampleIterator.DATAFILE)
+ with open(datapath, 'w', newline='') as csvfile:
+ writer = csv.DictWriter(csvfile,
+ fieldnames=sample.getInputNames(),
+ quoting=csv.QUOTE_NONNUMERIC )
+ writer.writeheader()
+ writer.writerows(sample.inputIterator())
+
+ outnamespath = os.path.join(directory, SampleIterator.OUTPUTNAMESFILE)
+ with open(outnamespath, 'w') as outputfile:
+ for v in sample.getOutputNames():
+ outputfile.write(v+'\n')
+ filename = inspect.getframeinfo(inspect.currentframe()).filename
+ install_directory = pathlib.Path(filename).resolve().parent
+ iteratorFile = os.path.join(install_directory, "samplecsviterator.py")
+ return [datapath,
+ outnamespath,
+ iteratorFile
+ ]
+
+ def loadResult(self, sample, directory):
+ """ The directory should contain a file with the name given by
+ getResultFileName. The results are loaded from that file to the sample.
+ Return the modified sample.
+ """
+ datapath = os.path.join(directory, SampleIterator.RESULTFILE)
+ with open(datapath, newline='') as datafile:
+ data = csv.DictReader(datafile, quoting=csv.QUOTE_NONNUMERIC)
+ for elt in data:
+ index = int(elt[SampleIterator.IDCOLUMN]) # float to int
+ input_vals = {}
+ for name in sample.getInputNames():
+ input_vals[name] = elt[name]
+ output_vals = {}
+ for name in sample.getOutputNames():
+ output_vals[name] = elt[name]
+ try:
+ sample.checkId(index, input_vals)
+ except Exception as err:
+ extraInfo = "Error on processing file {} index number {}:".format(
+ datapath, str(index))
+ raise Exception(extraInfo + str(err))
+ sample.addResult(index, output_vals, elt[SampleIterator.ERRORCOLUMN])
+ return sample
+
+ def loadSample(self, directory):
+ """ The directory should contain the files created by prepareRun. A new
+ sample object is created and returned from those files.
+ This function is used to recover a previous run.
+ """
+ outputnamesfile = os.path.join(directory, SampleIterator.OUTPUTNAMESFILE)
+ outputnames = samplecsviterator._loadOutputNames(outputnamesfile)
+ inputFilePath = os.path.join(directory, SampleIterator.DATAFILE)
+ with open(inputFilePath) as datafile:
+ data = csv.DictReader(datafile, quoting=csv.QUOTE_NONNUMERIC)
+ inputvalues = {}
+ for name in data.fieldnames:
+ inputvalues[name] = []
+ for line in data:
+ for name in data.fieldnames:
+ inputvalues[name].append(line[name])
+ result = sample.Sample(data.fieldnames, outputnames)
+ result.setInputValues(inputvalues)
+ return result
+
+
+ def getModuleName(self):
+ """
+ Return the module name which contains the class SampleIterator.
+ """
+ return "samplecsviterator"
+
+ def getResultFileName(self):
+ return SampleIterator.RESULTFILE
--- /dev/null
+SET(SCHEMA_FILES
+ plugin.py
+ idefix_pyschema.xml
+ )
+
+INSTALL(FILES ${SCHEMA_FILES} DESTINATION ${SALOME_INSTALL_PYTHON}/pydefx/schemas)
--- /dev/null
+<?xml version='1.0' encoding='iso-8859-1' ?>
+<proc name="newSchema_1">
+ <type name="string" kind="string"/>
+ <struct name="Engines/dataref">
+ <member name="ref" type="string"/>
+ </struct>
+ <type name="bool" kind="bool"/>
+ <sequence name="boolvec" content="bool"/>
+ <type name="double" kind="double"/>
+ <sequence name="dblevec" content="double"/>
+ <objref name="file" id="file"/>
+ <type name="int" kind="int"/>
+ <sequence name="intvec" content="int"/>
+ <struct name="stringpair">
+ <member name="name" type="string"/>
+ <member name="value" type="string"/>
+ </struct>
+ <sequence name="propvec" content="stringpair"/>
+ <objref name="pyobj" id="python:obj:1.0"/>
+ <sequence name="seqboolvec" content="boolvec"/>
+ <sequence name="seqdblevec" content="dblevec"/>
+ <sequence name="seqintvec" content="intvec"/>
+ <sequence name="seqpyobj" content="pyobj"/>
+ <sequence name="stringvec" content="string"/>
+ <sequence name="seqstringvec" content="stringvec"/>
+ <container name="DefaultContainer">
+ <property name="container_kind" value="Salome"/>
+ <property name="attached_on_cloning" value="0"/>
+ <property name="container_name" value="FactoryServer"/>
+ <property name="name" value="localhost"/>
+ </container>
+ <container name="container0">
+ <property name="container_kind" value="Salome"/>
+ <property name="attached_on_cloning" value="0"/>
+ </container>
+ <optimizer name="OptimizerLoop0" nbranch="4" loopWeight="-1" lib="plugin.py" entry="myalgosync">
+ <remote name="Solver" elementaryWeight="-1">
+ <script><code><![CDATA[import pickle
+import traceback
+import importlib
+inputvals=pickle.loads(i0.encode())
+idefixstudy=importlib.import_module(studymodule)
+error=None
+result=None
+try:
+ result=idefixstudy._exec(**inputvals)
+except Exception as e:
+ error=str(e)
+ traceback.print_exc()
+o0=pickle.dumps((error, result), protocol=0).decode()
+]]></code></script>
+ <load container="container0"/>
+ <inport name="i0" type="string"/>
+ <inport name="studymodule" type="string"/>
+ <outport name="o0" type="string"/>
+ </remote>
+ </optimizer>
+ <inline name="Initialisation">
+ <script><code><![CDATA[import json
+
+with open("idefixconfig.json", "r") as f:
+ config = json.load(f)
+nbbranches=config["nbbranches"]
+studymodule=config["studymodule"]
+]]></code></script>
+ <load container="DefaultContainer"/>
+ <outport name="nbbranches" type="int"/>
+ <outport name="studymodule" type="string"/>
+ </inline>
+ <control> <fromnode>Initialisation</fromnode> <tonode>OptimizerLoop0</tonode> </control>
+ <datalink control="false">
+ <fromnode>OptimizerLoop0</fromnode> <fromport>evalSamples</fromport>
+ <tonode>OptimizerLoop0.Solver</tonode> <toport>i0</toport>
+ </datalink>
+ <datalink control="false">
+ <fromnode>Initialisation</fromnode> <fromport>nbbranches</fromport>
+ <tonode>OptimizerLoop0</tonode> <toport>nbBranches</toport>
+ </datalink>
+ <datalink control="false">
+ <fromnode>Initialisation</fromnode> <fromport>studymodule</fromport>
+ <tonode>OptimizerLoop0.Solver</tonode> <toport>studymodule</toport>
+ </datalink>
+ <datalink control="false">
+ <fromnode>OptimizerLoop0.Solver</fromnode> <fromport>o0</fromport>
+ <tonode>OptimizerLoop0</tonode> <toport>evalResults</toport>
+ </datalink>
+ <parameter>
+ <tonode>OptimizerLoop0</tonode><toport>nbBranches</toport>
+ <value><int>4</int></value>
+ </parameter>
+ <presentation name="OptimizerLoop0" x="180.5" y="34.5" width="170" height="214" expanded="1" expx="180.5" expy="34.5" expWidth="170" expHeight="214" shownState="0"/>
+ <presentation name="OptimizerLoop0.Solver" x="8" y="120" width="158" height="90" expanded="1" expx="8" expy="120" expWidth="158" expHeight="90" shownState="0"/>
+ <presentation name="Initialisation" x="14" y="34" width="158" height="90" expanded="1" expx="14" expy="34" expWidth="158" expHeight="90" shownState="0"/>
+ <presentation name="__ROOT__" x="0" y="0" width="354.5" height="252.5" expanded="1" expx="0" expy="0" expWidth="354.5" expHeight="252.5" shownState="0"/>
+</proc>
--- /dev/null
+import SALOMERuntime
+import pickle
+import json
+import importlib
+
+class myalgosync(SALOMERuntime.OptimizerAlgSync):
+ def __init__(self):
+ SALOMERuntime.OptimizerAlgSync.__init__(self, None)
+
+ def setPool(self,pool):
+ """Must be implemented to set the pool"""
+ self.pool=pool
+
+ def getTCForIn(self):
+ """return typecode of type expected as Input of the internal node """
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("string")
+
+ def getTCForOut(self):
+ """return typecode of type expected as Output of the internal node"""
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("string")
+
+ def getTCForAlgoInit(self):
+ """return typecode of type expected as input for initialize """
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("string")
+
+ def getTCForAlgoResult(self):
+ """return typecode of type expected as output of the algorithm """
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("int")
+
+ def initialize(self,input):
+ """Optional method called on initialization.
+ The type of "input" is returned by "getTCForAlgoInit"
+ """
+ with open("idefixconfig.json", "r") as f:
+ self.config = json.load(f)
+
+ def start(self):
+ """Start to fill the pool with samples to evaluate."""
+ itModuleName = self.config["sampleIterator"]
+ itModule = importlib.import_module(itModuleName)
+ self.data = itModule.SampleIterator()
+ values=None
+ for i in range(0, self.getNbOfBranches()):
+ try:
+ newid, values = next(self.data)
+ self.pool.pushInSample(newid, pickle.dumps(values, protocol=0).decode())
+ except StopIteration:
+ pass
+
+ 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()
+ samplebyte=self.pool.getCurrentInSample().getStringValue().encode()
+ sample = pickle.loads(samplebyte)
+ resultbyte=self.pool.getCurrentOutSample().getStringValue().encode()
+ error,result = pickle.loads(resultbyte)
+ self.data.addResult(currentId, sample, result, error)
+ try:
+ newid, values = next(self.data)
+ self.pool.pushInSample(newid, pickle.dumps(values, protocol=0).decode())
+ except StopIteration:
+ pass
+
+ def finish(self):
+ """Optional method called when the algorithm has finished, successfully
+ or not, to perform any necessary clean up."""
+ self.pool.destroyAll()
+
+ def getAlgoResult(self):
+ """return the result of the algorithm.
+ The object returned is of type indicated by getTCForAlgoResult.
+ """
+ return 0
--- /dev/null
+#!/usr/bin/env python3
+#from inspect import currentframe, getframeinfo
+#from pathlib import Path
+
+#filename = getframeinfo(currentframe()).filename
+#parent = Path(filename).resolve().parent
+import inspect
+import pathlib
+
+filename = inspect.getframeinfo(inspect.currentframe()).filename
+parent = pathlib.Path(filename).resolve().parent
+print(parent)
--- /dev/null
+{
+ "nbbranches": 8,
+ "studymodule": "idefixstudy",
+ "sampleIterator": "samplecsviterator"
+}
\ No newline at end of file
--- /dev/null
+nbbranches=8
+studymodule="idefixstudy"
--- /dev/null
+"x","y","z"\r
+0.0,0.0,0.0\r
+1.0,0.0,0.0\r
+2.0,0.0,0.0\r
+3.0,0.0,0.0\r
+4.0,0.0,0.0\r
+5.0,0.0,0.0\r
+6.0,0.0,0.0\r
+7.0,0.0,0.0\r
+8.0,0.0,0.0\r
+9.0,0.0,0.0\r
+0.0,10.0,0.0\r
+1.0,10.0,0.0\r
+2.0,10.0,0.0\r
+3.0,10.0,0.0\r
+4.0,10.0,0.0\r
+5.0,10.0,0.0\r
+6.0,10.0,0.0\r
+7.0,10.0,0.0\r
+8.0,10.0,0.0\r
+9.0,10.0,0.0\r
+0.0,20.0,0.0\r
+1.0,20.0,0.0\r
+2.0,20.0,0.0\r
+3.0,20.0,0.0\r
+4.0,20.0,0.0\r
+5.0,20.0,0.0\r
+6.0,20.0,0.0\r
+7.0,20.0,0.0\r
+8.0,20.0,0.0\r
+9.0,20.0,0.0\r
+0.0,30.0,0.0\r
+1.0,30.0,0.0\r
+2.0,30.0,0.0\r
+3.0,30.0,0.0\r
+4.0,30.0,0.0\r
+5.0,30.0,0.0\r
+6.0,30.0,0.0\r
+7.0,30.0,0.0\r
+8.0,30.0,0.0\r
+9.0,30.0,0.0\r
+0.0,40.0,0.0\r
+1.0,40.0,0.0\r
+2.0,40.0,0.0\r
+3.0,40.0,0.0\r
+4.0,40.0,0.0\r
+5.0,40.0,0.0\r
+6.0,40.0,0.0\r
+7.0,40.0,0.0\r
+8.0,40.0,0.0\r
+9.0,40.0,0.0\r
+0.0,50.0,0.0\r
+1.0,50.0,0.0\r
+2.0,50.0,0.0\r
+3.0,50.0,0.0\r
+4.0,50.0,0.0\r
+5.0,50.0,0.0\r
+6.0,50.0,0.0\r
+7.0,50.0,0.0\r
+8.0,50.0,0.0\r
+9.0,50.0,0.0\r
+0.0,60.0,0.0\r
+1.0,60.0,0.0\r
+2.0,60.0,0.0\r
+3.0,60.0,0.0\r
+4.0,60.0,0.0\r
+5.0,60.0,0.0\r
+6.0,60.0,0.0\r
+7.0,60.0,0.0\r
+8.0,60.0,0.0\r
+9.0,60.0,0.0\r
+0.0,70.0,0.0\r
+1.0,70.0,0.0\r
+2.0,70.0,0.0\r
+3.0,70.0,0.0\r
+4.0,70.0,0.0\r
+5.0,70.0,0.0\r
+6.0,70.0,0.0\r
+7.0,70.0,0.0\r
+8.0,70.0,0.0\r
+9.0,70.0,0.0\r
+0.0,80.0,0.0\r
+1.0,80.0,0.0\r
+2.0,80.0,0.0\r
+3.0,80.0,0.0\r
+4.0,80.0,0.0\r
+5.0,80.0,0.0\r
+6.0,80.0,0.0\r
+7.0,80.0,0.0\r
+8.0,80.0,0.0\r
+9.0,80.0,0.0\r
+0.0,90.0,0.0\r
+1.0,90.0,0.0\r
+2.0,90.0,0.0\r
+3.0,90.0,0.0\r
+4.0,90.0,0.0\r
+5.0,90.0,0.0\r
+6.0,90.0,0.0\r
+7.0,90.0,0.0\r
+8.0,90.0,0.0\r
+9.0,90.0,0.0\r
+0.0,0.0,100.0\r
+1.0,0.0,100.0\r
+2.0,0.0,100.0\r
+3.0,0.0,100.0\r
+4.0,0.0,100.0\r
+5.0,0.0,100.0\r
+6.0,0.0,100.0\r
+7.0,0.0,100.0\r
+8.0,0.0,100.0\r
+9.0,0.0,100.0\r
+0.0,10.0,100.0\r
+1.0,10.0,100.0\r
+2.0,10.0,100.0\r
+3.0,10.0,100.0\r
+4.0,10.0,100.0\r
+5.0,10.0,100.0\r
+6.0,10.0,100.0\r
+7.0,10.0,100.0\r
+8.0,10.0,100.0\r
+9.0,10.0,100.0\r
+0.0,20.0,100.0\r
+1.0,20.0,100.0\r
+2.0,20.0,100.0\r
+3.0,20.0,100.0\r
+4.0,20.0,100.0\r
+5.0,20.0,100.0\r
+6.0,20.0,100.0\r
+7.0,20.0,100.0\r
+8.0,20.0,100.0\r
+9.0,20.0,100.0\r
+0.0,30.0,100.0\r
+1.0,30.0,100.0\r
+2.0,30.0,100.0\r
+3.0,30.0,100.0\r
+4.0,30.0,100.0\r
+5.0,30.0,100.0\r
+6.0,30.0,100.0\r
+7.0,30.0,100.0\r
+8.0,30.0,100.0\r
+9.0,30.0,100.0\r
+0.0,40.0,100.0\r
+1.0,40.0,100.0\r
+2.0,40.0,100.0\r
+3.0,40.0,100.0\r
+4.0,40.0,100.0\r
+5.0,40.0,100.0\r
+6.0,40.0,100.0\r
+7.0,40.0,100.0\r
+8.0,40.0,100.0\r
+9.0,40.0,100.0\r
+0.0,50.0,100.0\r
+1.0,50.0,100.0\r
+2.0,50.0,100.0\r
+3.0,50.0,100.0\r
+4.0,50.0,100.0\r
+5.0,50.0,100.0\r
+6.0,50.0,100.0\r
+7.0,50.0,100.0\r
+8.0,50.0,100.0\r
+9.0,50.0,100.0\r
+0.0,60.0,100.0\r
+1.0,60.0,100.0\r
+2.0,60.0,100.0\r
+3.0,60.0,100.0\r
+4.0,60.0,100.0\r
+5.0,60.0,100.0\r
+6.0,60.0,100.0\r
+7.0,60.0,100.0\r
+8.0,60.0,100.0\r
+9.0,60.0,100.0\r
+0.0,70.0,100.0\r
+1.0,70.0,100.0\r
+2.0,70.0,100.0\r
+3.0,70.0,100.0\r
+4.0,70.0,100.0\r
+5.0,70.0,100.0\r
+6.0,70.0,100.0\r
+7.0,70.0,100.0\r
+8.0,70.0,100.0\r
+9.0,70.0,100.0\r
+0.0,80.0,100.0\r
+1.0,80.0,100.0\r
+2.0,80.0,100.0\r
+3.0,80.0,100.0\r
+4.0,80.0,100.0\r
+5.0,80.0,100.0\r
+6.0,80.0,100.0\r
+7.0,80.0,100.0\r
+8.0,80.0,100.0\r
+9.0,80.0,100.0\r
+0.0,90.0,100.0\r
+1.0,90.0,100.0\r
+2.0,90.0,100.0\r
+3.0,90.0,100.0\r
+4.0,90.0,100.0\r
+5.0,90.0,100.0\r
+6.0,90.0,100.0\r
+7.0,90.0,100.0\r
+8.0,90.0,100.0\r
+9.0,90.0,100.0\r
+0.0,0.0,200.0\r
+1.0,0.0,200.0\r
+2.0,0.0,200.0\r
+3.0,0.0,200.0\r
+4.0,0.0,200.0\r
+5.0,0.0,200.0\r
+6.0,0.0,200.0\r
+7.0,0.0,200.0\r
+8.0,0.0,200.0\r
+9.0,0.0,200.0\r
+0.0,10.0,200.0\r
+1.0,10.0,200.0\r
+2.0,10.0,200.0\r
+3.0,10.0,200.0\r
+4.0,10.0,200.0\r
+5.0,10.0,200.0\r
+6.0,10.0,200.0\r
+7.0,10.0,200.0\r
+8.0,10.0,200.0\r
+9.0,10.0,200.0\r
+0.0,20.0,200.0\r
+1.0,20.0,200.0\r
+2.0,20.0,200.0\r
+3.0,20.0,200.0\r
+4.0,20.0,200.0\r
+5.0,20.0,200.0\r
+6.0,20.0,200.0\r
+7.0,20.0,200.0\r
+8.0,20.0,200.0\r
+9.0,20.0,200.0\r
+0.0,30.0,200.0\r
+1.0,30.0,200.0\r
+2.0,30.0,200.0\r
+3.0,30.0,200.0\r
+4.0,30.0,200.0\r
+5.0,30.0,200.0\r
+6.0,30.0,200.0\r
+7.0,30.0,200.0\r
+8.0,30.0,200.0\r
+9.0,30.0,200.0\r
+0.0,40.0,200.0\r
+1.0,40.0,200.0\r
+2.0,40.0,200.0\r
+3.0,40.0,200.0\r
+4.0,40.0,200.0\r
+5.0,40.0,200.0\r
+6.0,40.0,200.0\r
+7.0,40.0,200.0\r
+8.0,40.0,200.0\r
+9.0,40.0,200.0\r
+0.0,50.0,200.0\r
+1.0,50.0,200.0\r
+2.0,50.0,200.0\r
+3.0,50.0,200.0\r
+4.0,50.0,200.0\r
+5.0,50.0,200.0\r
+6.0,50.0,200.0\r
+7.0,50.0,200.0\r
+8.0,50.0,200.0\r
+9.0,50.0,200.0\r
+0.0,60.0,200.0\r
+1.0,60.0,200.0\r
+2.0,60.0,200.0\r
+3.0,60.0,200.0\r
+4.0,60.0,200.0\r
+5.0,60.0,200.0\r
+6.0,60.0,200.0\r
+7.0,60.0,200.0\r
+8.0,60.0,200.0\r
+9.0,60.0,200.0\r
+0.0,70.0,200.0\r
+1.0,70.0,200.0\r
+2.0,70.0,200.0\r
+3.0,70.0,200.0\r
+4.0,70.0,200.0\r
+5.0,70.0,200.0\r
+6.0,70.0,200.0\r
+7.0,70.0,200.0\r
+8.0,70.0,200.0\r
+9.0,70.0,200.0\r
+0.0,80.0,200.0\r
+1.0,80.0,200.0\r
+2.0,80.0,200.0\r
+3.0,80.0,200.0\r
+4.0,80.0,200.0\r
+5.0,80.0,200.0\r
+6.0,80.0,200.0\r
+7.0,80.0,200.0\r
+8.0,80.0,200.0\r
+9.0,80.0,200.0\r
+0.0,90.0,200.0\r
+1.0,90.0,200.0\r
+2.0,90.0,200.0\r
+3.0,90.0,200.0\r
+4.0,90.0,200.0\r
+5.0,90.0,200.0\r
+6.0,90.0,200.0\r
+7.0,90.0,200.0\r
+8.0,90.0,200.0\r
+9.0,90.0,200.0\r
+0.0,0.0,300.0\r
+1.0,0.0,300.0\r
+2.0,0.0,300.0\r
+3.0,0.0,300.0\r
+4.0,0.0,300.0\r
+5.0,0.0,300.0\r
+6.0,0.0,300.0\r
+7.0,0.0,300.0\r
+8.0,0.0,300.0\r
+9.0,0.0,300.0\r
+0.0,10.0,300.0\r
+1.0,10.0,300.0\r
+2.0,10.0,300.0\r
+3.0,10.0,300.0\r
+4.0,10.0,300.0\r
+5.0,10.0,300.0\r
+6.0,10.0,300.0\r
+7.0,10.0,300.0\r
+8.0,10.0,300.0\r
+9.0,10.0,300.0\r
+0.0,20.0,300.0\r
+1.0,20.0,300.0\r
+2.0,20.0,300.0\r
+3.0,20.0,300.0\r
+4.0,20.0,300.0\r
+5.0,20.0,300.0\r
+6.0,20.0,300.0\r
+7.0,20.0,300.0\r
+8.0,20.0,300.0\r
+9.0,20.0,300.0\r
+0.0,30.0,300.0\r
+1.0,30.0,300.0\r
+2.0,30.0,300.0\r
+3.0,30.0,300.0\r
+4.0,30.0,300.0\r
+5.0,30.0,300.0\r
+6.0,30.0,300.0\r
+7.0,30.0,300.0\r
+8.0,30.0,300.0\r
+9.0,30.0,300.0\r
+0.0,40.0,300.0\r
+1.0,40.0,300.0\r
+2.0,40.0,300.0\r
+3.0,40.0,300.0\r
+4.0,40.0,300.0\r
+5.0,40.0,300.0\r
+6.0,40.0,300.0\r
+7.0,40.0,300.0\r
+8.0,40.0,300.0\r
+9.0,40.0,300.0\r
+0.0,50.0,300.0\r
+1.0,50.0,300.0\r
+2.0,50.0,300.0\r
+3.0,50.0,300.0\r
+4.0,50.0,300.0\r
+5.0,50.0,300.0\r
+6.0,50.0,300.0\r
+7.0,50.0,300.0\r
+8.0,50.0,300.0\r
+9.0,50.0,300.0\r
+0.0,60.0,300.0\r
+1.0,60.0,300.0\r
+2.0,60.0,300.0\r
+3.0,60.0,300.0\r
+4.0,60.0,300.0\r
+5.0,60.0,300.0\r
+6.0,60.0,300.0\r
+7.0,60.0,300.0\r
+8.0,60.0,300.0\r
+9.0,60.0,300.0\r
+0.0,70.0,300.0\r
+1.0,70.0,300.0\r
+2.0,70.0,300.0\r
+3.0,70.0,300.0\r
+4.0,70.0,300.0\r
+5.0,70.0,300.0\r
+6.0,70.0,300.0\r
+7.0,70.0,300.0\r
+8.0,70.0,300.0\r
+9.0,70.0,300.0\r
+0.0,80.0,300.0\r
+1.0,80.0,300.0\r
+2.0,80.0,300.0\r
+3.0,80.0,300.0\r
+4.0,80.0,300.0\r
+5.0,80.0,300.0\r
+6.0,80.0,300.0\r
+7.0,80.0,300.0\r
+8.0,80.0,300.0\r
+9.0,80.0,300.0\r
+0.0,90.0,300.0\r
+1.0,90.0,300.0\r
+2.0,90.0,300.0\r
+3.0,90.0,300.0\r
+4.0,90.0,300.0\r
+5.0,90.0,300.0\r
+6.0,90.0,300.0\r
+7.0,90.0,300.0\r
+8.0,90.0,300.0\r
+9.0,90.0,300.0\r
+0.0,0.0,400.0\r
+1.0,0.0,400.0\r
+2.0,0.0,400.0\r
+3.0,0.0,400.0\r
+4.0,0.0,400.0\r
+5.0,0.0,400.0\r
+6.0,0.0,400.0\r
+7.0,0.0,400.0\r
+8.0,0.0,400.0\r
+9.0,0.0,400.0\r
+0.0,10.0,400.0\r
+1.0,10.0,400.0\r
+2.0,10.0,400.0\r
+3.0,10.0,400.0\r
+4.0,10.0,400.0\r
+5.0,10.0,400.0\r
+6.0,10.0,400.0\r
+7.0,10.0,400.0\r
+8.0,10.0,400.0\r
+9.0,10.0,400.0\r
+0.0,20.0,400.0\r
+1.0,20.0,400.0\r
+2.0,20.0,400.0\r
+3.0,20.0,400.0\r
+4.0,20.0,400.0\r
+5.0,20.0,400.0\r
+6.0,20.0,400.0\r
+7.0,20.0,400.0\r
+8.0,20.0,400.0\r
+9.0,20.0,400.0\r
+0.0,30.0,400.0\r
+1.0,30.0,400.0\r
+2.0,30.0,400.0\r
+3.0,30.0,400.0\r
+4.0,30.0,400.0\r
+5.0,30.0,400.0\r
+6.0,30.0,400.0\r
+7.0,30.0,400.0\r
+8.0,30.0,400.0\r
+9.0,30.0,400.0\r
+0.0,40.0,400.0\r
+1.0,40.0,400.0\r
+2.0,40.0,400.0\r
+3.0,40.0,400.0\r
+4.0,40.0,400.0\r
+5.0,40.0,400.0\r
+6.0,40.0,400.0\r
+7.0,40.0,400.0\r
+8.0,40.0,400.0\r
+9.0,40.0,400.0\r
+0.0,50.0,400.0\r
+1.0,50.0,400.0\r
+2.0,50.0,400.0\r
+3.0,50.0,400.0\r
+4.0,50.0,400.0\r
+5.0,50.0,400.0\r
+6.0,50.0,400.0\r
+7.0,50.0,400.0\r
+8.0,50.0,400.0\r
+9.0,50.0,400.0\r
+0.0,60.0,400.0\r
+1.0,60.0,400.0\r
+2.0,60.0,400.0\r
+3.0,60.0,400.0\r
+4.0,60.0,400.0\r
+5.0,60.0,400.0\r
+6.0,60.0,400.0\r
+7.0,60.0,400.0\r
+8.0,60.0,400.0\r
+9.0,60.0,400.0\r
+0.0,70.0,400.0\r
+1.0,70.0,400.0\r
+2.0,70.0,400.0\r
+3.0,70.0,400.0\r
+4.0,70.0,400.0\r
+5.0,70.0,400.0\r
+6.0,70.0,400.0\r
+7.0,70.0,400.0\r
+8.0,70.0,400.0\r
+9.0,70.0,400.0\r
+0.0,80.0,400.0\r
+1.0,80.0,400.0\r
+2.0,80.0,400.0\r
+3.0,80.0,400.0\r
+4.0,80.0,400.0\r
+5.0,80.0,400.0\r
+6.0,80.0,400.0\r
+7.0,80.0,400.0\r
+8.0,80.0,400.0\r
+9.0,80.0,400.0\r
+0.0,90.0,400.0\r
+1.0,90.0,400.0\r
+2.0,90.0,400.0\r
+3.0,90.0,400.0\r
+4.0,90.0,400.0\r
+5.0,90.0,400.0\r
+6.0,90.0,400.0\r
+7.0,90.0,400.0\r
+8.0,90.0,400.0\r
+9.0,90.0,400.0\r
+0.0,0.0,500.0\r
+1.0,0.0,500.0\r
+2.0,0.0,500.0\r
+3.0,0.0,500.0\r
+4.0,0.0,500.0\r
+5.0,0.0,500.0\r
+6.0,0.0,500.0\r
+7.0,0.0,500.0\r
+8.0,0.0,500.0\r
+9.0,0.0,500.0\r
+0.0,10.0,500.0\r
+1.0,10.0,500.0\r
+2.0,10.0,500.0\r
+3.0,10.0,500.0\r
+4.0,10.0,500.0\r
+5.0,10.0,500.0\r
+6.0,10.0,500.0\r
+7.0,10.0,500.0\r
+8.0,10.0,500.0\r
+9.0,10.0,500.0\r
+0.0,20.0,500.0\r
+1.0,20.0,500.0\r
+2.0,20.0,500.0\r
+3.0,20.0,500.0\r
+4.0,20.0,500.0\r
+5.0,20.0,500.0\r
+6.0,20.0,500.0\r
+7.0,20.0,500.0\r
+8.0,20.0,500.0\r
+9.0,20.0,500.0\r
+0.0,30.0,500.0\r
+1.0,30.0,500.0\r
+2.0,30.0,500.0\r
+3.0,30.0,500.0\r
+4.0,30.0,500.0\r
+5.0,30.0,500.0\r
+6.0,30.0,500.0\r
+7.0,30.0,500.0\r
+8.0,30.0,500.0\r
+9.0,30.0,500.0\r
+0.0,40.0,500.0\r
+1.0,40.0,500.0\r
+2.0,40.0,500.0\r
+3.0,40.0,500.0\r
+4.0,40.0,500.0\r
+5.0,40.0,500.0\r
+6.0,40.0,500.0\r
+7.0,40.0,500.0\r
+8.0,40.0,500.0\r
+9.0,40.0,500.0\r
+0.0,50.0,500.0\r
+1.0,50.0,500.0\r
+2.0,50.0,500.0\r
+3.0,50.0,500.0\r
+4.0,50.0,500.0\r
+5.0,50.0,500.0\r
+6.0,50.0,500.0\r
+7.0,50.0,500.0\r
+8.0,50.0,500.0\r
+9.0,50.0,500.0\r
+0.0,60.0,500.0\r
+1.0,60.0,500.0\r
+2.0,60.0,500.0\r
+3.0,60.0,500.0\r
+4.0,60.0,500.0\r
+5.0,60.0,500.0\r
+6.0,60.0,500.0\r
+7.0,60.0,500.0\r
+8.0,60.0,500.0\r
+9.0,60.0,500.0\r
+0.0,70.0,500.0\r
+1.0,70.0,500.0\r
+2.0,70.0,500.0\r
+3.0,70.0,500.0\r
+4.0,70.0,500.0\r
+5.0,70.0,500.0\r
+6.0,70.0,500.0\r
+7.0,70.0,500.0\r
+8.0,70.0,500.0\r
+9.0,70.0,500.0\r
+0.0,80.0,500.0\r
+1.0,80.0,500.0\r
+2.0,80.0,500.0\r
+3.0,80.0,500.0\r
+4.0,80.0,500.0\r
+5.0,80.0,500.0\r
+6.0,80.0,500.0\r
+7.0,80.0,500.0\r
+8.0,80.0,500.0\r
+9.0,80.0,500.0\r
+0.0,90.0,500.0\r
+1.0,90.0,500.0\r
+2.0,90.0,500.0\r
+3.0,90.0,500.0\r
+4.0,90.0,500.0\r
+5.0,90.0,500.0\r
+6.0,90.0,500.0\r
+7.0,90.0,500.0\r
+8.0,90.0,500.0\r
+9.0,90.0,500.0\r
+0.0,0.0,600.0\r
+1.0,0.0,600.0\r
+2.0,0.0,600.0\r
+3.0,0.0,600.0\r
+4.0,0.0,600.0\r
+5.0,0.0,600.0\r
+6.0,0.0,600.0\r
+7.0,0.0,600.0\r
+8.0,0.0,600.0\r
+9.0,0.0,600.0\r
+0.0,10.0,600.0\r
+1.0,10.0,600.0\r
+2.0,10.0,600.0\r
+3.0,10.0,600.0\r
+4.0,10.0,600.0\r
+5.0,10.0,600.0\r
+6.0,10.0,600.0\r
+7.0,10.0,600.0\r
+8.0,10.0,600.0\r
+9.0,10.0,600.0\r
+0.0,20.0,600.0\r
+1.0,20.0,600.0\r
+2.0,20.0,600.0\r
+3.0,20.0,600.0\r
+4.0,20.0,600.0\r
+5.0,20.0,600.0\r
+6.0,20.0,600.0\r
+7.0,20.0,600.0\r
+8.0,20.0,600.0\r
+9.0,20.0,600.0\r
+0.0,30.0,600.0\r
+1.0,30.0,600.0\r
+2.0,30.0,600.0\r
+3.0,30.0,600.0\r
+4.0,30.0,600.0\r
+5.0,30.0,600.0\r
+6.0,30.0,600.0\r
+7.0,30.0,600.0\r
+8.0,30.0,600.0\r
+9.0,30.0,600.0\r
+0.0,40.0,600.0\r
+1.0,40.0,600.0\r
+2.0,40.0,600.0\r
+3.0,40.0,600.0\r
+4.0,40.0,600.0\r
+5.0,40.0,600.0\r
+6.0,40.0,600.0\r
+7.0,40.0,600.0\r
+8.0,40.0,600.0\r
+9.0,40.0,600.0\r
+0.0,50.0,600.0\r
+1.0,50.0,600.0\r
+2.0,50.0,600.0\r
+3.0,50.0,600.0\r
+4.0,50.0,600.0\r
+5.0,50.0,600.0\r
+6.0,50.0,600.0\r
+7.0,50.0,600.0\r
+8.0,50.0,600.0\r
+9.0,50.0,600.0\r
+0.0,60.0,600.0\r
+1.0,60.0,600.0\r
+2.0,60.0,600.0\r
+3.0,60.0,600.0\r
+4.0,60.0,600.0\r
+5.0,60.0,600.0\r
+6.0,60.0,600.0\r
+7.0,60.0,600.0\r
+8.0,60.0,600.0\r
+9.0,60.0,600.0\r
+0.0,70.0,600.0\r
+1.0,70.0,600.0\r
+2.0,70.0,600.0\r
+3.0,70.0,600.0\r
+4.0,70.0,600.0\r
+5.0,70.0,600.0\r
+6.0,70.0,600.0\r
+7.0,70.0,600.0\r
+8.0,70.0,600.0\r
+9.0,70.0,600.0\r
+0.0,80.0,600.0\r
+1.0,80.0,600.0\r
+2.0,80.0,600.0\r
+3.0,80.0,600.0\r
+4.0,80.0,600.0\r
+5.0,80.0,600.0\r
+6.0,80.0,600.0\r
+7.0,80.0,600.0\r
+8.0,80.0,600.0\r
+9.0,80.0,600.0\r
+0.0,90.0,600.0\r
+1.0,90.0,600.0\r
+2.0,90.0,600.0\r
+3.0,90.0,600.0\r
+4.0,90.0,600.0\r
+5.0,90.0,600.0\r
+6.0,90.0,600.0\r
+7.0,90.0,600.0\r
+8.0,90.0,600.0\r
+9.0,90.0,600.0\r
+0.0,0.0,700.0\r
+1.0,0.0,700.0\r
+2.0,0.0,700.0\r
+3.0,0.0,700.0\r
+4.0,0.0,700.0\r
+5.0,0.0,700.0\r
+6.0,0.0,700.0\r
+7.0,0.0,700.0\r
+8.0,0.0,700.0\r
+9.0,0.0,700.0\r
+0.0,10.0,700.0\r
+1.0,10.0,700.0\r
+2.0,10.0,700.0\r
+3.0,10.0,700.0\r
+4.0,10.0,700.0\r
+5.0,10.0,700.0\r
+6.0,10.0,700.0\r
+7.0,10.0,700.0\r
+8.0,10.0,700.0\r
+9.0,10.0,700.0\r
+0.0,20.0,700.0\r
+1.0,20.0,700.0\r
+2.0,20.0,700.0\r
+3.0,20.0,700.0\r
+4.0,20.0,700.0\r
+5.0,20.0,700.0\r
+6.0,20.0,700.0\r
+7.0,20.0,700.0\r
+8.0,20.0,700.0\r
+9.0,20.0,700.0\r
+0.0,30.0,700.0\r
+1.0,30.0,700.0\r
+2.0,30.0,700.0\r
+3.0,30.0,700.0\r
+4.0,30.0,700.0\r
+5.0,30.0,700.0\r
+6.0,30.0,700.0\r
+7.0,30.0,700.0\r
+8.0,30.0,700.0\r
+9.0,30.0,700.0\r
+0.0,40.0,700.0\r
+1.0,40.0,700.0\r
+2.0,40.0,700.0\r
+3.0,40.0,700.0\r
+4.0,40.0,700.0\r
+5.0,40.0,700.0\r
+6.0,40.0,700.0\r
+7.0,40.0,700.0\r
+8.0,40.0,700.0\r
+9.0,40.0,700.0\r
+0.0,50.0,700.0\r
+1.0,50.0,700.0\r
+2.0,50.0,700.0\r
+3.0,50.0,700.0\r
+4.0,50.0,700.0\r
+5.0,50.0,700.0\r
+6.0,50.0,700.0\r
+7.0,50.0,700.0\r
+8.0,50.0,700.0\r
+9.0,50.0,700.0\r
+0.0,60.0,700.0\r
+1.0,60.0,700.0\r
+2.0,60.0,700.0\r
+3.0,60.0,700.0\r
+4.0,60.0,700.0\r
+5.0,60.0,700.0\r
+6.0,60.0,700.0\r
+7.0,60.0,700.0\r
+8.0,60.0,700.0\r
+9.0,60.0,700.0\r
+0.0,70.0,700.0\r
+1.0,70.0,700.0\r
+2.0,70.0,700.0\r
+3.0,70.0,700.0\r
+4.0,70.0,700.0\r
+5.0,70.0,700.0\r
+6.0,70.0,700.0\r
+7.0,70.0,700.0\r
+8.0,70.0,700.0\r
+9.0,70.0,700.0\r
+0.0,80.0,700.0\r
+1.0,80.0,700.0\r
+2.0,80.0,700.0\r
+3.0,80.0,700.0\r
+4.0,80.0,700.0\r
+5.0,80.0,700.0\r
+6.0,80.0,700.0\r
+7.0,80.0,700.0\r
+8.0,80.0,700.0\r
+9.0,80.0,700.0\r
+0.0,90.0,700.0\r
+1.0,90.0,700.0\r
+2.0,90.0,700.0\r
+3.0,90.0,700.0\r
+4.0,90.0,700.0\r
+5.0,90.0,700.0\r
+6.0,90.0,700.0\r
+7.0,90.0,700.0\r
+8.0,90.0,700.0\r
+9.0,90.0,700.0\r
+0.0,0.0,800.0\r
+1.0,0.0,800.0\r
+2.0,0.0,800.0\r
+3.0,0.0,800.0\r
+4.0,0.0,800.0\r
+5.0,0.0,800.0\r
+6.0,0.0,800.0\r
+7.0,0.0,800.0\r
+8.0,0.0,800.0\r
+9.0,0.0,800.0\r
+0.0,10.0,800.0\r
+1.0,10.0,800.0\r
+2.0,10.0,800.0\r
+3.0,10.0,800.0\r
+4.0,10.0,800.0\r
+5.0,10.0,800.0\r
+6.0,10.0,800.0\r
+7.0,10.0,800.0\r
+8.0,10.0,800.0\r
+9.0,10.0,800.0\r
+0.0,20.0,800.0\r
+1.0,20.0,800.0\r
+2.0,20.0,800.0\r
+3.0,20.0,800.0\r
+4.0,20.0,800.0\r
+5.0,20.0,800.0\r
+6.0,20.0,800.0\r
+7.0,20.0,800.0\r
+8.0,20.0,800.0\r
+9.0,20.0,800.0\r
+0.0,30.0,800.0\r
+1.0,30.0,800.0\r
+2.0,30.0,800.0\r
+3.0,30.0,800.0\r
+4.0,30.0,800.0\r
+5.0,30.0,800.0\r
+6.0,30.0,800.0\r
+7.0,30.0,800.0\r
+8.0,30.0,800.0\r
+9.0,30.0,800.0\r
+0.0,40.0,800.0\r
+1.0,40.0,800.0\r
+2.0,40.0,800.0\r
+3.0,40.0,800.0\r
+4.0,40.0,800.0\r
+5.0,40.0,800.0\r
+6.0,40.0,800.0\r
+7.0,40.0,800.0\r
+8.0,40.0,800.0\r
+9.0,40.0,800.0\r
+0.0,50.0,800.0\r
+1.0,50.0,800.0\r
+2.0,50.0,800.0\r
+3.0,50.0,800.0\r
+4.0,50.0,800.0\r
+5.0,50.0,800.0\r
+6.0,50.0,800.0\r
+7.0,50.0,800.0\r
+8.0,50.0,800.0\r
+9.0,50.0,800.0\r
+0.0,60.0,800.0\r
+1.0,60.0,800.0\r
+2.0,60.0,800.0\r
+3.0,60.0,800.0\r
+4.0,60.0,800.0\r
+5.0,60.0,800.0\r
+6.0,60.0,800.0\r
+7.0,60.0,800.0\r
+8.0,60.0,800.0\r
+9.0,60.0,800.0\r
+0.0,70.0,800.0\r
+1.0,70.0,800.0\r
+2.0,70.0,800.0\r
+3.0,70.0,800.0\r
+4.0,70.0,800.0\r
+5.0,70.0,800.0\r
+6.0,70.0,800.0\r
+7.0,70.0,800.0\r
+8.0,70.0,800.0\r
+9.0,70.0,800.0\r
+0.0,80.0,800.0\r
+1.0,80.0,800.0\r
+2.0,80.0,800.0\r
+3.0,80.0,800.0\r
+4.0,80.0,800.0\r
+5.0,80.0,800.0\r
+6.0,80.0,800.0\r
+7.0,80.0,800.0\r
+8.0,80.0,800.0\r
+9.0,80.0,800.0\r
+0.0,90.0,800.0\r
+1.0,90.0,800.0\r
+2.0,90.0,800.0\r
+3.0,90.0,800.0\r
+4.0,90.0,800.0\r
+5.0,90.0,800.0\r
+6.0,90.0,800.0\r
+7.0,90.0,800.0\r
+8.0,90.0,800.0\r
+9.0,90.0,800.0\r
+0.0,0.0,900.0\r
+1.0,0.0,900.0\r
+2.0,0.0,900.0\r
+3.0,0.0,900.0\r
+4.0,0.0,900.0\r
+5.0,0.0,900.0\r
+6.0,0.0,900.0\r
+7.0,0.0,900.0\r
+8.0,0.0,900.0\r
+9.0,0.0,900.0\r
+0.0,10.0,900.0\r
+1.0,10.0,900.0\r
+2.0,10.0,900.0\r
+3.0,10.0,900.0\r
+4.0,10.0,900.0\r
+5.0,10.0,900.0\r
+6.0,10.0,900.0\r
+7.0,10.0,900.0\r
+8.0,10.0,900.0\r
+9.0,10.0,900.0\r
+0.0,20.0,900.0\r
+1.0,20.0,900.0\r
+2.0,20.0,900.0\r
+3.0,20.0,900.0\r
+4.0,20.0,900.0\r
+5.0,20.0,900.0\r
+6.0,20.0,900.0\r
+7.0,20.0,900.0\r
+8.0,20.0,900.0\r
+9.0,20.0,900.0\r
+0.0,30.0,900.0\r
+1.0,30.0,900.0\r
+2.0,30.0,900.0\r
+3.0,30.0,900.0\r
+4.0,30.0,900.0\r
+5.0,30.0,900.0\r
+6.0,30.0,900.0\r
+7.0,30.0,900.0\r
+8.0,30.0,900.0\r
+9.0,30.0,900.0\r
+0.0,40.0,900.0\r
+1.0,40.0,900.0\r
+2.0,40.0,900.0\r
+3.0,40.0,900.0\r
+4.0,40.0,900.0\r
+5.0,40.0,900.0\r
+6.0,40.0,900.0\r
+7.0,40.0,900.0\r
+8.0,40.0,900.0\r
+9.0,40.0,900.0\r
+0.0,50.0,900.0\r
+1.0,50.0,900.0\r
+2.0,50.0,900.0\r
+3.0,50.0,900.0\r
+4.0,50.0,900.0\r
+5.0,50.0,900.0\r
+6.0,50.0,900.0\r
+7.0,50.0,900.0\r
+8.0,50.0,900.0\r
+9.0,50.0,900.0\r
+0.0,60.0,900.0\r
+1.0,60.0,900.0\r
+2.0,60.0,900.0\r
+3.0,60.0,900.0\r
+4.0,60.0,900.0\r
+5.0,60.0,900.0\r
+6.0,60.0,900.0\r
+7.0,60.0,900.0\r
+8.0,60.0,900.0\r
+9.0,60.0,900.0\r
+0.0,70.0,900.0\r
+1.0,70.0,900.0\r
+2.0,70.0,900.0\r
+3.0,70.0,900.0\r
+4.0,70.0,900.0\r
+5.0,70.0,900.0\r
+6.0,70.0,900.0\r
+7.0,70.0,900.0\r
+8.0,70.0,900.0\r
+9.0,70.0,900.0\r
+0.0,80.0,900.0\r
+1.0,80.0,900.0\r
+2.0,80.0,900.0\r
+3.0,80.0,900.0\r
+4.0,80.0,900.0\r
+5.0,80.0,900.0\r
+6.0,80.0,900.0\r
+7.0,80.0,900.0\r
+8.0,80.0,900.0\r
+9.0,80.0,900.0\r
+0.0,90.0,900.0\r
+1.0,90.0,900.0\r
+2.0,90.0,900.0\r
+3.0,90.0,900.0\r
+4.0,90.0,900.0\r
+5.0,90.0,900.0\r
+6.0,90.0,900.0\r
+7.0,90.0,900.0\r
+8.0,90.0,900.0\r
+9.0,90.0,900.0\r
--- /dev/null
+# -*- coding: utf-8 -*-
+def _exec(x,y,z):
+ s = (x + y + z) / z
+ import time
+ time.sleep(1)
+ return s
--- /dev/null
+"x","y","z"
+0,0,0
+1,0,0
+2,0,0
+3,0,0
+4,0,0
+5,0,0
+6,0,0
+7,0,0
+8,0,0
+9,0,0
+0,10,0
+1,10,0
+2,10,0
+3,10,0
+4,10,0
+5,10,0
+6,10,0
+7,10,0
+8,10,0
+9,10,0
+0,20,0
+1,20,0
+2,20,0
+3,20,0
+4,20,0
+5,20,0
+6,20,0
+7,20,0
+8,20,0
+9,20,0
+0,30,0
+1,30,0
+2,30,0
+3,30,0
+4,30,0
+5,30,0
+6,30,0
+7,30,0
+8,30,0
+9,30,0
+0,40,0
+1,40,0
+2,40,0
+3,40,0
+4,40,0
+5,40,0
+6,40,0
+7,40,0
+8,40,0
+9,40,0
+0,50,0
+1,50,0
+2,50,0
+3,50,0
+4,50,0
+5,50,0
+6,50,0
+7,50,0
+8,50,0
+9,50,0
+0,60,0
+1,60,0
+2,60,0
+3,60,0
+4,60,0
+5,60,0
+6,60,0
+7,60,0
+8,60,0
+9,60,0
+0,70,0
+1,70,0
+2,70,0
+3,70,0
+4,70,0
+5,70,0
+6,70,0
+7,70,0
+8,70,0
+9,70,0
+0,80,0
+1,80,0
+2,80,0
+3,80,0
+4,80,0
+5,80,0
+6,80,0
+7,80,0
+8,80,0
+9,80,0
+0,90,0
+1,90,0
+2,90,0
+3,90,0
+4,90,0
+5,90,0
+6,90,0
+7,90,0
+8,90,0
+9,90,0
+0,0,100
+1,0,100
+2,0,100
+3,0,100
+4,0,100
+5,0,100
+6,0,100
+7,0,100
+8,0,100
+9,0,100
+0,10,100
+1,10,100
+2,10,100
+3,10,100
+4,10,100
+5,10,100
+6,10,100
+7,10,100
+8,10,100
+9,10,100
+0,20,100
+1,20,100
+2,20,100
+3,20,100
+4,20,100
+5,20,100
+6,20,100
+7,20,100
+8,20,100
+9,20,100
+0,30,100
+1,30,100
+2,30,100
+3,30,100
+4,30,100
+5,30,100
+6,30,100
+7,30,100
+8,30,100
+9,30,100
+0,40,100
+1,40,100
+2,40,100
+3,40,100
+4,40,100
+5,40,100
+6,40,100
+7,40,100
+8,40,100
+9,40,100
+0,50,100
+1,50,100
+2,50,100
+3,50,100
+4,50,100
+5,50,100
+6,50,100
+7,50,100
+8,50,100
+9,50,100
+0,60,100
+1,60,100
+2,60,100
+3,60,100
+4,60,100
+5,60,100
+6,60,100
+7,60,100
+8,60,100
+9,60,100
+0,70,100
+1,70,100
+2,70,100
+3,70,100
+4,70,100
+5,70,100
+6,70,100
+7,70,100
+8,70,100
+9,70,100
+0,80,100
+1,80,100
+2,80,100
+3,80,100
+4,80,100
+5,80,100
+6,80,100
+7,80,100
+8,80,100
+9,80,100
+0,90,100
+1,90,100
+2,90,100
+3,90,100
+4,90,100
+5,90,100
+6,90,100
+7,90,100
+8,90,100
+9,90,100
+0,0,200
+1,0,200
+2,0,200
+3,0,200
+4,0,200
+5,0,200
+6,0,200
+7,0,200
+8,0,200
+9,0,200
+0,10,200
+1,10,200
+2,10,200
+3,10,200
+4,10,200
+5,10,200
+6,10,200
+7,10,200
+8,10,200
+9,10,200
+0,20,200
+1,20,200
+2,20,200
+3,20,200
+4,20,200
+5,20,200
+6,20,200
+7,20,200
+8,20,200
+9,20,200
+0,30,200
+1,30,200
+2,30,200
+3,30,200
+4,30,200
+5,30,200
+6,30,200
+7,30,200
+8,30,200
+9,30,200
+0,40,200
+1,40,200
+2,40,200
+3,40,200
+4,40,200
+5,40,200
+6,40,200
+7,40,200
+8,40,200
+9,40,200
+0,50,200
+1,50,200
+2,50,200
+3,50,200
+4,50,200
+5,50,200
+6,50,200
+7,50,200
+8,50,200
+9,50,200
+0,60,200
+1,60,200
+2,60,200
+3,60,200
+4,60,200
+5,60,200
+6,60,200
+7,60,200
+8,60,200
+9,60,200
+0,70,200
+1,70,200
+2,70,200
+3,70,200
+4,70,200
+5,70,200
+6,70,200
+7,70,200
+8,70,200
+9,70,200
+0,80,200
+1,80,200
+2,80,200
+3,80,200
+4,80,200
+5,80,200
+6,80,200
+7,80,200
+8,80,200
+9,80,200
+0,90,200
+1,90,200
+2,90,200
+3,90,200
+4,90,200
+5,90,200
+6,90,200
+7,90,200
+8,90,200
+9,90,200
+0,0,300
+1,0,300
+2,0,300
+3,0,300
+4,0,300
+5,0,300
+6,0,300
+7,0,300
+8,0,300
+9,0,300
+0,10,300
+1,10,300
+2,10,300
+3,10,300
+4,10,300
+5,10,300
+6,10,300
+7,10,300
+8,10,300
+9,10,300
+0,20,300
+1,20,300
+2,20,300
+3,20,300
+4,20,300
+5,20,300
+6,20,300
+7,20,300
+8,20,300
+9,20,300
+0,30,300
+1,30,300
+2,30,300
+3,30,300
+4,30,300
+5,30,300
+6,30,300
+7,30,300
+8,30,300
+9,30,300
+0,40,300
+1,40,300
+2,40,300
+3,40,300
+4,40,300
+5,40,300
+6,40,300
+7,40,300
+8,40,300
+9,40,300
+0,50,300
+1,50,300
+2,50,300
+3,50,300
+4,50,300
+5,50,300
+6,50,300
+7,50,300
+8,50,300
+9,50,300
+0,60,300
+1,60,300
+2,60,300
+3,60,300
+4,60,300
+5,60,300
+6,60,300
+7,60,300
+8,60,300
+9,60,300
+0,70,300
+1,70,300
+2,70,300
+3,70,300
+4,70,300
+5,70,300
+6,70,300
+7,70,300
+8,70,300
+9,70,300
+0,80,300
+1,80,300
+2,80,300
+3,80,300
+4,80,300
+5,80,300
+6,80,300
+7,80,300
+8,80,300
+9,80,300
+0,90,300
+1,90,300
+2,90,300
+3,90,300
+4,90,300
+5,90,300
+6,90,300
+7,90,300
+8,90,300
+9,90,300
+0,0,400
+1,0,400
+2,0,400
+3,0,400
+4,0,400
+5,0,400
+6,0,400
+7,0,400
+8,0,400
+9,0,400
+0,10,400
+1,10,400
+2,10,400
+3,10,400
+4,10,400
+5,10,400
+6,10,400
+7,10,400
+8,10,400
+9,10,400
+0,20,400
+1,20,400
+2,20,400
+3,20,400
+4,20,400
+5,20,400
+6,20,400
+7,20,400
+8,20,400
+9,20,400
+0,30,400
+1,30,400
+2,30,400
+3,30,400
+4,30,400
+5,30,400
+6,30,400
+7,30,400
+8,30,400
+9,30,400
+0,40,400
+1,40,400
+2,40,400
+3,40,400
+4,40,400
+5,40,400
+6,40,400
+7,40,400
+8,40,400
+9,40,400
+0,50,400
+1,50,400
+2,50,400
+3,50,400
+4,50,400
+5,50,400
+6,50,400
+7,50,400
+8,50,400
+9,50,400
+0,60,400
+1,60,400
+2,60,400
+3,60,400
+4,60,400
+5,60,400
+6,60,400
+7,60,400
+8,60,400
+9,60,400
+0,70,400
+1,70,400
+2,70,400
+3,70,400
+4,70,400
+5,70,400
+6,70,400
+7,70,400
+8,70,400
+9,70,400
+0,80,400
+1,80,400
+2,80,400
+3,80,400
+4,80,400
+5,80,400
+6,80,400
+7,80,400
+8,80,400
+9,80,400
+0,90,400
+1,90,400
+2,90,400
+3,90,400
+4,90,400
+5,90,400
+6,90,400
+7,90,400
+8,90,400
+9,90,400
+0,0,500
+1,0,500
+2,0,500
+3,0,500
+4,0,500
+5,0,500
+6,0,500
+7,0,500
+8,0,500
+9,0,500
+0,10,500
+1,10,500
+2,10,500
+3,10,500
+4,10,500
+5,10,500
+6,10,500
+7,10,500
+8,10,500
+9,10,500
+0,20,500
+1,20,500
+2,20,500
+3,20,500
+4,20,500
+5,20,500
+6,20,500
+7,20,500
+8,20,500
+9,20,500
+0,30,500
+1,30,500
+2,30,500
+3,30,500
+4,30,500
+5,30,500
+6,30,500
+7,30,500
+8,30,500
+9,30,500
+0,40,500
+1,40,500
+2,40,500
+3,40,500
+4,40,500
+5,40,500
+6,40,500
+7,40,500
+8,40,500
+9,40,500
+0,50,500
+1,50,500
+2,50,500
+3,50,500
+4,50,500
+5,50,500
+6,50,500
+7,50,500
+8,50,500
+9,50,500
+0,60,500
+1,60,500
+2,60,500
+3,60,500
+4,60,500
+5,60,500
+6,60,500
+7,60,500
+8,60,500
+9,60,500
+0,70,500
+1,70,500
+2,70,500
+3,70,500
+4,70,500
+5,70,500
+6,70,500
+7,70,500
+8,70,500
+9,70,500
+0,80,500
+1,80,500
+2,80,500
+3,80,500
+4,80,500
+5,80,500
+6,80,500
+7,80,500
+8,80,500
+9,80,500
+0,90,500
+1,90,500
+2,90,500
+3,90,500
+4,90,500
+5,90,500
+6,90,500
+7,90,500
+8,90,500
+9,90,500
+0,0,600
+1,0,600
+2,0,600
+3,0,600
+4,0,600
+5,0,600
+6,0,600
+7,0,600
+8,0,600
+9,0,600
+0,10,600
+1,10,600
+2,10,600
+3,10,600
+4,10,600
+5,10,600
+6,10,600
+7,10,600
+8,10,600
+9,10,600
+0,20,600
+1,20,600
+2,20,600
+3,20,600
+4,20,600
+5,20,600
+6,20,600
+7,20,600
+8,20,600
+9,20,600
+0,30,600
+1,30,600
+2,30,600
+3,30,600
+4,30,600
+5,30,600
+6,30,600
+7,30,600
+8,30,600
+9,30,600
+0,40,600
+1,40,600
+2,40,600
+3,40,600
+4,40,600
+5,40,600
+6,40,600
+7,40,600
+8,40,600
+9,40,600
+0,50,600
+1,50,600
+2,50,600
+3,50,600
+4,50,600
+5,50,600
+6,50,600
+7,50,600
+8,50,600
+9,50,600
+0,60,600
+1,60,600
+2,60,600
+3,60,600
+4,60,600
+5,60,600
+6,60,600
+7,60,600
+8,60,600
+9,60,600
+0,70,600
+1,70,600
+2,70,600
+3,70,600
+4,70,600
+5,70,600
+6,70,600
+7,70,600
+8,70,600
+9,70,600
+0,80,600
+1,80,600
+2,80,600
+3,80,600
+4,80,600
+5,80,600
+6,80,600
+7,80,600
+8,80,600
+9,80,600
+0,90,600
+1,90,600
+2,90,600
+3,90,600
+4,90,600
+5,90,600
+6,90,600
+7,90,600
+8,90,600
+9,90,600
+0,0,700
+1,0,700
+2,0,700
+3,0,700
+4,0,700
+5,0,700
+6,0,700
+7,0,700
+8,0,700
+9,0,700
+0,10,700
+1,10,700
+2,10,700
+3,10,700
+4,10,700
+5,10,700
+6,10,700
+7,10,700
+8,10,700
+9,10,700
+0,20,700
+1,20,700
+2,20,700
+3,20,700
+4,20,700
+5,20,700
+6,20,700
+7,20,700
+8,20,700
+9,20,700
+0,30,700
+1,30,700
+2,30,700
+3,30,700
+4,30,700
+5,30,700
+6,30,700
+7,30,700
+8,30,700
+9,30,700
+0,40,700
+1,40,700
+2,40,700
+3,40,700
+4,40,700
+5,40,700
+6,40,700
+7,40,700
+8,40,700
+9,40,700
+0,50,700
+1,50,700
+2,50,700
+3,50,700
+4,50,700
+5,50,700
+6,50,700
+7,50,700
+8,50,700
+9,50,700
+0,60,700
+1,60,700
+2,60,700
+3,60,700
+4,60,700
+5,60,700
+6,60,700
+7,60,700
+8,60,700
+9,60,700
+0,70,700
+1,70,700
+2,70,700
+3,70,700
+4,70,700
+5,70,700
+6,70,700
+7,70,700
+8,70,700
+9,70,700
+0,80,700
+1,80,700
+2,80,700
+3,80,700
+4,80,700
+5,80,700
+6,80,700
+7,80,700
+8,80,700
+9,80,700
+0,90,700
+1,90,700
+2,90,700
+3,90,700
+4,90,700
+5,90,700
+6,90,700
+7,90,700
+8,90,700
+9,90,700
+0,0,800
+1,0,800
+2,0,800
+3,0,800
+4,0,800
+5,0,800
+6,0,800
+7,0,800
+8,0,800
+9,0,800
+0,10,800
+1,10,800
+2,10,800
+3,10,800
+4,10,800
+5,10,800
+6,10,800
+7,10,800
+8,10,800
+9,10,800
+0,20,800
+1,20,800
+2,20,800
+3,20,800
+4,20,800
+5,20,800
+6,20,800
+7,20,800
+8,20,800
+9,20,800
+0,30,800
+1,30,800
+2,30,800
+3,30,800
+4,30,800
+5,30,800
+6,30,800
+7,30,800
+8,30,800
+9,30,800
+0,40,800
+1,40,800
+2,40,800
+3,40,800
+4,40,800
+5,40,800
+6,40,800
+7,40,800
+8,40,800
+9,40,800
+0,50,800
+1,50,800
+2,50,800
+3,50,800
+4,50,800
+5,50,800
+6,50,800
+7,50,800
+8,50,800
+9,50,800
+0,60,800
+1,60,800
+2,60,800
+3,60,800
+4,60,800
+5,60,800
+6,60,800
+7,60,800
+8,60,800
+9,60,800
+0,70,800
+1,70,800
+2,70,800
+3,70,800
+4,70,800
+5,70,800
+6,70,800
+7,70,800
+8,70,800
+9,70,800
+0,80,800
+1,80,800
+2,80,800
+3,80,800
+4,80,800
+5,80,800
+6,80,800
+7,80,800
+8,80,800
+9,80,800
+0,90,800
+1,90,800
+2,90,800
+3,90,800
+4,90,800
+5,90,800
+6,90,800
+7,90,800
+8,90,800
+9,90,800
+0,0,900
+1,0,900
+2,0,900
+3,0,900
+4,0,900
+5,0,900
+6,0,900
+7,0,900
+8,0,900
+9,0,900
+0,10,900
+1,10,900
+2,10,900
+3,10,900
+4,10,900
+5,10,900
+6,10,900
+7,10,900
+8,10,900
+9,10,900
+0,20,900
+1,20,900
+2,20,900
+3,20,900
+4,20,900
+5,20,900
+6,20,900
+7,20,900
+8,20,900
+9,20,900
+0,30,900
+1,30,900
+2,30,900
+3,30,900
+4,30,900
+5,30,900
+6,30,900
+7,30,900
+8,30,900
+9,30,900
+0,40,900
+1,40,900
+2,40,900
+3,40,900
+4,40,900
+5,40,900
+6,40,900
+7,40,900
+8,40,900
+9,40,900
+0,50,900
+1,50,900
+2,50,900
+3,50,900
+4,50,900
+5,50,900
+6,50,900
+7,50,900
+8,50,900
+9,50,900
+0,60,900
+1,60,900
+2,60,900
+3,60,900
+4,60,900
+5,60,900
+6,60,900
+7,60,900
+8,60,900
+9,60,900
+0,70,900
+1,70,900
+2,70,900
+3,70,900
+4,70,900
+5,70,900
+6,70,900
+7,70,900
+8,70,900
+9,70,900
+0,80,900
+1,80,900
+2,80,900
+3,80,900
+4,80,900
+5,80,900
+6,80,900
+7,80,900
+8,80,900
+9,80,900
+0,90,900
+1,90,900
+2,90,900
+3,90,900
+4,90,900
+5,90,900
+6,90,900
+7,90,900
+8,90,900
+9,90,900
--- /dev/null
+import SALOMERuntime
+import pickle
+import json
+
+datafile="input.csv"
+resultfile="output.csv"
+class myalgosync(SALOMERuntime.OptimizerAlgSync):
+ def __init__(self):
+ SALOMERuntime.OptimizerAlgSync.__init__(self, None)
+
+ def setPool(self,pool):
+ """Must be implemented to set the pool"""
+ self.pool=pool
+
+ def getTCForIn(self):
+ """return typecode of type expected as Input of the internal node """
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("string")
+
+ def getTCForOut(self):
+ """return typecode of type expected as Output of the internal node"""
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("string")
+
+ def getTCForAlgoInit(self):
+ """return typecode of type expected as input for initialize """
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("string")
+
+ def getTCForAlgoResult(self):
+ """return typecode of type expected as output of the algorithm """
+ return SALOMERuntime.getSALOMERuntime().getTypeCode("int")
+
+ def initialize(self,input):
+ """Optional method called on initialization.
+ The type of "input" is returned by "getTCForAlgoInit"
+ """
+ with open("idefixconfig.json", "r") as f:
+ self.config = json.load(f)
+
+ def start(self):
+ """Start to fill the pool with samples to evaluate."""
+ self.id=0
+ self.datafile=open(datafile, newline='')
+ #self.datafile=open(datafile)
+ import csv
+ self.data = csv.DictReader(self.datafile, quoting=csv.QUOTE_NONNUMERIC)
+ values=None
+ for i in range(0, self.getNbOfBranches()):
+ try:
+ values = next(self.data)
+ self.pool.pushInSample(self.id,
+ pickle.dumps(values, protocol=0).decode())
+ self.id += 1
+ except StopIteration:
+ pass
+ if values is not None:
+ with open(resultfile,"w") as f:
+ f.write("id,")
+ for v in values.keys():
+ f.write(v+",")
+ f.write("\n")
+
+ 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()
+ samplebyte=self.pool.getCurrentInSample().getStringValue().encode()
+ sample = pickle.loads(samplebyte)
+ resultbyte=self.pool.getCurrentOutSample().getStringValue().encode()
+ error,result = pickle.loads(resultbyte)
+ with open(resultfile,"a") as f:
+ f.write(repr(currentId)+",")
+ for v in sample.values():
+ f.write(repr(v)+",")
+ if error is None:
+ try:
+ for v in result:
+ f.write(repr(v)+",")
+ except TypeError:
+ # result is not iterable, it is just one number
+ f.write(repr(result))
+ else:
+ error="Error:"+error.split('\n')[0]
+ f.write(error)
+ f.write("\n")
+ try:
+ values = next(self.data)
+ self.pool.pushInSample(self.id, pickle.dumps(values, protocol=0).decode())
+ self.id += 1
+ except StopIteration:
+ pass
+
+ def finish(self):
+ """Optional method called when the algorithm has finished, successfully
+ or not, to perform any necessary clean up."""
+ try:
+ self.datafile.close()
+ except:
+ pass
+ self.pool.destroyAll()
+
+ def getAlgoResult(self):
+ """return the result of the algorithm.
+ The object returned is of type indicated by getTCForAlgoResult.
+ """
+ return 0
--- /dev/null
+#!/bin/bash
+commande=$*
+/home/I35256/salome/base/appli_DEV/salome -t
+/home/I35256/salome/base/appli_DEV/salome shell $commande
+/home/I35256/salome/base/appli_DEV/salome killall
--- /dev/null
+# -*- coding: utf-8 -*-
+import pydefx
+import os
+
+myParams = pydefx.Parameters(resource="localhost",nb_branches=2);
+#wd = os.path.join(myParams.salome_parameters.work_directory, "minifixtest")
+#myParams.salome_parameters.local_directory = "/toto/titi/tata"
+
+myScript = pydefx.PyScript()
+myScript.loadFile("scenario_study.py")
+
+mySample = myScript.CreateEmptySample()
+print(mySample.getInputNames())
+print(mySample.getOutputNames())
+
+mySample.setInputValues({ "x":[0.1, 0.2, 0.3, 0.4, 0.5],
+ "y":[1.0, 2.0, 3.0, 4.0, 5.0],
+ "z":["a", "b", "c", "d", "e"]})
+
+myStudy = pydefx.PyStudy(myScript.script, mySample, myParams)
+myStudy.run()
--- /dev/null
+# -*- coding: utf-8 -*-
+def _exec(x,y,z):
+ s = x + y
+ t = "{}={}".format(z,repr(s))
+ return s,t
--- /dev/null
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+import pydefix
+import os
+
+# load data
+import csv
+
+STUDY_DIR = "/home/I35256/openturns/work/py/cassyrthes"
+
+mydata = {}
+with open("syrthes.csv", newline='') as datafile:
+ csvdata = csv.DictReader(datafile, quoting=csv.QUOTE_NONNUMERIC)
+ for field in csvdata.fieldnames:
+ mydata[field] = []
+ for line in csvdata:
+ for field in csvdata.fieldnames:
+ mydata[field].append(line[field])
+
+myParams = pydefix.Parameters(resource="eole",nb_branches=26);
+wd = os.path.join(myParams.salome_parameters.work_directory, "test_syrthes")
+myParams.salome_parameters.work_directory = wd
+myParams.salome_parameters.local_directory = STUDY_DIR
+myParams.salome_parameters.in_files = ["brique_ech.syd", "Makefile", "Mesh",
+ "run.sh", "syrthes.py", "user_cond.c"]
+#myParams.salome_parameters.resource_required.nb_node = 2
+myScript = pydefix.PyScript()
+myScript.loadFile(os.path.join(STUDY_DIR, "etude.py"))
+
+mySample = myScript.CreateEmptySample()
+print(mySample.getInputNames())
+print(mySample.getOutputNames())
+
+mySample.setInputValues(mydata)
+
+myStudy = pydefix.PyStudy(myScript, mySample, myParams)
+myStudy.run()
+
+print(myStudy.getJobState())
+print(myStudy.getResult().progressRate())
--- /dev/null
+# -*- coding: utf-8 -*-
+import pydefx
+import os
+
+# load data
+import csv
+
+mydata = {}
+with open("input.csv", newline='') as datafile:
+ csvdata = csv.DictReader(datafile, quoting=csv.QUOTE_NONNUMERIC)
+ for field in csvdata.fieldnames:
+ mydata[field] = []
+ for line in csvdata:
+ for field in csvdata.fieldnames:
+ mydata[field].append(line[field])
+
+myScript = pydefx.PyScript()
+myScript.loadFile("tempostudy.py")
+
+mySample = myScript.CreateEmptySample()
+print(mySample.getInputNames())
+print(mySample.getOutputNames())
+
+mySample.setInputValues(mydata)
+
+myStudy = pydefx.PyStudy()
+myParams = myStudy.createDefaultParameters(resource="localhost");
+
+wd = os.path.join(myParams.salome_parameters.work_directory, "minifixtest")
+myParams.salome_parameters.work_directory = wd
+
+myStudy.createNewJob(myScript.script, mySample, myParams)
+myStudy.launch()
+
+print(myStudy.getJobState())
+print(myStudy.getResult().progressRate())
--- /dev/null
+# -*- coding: utf-8 -*-
+def _exec(x,y,z):
+ s = (x + y + z) / z
+ import time
+ time.sleep(1)
+ return s
--- /dev/null
+import pydefx
+
+myParams = pydefx.Parameters()
+myParams.configureResource("localhost")
+myParams.createResultDirectory("/tmp")
+
+pyScript = """
+def _exec(a, b):
+ d = a / b
+ return d"""
+
+myScript = pydefx.PyScript()
+myScript.loadString(pyScript)
+
+mySample = myScript.CreateEmptySample()
+mydata = {"a":[1.1, 2.2, 3.4, 5.5],
+ "b":[2.2, 4.4, 6.8, 11]}
+mySample.setInputValues(mydata)
+
+myStudy = pydefx.PyStudy()
+myStudy.createNewJob(myScript.script, mySample, myParams)
+print(myStudy.getProgress())
+myStudy.launch()
+print(myStudy.getJobState())
+print(myStudy.getProgress())
--- /dev/null
+import pydefx
+
+myParams = pydefx.Parameters()
+myParams.configureResource("localhost")
+myParams.createResultDirectory("/tmp")
+
+pyScript = """
+def _exec(a, b):
+ d = a / b
+ return d"""
+
+myScript = pydefx.PyScript()
+myScript.loadString(pyScript)
+
+mySample = myScript.CreateEmptySample()
+mydata = {"a":[1.1, 2.2, 3.4, 5.5],
+ "b":[2.2, 4.4, 6.8, 11]}
+mySample.setInputValues(mydata)
+
+myStudy = pydefx.PyStudy()
+myStudy.createNewJob(myScript.script, mySample, myParams)
+myStudy.launch()
+
+strdmp= myStudy.dump()
+restoredJob = pydefx.PyStudy()
+restoredJob.loadFromString(strdmp)
+
+print(myStudy.getJobState())
+print(myStudy.getProgress())