Skip to content

Commit aa91284

Browse files
Add python binding for Mappings (#505)
* WIP for mapping * wip for mapping * Retrieve the target from a linkpath * Add Binding_Mapping * Vec1D * Example with 3 to 1 mapping...
1 parent be45133 commit aa91284

File tree

8 files changed

+488
-2
lines changed

8 files changed

+488
-2
lines changed

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_LinkPath.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ using sofa::core::objectmodel::BaseLink;
2424
#include <sofa/core/objectmodel/BaseObject.h>
2525
using sofa::core::objectmodel::BaseObject;
2626

27+
#include <SofaPython3/PythonFactory.h>
28+
2729
#include <SofaPython3/Sofa/Core/Binding_LinkPath.h>
2830
#include <SofaPython3/Sofa/Core/Binding_LinkPath_doc.h>
2931

@@ -79,6 +81,13 @@ void moduleAddLinkPath(py::module& m)
7981
py::class_<LinkPath> link(m, "LinkPath", sofapython3::doc::linkpath::linkpath);
8082
link.def("__str__", &__str__);
8183
link.def("__repr__", &__repr__);
84+
link.def("target", [](const LinkPath& entry) -> py::object{
85+
if(entry.targetData != nullptr)
86+
return PythonFactory::toPython(entry.targetData);
87+
else if(entry.targetBase.get() != nullptr)
88+
return PythonFactory::toPython(entry.targetBase.get());
89+
return py::none();
90+
});
8291
}
8392

8493
}/// namespace sofapython3
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/******************************************************************************
2+
* SofaPython3 plugin *
3+
* (c) 2021 CNRS, University of Lille, INRIA *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify it *
6+
* under the terms of the GNU Lesser General Public License as published by *
7+
* the Free Software Foundation; either version 2.1 of the License, or (at *
8+
* your option) any later version. *
9+
* *
10+
* This program is distributed in the hope that it will be useful, but WITHOUT *
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
13+
* for more details. *
14+
* *
15+
* You should have received a copy of the GNU Lesser General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
*******************************************************************************
18+
* Contact information: [email protected] *
19+
******************************************************************************/
20+
21+
#include <pybind11/pybind11.h>
22+
#include <pybind11/numpy.h>
23+
#include <SofaPython3/Sofa/Core/Binding_Base.h>
24+
#include <SofaPython3/Sofa/Core/Binding_Mapping.h>
25+
#include <SofaPython3/Sofa/Core/Binding_Mapping_doc.h>
26+
#include <SofaPython3/PythonFactory.h>
27+
28+
#include <sofa/core/ConstraintParams.h>
29+
30+
#include <sofa/core/behavior/MechanicalState.h>
31+
#include <sofa/core/MechanicalParams.h>
32+
#include <sofa/core/behavior/DefaultMultiMatrixAccessor.h>
33+
#include <sofa/linearalgebra/CompressedRowSparseMatrix.h>
34+
35+
#include <pybind11/eigen.h>
36+
37+
#include <SofaPython3/PythonEnvironment.h>
38+
using sofapython3::PythonEnvironment;
39+
40+
/// Makes an alias for the pybind11 namespace to increase readability.
41+
namespace py { using namespace pybind11; }
42+
/// To bring in the `_a` literal
43+
using namespace pybind11::literals;
44+
45+
namespace sofapython3
46+
{
47+
using sofa::core::Mapping;
48+
using sofa::core::objectmodel::BaseObject;
49+
using sofa::core::objectmodel::ComponentState;
50+
using sofa::core::behavior::MechanicalState;
51+
using sofa::core::MechanicalParams;
52+
using sofa::core::behavior::MultiMatrixAccessor;
53+
using sofa::defaulttype::Vec3dTypes;
54+
using sofa::defaulttype::Vec2dTypes;
55+
using sofa::defaulttype::Vec1dTypes;
56+
using sofa::defaulttype::Vec6dTypes;
57+
using sofa::defaulttype::Rigid3dTypes;
58+
using sofa::defaulttype::Rigid2dTypes;
59+
60+
template<class In, class Out>
61+
Mapping_Trampoline<In, Out>::Mapping_Trampoline() = default;
62+
63+
template<class In, class Out>
64+
Mapping_Trampoline<In, Out>::~Mapping_Trampoline() = default;
65+
66+
template<class In, class Out>
67+
std::string Mapping_Trampoline<In, Out>::getClassName() const
68+
{
69+
PythonEnvironment::gil acquire {"getClassName"};
70+
71+
// Get the actual class name from python.
72+
return py::str(py::cast(this).get_type().attr("__name__"));
73+
}
74+
75+
template<class In, class Out>
76+
void Mapping_Trampoline<In, Out>::init()
77+
{
78+
PythonEnvironment::gil acquire;
79+
80+
Inherit1::init();
81+
}
82+
83+
template<class In, class Out>
84+
void Mapping_Trampoline<In, Out>::apply( const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in){
85+
PythonEnvironment::gil acquire;
86+
87+
// pass bFactor, kFactor, energy
88+
py::dict mp = py::dict("time"_a=this->getContext()->getTime(),
89+
"mFactor"_a=mparams->mFactor(),
90+
"bFactor"_a=mparams->bFactor(),
91+
"kFactor"_a=mparams->kFactor(),
92+
"isImplicit"_a=mparams->implicit(),
93+
"energy"_a=mparams->energy());
94+
95+
PYBIND11_OVERLOAD_PURE(void, Inherit1, apply, mp,
96+
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
97+
}
98+
99+
template<class In, class Out>
100+
void Mapping_Trampoline<In, Out>::applyJ( const MechanicalParams* mparams, OutDataVecDeriv& out, const InDataVecDeriv& in){
101+
PythonEnvironment::gil acquire;
102+
103+
// pass bFactor, kFactor, energy
104+
py::dict mp = py::dict("time"_a=getContext()->getTime(),
105+
"mFactor"_a=mparams->mFactor(),
106+
"bFactor"_a=mparams->bFactor(),
107+
"kFactor"_a=mparams->kFactor(),
108+
"isImplicit"_a=mparams->implicit(),
109+
"energy"_a=mparams->energy());
110+
111+
PYBIND11_OVERLOAD_PURE(void, Inherit1, applyJ, mp,
112+
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
113+
}
114+
115+
template<class In, class Out>
116+
void Mapping_Trampoline<In, Out>::applyJT( const MechanicalParams* mparams, InDataVecDeriv& out, const OutDataVecDeriv& in){
117+
PythonEnvironment::gil acquire;
118+
119+
py::dict mp = py::dict("time"_a=getContext()->getTime(),
120+
"mFactor"_a=mparams->mFactor(),
121+
"bFactor"_a=mparams->bFactor(),
122+
"kFactor"_a=mparams->kFactor(),
123+
"isImplicit"_a=mparams->implicit(),
124+
"energy"_a=mparams->energy());
125+
126+
PYBIND11_OVERLOAD_PURE(void, Inherit1, applyJT, mp,
127+
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
128+
}
129+
130+
template<class In, class Out>
131+
void Mapping_Trampoline<In, Out>::applyJT( const ConstraintParams* cparams,
132+
InDataMatrixDeriv& out, const OutDataMatrixDeriv& in)
133+
{
134+
PythonEnvironment::gil acquire;
135+
136+
py::dict mp = py::dict("time"_a=getContext()->getTime());
137+
138+
PYBIND11_OVERLOAD_PURE(void, Inherit1, applyConstrainsJT, mp,
139+
PythonFactory::toPython(&out), PythonFactory::toPython(&in));
140+
}
141+
142+
template<class In, class Out>
143+
void declareMapping(py::module &m) {
144+
const std::string pyclass_name = std::string("Mapping_") + In::Name()+ "_" + Out::Name();
145+
146+
py::class_<Mapping<In, Out>, BaseObject, Mapping_Trampoline<In, Out>,
147+
py_shared_ptr<Mapping<In, Out>>> f(m, pyclass_name.c_str(), py::dynamic_attr(), py::multiple_inheritance(),
148+
sofapython3::doc::mapping::mappingClass);
149+
150+
f.def(py::init([](py::args &args, py::kwargs &kwargs) {
151+
auto ff = sofa::core::sptr<Mapping_Trampoline<In, Out>> (new Mapping_Trampoline<In, Out>());
152+
153+
ff->f_listening.setValue(true);
154+
155+
if (args.size() == 1)
156+
ff->setName(py::cast<std::string>(args[0]));
157+
158+
py::object cc = py::cast(ff);
159+
for (auto kv : kwargs) {
160+
std::string key = py::cast<std::string>(kv.first);
161+
py::object value = py::reinterpret_borrow<py::object>(kv.second);
162+
if (key == "name") {
163+
if (args.size() != 0) {
164+
throw py::type_error("The name is set twice as a "
165+
"named argument='" + py::cast<std::string>(value) + "' and as a"
166+
"positional argument='" +
167+
py::cast<std::string>(args[0]) + "'.");
168+
}
169+
}
170+
BindingBase::SetAttr(cc, key, value);
171+
}
172+
return ff;
173+
}));
174+
}
175+
176+
void moduleAddMapping(py::module &m) {
177+
declareMapping<Rigid3dTypes, Vec3dTypes>(m);
178+
declareMapping<Vec3dTypes, Vec3dTypes>(m);
179+
declareMapping<Vec3dTypes, Vec1dTypes>(m);
180+
}
181+
182+
} // namespace sofapython3
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/******************************************************************************
2+
* SofaPython3 plugin *
3+
* (c) 2021 CNRS, University of Lille, INRIA *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify it *
6+
* under the terms of the GNU Lesser General Public License as published by *
7+
* the Free Software Foundation; either version 2.1 of the License, or (at *
8+
* your option) any later version. *
9+
* *
10+
* This program is distributed in the hope that it will be useful, but WITHOUT *
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
13+
* for more details. *
14+
* *
15+
* You should have received a copy of the GNU Lesser General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
*******************************************************************************
18+
* Contact information: [email protected] *
19+
******************************************************************************/
20+
21+
#pragma once
22+
23+
#include <sofa/core/BaseMapping.h>
24+
#include <sofa/core/Mapping.h>
25+
#include <sofa/defaulttype/VecTypes.h>
26+
#include <sofa/core/MechanicalParams.h>
27+
#include <pybind11/pybind11.h>
28+
29+
namespace sofapython3 {
30+
using sofa::core::ConstraintParams;
31+
using sofa::core::MechanicalParams;
32+
33+
template<class In, class Out>
34+
class Mapping_Trampoline : public sofa::core::Mapping<In, Out> {
35+
public:
36+
SOFA_CLASS(SOFA_TEMPLATE2(Mapping_Trampoline, In, Out) ,
37+
SOFA_TEMPLATE2(sofa::core::Mapping, In, Out));
38+
using sofa::core::Mapping<In,Out>::getContext;
39+
using typename sofa::core::Mapping<In,Out>::OutDataVecCoord;
40+
using typename sofa::core::Mapping<In,Out>::OutDataVecDeriv;
41+
using typename sofa::core::Mapping<In,Out>::InDataVecCoord;
42+
using typename sofa::core::Mapping<In,Out>::InDataVecDeriv;
43+
using typename sofa::core::Mapping<In,Out>::OutDataMatrixDeriv;
44+
using typename sofa::core::Mapping<In,Out>::InDataMatrixDeriv;
45+
46+
Mapping_Trampoline();
47+
~Mapping_Trampoline() override;
48+
49+
void init() override;
50+
std::string getClassName() const override;
51+
52+
void apply( const MechanicalParams* mparams, OutDataVecCoord& out, const InDataVecCoord& in) override;
53+
void applyJ( const MechanicalParams* mparams, OutDataVecDeriv& out, const InDataVecDeriv& in) override;
54+
void applyJT( const MechanicalParams* mparams, InDataVecDeriv& out, const OutDataVecDeriv& in) override;
55+
void applyJT( const ConstraintParams* mparams, InDataMatrixDeriv& out, const OutDataMatrixDeriv& in) override;
56+
57+
};
58+
59+
void moduleAddMapping(pybind11::module &m);
60+
61+
} /// namespace sofapython3
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/******************************************************************************
2+
* SofaPython3 plugin *
3+
* (c) 2021 CNRS, University of Lille, INRIA *
4+
* *
5+
* This program is free software; you can redistribute it and/or modify it *
6+
* under the terms of the GNU Lesser General Public License as published by *
7+
* the Free Software Foundation; either version 2.1 of the License, or (at *
8+
* your option) any later version. *
9+
* *
10+
* This program is distributed in the hope that it will be useful, but WITHOUT *
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
13+
* for more details. *
14+
* *
15+
* You should have received a copy of the GNU Lesser General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
*******************************************************************************
18+
* Contact information: [email protected] *
19+
******************************************************************************/
20+
21+
#pragma once
22+
23+
namespace sofapython3::doc::mapping
24+
{
25+
static auto mappingClass = R"(
26+
Overridable class to create your own customized mapping
27+
)";
28+
29+
}

bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ set(HEADER_FILES
2727
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mass_doc.h
2828
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ObjectFactory.h
2929
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ObjectFactory_doc.h
30+
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mapping.h
31+
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mapping_doc.h
3032
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Node.h
3133
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Node_doc.h
3234
${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.h
@@ -71,6 +73,7 @@ set(SOURCE_FILES
7173
${CMAKE_CURRENT_SOURCE_DIR}/Binding_LinkPath.cpp
7274
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mass.cpp
7375
${CMAKE_CURRENT_SOURCE_DIR}/Binding_ObjectFactory.cpp
76+
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Mapping.cpp
7477
${CMAKE_CURRENT_SOURCE_DIR}/Binding_Node.cpp
7578
${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.cpp
7679
${CMAKE_CURRENT_SOURCE_DIR}/Binding_PointSetTopologyModifier.cpp

bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ using sofa::helper::logging::Message;
3737
#include <SofaPython3/Sofa/Core/Binding_DataEngine.h>
3838
#include <SofaPython3/Sofa/Core/Binding_ObjectFactory.h>
3939
#include <SofaPython3/Sofa/Core/Binding_LinkPath.h>
40+
#include <SofaPython3/Sofa/Core/Binding_Mapping.h>
4041
#include <SofaPython3/Sofa/Core/Binding_Node.h>
4142
#include <SofaPython3/Sofa/Core/Binding_NodeIterator.h>
4243
#include <SofaPython3/Sofa/Core/Binding_Prefab.h>
@@ -140,11 +141,12 @@ PYBIND11_MODULE(Core, core)
140141
moduleAddController(core);
141142
moduleAddDataEngine(core);
142143
moduleAddForceField(core);
143-
moduleAddMass(core);
144-
moduleAddObjectFactory(core);
145144
moduleAddLinkPath(core);
145+
moduleAddMapping(core);
146+
moduleAddMass(core);
146147
moduleAddNode(core);
147148
moduleAddNodeIterator(core);
149+
moduleAddObjectFactory(core);
148150
moduleAddPrefab(core);
149151
moduleAddBaseLink(core);
150152
moduleAddTopology(core);

0 commit comments

Comments
 (0)