Add efm_contact to mjData - #3469
Open
smallquail wants to merge 1 commit into
Open
Conversation
smallquail
force-pushed
the
flex-contact-matrixfree
branch
from
August 10, 2026 17:37
432faf2 to
a855eab
Compare
Flex contact reaches the effective metric as a published pair list rather than as assembled matrix entries. mjData.efm_contact points at an mjEffContact, built once per step: for each pair, the participating vertices' dof triples, their weight vectors, and the stiffness. The metric's consumers read that one representation -- mjd_effMulAdd applies it, mjd_effPrecContact folds it into the preconditioner blocks -- so a producer that can express its contacts as pairs reaches all of them without touching the metric's internals. Contact is a sum of rank-1 terms, so applying D*w*w^T matrix-free costs O(npt) per pair against the O(npt^2) that assembling it costs both to store and to apply, and the stiffness CSR no longer grows with the contact set. This changes passive flex contact behaviour. With contact out of the CSR the metric's block preconditioner no longer picks up its diagonal, and that diagonal was a poor model of the operator: D*w*w^T with w = [n, -n] penalizes the pair's relative motion, while its diagonal penalizes each vertex's absolute motion, stiffening directions the operator leaves free. Dropping it roughly halves the iterations the qacc_smooth solve needs on model/flex/drape.xml; the trajectory differs accordingly.
smallquail
force-pushed
the
flex-contact-matrixfree
branch
from
August 10, 2026 17:41
a855eab to
1018024
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
mjData.efm_contact, through which flex contact reaches the effective metric as a published pair list rather than as assembled matrix entries.The field
efm_contactpoints at anmjEffContact, built once per step. For each pair it carries the participating vertices' dof triples, their weight vectors, and the stiffness — enough to describe the pair's contributionD·wwᵀwithout naming how it was detected. The metric's consumers all read that one representation:mjd_effMulAddapplies it,mjd_effPrecContactfolds it into the preconditioner blocks. A producer that can express its contacts as pairs reaches every consumer without touching the metric's internals.Why not assemble it
Contact is a sum of rank-1 terms. Applying
D·wwᵀmatrix-free is one dot and one scatter —O(npt)per pair — where materialising it in the CSR costsO(npt²)both to store and to apply. The stiffness CSR also stops growing with the contact set, which keeps its sparsity a function of the mesh rather than of the current configuration.Behaviour change
This changes passive flex contact. With contact out of the CSR, the metric's block preconditioner no longer picks up its diagonal — and that diagonal was a poor model of the operator.
D·wwᵀwithw ≈ [n, −n]penalises the pair's relative motion; its diagonal penalises each vertex's absolute motion, stiffening directions the operator leaves free. Dropping it roughly halves the iterations theqacc_smoothsolve needs onmodel/flex/drape.xml(193 → 104). The trajectory differs accordingly: 216 contacts and 5.31 m/s peak speed at t = 3 s, against 228 and 7.24 before.API
mjData.efm_contact(uintptr_t,MJDATA_SCALAR), zeroed inmj_resetDatamjd_effMulAddtakesflg_contact: the linear solves want the contact term, an energy evaluation that accounts for contact separately does notmjd_effContactMulAdd,mjd_effContactCount