sofa-framework / sofa

Real-time multi-physics simulation with an emphasis on medical simulation.
https://www.sofa-framework.org
GNU Lesser General Public License v2.1
867 stars 296 forks source link

[LinearSystem] Cache mapped mass matrix #4625

Closed alxbilger closed 2 days ago

alxbilger commented 1 month ago

In a mapped state, force fields and masses contribute to the global system matrix via a projection provided by mappings. The term $m M+ k K$ is assembled locally (association with the mapped state), and then the product $J^T (m M+ k K) J$. However, in most cases, $M$ is constant. In addition, in some cases $J$ is also constant. If we fulfill the conditions so that both $M$ and $J$ are constants, we can extract the product $J^T M J$ and pre-compute it once at the beginning of the simulation. This is what this PR does.

In addition to the pre-computation, there is a cache invalidation mechanism on masses to track when $M$ is subject to changes. For example, changes in the mass parameter by the user.

This pre-computation is the most efficient when there is a difference of sparsity between $M$ and $K$. And this is the case when hyper-reduction is involved. $K$ is super sparse (only a few elements are considered), while $M$ gets contributions from all the nodes of the detailed mesh. On a diamond robot with 70,334 tetrahedras and 15,553 vertices, I went from 79.8469 FPS to 177 FPS.


By submitting this pull request, I acknowledge that
I have read, understand, and agree SOFA Developer Certificate of Origin (DCO).


Reviewers will merge this pull-request only if

fredroy commented 1 month ago

[ci-build][with-all-tests]

damienmarchal commented 3 weeks ago

Hello @alxbilger,

Thanks for the PR.

I looked at the implementation and I'm not sure the Observer/Observable mechanism is needed. At current time is seem to be used to notify that, when a mass change, the component using the mass need to be updated.

Tracking component and data changes can already be done using the Directed Dependency Graph (DDG) mechanisms.

When I want a component (B) to track component (A) and detect it changes I connect A.componentState (the observable) by adding B as a DDG output of A.componentState (so B is the obsever). By using the DDG machinery you can have the choice of when the updates is done... when A.componentState is changed or when B is needed ... (thanks the lazy DDG update mechanism). Finally if using the DDG it too heavy, it is also possible to use the DataTracker, this allows to detect data change (eg: A.componentState has changed) when you need to invalidate the cache.

alxbilger commented 3 weeks ago

@damienmarchal Since the code using a BaseMass does not know in advance the conditions triggering the mass changes, do you suggest adding a Data in BaseMass that would change everytime the mass change?

damienmarchal commented 3 weeks ago

Actually I was more thinking on tracking Mass::d_componentState to either be notified on changed or to simply detect when a mass is changed using a DataTracker.

Using a DataTracker situation would be more or less the following...

class MatrixLinearSystem
{
     // .......
     private:
            DataTracker massChangedTracker; 
};

void MatrixLinearSystem<>::XXXX()
{
          ...
          /// somewhere where we add the mass to the lists of contributor
          massChangedTracker->trackData(contributor->d_componentState)
          ... 
}

void MatrixLinearSystem<TMatrix, TVector>::contribute(const core::MechanicalParams* mparams)
{
            ...
            /// Here we can then juste track the change
            else if constexpr (c == Contribution::MASS)
            {
                if( massChangedTracker->hasChanged(contributor->d_componentState) ) 
                {
                       contributor->buildMassMatrix(m_mass[contributor]);
                       massChangedTracker->clean(contributor->d_componentState);          
                 }
            }
           ....
}

PS: This is somehow connected to what @hugtalbot is doing in these PRs: https://github.com/sofa-framework/sofa/pull/3927

alxbilger commented 3 weeks ago

@damienmarchal thanks for your suggestions. The PR now uses a DataTracker associated to a introduced Data in BaseMass.

alxbilger commented 3 weeks ago

[ci-build][with-all-tests]