diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp index 75af4211..b6ae245c 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp @@ -31,24 +31,126 @@ #include #include +#include +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::behavior::Mass; +template +Mass_Trampoline::Mass_Trampoline() = default; + +template +Mass_Trampoline::~Mass_Trampoline() = default; + + +template +void Mass_Trampoline::init() +{ + Mass::init(); + + PythonEnvironment::gil acquire; + + if (!mstate.get()) + mstate.set(dynamic_cast< sofa::core::behavior::MechanicalState* >(getContext()->getMechanicalState())); + + if(!mstate.get()) + throw py::type_error("Missing mechanical state."); + + PYBIND11_OVERLOAD(void, Mass, init,); +} + + +template +std::string Mass_Trampoline::getClassName() const +{ + PythonEnvironment::gil acquire {"getClassName"}; + + // Get the actual class name from python. + return py::str(py::cast(this).get_type().attr("__name__")); +} + + +template +bool Mass_Trampoline::isDiagonal() const +{ + PythonEnvironment::gil acquire; + + PYBIND11_OVERLOAD_PURE(bool, Mass, isDiagonal); +} + + +template +void Mass_Trampoline::addGravitationalForce( const sofa::core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v, const Deriv& gravity) +{ + 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()); + PYBIND11_OVERLOAD_PURE(void, Mass, addGravitationalForce, mp, PythonFactory::toPython(&f), PythonFactory::toPython(&x), PythonFactory::toPython(&v), gravity); +} + + +template +SReal Mass_Trampoline::getGravitationalPotentialEnergy( const sofa::core::MechanicalParams* mparams, const DataVecCoord& x, const Deriv& gravity) const +{ + 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(SReal, Mass, getGravitationalPotentialEnergy, mp, PythonFactory::toPython(&x), gravity); +} + + template void declare_mass(py::module &m) { const std::string pyclass_name = std::string("Mass") + TDOFType::Name(); - py::class_, sofa::core::behavior::ForceField, py_shared_ptr>> f(m, pyclass_name.c_str(), py::multiple_inheritance(), sofapython3::doc::mass::massClass); + py::class_, sofa::core::objectmodel::BaseObject, Mass_Trampoline, py_shared_ptr>> f(m, pyclass_name.c_str(), py::dynamic_attr(), py::multiple_inheritance(), sofapython3::doc::mass::massClass); using Real = typename TDOFType::Real; using EigenSparseMatrix = Eigen::SparseMatrix; using EigenMatrixMap = Eigen::Map; + f.def(py::init([](py::args &args, py::kwargs &kwargs) { + auto mass = sofa::core::sptr> (new Mass_Trampoline()); + + mass->f_listening.setValue(true); + + if (args.size() == 1) mass->setName(py::cast(args[0])); + + py::object cc = py::cast(mass); + for (auto kv : kwargs) { + std::string key = py::cast(kv.first); + py::object value = py::reinterpret_borrow(kv.second); + if (key == "name") { + if (args.size() != 0) { + throw py::type_error("The name is set twice as a " + "named argument='" + py::cast(value) + "' and as a" + "positional argument='" + + py::cast(args[0]) + "'."); + } + } + BindingBase::SetAttr(cc, key, value); + } + return mass; + })); + f.def("assembleMMatrix", [](Mass& self) -> EigenSparseMatrix { sofa::linearalgebra::CompressedRowSparseMatrix matrix; diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h index 826b78da..71a0fedb 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h @@ -20,10 +20,37 @@ #pragma once -#include +#include +#include +#include +#include namespace sofapython3 { +template +class Mass_Trampoline : public sofa::core::behavior::Mass { +public: + SOFA_CLASS(Mass_Trampoline, SOFA_TEMPLATE(sofa::core::behavior::Mass, TDOFType)); + using sofa::core::behavior::Mass::mstate; + using sofa::core::behavior::Mass::getContext; + using typename sofa::core::behavior::Mass::DataTypes; + using typename sofa::core::behavior::Mass::Coord; + using typename sofa::core::behavior::Mass::Deriv; + using typename sofa::core::behavior::Mass::DataVecDeriv; + using typename sofa::core::behavior::Mass::DataVecCoord; + + Mass_Trampoline(); + ~Mass_Trampoline() override; + + void init() override; + std::string getClassName() const override; + + bool isDiagonal() const override; + + void addGravitationalForce( const sofa::core::MechanicalParams* mparams, DataVecDeriv& f, const DataVecCoord& x, const DataVecDeriv& v, const Deriv& gravity) override; + SReal getGravitationalPotentialEnergy( const sofa::core::MechanicalParams* mparams, const DataVecCoord& x, const Deriv& gravity) const override; +}; + void moduleAddMass(pybind11::module &m); } /// namespace sofapython3