Fix invalid symbolic atoms in DDt snapshot copies - #708
Conversation
Generic deepcopy reconstructs UWexpression atoms without their required internal state. Copy the symbolic history matrices and mutable timestep containers without reconstructing their symbolic atoms. Reproduced the invalid-expression failure on development 8709113. The focused clean branch passes all 25 in-memory snapshot tests and the two new checks on eight MPI ranks. This fixes expression validity, not the separately observed legacy Diffusion uninterrupted-continuation discrepancy.
…lation Populate symbolic history before first residual construction so cold and restored solvers embed identical Adams-Moulton terms. Previously zero placeholders disappeared from the initial operator, producing different continuation after restore despite exact field recovery. Add eight small Level 1 operator and replay regressions covering startup, orders 1-3 and variable timesteps. Validation: 33 serial tests and 10 tests per rank on eight MPI ranks pass; tight-tolerance replay errors remain at roundoff.
|
@lmoresi the previously disclosed numerical continuation mismatch is now fixed in d551b6f (developed and validated on the mantle branch first). Root cause: checkpoint restoration was exact, including temperature, nodal histories, timestep history and startup coefficients. Legacy Diffusion compiled its first residual before populating symbolic flux-history slots. Zero placeholder terms disappeared from that kernel; restore rebuilt it with populated slots, changing the operator. In the order-2 constant-diffusivity probe, the old cached flux retained only the 5/12 term instead of all AM terms summing to one. Fix: initialize uninitialized Symbolic flux history after assigning constitutive flux and before kernel compilation (five lines). No checkpoint format changes. This also corrects affected uninterrupted legacy Diffusion trajectories; composed AdvDiffusion, SUPG and SLCN are untouched.
Small Level 1 tests cover cold/partial/established history, orders 1-3, theta=0.5/1, changing timesteps, exact restored fields, and compiled-vs-live symbolic flux. Clean PR was independently rebuilt using existing dependencies; installed solvers.py and ddt.py match this branch. No A1 jobs or unrelated mantle commits are included. This is restart/operator consistency validation, not a claim of temporal accuracy for every legacy integration option. Please review the initialization ordering as well as the original symbolic atom-copy contract. |
|
Reviewed. We think this should go in — it fixes a crash and a real operator The validation is in-memory only, and the disk path drops the same state
Nothing warns at save time, and on restore the field is simply absent, so the
So it looks intact and is not. The magnitude is small enough to read as a solver Caveat on that number: we measured it on development without this branch Cheap mitigation worth taking either way: warn at save time when a state field The folded-zero-slot failure is a class, not a one-offThe root cause here — a placeholder slot holding zero disappears from the Worth naming in the changelog entry as the general hazard: an expression On the contract questionPreserving atom identity is the right pragmatic call and the only thing that The principled alternative is to rebuild the symbolic form from the solver Minor
with mesh.access(temperature):
temperature.data[:, 0] = temperature.coords[:, 0]The sibling Summary of asks
Underworld development team with AI support from Claude Code |
…ss Diffusion replay Warn when snapshot fields cannot be serialized and document live symbolic atom reference limitations. Add bounded fresh-process serial/MPI replay regression with a strict, narrowly recognized expected numerical failure: all fields and metadata restore exactly, but omitted symbolic history still changes continuation. Do not claim disk fidelity or reconstruct arbitrary symbolic history in this patch. Modernize array access and document the general folded-zero kernel hazard. Validation: 62 serial passes plus one known disk xfail; eight-rank disk workers reproduce the same 0.00350097 mismatch with exact field restoration.
|
@lmoresi addressed the four requests in 21a8451, developed first on the mantle branch and then applied alone to this PR.
The disk limitation is confirmed on this PR, including d551b6f. All restored fields and recorded history metadata agree exactly, but continuation differs by 0.00275634 after the first step and 0.00350097 over both steps, identically in serial and eight ranks. Symbolic matrices were skipped while history_initialised was restored true. Thus the in-memory fix does not close disk fidelity. The disk regression is a strict expected failure, narrowly restricted to numerical continuation mismatch after all ranks' exact restoration checks. Setup errors, incorrect restored data, missing outputs or missing warnings fail normally. A future accurate replay becomes strict XPASS, requiring this limitation marker to be removed. I have not implemented general symbolic reconstruction or unsafe expression deserialization; that remains separate work as you suggested.
The description now explicitly distinguishes fixed in-memory replay from uncorrected disk replay. No production benchmark jobs were needed. |
|
Review from the 2026-09 style/clutter audit. Findings against the Style Charter, scoped to lines this PR adds. All three are in the new worker 1. The test compares through np.savez(f"{phase}_{uw.mpi.rank}.npz", **values)§11: avoid 2. §11 names option parsing as the canonical case: use 3. Numbering. On the fix itself. The in-memory path looks right. The question this worker Underworld development team with AI support from Claude Code |
Replace npz sidecar comparisons with flushed checkpoint wrapper and PETSc bulk-vector checks. Assert exact restored field layouts and values, saved history metadata, and explicit skipped symbolic state before checking continuation. Use uw.Params for worker phases. Assign unused 1074 and 1079 test numbers to remove unrelated 1058 collisions. Serial and eight-rank checkpoint workers reproduce the documented 0.00350097 expected failure; 33 in-memory tests pass. No solver or checkpoint implementation changes.
|
@lmoresi implemented the style-review requests in 71c8a12 (developed first on mantle, dd34120).
The checkpoint files themselves confirm the disk state gap: restored fields/metadata match exactly, but symbolic history is skipped and continuation differs by 0.0035009713383 in both serial and eight-rank runs. The strict numerical xfail remains explicit; missing data, missing skip markers, bad restored values, or changed layouts are ordinary failures. No disk fidelity claim is added.
Test-only changes: no new solver build needed. The PR installed checkpoint and solver source still matches the checkout byte-for-byte. |
Review Follow-Up (10 September)
Addressed lmoresi's four requests in
21a84519: cross-process disk regression, warnings for skipped state, documented by-reference limitations, and.arrayaccess. The numerical fix below applies to in-memory replay. Fresh-process disk replay still differs because symbolic history is skipped. The new disk regression records this as a strict expected failure, not a passing restart test; setup and exact-restoration failures remain ordinary failures. General symbolic reconstruction is outside this PR. The changelog also describes the broader folded-zero-slot hazard.Problem
On current development (
87091138), saving/restoring a legacyDiffusionmodel with symbolic flux history and then solving raises
AttributeError:UWexpressionhas nois_finitebecause itssymproperty is invalid.The reproduction fails in 4.91 s on the clean upstream build.
Generic
copy.deepcopyreconstructs SymPy-derived UWexpression atoms withouttheir required wrapped state. These atoms are live references to the model's
expression/parameter machinery, not standalone values to reconstruct.
Fix
Give
DDtSymbolicStatea scoped deepcopy implementation: copy the mutablehistory list, timestep metadata and matrix containers, but preserve symbolic
atoms through matrix copies. No change to the integrator, global SymPy
copying behavior, or disk format. Derived from mantle commit
11348b3fandstrengthened with an atom-identity/container-isolation regression.
Validation
The clean PR was built in an isolated install using the existing Pixi
dependencies; its imported
ddt.pywas verified against this branch. Nomantle SUPG/geoid changes are included. Tests are small Level 1 regressions.
Original Limitation (Resolved by Follow-Up)
Update: commit
d551b6fdresolves the continuation mismatch below by initializing symbolic flux history before compiling the initial residual. Clean-branch validation: 33 serial tests (11.38 s), 10 tests per rank on eight MPI ranks (17.31 s), maximum tight-tolerance replay difference 5.55e-16. The text below records the original investigation; see the follow-up comment for the root cause and changed legacy-solver behavior.Original Finding
This fixes the exception, not full legacy Diffusion restart fidelity.
An additional experiment with
Diffusion(order=2, theta=1), P1 unit-squaremesh (
cellSize=0.3), initialT=x, diffusivity 0.05 anddt=0.01advancedthree steps, captured a snapshot, advanced for a reference, restored, and
advanced again. With this fix, the two temperatures differ by about
0.00289at maximum. Forced setup did not remove that discrepancy. Itsroot cause is not established and is outside this scoped atom-copy fix.
The passing solver regression deliberately asserts a finite solve after
restore, not bit-identical continuation.
@lmoresi please review whether preserving the live symbolic atoms at this
state boundary is the appropriate contract. The separate continuation
discrepancy above remains a follow-up, not a claimed fix in this PR.