Skip to content

Add python binding for Mappings #505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_LinkPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ using sofa::core::objectmodel::BaseLink;
#include <sofa/core/objectmodel/BaseObject.h>
using sofa::core::objectmodel::BaseObject;

#include <SofaPython3/PythonFactory.h>

#include <SofaPython3/Sofa/Core/Binding_LinkPath.h>
#include <SofaPython3/Sofa/Core/Binding_LinkPath_doc.h>

Expand Down Expand Up @@ -79,6 +81,13 @@ void moduleAddLinkPath(py::module& m)
py::class_<LinkPath> link(m, "LinkPath", sofapython3::doc::linkpath::linkpath);
link.def("__str__", &__str__);
link.def("__repr__", &__repr__);
link.def("target", [](const LinkPath& entry) -> py::object{
if(entry.targetData != nullptr)
return PythonFactory::toPython(entry.targetData);
else if(entry.targetBase.get() != nullptr)
return PythonFactory::toPython(entry.targetBase.get());
return py::none();
});
}

}/// namespace sofapython3
182 changes: 182 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mapping.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/******************************************************************************
* SofaPython3 plugin *
* (c) 2021 CNRS, University of Lille, INRIA *
* *
* This program 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 program 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 program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Contact information: [email protected] *
******************************************************************************/

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <SofaPython3/Sofa/Core/Binding_Base.h>
#include <SofaPython3/Sofa/Core/Binding_Mapping.h>
#include <SofaPython3/Sofa/Core/Binding_Mapping_doc.h>
#include <SofaPython3/PythonFactory.h>

#include <sofa/core/ConstraintParams.h>

#include <sofa/core/behavior/MechanicalState.h>
#include <sofa/core/MechanicalParams.h>
#include <sofa/core/behavior/DefaultMultiMatrixAccessor.h>
#include <sofa/linearalgebra/CompressedRowSparseMatrix.h>

#include <pybind11/eigen.h>

#include <SofaPython3/PythonEnvironment.h>
using sofapython3::PythonEnvironment;

/// Makes an alias for the pybind11 namespace to increase readability.
namespace py { using namespace pybind11; }
/// To bring in the `_a` literal
using namespace pybind11::literals;

namespace sofapython3
{
using sofa::core::Mapping;
using sofa::core::objectmodel::BaseObject;
using sofa::core::objectmodel::ComponentState;
using sofa::core::behavior::MechanicalState;
using sofa::core::MechanicalParams;
using sofa::core::behavior::MultiMatrixAccessor;
using sofa::defaulttype::Vec3dTypes;
using sofa::defaulttype::Vec2dTypes;
using sofa::defaulttype::Vec1dTypes;
using sofa::defaulttype::Vec6dTypes;
using sofa::defaulttype::Rigid3dTypes;
using sofa::defaulttype::Rigid2dTypes;

template<class In, class Out>
Mapping_Trampoline<In, Out>::Mapping_Trampoline() = default;

template<class In, class Out>
Mapping_Trampoline<In, Out>::~Mapping_Trampoline() = default;

template<class In, class Out>
std::string Mapping_Trampoline<In, Out>::getClassName() const
{
PythonEnvironment::gil acquire {"getClassName"};

// Get the actual class name from python.
return py::str(py::cast(this).get_type().attr("__name__"));
}

template<class In, class Out>
void Mapping_Trampoline<In, Out>::init()
{
PythonEnvironment::gil acquire;

Inherit1::init();
}

template<class In, class Out>
void Mapping_Trampoline<In, Out>::apply( const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in){
PythonEnvironment::gil acquire;

// pass bFactor, kFactor, energy
py::dict mp = py::dict("time"_a=this->getContext()->getTime(),
"mFactor"_a=mparams->mFactor(),
"bFactor"_a=mparams->bFactor(),
"kFactor"_a=mparams->kFactor(),
"isImplicit"_a=mparams->implicit(),
"energy"_a=mparams->energy());

PYBIND11_OVERLOAD_PURE(void, Inherit1, apply, mp,
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
}

template<class In, class Out>
void Mapping_Trampoline<In, Out>::applyJ( const MechanicalParams* mparams, OutDataVecDeriv& out, const InDataVecDeriv& in){
PythonEnvironment::gil acquire;

// pass bFactor, kFactor, energy
py::dict mp = py::dict("time"_a=getContext()->getTime(),
"mFactor"_a=mparams->mFactor(),
"bFactor"_a=mparams->bFactor(),
"kFactor"_a=mparams->kFactor(),
"isImplicit"_a=mparams->implicit(),
"energy"_a=mparams->energy());

PYBIND11_OVERLOAD_PURE(void, Inherit1, applyJ, mp,
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
}

template<class In, class Out>
void Mapping_Trampoline<In, Out>::applyJT( const MechanicalParams* mparams, InDataVecDeriv& out, const OutDataVecDeriv& in){
PythonEnvironment::gil acquire;

py::dict mp = py::dict("time"_a=getContext()->getTime(),
"mFactor"_a=mparams->mFactor(),
"bFactor"_a=mparams->bFactor(),
"kFactor"_a=mparams->kFactor(),
"isImplicit"_a=mparams->implicit(),
"energy"_a=mparams->energy());

PYBIND11_OVERLOAD_PURE(void, Inherit1, applyJT, mp,
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
}

template<class In, class Out>
void Mapping_Trampoline<In, Out>::applyJT( const ConstraintParams* cparams,
InDataMatrixDeriv& out, const OutDataMatrixDeriv& in)
{
PythonEnvironment::gil acquire;

py::dict mp = py::dict("time"_a=getContext()->getTime());

PYBIND11_OVERLOAD_PURE(void, Inherit1, applyConstrainsJT, mp,
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
}

template<class In, class Out>
void declareMapping(py::module &m) {
const std::string pyclass_name = std::string("Mapping_") + In::Name()+ "_" + Out::Name();

py::class_<Mapping<In, Out>, BaseObject, Mapping_Trampoline<In, Out>,
py_shared_ptr<Mapping<In, Out>>> f(m, pyclass_name.c_str(), py::dynamic_attr(), py::multiple_inheritance(),
sofapython3::doc::mapping::mappingClass);

f.def(py::init([](py::args &args, py::kwargs &kwargs) {
auto ff = sofa::core::sptr<Mapping_Trampoline<In, Out>> (new Mapping_Trampoline<In, Out>());

ff->f_listening.setValue(true);

if (args.size() == 1)
ff->setName(py::cast<std::string>(args[0]));

py::object cc = py::cast(ff);
for (auto kv : kwargs) {
std::string key = py::cast<std::string>(kv.first);
py::object value = py::reinterpret_borrow<py::object>(kv.second);
if (key == "name") {
if (args.size() != 0) {
throw py::type_error("The name is set twice as a "
"named argument='" + py::cast<std::string>(value) + "' and as a"
"positional argument='" +
py::cast<std::string>(args[0]) + "'.");
}
}
BindingBase::SetAttr(cc, key, value);
}
return ff;
}));
}

void moduleAddMapping(py::module &m) {
declareMapping<Rigid3dTypes, Vec3dTypes>(m);
declareMapping<Vec3dTypes, Vec3dTypes>(m);
declareMapping<Vec3dTypes, Vec1dTypes>(m);
}

} // namespace sofapython3
61 changes: 61 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mapping.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/******************************************************************************
* SofaPython3 plugin *
* (c) 2021 CNRS, University of Lille, INRIA *
* *
* This program 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 program 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 program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Contact information: [email protected] *
******************************************************************************/

#pragma once

#include <sofa/core/BaseMapping.h>
#include <sofa/core/Mapping.h>
#include <sofa/defaulttype/VecTypes.h>
#include <sofa/core/MechanicalParams.h>
#include <pybind11/pybind11.h>

namespace sofapython3 {
using sofa::core::ConstraintParams;
using sofa::core::MechanicalParams;

template<class In, class Out>
class Mapping_Trampoline : public sofa::core::Mapping<In, Out> {
public:
SOFA_CLASS(SOFA_TEMPLATE2(Mapping_Trampoline, In, Out) ,
SOFA_TEMPLATE2(sofa::core::Mapping, In, Out));
using sofa::core::Mapping<In,Out>::getContext;
using typename sofa::core::Mapping<In,Out>::OutDataVecCoord;
using typename sofa::core::Mapping<In,Out>::OutDataVecDeriv;
using typename sofa::core::Mapping<In,Out>::InDataVecCoord;
using typename sofa::core::Mapping<In,Out>::InDataVecDeriv;
using typename sofa::core::Mapping<In,Out>::OutDataMatrixDeriv;
using typename sofa::core::Mapping<In,Out>::InDataMatrixDeriv;

Mapping_Trampoline();
~Mapping_Trampoline() override;

void init() override;
std::string getClassName() const override;

void apply( const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in) override;
void applyJ( const MechanicalParams* mparams, OutDataVecDeriv& out, const InDataVecDeriv& in) override;
void applyJT( const MechanicalParams* mparams, InDataVecDeriv& out, const OutDataVecDeriv& in) override;
void applyJT( const ConstraintParams* mparams, InDataMatrixDeriv& out, const OutDataMatrixDeriv& in) override;

};

void moduleAddMapping(pybind11::module &m);

} /// namespace sofapython3
29 changes: 29 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mapping_doc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/******************************************************************************
* SofaPython3 plugin *
* (c) 2021 CNRS, University of Lille, INRIA *
* *
* This program 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 program 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 program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Contact information: [email protected] *
******************************************************************************/

#pragma once

namespace sofapython3::doc::mapping
{
static auto mappingClass = R"(
Overridable class to create your own customized mapping
)";

}
3 changes: 3 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mass_doc.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ObjectFactory.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ObjectFactory_doc.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mapping.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mapping_doc.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Node.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Node_doc.h
${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.h
Expand Down Expand Up @@ -71,6 +73,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinkPath.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mass.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ObjectFactory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mapping.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Node.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Binding_PointSetTopologyModifier.cpp
Expand Down
6 changes: 4 additions & 2 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ using sofa::helper::logging::Message;
#include <SofaPython3/Sofa/Core/Binding_DataEngine.h>
#include <SofaPython3/Sofa/Core/Binding_ObjectFactory.h>
#include <SofaPython3/Sofa/Core/Binding_LinkPath.h>
#include <SofaPython3/Sofa/Core/Binding_Mapping.h>
#include <SofaPython3/Sofa/Core/Binding_Node.h>
#include <SofaPython3/Sofa/Core/Binding_NodeIterator.h>
#include <SofaPython3/Sofa/Core/Binding_Prefab.h>
Expand Down Expand Up @@ -140,11 +141,12 @@ PYBIND11_MODULE(Core, core)
moduleAddController(core);
moduleAddDataEngine(core);
moduleAddForceField(core);
moduleAddMass(core);
moduleAddObjectFactory(core);
moduleAddLinkPath(core);
moduleAddMapping(core);
moduleAddMass(core);
moduleAddNode(core);
moduleAddNodeIterator(core);
moduleAddObjectFactory(core);
moduleAddPrefab(core);
moduleAddBaseLink(core);
moduleAddTopology(core);
Expand Down
Loading
Loading