Skip to content

Add efm_contact to mjData - #3469

Open
smallquail wants to merge 1 commit into
google-deepmind:mainfrom
smallquail:flex-contact-matrixfree
Open

Add efm_contact to mjData#3469
smallquail wants to merge 1 commit into
google-deepmind:mainfrom
smallquail:flex-contact-matrixfree

Conversation

@smallquail

Copy link
Copy Markdown
Contributor

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_contact points at an mjEffContact, 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 contribution D·wwᵀ without naming how it was detected. The metric's consumers all read that one representation: mjd_effMulAdd applies it, mjd_effPrecContact folds 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 costs O(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ᵀ with w ≈ [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 the qacc_smooth solve needs on model/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 in mj_resetData
  • mjd_effMulAdd takes flg_contact: the linear solves want the contact term, an energy evaluation that accounts for contact separately does not
  • mjd_effContactMulAdd, mjd_effContactCount

@quagla
quagla requested a review from yuvaltassa August 10, 2026 17:30
@smallquail
smallquail force-pushed the flex-contact-matrixfree branch from 432faf2 to a855eab Compare August 10, 2026 17:37
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant