On a split (add_fault) mesh, write_timestep -> fresh Mesh(h5) -> read_timestep corrupts velocity DOFs at the cut: the coincident duplicated fault nodes are mixed on read-back, so part of the slip discontinuity is smeared into the first element ring.
Evidence (2-D S-fault rig, 4-strand network, rotated free-slip contact, coarse): raw in-cell fault-frame stress probed at ±0.006 from the main trace, same solve, A/B:
| probe |
|tau_nt| mean |
|tau_nn| mean |
| A — in-memory after solve |
0.12 |
0.86 |
| B — after checkpoint round-trip |
27.1 |
14.1 |
A is correct physics (shear traction released on the frictionless contact; normal deviatoric stress below the far-field value of 2). B is ~200x garbage at the slip/h scale (jump 0.4 over one 0.01 element), and decays over ~2 rings. Velocity probed at ±0.006 also shows a ~13% jump deficit after reload — consistent with cut-node values partially swapped between sides, most likely a coordinate-matched read-back that is ambiguous at coincident duplicates.
Consequences: any post-hoc stress/strain-rate recovery from split-mesh checkpoints is unusable near faults (we caught it rendering a stress field that showed a bright fault line the in-memory solve does not have). Far-field quantities and on-trace slip profiles sampled at band-scale offsets (±0.03) are only mildly biased.
Reproduction: ~/+Simulations/s_fault_rig/diagnostics/rt_probe.py (self-contained A/B; solve converges, prints the table above).
Likely fix territory: read_timestep DOF matching for meshes with duplicated (coincident) vertices — match by plex index/section, not by coordinate. Should land after #638 merges to avoid churning that PR.
Underworld development team with AI support from Claude Code
On a split (add_fault) mesh, write_timestep -> fresh Mesh(h5) -> read_timestep corrupts velocity DOFs at the cut: the coincident duplicated fault nodes are mixed on read-back, so part of the slip discontinuity is smeared into the first element ring.
Evidence (2-D S-fault rig, 4-strand network, rotated free-slip contact, coarse): raw in-cell fault-frame stress probed at ±0.006 from the main trace, same solve, A/B:
A is correct physics (shear traction released on the frictionless contact; normal deviatoric stress below the far-field value of 2). B is ~200x garbage at the slip/h scale (jump 0.4 over one 0.01 element), and decays over ~2 rings. Velocity probed at ±0.006 also shows a ~13% jump deficit after reload — consistent with cut-node values partially swapped between sides, most likely a coordinate-matched read-back that is ambiguous at coincident duplicates.
Consequences: any post-hoc stress/strain-rate recovery from split-mesh checkpoints is unusable near faults (we caught it rendering a stress field that showed a bright fault line the in-memory solve does not have). Far-field quantities and on-trace slip profiles sampled at band-scale offsets (±0.03) are only mildly biased.
Reproduction: ~/+Simulations/s_fault_rig/diagnostics/rt_probe.py (self-contained A/B; solve converges, prints the table above).
Likely fix territory: read_timestep DOF matching for meshes with duplicated (coincident) vertices — match by plex index/section, not by coordinate. Should land after #638 merges to avoid churning that PR.
Underworld development team with AI support from Claude Code