diff --git a/src/filter/compute_interface.cc b/src/filter/compute_interface.cc index 40eea6b..5740baa 100644 --- a/src/filter/compute_interface.cc +++ b/src/filter/compute_interface.cc @@ -1,204 +1,201 @@ /** * @file compute.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author Jaehyun Cho <jaehyun.cho@epfl.ch> * @author Moseley Philip Arthur <philip.moseley@epfl.ch> * * @date Wed Jul 09 21:59:47 2014 * * @brief This is the mother class 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/>. * */ #include "lib_continuum.hh" #include "lib_dd.hh" #include "lib_dumper.hh" #include "lib_filter.hh" #include "lib_md.hh" #include "lib_stimulation.hh" #include "lm_common.hh" /* -------------------------------------------------------------------------- */ __BEGIN_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ UInt ComputeInterface::getTotalNbData(UInt root_rank) { CommGroup &group = this->getCommGroup(); UInt nb_data = this->getArray().size(); group.reduce(&nb_data, 1, "reduce total number of data element", OP_SUM); return nb_data; } /* -------------------------------------------------------------------------- */ ContainerArray<Real> &ComputeInterface::gatherAllData(UInt root_rank) { // Communicator &comm = Communicator::getCommunicator(); CommGroup &group = this->getCommGroup(); // CommGroup group = comm.getCommGroup(); UInt my_rank = group.getMyRank(); UInt nb_data = this->getArray().size(); std::vector<UInt> nb_data_per_proc; #ifndef LM_OPTIMIZED UInt total_data = this->getTotalNbData(root_rank); group.synchronize(); #endif // LM_OPTIMIZED gather_flag = true; gather_root_proc = root_rank; if (root_rank == my_rank) { // prepare the array to resizes the sizes UInt nb_procs = group.size(); DUMP("receive " << nb_procs << " procs", DBG_INFO); DUMP("my rank is " << my_rank, DBG_INFO); nb_data_per_proc.resize(nb_procs); for (UInt p = 0; p < nb_procs; ++p) { if (p == my_rank) nb_data_per_proc[p] = nb_data; else { DUMP("receive from proc " << p, DBG_INFO); group.receive(&nb_data_per_proc[p], 1, p, "gatherData: receive number"); } } // compute total size of the gathered data UInt tot_size = 0; for (UInt p = 0; p < nb_procs; ++p) { DUMP("nb_data_per_proc[" << p << "]=" << nb_data_per_proc[p], DBG_INFO); tot_size += nb_data_per_proc[p]; } #ifndef LM_OPTIMIZED LM_ASSERT(total_data == tot_size, "mismatched of global sizes"); #endif // LM_OPTIMIZED // resize the receiving buffer data_gather.resize(tot_size); // receive the data from the other processors UInt offset = 0; for (UInt p = 0; p < nb_procs; ++p) { // if p is my_rank/root_rank copy the data if (p == my_rank) { for (UInt i = 0; i < nb_data; ++i) { data_gather[offset + i] = this->getArray()[i]; } } // else receive from distant proc else if (nb_data_per_proc[p]) { group.receive(&data_gather[offset], nb_data_per_proc[p], p, "gatherData: receive data"); } // increment the offset offset += nb_data_per_proc[p]; } } else { DUMP("send my nb_data = " << nb_data, DBG_INFO); // send the amount of data I have group.send(&nb_data, 1, root_rank, "gatherData: send number"); // if there is data to be sent : do so if (nb_data != 0) group.send(static_cast<ContainerArray<Real> &>(this->getArray()), root_rank, "gatherData: send data"); } return data_gather; } /* -------------------------------------------------------------------------- */ ContainerArray<Real> &ComputeInterface::gatherData(UInt source_rank, UInt root_rank) { CommGroup &group = this->getCommGroup(); UInt my_rank = group.getMyRank(); UInt nb_data = this->getArray().size(); if (root_rank == my_rank) { if (source_rank == root_rank) return this->getArray(); group.receive(&nb_data, 1, source_rank, "gatherData: receive number"); if (nb_data != 0) { data_gather.resize(this->getArray().size()); group.receive(data_gather, source_rank, "gatherData: receive data"); } } else if (source_rank == my_rank) { group.send(&nb_data, 1, root_rank, "gatherData: send number"); if (nb_data != 0) { group.send(static_cast<ContainerArray<Real> &>(this->getArray()), root_rank, "gatherData: send data"); } } return data_gather; } /* -------------------------------------------------------------------------- */ ContainerArray<Real> &ComputeInterface::allGatherAllData() { CommGroup &group = this->getCommGroup(); int localSize = this->getArray().size(); UInt np = group.size(); rcnts.resize(np); std::vector<int> rcntscnts(np, 1), displs(np); for (UInt i = 0; i < np; ++i) displs[i] = i; group.allGatherv(&localSize, 1, &rcnts[0], &rcntscnts[0], &displs[0], "allgatherv for compute interface"); UInt globalSize = 0; for (UInt i = 0; i < np; ++i) { displs[i] = globalSize; globalSize += rcnts[i]; } data_gather.resize(globalSize); LM_TOIMPLEMENT; // group.allGatherv(&static_cast<std::vector<Real> &>(*this)[0], localSize, // &data_gather[0], &rcnts[0], &displs[0], // "allgatherv for compute interface"); return data_gather; } /* -------------------------------------------------------------------------- */ ComputeInterface::ComputeInterface() : LMObject("ComputeInterface") { - // this->createInput("input1"); - // this->createOutput("output"); - // this->getOutput() = - // make_argument(ContainerArray<Real>(this->getID() + ":output")); + this->comm_group = nullptr; } /* -------------------------------------------------------------------------- */ ComputeInterface::~ComputeInterface() { gather_flag = false; gather_root_proc = 0; } /* -------------------------------------------------------------------------- */ __END_LIBMULTISCALE__ diff --git a/src/filter/compute_interface.hh b/src/filter/compute_interface.hh index dfd1e3d..8fd89ea 100644 --- a/src/filter/compute_interface.hh +++ b/src/filter/compute_interface.hh @@ -1,137 +1,138 @@ /** * @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: ComputeInterface(); virtual ~ComputeInterface(); //! gather result routine ContainerArray<Real> &gatherData(UInt source_rank, UInt root_rank = 0); //! gather all other processor result routine ContainerArray<Real> &gatherAllData(UInt root_rank = 0); //! all gather result routine ContainerArray<Real> &allGatherAllData(); //! return the total number of elements (parallel safe) UInt getTotalNbData(UInt root_rank = 0); inline virtual void compute_make_call() override { LM_TOIMPLEMENT; }; ContainerArray<Real> &getArray(const std::string &output_name = "") { auto name = output_name; if (name == "") { if (this->getOutputs().size() == 0) { LM_FATAL("There is no output for " << this->getID()); } else if (this->getOutputs().size() != 1) { std::string mesg = this->getID() + " has several outputs: need a name"; mesg += "\n\nPossible names: \n\n"; for (auto &&pair : this->getOutputs()) { mesg += "\t" + pair.first + "\n"; } LM_FATAL(mesg); } name = this->getOutputs().begin()->first; } return this->getCastedOutput<ContainerArray<Real>>(name, false); } CommGroup &getCommGroup() { if (comm_group == nullptr) LM_FATAL("invalid group"); return *comm_group; } //! set the communication group virtual void setCommGroup(CommGroup &group) { comm_group = &group; for (auto &&pair : this->getOutputs()) { this->getArray(pair.first).setCommGroup(group); } }; //! set the communication group virtual void copyContainerInfo(ContainerInterface &cont) { + this->setCommGroup(cont.getCommGroup()); for (auto &&pair : this->getOutputs()) { this->getArray(pair.first).copyContainerInfo(cont); } }; //! set the communication group virtual void clear() { for (auto &&pair : this->getOutputs()) { this->getArray(pair.first).clear(); } }; template <typename Names> void createArrayOutputs(const Names &output_names) { for (auto f : output_names) { this->createOutput(f); this->getOutput(f) = make_argument(ContainerArray<Real>(this->getID() + ":" + f)); } } protected: //! vector for gather routine usage ContainerArray<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; private: CommGroup *comm_group; }; __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 14b83ff..1e903ca 100644 --- a/src/filter/compute_python.cc +++ b/src/filter/compute_python.cc @@ -1,384 +1,377 @@ /** * @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); } /* -------------------------------------------------------------------------- */ auto split_string(const std::string &str, char separator) { std::istringstream iss(str); std::vector<std::string> res; while (!iss.eof()) { std::string buf; std::getline(iss, buf, separator); res.push_back(buf); } return res; } auto make_dict(std::vector<std::string> ids, py::object obj) { py::object key = obj; std::for_each(ids.rbegin(), ids.rend(), [&key](auto &val) { py::dict new_key; new_key.attr("__setitem__")(val, key); key = new_key; }); return key; } /* -------------------------------------------------------------------------- */ template <typename Cont> void appendGeneralArray(py::object &kwargs, Cont &cont, bool gather_flag, CommGroup &group, bool gather_root_proc) { const UInt Dim = cont.getDim(); ContainerArray<Real> *vdata_ptr = nullptr; if (gather_flag) { LM_TOIMPLEMENT; // vdata_ptr = &cont.gatherAllData(gather_root_proc); } else { ContainerArray<Real> &tmp = dynamic_cast<ContainerArray<Real> &>(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"); ContainerArray<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); auto id = cont.getID(); DUMP("adding the compute " << id, DBG_INFO); auto split_id = split_string(id, ':'); kwargs.attr("update")(make_dict(split_id, pyvalue)); // py::dict pyThisNameComputed; // for (UInt i = 0; i < cont.name_computed.size(); ++i) { // pyThisNameComputed.attr("__setitem__")(cont.name_computed[i], i); // } // py::object pyNameComputed = make_dict(split_id, pyThisNameComputed); // py::dict updater; // updater.attr("__setitem__")("name_computed", pyNameComputed); // kwargs.attr("update")(updater); } /* -------------------------------------------------------------------------- */ ComputePython::ComputePython(const std::string &name) : LMObject(name) { gather_root_proc = 0; gather_flag = false; // pModule = new py::object; // pCompute = new py::none; kwargs = new py::dict; this->createInput("input"); }; /* -------------------------------------------------------------------------- */ ComputePython::~ComputePython() { if (Py_IsInitialized()) { delete kwargs; // delete pModule; // delete pCompute; } } /* -------------------------------------------------------------------------- */ void ComputePython::init() { - this->createArrayOutputs(this->output_list); + std::list<std::string> output_list; + for (auto &&pair : this->pComputes) + output_list.push_back(pair.first); + + this->createArrayOutputs(output_list); if (!this->isConnected("input")) this->removeInput("input"); if (filename != "") { try { auto pModule = py::module::import(filename.c_str()); LM_TOIMPLEMENT; //*pCompute = pModule.attr("compute"); } 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); } } else if (pComputes.size() == 0) { LM_FATAL("No compute function was set: use FILENAME or FUNC keywords"); } units_dict = decltype(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}}; kwargs->attr("__setitem__")("units", units_dict); try { } 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()"); } kwargs->attr("__setitem__")("constants", 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.getArray(), 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); } /* -------------------------------------------------------------------------- */ -void ComputePython::callPythonRoutine(std::shared_ptr<py::object> &pCompute) { +void ComputePython::callPythonRoutine(const std::string &name, + std::shared_ptr<py::object> &pCompute) { STARTTIMER(this->getID()); - // 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["output"] = res; - } - + py::array_t<Real> pValue = (*pCompute)(***kwargs); + auto &output = this->getOutput(name).get(false).cast<ContainerArray<Real>>(); using EigenArray = ContainerArray<Real>::EigenArray; - for (auto &&pair : results) { - auto &key = pair.first; - auto vec = pair.second.cast<EigenArray>(); - auto &output = this->getOutput(key).get(false).cast<ContainerArray<Real>>(); - output = vec; - - DUMP("compute python " << this->getID() << " computed " - << this->getArray().size() << " values", - DBG_INFO); - } + auto vec = pValue.cast<EigenArray>(); + output = vec; + + DUMP("compute python " << this->getID() << " computed " + << this->getArray(name).size() << " values", + DBG_INFO); 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); for (auto &&key_val : this->pComputes) { auto &pCompute = key_val.second; auto name = key_val.first; - this->callPythonRoutine(pCompute); + this->callPythonRoutine(name, pCompute); } } /* ----------------------------------------------------------------------- */ void ComputePython::compute_with_arg(ContainerArray<Real> &cont) { this->clear(); this->copyContainerInfo(cont); // import_array(); + DUMP("container_group" << cont.getCommGroup(),DBG_MESSAGE); CommGroup &group = this->getCommGroup(); appendGeneralArray(*kwargs, cont, this->gather_flag, group, this->gather_root_proc); this->appendGeneralInfo(group); for (auto &&key_val : this->pComputes) { auto &pCompute = key_val.second; auto name = key_val.first; - this->callPythonRoutine(pCompute); + this->callPythonRoutine(name, pCompute); } } /* ----------------------------------------------------------------------- */ /* 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 OUTPUTS Specify the name of the outputs which will be produced */ this->parseKeyword("FUNC", pComputes, std::map<std::string, std::shared_ptr<py::object>>()); /* 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("input")) call_compute(*this, [&](auto &... args) { this->compute_with_arg(args...); }, this->getInput("input")); else call_compute(*this, [&]() { this->compute_no_arg(); }); } __END_LIBMULTISCALE__ diff --git a/src/filter/compute_python.hh b/src/filter/compute_python.hh index 980b73c..0b318d9 100644 --- a/src/filter/compute_python.hh +++ b/src/filter/compute_python.hh @@ -1,85 +1,85 @@ /** * @file compute_python.hh * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * * @date Sun Feb 02 17:45:17 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/>. * */ #ifndef __LIBMULTISCALE_COMPUTE_PYTHON_HH__ #define __LIBMULTISCALE_COMPUTE_PYTHON_HH__ /* -------------------------------------------------------------------------- */ #include "compute_interface.hh" #include "container_mesh.hh" /* -------------------------------------------------------------------------- */ // backward declaration namespace pybind11 { class object; class dict; } // namespace pybind11 namespace py = pybind11; __BEGIN_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ class ComputePython : public ComputeInterface { public: DECLARE_COMPUTE(ComputePython); DECLARE_INPUT(COMPUTE); void compute_with_arg(ContainerArray<Real> &cont); void compute_no_arg(); void init() override; void appendGeneralInfo(CommGroup &group); - void callPythonRoutine(std::shared_ptr<py::object> & pCompute); + void callPythonRoutine(const std::string &name, + std::shared_ptr<py::object> &pCompute); protected: std::string filename; std::map<std::string, std::shared_ptr<py::object>> pComputes; std::map<std::string, decltype(code_unit_system.mvv2e)> units_dict; UInt gather_root_proc; bool gather_flag; std::vector<LMID> compute_list; - std::vector<LMID> output_list; // arguments to be passed to the python script py::dict *kwargs; }; /* -------------------------------------------------------------------------- */ __END_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ #undef DL_IMPORT #endif /* __LIBMULTISCALE_COMPUTE_PYTHON_HH__ */