Page MenuHomec4science

compute_python.cc
No OneTemporary

File Metadata

Created
Mon, May 20, 23:36

compute_python.cc

/**
* @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);
// 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;
// }
// 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);
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__

Event Timeline