Page MenuHomec4science

python_functor_inline_impl.cc
No OneTemporary

File Metadata

Created
Tue, May 21, 16:15

python_functor_inline_impl.cc

/**
* @file python_functor_inline_impl.cc
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date creation: Fri Nov 13 2015
* @date last modification: Wed Nov 18 2015
*
* @brief Python functor interface
*
* @section LICENSE
*
* Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory
* (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* Akantu 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.
*
* Akantu 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 Akantu. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* -------------------------------------------------------------------------- */
#include "integration_point.hh"
#include "internal_field.hh"
/* -------------------------------------------------------------------------- */
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <Python.h>
#include <numpy/arrayobject.h>
#include <typeinfo>
#if PY_MAJOR_VERSION >= 3
#include <codecvt>
#endif
/* -------------------------------------------------------------------------- */
#ifndef __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__
#define __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__
namespace akantu {
/* -------------------------------------------------------------------------- */
template <typename T> inline int PythonFunctor::getPythonDataTypeCode() const {
AKANTU_EXCEPTION("undefined type: " << debug::demangle(typeid(T).name()));
}
/* -------------------------------------------------------------------------- */
template <> inline int PythonFunctor::getPythonDataTypeCode<bool>() const {
int data_typecode = NPY_NOTYPE;
size_t s = sizeof(bool);
switch (s) {
case 1:
data_typecode = NPY_BOOL;
break;
case 2:
data_typecode = NPY_UINT16;
break;
case 4:
data_typecode = NPY_UINT32;
break;
case 8:
data_typecode = NPY_UINT64;
break;
}
return data_typecode;
}
/* -------------------------------------------------------------------------- */
template <> inline int PythonFunctor::getPythonDataTypeCode<double>() const {
return NPY_DOUBLE;
}
/* -------------------------------------------------------------------------- */
template <typename T>
PyObject * PythonFunctor::convertToPython(const T &) const {
AKANTU_DEBUG_ERROR(__func__ << " : not implemented yet !" << std::endl
<< debug::demangle(typeid(T).name()));
}
/* -------------------------------------------------------------------------- */
template <>
inline PyObject *
PythonFunctor::convertToPython<double>(const double & akantu_object) const {
return PyFloat_FromDouble(akantu_object);
}
/* -------------------------------------------------------------------------- */
template <>
inline PyObject *
PythonFunctor::convertToPython<UInt>(const UInt & akantu_object) const {
#if PY_MAJOR_VERSION >= 3
return PyLong_FromLong(akantu_object);
#else
return PyInt_FromLong(akantu_object);
#endif
}
/* -------------------------------------------------------------------------- */
template <>
inline PyObject *
PythonFunctor::convertToPython<bool>(const bool & akantu_object) const {
return PyBool_FromLong(long(akantu_object));
}
/* -------------------------------------------------------------------------- */
template <typename T>
inline PyObject *
PythonFunctor::convertToPython(const std::vector<T> & array) const {
int data_typecode = getPythonDataTypeCode<T>();
npy_intp dims[1] = {int(array.size())};
PyObject * obj = PyArray_SimpleNewFromData(1, dims, data_typecode,
const_cast<T *>(&array[0]));
auto * res = (PyArrayObject *)obj;
return (PyObject *)res;
}
/* -------------------------------------------------------------------------- */
template <typename T>
inline PyObject *
PythonFunctor::convertToPython(const std::vector<Array<T> *> & array) const {
PyObject * res = PyDict_New();
for (auto a : array) {
PyObject * obj = this->convertToPython(*a);
PyObject * name = this->convertToPython(a->getID());
PyDict_SetItem(res, name, obj);
}
return (PyObject *)res;
}
/* -------------------------------------------------------------------------- */
template <typename T1, typename T2>
inline PyObject *
PythonFunctor::convertToPython(const std::map<T1, T2> & map) const {
PyObject * res = PyDict_New();
for (auto && a : map) {
PyObject * key = this->convertToPython(a.first);
PyObject * value = this->convertToPython(a.second);
PyDict_SetItem(res, key, value);
}
return (PyObject *)res;
}
/* -------------------------------------------------------------------------- */
template <typename T>
PyObject * PythonFunctor::convertToPython(const Vector<T> & array) const {
int data_typecode = getPythonDataTypeCode<T>();
npy_intp dims[1] = {array.size()};
PyObject * obj =
PyArray_SimpleNewFromData(1, dims, data_typecode, array.storage());
auto * res = (PyArrayObject *)obj;
return (PyObject *)res;
}
/* -------------------------------------------------------------------------- */
template <typename T>
inline PyObject *
PythonFunctor::convertToPython(const InternalField<T> & internals) const {
std::map<std::string, Array<T>*> _internals;
for (const auto & type : internals.elementTypes()) {
std::stringstream sstr;
_internals[sstr.str()] = const_cast<Array<T>*>(&internals(type));
}
return convertToPython(_internals);
}
/* --------------------------------------------------------------------------
*/
template <typename T>
inline PyObject *
PythonFunctor::convertToPython(const std::unique_ptr<T> & u) const {
return convertToPython(*u);
}
/* --------------------------------------------------------------------------
*/
template <typename T>
PyObject * PythonFunctor::convertToPython(const Array<T> & array) const {
int data_typecode = getPythonDataTypeCode<T>();
npy_intp dims[2] = {array.size(), array.getNbComponent()};
PyObject * obj =
PyArray_SimpleNewFromData(2, dims, data_typecode, array.storage());
auto * res = (PyArrayObject *)obj;
return (PyObject *)res;
}
/* --------------------------------------------------------------------------
*/
template <typename T>
PyObject * PythonFunctor::convertToPython(Array<T> * array) const {
return this->convertToPython(*array);
}
/* --------------------------------------------------------------------------
*/
template <typename T>
PyObject * PythonFunctor::convertToPython(const Matrix<T> & mat) const {
int data_typecode = getPythonDataTypeCode<T>();
npy_intp dims[2] = {mat.size(0), mat.size(1)};
PyObject * obj =
PyArray_SimpleNewFromData(2, dims, data_typecode, mat.storage());
auto * res = (PyArrayObject *)obj;
return (PyObject *)res;
}
/* --------------------------------------------------------------------------
*/
template <>
inline PyObject *
PythonFunctor::convertToPython<std::string>(const std::string & str) const {
#if PY_MAJOR_VERSION >= 3
return PyUnicode_FromString(str.c_str());
#else
return PyString_FromString(str.c_str());
#endif
}
/* --------------------------------------------------------------------------
*/
template <>
inline PyObject * PythonFunctor::convertToPython<IntegrationPoint>(
const IntegrationPoint & qp) const {
PyObject * input = PyDict_New();
PyObject * num_point = this->convertToPython(qp.num_point);
PyObject * global_num = this->convertToPython(qp.global_num);
PyObject * material_id = this->convertToPython(qp.material_id);
PyObject * position = this->convertToPython(qp.getPosition());
PyDict_SetItemString(input, "num_point", num_point);
PyDict_SetItemString(input, "global_num", global_num);
PyDict_SetItemString(input, "material_id", material_id);
PyDict_SetItemString(input, "position", position);
return input;
}
/* --------------------------------------------------------------------------
*/
inline PyObject *
PythonFunctor::getPythonFunction(const std::string & functor_name) const {
#if PY_MAJOR_VERSION < 3
if (!PyInstance_Check(this->python_obj))
AKANTU_EXCEPTION("Python object is not an instance");
#else
// does not make sense to check everything is an instance of object in python 3
#endif
if (not PyObject_HasAttrString(this->python_obj, functor_name.c_str()))
AKANTU_EXCEPTION("Python dictionary has no " << functor_name << " entry");
PyObject * pFunctor =
PyObject_GetAttrString(this->python_obj, functor_name.c_str());
return pFunctor;
}
/* --------------------------------------------------------------------------
*/
inline void
PythonFunctor::packArguments(__attribute__((unused))
std::vector<PyObject *> & p_args) const {}
/* --------------------------------------------------------------------------
*/
template <typename T, typename... Args>
inline void PythonFunctor::packArguments(std::vector<PyObject *> & p_args,
T & p, Args &... params) const {
p_args.push_back(this->convertToPython(p));
if (sizeof...(params) != 0)
this->packArguments(p_args, params...);
}
/* --------------------------------------------------------------------------
*/
template <typename return_type, typename... Params>
return_type PythonFunctor::callFunctor(const std::string & functor_name,
Params &... parameters) const {
_import_array();
std::vector<PyObject *> arg_vector;
this->packArguments(arg_vector, parameters...);
PyObject * pArgs = PyTuple_New(arg_vector.size());
for (UInt i = 0; i < arg_vector.size(); ++i) {
PyTuple_SetItem(pArgs, i, arg_vector[i]);
}
PyObject * kwargs = PyDict_New();
PyObject * pFunctor = getPythonFunction(functor_name);
PyObject * res = this->callFunctor(pFunctor, pArgs, kwargs);
Py_XDECREF(pArgs);
Py_XDECREF(kwargs);
return this->convertToAkantu<return_type>(res);
}
/* --------------------------------------------------------------------------
*/
template <typename return_type>
inline return_type PythonFunctor::convertToAkantu(PyObject * python_obj) const {
if (PyList_Check(python_obj)) {
return this->convertListToAkantu<typename return_type::value_type>(
python_obj);
}
AKANTU_DEBUG_TO_IMPLEMENT();
}
/* --------------------------------------------------------------------------
*/
template <>
inline void PythonFunctor::convertToAkantu<void>(PyObject * python_obj) const {
if (python_obj != Py_None)
AKANTU_DEBUG_WARNING(
"functor return a value while none was expected: ignored");
}
/* --------------------------------------------------------------------------
*/
template <>
inline std::string
PythonFunctor::convertToAkantu<std::string>(PyObject * python_obj) const {
#if PY_MAJOR_VERSION >= 3
if (!PyUnicode_Check(python_obj))
AKANTU_EXCEPTION("cannot convert object to string");
std::wstring unicode_str(PyUnicode_AsWideCharString(python_obj, NULL));
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
return converter.to_bytes(unicode_str);
#else
if (!PyString_Check(python_obj))
AKANTU_EXCEPTION("cannot convert object to string");
return PyString_AsString(python_obj);
#endif
}
/* --------------------------------------------------------------------------
*/
template <>
inline Real PythonFunctor::convertToAkantu<Real>(PyObject * python_obj) const {
if (!PyFloat_Check(python_obj))
AKANTU_EXCEPTION("cannot convert object to float");
return PyFloat_AsDouble(python_obj);
}
/* --------------------------------------------------------------------------
*/
template <>
inline UInt PythonFunctor::convertToAkantu<UInt>(PyObject * python_obj) const {
#if PY_MAJOR_VERSION >= 3
if (!PyLong_Check(python_obj))
AKANTU_EXCEPTION("cannot convert object to integer");
return PyLong_AsLong(python_obj);
#else
if (!PyInt_Check(python_obj))
AKANTU_EXCEPTION("cannot convert object to integer");
return PyInt_AsLong(python_obj);
#endif
}
/* --------------------------------------------------------------------------
*/
template <typename T>
inline std::vector<T>
PythonFunctor::convertListToAkantu(PyObject * python_obj) const {
std::vector<T> res;
UInt size = PyList_Size(python_obj);
for (UInt i = 0; i < size; ++i) {
PyObject * item = PyList_GET_ITEM(python_obj, i);
res.push_back(this->convertToAkantu<T>(item));
}
return res;
}
/* --------------------------------------------------------------------------
*/
} // akantu
#endif /* __AKANTU_PYTHON_FUNCTOR_INLINE_IMPL_CC__ */

Event Timeline