diff --git a/src/filter/compute_interface.hh b/src/filter/compute_interface.hh index 083f407..f0a4176 100644 --- a/src/filter/compute_interface.hh +++ b/src/filter/compute_interface.hh @@ -1,130 +1,130 @@ /** * @file compute_interface.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date Mon Oct 28 19:23:14 2013 * * @brief This is the interface of all computes * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * LibMultiScale 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 3 of the License, or (at your option) any * later version. * * LibMultiScale 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 LibMultiScale. If not, see <http://www.gnu.org/licenses/>. * */ #ifndef __LIBMULTISCALE_COMPUTE_INTERFACE_HH__ #define __LIBMULTISCALE_COMPUTE_INTERFACE_HH__ /* -------------------------------------------------------------------------- */ #include "container_array.hh" #include "filter_interface.hh" /* -------------------------------------------------------------------------- */ __BEGIN_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ class ComputeInterface : public FilterInterface // , public ContainerArray<Real> { public: ComputeInterface(); virtual ~ComputeInterface(); //! gather result routine std::vector<Real> &gatherData(UInt source_rank, UInt root_rank = 0); //! gather all other processor result routine std::vector<Real> &gatherAllData(UInt root_rank = 0); //! all gather result routine std::vector<Real> &allGatherAllData(); //! return the total number of elements (parallel safe) UInt getTotalNbData(UInt root_rank = 0); //! get an item from its computed name virtual Real &operator()(const std::string &name, UInt index = 0) { std::vector<std::string>::iterator it; it = find(name_computed.begin(), name_computed.end(), name); if (it == name_computed.end()) { LM_FATAL("Name computed '" << name << "' not found"); } else { UInt position = it - name_computed.begin(); LM_FATAL("temp " << position); } } virtual UInt getDim() { return name_computed.size(); }; inline virtual void compute_make_call() override { LM_TOIMPLEMENT; }; //------------------------------------- // compatibility with array //------------------------------------- ContainerArray<Real> &getArray() { - return this->getCastedOutput<ContainerArray<Real>>(); + return this->getCastedOutput<ContainerArray<Real>>(false); } #define forward_method(name) \ template <typename... Args> inline decltype(auto) name(Args &&... args) { \ return this->getArray().name(args...); \ }; inline Real &operator[](UInt index) { return getArray()[index]; }; inline ContainerArray<Real> &operator[](const std::string &id); inline operator ContainerArray<Real> &() { return getArray(); }; inline operator std::vector<Real> &() { return getArray(); }; forward_method(begin); forward_method(end); forward_method(assign); forward_method(size); forward_method(resize); forward_method(setCommGroup); forward_method(getCommGroup); forward_method(push_back); forward_method(clear); forward_method(copyContainerInfo); forward_method(get); public: std::vector<std::string> name_computed; protected: //! vector for gather routine usage std::vector<Real> data_gather; //! vector for receive counts on allGatherAllData. std::vector<int> rcnts; //! flag specifying that input data was gathered(for python) bool gather_flag; //! processor number compute_python use to gather data UInt gather_root_proc; //! number of columns of the produced compute }; __END_LIBMULTISCALE__ #define DECLARE_COMPUTE(class_name) \ class_name(const std::string &name); \ virtual ~class_name(); \ \ void declareParams() override; \ void compute_make_call() override #endif /* __LIBMULTISCALE_COMPUTE_INTERFACE_HH__ */ diff --git a/src/filter/compute_python.cc b/src/filter/compute_python.cc index df700a0..3d7183f 100644 --- a/src/filter/compute_python.cc +++ b/src/filter/compute_python.cc @@ -1,393 +1,394 @@ /** * @file compute_python.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date Tue Jul 22 14:47:56 2014 * * @brief This compute allows to use Python to produce computed values as input * to LM * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * LibMultiScale 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 3 of the License, or (at your option) any * later version. * * LibMultiScale 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 LibMultiScale. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #define TIMER #include "compute_python.hh" #include "communicator.hh" #include "compute_compatibility.hh" #include "factory_multiscale.hh" #include "lib_dd.hh" #include "lib_md.hh" #include "lm_common.hh" #include "lm_parser.hh" #include "units.hh" #include <Eigen/Dense> #include <pybind11/eigen.h> #include <pybind11/pybind11.h> #include <pybind11/stl.h> /* -------------------------------------------------------------------------- */ __BEGIN_LIBMULTISCALE__ namespace py = pybind11; template <typename T> void appendGeneralVariables(py::object &kwargs, const std::string &name, T &value) { py::object pyvalue = py::cast(value); kwargs.attr("__setitem__")(name, pyvalue); } /* -------------------------------------------------------------------------- */ template <> void appendGeneralVariables<IntegrationSchemeStage>( py::object &kwargs, const std::string &name, IntegrationSchemeStage &value) { std::stringstream sstr; sstr << value; std::string str = sstr.str(); appendGeneralVariables<std::string>(kwargs, name, str); } /* -------------------------------------------------------------------------- */ template <typename Cont> void appendGeneralArray(py::object &kwargs, Cont &cont, bool gather_flag, CommGroup &group, bool gather_root_proc) { const UInt Dim = cont.getDim(); std::vector<Real> *vdata_ptr = nullptr; if (gather_flag) { vdata_ptr = &cont.gatherAllData(gather_root_proc); } else { std::vector<Real> &tmp = dynamic_cast<ComputeInterface &>(cont); vdata_ptr = &tmp; } if (gather_flag) { UInt my_rank = group.getMyRank(); if (my_rank != gather_root_proc) { // this->setDim(0); return; } } LM_ASSERT(vdata_ptr, "null pointer detected: abort"); std::vector<Real> &vdata = *vdata_ptr; UInt sz = vdata.size() / Dim; Eigen::Map< Eigen::Array<Real, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> python_input(&vdata[0], sz, Dim); py::object pyvalue = py::cast(python_input); DUMP("adding the compute " << cont.getID(), DBG_INFO); kwargs.attr("__setitem__")(cont.getID(), pyvalue); py::object pyNameComputed; try { pyNameComputed = kwargs.attr("__getitem__")("name_computed"); } catch (py::error_already_set &e) { pyNameComputed = py::dict(); } py::object pyThisNameComputed = py::dict(); for (UInt i = 0; i < cont.name_computed.size(); ++i) { py::object index = py::cast(i); pyThisNameComputed.attr("__setitem__")(cont.name_computed[i], index); } pyNameComputed.attr("__setitem__")(cont.getID(), pyThisNameComputed); kwargs.attr("__setitem__")("name_computed", pyNameComputed); } /* -------------------------------------------------------------------------- */ ComputePython::ComputePython(const std::string &name) : LMObject(name) { gather_root_proc = 0; gather_flag = false; pModule = std::make_unique<py::object>(); pCompute = std::make_unique<py::object>(); kwargs = std::make_unique<py::dict>(); }; /* -------------------------------------------------------------------------- */ ComputePython::~ComputePython() {} /* -------------------------------------------------------------------------- */ void ComputePython::init() { if (!this->isConnected("input1")) this->removeInput("input1"); try { *pModule = py::module::import(filename.c_str()); } catch (py::error_already_set &e) { DUMP(std::endl << "Python error while loading " << filename << ":" << std::endl << e.what() << std::endl << std::endl, DBG_MESSAGE); LM_FATAL("Failed to load " << filename); } std::map<std::string, decltype(code_unit_system.mvv2e)> units_dict{ {"mvv2e", code_unit_system.mvv2e}, {"f_m2v_t", code_unit_system.f_m2v_t}, {"ft_m2v", code_unit_system.ft_m2v}, {"mv_t2f", code_unit_system.mv_t2f}, {"kT2e", code_unit_system.kT2e}, {"kT2fd", code_unit_system.kT2fd}, {"m_tt2f_d", code_unit_system.m_tt2f_d}, {"e_dd2m_tt", code_unit_system.e_dd2m_tt}, {"e2fd", code_unit_system.e2fd}, {"e_m2dd_tt", code_unit_system.e_m2dd_tt}, {"fd2e", code_unit_system.fd2e}}; pModule->attr("__dict__").attr("update")(units_dict); try { *pCompute = pModule->attr("compute"); } catch (py::error_already_set &e) { DUMP(std::endl << "Python error in " << filename << ":" << std::endl << e.what() << std::endl << std::endl, DBG_MESSAGE); PyErr_Print(); LM_FATAL("Cannot find entry point: compute()"); } // try { // pSetNameComputed = pModule.attr("setNameComputed"); // } catch (py::error_already_set &e) { // pSetNameComputed = py::none(); // DUMP(this->getID() << ": no setNameComputed routine", DBG_WARNING); // } kwargs->attr("update")(Parser::getAlgebraicVariables()); } /* -------------------------------------------------------------------------- */ void ComputePython::appendGeneralInfo(CommGroup &group) { UInt my_rank = group.getMyRank(); for (UInt comp = 0; comp < compute_list.size(); ++comp) { LMID id = compute_list[comp]; auto &my_compute = FilterManager::getManager().getCastedObject<ComputeInterface>(id); my_compute.build(); appendGeneralArray(*kwargs, my_compute, this->gather_flag, group, this->gather_root_proc); } if (this->gather_flag && (my_rank != gather_root_proc)) return; appendGeneralVariables(*kwargs, "step", current_step); appendGeneralVariables(*kwargs, "current_stage", current_stage); appendGeneralVariables(*kwargs, "compute_name", this->getID()); appendGeneralVariables(*kwargs, "rank", lm_my_proc_id); } /* -------------------------------------------------------------------------- */ template <typename T> void treat_dict(T &dict) {} void ComputePython::callPythonRoutine() { STARTTIMER(this->getID()); - LM_TOIMPLEMENT; - // // py::array_t<Real> pValue = (*pCompute)(***kwargs); - // py::object pValue = (*pCompute)(***kwargs); + // py::array_t<Real> pValue = (*pCompute)(***kwargs); + py::object pValue = (*pCompute)(***kwargs); - // std::map<std::string, py::object> results; - // try{ - // results = pValue.cast<std::map<std::string, py::object>>(); - // }catch(...){ - // py::object res = pValue; - // results["result"] = res; - // } + std::map<std::string, py::object> results; + try { + results = pValue.cast<std::map<std::string, py::object>>(); + } catch (...) { + py::object res = pValue; + results["output"] = res; + } - // using eigen_array = Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic>; - // std::map<std::string, eigen_array> results_vec; - // for (auto && pair: results){ - // auto & key = pair.first; - // auto & vec = pair.second; - // results_vec[key] = vec.cast<eigen_array>(); - // } + using eigen_array = Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic>; + std::map<std::string, eigen_array> results_vec; + for (auto &&pair : results) { + auto &key = pair.first; + auto &vec = pair.second; + results_vec[key] = vec.cast<eigen_array>(); + } // UInt dim = result_vec.cols(); // // setNameComputed(pArgs, dim); // this->name_computed.clear(); // for (UInt i = 0; i < dim; ++i) { // std::stringstream title; // title << "python" << i; // this->name_computed.push_back(title.str()); // } // for (UInt i = 0; i < result_vec.rows(); ++i) { // for (UInt j = 0; j < dim; ++j) { // this->add(result_vec(i, j)); // } // } // DUMP("compute python " << this->getID() << " computed " << this->size() // << " values", // DBG_INFO); + LM_TOIMPLEMENT; + STOPTIMER(this->getID()); } /* -------------------------------------------------------------------------- */ void ComputePython::compute_no_arg() { this->clear(); // import_array(); this->setCommGroup(Communicator::getCommunicator().getObject("all")); CommGroup &group = this->getCommGroup(); this->appendGeneralInfo(group); this->callPythonRoutine(); } /* ----------------------------------------------------------------------- */ void ComputePython::compute_with_arg(ComputeInterface &cont) { this->clear(); this->copyContainerInfo(cont); // import_array(); CommGroup &group = this->getCommGroup(); appendGeneralArray(*kwargs, cont, this->gather_flag, group, this->gather_root_proc); this->appendGeneralInfo(group); this->callPythonRoutine(); } /* ----------------------------------------------------------------------- */ // void ComputePython::setNameComputed(py::object &pArgs, UInt dim) { // this->name_computed.clear(); // if (!pSetNameComputed.is_none()) { // std::list<py::object> pValue = // pSetNameComputed(pArgs, kwargs).cast<std::list<py::object>>(); // if (pValue.size() != dim) // LM_FATAL("The number of names provided is not correct " << // pValue.size() // << " != " << // dim); // for (auto &&entry : pValue) { // std::string name = entry.cast<std::string>(); // DUMP("adding name_computed " << name, DBG_INFO); // this->name_computed.push_back(std::string(name)); // } // } else { // for (UInt i = 0; i < dim; ++i) { // std::stringstream title; // title << "python" << i; // this->name_computed.push_back(title.str()); // } // } // } /* -------------------------------------------------------------------------- */ /* LMDESC PYTHON This computes an array of reals based on a python script */ /* LMEXAMPLE COMPUTE disp EXTRACT INPUT md FIELD displacement \\\\ COMPUTE disp2 PYTHON INPUT disp FILENAME script \\\\ with a python script stored in a file script.py with the content such as:\\\\ import numpy as np\\ \\ def compute(**kwargs):\\ ~~vec = np.copy(kwargs["disp"])\\ ~~vec *= 2. \\ ~~return vec */ void ComputePython::declareParams() { ComputeInterface::declareParams(); /* LMKEYWORD FILENAME Specify the name of the python script to use */ this->parseKeyword("FILENAME", filename); /* LMKEYWORD GATHER_ROOT Specify the processor where to gather data before inputing to python script */ this->parseKeyword("GATHER_ROOT", gather_root_proc, 0u); /* LMKEYWORD GATHER Specify the processor where to gather data before inputing to python script */ this->parseTag("GATHER", gather_flag, false); /* LMKEYWORD ADD_COMPUTE Add computes to input to the kwargs of the python script */ this->parseKeyword("ADD_COMPUTE", compute_list, std::vector<std::string>{}); } /* -------------------------------------------------------------------------- */ void ComputePython::compute_make_call() { DUMP(this->getID() << ": Compute", DBG_INFO); if (this->isConnected("input1")) call_compute(*this, [&](auto &... args) { this->compute_with_arg(args...); }, this->getInput("input1")); else call_compute(*this, [&]() { this->compute_no_arg(); }); } __END_LIBMULTISCALE__