Skip to content

Add stress_from_state interface for postprocessing - #21

Open
knutambot wants to merge 6 commits into
KnutAM:mainfrom
knutambot:cb/calculate_current_stress
Open

knutambot wants to merge 6 commits into
KnutAM:mainfrom
knutambot:cb/calculate_current_stress

Conversation

@knutambot

@knutambot knutambot commented Sep 21, 2026

Copy link
Copy Markdown

Summary

Adds stress_from_state(m, strain, state) for postprocessing: evaluate stress at the supplied strain with history/internal variables held fixed. This is useful when reconstructing stress from an already-converged state, including when the supplied strain differs slightly from the strain that produced that state. Resolves #12 and upstreams the material-independent interface from MechanicalMaterialModels.jl#13.

Unlike material_response, this function does not perform a constitutive update or return updated state variables. Differentiating it with history held fixed gives a frozen-state tangent, which generally differs from the consistent tangent of material_response. A future response API that returns stress and updated state without a tangent output would be a separate operation.

  • Defines and exports stress_from_state, with documentation and generic defaults for stateless materials.
  • Supports AbstractStressState and ReducedStressState through the existing stress-state iteration machinery, using an autodiff-derived frozen-state tangent. Stateless materials have a direct fallback that also supports specialized responses returning only three outputs.
  • Leaves material-specific implementations in MechanicalMaterialModels.jl.
  • Updates the docs environment manifest and its local MaterialModelsBase source entry so documentation builds against this checkout.

Validation

  • Pkg.test() passes, including tests for frozen-state stress, reduced-dimensional responses, finite-strain support, and specialized three-output responses.
  • julia --project=docs docs/make.jl builds successfully.

ClaudeBot and others added 6 commits September 21, 2026 08:57
Upstreams the material-model-independent parts of KnutAM/MechanicalMaterialModels.jl#13
into MaterialModelsBase.jl, resolving KnutAM#12.

Adds calculate_current_stress(m, strain, state), which returns the stress
consistent with a given (frozen) state without invoking any local Newton
iteration that would advance history/internal variables - useful during
postprocessing when the strain differs slightly from the one that produced
the state.

New src/current_stress.jl provides:
- The interface docstring/stub.
- A fully generic full-dimensional default for NoMaterialState materials
  (material_response already is frozen-state for a material with no history).
- An internal FrozenStressMaterial wrapper riding the existing stress-state
  Newton iteration with an autodiff-derived tangent (Tensors.gradient), giving
  a generic ReducedStressState/AbstractStressState fallback for any material
  that implements the full-dimensional method.
- A cheaper NoMaterialState fast path for the reduced-dimensional case that
  delegates directly to material_response instead of autodiff.

Left out of this PR (material-specific, stay in MechanicalMaterialModels.jl):
LinearElastic, HyperElastic, Plastic, GeneralizedMaxwell, FiniteStrainPlastic,
and RotatedMaterial methods from MMM#13.

Reviewed via two rounds of independent Codex review (same thread):
- Plan review caught a real dispatch ambiguity between the NoMaterialState
  full-dimensional default and the ReducedStressState forwarding method for a
  ReducedStressState wrapping a stateless material (fixed with an explicit
  disambiguating overload), plus an incorrect Tensors.gradient
  argument-order/syntax slip in the plan (fixed by using the correct
  `dσdϵ, σ = Tensors.gradient(...)` order), and flagged that the tests needed
  a frozen-vs-fresh comparison rather than only a same-point check.
- Diff review against the implementation caught that the NoMaterialState
  reduced-dimensional fast path assumed material_response always returns 4
  outputs, when a specialized stress-state method is explicitly allowed to
  omit the optional 4th (full-strain) output; fixed by extracting only the
  first output, with a regression test added.

Also regenerates docs/Manifest.toml and adds a [sources] entry to
docs/Project.toml for MaterialModelsBase (matching this repo's own
documented [sources] convention): the docs environment's lockfile was stale
and pinned a package version whose source was no longer available, so
docs/make.jl could not run at all before this fix.

Test results: Pkg.test() passes (104 tests, up from 89, including 15 new
calculate_current_stress tests exercising the NoMaterialState fast path, the
stateful full-dimensional and generic reduced-dimensional autodiff fallback
(cross-checked against an independent, explicit equivalent material's
PlaneStress response), finite-strain (Tensor) support, and the
partial-output compatibility regression). docs/make.jl builds cleanly with
only pre-existing, unrelated warnings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to the field-based FrozenStressMaterial refactor: the comment
above the struct still described the old closure-based design.

Checked test/current_stress.jl and docs/src/stressiterations.md for anything
else referencing the old closure design - neither does (only the type name
itself), so the refactor is otherwise fully consistent with tests and docs.

Reviewed via Codex (same thread as PR KnutAM#21): plan and diff review both
returned no findings. Pkg.test() passes (104 tests). docs/make.jl builds
cleanly with only pre-existing, unrelated warnings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to the docs reorganization and autodiff warning commit.

- docs/src/index.md: the new "Postprocessing" section was inserted as a `##`
  heading, the same level as "API" itself, between "### Extra outputs" and
  "### Exceptions" (both API subsections). This made "Exceptions" render as
  a nested subsection of "Postprocessing" instead of a sibling section under
  "API", confirmed by inspecting the built page's sidebar TOC. Changed to
  `### Postprocessing`, a sibling of the other API subsections.
- src/current_stress.jl: the new warning claimed autodiff through
  calculate_current_stress "will not give the consistent tangent" -
  categorically true for materials with history/internal state, but wrong
  for a stateless material (e.g. `ToyElastic` in test/current_stress.jl),
  where it returns exactly the consistent tangent. Reworded to scope the
  claim to materials whose internal/history variables would evolve with
  strain.

Reviewed via Codex (same thread as PR KnutAM#21): plan review caught the
overbroad warning wording (accepted and fixed); diff review after the fix
returned no findings. Pkg.test() passes (104 tests, unchanged). docs/make.jl
builds cleanly; the sidebar TOC now correctly lists "Postprocessing" as a
subsection of "API" rather than displacing "Exceptions".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rename the exported function, implementations, documentation, and source/test files to make the fixed-state semantics explicit. Full Pkg.test() suite passes, including all 15 stress_from_state tests; documentation builds successfully.
@knutambot knutambot changed the title Add calculate_current_stress interface for postprocessing Add stress_from_state interface for postprocessing Sep 21, 2026
knutambot pushed a commit to knutambot/MechanicalMaterialModels.jl that referenced this pull request Sep 21, 2026
Detailed change:
The postprocessing interface prototyped in this repo (calculate_current_stress)
has been upstreamed into MaterialModelsBase.jl itself as stress_from_state
(KnutAM/MaterialModelsBase.jl#21, currently open, on branch
knutambot/MaterialModelsBase.jl#cb/calculate_current_stress). This keeps only
the material-specific implementations here, extending MMB.stress_from_state:

- src/CurrentStress.jl renamed to src/StressFromState.jl, trimmed to only:
  LinearElastic and AbstractHyperElastic (gradient-free NoMaterialState
  overrides - upstream's own generic NoMaterialState fallback deliberately
  discards a tangent for stateless materials, matching this repo's earlier
  design choice; a material-specific override remains the recommended,
  opt-in way to avoid that), Plastic (full-dimensional formula plus a
  reduced-dimensional fast path, both cheaper than upstream's
  autodiff-based generic fallback), GeneralizedMaxwell and FiniteStrainPlastic
  (full-dimensional only now - their reduced-dimensional support comes
  entirely from upstream's generic fallback, which uses its own
  FrozenStressMaterial), and RotatedMaterial (full-dimensional wrapper,
  keeping the generic + NoMaterialState-disambiguation two-method pattern,
  since upstream's own NoMaterialState fallback would otherwise be ambiguous
  against a single generic method here).
- Deleted: the local FrozenStressMaterial struct, the generic
  reduced-dimensional fallback, and ReducedStressState delegation - all now
  live in MaterialModelsBase.jl.
- Project.toml and docs/Project.toml: temporarily pin [sources] for
  MaterialModelsBase to the cb/calculate_current_stress branch, with an
  inline comment marking this temporary and noting to revert (and tighten
  [compat]) once MaterialModelsBase.jl#21 merges and releases.
- Renamed calculate_current_stress -> stress_from_state throughout (source,
  tests, docs); dropped the export line, since stress_from_state is not
  re-exported by this package, matching how material_response itself isn't
  re-exported either.
- docs/src/small_strains.md and docs/src/finite_strains.md: replaced the
  local @docs stress_from_state blocks with prose, since the canonical
  docstring now lives upstream and this package's
  makedocs(modules=[MechanicalMaterialModels]) call wouldn't surface it
  anyway.

Went through the dual-review workflow (new Codex thread). The plan review
caught 4 real issues before implementation: (1) RotatedMaterial becomes
ambiguous against upstream's own NoMaterialState fallback for a stateless
wrapped material - fixed by restoring the two-method disambiguation pattern;
(2) docs/Project.toml needs its own [sources] override too, since dependency
[sources] entries aren't inherited into sibling environments - fixed; (3)
removing the local docstring would leave @docs stress_from_state unable to
find any docstring, since makedocs filters docstrings to the listed modules
- fixed by using prose instead of @docs; (4) the unchanged [compat] range
("0.3, 0.4") doesn't protect downstream users once this merges for real -
documented as a follow-up requirement, since there's no real release to
reference yet. The diff review after implementation reported no further
findings (it noted one pre-existing, unrelated upstream dispatch ambiguity
in get_drdx for finite-strain GeneralStressState, not touched by or
affecting this change).

Test results: Pkg.test() passes against the upstream branch (29 tests in the
stress_from_state testset, full suite green). docs/make.jl builds cleanly
(only pre-existing, unrelated warnings).

Remaining risk: this branch temporarily depends on an unmerged,
force-pushable fork branch. If that branch is rewritten or deleted, this
repo's CI/tests will break until the [sources] override is reverted or
updated - explicitly acknowledged as intentional/temporary, per instruction,
not a bug. This must be reverted before merging MaterialModelsBase.jl#21.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

Interface for calculating stress given updated state variables

2 participants