Skip to content

Phase 2b: emit the strain-coupled consistent tangent dσ/dε for Mode-B residual materials - #101

Merged
petlenz merged 4 commits into
mainfrom
phase-2b-consistent-tangent
Jul 17, 2026
Merged

Phase 2b: emit the strain-coupled consistent tangent dσ/dε for Mode-B residual materials#101
petlenz merged 4 commits into
mainfrom
phase-2b-consistent-tangent

Conversation

@petlenz

@petlenz petlenz commented Jul 8, 2026

Copy link
Copy Markdown
Member

What

Completes the strain-coupled arc: PR #100 emitted the Mode-B residual solve; this PR emits the consistent tangent dσ/dε that makes the generated material usable in an outer FE Newton solve.

For a stress output σ and strain input ε of a material whose scalar state z solves R(z,ε)=0:

dσ/dε = ∂σ/∂ε + ∂σ/∂z ⊗ dz/dε ,   dz/dε = −∂R/∂ε / ∂R/∂z

∂R/∂z is a scalar (scalar state ⇒ no matrix inverse), so the whole tangent is a rank-4 tensor expression in (z, ε, params), emitted as an extra post-solve output evaluated at the converged z (bound to &compute like every output). ∂σ/∂z goes through the detail::diff_tensor_wrt_scalar seam (cas#275).

Commits

  1. Flip the seam ondiff_tensor_wrt_scalar now self-detects the cas#275 overload (diff(tensor, scalar)) via __has_include and collapses to cas::diff. De-risked: all four diffs compile+link+produce valid exprs against the pin; the seam test now renders ∂(x·ε)/∂x = ε (and ∂(x²·ε)/∂x = 2x·ε).
  2. Emit the tangent in emit_residual_material() — assemble the four diffs (∂σ/∂ε, ∂σ/∂z, ∂R/∂ε, ∂R/∂z), render the rank-4 output; full guard set (of_output must be a tensor output, wrt_input a declared tensor input, dim match, name-collision). 6 unit tests.
  3. e2e — the generated ReturnMap tangent is validated numerically vs the real backward_euler solve: the off-block coupling term C_{0011}=c·ε₀₀ a naive ∂σ/∂ε drops.
  4. Review-hardening (2-lens review folded in — cpp-pro + code-reviewer):
    • Exercise the 1/∂R/∂z division: the linear ReturnMap (∂R/∂z≡1) can't detect a dropped divisor, so ReturnMapCubic (∂R/∂z=1+3z²) now carries a tangent asserting C_{0011}=c·ε₀₀/(1+3z²). Sabotage-verified (dropping the divisor fails the cubic test, passes the linear).
    • converged() guard in generated compute() + a tangent caveat: outputs are evaluated at the solved state, so a non-converged/clamped root is rejected loudly (the max(x,0) elastic-branch case needs an upstream was_clamped() — numsim-materials follow-up).
    • Self-detect the seam (was an unconditional compile-def → inline-def ODR hazard).
    • Strengthened the unit pins (correction sign, both otimesu/otimesl, factor) and the seam test (non-trivial coefficient).

Test plan

  • Unit: 287/287 (g++).
  • e2e: 11/11 under g++-14 against the pinned siblings (backward_euler in the loop). Both the coupling term and the /∂R/∂z division sabotage-verified.
  • cpp-pro confirmed no type/correctness bug in the assembled expression (correct partial-derivative IFT composition; CSE brace-scoping; complete leaf/collision guards).

Scope notes

petlenz added 4 commits July 8, 2026 23:13
… verified in pin), seam now computes diff(tensor,scalar)
…) guard + tangent caveat, self-detect the diff seam, strengthen tangent/seam pins
@petlenz
petlenz merged commit 622bc8c into main Jul 17, 2026
4 checks passed
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