Add the geometric term to the flex stretch stiffness

K_stretch was the Gauss-Newton Hessian of the stretch force, not its Jacobian.
With elongation e_a = L_a^2 - L0_a^2 and force f = -sum_ab M_ab e_a grad(e_b)/2,

  K = 2 sum_ab M_ab (s_a d_a)(s_b d_b)^T + sum_a Me_a (Laplacian_a (x) I3)

and only the first term was there. The second is proportional to the edge
tension Me_a = sum_b M_ab e_b, so it vanishes at rest and grows with strain:
the operator was first-order correct and no more. Finite-differencing it
against -d(qfrc_passive)/dq on a mesh dilated by 5% gives 7.8% of the force
scale; with the term it is exact to roundoff.

Add only the tensile part. The geometric block is Me_a*[[I,-I],[-I,I]] over the
edge's two vertices, which is positive semi-definite exactly when Me_a >= 0; a
compressed edge would make K indefinite, and both consumers -- the CG
constraint solver and the PCG in mjd_effSolve -- require SPD. The clamp is
structural, so no eigendecomposition is needed, and it is confined to the
operator: mj_flexPassiveStretch keeps the full Me_a, so no force changes.

Both the matrix-free operator and the CSR assembly the effective metric builds
from are updated, since they must agree.

This changes how flexes with elastic2d="stretch" integrate under the implicit
integrators and the effective metric -- bag.xml moves, poncho.xml is
bit-identical because bending energy is quadratic and has no geometric term.
The interpolated-flex path still uses its Gauss-Newton approximation, which
FlexInterpDerivativesDeformed asserts.
This commit is contained in:
Alessio
2026-08-03 16:16:23 +01:00
parent 7927e908a3
commit 5497994763
3 changed files with 138 additions and 14 deletions
+5
View File
@@ -63,6 +63,11 @@ Bug fixes
large penetration depth between nearly touching thin boxes with positive margin, causing resting stacks to explode.
- Fixed a bug in the box-box collider where penetrations deeper than a box's smallest half-size could produce no
contacts, letting boxes tunnel through thin boxes. Fixes :issue:`1800`.
- Fixed the flex stretch stiffness operator, which was the Gauss-Newton Hessian of the stretch force rather than its
Jacobian: the geometric (stress-proportional) term was missing. Only the tensile part of that term is added, since
it is positive semi-definite exactly when the edge is in tension, and its consumers require an SPD operator; the
stretch force itself is unchanged. This affects the implicit integrators and the implicit effective metric, so
flexes using ``elastic2d="stretch"`` integrate slightly differently. Bending-only flexes are unaffected.
Version 3.11.0 (July 27, 2026)
------------------------------