diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.cpp new file mode 100644 index 00000000..62b337fd --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.cpp @@ -0,0 +1,96 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace py { using namespace pybind11; } + +namespace sofapython3 +{ + +template +typename sofa::linearalgebra::CompressedRowSparseMatrixToEigenSparseVec::EigenSparseMatrix +toEigen(const sofa::linearalgebra::CompressedRowSparseMatrixConstraint& matrix) +{ + static sofa::linearalgebra::CompressedRowSparseMatrixToEigenSparseVec convert; + return convert(matrix); +} + +template +void bindCompressedRowSparseMatrixConstraint(pybind11::module& m) +{ + static_assert(sofa::type::trait::is_specialization_of_v, + "Template argument must be a specialization of CompressedRowSparseMatrixConstraint"); + + py::class_, sofa::core::objectmodel::BaseData, + std::unique_ptr, pybind11::nodelete> > crsmc(m, MatrixDeriv::Name() ); + + crsmc.def_property_readonly("value", [](sofa::Data& self) + { + sofa::helper::ReadAccessor accessor(self); + return toEigen(accessor.ref()); + }); + + PythonFactory::registerType(MatrixDeriv::Name(), [](sofa::core::BaseData* data) -> py::object { + auto matrix = reinterpret_cast*>(data); + return py::cast(matrix); + }); +} + +/** + * Given a template parameter pack, create the bindings of all the templates in + * the pack, making sure that there are no duplicate types. + */ +template +void bindAllCompressedRowSparseMatrixConstraintTypes(pybind11::module& m) +{ + static_assert(!(std::is_same_v || ...), "Error: Duplicate types found!"); + + bindCompressedRowSparseMatrixConstraint(m); + if constexpr (sizeof...(Args) > 0) + { + bindAllCompressedRowSparseMatrixConstraintTypes(m); + } +} + +void moduleAddCompressedRowSparseMatrix(pybind11::module& m) +{ + using namespace sofa::defaulttype; + + bindAllCompressedRowSparseMatrixConstraintTypes< + Vec1Types::MatrixDeriv, + Vec2Types::MatrixDeriv, + Vec3Types::MatrixDeriv, + Vec6Types::MatrixDeriv, + Rigid2Types::MatrixDeriv, + Rigid3Types::MatrixDeriv + >(m); +} + +} diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h b/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h new file mode 100644 index 00000000..13eeb571 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h @@ -0,0 +1,29 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +#include + +namespace sofapython3 { + +void moduleAddCompressedRowSparseMatrix(pybind11::module& m); + +} // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Types/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Types/CMakeLists.txt index d741b52a..0c279a51 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Types/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Types/CMakeLists.txt @@ -2,10 +2,12 @@ project(Bindings.Sofa.Types) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BoundingBox.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_CompressedRowSparseMatrix.h ) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Types.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_CompressedRowSparseMatrix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BoundingBox.cpp ) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Types/Submodule_Types.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Types/Submodule_Types.cpp index 86324bc3..be65bed8 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Types/Submodule_Types.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Types/Submodule_Types.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace sofapython3 { /// The first parameter must be named the same as the module file to load. @@ -42,6 +44,7 @@ PYBIND11_MODULE(Types, types) )doc"; moduleAddBoundingBox(types); + moduleAddCompressedRowSparseMatrix(types); } } // namespace sofapython3 diff --git a/examples/access_constraint_matrix.py b/examples/access_constraint_matrix.py new file mode 100644 index 00000000..f12d9784 --- /dev/null +++ b/examples/access_constraint_matrix.py @@ -0,0 +1,66 @@ +# Required import for python +import Sofa +import SofaRuntime +import numpy as np + + +# Function called when the scene graph is being created +def createScene(root): + root.addObject("RequiredPlugin", pluginName=["Sofa.Component.AnimationLoop", + "Sofa.Component.Constraint.Lagrangian.Correction", + "Sofa.Component.Constraint.Lagrangian.Model", + "Sofa.Component.Constraint.Lagrangian.Solver", + "Sofa.Component.Constraint.Projective", + "Sofa.Component.IO.Mesh", + "Sofa.Component.LinearSolver.Direct", + "Sofa.Component.Mapping.MappedMatrix", + "Sofa.Component.Mass", + "Sofa.Component.ODESolver.Backward", + "Sofa.Component.Topology.Container.Dynamic", + "Sofa.Component.Mapping.NonLinear", + "Sofa.Component.StateContainer" + ]) + + root.addObject("FreeMotionAnimationLoop", solveVelocityConstraintFirst=True) + root.addObject("GenericConstraintSolver", tolerance=1e-9, maxIterations=1000) + root.addObject("StringMeshCreator", name="loader", resolution="20") + + root.addObject("EulerImplicitSolver") + root.addObject("EigenSimplicialLLT", template='CompressedRowSparseMatrixMat3x3d') + root.addObject("GenericConstraintCorrection") + + root.addObject("EdgeSetTopologyContainer", name="topo", position="@loader.position", edges="@loader.edges") + mechanical_object = root.addObject("MechanicalObject", name="defoDOF", template="Vec3d") + root.addObject("EdgeSetGeometryAlgorithms", drawEdges=True) + root.addObject("FixedProjectiveConstraint", indices=[0]) + root.addObject("DiagonalMass", name="mass", totalMass="1e-3") + + ext = root.addChild("extensionsNode") + ext.addObject("MechanicalObject", template="Vec1d", name="extensionsDOF") + ext.addObject("DistanceMapping", name="distanceMapping", topology="@topo") + ext.addObject("UniformLagrangianConstraint", template="Vec1d", iterative=True) + + root.addObject(MatrixAccessController('MatrixAccessor', name='matrixAccessor', mechanical_object=mechanical_object)) + + +class MatrixAccessController(Sofa.Core.Controller): + + def __init__(self, *args, **kwargs): + Sofa.Core.Controller.__init__(self, *args, **kwargs) + self.mechanical_object = kwargs.get("mechanical_object") + + def onBuildConstraintSystemEndEvent(self, event): + constraint_matrix = self.mechanical_object.constraint.value + + print(self.mechanical_object.constraint.linkpath) + + print('====================================') + print('Constraint matrix in constraint space') + print('====================================') + print('dtype: ' + str(constraint_matrix.dtype)) + print('shape: ' + str(constraint_matrix.shape)) + print('ndim: ' + str(constraint_matrix.ndim)) + + print(constraint_matrix) + +