You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let a recipe declare which stress–strain (work-conjugate) pair the algorithmic
tangent differentiates, including when the strain measure is a derived finite-
strain quantity (E = ½(C−I), ½logC, U, …) rather than the raw tensor input.
Today add_algorithmic_tangent(name, of_output, wrt_input) (recipe.h:807, TangentSpec at recipe.h:271) can only differentiate w.r.t. a declared input
leaf — the pass calls cas::diff(expr, arg) where arg is that input symbol
(passes/internal/algorithmic_tangent.h:56). So the pair is expressible only
when the strain you want happens to be the input.
Why this matters
The Hencky material (#109) makes it concrete. It emits σ(C) and dσ/dC, but
MOOSE's StressDivergence kernels consume _Jacobian_mult as the tangent w.r.t. their strain measure. dσ/dC is notdσ/dε_kernel; the recipe carries a
prominent caveat (examples/hencky_recipe.h) and SCOPE-moose-hencky.md defers
the "kinematic wrapping" precisely because the conjugate pair can't be chosen at
codegen time. Different FE settings want different conjugate pairs
(2nd-PK ↔ Green–Lagrange, Kirchhoff ↔ log-strain, material-Hencky ↔ ½logC, …).
Available today (workaround — approach A)
Author the recipe with the desired strain measure as the input: declare input E (Green–Lagrange), build C = 2E+I internally, express stress through it, then add_algorithmic_tangent("dS_dE", "S", "E"). Exact, zero codegen change — but each
conjugate pair is a separate recipe and nothing validates work-conjugacy.
Proposed feature (B) — differentiation seam
Allow the differentiation variable to be a named derived strain measure:
Recipe API. Extend TangentSpec / add_algorithmic_tangent so wrt may
name a declared strain-measure expression (a named intermediate), not only an
input leaf. E.g. add_strain_measure("E_gl", 0.5*(C - I)) then add_algorithmic_tangent("dS_dE", "stress", "E_gl").
Lowering (AlgorithmicTangentPass). Introduce the measure as a fresh CAS
leaf ε̃, re-express the stress output through ε̃ (substitution / inversion of
the measure map where needed), then cas::diff(σ, ε̃). Where a closed-form
inverse of the measure isn't available, emit the chain-rule form dσ/dε̃ = dσ/dC : (dC/dε̃) using the measure's known derivative.
JSON-selectable. The pair becomes a first-class codegen input, so one recipe
can target multiple FE conventions by config rather than by copy.
Scope / non-goals
The spatial push-forward to a rate form (Truesdell/Jaumann objective rates)
is a separate modeling concern — this issue is about material-frame conjugate
pairs dS_i/dE_j, which is what the generated _Jacobian_mult needs.
Uses only diff(·,tensor) (have it); no rank-4 inverse on the primary path
(per D16).
Acceptance
A single Hencky recipe emits dS/dE (2nd-PK ↔ Green–Lagrange) AND dσ/dC
by pair selection, both FD-verified (extend hencky_check_driver).
Non-conjugate pair request is rejected at emit with an actionable message.
Related: #109 (Hencky, the motivating consumer), #105 (spectral lowering),
Phase 3b in the roadmap.
Summary
Let a recipe declare which stress–strain (work-conjugate) pair the algorithmic
tangent differentiates, including when the strain measure is a derived finite-
strain quantity (
E = ½(C−I),½logC,U, …) rather than the raw tensor input.Today
add_algorithmic_tangent(name, of_output, wrt_input)(recipe.h:807,TangentSpecatrecipe.h:271) can only differentiate w.r.t. a declared inputleaf — the pass calls
cas::diff(expr, arg)whereargis that input symbol(
passes/internal/algorithmic_tangent.h:56). So the pair is expressible onlywhen the strain you want happens to be the input.
Why this matters
The Hencky material (#109) makes it concrete. It emits
σ(C)anddσ/dC, butMOOSE's
StressDivergencekernels consume_Jacobian_multas the tangent w.r.t.their strain measure.
dσ/dCis notdσ/dε_kernel; the recipe carries aprominent caveat (
examples/hencky_recipe.h) andSCOPE-moose-hencky.mddefersthe "kinematic wrapping" precisely because the conjugate pair can't be chosen at
codegen time. Different FE settings want different conjugate pairs
(2nd-PK ↔ Green–Lagrange, Kirchhoff ↔ log-strain, material-Hencky ↔ ½logC, …).
Available today (workaround — approach A)
Author the recipe with the desired strain measure as the input: declare input
E(Green–Lagrange), buildC = 2E+Iinternally, express stress through it, thenadd_algorithmic_tangent("dS_dE", "S", "E"). Exact, zero codegen change — but eachconjugate pair is a separate recipe and nothing validates work-conjugacy.
Proposed feature (B) — differentiation seam
Allow the differentiation variable to be a named derived strain measure:
TangentSpec/add_algorithmic_tangentsowrtmayname a declared strain-measure expression (a named intermediate), not only an
input leaf. E.g.
add_strain_measure("E_gl", 0.5*(C - I))thenadd_algorithmic_tangent("dS_dE", "stress", "E_gl").leaf
ε̃, re-express the stress output throughε̃(substitution / inversion ofthe measure map where needed), then
cas::diff(σ, ε̃). Where a closed-forminverse of the measure isn't available, emit the chain-rule form
dσ/dε̃ = dσ/dC : (dC/dε̃)using the measure's known derivative.dimensionally a tangent and — where cheaply checkable — flag non-work-conjugate
pairs at emit (loud reject, per the repo's "never silently wrong" rule; cf. the
silent-wrong-diff risk that motivated the Phase-C FD spine, Verification spine: pull numerical-correctness verification (FD tangent + golden model + gates) to the front #90).
can target multiple FE conventions by config rather than by copy.
Scope / non-goals
is a separate modeling concern — this issue is about material-frame conjugate
pairs
dS_i/dE_j, which is what the generated_Jacobian_multneeds.diff(·,tensor)(have it); no rank-4 inverse on the primary path(per D16).
Acceptance
dS/dE(2nd-PK ↔ Green–Lagrange) ANDdσ/dCby pair selection, both FD-verified (extend
hencky_check_driver).Related: #109 (Hencky, the motivating consumer), #105 (spectral lowering),
Phase 3b in the roadmap.