2222#include < pybind11/numpy.h>
2323
2424#include < sofa/simulation/Simulation.h>
25+ #include < sofa/simulation/mechanicalvisitor/MechanicalComputeEnergyVisitor.h>
2526#include < sofa/core/ComponentNameHelper.h>
2627
2728#include < sofa/core/objectmodel/BaseData.h>
@@ -234,9 +235,47 @@ void setFieldsFromPythonValues(Base* self, const py::kwargs& dict)
234235 }
235236}
236237
238+ class NumpyReprFixerRAII
239+ {
240+ public:
241+ NumpyReprFixerRAII ()
242+ {
243+ using namespace pybind11 ::literals;
244+
245+ m_numpy = py::module_::import (" numpy" );
246+ const std::string version = py::cast<std::string>(m_numpy.attr (" __version__" ));
247+ m_majorVersion = std::stoi (version.substr (0 ,1 ));
248+ if ( m_majorVersion > 1 )
249+ {
250+ m_setPO = m_numpy.attr (" set_printoptions" );
251+ m_initialState = m_numpy.attr (" get_printoptions" )();
252+ m_setPO (" legacy" _a = true );
253+ }
254+ }
255+
256+ ~NumpyReprFixerRAII ()
257+ {
258+ if ( m_majorVersion > 1 )
259+ {
260+ m_setPO (**m_initialState);
261+ }
262+ }
263+
264+ private:
265+ py::module_ m_numpy;
266+ int m_majorVersion;
267+ py::object m_setPO;
268+ py::dict m_initialState;
269+
270+ };
271+
272+
237273// / Implement the addObject function.
238274py::object addObjectKwargs (Node* self, const std::string& type, const py::kwargs& kwargs)
239275{
276+ // Instantiating this object will make sure the numpy representation is fixed during the call of this function, and comes back to its previous state after
277+ [[maybe_unused]] const NumpyReprFixerRAII numpyReprFixer;
278+
240279 std::string name {};
241280 if (kwargs.contains (" name" ))
242281 {
@@ -291,6 +330,8 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs
291330 if (d)
292331 d->setPersistent (true );
293332 }
333+
334+
294335 return PythonFactory::toPython (object.get ());
295336}
296337
@@ -360,6 +401,9 @@ py::object createObject(Node* self, const std::string& type, const py::kwargs& k
360401
361402py::object addChildKwargs (Node* self, const std::string& name, const py::kwargs& kwargs)
362403{
404+ // Instantiating this object will make sure the numpy representation is fixed during the call of this function, and comes back to its previous state after
405+ [[maybe_unused]] const NumpyReprFixerRAII numpyReprFixer;
406+
363407 if (sofapython3::isProtectedKeyword (name))
364408 throw py::value_error (" addChild: Cannot call addChild with name " + name + " : Protected keyword" );
365409 BaseObjectDescription desc (name.c_str ());
@@ -378,6 +422,7 @@ py::object addChildKwargs(Node* self, const std::string& name, const py::kwargs&
378422 d->setPersistent (true );
379423 }
380424
425+
381426 return py::cast (node);
382427}
383428
@@ -606,6 +651,15 @@ void sendEvent(Node* self, py::object pyUserData, char* eventName)
606651 self->propagateEvent (sofa::core::execparams::defaultInstance (), &event);
607652}
608653
654+ py::object computeEnergy (Node* self)
655+ {
656+ sofa::simulation::mechanicalvisitor::MechanicalComputeEnergyVisitor energyVisitor (sofa::core::mechanicalparams::defaultInstance ());
657+ energyVisitor.execute (self->getContext ());
658+ const SReal kineticEnergy = energyVisitor.getKineticEnergy ();
659+ const SReal potentialEnergy = energyVisitor.getPotentialEnergy ();
660+ return py::cast (std::make_tuple (kineticEnergy, potentialEnergy));
661+ }
662+
609663}
610664
611665void moduleAddNode (py::module &m) {
@@ -660,6 +714,7 @@ void moduleAddNode(py::module &m) {
660714 p.def (" getMechanicalState" , &getMechanicalState, sofapython3::doc::sofa::core::Node::getMechanicalState);
661715 p.def (" getMechanicalMapping" , &getMechanicalMapping, sofapython3::doc::sofa::core::Node::getMechanicalMapping);
662716 p.def (" sendEvent" , &sendEvent, sofapython3::doc::sofa::core::Node::sendEvent);
717+ p.def (" computeEnergy" , &computeEnergy, sofapython3::doc::sofa::core::Node::computeEnergy);
663718
664719}
665720} // / namespace sofapython3
0 commit comments