Repository navigation
Stress histories in a units-aware model: reduce on the way in, read back in Pa (#788) - #789
Conversation
|
Adversarial review before the push, one pass over the diff with probes run in the worktree. Found and fixed in the pushed commit:
Recorded, not fixed: the strain-rate forcing stores keep |
…ork arrays, one dimensional read (#788) Every history store is a non-dimensional work array behind the units boundary and carries no units of its own. In a model with reference quantities the histories failed in four ways: the nodal commit and the SUPG carry copied through unit-aware .array views (np.copy raised); the particle flavours wrote the dimensional values evaluate returns straight into storage and ran away (1e148 after 20 steps); the integration-point trace cache keyed on an unhashable unit-carrying timestep; and nothing read back in pascals. - The timestep is reduced where every flavour receives it. - Anything written from evaluate is reduced on the way in. - Copies between stores go through .data with the component layout (EnhancedMeshVariable gains the layout delegate). - DFDt.carried(level) is the one way to read a history back: the constitutive model supplies the map from the stored value to the stress, the value times the model's unit of stress, so the read is in pascals when reference scales are set and unchanged when they are not. Test: the Maxwell shear box with reference quantities, all five stress_transport flavours, read through carried and held to the loading curve in Pa at the order-1 tolerance. Underworld development team with AI support from Claude Code Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kSkAq7oJ5J3XisuvLBovo
55e12bf to
4462b7d
Compare
…eparate dimensional read (#788) Adversarial review of the previous commit found the separate read (carried, decode_history, a reference-stress expression, a private map handed from the solver) reimplements what MeshVariable units already do, and found defects the test could not see. Now: - A solver builds its stress history with the stress's units (the flux it hands over at construction is a zero placeholder and cannot say so). .data stays non-dimensional; .array and evaluate read in Pa. One helper, _history_units, replaces the derivation pasted into four flavours, and Eulerian/EulerianSUPG stores take units too. - One rule for writing an evaluation into a store (_write_evaluated): a result that carries units is reduced, one that does not is already non-dimensional; the re-wraps that assumed an unlabelled result was dimensional are gone, and so are the units attached before reducing in the inflow, integration-point and forward writes. The Eulerian and Lagrangian_Swarm initialisations were writing dimensional values unreduced. - The BDF-2 step-ratio guard compared a dimensional dt_elastic with the non-dimensional history and silently fell back to BDF-1 whenever the time unit differed from the reference; both are compared non-dimensionally. - The mirror write in the component copies (wrong for a full tensor, a no-op for a symmetric one) is removed; one timestep reducer, built on _as_float. - Swarm advection wrote the dimensional velocity global_evaluate returns into its model-unit arithmetic, so in a units model the particles did not move (every swarm-carried quantity, not only stress); the reads are reduced. Test: every flavour, in a units model with the timestep in kyr (not the reference unit) and as the same problem in plain numbers, from a moving start, orders 1 and 2: the stores agree to 1e-6 and the stress reads back in Pa as the non-dimensional value times the stress scale. The previous test was blind to the timestep, the order-2 guard, the initial writes and the swarm motion. Underworld development team with AI support from Claude Code Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kSkAq7oJ5J3XisuvLBovo
Why this is red, and what it needsThe two CI failures are not this PR's. They are byte-identical across #785, #789, #795 and #800: Both tests were already fixed on
So this branch is stale, not broken — 58 commits behind The merge is not clean, and the conflicts are the same on all four
The fifth, at the top of Order mattersAll four touch Found in the backlog sweep (#819). No commits pushed to this branch. |
scripts/test.sh keeps this branch's broader `tests/test_110*py`. development narrowed it to `test_1100*py`, which matches neither test_1101_advdiff_swarm_rotating_gaussian.py nor the other test_110* files this branch adds — #721 recurring. scripts/check_test_coverage.py verifies the resolution. ddt.py has five hunks and four of them have a zero-line development side: they are this branch's own `applies_inflow_value`, `commits_flux_in_post_solve` and `inflow_value` setter (the #745/#783 inflow work), flagged only because the surrounding context moved. None of those three names exists on development. The fifth takes both sides. This branch hoists `update_exp_coefficients` / `_exp_alpha` / `_exp_phi` onto `_DDtBase` (#739, 2026-09-14), replacing three per-flavour copies that date from 2026-04-28 (b6b0e7a); development adds `_note_history_shift` in that same place. Keeping both duplicates nothing, because this branch's own change already deletes the three copies and development never touched them — verified on the merged tree: exactly one definition of each of the four. Underworld development team with AI support from Claude Code
This branch is the base of a four-PR stack (#785 -> #789 -> #795 -> #800) and was 71 commits behind development, which is why all four showed the same two CI failures: tests development had already renamed (test_1060_nitsche_freeslip's absolute 1e-4 bound and test_1070_free_surface_plume's strong-vs-penalty ratio). The refresh belongs here, at the root, so each PR's diff against its base stays its own work rather than growing development's history. Two conflicts, both this branch's own additions. scripts/test.sh keeps the broader `tests/test_110*py` glob -- development narrowed it to `test_1100*py`, which matches none of the other test_110* files here (#721 recurring); scripts/check_test_coverage.py verifies it. Four of the five ddt.py hunks have an empty development side, and the fifth takes both: this branch's base-class `update_exp_coefficients` / `_exp_alpha` / `_exp_phi` (#739, which replaced three per-flavour copies dating from b6b0e7a in April) and development's `_note_history_shift`. Verified on the merged tree: one definition of each. Underworld development team with AI support from Claude Code
…ugfix/stress-history-units
Stacked on #785. Makes the viscoelastic stress histories, and swarm advection, work in a model with reference quantities.
Design. A history's stores hold non-dimensional values in
.data, which is what the solver reads and what copies between stores go through. A solver builds its stress history with the stress's units, so.arrayandevaluateof the store read in Pa, as for any MeshVariable. What enters is reduced on the way in: the timestep where each flavour receives it, and anything written fromevaluate(one rule,_write_evaluated: a result that carries units is reduced, one that does not is already non-dimensional).What failed before, Maxwell shear box with reference quantities (1 km, 1e21 Pa s, 1 Myr):
Test
test_1064_stress_history_units: every flavour, in a units model with the timestep in kyr (not the reference unit) and as the same problem in plain numbers, from a moving start, at orders 1 and 2. The stores agree to 1e-6, and the stress reads back in Pa as the non-dimensional value times the stress scale.The stress-history, swarm and advection test files pass (324, plus one known fragile test that now passes); the style gate is clean.
History of this PR. The first version stamped the flux's units onto every store; the second made the stores unitless with a separate dimensional read (
carried). Adversarial review found the second reimplemented MeshVariable units and that its test was blind to the timestep, the order-2 guard, the initial writes and the swarm motion; this version replaces both.Fixes #788.
Underworld development team with AI support from Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_017kSkAq7oJ5J3XisuvLBovo