From ba947da77ce273f0db0328f89a73d208522ead8a Mon Sep 17 00:00:00 2001 From: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Thu, 14 Nov 2024 00:46:08 +0100 Subject: [PATCH 01/24] [All] Clean collision detection in FreeMotionAnimationLoop (#5042) * Divided constraint visitors and removed timers in pipeline (need to add them in the animation loops * Chaged to SCOPED_TIMER * Fix for SOFA_DUMP_VISITOR_INFO * Update Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h Co-authored-by: Hugo * Update Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h Co-authored-by: Hugo * Update Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h Co-authored-by: Hugo --------- Co-authored-by: Hugo --- .../animationloop/FreeMotionAnimationLoop.cpp | 15 +++- .../src/sofa/simulation/CollisionVisitor.cpp | 84 +++++++++++++------ .../src/sofa/simulation/CollisionVisitor.h | 56 +++++++++---- .../Core/src/sofa/simulation/PipelineImpl.cpp | 3 - 4 files changed, 112 insertions(+), 46 deletions(-) diff --git a/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.cpp b/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.cpp index c9b6066388f..3e53dc399d4 100644 --- a/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.cpp +++ b/Sofa/Component/AnimationLoop/src/sofa/component/animationloop/FreeMotionAnimationLoop.cpp @@ -352,7 +352,14 @@ void FreeMotionAnimationLoop::computeFreeMotionAndCollisionDetection(const sofa: preCollisionComputation(params); { - ScopedAdvancedTimer collisionResetTimer("CollisionReset"); + SCOPED_TIMER("ProcessGeometricalData"); + ProcessGeometricalDataVisitor act(params); + act.setTags(this->getTags()); + act.execute(node); + } + + { + SCOPED_TIMER("CollisionReset"); CollisionResetVisitor act(params); act.setTags(this->getTags()); act.execute(node); @@ -362,19 +369,19 @@ void FreeMotionAnimationLoop::computeFreeMotionAndCollisionDetection(const sofa: taskScheduler->addTask(freeMotionTaskStatus, [&]() { computeFreeMotion(params, cparams, dt, pos, freePos, freeVel, mop); }); { - ScopedAdvancedTimer collisionDetectionTimer("CollisionDetection"); + SCOPED_TIMER("CollisionDetection"); CollisionDetectionVisitor act(params); act.setTags(this->getTags()); act.execute(node); } { - ScopedAdvancedTimer waitFreeMotionTimer("WaitFreeMotion"); + SCOPED_TIMER("WaitFreeMotion"); taskScheduler->workUntilDone(&freeMotionTaskStatus); } { - ScopedAdvancedTimer collisionResponseTimer("CollisionResponse"); + SCOPED_TIMER("CollisionResponse"); CollisionResponseVisitor act(params); act.setTags(this->getTags()); act.execute(node); diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.cpp index 07860267cf1..9f3d3f27558 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.cpp @@ -30,34 +30,12 @@ namespace sofa::simulation { -Visitor::Result CollisionVisitor::processNodeTopDown(simulation::Node* node) -{ - for_each(this, node, node->constraintSet, &CollisionVisitor::fwdConstraintSet); - for_each(this, node, node->collisionPipeline, &CollisionVisitor::processCollisionPipeline); - return RESULT_CONTINUE; -} -void CollisionVisitor::fwdConstraintSet(simulation::Node* +void BaseCollisionVisitor::processCollisionPipeline(simulation::Node* #ifdef SOFA_DUMP_VISITOR_INFO - node + node #endif - , core::behavior::BaseConstraintSet* c) -{ -#ifdef SOFA_DUMP_VISITOR_INFO - printComment("computeCollisionDetectionInConstraints"); - ctime_t t0=begin(node, c); -#endif - c->processGeometricalData(); -#ifdef SOFA_DUMP_VISITOR_INFO - end(node, c,t0); -#endif -} - -void CollisionVisitor::processCollisionPipeline(simulation::Node* -#ifdef SOFA_DUMP_VISITOR_INFO - node -#endif - , core::collision::Pipeline* obj) + , core::collision::Pipeline* obj) { //msg_info()<<"CollisionVisitor::processCollisionPipeline"<collisionPipeline, &BaseCollisionVisitor::processCollisionPipeline); + return RESULT_CONTINUE; +} + + +void CollisionVisitor::fwdConstraintSet(simulation::Node* +#ifdef SOFA_DUMP_VISITOR_INFO + node +#endif + , core::behavior::BaseConstraintSet* c) +{ +#ifdef SOFA_DUMP_VISITOR_INFO + printComment("computeCollisionDetectionInConstraints"); + ctime_t t0=begin(node, c); +#endif + c->processGeometricalData(); +#ifdef SOFA_DUMP_VISITOR_INFO + end(node, c,t0); +#endif +} + +void ProcessGeometricalDataVisitor::fwdConstraintSet(simulation::Node* +#ifdef SOFA_DUMP_VISITOR_INFO + node +#endif + , core::behavior::BaseConstraintSet* c) +{ +#ifdef SOFA_DUMP_VISITOR_INFO + printComment("computeCollisionDetectionInConstraints"); + ctime_t t0=begin(node, c); +#endif + c->processGeometricalData(); +#ifdef SOFA_DUMP_VISITOR_INFO + end(node, c,t0); +#endif +} + +Visitor::Result ProcessGeometricalDataVisitor::processNodeTopDown(simulation::Node* node) +{ + for_each,core::behavior::BaseConstraintSet>(this, node, node->constraintSet, &ProcessGeometricalDataVisitor::fwdConstraintSet); + return RESULT_CONTINUE; +} + +Visitor::Result CollisionVisitor::processNodeTopDown(simulation::Node* node) +{ + for_each,core::behavior::BaseConstraintSet>(this, node, node->constraintSet, &CollisionVisitor::fwdConstraintSet); + for_each,sofa::core::collision::Pipeline>(this, node, node->collisionPipeline, &CollisionVisitor::processCollisionPipeline); + return RESULT_CONTINUE; +} + + + void CollisionResetVisitor::processCollisionPipeline(simulation::Node* #ifdef SOFA_DUMP_VISITOR_INFO node diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h index d0d31ebba19..424557400bb 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/CollisionVisitor.h @@ -30,13 +30,10 @@ namespace sofa::simulation { -/// Compute collision reset, detection and response in one step -class SOFA_SIMULATION_CORE_API CollisionVisitor : public Visitor +class SOFA_SIMULATION_CORE_API BaseCollisionVisitor : public Visitor { -public: - CollisionVisitor(const core::ExecParams* params) :Visitor(params) , m_primitiveTestCount(0) {} - - virtual void fwdConstraintSet(simulation::Node* node, core::behavior::BaseConstraintSet* cSet); + public: + BaseCollisionVisitor(const core::ExecParams* params) :Visitor(params) , m_primitiveTestCount(0) {} virtual void processCollisionPipeline(simulation::Node* node, core::collision::Pipeline* obj); @@ -45,37 +42,68 @@ class SOFA_SIMULATION_CORE_API CollisionVisitor : public Visitor /// Return a category name for this action. /// Only used for debugging / profiling purposes const char* getCategoryName() const override { return "collision"; } - const char* getClassName() const override { return "CollisionVisitor"; } + const char* getClassName() const override { return "BaseCollisionVisitor"; } size_t getPrimitiveTestCount() const {return m_primitiveTestCount;} -private: + private: size_t m_primitiveTestCount; }; +class SOFA_SIMULATION_CORE_API ProcessGeometricalDataVisitor : public Visitor +{ + public: + ProcessGeometricalDataVisitor(const core::ExecParams* params) :Visitor(params) {} + + virtual void fwdConstraintSet(simulation::Node* node, core::behavior::BaseConstraintSet* cSet); + Result processNodeTopDown(simulation::Node* node) override; + + /// Return a category name for this action. + /// Only used for debugging / profiling purposes + const char* getCategoryName() const override { return "collision"; } + const char* getClassName() const override { return "ProcessGeometricalDataVisitor"; } + +}; + +/// Compute collision reset, detection and response in one step +class SOFA_SIMULATION_CORE_API CollisionVisitor : public BaseCollisionVisitor +{ +public: + CollisionVisitor(const core::ExecParams* params) : BaseCollisionVisitor(params) {} + + virtual void fwdConstraintSet(simulation::Node* node, core::behavior::BaseConstraintSet* cSet); + Result processNodeTopDown(simulation::Node* node) override; + + /// Return a category name for this action. + /// Only used for debugging / profiling purposes + const char* getCategoryName() const override { return "collision"; } + const char* getClassName() const override { return "CollisionVisitor"; } + +}; + /// Remove collision response from last step -class SOFA_SIMULATION_CORE_API CollisionResetVisitor : public CollisionVisitor +class SOFA_SIMULATION_CORE_API CollisionResetVisitor : public BaseCollisionVisitor { public: - CollisionResetVisitor(const core::ExecParams* params) :CollisionVisitor(params) {} + CollisionResetVisitor(const core::ExecParams* params) : BaseCollisionVisitor(params) {} void processCollisionPipeline(simulation::Node* node, core::collision::Pipeline* obj) override; const char* getClassName() const override { return "CollisionResetVisitor"; } }; /// Compute collision detection -class SOFA_SIMULATION_CORE_API CollisionDetectionVisitor : public CollisionVisitor +class SOFA_SIMULATION_CORE_API CollisionDetectionVisitor : public BaseCollisionVisitor { public: - CollisionDetectionVisitor(const core::ExecParams* params) :CollisionVisitor(params) {} + CollisionDetectionVisitor(const core::ExecParams* params) : BaseCollisionVisitor(params) {} void processCollisionPipeline(simulation::Node* node, core::collision::Pipeline* obj) override; const char* getClassName() const override { return "CollisionDetectionVisitor"; } }; /// Compute collision response -class SOFA_SIMULATION_CORE_API CollisionResponseVisitor : public CollisionVisitor +class SOFA_SIMULATION_CORE_API CollisionResponseVisitor : public BaseCollisionVisitor { public: - CollisionResponseVisitor(const core::ExecParams* params) :CollisionVisitor(params) {} + CollisionResponseVisitor(const core::ExecParams* params) : BaseCollisionVisitor(params) {} void processCollisionPipeline(simulation::Node* node, core::collision::Pipeline* obj) override; const char* getClassName() const override { return "CollisionResponseVisitor"; } }; diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/PipelineImpl.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/PipelineImpl.cpp index f0cd613d37a..08e6e1087e5 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/PipelineImpl.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/PipelineImpl.cpp @@ -106,7 +106,6 @@ void PipelineImpl::computeCollisionReset() if (contactManager!=nullptr && contactManager->getIntersectionMethod()!=intersectionMethod) contactManager->setIntersectionMethod(intersectionMethod); - SCOPED_TIMER("CollisionReset"); doCollisionReset(); } @@ -114,7 +113,6 @@ void PipelineImpl::computeCollisionDetection() { simulation::Node* root = dynamic_cast(getContext()); if(root == nullptr) return; - SCOPED_TIMER("CollisionDetection"); std::vector collisionModels; root->getTreeObjects(&collisionModels); doCollisionDetection(collisionModels); @@ -125,7 +123,6 @@ void PipelineImpl::computeCollisionResponse() const simulation::Node* root = dynamic_cast(getContext()); if(root == nullptr) return; - SCOPED_TIMER("CollisionResponse"); doCollisionResponse(); } From 882c296a1a4b2202afff716bcfd89f75297c0c1a Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 14 Nov 2024 04:06:23 +0100 Subject: [PATCH 02/24] [all] Compatibility with C++20 (#5056) * Fix std::memory_order according to changes in C++20 The new code should be compatible with C++17 as well * declare BilateralLagrangianConstraint::bwdInit specialization * simplify real type * remove duplicated using * scope initData to direct parent * remove forward declaration * Missing aliases cause compilation fail --- .../model/BilateralLagrangianConstraint.h | 3 +++ .../lagrangian/solver/ConstraintSolverImpl.cpp | 2 +- .../component/engine/transform/Vertex2Frame.inl | 2 +- .../BaseAssemblingMatrixAccumulator.h | 1 - .../sofa/component/mapping/linear/IdentityMapping.h | 4 ++++ .../sofa/component/mapping/nonlinear/RigidMapping.h | 4 ++++ .../Core/src/sofa/core/objectmodel/BaseClass.h | 13 ++++++++++++- .../src/sofa/simulation/DefaultTaskScheduler.cpp | 4 ++-- .../src/sofa/simulation/DefaultVisualManagerLoop.h | 7 +------ 9 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h index 93a0aeff7c9..f986ad3321b 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h @@ -189,6 +189,9 @@ class BilateralLagrangianConstraint : public PairInteractionConstraint SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API +void BilateralLagrangianConstraint::bwdInit(); + #if !defined(SOFA_COMPONENT_CONSTRAINTSET_BILATERALLAGRANGIANCONSTRAINT_CPP) extern template class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API BilateralLagrangianConstraint< Vec3Types >; diff --git a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/ConstraintSolverImpl.cpp b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/ConstraintSolverImpl.cpp index 5278af3faa9..2e9105b45b9 100644 --- a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/ConstraintSolverImpl.cpp +++ b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/ConstraintSolverImpl.cpp @@ -52,7 +52,7 @@ void ConstraintProblem::clear(int nbConstraints) f.resize(nbConstraints); static std::atomic counter = 0; - problemId = counter.fetch_add(1, std::memory_order::memory_order_relaxed); + problemId = counter.fetch_add(1, std::memory_order_relaxed); } unsigned int ConstraintProblem::getProblemId() diff --git a/Sofa/Component/Engine/Transform/src/sofa/component/engine/transform/Vertex2Frame.inl b/Sofa/Component/Engine/Transform/src/sofa/component/engine/transform/Vertex2Frame.inl index af00c92cec7..abed2ed8c5b 100644 --- a/Sofa/Component/Engine/Transform/src/sofa/component/engine/transform/Vertex2Frame.inl +++ b/Sofa/Component/Engine/Transform/src/sofa/component/engine/transform/Vertex2Frame.inl @@ -28,7 +28,7 @@ namespace sofa::component::engine::transform { template -const typename Vertex2Frame::Real Vertex2Frame::EPSILON = std::numeric_limits::Real>::epsilon(); +const Real_t Vertex2Frame::EPSILON = std::numeric_limits>::epsilon(); template Vertex2Frame::Vertex2Frame(): diff --git a/Sofa/Component/LinearSystem/src/sofa/component/linearsystem/matrixaccumulators/BaseAssemblingMatrixAccumulator.h b/Sofa/Component/LinearSystem/src/sofa/component/linearsystem/matrixaccumulators/BaseAssemblingMatrixAccumulator.h index be731087f49..68aa75f4ae0 100644 --- a/Sofa/Component/LinearSystem/src/sofa/component/linearsystem/matrixaccumulators/BaseAssemblingMatrixAccumulator.h +++ b/Sofa/Component/LinearSystem/src/sofa/component/linearsystem/matrixaccumulators/BaseAssemblingMatrixAccumulator.h @@ -34,7 +34,6 @@ class BaseAssemblingMatrixAccumulator : public sofa::core::get_base_object_stron SOFA_CLASS(SOFA_TEMPLATE(BaseAssemblingMatrixAccumulator, c), sofa::core::get_base_object_strong_type); using ComponentType = typename Inherit1::ComponentType; - using Inherit1::initData; using Inherit1::add; virtual void setMatrixSize(const sofa::type::Vec2u&); diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMapping.h index 19f37bf1ff7..5b926849ced 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMapping.h @@ -50,6 +50,8 @@ class IdentityMapping : public LinearMapping typedef typename In::Coord InCoord; typedef typename In::Deriv InDeriv; typedef typename In::MatrixDeriv InMatrixDeriv; + typedef Data InDataVecCoord; + typedef Data InDataVecDeriv; typedef typename Out::VecCoord VecCoord; typedef typename Out::VecDeriv VecDeriv; @@ -61,6 +63,8 @@ class IdentityMapping : public LinearMapping typedef typename OutDataTypes::Real OutReal; typedef typename OutDataTypes::VecCoord OutVecCoord; typedef typename OutDataTypes::VecDeriv OutVecDeriv; + typedef Data OutDataVecCoord; + typedef Data OutDataVecDeriv; enum { diff --git a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.h b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.h index 316b04215fd..5f61362a380 100644 --- a/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.h +++ b/Sofa/Component/Mapping/NonLinear/src/sofa/component/mapping/nonlinear/RigidMapping.h @@ -60,6 +60,8 @@ class RigidMapping : public core::Mapping, public NonLinearMappingDat typedef typename Out::VecCoord OutVecCoord; typedef typename Out::VecDeriv OutVecDeriv; typedef typename Out::MatrixDeriv OutMatrixDeriv; + typedef Data OutDataVecCoord; + typedef Data OutDataVecDeriv; typedef typename In::Real InReal; typedef typename In::Coord InCoord; @@ -67,6 +69,8 @@ class RigidMapping : public core::Mapping, public NonLinearMappingDat typedef typename In::VecCoord InVecCoord; typedef typename In::VecDeriv InVecDeriv; typedef typename In::MatrixDeriv InMatrixDeriv; + typedef Data InDataVecCoord; + typedef Data InDataVecDeriv; enum { diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseClass.h b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseClass.h index 6c169779e64..de03c1ac860 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseClass.h +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseClass.h @@ -111,6 +111,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef T MyType; \ typedef ::sofa::core::objectmodel::TClass< T, Parent > MyClass; \ typedef Parent Inherit1; \ + using Parent::initData; \ SOFA_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 1 base class @@ -118,6 +119,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef T MyType; \ typedef ::sofa::core::objectmodel::TClass< T, Parent > MyClass; \ typedef Parent Inherit1; \ + using Parent::initData; \ SOFA_ABSTRACT_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 2 base classes @@ -126,6 +128,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef ::sofa::core::objectmodel::TClass< T, ::sofa::core::objectmodel::Parents > MyClass; \ typedef Parent1 Inherit1; \ typedef Parent2 Inherit2; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 2 base classes @@ -134,6 +137,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef ::sofa::core::objectmodel::TClass< T, ::sofa::core::objectmodel::Parents > MyClass; \ typedef Parent1 Inherit1; \ typedef Parent2 Inherit2; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_ABSTRACT_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 3 base classes @@ -143,6 +147,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent1 Inherit1; \ typedef Parent2 Inherit2; \ typedef Parent3 Inherit3; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 3 base classes @@ -152,6 +157,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent1 Inherit1; \ typedef Parent2 Inherit2; \ typedef Parent3 Inherit3; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_ABSTRACT_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 4 base classes @@ -162,6 +168,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent2 Inherit2; \ typedef Parent3 Inherit3; \ typedef Parent4 Inherit4; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 4 base classes @@ -172,6 +179,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent2 Inherit2; \ typedef Parent3 Inherit3; \ typedef Parent4 Inherit4; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_ABSTRACT_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 5 base classes @@ -183,6 +191,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent3 Inherit3; \ typedef Parent4 Inherit4; \ typedef Parent5 Inherit5; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 5 base classes @@ -194,6 +203,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent3 Inherit3; \ typedef Parent4 Inherit4; \ typedef Parent5 Inherit5; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_ABSTRACT_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 5 base classes @@ -206,6 +216,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent4 Inherit4; \ typedef Parent5 Inherit5; \ typedef Parent6 Inherit6; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_CLASS_DECL // This macro should now be used at the beginning of all declarations of classes with 5 base classes @@ -218,6 +229,7 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass typedef Parent4 Inherit4; \ typedef Parent5 Inherit5; \ typedef Parent6 Inherit6; \ + using ::sofa::core::objectmodel::Base::initData; \ SOFA_ABSTRACT_CLASS_DECL // Do not use this macro directly, use SOFA_ABSTRACT_CLASS instead @@ -230,7 +242,6 @@ class SOFA_CORE_API DeprecatedBaseClass : public BaseClass virtual const ::sofa::core::objectmodel::BaseClass* getClass() const override \ { return GetClass(); } \ static const char* HeaderFileLocation() { return __FILE__; } \ - using ::sofa::core::objectmodel::Base::initData; \ ::sofa::core::objectmodel::BaseLink::InitLink \ initLink(const char* name, const char* help) \ { \ diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultTaskScheduler.cpp b/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultTaskScheduler.cpp index 3672db0ce3f..5cb3450212f 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultTaskScheduler.cpp +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultTaskScheduler.cpp @@ -224,12 +224,12 @@ void DefaultTaskScheduler::WaitForWorkersToBeReady() void DefaultTaskScheduler::setMainTaskStatus(const Task::Status* mainTaskStatus) { - m_mainTaskStatus.store(mainTaskStatus, std::memory_order::memory_order_relaxed); + m_mainTaskStatus.store(mainTaskStatus, std::memory_order_relaxed); } bool DefaultTaskScheduler::testMainTaskStatus(const Task::Status* status) { - return m_mainTaskStatus.load(std::memory_order::memory_order_relaxed) == status; + return m_mainTaskStatus.load(std::memory_order_relaxed) == status; } } // namespace sofa::simulation diff --git a/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultVisualManagerLoop.h b/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultVisualManagerLoop.h index 97fd310dc7c..2f18bfae51c 100644 --- a/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultVisualManagerLoop.h +++ b/Sofa/framework/Simulation/Core/src/sofa/simulation/DefaultVisualManagerLoop.h @@ -25,13 +25,8 @@ #include #include #include +#include -namespace sofa::core::objectmodel -{ -// Forward declaration for extern template declaration. This design permit to -// not #include -extern template class SingleLink< sofa::simulation::DefaultVisualManagerLoop, simulation::Node, BaseLink::FLAG_STOREPATH>; -} namespace sofa::simulation { From fce8e193566ead4d8b06f6b20362a4812cb52fa2 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 14 Nov 2024 07:50:18 +0100 Subject: [PATCH 03/24] [Core] Test for nullptr in force field creation (#5075) * [Core] Test for nullptr in force field creation * return false if context is null + check for arg --- .../Core/src/sofa/core/behavior/ForceField.h | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h b/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h index 3b9caa987e6..8feb151c463 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h +++ b/Sofa/framework/Core/src/sofa/core/behavior/ForceField.h @@ -189,28 +189,43 @@ class ForceField : public BaseForceField, public SingleStateAccessor template static bool canCreate(T*& obj, objectmodel::BaseContext* context, objectmodel::BaseObjectDescription* arg) { - const std::string attributeName {"mstate"}; - std::string mstateLink = arg->getAttribute(attributeName,""); - if (mstateLink.empty()) + if (context) { - if (dynamic_cast*>(context->getMechanicalState()) == nullptr) + if (arg) { - arg->logError("Since the attribute '" + attributeName + "' has not been specified, a mechanical state " - "with the datatype '" + DataTypes::Name() + "' has been searched in the current context, but not found."); - return false; + static const std::string attributeName {"mstate"}; + const std::string mstateLink = arg->getAttribute(attributeName,""); + if (mstateLink.empty()) + { + if (dynamic_cast*>(context->getMechanicalState()) == nullptr) + { + arg->logError("Since the attribute '" + attributeName + "' has not been specified, a mechanical state " + "with the datatype '" + DataTypes::Name() + "' has been searched in the current context, but not found."); + return false; + } + } + else + { + MechanicalState* mstate = nullptr; + context->findLinkDest(mstate, mstateLink, nullptr); + if (!mstate) + { + arg->logError("Data attribute '" + attributeName + "' does not point to a valid mechanical state of datatype '" + std::string(DataTypes::Name()) + "'."); + return false; + } + } } - } - else - { - MechanicalState* mstate = nullptr; - context->findLinkDest(mstate, mstateLink, nullptr); - if (!mstate) + else { - arg->logError("Data attribute '" + attributeName + "' does not point to a valid mechanical state of datatype '" + std::string(DataTypes::Name()) + "'."); - return false; + if (dynamic_cast*>(context->getMechanicalState()) == nullptr) + { + return false; + } } + + return BaseObject::canCreate(obj, context, arg); } - return BaseObject::canCreate(obj, context, arg); + return false; } template From 7d7d5cf9bfc5ac177e5db076a9ec9d03d771bbf6 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 14 Nov 2024 17:43:27 +0100 Subject: [PATCH 04/24] [Gl.Component] Swap data description in OglColorMap (#5118) --- .../src/sofa/gl/component/rendering2d/OglColorMap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sofa/GL/Component/Rendering2D/src/sofa/gl/component/rendering2d/OglColorMap.cpp b/Sofa/GL/Component/Rendering2D/src/sofa/gl/component/rendering2d/OglColorMap.cpp index fa4c6a1f262..91ba9cc396f 100644 --- a/Sofa/GL/Component/Rendering2D/src/sofa/gl/component/rendering2d/OglColorMap.cpp +++ b/Sofa/GL/Component/Rendering2D/src/sofa/gl/component/rendering2d/OglColorMap.cpp @@ -43,8 +43,8 @@ OglColorMap::OglColorMap() , d_colorScheme(initData(&d_colorScheme, "colorScheme", "Color scheme to use")) , d_showLegend(initData(&d_showLegend, false, "showLegend", "Activate rendering of color scale legend on the side")) , d_legendOffset(initData(&d_legendOffset, type::Vec2f(10.0f,5.0f),"legendOffset", "Draw the legend on screen with an x,y offset")) -, d_legendTitle(initData(&d_legendTitle,"legendTitle", "Font size of the legend (if any)")) -, d_legendSize(initData(&d_legendSize, 11u, "legendSize", "Add a title to the legend")) +, d_legendTitle(initData(&d_legendTitle,"legendTitle", "Add a title to the legend")) +, d_legendSize(initData(&d_legendSize, 11u, "legendSize", "Font size of the legend (if any)")) , d_min(initData(&d_min,0.0f,"min","min value for drawing the legend without the need to actually use the range with getEvaluator method which sets the min")) , d_max(initData(&d_max,0.0f,"max","max value for drawing the legend without the need to actually use the range with getEvaluator method which sets the max")) , d_legendRangeScale(initData(&d_legendRangeScale,1.f,"legendRangeScale","to change the unit of the min/max value of the legend")) From e27e1a1745804721dc09531899e1950e94c86a30 Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Fri, 15 Nov 2024 17:13:36 +0900 Subject: [PATCH 05/24] [Core] Fix isSet flag when setting a link to a not-yet created data (#5081) * set isset flag even if the parent is null * add tests * add test with a bogus link path --------- Co-authored-by: Paul Baksic <30337881+bakpaul@users.noreply.github.com> --- .../src/sofa/core/objectmodel/BaseData.cpp | 9 +++- .../SimpleApi/test/SimpleApi_test.cpp | 52 +++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseData.cpp b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseData.cpp index 3d16511118f..d449b0b7a7e 100644 --- a/Sofa/framework/Core/src/sofa/core/objectmodel/BaseData.cpp +++ b/Sofa/framework/Core/src/sofa/core/objectmodel/BaseData.cpp @@ -128,9 +128,14 @@ bool BaseData::setParent(BaseData* parent, const std::string& path) addInput(parent); BaseData::setDirtyValue(); m_counter++; - m_isSet = true; - }else if (!path.empty()) + } + // the referenced parent data has not been created yet but a path has been given + else if (!path.empty()) + { parentData.setPath(path); + } + + m_isSet = true; return true; } diff --git a/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp b/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp index dc5ae56c599..f9c26dfccd7 100644 --- a/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp +++ b/Sofa/framework/SimpleApi/test/SimpleApi_test.cpp @@ -90,3 +90,55 @@ TEST_F(SimpleApi_test, createParamString ) { ASSERT_TRUE( testParamString() ); } + +TEST(SimpleApi_test_solo, testIsSetWithDataLink) +{ + const Simulation::SPtr simu = createSimulation("DAG"); + const Node::SPtr root = createRootNode(simu, "root"); + + // test not set + const auto obj1 = createObject(root, "DefaultAnimationLoop", { + {"name", "loop1"} + }); + auto* objdata1 = obj1->findData("printLog"); + ASSERT_FALSE(objdata1->isSet()); + + // test set + const auto obj2 = createObject(root, "DefaultAnimationLoop", { + {"name", "loop2"}, + {"printLog", "false"} + }); + auto* objdata2 = obj2->findData("printLog"); + ASSERT_TRUE(objdata2->isSet()); + + // test set through a link of a already created object + const auto obj3 = createObject(root, "DefaultAnimationLoop", { + {"name", "loop3"}, + {"printLog", "@/loop2.printLog"} + }); + auto* objdata3 = obj3->findData("printLog"); + ASSERT_TRUE(objdata3->isSet()); + + // test set through a link of a not yet created object (deferred linking) + const auto obj4 = createObject(root, "DefaultAnimationLoop", { + {"name", "loop4"}, + {"printLog", "@/loop5.printLog"} + }); + const auto obj5 = createObject(root, "DefaultAnimationLoop", { + {"name", "loop5"}, + {"printLog", "true"} + }); + auto* objdata4 = obj4->findData("printLog"); + ASSERT_TRUE(objdata4->isSet()); + + // test link with a wrong path (or non existent parent) + const auto obj6 = createObject(root, "DefaultAnimationLoop", { + {"name", "loop6"}, + {"printLog", "@/loop7.printLog"} + }); + + auto* objdata6 = obj6->findData("printLog"); + ASSERT_TRUE(objdata6->isSet()); + ASSERT_EQ(objdata6->getParent(), nullptr); + +} From 0da5cddcfb719b8eb6905f17d2cc109c06ad9a7b Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Fri, 15 Nov 2024 09:52:54 +0100 Subject: [PATCH 06/24] [test] Add test on Data link between 1d vectors (#5119) Co-authored-by: Paul Baksic <30337881+bakpaul@users.noreply.github.com> --- .../Core/test/objectmodel/DataLink_test.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp b/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp index 5224554b18f..34cd074c650 100644 --- a/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp +++ b/Sofa/framework/Core/test/objectmodel/DataLink_test.cpp @@ -40,7 +40,6 @@ struct DataLink_test: public BaseTest Data dataVec3f; Data dataVec3d; - /// This method is defined in gtest framework to setting the test up. void SetUp() override { /// Setup the data and create a link between the two data @@ -58,7 +57,7 @@ struct DataLink_test: public BaseTest } }; -/// This test check that the setting/unsetting mechanisme when the value is changed is working +/// This test check that the setting/unsetting mechanism when the value is changed is working /// Currently in Sofa the parenting link is not broken if the value is written. TEST_F(DataLink_test, UnsetByValue) { @@ -79,7 +78,19 @@ TEST_F(DataLink_test, SetParentOfDifferentType) ASSERT_FLOAT_EQ(dataVec3f.getValue().z(), 3.0f); } -/// This test check that the setting/unsetting mechanisme is working +TEST_F(DataLink_test, SetParentOfDifferentType2) +{ + Data> dataVecVec1d; + Data> dataVecSReal; + + ASSERT_TRUE(dataVecSReal.setParent(&dataVecVec1d)); + ASSERT_TRUE(dataVecVec1d.getParent() == nullptr); + dataVecVec1d.setValue({sofa::type::Vec1d(1.0), sofa::type::Vec1d(2.0)}); + ASSERT_DOUBLE_EQ(dataVecSReal.getValue()[0], 1.); + ASSERT_DOUBLE_EQ(dataVecSReal.getValue()[1], 2.); +} + +/// This test check that the setting/unsetting mechanism is working TEST_F(DataLink_test, Set) { ASSERT_EQ(data1.getParent(),nullptr); @@ -89,7 +100,7 @@ TEST_F(DataLink_test, Set) ASSERT_EQ(data2.getParent(), &data1); } -/// This test check that the setting/unsetting mechanisme is working +/// This test check that the setting/unsetting mechanism is working TEST_F(DataLink_test, Unset) { ASSERT_EQ(data1.getParent(),nullptr); From 1c8b807d3fb0eab2a36df513ede87bc71c27363d Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Fri, 15 Nov 2024 09:53:14 +0100 Subject: [PATCH 07/24] [GL.Component] Fix min max computation in DataDisplay (#5120) * [GL.Component] Fix min max computation in DataDisplay * rename variables according to guidelines --- .../gl/component/rendering3d/DataDisplay.cpp | 17 ++++++++--------- .../sofa/gl/component/rendering3d/DataDisplay.h | 5 +++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.cpp b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.cpp index 2249b18d5e1..d126f8ac906 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.cpp +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.cpp @@ -56,8 +56,8 @@ DataDisplay::DataDisplay() , state(nullptr) , m_topology(nullptr) , l_topology(initLink("topology", "link to the topology container")) - , oldMin(0) - , oldMax(0) + , m_oldMin(std::numeric_limits::max()) + , m_oldMax(std::numeric_limits::lowest()) { this->addAlias(&f_triangleData,"cellData"); // backward compatibility d_currentMin.setReadOnly(true); @@ -141,9 +141,8 @@ void DataDisplay::doDrawVisual(const core::visual::VisualParams* vparams) } // Range for points - Real min ; - Real max ; - min = max = 0; + Real min = std::numeric_limits::max(); + Real max = std::numeric_limits::lowest(); if (bDrawPointData) { VecPointData::const_iterator i = ptData.begin(); min = *i; @@ -212,12 +211,12 @@ void DataDisplay::doDrawVisual(const core::visual::VisualParams* vparams) } - if (max > oldMax) oldMax = max; - if (min < oldMin) oldMin = min; + if (max > m_oldMax) m_oldMax = max; + if (min < m_oldMin) m_oldMin = min; if (f_maximalRange.getValue()) { - max = oldMax; - min = oldMin; + max = m_oldMax; + min = m_oldMin; } d_currentMin.setValue(min); d_currentMax.setValue(max); diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.h b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.h index 91491ef5d43..91bb25b1acb 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.h +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/DataDisplay.h @@ -66,8 +66,6 @@ class SOFA_GL_COMPONENT_RENDERING3D_API DataDisplay : public core::visual::Visua /// Link to be set to the topology container in the component graph. SingleLink l_topology; - Real oldMin, oldMax; - void init() override; void doDrawVisual(const core::visual::VisualParams* vparams) override; void doUpdateVisual(const core::visual::VisualParams* vparams) override; @@ -80,6 +78,9 @@ class SOFA_GL_COMPONENT_RENDERING3D_API DataDisplay : public core::visual::Visua type::vector m_normals; DataDisplay(); + + Real m_oldMin, m_oldMax; + }; } // namespace sofa::gl::component::rendering3d From 45e8233e33c3b3080ef05f399abebe31f7bdef4c Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 18 Nov 2024 01:33:31 +0100 Subject: [PATCH 08/24] [Type] Consistent string to color conversion (#5121) * [Type] Consistent string to color conversion * rename --- .../Type/src/sofa/type/RGBAColor.cpp | 45 +++++++++++---- Sofa/framework/Type/src/sofa/type/RGBAColor.h | 56 +++++++++++++++---- Sofa/framework/Type/test/CMakeLists.txt | 2 +- .../{Color_test.cpp => RGBAColor_test.cpp} | 13 +++++ 4 files changed, 92 insertions(+), 24 deletions(-) rename Sofa/framework/Type/test/{Color_test.cpp => RGBAColor_test.cpp} (90%) diff --git a/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp b/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp index 611ed9d0687..79c4aebe25a 100644 --- a/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp +++ b/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -176,6 +177,30 @@ static std::istream& trimInitialSpaces(std::istream& in) return in; } +const std::map stringToColorMap { + {"white", g_white}, + {"black", g_black}, + {"red", g_red}, + {"green", g_green}, + {"blue", g_blue}, + {"cyan", g_cyan}, + {"magenta", g_magenta}, + {"yellow", g_yellow}, + {"gray", g_gray}, + {"darkgray", g_darkgray}, + {"lightgray", g_lightgray}, + {"orange", g_orange}, + {"purple", g_purple}, + {"pink", g_pink}, + {"brown", g_brown}, + {"lime", g_lime}, + {"teal", g_teal}, + {"navy", g_navy}, + {"olive", g_olive}, + {"maroon", g_maroon}, + {"silver", g_silver}, + {"gold", g_gold} +}; SOFA_TYPE_API std::istream& operator>>(std::istream& i, RGBAColor& t) { @@ -230,18 +255,14 @@ SOFA_TYPE_API std::istream& operator>>(std::istream& i, RGBAColor& t) /// if end of line is returned before encountering ' ' or 7... is it fine /// so we can clear the failure bitset. - - /// Compare the resulting string with supported colors. - /// If you add more colors... please also add them in the test file. - if (str == "white") { r = 1.0f; g = 1.0f; b = 1.0f; } - else if (str == "black") { r = 0.0f; g = 0.0f; b = 0.0f; } - else if (str == "red") { r = 1.0f; g = 0.0f; b = 0.0f; } - else if (str == "green") { r = 0.0f; g = 1.0f; b = 0.0f; } - else if (str == "blue") { r = 0.0f; g = 0.0f; b = 1.0f; } - else if (str == "cyan") { r = 0.0f; g = 1.0f; b = 1.0f; } - else if (str == "magenta") { r = 1.0f; g = 0.0f; b = 1.0f; } - else if (str == "yellow") { r = 1.0f; g = 1.0f; b = 0.0f; } - else if (str == "gray") { r = 0.5f; g = 0.5f; b = 0.5f; } + if (const auto it = stringToColorMap.find(str); + it != stringToColorMap.end()) + { + r = it->second.r(); + g = it->second.g(); + b = it->second.b(); + a = it->second.a(); + } else { /// If we cannot parse the field we returns that with the fail bit. i.setstate(std::ios_base::failbit) ; diff --git a/Sofa/framework/Type/src/sofa/type/RGBAColor.h b/Sofa/framework/Type/src/sofa/type/RGBAColor.h index 13e2bbbf70a..44fefc4eacc 100644 --- a/Sofa/framework/Type/src/sofa/type/RGBAColor.h +++ b/Sofa/framework/Type/src/sofa/type/RGBAColor.h @@ -91,6 +91,17 @@ class SOFA_TYPE_API RGBAColor constexpr static const RGBAColor& gray(); constexpr static const RGBAColor& darkgray(); constexpr static const RGBAColor& lightgray(); + constexpr static const RGBAColor& orange(); + constexpr static const RGBAColor& purple(); + constexpr static const RGBAColor& pink(); + constexpr static const RGBAColor& brown(); + constexpr static const RGBAColor& lime(); + constexpr static const RGBAColor& teal(); + constexpr static const RGBAColor& navy(); + constexpr static const RGBAColor& olive(); + constexpr static const RGBAColor& maroon(); + constexpr static const RGBAColor& silver(); + constexpr static const RGBAColor& gold(); /// @brief enlight a color by a given factor. static RGBAColor lighten(const RGBAColor& in, const SReal factor); @@ -226,17 +237,28 @@ constexpr RGBAColor operator/(const RGBAColor& l, const float div) } -constexpr RGBAColor g_white {1.0f,1.0f,1.0f,1.0f}; -constexpr RGBAColor g_black {0.0f,0.0f,0.0f,1.0f}; -constexpr RGBAColor g_red {1.0f,0.0f,0.0f,1.0f}; -constexpr RGBAColor g_green {0.0f,1.0f,0.0f,1.0f}; -constexpr RGBAColor g_blue {0.0f,0.0f,1.0f,1.0f}; -constexpr RGBAColor g_cyan {0.0f,1.0f,1.0f,1.0f}; -constexpr RGBAColor g_magenta {1.0f,0.0f,1.0f,1.0f}; -constexpr RGBAColor g_yellow {1.0f,1.0f,0.0f,1.0f}; -constexpr RGBAColor g_gray {0.5f,0.5f,0.5f,1.0f}; -constexpr RGBAColor g_darkgray {0.25f,0.25f,0.25f,1.0f}; -constexpr RGBAColor g_lightgray {0.75f,0.75f,0.75f,1.0f}; +constexpr RGBAColor g_white {1.0f, 1.0f, 1.0f, 1.0f}; +constexpr RGBAColor g_black {0.0f, 0.0f, 0.0f, 1.0f}; +constexpr RGBAColor g_red {1.0f, 0.0f, 0.0f, 1.0f}; +constexpr RGBAColor g_green {0.0f, 1.0f, 0.0f, 1.0f}; +constexpr RGBAColor g_blue {0.0f, 0.0f, 1.0f, 1.0f}; +constexpr RGBAColor g_cyan {0.0f, 1.0f, 1.0f, 1.0f}; +constexpr RGBAColor g_magenta {1.0f, 0.0f, 1.0f, 1.0f}; +constexpr RGBAColor g_yellow {1.0f, 1.0f, 0.0f, 1.0f}; +constexpr RGBAColor g_gray {0.5f, 0.5f, 0.5f, 1.0f}; +constexpr RGBAColor g_darkgray {0.25f, 0.25f,0.25f, 1.0f}; +constexpr RGBAColor g_lightgray {0.75f, 0.75f,0.75f, 1.0f}; +constexpr RGBAColor g_orange { 1.0f, 0.5f, 0.0f, 1.0f }; +constexpr RGBAColor g_purple { 0.5f, 0.0f, 0.5f, 1.0f }; +constexpr RGBAColor g_pink { 1.0f, 0.0f, 0.5f, 1.0f }; +constexpr RGBAColor g_brown { 0.6f, 0.3f, 0.0f, 1.0f }; +constexpr RGBAColor g_lime { 0.5f, 1.0f, 0.0f, 1.0f }; +constexpr RGBAColor g_teal { 0.0f, 0.5f, 0.5f, 1.0f }; +constexpr RGBAColor g_navy { 0.0f, 0.0f, 0.5f, 1.0f }; +constexpr RGBAColor g_olive { 0.5f, 0.5f, 0.0f, 1.0f }; +constexpr RGBAColor g_maroon { 0.5f, 0.0f, 0.0f, 1.0f }; +constexpr RGBAColor g_silver { 0.75f, 0.75f, 0.75f, 1.0f }; +constexpr RGBAColor g_gold { 1.0f, 0.84f, 0.0f, 1.0f }; constexpr const RGBAColor& RGBAColor::white() { return g_white; } constexpr const RGBAColor& RGBAColor::black() { return g_black; } @@ -249,5 +271,17 @@ constexpr const RGBAColor& RGBAColor::yellow() { return g_yellow; } constexpr const RGBAColor& RGBAColor::gray() { return g_gray; } constexpr const RGBAColor& RGBAColor::darkgray() { return g_darkgray; } constexpr const RGBAColor& RGBAColor::lightgray(){ return g_lightgray; } +constexpr const RGBAColor& RGBAColor::orange() { return g_orange; } +constexpr const RGBAColor& RGBAColor::purple() { return g_purple; } +constexpr const RGBAColor& RGBAColor::pink() { return g_pink ; } +constexpr const RGBAColor& RGBAColor::brown() { return g_brown ; } +constexpr const RGBAColor& RGBAColor::lime() { return g_lime ; } +constexpr const RGBAColor& RGBAColor::teal() { return g_teal ; } +constexpr const RGBAColor& RGBAColor::navy() { return g_navy ; } +constexpr const RGBAColor& RGBAColor::olive() { return g_olive ; } +constexpr const RGBAColor& RGBAColor::maroon() { return g_maroon; } +constexpr const RGBAColor& RGBAColor::silver() { return g_silver; } +constexpr const RGBAColor& RGBAColor::gold() { return g_gold ; } + } // namespace sofa::type diff --git a/Sofa/framework/Type/test/CMakeLists.txt b/Sofa/framework/Type/test/CMakeLists.txt index 7211d45a336..5aae429ac84 100644 --- a/Sofa/framework/Type/test/CMakeLists.txt +++ b/Sofa/framework/Type/test/CMakeLists.txt @@ -3,11 +3,11 @@ cmake_minimum_required(VERSION 3.22) project(Sofa.Type_test) set(SOURCE_FILES - Color_test.cpp MatSym_test.cpp MatTypes_test.cpp Material_test.cpp Quater_test.cpp + RGBAColor_test.cpp SVector_test.cpp VecTypes_test.cpp fixed_array_test.cpp diff --git a/Sofa/framework/Type/test/Color_test.cpp b/Sofa/framework/Type/test/RGBAColor_test.cpp similarity index 90% rename from Sofa/framework/Type/test/Color_test.cpp rename to Sofa/framework/Type/test/RGBAColor_test.cpp index fb30479c4af..1f4d37dc5b1 100644 --- a/Sofa/framework/Type/test/Color_test.cpp +++ b/Sofa/framework/Type/test/RGBAColor_test.cpp @@ -65,6 +65,19 @@ void Color_Test::checkCreateFromString() EXPECT_EQ( RGBAColor::fromString("magenta"), RGBAColor(1.0,0.0,1.0,1.0) ) ; EXPECT_EQ( RGBAColor::fromString("yellow"), RGBAColor(1.0,1.0,0.0,1.0) ) ; EXPECT_EQ( RGBAColor::fromString("gray"), RGBAColor(0.5,0.5,0.5,1.0) ) ; + EXPECT_EQ( RGBAColor::fromString("darkgray"), RGBAColor(0.25f, 0.25f,0.25f, 1.0f ) ); + EXPECT_EQ( RGBAColor::fromString("lightgray"), RGBAColor(0.75f, 0.75f,0.75f, 1.0f ) ); + EXPECT_EQ( RGBAColor::fromString("orange"), RGBAColor(1.0f, 0.5f, 0.0f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("purple"), RGBAColor(0.5f, 0.0f, 0.5f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("pink"), RGBAColor(1.0f, 0.0f, 0.5f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("brown"), RGBAColor(0.6f, 0.3f, 0.0f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("lime"), RGBAColor(0.5f, 1.0f, 0.0f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("teal"), RGBAColor(0.0f, 0.5f, 0.5f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("navy"), RGBAColor(0.0f, 0.0f, 0.5f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("olive"), RGBAColor(0.5f, 0.5f, 0.0f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("maroon"), RGBAColor(0.5f, 0.0f, 0.0f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("silver"), RGBAColor(0.75f, 0.75f, 0.75f, 1.0f )); + EXPECT_EQ( RGBAColor::fromString("gold"), RGBAColor(1.0f, 0.84f, 0.0f, 1.0f )); RGBAColor color; EXPECT_TRUE( RGBAColor::read("white", color) ) ; From 7ae5603b70e70451c5c8af708fb6baf00b0d4323 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 18 Nov 2024 03:08:54 +0100 Subject: [PATCH 09/24] [example] Update scene to display colors representing triangle areas (#5122) --- examples/Component/Mapping/NonLinear/AreaMapping.scn | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/Component/Mapping/NonLinear/AreaMapping.scn b/examples/Component/Mapping/NonLinear/AreaMapping.scn index 15d707aae2c..1591dceb42e 100644 --- a/examples/Component/Mapping/NonLinear/AreaMapping.scn +++ b/examples/Component/Mapping/NonLinear/AreaMapping.scn @@ -48,7 +48,9 @@ - + + + @@ -73,7 +75,7 @@ - + From 5ae7066758f57cb1cda1f9fd42bcf5e949578298 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Wed, 20 Nov 2024 00:33:38 +0100 Subject: [PATCH 10/24] [Test] Refactor Mapping_test (#5079) * refactor mapping test * refactor mapping test 2 * refactor mapping test 3 * refactor mapping test 4 * refactor mapping test 5 * refactor mapping test 6 * refactor mapping test 7 * refactor mapping test 8 * refactor mapping test 9 * a function to check applyDJT * check consistency applyJT getJs * check jacobian transpose * factorize computeForceInFromForceOut * testApplyJonPosition * use computeForceInFromForceOut * computeForceChange * testGetK * testBuildGeometricStiffnessMatrix * typo * overcomplicated * move computeForceChange --- .../NonLinear/tests/RigidMapping_test.cpp | 2 +- .../mapping/testing/MappingTestCreation.h | 775 ++++++++++-------- 2 files changed, 452 insertions(+), 325 deletions(-) diff --git a/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp b/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp index 46a53cb53ef..630add17ad0 100644 --- a/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp +++ b/Sofa/Component/Mapping/NonLinear/tests/RigidMapping_test.cpp @@ -90,7 +90,7 @@ struct RigidMappingTest : public sofa::mapping_test::Mapping_test<_RigidMapping> if constexpr ( InDataTypes::spatial_dimensions != 3 ) { // RigidMapping::getK is not yet implemented for 2D rigids - this->flags &= ~Inherit::TEST_getK; + this->setTestExecution(Inherit::TEST_getK, false); } } diff --git a/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h b/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h index 3a430a8deed..3c390ecec0b 100644 --- a/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h +++ b/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include using sofa::testing::BaseSimulationTest; @@ -30,7 +31,6 @@ using sofa::testing::NumericTest; #include -#include #include #include #include @@ -38,16 +38,17 @@ using sofa::testing::NumericTest; #include -namespace sofa::mapping_test { +namespace sofa::mapping_test +{ /** @brief Base class for the Mapping tests, with helpers to automatically test applyJ, applyJT, applyDJT and getJs using finite differences. Specific test cases can be created using a derived class instantiated on the mapping class to test, - and calling function runTest( const InVecCoord& parentInit, - const OutVecCoord& childInit, - const InVecCoord parentNew, - const OutVecCoord expectedChildNew); + and calling function runTest( const VecCoord_t& parentInit, + const VecCoord_t& childInit, + const VecCoord_t parentNew, + const VecCoord_t expectedChildNew); This function compares the actual output positions with the expected ones, then automatically tests the methods related to @@ -65,41 +66,16 @@ namespace sofa::mapping_test { @author François Faure @date 2013 */ - template< class _Mapping> struct Mapping_test: public BaseSimulationTest, NumericTest { - typedef _Mapping Mapping; - typedef typename Mapping::In In; - typedef component::statecontainer::MechanicalObject InDOFs; - typedef typename InDOFs::Real Real; - typedef typename InDOFs::Coord InCoord; - typedef typename InDOFs::Deriv InDeriv; - typedef typename InDOFs::VecCoord InVecCoord; - typedef typename InDOFs::VecDeriv InVecDeriv; - typedef typename InDOFs::ReadVecCoord ReadInVecCoord; - typedef typename InDOFs::WriteVecCoord WriteInVecCoord; - typedef typename InDOFs::ReadVecDeriv ReadInVecDeriv; - typedef typename InDOFs::WriteVecDeriv WriteInVecDeriv; - typedef typename InDOFs::MatrixDeriv InMatrixDeriv; - typedef Data InDataVecCoord; - typedef Data InDataVecDeriv; - typedef Data InDataMatrixDeriv; - - typedef typename Mapping::Out Out; - typedef component::statecontainer::MechanicalObject OutDOFs; - typedef typename OutDOFs::Coord OutCoord; - typedef typename OutDOFs::Deriv OutDeriv; - typedef typename OutDOFs::VecCoord OutVecCoord; - typedef typename OutDOFs::VecDeriv OutVecDeriv; - typedef typename OutDOFs::ReadVecCoord ReadOutVecCoord; - typedef typename OutDOFs::WriteVecCoord WriteOutVecCoord; - typedef typename OutDOFs::ReadVecDeriv ReadOutVecDeriv; - typedef typename OutDOFs::WriteVecDeriv WriteOutVecDeriv; - typedef typename OutDOFs::MatrixDeriv OutMatrixDeriv; - typedef Data OutDataVecCoord; - typedef Data OutDataVecDeriv; - typedef Data OutDataMatrixDeriv; + using Mapping = _Mapping; + + using In = typename Mapping::In; + using InDOFs = component::statecontainer::MechanicalObject; + + using Out = typename Mapping::Out; + using OutDOFs = component::statecontainer::MechanicalObject; typedef linearalgebra::EigenSparseMatrix EigenSparseMatrix; @@ -107,10 +83,9 @@ struct Mapping_test: public BaseSimulationTest, NumericTest deltaRange; ///< The minimum and maximum magnitudes of the change of each scalar value of the small displacement is perturbation * numeric_limits::epsilon. This epsilon is 1.19209e-07 for float and 2.22045e-16 for double. - Real errorMax; ///< The test is successful if the (infinite norm of the) difference is less than errorMax * numeric_limits::epsilon - Real errorFactorDJ; ///< The test for geometric stiffness is successful if the (infinite norm of the) difference is less than errorFactorDJ * errorMax * numeric_limits::epsilon + std::pair, Real_t> deltaRange; ///< The minimum and maximum magnitudes of the change of each scalar value of the small displacement is perturbation * numeric_limits::epsilon. This epsilon is 1.19209e-07 for float and 2.22045e-16 for double. + Real_t errorMax; ///< The test is successful if the (infinite norm of the) difference is less than errorMax * numeric_limits::epsilon + Real_t errorFactorDJ; ///< The test for geometric stiffness is successful if the (infinite norm of the) difference is less than errorFactorDJ * errorMax * numeric_limits::epsilon static constexpr unsigned char TEST_getJs = 1; ///< testing getJs used in assembly API @@ -122,6 +97,25 @@ struct Mapping_test: public BaseSimulationTest, NumericTestcreateNewGraph("root"); + root = simpleapi::createRootNode(simulation::getSimulation(), "root"); inDofs = core::objectmodel::New(); root->addObject(inDofs); @@ -149,8 +141,7 @@ struct Mapping_test: public BaseSimulationTest, NumericTestcreateNewGraph("root"); + root = simpleapi::createRootNode(simulation::getSimulation(), "root"); root = sofa::simulation::node::load(fileName.c_str(), false); // InDofs @@ -180,34 +171,8 @@ struct Mapping_test: public BaseSimulationTest, NumericTest& parentInit, + const VecCoord_t& childInit, + const VecCoord_t& parentNew, + const VecCoord_t& expectedChildNew) { - if( deltaRange.second / errorMax <= sofa::testing::g_minDeltaErrorRatio ) - ADD_FAILURE() << "The comparison threshold is too large for the finite difference delta"; - - if( !(flags & TEST_getJs) ) msg_warning("MappingTest") << "getJs is not tested"; - if( !(flags & TEST_getK) ) msg_warning("MappingTest") << "getK is not tested"; - if( !(flags & TEST_applyJT_matrix) ) msg_warning("MappingTest") << "applyJT on matrices is not tested"; - if( !(flags & TEST_applyDJT) ) msg_warning("MappingTest") << "applyDJT is not tested"; + checkComparisonThreshold(); + warnMissingTests(); + const auto errorThreshold = this->epsilon() * errorMax; - const Real errorThreshold = this->epsilon()*errorMax; + using EigenSparseMatrix = linearalgebra::EigenSparseMatrix; - typedef linearalgebra::EigenSparseMatrix EigenSparseMatrix; core::MechanicalParams mparams; mparams.setKFactor(1.0); mparams.setSupportOnlySymmetricMatrix(false); - inDofs->resize(parentInit.size()); - WriteInVecCoord xin = inDofs->writePositions(); - sofa::testing::copyToData(xin,parentInit); // xin = parentInit - - outDofs->resize(childInit.size()); - WriteOutVecCoord xout = outDofs->writePositions(); - sofa::testing::copyToData(xout,childInit); - - /// Init based on parentInit - sofa::simulation::node::initRoot(root.get()); - - /// Updated to parentNew - sofa::testing::copyToData(xin,parentNew); - mapping->apply(&mparams, core::VecCoordId::position(), core::VecCoordId::position()); - mapping->applyJ(&mparams, core::VecDerivId::velocity(), core::VecDerivId::velocity()); /// test apply: check if the child positions are the expected ones - bool succeed=true; + bool succeed = testMappingPositionVelocity( + parentInit, childInit, parentNew, expectedChildNew, errorThreshold, + mparams); - if (expectedChildNew.size() != xout.size()) { - ADD_FAILURE() << "Size of output dofs is wrong: " << xout.size() << " expected: " << expectedChildNew.size(); - succeed = false; - } - for( unsigned i=0; iisSmall( difference(xout[i],expectedChildNew[i]).norm(), errorMax ) ) { - ADD_FAILURE() << "Position of mapped particle " << i << " is wrong: \n" << xout[i] <<"\nexpected: \n" << expectedChildNew[i] - << "\ndifference should be less than " << errorThreshold << " (" << difference(xout[i],expectedChildNew[i]).norm() << ")" << std::endl; - succeed = false; - } - } - - /// test applyJ and everything related to Jacobians - size_t Np = inDofs->getSize(), Nc=outDofs->getSize(); - - InVecCoord xp(Np),xp1(Np); - InVecDeriv vp(Np),fp(Np); - InVecDeriv dfp_a(Np); - InVecDeriv dfp_b(Np); - InVecDeriv fp2(Np); - OutVecCoord xc(Nc),xc1(Nc); - OutVecDeriv vc(Nc),fc(Nc); + const std::size_t sizeIn = inDofs->getSize(); + const std::size_t sizeOut = outDofs->getSize(); // get position data - sofa::testing::copyFromData( xp, inDofs->readPositions() ); - sofa::testing::copyFromData( xc, outDofs->readPositions() ); // positions and have already been propagated + VecCoord_t positionOut = outDofs->readPositions().ref(); // set random child forces and propagate them to the parent - for( unsigned i=0; iwriteForces(); - sofa::testing::copyToData( fin, fp2 ); // reset parent forces before accumulating child forces + VecDeriv_t forceOut = generateRandomVecDeriv(sizeOut, 0.1, 1.); - WriteOutVecDeriv fout = outDofs->writeForces(); - sofa::testing::copyToData( fout, fc ); - mapping->applyJT( &mparams, core::VecDerivId::force(), core::VecDerivId::force() ); - sofa::testing::copyFromData( fp, inDofs->readForces() ); + VecDeriv_t forceIn; + computeForceInFromForceOut(mparams, forceIn, forceOut); // set small parent velocities and use them to update the child - for( unsigned i=0; iepsilon() * deltaRange.first, this->epsilon() * deltaRange.second ); - } + const VecDeriv_t velocityIn = generateRandomVecDeriv(sizeIn, + this->epsilon() * deltaRange.first, + this->epsilon() * deltaRange.second); - for( unsigned i=0; i perturbedPositionIn = computePerturbedPositions(sizeIn, velocityIn); - // propagate small velocity - WriteInVecDeriv vin = inDofs->writeVelocities(); - sofa::testing::copyToData( vin, vp ); - mapping->applyJ( &mparams, core::VecDerivId::velocity(), core::VecDerivId::velocity() ); - ReadOutVecDeriv vout = outDofs->readVelocities(); - sofa::testing::copyFromData( vc, vout); + VecDeriv_t velocityOut; + computeVelocityOutFromVelocityIn(mparams, velocityOut, velocityIn); // apply geometric stiffness inDofs->vRealloc( &mparams, core::VecDerivId::dx() ); // dx is not allocated by default - WriteInVecDeriv dxin = inDofs->writeDx(); - sofa::testing::copyToData( dxin, vp ); - dfp_a.fill( InDeriv() ); - dfp_b.fill( InDeriv() ); - sofa::testing::copyToData( fin, dfp_a ); - sofa::testing::copyToData( fin, dfp_b ); - - //calling applyDJT without updateK before - mapping->applyDJT( &mparams, core::VecDerivId::force(), core::VecDerivId::force() ); - sofa::testing::copyFromData( dfp_a, inDofs->readForces() ); // fp + df due to geometric stiffness - sofa::testing::copyToData( fin, fp2 ); //reset forces + inDofs->writeDx().wref() = velocityIn; - //calling applyDJT after updateK - mapping->updateK( &mparams, core::ConstVecDerivId::force() ); // updating stiffness matrix for the current state and force - mapping->applyDJT( &mparams, core::VecDerivId::force(), core::VecDerivId::force() ); - sofa::testing::copyFromData( dfp_b, inDofs->readForces() ); // fp + df due to geometric stiffness + const VecDeriv_t dfp_withoutUpdateK = applyDJT(mparams, false); + const VecDeriv_t dfp_withUpdateK = applyDJT(mparams, true); // Jacobian will be obsolete after applying new positions - if( flags & TEST_getJs ) + if( isTestExecuted(TEST_getJs) ) { EigenSparseMatrix* J = this->getMatrix(mapping->getJs()); - // cout<<"J = "<< endl << *J << endl; - OutVecDeriv Jv(Nc); - J->mult(Jv,vp); - - // ================ test applyJT() - InVecDeriv jfc( (long)Np,InDeriv()); - J->addMultTranspose(jfc,fc); - if( this->vectorMaxDiff(jfc,fp)>errorThreshold ){ - succeed = false; - ADD_FAILURE() << "applyJT test failed, difference should be less than " << errorThreshold << " (" << this->vectorMaxDiff(jfc,fp) << ")" << std::endl - << "jfc = " << jfc << std::endl<<" fp = " << fp << std::endl; - } - // ================ test getJs() - // check that J.vp = vc - if(this->vectorMaxDiff(Jv,vc)>errorThreshold ){ - succeed = false; - std::cout<<"vp = " << vp << std::endl; - std::cout<<"Jvp = " << Jv << std::endl; - std::cout<<"vc = " << vc << std::endl; - ADD_FAILURE() << "getJs() test failed"<vectorMaxAbs(difference(dxc,vc))<<" should be less than " << errorThreshold << std::endl - << "position change = " << dxc << std::endl - << "velocity = " << vc << std::endl; + if( isTestExecuted(TEST_getK)) + { + succeed &= testGetK(sizeIn, velocityIn, forceChange, errorThreshold); } + if( isTestExecuted(TEST_buildGeometricStiffnessMatrix) ) + { + succeed &= testBuildGeometricStiffnessMatrix(sizeIn, velocityIn, forceChange, errorThreshold); + } + if(!succeed) + { + ADD_FAILURE() << "Failed Seed number = " << this->seed << std::endl; + } + return succeed; + } - // update parent force based on the same child forces - fp2.fill( InDeriv() ); - sofa::testing::copyToData( fin, fp2 ); // reset parent forces before accumulating child forces - sofa::testing::copyToData( fout, preTreatment(fc) ); - mapping->applyJT( &mparams, core::VecDerivId::force(), core::VecDerivId::force() ); - sofa::testing::copyFromData( fp2, inDofs->readForces() ); - InVecDeriv fp12(Np); - for(unsigned i=0; i& parent, + const VecCoord_t expectedChild) + { + VecCoord_t childInit( expectedChild.size() ); // start with null child + return runTest( parent, childInit, parent, expectedChild ); + } + + ~Mapping_test() override + { + if (root != nullptr) + { + sofa::simulation::node::unload(root); } + } + +protected: + - // ================ test applyDJT() - if( flags & TEST_applyDJT ) + /** Returns OutCoord substraction a-b */ + virtual Deriv_t difference( const Coord_t& a, const Coord_t& b ) + { + return Out::coordDifference(a,b); + } + + virtual VecDeriv_t difference( const VecDeriv_t& a, const VecDeriv_t& b ) + { + if (a.size() != b.size()) { - //we test the function applyDJT in two different contexts because - //the implementation usually depends on the context - if (this->vectorMaxDiff(dfp_a,fp12) > errorThreshold * errorFactorDJ) - { - succeed = false; - ADD_FAILURE() << "applyDJT (no call to updateK) test failed" << std::endl - << "dfp = " << dfp_a << std::endl - << "fp2-fp = " << fp12 << std::endl - << "error threshold = " << errorThreshold * errorFactorDJ << std::endl; - } - if (this->vectorMaxDiff(dfp_b, fp12) > errorThreshold * errorFactorDJ) - { - succeed = false; - ADD_FAILURE() << "applyDJT (after call to updateK) test failed" << std::endl - << "dfp = " << dfp_b << std::endl - << "fp2-fp = " << fp12 << std::endl - << "error threshold = " << errorThreshold * errorFactorDJ << std::endl; - } + ADD_FAILURE() << "VecDeriv_t have different sizes"; + return {}; } + VecDeriv_t c; + c.reserve(a.size()); + std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(c), std::minus()); - // ================ test getK() - if( flags & TEST_getK ) + return c; + } + + /** Possible child force pre-treatment, does nothing by default + */ + virtual VecDeriv_t preTreatment( const VecDeriv_t& f ) + { + return f; + } + + + void checkComparisonThreshold() + { + if( deltaRange.second / errorMax <= sofa::testing::g_minDeltaErrorRatio ) { - InVecDeriv Kv(Np); + ADD_FAILURE() << "The comparison threshold is too large for the finite difference delta"; + } + } - const linearalgebra::BaseMatrix* bk = mapping->getK(); + void warnMissingTests() const + { + msg_warning_when(!isTestExecuted(TEST_getJs), "MappingTest") << "getJs is not tested"; + msg_warning_when(!isTestExecuted(TEST_getK) , "MappingTest") << "getK is not tested"; + msg_warning_when(!isTestExecuted(TEST_applyJT_matrix) , "MappingTest") << "applyJT on matrices is not tested"; + msg_warning_when(!isTestExecuted(TEST_applyDJT) , "MappingTest") << "applyDJT is not tested"; + msg_warning_when(!isTestExecuted(TEST_buildGeometricStiffnessMatrix) , "MappingTest") << "buildGeometricStiffnessMatrix is not tested"; + } - // K can be null or empty for linear mappings - // still performing the test with a null Kv vector to check if the mapping is really linear + bool testMappingPositionVelocity(const VecCoord_t& parentInit, + const VecCoord_t& childInit, + const VecCoord_t& parentNew, + const VecCoord_t& expectedChildNew, + const Real_t errorThreshold, + core::MechanicalParams mparams) + { + helper::WriteAccessor positionAccessorIn = inDofs->writePositions(); + positionAccessorIn.wref() = parentInit; - if( bk != nullptr ){ + helper::WriteAccessor positionAccessorOut = outDofs->writePositions(); + positionAccessorOut.wref() = childInit; - typedef linearalgebra::EigenSparseMatrix EigenSparseKMatrix; - const EigenSparseKMatrix* K = dynamic_cast(bk); - if( K == nullptr ){ - succeed = false; - ADD_FAILURE() << "getK returns a matrix of non-EigenSparseMatrix type"; - // TODO perform a slow conversion with a big warning rather than a failure? - } + /// Init based on parentInit + sofa::simulation::node::initRoot(root.get()); - if( K->compressedMatrix.nonZeros() ) K->mult(Kv,vp); - } + /// Updated to parentNew + positionAccessorIn.wref() = parentNew; + mapping->apply(&mparams, core::VecCoordId::position(), core::VecCoordId::position()); + mapping->applyJ(&mparams, core::VecDerivId::velocity(), core::VecDerivId::velocity()); - // check that K.vp = dfp - if(this->vectorMaxDiff(Kv,fp12)>errorThreshold*errorFactorDJ ){ - succeed = false; - ADD_FAILURE() << "K test failed, difference should be less than " << errorThreshold*errorFactorDJ << std::endl - << "Kv = " << Kv << std::endl - << "dfp = " << fp12 << std::endl; - } - } + bool succeed = true; - if( flags & TEST_buildGeometricStiffnessMatrix ) + if (expectedChildNew.size() != positionAccessorOut.size()) { - core::GeometricStiffnessMatrix testGeometricStiffness; - - struct GeometricStiffnessAccumulator : core::MappingMatrixAccumulator - { - void add(sofa::SignedIndex row, sofa::SignedIndex col, float value) override - { - assembledMatrix.add(row, col, value); - } - void add(sofa::SignedIndex row, sofa::SignedIndex col, double value) override - { - assembledMatrix.add(row, col, value); - } - - linearalgebra::EigenSparseMatrix assembledMatrix; - } accumulator; - - testGeometricStiffness.setMatrixAccumulator(&accumulator, mapping->getFromModel(), mapping->getFromModel()); - - accumulator.assembledMatrix.resize(mapping->getFromModel()->getSize() * In::deriv_total_size, mapping->getFromModel()->getSize() * In::deriv_total_size); - mapping->buildGeometricStiffnessMatrix(&testGeometricStiffness); - accumulator.assembledMatrix.compress(); - - InVecDeriv Kv(Np); - if( accumulator.assembledMatrix.compressedMatrix.nonZeros() ) - { - accumulator.assembledMatrix.mult(Kv,vp); - } + ADD_FAILURE() << "Size of output dofs is wrong: " << positionAccessorOut.size() << " expected: " << expectedChildNew.size(); + succeed = false; + } - // check that K.vp = dfp - if (this->vectorMaxDiff(Kv,fp12) > errorThreshold*errorFactorDJ ) + for (unsigned i = 0; i < positionAccessorOut.size(); ++i) + { + if (!this->isSmall(difference(positionAccessorOut[i], expectedChildNew[i]).norm(), errorMax)) { + ADD_FAILURE() << "Position of mapped particle " << i << " is wrong: \n" << positionAccessorOut[i] <<"\nexpected: \n" << expectedChildNew[i] + << "\ndifference should be less than " << errorThreshold << " (" << difference(positionAccessorOut[i],expectedChildNew[i]).norm() << ")" << std::endl; succeed = false; - ADD_FAILURE() << "buildGeometricStiffnessMatrix test failed, difference should be less than " << errorThreshold*errorFactorDJ << std::endl - << "Kv = " << Kv << std::endl - << "dfp = " << fp12 << std::endl; } } - if(!succeed) - { ADD_FAILURE() << "Failed Seed number = " << this->seed << std::endl;} return succeed; } + template + VecDeriv_t generateRandomVecDeriv(const std::size_t size, const Real_t minMagnitude, const Real_t maxMagnitude) + { + VecDeriv_t randomForce; + randomForce.reserve(size); + for (std::size_t i = 0; i < size; i++) + { + randomForce.push_back(DataTypes::randomDeriv(minMagnitude, maxMagnitude)); + } + return randomForce; + } - /** Test the mapping using the given values and small changes. - * Return true in case of success, if all errors are below maxError*epsilon. - * The mapping is initialized using the first parameter, - * @warning this version supposes the mapping initialization does not depend on child positions - * otherwise, use the runTest functions with 4 parameters - * the child position is computed from parent position and compared with the expected one. - * Additionally, the Jacobian-related methods are tested using finite differences. - * - *\param parent parent position - *\param expectedChild expected position of the child corresponding to the parent position - */ - virtual bool runTest( const InVecCoord& parent, - const OutVecCoord expectedChild) + void computeForceInFromForceOut(core::MechanicalParams mparams, VecDeriv_t& forceIn, const VecDeriv_t& forceOut) { - OutVecCoord childInit( expectedChild.size() ); // start with null child - return runTest( parent, childInit, parent, expectedChild ); + inDofs->writeForces()->fill(Deriv_t()); // reset parent forces before accumulating child forces + + outDofs->writeForces().wref() = forceOut; + mapping->applyJT( &mparams, core::VecDerivId::force(), core::VecDerivId::force() ); + forceIn = inDofs->readForces().ref(); } - ~Mapping_test() override + void computeVelocityOutFromVelocityIn(core::MechanicalParams mparams, VecDeriv_t& velocityOut, const VecDeriv_t& velocityIn) { - if (root!=nullptr) - sofa::simulation::node::unload(root); + inDofs->writeVelocities().wref() = velocityIn; + mapping->applyJ( &mparams, core::VecDerivId::velocity(), core::VecDerivId::velocity() ); + velocityOut = outDofs->readVelocities().ref(); + } + + const VecDeriv_t& applyDJT(core::MechanicalParams mparams, bool updateK) + { + inDofs->writeForces()->fill(Deriv_t()); //reset force + + if (updateK) + { + mapping->updateK( &mparams, core::ConstVecDerivId::force() ); // updating stiffness matrix for the current state and force + } + mapping->applyDJT( &mparams, core::VecDerivId::force(), core::VecDerivId::force() ); + return inDofs->readForces().ref(); + } + + [[nodiscard]] bool checkApplyDJT(const VecDeriv_t& dfp, const VecDeriv_t& fp12, Real_t errorThreshold, bool updateK) + { + if (this->vectorMaxDiff(dfp, fp12) > errorThreshold * errorFactorDJ) + { + const std::string updateKString = updateK ? "after call to updateK" : "no call to updateK"; + ADD_FAILURE() << "applyDJT (" << updateKString << ") test failed" << std::endl + << "dfp = " << dfp << std::endl + << "fp2-fp = " << fp12 << std::endl + << "error threshold = " << errorThreshold * errorFactorDJ << std::endl; + return false; + } + return true; + } + + VecCoord_t computePerturbedPositions(const std::size_t sizeIn, const VecDeriv_t velocityIn) + { + VecCoord_t perturbedPositionIn; + perturbedPositionIn.reserve(sizeIn); + const helper::ReadAccessor positionIn = inDofs->readPositions(); + for (std::size_t i = 0; i < sizeIn; ++i) + { + perturbedPositionIn.push_back(positionIn[i] + velocityIn[i]); + } + return perturbedPositionIn; } -protected: /// Get one EigenSparseMatrix out of a list. Error if not one single matrix in the list. template static EigenSparseMatrixType* getMatrix(const type::vector* matrices) { - if( !matrices ){ + if( !matrices ) + { ADD_FAILURE()<< "Matrix list is nullptr (API for assembly is not implemented)"; } - if( matrices->size() != 1 ){ - ADD_FAILURE()<< "Matrix list should have size == 1 in simple mappings"; + + if( matrices->empty() ) + { + ADD_FAILURE()<< "Matrix list is empty"; + return nullptr; + } + + if( matrices->size() != 1 ) + { + ADD_FAILURE()<< "Matrix list should have size == 1 in simple mappings (current size = " << matrices->size() << ")"; } EigenSparseMatrixType* ei = dynamic_cast((*matrices)[0] ); - if( ei == nullptr ){ + if( ei == nullptr ) + { ADD_FAILURE() << "getJs returns a matrix of non-EigenSparseMatrix type"; // TODO perform a slow conversion with a big warning rather than a failure? } return ei; } + bool checkJacobianMatrixTranspose( + EigenSparseMatrix* jacobianMatrix, + const VecDeriv_t& forceOut, + const VecDeriv_t& expectedForceIn, + Real_t errorThreshold) + { + VecDeriv_t computedForceIn(expectedForceIn.size(), Deriv_t()); + + //computedForceIn += J^T * forceOut + jacobianMatrix->addMultTranspose(computedForceIn, forceOut); + const auto diff = this->vectorMaxDiff(computedForceIn, expectedForceIn); + if (diff > errorThreshold) + { + ADD_FAILURE() << + "getJs is not consistent with applyJT, difference should be " + "less than " << errorThreshold << " (" << diff << ")" << std::endl + << "computedForceIn = " << computedForceIn << std::endl + << "expectedForceIn = " << expectedForceIn << std::endl; + return false; + } + return true; + } + + bool checkJacobianMatrix( + EigenSparseMatrix* jacobianMatrix, + const VecDeriv_t& velocityIn, + const VecDeriv_t& expectedVelocityOut, + Real_t errorThreshold) + { + VecDeriv_t computedVelocityOut(expectedVelocityOut.size()); + + jacobianMatrix->mult(computedVelocityOut, velocityIn); + + const auto diff = this->vectorMaxDiff(computedVelocityOut, expectedVelocityOut); + if (diff > errorThreshold) + { + ADD_FAILURE() << + "getJs is not consistent with applyJ, difference should be " + "less than " << errorThreshold << " (" << diff << ")" << std::endl + << "velocityIn = " << velocityIn << std::endl + << "computedVelocityOut = " << computedVelocityOut << std::endl + << "expectedVelocityOut = " << expectedVelocityOut << std::endl; + return false; + } + + return true; + } + + bool testApplyJonPosition( + core::MechanicalParams mparams, + const VecCoord_t& positionOut, + const VecDeriv_t& expectedVelocityOut, + Real_t errorThreshold + ) + { + mapping->apply ( &mparams, core::VecCoordId::position(), core::VecCoordId::position() ); + const VecCoord_t& positionOut1 = outDofs->readPositions(); + + const auto sizeOut = positionOut.size(); + VecDeriv_t dxOut(sizeOut); + for (unsigned i = 0; i < sizeOut; i++) + { + dxOut[i] = difference(positionOut1[i], positionOut[i]); + } + + const auto diff = this->vectorMaxAbs(difference(dxOut, expectedVelocityOut)); + if (diff > errorThreshold) + { + ADD_FAILURE() << "applyJ test failed: the difference between child " + "position change and child velocity (dt=1) " << diff << + " should be less than " << errorThreshold << std::endl + << "position change = " << dxOut << std::endl + << "expectedVelocityOut = " << expectedVelocityOut << std::endl; + return false; + } + + return true; + } + + VecDeriv_t computeForceChange(core::MechanicalParams mparams, const std::size_t sizeIn, VecDeriv_t forceOut, VecDeriv_t forceIn) + { + VecDeriv_t forceChange; + forceChange.reserve(sizeIn); + + // apply has been called, therefore parent force must be updated + // based on the same child forces + VecDeriv_t forceIn2; + computeForceInFromForceOut(mparams, forceIn2, preTreatment(forceOut)); + + for (unsigned i = 0; i < sizeIn; ++i) + { + forceChange.push_back(forceIn2[i] - forceIn[i]); + } + + return forceChange; + } + + bool testGetK(const std::size_t& sizeIn, + const VecDeriv_t& velocityIn, + const VecDeriv_t& forceChange, + Real_t errorThreshold) + { + VecDeriv_t Kv(sizeIn); + + const linearalgebra::BaseMatrix* bk = mapping->getK(); + + // K can be null or empty for linear mappings + // still performing the test with a null Kv vector to check if the mapping is really linear + + if( bk != nullptr ) + { + typedef linearalgebra::EigenSparseMatrix EigenSparseKMatrix; + const EigenSparseKMatrix* K = dynamic_cast(bk); + if( K == nullptr ) + { + ADD_FAILURE() << "getK returns a matrix of non-EigenSparseMatrix type"; + // TODO perform a slow conversion with a big warning rather than a failure? + return false; + } + + if( K->compressedMatrix.nonZeros() ) + { + K->mult(Kv,velocityIn); + } + } + + // check that K.vp = dfp + if (this->vectorMaxDiff(Kv, forceChange) > errorThreshold * errorFactorDJ) + { + ADD_FAILURE() << "K test failed, difference should be less than " << errorThreshold*errorFactorDJ << std::endl + << "Kv = " << Kv << std::endl + << "dfp = " << forceChange << std::endl; + return false; + } + + return true; + } + + bool testBuildGeometricStiffnessMatrix( + std::size_t sizeIn, + const VecDeriv_t& velocityIn, + const VecDeriv_t& forceChange, + Real_t errorThreshold + ) + { + core::GeometricStiffnessMatrix testGeometricStiffness; + + struct GeometricStiffnessAccumulator : core::MappingMatrixAccumulator + { + void add(sofa::SignedIndex row, sofa::SignedIndex col, float value) override + { + assembledMatrix.add(row, col, value); + } + void add(sofa::SignedIndex row, sofa::SignedIndex col, double value) override + { + assembledMatrix.add(row, col, value); + } + + linearalgebra::EigenSparseMatrix assembledMatrix; + } accumulator; + + testGeometricStiffness.setMatrixAccumulator(&accumulator, mapping->getFromModel(), mapping->getFromModel()); + + accumulator.assembledMatrix.resize(mapping->getFromModel()->getSize() * In::deriv_total_size, mapping->getFromModel()->getSize() * In::deriv_total_size); + mapping->buildGeometricStiffnessMatrix(&testGeometricStiffness); + accumulator.assembledMatrix.compress(); + + VecDeriv_t Kv(sizeIn); + if( accumulator.assembledMatrix.compressedMatrix.nonZeros() ) + { + accumulator.assembledMatrix.mult(Kv,velocityIn); + } + + // check that K.vp = dfp + if (this->vectorMaxDiff(Kv,forceChange) > errorThreshold*errorFactorDJ ) + { + ADD_FAILURE() << "buildGeometricStiffnessMatrix test failed, difference should be less than " << errorThreshold*errorFactorDJ << std::endl + << "Kv = " << Kv << std::endl + << "dfp = " << forceChange << std::endl; + return false; + } + + return true; + } }; From 9f89e1a2b18f95bcc9d9d5578a4d2dff971d5854 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Wed, 20 Nov 2024 00:34:30 +0100 Subject: [PATCH 11/24] [Config] Minor cleaning of config.h (#5103) --- Sofa/framework/Config/src/sofa/config.h.in | 16 ++-------------- .../ArticulatedHierarchyBVHController.cpp | 2 -- .../ArticulatedHierarchyController.cpp | 2 -- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/Sofa/framework/Config/src/sofa/config.h.in b/Sofa/framework/Config/src/sofa/config.h.in index df763c20356..ccd35844237 100644 --- a/Sofa/framework/Config/src/sofa/config.h.in +++ b/Sofa/framework/Config/src/sofa/config.h.in @@ -69,12 +69,6 @@ constexpr SReal operator"" _sreal(unsigned long long int integer) # endif #endif -// snprintf() has been provided since MSVC++ 14 (Visual Studio 2015). For other -// versions, it is simply #defined to _snprintf(). -#if (defined(_MSC_VER) && _MSC_VER < 1900) -# define snprintf _snprintf -#endif - #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN # include @@ -223,8 +217,8 @@ class DeprecatedAndRemoved {}; /**********************************************/ -#define SOFA_DECL_CLASS(name) // extern "C" { int sofa_concat(class_,name) = 0; } -#define SOFA_LINK_CLASS(name) // extern "C" { extern int sofa_concat(class_,name); int sofa_concat(link_,name) = sofa_concat(class_,name); } +#define SOFA_DECL_CLASS(name) SOFA_PRAGMA_WARNING("The macro SOFA_DECL_CLASS is no longer used") +#define SOFA_LINK_CLASS(name) SOFA_PRAGMA_WARNING("The macro SOFA_LINK_CLASS is no longer used") // Prevent compiler warnings about 'unused variables'. // This should be used when a parameter name is needed (e.g. for @@ -238,12 +232,6 @@ class DeprecatedAndRemoved {}; #define SOFA_CLASS_METHOD ( std::string(this->getClassName()) + "::" + __func__ + " " ) #endif - -// The SOFA_EXTERN_TEMPLATE macro was used to control the use of extern templates in Sofa. -// It has been cleaned out in 41e0ab98bbb6e22b053b24e7bbdd31c8636336c9 "[ALL] Remove SOFA_EXTERN_TEMPLATE". -// Macro definition is kept to avoid breaking all external plugins. -#define SOFA_EXTERN_TEMPLATE SOFA_PRAGMA_ERROR("The usage of SOFA_EXTERN_TEMPLATE is now disabled. See commit 41e0ab9 for more information") - namespace sofa { diff --git a/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyBVHController.cpp b/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyBVHController.cpp index a7b0672fd02..f735d6b58cb 100644 --- a/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyBVHController.cpp +++ b/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyBVHController.cpp @@ -166,8 +166,6 @@ void ArticulatedHierarchyBVHController::applyController(void) } } -SOFA_DECL_CLASS(ArticulatedHierarchyBVHController) - // Register in the Factory int ArticulatedHierarchyBVHControllerClass = core::RegisterObject("Implements a handler that controls the values of the articulations of an articulated hierarchy container using a .bvh file.") .add< ArticulatedHierarchyBVHController >() diff --git a/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyController.cpp b/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyController.cpp index 2542e59290e..89f8830e987 100644 --- a/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyController.cpp +++ b/applications/plugins/ArticulatedSystemPlugin/src/ArticulatedSystemPlugin/ArticulatedHierarchyController.cpp @@ -407,8 +407,6 @@ void ArticulatedHierarchyController::applyController(void) } } -SOFA_DECL_CLASS(ArticulatedHierarchyController) - // Register in the Factory int ArticulatedHierarchyControllerClass = core::RegisterObject("Implements an user interaction handler that controls the values of the articulations of an articulated hierarchy container.") .add< ArticulatedHierarchyController >() From 514b66719920063b37a2b23dd97697d8217c1026 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Wed, 20 Nov 2024 02:56:41 +0100 Subject: [PATCH 12/24] [Constraint] Clean BilateralLagrangianConstraint (#5109) [Constraint] Clean BilageralLagrangianConstraint --- .../model/BilateralLagrangianConstraint.cpp | 209 +++++++++--------- .../model/BilateralLagrangianConstraint.h | 25 ++- .../model/BilateralLagrangianConstraint.inl | 60 ++--- 3 files changed, 156 insertions(+), 138 deletions(-) diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp index e6932abfdae..5f694d58dd0 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.cpp @@ -37,33 +37,37 @@ class BilateralLagrangianConstraintSpecialization { public: + template + using SubsetIndices = typename BilateralLagrangianConstraint::SubsetIndices; + + template static void bwdInit(BilateralLagrangianConstraint& self) { if (!self.d_keepOrientDiff.getValue()) return; - helper::WriteAccessor::VecDeriv > > wrest = self.d_restVector; + auto wrest = sofa::helper::getWriteAccessor(self.d_restVector); - if (wrest.size() > 0) { - msg_warning("BilateralLagrangianConstraintSpecialization") << "keepOrientationDifference is activated, rest_vector will be ignored! " ; + if (!wrest.empty()) { + msg_warning(&self) << "keepOrientationDifference is activated, rest_vector will be ignored! " ; wrest.resize(0); } - const typename BilateralLagrangianConstraint::SubsetIndices& m1Indices = self.d_m1.getValue(); - const typename BilateralLagrangianConstraint::SubsetIndices& m2Indices = self.d_m2.getValue(); + const SubsetIndices& m1Indices = self.d_m1.getValue(); + const SubsetIndices& m2Indices = self.d_m2.getValue(); const unsigned minp = std::min(m1Indices.size(),m2Indices.size()); - const typename BilateralLagrangianConstraint::DataVecCoord &d_x1 = *self.mstate1->read(core::ConstVecCoordId::position()); - const typename BilateralLagrangianConstraint::DataVecCoord &d_x2 = *self.mstate2->read(core::ConstVecCoordId::position()); + const DataVecCoord_t &d_x1 = *self.mstate1->read(core::ConstVecCoordId::position()); + const DataVecCoord_t &d_x2 = *self.mstate2->read(core::ConstVecCoordId::position()); - const typename BilateralLagrangianConstraint::VecCoord &x1 = d_x1.getValue(); - const typename BilateralLagrangianConstraint::VecCoord &x2 = d_x2.getValue(); + const VecCoord_t &x1 = d_x1.getValue(); + const VecCoord_t &x2 = d_x2.getValue(); for (unsigned pid=0; pid::Coord P = x1[m1Indices[pid]]; - const typename BilateralLagrangianConstraint::Coord Q = x2[m2Indices[pid]]; + const Coord_t P = x1[m1Indices[pid]]; + const Coord_t Q = x2[m2Indices[pid]]; type::Quat qP, qQ, dQP; qP = P.getOrientation(); @@ -73,7 +77,7 @@ class BilateralLagrangianConstraintSpecialization dQP = qP.quatDiff(qQ, qP); dQP.normalize(); - typename BilateralLagrangianConstraint::Coord df; + Coord_t df; df.getCenter() = Q.getCenter() - P.getCenter(); df.getOrientation() = dQP; self.initialDifference.push_back(df); @@ -86,12 +90,12 @@ class BilateralLagrangianConstraintSpecialization static void getConstraintResolution(BilateralLagrangianConstraint& self, const ConstraintParams* cParams, std::vector& resTab, - unsigned int& offset, double tolerance) + unsigned int& offset, SReal tolerance) { SOFA_UNUSED(cParams); - const unsigned minp=std::min(self.d_m1.getValue().size(), - self.d_m2.getValue().size()); - for (unsigned pid=0; pid template static void buildConstraintMatrix(BilateralLagrangianConstraint& self, const ConstraintParams* cParams, - typename BilateralLagrangianConstraint::DataMatrixDeriv &c1_d, - typename BilateralLagrangianConstraint::DataMatrixDeriv &c2_d, + DataMatrixDeriv_t &c1_d, + DataMatrixDeriv_t &c2_d, unsigned int &constraintId, - const typename BilateralLagrangianConstraint::DataVecCoord &/*x1*/, - const typename BilateralLagrangianConstraint::DataVecCoord &/*x2*/) + const DataVecCoord_t &/*x1*/, + const DataVecCoord_t &/*x2*/) { SOFA_UNUSED(cParams) ; - const typename BilateralLagrangianConstraint::SubsetIndices& m1Indices = self.d_m1.getValue(); - const typename BilateralLagrangianConstraint::SubsetIndices& m2Indices = self.d_m2.getValue(); + const SubsetIndices& m1Indices = self.d_m1.getValue(); + const SubsetIndices& m2Indices = self.d_m2.getValue(); unsigned minp = std::min(m1Indices.size(),m2Indices.size()); self.cid.resize(minp); - typename BilateralLagrangianConstraint::MatrixDeriv &c1 = *c1_d.beginEdit(); - typename BilateralLagrangianConstraint::MatrixDeriv &c2 = *c2_d.beginEdit(); + auto c1 = sofa::helper::getWriteAccessor(c1_d); + auto c2 = sofa::helper::getWriteAccessor(c2_d); - const Vec<3, typename BilateralLagrangianConstraint::Real> cx(1,0,0), cy(0,1,0), cz(0,0,1); - const Vec<3, typename BilateralLagrangianConstraint::Real> vZero(0,0,0); + static constexpr Vec<3, Real_t> cx(1,0,0), cy(0,1,0), cz(0,0,1); + static constexpr Vec<3, Real_t> vZero(0,0,0); - for (unsigned pid=0; pid constraintId += 6; //Apply constraint for position - typename BilateralLagrangianConstraint::MatrixDerivRowIterator c1_it = c1.writeLine(self.cid[pid]); - c1_it.addCol(tm1, typename BilateralLagrangianConstraint::Deriv(-cx, vZero)); + auto c1_it = c1->writeLine(self.cid[pid]); + c1_it.addCol(tm1, Deriv_t(-cx, vZero)); - typename BilateralLagrangianConstraint::MatrixDerivRowIterator c2_it = c2.writeLine(self.cid[pid]); - c2_it.addCol(tm2, typename BilateralLagrangianConstraint::Deriv(cx, vZero)); + auto c2_it = c2->writeLine(self.cid[pid]); + c2_it.addCol(tm2, Deriv_t(cx, vZero)); - c1_it = c1.writeLine(self.cid[pid] + 1); - c1_it.setCol(tm1, typename BilateralLagrangianConstraint::Deriv(-cy, vZero)); + c1_it = c1->writeLine(self.cid[pid] + 1); + c1_it.setCol(tm1, Deriv_t(-cy, vZero)); - c2_it = c2.writeLine(self.cid[pid] + 1); - c2_it.setCol(tm2, typename BilateralLagrangianConstraint::Deriv(cy, vZero)); + c2_it = c2->writeLine(self.cid[pid] + 1); + c2_it.setCol(tm2, Deriv_t(cy, vZero)); - c1_it = c1.writeLine(self.cid[pid] + 2); - c1_it.setCol(tm1, typename BilateralLagrangianConstraint::Deriv(-cz, vZero)); + c1_it = c1->writeLine(self.cid[pid] + 2); + c1_it.setCol(tm1, Deriv_t(-cz, vZero)); - c2_it = c2.writeLine(self.cid[pid] + 2); - c2_it.setCol(tm2, typename BilateralLagrangianConstraint::Deriv(cz, vZero)); + c2_it = c2->writeLine(self.cid[pid] + 2); + c2_it.setCol(tm2, Deriv_t(cz, vZero)); //Apply constraint for orientation - c1_it = c1.writeLine(self.cid[pid] + 3); - c1_it.setCol(tm1, typename BilateralLagrangianConstraint::Deriv(vZero, -cx)); + c1_it = c1->writeLine(self.cid[pid] + 3); + c1_it.setCol(tm1, Deriv_t(vZero, -cx)); - c2_it = c2.writeLine(self.cid[pid] + 3); - c2_it.setCol(tm2, typename BilateralLagrangianConstraint::Deriv(vZero, cx)); + c2_it = c2->writeLine(self.cid[pid] + 3); + c2_it.setCol(tm2, Deriv_t(vZero, cx)); - c1_it = c1.writeLine(self.cid[pid] + 4); - c1_it.setCol(tm1, typename BilateralLagrangianConstraint::Deriv(vZero, -cy)); + c1_it = c1->writeLine(self.cid[pid] + 4); + c1_it.setCol(tm1, Deriv_t(vZero, -cy)); - c2_it = c2.writeLine(self.cid[pid] + 4); - c2_it.setCol(tm2, typename BilateralLagrangianConstraint::Deriv(vZero, cy)); + c2_it = c2->writeLine(self.cid[pid] + 4); + c2_it.setCol(tm2, Deriv_t(vZero, cy)); - c1_it = c1.writeLine(self.cid[pid] + 5); - c1_it.setCol(tm1, typename BilateralLagrangianConstraint::Deriv(vZero, -cz)); + c1_it = c1->writeLine(self.cid[pid] + 5); + c1_it.setCol(tm1, Deriv_t(vZero, -cz)); - c2_it = c2.writeLine(self.cid[pid] + 5); - c2_it.setCol(tm2, typename BilateralLagrangianConstraint::Deriv(vZero, cz)); + c2_it = c2->writeLine(self.cid[pid] + 5); + c2_it.setCol(tm2, Deriv_t(vZero, cz)); } - - c1_d.endEdit(); - c2_d.endEdit(); } @@ -190,41 +191,45 @@ class BilateralLagrangianConstraintSpecialization const typename BilateralLagrangianConstraint::SubsetIndices& m2Indices = self.d_m2.getValue(); unsigned min = std::min(m1Indices.size(), m2Indices.size()); - const typename BilateralLagrangianConstraint::VecDeriv& restVector = self.d_restVector.getValue(); - self.dfree.resize(min); + const VecDeriv_t& restVector = self.d_restVector.getValue(); + self.m_violation.resize(min); - const typename BilateralLagrangianConstraint::VecCoord &x1 = d_x1.getValue(); - const typename BilateralLagrangianConstraint::VecCoord &x2 = d_x2.getValue(); + const VecCoord_t &x1 = d_x1.getValue(); + const VecCoord_t &x2 = d_x2.getValue(); - for (unsigned pid=0; pid::Coord dof1 = x1[m1Indices[pid]]; - //typename BilateralLagrangianConstraint::Coord dof2 = x2[m2Indices[pid]]; - typename BilateralLagrangianConstraint::Coord dof1; + Coord_t dof1; - if (self.d_keepOrientDiff.getValue()) { - const typename BilateralLagrangianConstraint::Coord dof1c = x1[m1Indices[pid]]; + if (self.d_keepOrientDiff.getValue()) + { + const Coord_t dof1c = x1[m1Indices[pid]]; - typename BilateralLagrangianConstraint::Coord corr=self.initialDifference[pid]; - type::Quat df = corr.getOrientation(); - type::Quat o1 = dof1c.getOrientation(); - type::Quat ro1 = o1 * df; + Coord_t corr = self.initialDifference[pid]; + type::Quat> df = corr.getOrientation(); + type::Quat> o1 = dof1c.getOrientation(); + type::Quat> ro1 = o1 * df; - dof1.getCenter() = dof1c.getCenter() + corr.getCenter(); - dof1.getOrientation() = ro1; - } else - dof1 = x1[m1Indices[pid]]; + dof1.getCenter() = dof1c.getCenter() + corr.getCenter(); + dof1.getOrientation() = ro1; + } + else + { + dof1 = x1[m1Indices[pid]]; + } - const typename BilateralLagrangianConstraint::Coord dof2 = x2[m2Indices[pid]]; + const Coord_t dof2 = x2[m2Indices[pid]]; - getVCenter(self.dfree[pid]) = dof2.getCenter() - dof1.getCenter(); - getVOrientation(self.dfree[pid]) = dof1.rotate(self.q.angularDisplacement(dof2.getOrientation() , + getVCenter(self.m_violation[pid]) = dof2.getCenter() - dof1.getCenter(); + getVOrientation(self.m_violation[pid]) = dof1.rotate(self.q.angularDisplacement(dof2.getOrientation() , dof1.getOrientation())); // angularDisplacement compute the rotation vector btw the two quaternions if (pid < restVector.size()) - self.dfree[pid] -= restVector[pid]; + self.m_violation[pid] -= restVector[pid]; - for (unsigned int i=0 ; iset(self.cid[pid]+i, self.dfree[pid][i]); + for (unsigned int i = 0; i < self.m_violation[pid].size(); i++) + { + v->set(self.cid[pid]+i, self.m_violation[pid][i]); + } } } @@ -235,9 +240,9 @@ class BilateralLagrangianConstraintSpecialization typename MyClass::Real /*contactDistance*/, int m1, int m2, typename MyClass::Coord /*Pfree*/, typename MyClass::Coord /*Qfree*/, long /*id*/, typename MyClass::PersistentID /*localid*/) { - helper::WriteAccessor::SubsetIndices > > wm1 = self.d_m1; - helper::WriteAccessor::SubsetIndices > > wm2 = self.d_m2; - helper::WriteAccessor > wrest = self.d_restVector; + sofa::helper::WriteAccessor>> wm1 = self.d_m1; + sofa::helper::WriteAccessor>> wm2 = self.d_m2; + auto wrest = sofa::helper::WriteAccessor(self.d_restVector); wm1.push_back(m1); wm2.push_back(m2); @@ -249,25 +254,30 @@ class BilateralLagrangianConstraintSpecialization }; +using RigidBilateralLagrangianConstraint = BilateralLagrangianConstraintSpecialization; + template<> SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API -void BilateralLagrangianConstraint::init(){ +void BilateralLagrangianConstraint::init() +{ unspecializedInit() ; } template<> SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API -void BilateralLagrangianConstraint::bwdInit() { - BilateralLagrangianConstraintSpecialization::bwdInit(*this); +void BilateralLagrangianConstraint::bwdInit() +{ + RigidBilateralLagrangianConstraint::bwdInit(*this); } template<> SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API -void BilateralLagrangianConstraint::getConstraintResolution(const ConstraintParams* cParams, - std::vector& resTab, - unsigned int& offset) +void BilateralLagrangianConstraint::getConstraintResolution( + const ConstraintParams* cParams, + std::vector& resTab, + unsigned int& offset) { - BilateralLagrangianConstraintSpecialization::getConstraintResolution(*this, - cParams, resTab, offset, - d_numericalTolerance.getValue()) ; + RigidBilateralLagrangianConstraint::getConstraintResolution(*this, + cParams, resTab, offset, + d_numericalTolerance.getValue()); } template <> SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_MODEL_API @@ -277,9 +287,9 @@ void BilateralLagrangianConstraint::buildConstraintMatrix(const Con unsigned int &constraintId, const DataVecCoord &x1, const DataVecCoord &x2) { - BilateralLagrangianConstraintSpecialization::buildConstraintMatrix(*this, - cParams, c1_d, c2_d, constraintId, - x1, x2) ; + RigidBilateralLagrangianConstraint::buildConstraintMatrix(*this, + cParams, c1_d, c2_d, constraintId, + x1, x2); } @@ -289,9 +299,9 @@ void BilateralLagrangianConstraint::getConstraintViolation(const Co const DataVecCoord &d_x1, const DataVecCoord &d_x2, const DataVecDeriv &v1, const DataVecDeriv &v2) { - BilateralLagrangianConstraintSpecialization::getConstraintViolation(*this, - cParams, v, d_x1, d_x2, - v1, v2) ; + RigidBilateralLagrangianConstraint::getConstraintViolation(*this, + cParams, v, d_x1, d_x2, + v1, v2); } @@ -312,9 +322,10 @@ void BilateralLagrangianConstraint::addContact(Deriv n Coord Pfree, Coord Qfree, long id, PersistentID localid) { - BilateralLagrangianConstraintSpecialization::addContact(*this, - norm, P, Q, contactDistance, m1, m2, Pfree, Qfree, - id, localid) ; + RigidBilateralLagrangianConstraint::addContact(*this, + norm, P, Q, contactDistance, + m1, m2, Pfree, Qfree, + id, localid); } void registerBilateralLagrangianConstraint(sofa::core::ObjectFactory* factory) diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h index f986ad3321b..abc001ded95 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.h @@ -45,7 +45,6 @@ namespace sofa::component::constraint::lagrangian::model using sofa::core::behavior::BaseConstraint ; using sofa::core::behavior::ConstraintResolution ; using sofa::core::behavior::PairInteractionConstraint ; -using sofa::core::objectmodel::Data ; using sofa::core::ConstraintParams ; using sofa::core::ConstVecCoordId; @@ -93,10 +92,11 @@ class BilateralLagrangianConstraint : public PairInteractionConstraint dfree; + sofa::type::vector m_violation; Quat q; std::vector cid; + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_MODEL() sofa::core::objectmodel::RenamedData > m1; @@ -114,7 +114,7 @@ class BilateralLagrangianConstraint : public PairInteractionConstraint d_restVector; ///< Relative position to maintain between attached points (optional) VecCoord initialDifference; - Data d_numericalTolerance; ///< a real value specifying the tolerance during the constraint solving. (default=0.0001 + Data d_numericalTolerance; ///< a real value specifying the tolerance during the constraint solving. (default=0.0001 Data d_activate; ///< control constraint activation (true by default) Data d_keepOrientDiff; ///< keep the initial difference in orientation (only for rigids) @@ -128,7 +128,8 @@ class BilateralLagrangianConstraint : public PairInteractionConstraint& resTab, - unsigned int& offset) override; + std::vector& resTab, + unsigned int& offset) override; void handleEvent(sofa::core::objectmodel::Event *event) override; diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl index ad18a6ed7f7..a486df45ecd 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/BilateralLagrangianConstraint.inl @@ -44,8 +44,8 @@ BilateralLagrangianConstraint::BilateralLagrangianConstraint(Mechanic , d_m1(initData(&d_m1, "first_point","index of the constraint on the first model (object1)")) , d_m2(initData(&d_m2, "second_point","index of the constraint on the second model (object2)")) , d_restVector(initData(&d_restVector, "rest_vector","Relative position to maintain between attached points (optional)")) - , d_numericalTolerance(initData(&d_numericalTolerance, 0.0001, "numericalTolerance", - "a real value specifying the tolerance during the constraint solving. (optional, default=0.0001)") ) + , d_numericalTolerance(initData(&d_numericalTolerance, 1e-4_sreal, "numericalTolerance", + "a real value specifying the tolerance during the constraint solving.") ) , d_activate( initData(&d_activate, true, "activate", "control constraint activation (true by default)")) , d_keepOrientDiff(initData(&d_keepOrientDiff, false, "keepOrientationDifference", "keep the initial difference in orientation (only for rigids)")) , l_topology1(initLink("topology1", "link to the first topology container")) @@ -81,6 +81,11 @@ void BilateralLagrangianConstraint::unspecializedInit() assert(this->mstate1); assert(this->mstate2); + if (!this->mstate1 || !this->mstate2) + { + this->d_componentState.setValue(core::objectmodel::ComponentState::Invalid); + } + prevForces.clear(); } @@ -120,8 +125,10 @@ void BilateralLagrangianConstraint::reinit() template -void BilateralLagrangianConstraint::buildConstraintMatrix(const ConstraintParams*, DataMatrixDeriv &c1_d, DataMatrixDeriv &c2_d, unsigned int &constraintId - , const DataVecCoord &/*x1*/, const DataVecCoord &/*x2*/) +void BilateralLagrangianConstraint::buildConstraintMatrix( + const ConstraintParams*, DataMatrixDeriv& c1_d, DataMatrixDeriv& c2_d, + unsigned int& constraintId, + const DataVecCoord&/*x1*/, const DataVecCoord&/*x2*/) { if (!d_activate.getValue()) return; @@ -133,12 +140,12 @@ void BilateralLagrangianConstraint::buildConstraintMatrix(const Const const SubsetIndices& m1Indices = d_m1.getValue(); const SubsetIndices& m2Indices = d_m2.getValue(); - MatrixDeriv &c1 = *c1_d.beginEdit(); - MatrixDeriv &c2 = *c2_d.beginEdit(); + auto c1 = sofa::helper::getWriteAccessor(c1_d); + auto c2 = sofa::helper::getWriteAccessor(c2_d); cid.resize(minp); - for (unsigned pid=0; pid::buildConstraintMatrix(const Const cid[pid] = constraintId; constraintId += 3; - MatrixDerivRowIterator c1_it = c1.writeLine(cid[pid]); + MatrixDerivRowIterator c1_it = c1->writeLine(cid[pid]); c1_it.addCol(tm1, -cx); - MatrixDerivRowIterator c2_it = c2.writeLine(cid[pid]); + MatrixDerivRowIterator c2_it = c2->writeLine(cid[pid]); c2_it.addCol(tm2, cx); - c1_it = c1.writeLine(cid[pid] + 1); + c1_it = c1->writeLine(cid[pid] + 1); c1_it.setCol(tm1, -cy); - c2_it = c2.writeLine(cid[pid] + 1); + c2_it = c2->writeLine(cid[pid] + 1); c2_it.setCol(tm2, cy); - c1_it = c1.writeLine(cid[pid] + 2); + c1_it = c1->writeLine(cid[pid] + 2); c1_it.setCol(tm1, -cz); - c2_it = c2.writeLine(cid[pid] + 2); + c2_it = c2->writeLine(cid[pid] + 2); c2_it.setCol(tm2, cz); } - - c1_d.endEdit(); - c2_d.endEdit(); } template void BilateralLagrangianConstraint::getConstraintViolation(const ConstraintParams* cParams, - BaseVector *v, - const DataVecCoord &d_x1, const DataVecCoord &d_x2 - , const DataVecDeriv & d_v1, const DataVecDeriv & d_v2) + BaseVector* v, + const DataVecCoord& d_x1, const DataVecCoord& d_x2, + const DataVecDeriv& d_v1, const DataVecDeriv& d_v2) { if (!d_activate.getValue()) return; @@ -196,18 +200,20 @@ void BilateralLagrangianConstraint::getConstraintViolation(const Cons const VecCoord &x1 = d_x1.getValue(); const VecCoord &x2 = d_x2.getValue(); - dfree.resize(minp); + m_violation.resize(minp); - for (unsigned pid=0; pidset(cid[pid] , dfree[pid][0]); - v->set(cid[pid]+1, dfree[pid][1]); - v->set(cid[pid]+2, dfree[pid][2]); + v->set(cid[pid] , m_violation[pid][0]); + v->set(cid[pid]+1, m_violation[pid][1]); + v->set(cid[pid]+2, m_violation[pid][2]); } } @@ -235,7 +241,7 @@ void BilateralLagrangianConstraint::getVelocityViolation(BaseVector * auto pos2 = this->getMState2()->readPositions(); const SReal dt = this->getContext()->getDt(); - const SReal invDt = SReal(1.0) / dt; + const SReal invDt = 1_sreal / dt; for (unsigned pid=0; pid Date: Wed, 20 Nov 2024 07:58:05 +0100 Subject: [PATCH 13/24] [all] Minor esthetic changes (#5129) --- .../sofa/component/mapping/linear/IdentityMultiMapping.h | 2 +- Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMultiMapping.h b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMultiMapping.h index 8f5b998cd95..2ebb82cf83b 100644 --- a/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMultiMapping.h +++ b/Sofa/Component/Mapping/Linear/src/sofa/component/mapping/linear/IdentityMultiMapping.h @@ -30,7 +30,7 @@ namespace sofa::component::mapping::linear { -/// concatanate several entire mechanical states together +/// Concatenate several mechanical states together template class IdentityMultiMapping : public LinearMultiMapping { diff --git a/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp b/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp index b2b609088c2..e09f283ef12 100644 --- a/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp +++ b/Sofa/GUI/Qt/src/sofa/gui/qt/DisplayFlagsDataWidget.cpp @@ -98,7 +98,8 @@ DisplayFlagWidget::DisplayFlagWidget(QWidget* parent, const char* name, Qt::Win itemShowFlag[NORMALS] = new QTreeWidgetItem(itemShowOptions, itemShowFlag[WIREFRAME]); this->setTreeWidgetCheckable(itemShowFlag[NORMALS], "Normals"); this->addTopLevelItem(itemShowAll); - itemShowAll->addChild(itemShowVisual); itemShowAll->setExpanded(true); + itemShowAll->setExpanded(true); + itemShowAll->addChild(itemShowVisual); itemShowVisual->addChild(itemShowFlag[VISUALMODELS]); itemShowAll->addChild(itemShowBehavior); itemShowBehavior->addChild(itemShowFlag[BEHAVIORMODELS]); @@ -112,7 +113,8 @@ DisplayFlagWidget::DisplayFlagWidget(QWidget* parent, const char* name, Qt::Win itemShowMapping->addChild(itemShowFlag[MAPPINGS]); itemShowMapping->addChild(itemShowFlag[MECHANICALMAPPINGS]); - this->addTopLevelItem(itemShowOptions); itemShowOptions->setExpanded(true); + this->addTopLevelItem(itemShowOptions); + itemShowOptions->setExpanded(true); itemShowOptions->addChild(itemShowFlag[RENDERING]); itemShowOptions->addChild(itemShowFlag[WIREFRAME]); itemShowOptions->addChild(itemShowFlag[NORMALS]); From 4cc28d670e4cf8702da3656d8b5922d08ccd6677 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Fri, 22 Nov 2024 21:04:32 +0100 Subject: [PATCH 14/24] [Helper] Fix warning unexpected tokens following preprocessor directive (#5137) [Helper] Fix warning --- Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp b/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp index feb08471881..fa90b3195f2 100644 --- a/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp +++ b/Sofa/framework/Helper/src/sofa/helper/system/DynamicLibrary.cpp @@ -111,7 +111,7 @@ void * DynamicLibrary::getSymbolAddress(Handle handle, # endif if(symbolAddress == nullptr) fetchLastError(); -#if not defined (WIN32) +#if !defined (WIN32) else // checking that the symbol really comes from the provided library { From 1c0322653af4054d58ac20fd5d6de8425863c203 Mon Sep 17 00:00:00 2001 From: Paul Baksic <30337881+bakpaul@users.noreply.github.com> Date: Sat, 23 Nov 2024 18:48:08 +0100 Subject: [PATCH 15/24] [LinearSolver] Renamed ShewchuckPCGLinearSolver by removing the Shewchuck (#5139) * Renamed + compatibility layer * Fix factory registration * rename component into scenes * update componentChange.cpp * Update Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.h Co-authored-by: Hugo * Update Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.cpp Co-authored-by: Hugo * Update Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h Co-authored-by: Hugo * Update Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h Co-authored-by: Hugo --------- Co-authored-by: Hugo --- .../LinearSolver/Iterative/CMakeLists.txt | 4 +- ...CGLinearSolver.cpp => PCGLinearSolver.cpp} | 10 +- .../linearsolver/iterative/PCGLinearSolver.h | 123 +++++++++ .../iterative/PCGLinearSolver.inl | 247 ++++++++++++++++++ .../iterative/ShewchukPCGLinearSolver.h | 97 +------ .../iterative/ShewchukPCGLinearSolver.inl | 225 +--------------- .../component/linearsolver/iterative/init.cpp | 4 +- .../src/sofa/helper/ComponentChange.cpp | 4 +- .../plugins/SofaCUDA/examples/raptor-cpu.scn | 2 +- .../plugins/SofaCUDA/examples/raptor-cuda.scn | 2 +- .../plugins/SofaCUDA/examples/raptor.scn | 4 +- .../FEMBAR_ShewchukPCGLinearSolver.scn | 2 +- .../FEMBAR_PCG_AsyncSparseLDLSolver.scn | 2 +- .../FEMBAR_PCG_BlockJacobiPreconditioner.scn | 2 +- .../FEMBAR_PCG_JacobiPreconditioner.scn | 2 +- .../FEMBAR_PCG_NoPreconditioner.scn | 2 +- ...MBAR_PCG_PrecomputedWarpPreconditioner.scn | 2 +- .../FEMBAR_PCG_SSORPreconditioner.scn | 2 +- .../FEMBAR_PCG_WarpPreconditioner.scn | 2 +- .../FEMBAR_PCG_WarpedAsyncSparseLDLSolver.scn | 2 +- ...Heterogeneous-TetrahedronFEMForceField.scn | 4 +- .../Spring/TriangularBendingSprings.scn | 4 +- .../Demos/fallingBeamLagrangianCollision.scn | 4 +- 23 files changed, 406 insertions(+), 346 deletions(-) rename Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/{ShewchukPCGLinearSolver.cpp => PCGLinearSolver.cpp} (82%) create mode 100644 Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h create mode 100644 Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.inl diff --git a/Sofa/Component/LinearSolver/Iterative/CMakeLists.txt b/Sofa/Component/LinearSolver/Iterative/CMakeLists.txt index e94666809ec..50514787466 100644 --- a/Sofa/Component/LinearSolver/Iterative/CMakeLists.txt +++ b/Sofa/Component/LinearSolver/Iterative/CMakeLists.txt @@ -18,6 +18,8 @@ set(HEADER_FILES ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/MinResLinearSolver.inl ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/ShewchukPCGLinearSolver.h ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/ShewchukPCGLinearSolver.inl + ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/PCGLinearSolver.h + ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/PCGLinearSolver.inl ) set(SOURCE_FILES @@ -29,7 +31,7 @@ set(SOURCE_FILES ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/MatrixLinearSolver.cpp ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/MatrixLinearSystem[GraphScattered].cpp ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/MinResLinearSolver.cpp - ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/ShewchukPCGLinearSolver.cpp + ${SOFACOMPONENTLINEARSOLVERITERATIVE_SOURCE_DIR}/PCGLinearSolver.cpp ) sofa_find_package(Sofa.Simulation.Core REQUIRED) diff --git a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.cpp b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.cpp similarity index 82% rename from Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.cpp rename to Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.cpp index 5cd240c90db..72f4df45bed 100644 --- a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.cpp +++ b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.cpp @@ -19,8 +19,8 @@ * * * Contact information: contact@sofa-framework.org * ******************************************************************************/ -#define SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_SHEWCHUKPCGLINEARSOLVER_CPP -#include +#define SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_PCGLINEARSOLVER_CPP +#include #include #include #include @@ -28,12 +28,12 @@ namespace sofa::component::linearsolver::iterative { -void registerShewchukPCGLinearSolver(sofa::core::ObjectFactory* factory) +void registerPCGLinearSolver(sofa::core::ObjectFactory* factory) { factory->registerObjects(core::ObjectRegistrationData("Linear system solver using the Shewchuk conjugate gradient iterative algorithm.") - .add< ShewchukPCGLinearSolver >()); + .add< PCGLinearSolver >()); } -template class SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_API ShewchukPCGLinearSolver; +template class SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_API PCGLinearSolver; } // namespace sofa::component::linearsolver::iterative diff --git a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h new file mode 100644 index 00000000000..1506256becd --- /dev/null +++ b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.h @@ -0,0 +1,123 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 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 . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include + +#include + +#include + +namespace sofa::component::linearsolver::iterative +{ + +/// Linear system solver using the conjugate gradient iterative algorithm +template +class PCGLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver +{ +public: + SOFA_CLASS(SOFA_TEMPLATE2(PCGLinearSolver,TMatrix,TVector),SOFA_TEMPLATE2(sofa::component::linearsolver::MatrixLinearSolver,TMatrix,TVector)); + + typedef TMatrix Matrix; + typedef TVector Vector; + typedef sofa::component::linearsolver::MatrixLinearSolver Inherit; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() + sofa::core::objectmodel::RenamedData f_maxIter; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() + sofa::core::objectmodel::RenamedData f_tolerance; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() + sofa::core::objectmodel::RenamedData f_use_precond; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() + sofa::core::objectmodel::RenamedData f_update_step; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() + sofa::core::objectmodel::RenamedData f_build_precond; + + SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() + sofa::core::objectmodel::RenamedData > > f_graph; + + + Data d_maxIter; ///< Maximum number of iterations after which the iterative descent of the Conjugate Gradient must stop + Data d_tolerance; ///< Desired accuracy of the Conjugate Gradient solution evaluating: |r|²/|b|² (ratio of current residual norm over initial residual norm) + Data d_use_precond; ///< Use a preconditioner + SingleLink l_preconditioner; ///< Link towards the linear solver used to precondition the conjugate gradient + Data d_update_step; ///< Number of steps before the next refresh of preconditioners + Data d_build_precond; ///< Build the preconditioners, if false build the preconditioner only at the initial step + Data > > d_graph; ///< Graph of residuals at each iteration + +protected: + PCGLinearSolver(); + +public: + void solve (Matrix& M, Vector& x, Vector& b) override; + void init() override; + void setSystemMBKMatrix(const core::MechanicalParams* mparams) override; + +private : + unsigned next_refresh_step; + bool first; + int newton_iter; + +protected: + /// This method is separated from the rest to be able to use custom/optimized versions depending on the types of vectors. + /// It computes: p = p*beta + r + inline void cgstep_beta(Vector& p, Vector& r, double beta); + /// This method is separated from the rest to be able to use custom/optimized versions depending on the types of vectors. + /// It computes: x += p*alpha, r -= q*alpha + inline void cgstep_alpha(Vector& x,Vector& p,double alpha); + + void handleEvent(sofa::core::objectmodel::Event* event) override; + + +}; + +template +inline void PCGLinearSolver::cgstep_beta(Vector& p, Vector& r, double beta) +{ + p *= beta; + p += r; //z; +} + +template +inline void PCGLinearSolver::cgstep_alpha(Vector& x,Vector& p,double alpha) +{ + x.peq(p,alpha); // x = x + alpha p +} + +template<> +inline void PCGLinearSolver::cgstep_beta(Vector& p, Vector& r, double beta); + +template<> +inline void PCGLinearSolver::cgstep_alpha(Vector& x,Vector& p,double alpha); + +#if !defined(SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_PCGLINEARSOLVER_CPP) +template class SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_API PCGLinearSolver; +#endif // !defined(SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_PCGLINEARSOLVER_CPP) + +} // namespace sofa::component::linearsolver::iterative diff --git a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.inl b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.inl new file mode 100644 index 00000000000..ff9da2bb46e --- /dev/null +++ b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/PCGLinearSolver.inl @@ -0,0 +1,247 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2006 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 . * +******************************************************************************* +* Authors: The SOFA Team and external contributors (see Authors.txt) * +* * +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace sofa::component::linearsolver::iterative +{ + +template +PCGLinearSolver::PCGLinearSolver() + : d_maxIter(initData(&d_maxIter, (unsigned)25, "iterations", "Maximum number of iterations after which the iterative descent of the Conjugate Gradient must stop") ) + , d_tolerance(initData(&d_tolerance, 1e-5, "tolerance", "Desired accuracy of the Conjugate Gradient solution evaluating: |r|²/|b|² (ratio of current residual norm over initial residual norm)") ) + , d_use_precond(initData(&d_use_precond, true, "use_precond", "Use a preconditioner") ) + , l_preconditioner(initLink("preconditioner", "Link towards the linear solver used to precondition the conjugate gradient")) + , d_update_step(initData(&d_update_step, (unsigned)1, "update_step", "Number of steps before the next refresh of preconditioners") ) + , d_build_precond(initData(&d_build_precond, true, "build_precond", "Build the preconditioners, if false build the preconditioner only at the initial step") ) + , d_graph(initData(&d_graph, "graph", "Graph of residuals at each iteration") ) + , next_refresh_step(0) + , newton_iter(0) +{ + d_graph.setWidget("graph"); + first = true; + this->f_listening.setValue(true); + + f_maxIter.setOriginalData(&d_maxIter); + f_tolerance.setOriginalData(&d_tolerance); + f_use_precond.setOriginalData(&d_use_precond); + f_update_step.setOriginalData(&d_update_step); + f_build_precond.setOriginalData(&d_build_precond); + f_graph.setOriginalData(&d_graph); + +} + +template +void PCGLinearSolver::init() +{ + Inherit1::init(); + + // Find linear solvers + if (l_preconditioner.empty()) + { + msg_info() << "Link \"preconditioner\" to the desired linear solver should be set to precondition the conjugate gradient."; + } + else + { + if (l_preconditioner.get() == nullptr) + { + msg_error() << "No preconditioner found at path: " << l_preconditioner.getLinkedPath(); + sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + else + { + if (l_preconditioner.get()->getTemplateName() == "GraphScattered") + { + msg_error() << "Can not use the preconditioner " << l_preconditioner.get()->getName() << " because it is templated on GraphScatteredType"; + sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + return; + } + else + { + msg_info() << "Preconditioner path used: '" << l_preconditioner.getLinkedPath() << "'"; + } + } + } + + first = true; + sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); +} + +template +void PCGLinearSolver::setSystemMBKMatrix(const core::MechanicalParams* mparams) +{ + sofa::helper::AdvancedTimer::valSet("PCG::buildMBK", 1); + + { + SCOPED_TIMER("PCG::setSystemMBKMatrix"); + Inherit::setSystemMBKMatrix(mparams); + } + + if (l_preconditioner.get()==nullptr) return; + + if (first) //We initialize all the preconditioners for the first step + { + l_preconditioner.get()->setSystemMBKMatrix(mparams); + first = false; + next_refresh_step = 1; + } + else if (d_build_precond.getValue()) + { + sofa::helper::AdvancedTimer::valSet("PCG::PrecondBuildMBK", 1); + SCOPED_TIMER_VARNAME(mbkTimer, "PCG::PrecondSetSystemMBKMatrix"); + + if (d_update_step.getValue() > 0) + { + if (next_refresh_step >= d_update_step.getValue()) + { + l_preconditioner.get()->setSystemMBKMatrix(mparams); + next_refresh_step=1; + } + else + { + next_refresh_step++; + } + } + } + + l_preconditioner.get()->updateSystemMatrix(); +} + +template<> +inline void PCGLinearSolver::cgstep_beta(Vector& p, Vector& r, double beta) +{ + p.eq(r,p,beta); // p = p*beta + r +} + +template<> +inline void PCGLinearSolver::cgstep_alpha(Vector& x, Vector& p, double alpha) +{ + x.peq(p,alpha); // x = x + alpha p +} + +template +void PCGLinearSolver::handleEvent(sofa::core::objectmodel::Event* event) { + /// this event shoul be launch before the addKToMatrix + if (sofa::simulation::AnimateBeginEvent::checkEventType(event)) + { + newton_iter = 0; + std::map < std::string, sofa::type::vector >& graph = * d_graph.beginEdit(); + graph.clear(); + } +} + + +template +void PCGLinearSolver::solve (Matrix& M, Vector& x, Vector& b) +{ + SCOPED_TIMER_VARNAME(solveTimer, "PCGLinearSolver::solve"); + + std::map < std::string, sofa::type::vector >& graph = * d_graph.beginEdit(); +// sofa::type::vector& graph_error = graph["Error"]; + + newton_iter++; + char name[256]; + sprintf(name,"Error %d",newton_iter); + sofa::type::vector& graph_error = graph[std::string(name)]; + + const core::ExecParams* params = core::execparams::defaultInstance(); + typename Inherit::TempVectorContainer vtmp(this, params, M, x, b); + Vector& r = *vtmp.createTempVector(); + Vector& w = *vtmp.createTempVector(); + Vector& s = *vtmp.createTempVector(); + + const bool apply_precond = l_preconditioner.get()!=nullptr && d_use_precond.getValue(); + + const double b_norm = b.dot(b); + const double tol = d_tolerance.getValue() * b_norm; + + r = M * x; + cgstep_beta(r,b,-1);// r = -1 * r + b = b - (M * x) + + if (apply_precond) + { + SCOPED_TIMER_VARNAME(applyPrecondTimer, "PCGLinearSolver::apply Precond"); + l_preconditioner.get()->setSystemLHVector(w); + l_preconditioner.get()->setSystemRHVector(r); + l_preconditioner.get()->solveSystem(); + } + else + { + w = r; + } + + double r_norm = r.dot(w); + graph_error.push_back(r_norm/b_norm); + + unsigned iter=1; + while ((iter <= d_maxIter.getValue()) && (r_norm > tol)) + { + s = M * w; + const double dtq = w.dot(s); + double alpha = r_norm / dtq; + + cgstep_alpha(x,w,alpha);//for(int i=0; isetSystemLHVector(s); + l_preconditioner.get()->setSystemRHVector(r); + l_preconditioner.get()->solveSystem(); + } + else + { + s = r; + } + + const double deltaOld = r_norm; + r_norm = r.dot(s); + graph_error.push_back(r_norm/b_norm); + + double beta = r_norm / deltaOld; + + cgstep_beta(w,s,beta);//for (int i=0; i -#include -#include -#include +#include -#include - -#include +SOFA_HEADER_DEPRECATED("v24.12", "v25.12", "sofa/component/linearsolver/iterative/PCGLinearSolver.h") namespace sofa::component::linearsolver::iterative { - -/// Linear system solver using the conjugate gradient iterative algorithm -template -class ShewchukPCGLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver -{ -public: - SOFA_CLASS(SOFA_TEMPLATE2(ShewchukPCGLinearSolver,TMatrix,TVector),SOFA_TEMPLATE2(sofa::component::linearsolver::MatrixLinearSolver,TMatrix,TVector)); - - typedef TMatrix Matrix; - typedef TVector Vector; - typedef sofa::component::linearsolver::MatrixLinearSolver Inherit; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_maxIter; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_tolerance; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_use_precond; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_update_step; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData f_build_precond; - - SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_LINEARSOLVER_ITERATIVE() - sofa::core::objectmodel::RenamedData > > f_graph; - - - Data d_maxIter; ///< Maximum number of iterations after which the iterative descent of the Conjugate Gradient must stop - Data d_tolerance; ///< Desired accuracy of the Conjugate Gradient solution evaluating: |r|²/|b|² (ratio of current residual norm over initial residual norm) - Data d_use_precond; ///< Use a preconditioner - SingleLink l_preconditioner; ///< Link towards the linear solver used to precondition the conjugate gradient - Data d_update_step; ///< Number of steps before the next refresh of preconditioners - Data d_build_precond; ///< Build the preconditioners, if false build the preconditioner only at the initial step - Data > > d_graph; ///< Graph of residuals at each iteration - -protected: - ShewchukPCGLinearSolver(); - -public: - void solve (Matrix& M, Vector& x, Vector& b) override; - void init() override; - void setSystemMBKMatrix(const core::MechanicalParams* mparams) override; - -private : - unsigned next_refresh_step; - bool first; - int newton_iter; - -protected: - /// This method is separated from the rest to be able to use custom/optimized versions depending on the types of vectors. - /// It computes: p = p*beta + r - inline void cgstep_beta(Vector& p, Vector& r, double beta); - /// This method is separated from the rest to be able to use custom/optimized versions depending on the types of vectors. - /// It computes: x += p*alpha, r -= q*alpha - inline void cgstep_alpha(Vector& x,Vector& p,double alpha); - - void handleEvent(sofa::core::objectmodel::Event* event) override; - - -}; - -template -inline void ShewchukPCGLinearSolver::cgstep_beta(Vector& p, Vector& r, double beta) -{ - p *= beta; - p += r; //z; -} - template -inline void ShewchukPCGLinearSolver::cgstep_alpha(Vector& x,Vector& p,double alpha) -{ - x.peq(p,alpha); // x = x + alpha p +using ShewchukPCGLinearSolver SOFA_ATTRIBUTE_DEPRECATED("v24.12", "v25.12", "ShewchukPCGLinearSolver has been renamed to PCGLinearSolver") = PCGLinearSolver; } - -template<> -inline void ShewchukPCGLinearSolver::cgstep_beta(Vector& p, Vector& r, double beta); - -template<> -inline void ShewchukPCGLinearSolver::cgstep_alpha(Vector& x,Vector& p,double alpha); - -#if !defined(SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_SHEWCHUKPCGLINEARSOLVER_CPP) -template class SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_API ShewchukPCGLinearSolver; -#endif // !defined(SOFA_COMPONENT_LINEARSOLVER_ITERATIVE_SHEWCHUKPCGLINEARSOLVER_CPP) - -} // namespace sofa::component::linearsolver::iterative diff --git a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.inl b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.inl index 68eb09ae9d0..8345764ae6c 100644 --- a/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.inl +++ b/Sofa/Component/LinearSolver/Iterative/src/sofa/component/linearsolver/iterative/ShewchukPCGLinearSolver.inl @@ -20,228 +20,7 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #pragma once -#include -#include -#include -#include -#include -#include -#include +#include -#include - -namespace sofa::component::linearsolver::iterative -{ - -template -ShewchukPCGLinearSolver::ShewchukPCGLinearSolver() - : d_maxIter(initData(&d_maxIter, (unsigned)25, "iterations", "Maximum number of iterations after which the iterative descent of the Conjugate Gradient must stop") ) - , d_tolerance(initData(&d_tolerance, 1e-5, "tolerance", "Desired accuracy of the Conjugate Gradient solution evaluating: |r|²/|b|² (ratio of current residual norm over initial residual norm)") ) - , d_use_precond(initData(&d_use_precond, true, "use_precond", "Use a preconditioner") ) - , l_preconditioner(initLink("preconditioner", "Link towards the linear solver used to precondition the conjugate gradient")) - , d_update_step(initData(&d_update_step, (unsigned)1, "update_step", "Number of steps before the next refresh of preconditioners") ) - , d_build_precond(initData(&d_build_precond, true, "build_precond", "Build the preconditioners, if false build the preconditioner only at the initial step") ) - , d_graph(initData(&d_graph, "graph", "Graph of residuals at each iteration") ) - , next_refresh_step(0) - , newton_iter(0) -{ - d_graph.setWidget("graph"); - first = true; - this->f_listening.setValue(true); - - f_maxIter.setOriginalData(&d_maxIter); - f_tolerance.setOriginalData(&d_tolerance); - f_use_precond.setOriginalData(&d_use_precond); - f_update_step.setOriginalData(&d_update_step); - f_build_precond.setOriginalData(&d_build_precond); - f_graph.setOriginalData(&d_graph); - -} - -template -void ShewchukPCGLinearSolver::init() -{ - Inherit1::init(); - - // Find linear solvers - if (l_preconditioner.empty()) - { - msg_info() << "Link \"preconditioner\" to the desired linear solver should be set to precondition the conjugate gradient."; - } - else - { - if (l_preconditioner.get() == nullptr) - { - msg_error() << "No preconditioner found at path: " << l_preconditioner.getLinkedPath(); - sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; - } - else - { - if (l_preconditioner.get()->getTemplateName() == "GraphScattered") - { - msg_error() << "Can not use the preconditioner " << l_preconditioner.get()->getName() << " because it is templated on GraphScatteredType"; - sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; - } - else - { - msg_info() << "Preconditioner path used: '" << l_preconditioner.getLinkedPath() << "'"; - } - } - } - - first = true; - sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); -} - -template -void ShewchukPCGLinearSolver::setSystemMBKMatrix(const core::MechanicalParams* mparams) -{ - sofa::helper::AdvancedTimer::valSet("PCG::buildMBK", 1); - - { - SCOPED_TIMER("PCG::setSystemMBKMatrix"); - Inherit::setSystemMBKMatrix(mparams); - } - - if (l_preconditioner.get()==nullptr) return; - - if (first) //We initialize all the preconditioners for the first step - { - l_preconditioner.get()->setSystemMBKMatrix(mparams); - first = false; - next_refresh_step = 1; - } - else if (d_build_precond.getValue()) - { - sofa::helper::AdvancedTimer::valSet("PCG::PrecondBuildMBK", 1); - SCOPED_TIMER_VARNAME(mbkTimer, "PCG::PrecondSetSystemMBKMatrix"); - - if (d_update_step.getValue() > 0) - { - if (next_refresh_step >= d_update_step.getValue()) - { - l_preconditioner.get()->setSystemMBKMatrix(mparams); - next_refresh_step=1; - } - else - { - next_refresh_step++; - } - } - } - - l_preconditioner.get()->updateSystemMatrix(); -} - -template<> -inline void ShewchukPCGLinearSolver::cgstep_beta(Vector& p, Vector& r, double beta) -{ - p.eq(r,p,beta); // p = p*beta + r -} - -template<> -inline void ShewchukPCGLinearSolver::cgstep_alpha(Vector& x, Vector& p, double alpha) -{ - x.peq(p,alpha); // x = x + alpha p -} - -template -void ShewchukPCGLinearSolver::handleEvent(sofa::core::objectmodel::Event* event) { - /// this event shoul be launch before the addKToMatrix - if (sofa::simulation::AnimateBeginEvent::checkEventType(event)) - { - newton_iter = 0; - std::map < std::string, sofa::type::vector >& graph = * d_graph.beginEdit(); - graph.clear(); - } -} - - -template -void ShewchukPCGLinearSolver::solve (Matrix& M, Vector& x, Vector& b) -{ - SCOPED_TIMER_VARNAME(solveTimer, "PCGLinearSolver::solve"); - - std::map < std::string, sofa::type::vector >& graph = * d_graph.beginEdit(); -// sofa::type::vector& graph_error = graph["Error"]; - - newton_iter++; - char name[256]; - sprintf(name,"Error %d",newton_iter); - sofa::type::vector& graph_error = graph[std::string(name)]; - - const core::ExecParams* params = core::execparams::defaultInstance(); - typename Inherit::TempVectorContainer vtmp(this, params, M, x, b); - Vector& r = *vtmp.createTempVector(); - Vector& w = *vtmp.createTempVector(); - Vector& s = *vtmp.createTempVector(); - - const bool apply_precond = l_preconditioner.get()!=nullptr && d_use_precond.getValue(); - - const double b_norm = b.dot(b); - const double tol = d_tolerance.getValue() * b_norm; - - r = M * x; - cgstep_beta(r,b,-1);// r = -1 * r + b = b - (M * x) - - if (apply_precond) - { - SCOPED_TIMER_VARNAME(applyPrecondTimer, "PCGLinearSolver::apply Precond"); - l_preconditioner.get()->setSystemLHVector(w); - l_preconditioner.get()->setSystemRHVector(r); - l_preconditioner.get()->solveSystem(); - } - else - { - w = r; - } - - double r_norm = r.dot(w); - graph_error.push_back(r_norm/b_norm); - - unsigned iter=1; - while ((iter <= d_maxIter.getValue()) && (r_norm > tol)) - { - s = M * w; - const double dtq = w.dot(s); - double alpha = r_norm / dtq; - - cgstep_alpha(x,w,alpha);//for(int i=0; isetSystemLHVector(s); - l_preconditioner.get()->setSystemRHVector(r); - l_preconditioner.get()->solveSystem(); - } - else - { - s = r; - } - - const double deltaOld = r_norm; - r_norm = r.dot(s); - graph_error.push_back(r_norm/b_norm); - - double beta = r_norm / deltaOld; - - cgstep_beta(w,s,beta);//for (int i=0; i > renamedComponents = { {"UniformConstraint", Renamed("v24.06","v25.06","UniformLagrangianConstraint")}, {"UnilateralInteractionConstraint", Renamed("v24.06","v25.06","UnilateralLagrangianConstraint")}, {"StiffSpringForceField", Renamed("v24.06","v25.06","SpringForceField")}, - {"ParallelStiffSpringForceField", Renamed("v24.06","v25.06","ParallelSpringForceField")} + {"ParallelStiffSpringForceField", Renamed("v24.06","v25.06","ParallelSpringForceField")}, + {"ShewchukPCGLinearSolver", Renamed("v24.12","v25.12","PCGLinearSolver")} }; @@ -799,7 +800,6 @@ const std::map< std::string, Dealiased, std::less<> > dealiasedComponents = { {"ConjugateGradient", Dealiased("v24.12","CGLinearSolver")}, {"MINRESSolver", Dealiased("v24.12","MinResLinearSolver")}, {"MinResSolver", Dealiased("v24.12","MinResLinearSolver")}, - {"PCGLinearSolver", Dealiased("v24.12","ShewchukPCGLinearSolver")}, {"JacobiLinearSolver", Dealiased("v24.12","JacobiPreconditioner")}, {"JacobiSolver", Dealiased("v24.12","JacobiPreconditioner")}, {"SSORLinearSolver", Dealiased("v24.12","SSORPreconditioner")}, diff --git a/applications/plugins/SofaCUDA/examples/raptor-cpu.scn b/applications/plugins/SofaCUDA/examples/raptor-cpu.scn index 13de694e82d..a29d72c86d4 100644 --- a/applications/plugins/SofaCUDA/examples/raptor-cpu.scn +++ b/applications/plugins/SofaCUDA/examples/raptor-cpu.scn @@ -6,7 +6,7 @@ - diff --git a/applications/plugins/SofaCUDA/examples/raptor-cuda.scn b/applications/plugins/SofaCUDA/examples/raptor-cuda.scn index 4b3c414284d..962f7f57077 100644 --- a/applications/plugins/SofaCUDA/examples/raptor-cuda.scn +++ b/applications/plugins/SofaCUDA/examples/raptor-cuda.scn @@ -13,7 +13,7 @@ - diff --git a/applications/plugins/SofaCUDA/examples/raptor.scn b/applications/plugins/SofaCUDA/examples/raptor.scn index 0a6c0019fe9..69b658ffb1a 100644 --- a/applications/plugins/SofaCUDA/examples/raptor.scn +++ b/applications/plugins/SofaCUDA/examples/raptor.scn @@ -1,7 +1,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/examples/Component/LinearSolver/Iterative/FEMBAR_ShewchukPCGLinearSolver.scn b/examples/Component/LinearSolver/Iterative/FEMBAR_ShewchukPCGLinearSolver.scn index c11b2de4255..89b5871bb32 100644 --- a/examples/Component/LinearSolver/Iterative/FEMBAR_ShewchukPCGLinearSolver.scn +++ b/examples/Component/LinearSolver/Iterative/FEMBAR_ShewchukPCGLinearSolver.scn @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_AsyncSparseLDLSolver.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_AsyncSparseLDLSolver.scn index 588a6fc78ed..082a192cb47 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_AsyncSparseLDLSolver.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_AsyncSparseLDLSolver.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_BlockJacobiPreconditioner.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_BlockJacobiPreconditioner.scn index e657eb38a31..797e956cb24 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_BlockJacobiPreconditioner.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_BlockJacobiPreconditioner.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_JacobiPreconditioner.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_JacobiPreconditioner.scn index 2940aa82c53..b8a29eb500e 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_JacobiPreconditioner.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_JacobiPreconditioner.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_NoPreconditioner.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_NoPreconditioner.scn index dacb8fed69d..91a74ddd909 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_NoPreconditioner.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_NoPreconditioner.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_PrecomputedWarpPreconditioner.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_PrecomputedWarpPreconditioner.scn index de1f8a7a434..fcb6eea9c34 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_PrecomputedWarpPreconditioner.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_PrecomputedWarpPreconditioner.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_SSORPreconditioner.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_SSORPreconditioner.scn index 295669b9709..7f0307c18f3 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_SSORPreconditioner.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_SSORPreconditioner.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpPreconditioner.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpPreconditioner.scn index 24134226f6b..aa4c61c823e 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpPreconditioner.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpPreconditioner.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpedAsyncSparseLDLSolver.scn b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpedAsyncSparseLDLSolver.scn index fb72a11ea40..5198f1f8e9e 100644 --- a/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpedAsyncSparseLDLSolver.scn +++ b/examples/Component/LinearSolver/Preconditioner/FEMBAR_PCG_WarpedAsyncSparseLDLSolver.scn @@ -2,7 +2,7 @@ - + diff --git a/examples/Component/SolidMechanics/FEM/Heterogeneous-TetrahedronFEMForceField.scn b/examples/Component/SolidMechanics/FEM/Heterogeneous-TetrahedronFEMForceField.scn index 0fe9a314781..557186571f7 100644 --- a/examples/Component/SolidMechanics/FEM/Heterogeneous-TetrahedronFEMForceField.scn +++ b/examples/Component/SolidMechanics/FEM/Heterogeneous-TetrahedronFEMForceField.scn @@ -8,7 +8,7 @@ - + @@ -39,7 +39,7 @@ - + diff --git a/examples/Component/SolidMechanics/Spring/TriangularBendingSprings.scn b/examples/Component/SolidMechanics/Spring/TriangularBendingSprings.scn index 8a54f619b88..06cace33be4 100644 --- a/examples/Component/SolidMechanics/Spring/TriangularBendingSprings.scn +++ b/examples/Component/SolidMechanics/Spring/TriangularBendingSprings.scn @@ -4,7 +4,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/examples/Demos/fallingBeamLagrangianCollision.scn b/examples/Demos/fallingBeamLagrangianCollision.scn index 9910730d396..3706a2e8791 100644 --- a/examples/Demos/fallingBeamLagrangianCollision.scn +++ b/examples/Demos/fallingBeamLagrangianCollision.scn @@ -10,7 +10,7 @@ - + @@ -44,7 +44,7 @@ - + Date: Sat, 23 Nov 2024 18:50:21 +0100 Subject: [PATCH 16/24] [Mapping] Fix debug compilation (#5134) Modify content of assert accordingly Co-authored-by: Hugo --- .../src/sofa/component/mapping/testing/MappingTestCreation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h b/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h index 3c390ecec0b..075524fe651 100644 --- a/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h +++ b/Sofa/Component/Mapping/Testing/src/sofa/component/mapping/testing/MappingTestCreation.h @@ -146,7 +146,7 @@ struct Mapping_test: public BaseSimulationTest, NumericTest Date: Fri, 29 Nov 2024 12:08:12 +0100 Subject: [PATCH 17/24] [Backward] Fix typo (#5146) --- .../component/odesolver/backward/StaticSolver.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/StaticSolver.cpp b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/StaticSolver.cpp index 48d6750452f..f1703d24561 100644 --- a/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/StaticSolver.cpp +++ b/Sofa/Component/ODESolver/Backward/src/sofa/component/odesolver/backward/StaticSolver.cpp @@ -45,29 +45,29 @@ StaticSolver::StaticSolver() : d_newton_iterations(initData(&d_newton_iterations, (unsigned) 1, "newton_iterations", - "Number of Netwon iterations between each load increments (normally, one load increment per simulation time-step.")) + "Number of Newton iterations between each load increments (normally, one load increment per simulation time-step.")) , d_absolute_correction_tolerance_threshold(initData(&d_absolute_correction_tolerance_threshold, 1e-5_sreal, "absolute_correction_tolerance_threshold", - "Convergence criterion of the norm |du| under which the Netwon iterations stop")) + "Convergence criterion of the norm |du| under which the Newton iterations stop")) , d_relative_correction_tolerance_threshold(initData(&d_relative_correction_tolerance_threshold, 1e-5_sreal, "relative_correction_tolerance_threshold", - "Convergence criterion regarding the ratio |du| / |U| under which the Netwon iterations stop")) + "Convergence criterion regarding the ratio |du| / |U| under which the Newton iterations stop")) , d_absolute_residual_tolerance_threshold( initData(&d_absolute_residual_tolerance_threshold, 1e-5_sreal, "absolute_residual_tolerance_threshold", - "Convergence criterion of the norm |R| under which the Netwon iterations stop." + "Convergence criterion of the norm |R| under which the Newton iterations stop." "Use a negative value to disable this criterion")) , d_relative_residual_tolerance_threshold( initData(&d_relative_residual_tolerance_threshold, 1e-5_sreal, "relative_residual_tolerance_threshold", - "Convergence criterion regarding the ratio |R|/|R0| under which the Netwon iterations stop." + "Convergence criterion regarding the ratio |R|/|R0| under which the Newton iterations stop." "Use a negative value to disable this criterion")) , d_should_diverge_when_residual_is_growing( initData(&d_should_diverge_when_residual_is_growing, false, "should_diverge_when_residual_is_growing", - "Boolean stopping Netwon iterations when the residual is greater than the one from the previous iteration")) + "Boolean stopping Newton iterations when the residual is greater than the one from the previous iteration")) {} void StaticSolver::solve(const sofa::core::ExecParams* params, SReal dt, sofa::core::MultiVecCoordId xResult, sofa::core::MultiVecDerivId vResult) From ae42c7e93ceb60605b3e9208bc8d714a995a3854 Mon Sep 17 00:00:00 2001 From: Guilhem Saurel Date: Wed, 4 Dec 2024 15:20:55 +0100 Subject: [PATCH 18/24] [workflow][Nix] initial packaging & flake (#5059) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Nix] initial packaging & flake * [Nix] setup CI * [CMake] FindQGLViewer: fix include dir computation we use `#include `, so `QGLViewer_INCLUDE_DIR` must not include `QGLViewer` component. Also, on darwin, headers are installed in Headers dir, not include, ref: https://github.com/GillesDebunne/libQGLViewer/blob/ba9a875784afbb7ee73088fe0e8701c31bc7277d/QGLViewer/QGLViewer.pro#L138 * [Nix] fix build on macos This require fixes in upstream nixpkgs: https://github.com/NixOS/nixpkgs/pull/348549 So we can use the source of that PR for now * [CMake] FindQGLViewer: fix for Qt6 ref. https://github.com/GillesDebunne/libQGLViewer/blob/ba9a875784afbb7ee73088fe0e8701c31bc7277d/QGLViewer/QGLViewer.pro#L176 * [Nix] Qt5 -> Qt6 * [CMake] fix typo for Qt6 * [CMake] fix SOFA_GUI_QT_HAVE_QT6 definition without this, `lib/cmake/Sofa.GUI.Qt/Sofa.GUI.QtConfig.cmake` has: > `set(SOFA_GUI_QT_HAVE_QT6 0)` and therefore, in SofaPython3, `find_package(QGLViewer QUIET REQUIRED)` is not called, and build ends up with: > [ 98%] Linking CXX shared library ../../lib/python3/site-packages/Sofa/Gui.cpython-312-x86_64-linux-gnu.so > […]/ld: cannot find -lQGLViewer: No such file or directory * [Nix] fixup lib path on Darwin TODO: This should be fixed in CMake instead, but I have no clue. error was: > dyld[61665]: Library not loaded: /nix/store/aalbn4pznxwy18ydjmb15c3y4izj8isi-sofa-24.06.00/lib/libSceneChecking.24.12.99.dylib > Referenced from: <8B75C775-7FE5-3755-A190-B11A3F4F6666> /nix/store/aalbn4pznxwy18ydjmb15c3y4izj8isi-sofa-24.06.00/bin/.runSofa-24.12.99-wrapped > Reason: tried: '/nix/store/aalbn4pznxwy18ydjmb15c3y4izj8isi-sofa-24.06.00/lib/libSceneChecking.24.12.99.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/nix/store/aalbn4pznxwy18ydjmb15c3y4izj8isi-sofa-24.06.00/lib/libSceneChecking.24.12.99.dylib' (no such file), '/nix/store/aalbn4pznxwy18ydjmb15c3y4izj8isi-sofa-24.06.00/lib/libSceneChecking.24.12.99.dylib' (no such file), '/usr/local/lib/libSceneChecking.24.12.99.dylib' (no such file), '/usr/lib/libSceneChecking.24.12.99.dylib' (no such file, not in dyld cache) > zsh: abort ./result/bin/runSofa * [Nix] CI on macos too * nix: add nixGL * [Nix] fix package description Co-authored-by: Hugo * Apply suggestions from code review --------- Co-authored-by: Hugo --- .github/workflows/nix.yml | 21 ++++++ Sofa/GUI/Qt/CMakeLists.txt | 7 +- cmake/Modules/FindQGLViewer.cmake | 6 +- flake.lock | 108 ++++++++++++++++++++++++++++++ flake.nix | 37 ++++++++++ package.nix | 82 +++++++++++++++++++++++ 6 files changed, 256 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/nix.yml create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 package.nix diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 00000000000..a1bff8fcec3 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,21 @@ +name: "CI - Nix" + +on: + push: + +jobs: + nix: + runs-on: "${{ matrix.os }}-latest" + if: ${{ github.repository_owner == 'sofa-framework' }} + strategy: + matrix: + os: [ubuntu, macos] + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v27 + # TODO: the "sofa" account on cachix does not exist yet + #- uses: cachix/cachix-action@v15 + #with: + #name: sofa + #authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - run: nix build -L diff --git a/Sofa/GUI/Qt/CMakeLists.txt b/Sofa/GUI/Qt/CMakeLists.txt index 2989ce4279f..85ebe4e49ee 100644 --- a/Sofa/GUI/Qt/CMakeLists.txt +++ b/Sofa/GUI/Qt/CMakeLists.txt @@ -24,8 +24,11 @@ endif() if (Qt6Core_FOUND) message("${PROJECT_NAME}: will use Qt6") - sofa_find_package(Qt6 COMPONENTS Gui GuiTools Widgets WidgetsTools OpenGLWidgets REQUIRED) - set(SOFA_GUI_QT_TARETS ${SOFA_GUI_QT_TARGETS} Qt::Core Qt::Gui Qt::Widgets Qt::OpenGLWidgets ) + find_package(Qt6 COMPONENTS Gui GuiTools Widgets WidgetsTools OpenGLWidgets REQUIRED) + # GuiTools & WidgetsTools does not define a Qt6::component CMake target + # So we can't look for those target to know how we should define SOFA_GUI_QT_HAVE_QT6 + sofa_find_package(Qt6 COMPONENTS Gui Widgets OpenGLWidgets REQUIRED) + set(SOFA_GUI_QT_TARGETS ${SOFA_GUI_QT_TARGETS} Qt::Core Qt::Gui Qt::Widgets Qt::OpenGLWidgets ) elseif (Qt5Core_FOUND) message("${PROJECT_NAME}: will use Qt5 (deprecated)") sofa_find_package(Qt5 COMPONENTS Core Gui OpenGL REQUIRED) diff --git a/cmake/Modules/FindQGLViewer.cmake b/cmake/Modules/FindQGLViewer.cmake index ae6fe0d2091..65eb618dfff 100644 --- a/cmake/Modules/FindQGLViewer.cmake +++ b/cmake/Modules/FindQGLViewer.cmake @@ -14,14 +14,14 @@ if(NOT TARGET QGLViewer) if(NOT QGLViewer_INCLUDE_DIR) find_path(QGLViewer_INCLUDE_DIR - NAMES qglviewer.h - PATH_SUFFIXES include/QGLViewer + NAMES QGLViewer/qglviewer.h + PATH_SUFFIXES include Headers ) endif() if(NOT QGLViewer_LIBRARY) find_library(QGLViewer_LIBRARY - NAMES QGLViewer QGLViewer2 QGLViewer-qt5 + NAMES QGLViewer QGLViewer2 QGLViewer-qt5 QGLViewer-qt6 PATH_SUFFIXES lib ) endif() diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000000..26492ec359a --- /dev/null +++ b/flake.lock @@ -0,0 +1,108 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixgl": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1713543440, + "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", + "owner": "nix-community", + "repo": "nixGL", + "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixGL", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1660551188, + "narHash": "sha256-a1LARMMYQ8DPx1BgoI/UN4bXe12hhZkCNqdxNi6uS0g=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "441dc5d512153039f19ef198e662e4f3dbb9fd65", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1727825735, + "narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1728930054, + "narHash": "sha256-mCaSyViQyiLgZKVLpDcVacbPSNjvsBzfWnGaxvhTzs8=", + "owner": "nim65s", + "repo": "nixpkgs", + "rev": "8e906b3e2aa2274c9d0c555393b4801d3c0badee", + "type": "github" + }, + "original": { + "owner": "nim65s", + "ref": "qt6-libqglviewer", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "nixgl": "nixgl", + "nixpkgs": "nixpkgs_2" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000000..054afca0134 --- /dev/null +++ b/flake.nix @@ -0,0 +1,37 @@ +{ + description = "SOFA is an open-source framework for interactive physics simulation, with emphasis on biomechanical and robotic simulations"; + + inputs = { + flake-parts.url = "github:hercules-ci/flake-parts"; + #nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # ref. https://github.com/NixOS/nixpkgs/pull/348549 + nixpkgs.url = "github:nim65s/nixpkgs/qt6-libqglviewer"; + nixgl.url = "github:nix-community/nixGL"; + }; + + outputs = + inputs@{ flake-parts, nixgl, nixpkgs, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = nixpkgs.lib.systems.flakeExposed; + perSystem = + { pkgs, self', system, ... }: + { + _module.args.pkgs = import nixpkgs { + inherit system; + overlays = [ nixgl.overlay ]; + }; + apps.nixgl = { + type = "app"; + program = pkgs.writeShellApplication { + name = "nixgl-sofa"; + text = "${pkgs.lib.getExe pkgs.nixgl.auto.nixGLDefault} ${pkgs.lib.getExe self'.packages.sofa}"; + }; + }; + devShells.default = pkgs.mkShell { inputsFrom = [ self'.packages.default ]; }; + packages = { + default = self'.packages.sofa; + sofa = pkgs.callPackage ./package.nix { }; + }; + }; + }; +} diff --git a/package.nix b/package.nix new file mode 100644 index 00000000000..1b879c51d14 --- /dev/null +++ b/package.nix @@ -0,0 +1,82 @@ +{ + boost, + cmake, + cxxopts, + eigen, + #fetchFromGitHub, + glew, + gtest, + lib, + qt6Packages, + libGL, + metis, + stdenv, + tinyxml-2, + zlib, +}: + +stdenv.mkDerivation { + pname = "sofa"; + version = "24.06.00"; + + src = lib.fileset.toSource { + root = ./.; + fileset = lib.fileset.unions [ + ./applications + ./Authors.txt + ./cmake + ./CHANGELOG.md + ./CMakeLists.txt + ./CMakePresets.json + ./examples + ./extlibs + ./LICENSE-LGPL.md + ./package.cmake + ./README.md + ./scripts + ./share + ./Sofa + ./tools + ]; + }; + + propagatedNativeBuildInputs = [ + cmake + qt6Packages.wrapQtAppsHook + ]; + propagatedBuildInputs = [ + boost + cxxopts + eigen + glew + gtest + qt6Packages.libqglviewer + qt6Packages.qtbase + libGL + metis + tinyxml-2 + zlib + ]; + + cmakeFlags = [ + (lib.cmakeBool "SOFA_ALLOW_FETCH_DEPENDENCIES" false) + ]; + + doCheck = true; + + postFixup = lib.optionalString stdenv.hostPlatform.isDarwin '' + install_name_tool -change \ + $out/lib/libSceneChecking.24.12.99.dylib \ + $out/plugins/SceneChecking/lib/libSceneChecking.24.12.99.dylib \ + $out/bin/.runSofa-24.12.99-wrapped + ''; + + meta = { + description = "SOFA is an open-source framework for interactive physics simulation, with emphasis on biomechanical and robotic simulations"; + homepage = "https://github.com/sofa-framework/sofa"; + license = lib.licenses.lgpl21Only; + maintainers = with lib.maintainers; [ nim65s ]; + mainProgram = "runSofa"; + platforms = lib.platforms.unix ++ lib.platforms.windows; + }; +} From 71076be65aad8d360efe8ead45d3f457ea1e448e Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Wed, 4 Dec 2024 15:26:54 +0100 Subject: [PATCH 19/24] [Helper] A static alternative to OptionsGroup: SelectableItem (#5062) * [Helper] A static alternative to OptionsGroup: SelectableItem * include map * missing include * add unit tests for a common type string * A type info for SelectableItem * fix compilation * second fix * fix setSelectedId * Support SelectableItem in Qt * add Style and Alignment description * cleaning --- .../model/SlidingLagrangianConstraint.h | 2 +- .../solver/GenericConstraintSolver.cpp | 30 +- .../solver/GenericConstraintSolver.h | 10 +- .../component/rendering3d/OglSceneFrame.cpp | 35 +- .../gl/component/rendering3d/OglSceneFrame.h | 21 +- Sofa/GUI/Qt/src/sofa/gui/qt/DataWidget.h | 41 ++- .../Qt/src/sofa/gui/qt/SimpleDataWidget.cpp | 116 +++++++ .../GUI/Qt/src/sofa/gui/qt/SimpleDataWidget.h | 25 +- .../core/objectmodel/BaseClassNameHelper.h | 6 +- Sofa/framework/DefaultType/CMakeLists.txt | 1 + .../src/sofa/defaulttype/DataTypeInfo.h | 1 + .../sofa/defaulttype/typeinfo/DataTypeInfo.h | 4 +- .../typeinfo/TypeInfo_SelectableItem.h | 50 +++ Sofa/framework/Helper/CMakeLists.txt | 1 + .../Helper/src/sofa/helper/SelectableItem.h | 328 ++++++++++++++++++ Sofa/framework/Helper/test/CMakeLists.txt | 1 + .../Helper/test/OptionsGroup_test.cpp | 7 + .../Helper/test/SelectableItem_test.cpp | 214 ++++++++++++ 18 files changed, 842 insertions(+), 51 deletions(-) create mode 100644 Sofa/framework/DefaultType/src/sofa/defaulttype/typeinfo/TypeInfo_SelectableItem.h create mode 100644 Sofa/framework/Helper/src/sofa/helper/SelectableItem.h create mode 100644 Sofa/framework/Helper/test/SelectableItem_test.cpp diff --git a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/SlidingLagrangianConstraint.h b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/SlidingLagrangianConstraint.h index 2aec761548d..4c9e9aa5c9c 100644 --- a/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/SlidingLagrangianConstraint.h +++ b/Sofa/Component/Constraint/Lagrangian/Model/src/sofa/component/constraint/lagrangian/model/SlidingLagrangianConstraint.h @@ -66,7 +66,7 @@ class SlidingLagrangianConstraint : public core::behavior::PairInteractionConstr SlidingLagrangianConstraint(MechanicalState* object); SlidingLagrangianConstraint(MechanicalState* object1, MechanicalState* object2); - virtual ~SlidingLagrangianConstraint(){} + ~SlidingLagrangianConstraint() override {} diff --git a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.cpp b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.cpp index cf3d4e1a770..e33cbaa1b0b 100644 --- a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.cpp +++ b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.cpp @@ -60,8 +60,10 @@ void clearMultiVecId(sofa::core::objectmodel::BaseContext* ctx, const sofa::core } +static constexpr GenericConstraintSolver::ResolutionMethod defaultResolutionMethod("ProjectedGaussSeidel"); + GenericConstraintSolver::GenericConstraintSolver() - : d_resolutionMethod( initData(&d_resolutionMethod, "resolutionMethod", "Method used to solve the constraint problem, among: \"ProjectedGaussSeidel\", \"UnbuiltGaussSeidel\" or \"for NonsmoothNonlinearConjugateGradient\"")) + : d_resolutionMethod( initData(&d_resolutionMethod, defaultResolutionMethod, "resolutionMethod", ("Method used to solve the constraint problem\n" + ResolutionMethod::dataDescription()).c_str())) , d_maxIt(initData(&d_maxIt, 1000, "maxIterations", "maximal number of iterations of the Gauss-Seidel algorithm")) , d_tolerance(initData(&d_tolerance, 0.001_sreal, "tolerance", "residual error threshold for termination of the Gauss-Seidel algorithm")) , d_sor(initData(&d_sor, 1.0_sreal, "sor", "Successive Over Relaxation parameter (0-2)")) @@ -86,10 +88,6 @@ GenericConstraintSolver::GenericConstraintSolver() , current_cp(&m_cpBuffer[0]) , last_cp(nullptr) { - sofa::helper::OptionsGroup m_newoptiongroup{"ProjectedGaussSeidel","UnbuiltGaussSeidel", "NonsmoothNonlinearConjugateGradient"}; - m_newoptiongroup.setSelectedItem("ProjectedGaussSeidel"); - d_resolutionMethod.setValue(m_newoptiongroup); - addAlias(&d_maxIt, "maxIt"); d_graphErrors.setWidget("graph"); @@ -159,7 +157,8 @@ void GenericConstraintSolver::init() if(d_newtonIterations.isSet()) { - if (d_resolutionMethod.getValue().getSelectedId() != 2) + static constexpr ResolutionMethod NonsmoothNonlinearConjugateGradient("NonsmoothNonlinearConjugateGradient"); + if (d_resolutionMethod.getValue() != NonsmoothNonlinearConjugateGradient) { msg_warning() << "data \"newtonIterations\" is not only taken into account when using the NonsmoothNonlinearConjugateGradient solver"; } @@ -225,15 +224,15 @@ bool GenericConstraintSolver::buildSystem(const core::ConstraintParams *cParams, } // Resolution depending on the method selected - switch ( d_resolutionMethod.getValue().getSelectedId() ) + switch ( d_resolutionMethod.getValue() ) { - case 0: // ProjectedGaussSeidel - case 2: // NonsmoothNonlinearConjugateGradient + case ResolutionMethod("ProjectedGaussSeidel"): + case ResolutionMethod("NonsmoothNonlinearConjugateGradient"): { buildSystem_matrixAssembly(cParams); break; } - case 1: // UnbuiltGaussSeidel + case ResolutionMethod("UnbuiltGaussSeidel"): { buildSystem_matrixFree(numConstraints); break; @@ -429,10 +428,9 @@ bool GenericConstraintSolver::solveSystem(const core::ConstraintParams * /*cPara // Resolution depending on the method selected - switch ( d_resolutionMethod.getValue().getSelectedId() ) + switch ( d_resolutionMethod.getValue()) { - // ProjectedGaussSeidel - case 0: { + case ResolutionMethod("ProjectedGaussSeidel"): { if (notMuted()) { std::stringstream tmp; @@ -445,14 +443,12 @@ bool GenericConstraintSolver::solveSystem(const core::ConstraintParams * /*cPara current_cp->gaussSeidel(0, this); break; } - // UnbuiltGaussSeidel - case 1: { + case ResolutionMethod("UnbuiltGaussSeidel"): { SCOPED_TIMER_VARNAME(unbuiltGaussSeidelTimer, "ConstraintsUnbuiltGaussSeidel"); current_cp->unbuiltGaussSeidel(0, this); break; } - // NonsmoothNonlinearConjugateGradient - case 2: { + case ResolutionMethod("NonsmoothNonlinearConjugateGradient"): { current_cp->NNCG(this, d_newtonIterations.getValue()); break; } diff --git a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h index 7d752048930..cd3c770fd97 100644 --- a/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h +++ b/Sofa/Component/Constraint/Lagrangian/Solver/src/sofa/component/constraint/lagrangian/solver/GenericConstraintSolver.h @@ -33,6 +33,8 @@ #include #include +#include + namespace sofa::component::constraint::lagrangian::solver { @@ -60,7 +62,13 @@ class SOFA_COMPONENT_CONSTRAINT_LAGRANGIAN_SOLVER_API GenericConstraintSolver : ConstraintProblem* getConstraintProblem() override; void lockConstraintProblem(sofa::core::objectmodel::BaseObject* from, ConstraintProblem* p1, ConstraintProblem* p2 = nullptr) override; - Data< sofa::helper::OptionsGroup > d_resolutionMethod; ///< Method used to solve the constraint problem, among: "ProjectedGaussSeidel", "UnbuiltGaussSeidel" or "for NonsmoothNonlinearConjugateGradient" + MAKE_SELECTABLE_ITEMS(ResolutionMethod, + sofa::helper::Item{"ProjectedGaussSeidel", "Projected Gauss-Seidel"}, + sofa::helper::Item{"UnbuiltGaussSeidel", "Gauss-Seidel where the matrix is not assembled"}, + sofa::helper::Item{"NonsmoothNonlinearConjugateGradient", "Non-smooth non-linear conjugate gradient"} + ); + + Data< ResolutionMethod > d_resolutionMethod; ///< Method used to solve the constraint problem, among: "ProjectedGaussSeidel", "UnbuiltGaussSeidel" or "for NonsmoothNonlinearConjugateGradient" SOFA_ATTRIBUTE_DEPRECATED__RENAME_DATA_IN_CONSTRAINT_LAGRANGIAN_SOLVER() sofa::core::objectmodel::RenamedData maxIt; diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.cpp b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.cpp index 41d46622f1a..f2bba6ceb04 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.cpp +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.cpp @@ -32,20 +32,15 @@ int OglSceneFrameClass = core::RegisterObject("Display a frame at the corner of using namespace sofa::defaulttype; +static constexpr OglSceneFrame::Alignment defaultAlignment("BottomRight"); +static constexpr OglSceneFrame::Style defaultStyle("Cylinders"); + OglSceneFrame::OglSceneFrame() : d_drawFrame(initData(&d_drawFrame, true, "draw", "Display the frame or not")) - , d_style(initData(&d_style, "style", "Style of the frame")) - , d_alignment(initData(&d_alignment, "alignment", "Alignment of the frame in the view")) + , d_style(initData(&d_style, defaultStyle, "style", ("Style of the frame\n" + Style::dataDescription()).c_str())) + , d_alignment(initData(&d_alignment, defaultAlignment, "alignment", ("Alignment of the frame in the view\n" + Alignment::dataDescription()).c_str())) , d_viewportSize(initData(&d_viewportSize, 150, "viewportSize", "Size of the viewport where the frame is rendered")) -{ - sofa::helper::OptionsGroup styleOptions{"Arrows", "Cylinders", "CubeCones"}; - styleOptions.setSelectedItem(1); - d_style.setValue(styleOptions); - - sofa::helper::OptionsGroup alignmentOptions{"BottomLeft", "BottomRight", "TopRight", "TopLeft"}; - alignmentOptions.setSelectedItem(1); - d_alignment.setValue(alignmentOptions); -} +{} void OglSceneFrame::drawArrows(const core::visual::VisualParams* vparams) { @@ -112,22 +107,22 @@ void OglSceneFrame::doDrawVisual(const core::visual::VisualParams* vparams) const auto viewportSize = d_viewportSize.getValue(); - switch(d_alignment.getValue().getSelectedId()) + switch(d_alignment.getValue()) { - case 0: //BottomLeft + case Alignment("BottomLeft"): default: glViewport(0,0,viewportSize,viewportSize); glScissor(0,0,viewportSize,viewportSize); break; - case 1: //BottomRight + case Alignment("BottomRight"): glViewport(viewport[2]-viewportSize,0,viewportSize,viewportSize); glScissor(viewport[2]-viewportSize,0,viewportSize,viewportSize); break; - case 2: //TopRight + case Alignment("TopRight"): glViewport(viewport[2]-viewportSize,viewport[3]-viewportSize,viewportSize,viewportSize); glScissor(viewport[2]-viewportSize,viewport[3]-viewportSize,viewportSize,viewportSize); break; - case 3: //TopLeft + case Alignment("TopLeft"): glViewport(0,viewport[3]-viewportSize,viewportSize,viewportSize); glScissor(0,viewport[3]-viewportSize,viewportSize,viewportSize); break; @@ -157,18 +152,18 @@ void OglSceneFrame::doDrawVisual(const core::visual::VisualParams* vparams) vparams->drawTool()->disableLighting(); - switch (d_style.getValue().getSelectedId()) + switch (d_style.getValue()) { - case 0: + case Style("Arrows"): default: drawArrows(vparams); break; - case 1: + case Style("Cylinders"): drawCylinders(vparams); break; - case 2: + case Style("CubeCones"): drawCubeCones(vparams); break; } diff --git a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.h b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.h index c6cdd2288bb..d834c9584d1 100644 --- a/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.h +++ b/Sofa/GL/Component/Rendering3D/src/sofa/gl/component/rendering3d/OglSceneFrame.h @@ -25,6 +25,8 @@ #include #include #include +#include + namespace sofa::gl::component::rendering3d { @@ -38,8 +40,23 @@ class SOFA_GL_COMPONENT_RENDERING3D_API OglSceneFrame : public core::visual::Vis typedef core::visual::VisualParams::Viewport Viewport; Data d_drawFrame; ///< Display the frame or not - Data d_style; ///< Style of the frame - Data d_alignment; ///< Alignment of the frame in the view + + MAKE_SELECTABLE_ITEMS(Style, + sofa::helper::Item{"Arrows", "The frame is composed of arrows"}, + sofa::helper::Item{"Cylinders", "The frame is composed of cylinders"}, + sofa::helper::Item{"CubeCones", "The frame is composed of cubes and cones"}, + ); + + Data