[Lagrangian.Solver] UnbuiltConstraintSolver: implement hotstart#5875
[Lagrangian.Solver] UnbuiltConstraintSolver: implement hotstart#5875fredroy wants to merge 5 commits intosofa-framework:masterfrom
Conversation
|
[ci-build][with-all-tests] |
79b43ad to
ef0b031
Compare
...agrangian/Solver/src/sofa/component/constraint/lagrangian/solver/UnbuiltConstraintSolver.cpp
Outdated
Show resolved
Hide resolved
ef0b031 to
f7190e9
Compare
|
Before merging, I would like a review (or at least the opinion) of either @ChristianDuriez or @EulalieCoevoet |
| type::vector<SReal> m_previousForces; | ||
| VecConstraintBlockInfo m_constraintBlockInfo; | ||
| VecPersistentID m_constraintIds; | ||
| unsigned int m_numConstraints{0}; ///< Number of constraints from current/previous timestep |
There was a problem hiding this comment.
Can you prefix all of these by previous so it is clear that they are used for storing values of previous time step ?
| // Get constraint info for hot-start BEFORE clear() resets the constraint count check | ||
| preClearCorrection(cParams); | ||
|
|
There was a problem hiding this comment.
I don't get why this is needed. When you look at the implementation of the doPreClear, clearing the curren_cp wouldn't change a thing in what MechanicalGetConstraintInfoVisitor will get. So for me the pre/post is not necessary. could you try mergin both and calling the merged method after the clear ?
| for (auto& previousConstraint : m_previousConstraints) | ||
| { | ||
| ConstraintBlockBuf& buf = previousConstraint.second; | ||
| for (auto& it2 : buf.persistentToConstraintIdMap) | ||
| { | ||
| it2.second = -1; | ||
| } | ||
| } |
There was a problem hiding this comment.
Wouldn't it be better to simply clear the whole map and start fresh ? Otherwise if the parent keep changing, this map will grow without getting properly cleaned
| if (!info.parent) continue; | ||
| if (!info.hasId) continue; | ||
|
|
||
| auto previt = m_previousConstraints.find(info.parent); |
There was a problem hiding this comment.
Using the parent as a key is somewhat strange because it it irrelevant @the level of the solver. What is relevant is the element on which the force is applied. This information is only kept in the constraint jacobian matrix. At this level I don't think it is possible to get an actual proper hotstart. What is done here it is looking at the id of the constraint at the level of the component which transform the collision detection output into the constraint jacobian. So what you are comparing here is the place of the force in the original vector of the collision detection. So for me this hotstart is just as good as copying back the content of the old force vector into the new one while clamping or padding if size mismatch. This is only by chance that you get forces that are good because the collision detection is somewhat deterministic.
The only strong difference would be when there are two component responsible of transforming this collision output into contact force, this would keep the force at least in the good part of the vector (the old forces will be used a starting point of forces coming from the same collision detection), but there is no garantee that the force is applied in the same region of the object as before. This happens when you have multiple objects colliding. But really, I don't know how much you gain with respect of a simple copy/clipping/padding work.
Could you try out your example with this simple implementation to see if you get worst convergence ?
Based on
in #5871 (and more cases) it was noted that (unbuilt) LCP was always faster than UnbuiltGaussSeidelConstraintSolver (in average ~10-20 %) and usually converged in less iterations.
Even if the algorithm is rigorously the same (apparently...)
After investigations, Claude 🤖successfully found that the main difference is UnbuiltGaussSeidelConstraintSolver was always starting its GS with the forces at 0 (cold start), whereas LCP was keeping track of the previous forces.
It also provided the implementation (I could never do that by myself 💩) which... looks good to me at least 🙃
Benches (continuation of #5871)
This PR could be considered a little bit... controversial (:vibe:) as Claude-code implemented lots of stuff
[with-all-tests]
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