From b7a137317c4d4f11d168d025a44ccc9dd10d078c Mon Sep 17 00:00:00 2001 From: Frederick Roy Date: Tue, 13 Oct 2026 10:55:11 +0900 Subject: [PATCH 1/2] [LinearSolver.Direct] BTDLinearSolver: do not clear the dense inverse at each factorization invert() resized Minv at every factorization, and BlockFullMatrix::resize() always clears all its nb*nb blocks. Clearing is not needed: a block of Minv is only read after computeMinvBlock() has written it (tracked by nBlockComputedMinv, reset at each factorization). Minv is now only resized when its size changes. The previous behaviour can be restored with the new forceClearInverse Data. --- .../sofa/component/linearsolver/direct/BTDLinearSolver.h | 2 ++ .../sofa/component/linearsolver/direct/BTDLinearSolver.inl | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h index 19734a7a1e7..cdbd138414d 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h @@ -52,6 +52,7 @@ class BTDLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver Data d_verbose; ///< Dump system state at each iteration Data d_problem; ///< display debug information about subpartSolve computation Data d_subpartSolve; ///< Allows for the computation of a subpart of the system + Data d_forceClearInverse; ///< Clear the whole (dense) inverse matrix at each factorization, as done in previous versions. Not needed for correctness, and costly for long chains Data d_verification; ///< verification of the subpartSolve typedef typename Vector::SubVectorType SubVector; @@ -91,6 +92,7 @@ class BTDLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver : d_verbose( initData(&d_verbose,false,"verbose","Dump system state at each iteration") ) , d_problem(initData(&d_problem, false,"showProblem", "display debug information about subpartSolve computation") ) , d_subpartSolve(initData(&d_subpartSolve, false,"subpartSolve", "Allows for the computation of a subpart of the system") ) + , d_forceClearInverse(initData(&d_forceClearInverse, false, "forceClearInverse", "Clear the whole (dense) inverse matrix at each factorization, as done in previous versions. Not needed for correctness (a block is computed before being used), and costly for long chains")) , d_verification(initData(&d_verification, false,"verification", "verification of the subpartSolve")) { diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl index e0665c9cb60..a093132ec1a 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl @@ -159,8 +159,11 @@ void BTDLinearSolver::invert(Matrix& M) for (Index i=0; i Date: Thu, 29 Oct 2026 13:19:07 +0900 Subject: [PATCH 2/2] [LinearSolver.Direct] BTDLinearSolver: remove forceClearInverse Clearing the dense inverse is never needed: every block of Minv is written (plain assignment) by computeMinvBlock() before being read, and nBlockComputedMinv is reset at each factorization, whatever the topology. A size change still goes through resize(), as before. Checked by filling Minv with NaN instead of clearing it: no NaN read and bit-identical trajectories on the BTD example scenes, including subpartSolve and partial_solve (unbuilt Gauss-Seidel) paths. --- .../src/sofa/component/linearsolver/direct/BTDLinearSolver.h | 2 -- .../sofa/component/linearsolver/direct/BTDLinearSolver.inl | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h index cdbd138414d..19734a7a1e7 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.h @@ -52,7 +52,6 @@ class BTDLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver Data d_verbose; ///< Dump system state at each iteration Data d_problem; ///< display debug information about subpartSolve computation Data d_subpartSolve; ///< Allows for the computation of a subpart of the system - Data d_forceClearInverse; ///< Clear the whole (dense) inverse matrix at each factorization, as done in previous versions. Not needed for correctness, and costly for long chains Data d_verification; ///< verification of the subpartSolve typedef typename Vector::SubVectorType SubVector; @@ -92,7 +91,6 @@ class BTDLinearSolver : public sofa::component::linearsolver::MatrixLinearSolver : d_verbose( initData(&d_verbose,false,"verbose","Dump system state at each iteration") ) , d_problem(initData(&d_problem, false,"showProblem", "display debug information about subpartSolve computation") ) , d_subpartSolve(initData(&d_subpartSolve, false,"subpartSolve", "Allows for the computation of a subpart of the system") ) - , d_forceClearInverse(initData(&d_forceClearInverse, false, "forceClearInverse", "Clear the whole (dense) inverse matrix at each factorization, as done in previous versions. Not needed for correctness (a block is computed before being used), and costly for long chains")) , d_verification(initData(&d_verification, false,"verification", "verification of the subpartSolve")) { diff --git a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl index a093132ec1a..f529883bb27 100644 --- a/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl +++ b/Sofa/Component/LinearSolver/Direct/src/sofa/component/linearsolver/direct/BTDLinearSolver.inl @@ -161,8 +161,8 @@ void BTDLinearSolver::invert(Matrix& M) // Minv is dense: resizing it clears all its nb*nb blocks, which is very costly for long chains. // Clearing is not needed: a block is only read after computeMinvBlock() has written it - // (tracked by nBlockComputedMinv, reset above), so by default only resize when the size changes. - if (d_forceClearInverse.getValue() || Minv.rowSize() != nb*bsize || Minv.colSize() != nb*bsize) + // (tracked by nBlockComputedMinv, reset above), so only resize when the size changes. + if (Minv.rowSize() != nb*bsize || Minv.colSize() != nb*bsize) Minv.resize(nb*bsize,nb*bsize); Minv.setAlignedSubMatrix((nb-1),(nb-1),bsize,bsize,alpha_inv[nb-1]);