Skip to content

fix: resize paths, non-mutating diagnostics and residual report, stage S5 (spec 005) - #402

Merged
lachlangrose merged 28 commits into
masterfrom
feat/005-s5-diagnostics-and-resize
Nov 5, 2026
Merged

lachlangrose merged 28 commits into
masterfrom
feat/005-s5-diagnostics-and-resize

Conversation

@lachlangrose

@lachlangrose lachlangrose commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Summary

Stage S5 of spec 005 (coordinate and fault-frame correctness): the remaining resize paths, cell-centre sampling, non-mutating diagnostics, and the residual and exclusion report (FR-014 remainder, FR-015, FR-023, FR-024; SC-009, SC-011). The spec, plan and tasks are in specs/005-coordinate-frame-correctness/. All 20 S5 tasks (T069 to T088) are done. S6 is not planned yet.

Changes

  • Resize (FR-014, SC-011):
    • The 3D nsteps and step_vector setters keep the origin and the extent. Before, nsteps changed the extent (11 to 21 nodes at step 1 gave an extent of 10.48), and step_vector treated a node count as a cell count.
    • The 2D nsteps_cells, n_cell_x and n_cell_y are derived from nsteps. The 2D maximum keeps its legacy value (FR-028).
    • The rectilinear grid setters raise NotImplementedError, because they left the node arrays unchanged.
    • set_nelements clamps nsteps to at least 2.
  • Cell centres (FR-015): the defect could not be reproduced. BoundingBox.cell_centres is correct for rotated boxes. _bounding_box.py is unchanged. A guard test records this (OP12).
  • Diagnostics (FR-023, FR-024, SC-009):
    • The misfit methods no longer change the stored arrays. Before, grad /= norm changed the stored gradient data in place (position and weight columns too), and grad[:, :3:6] selected one column.
    • They no longer rebuild a stale model. If the builder, a fault builder or the interpolator is stale, they warn once and return NaN.
    • New methods: evaluate_value_residuals, evaluate_gradient_cosines and GeologicalFeature.verification_report().
    • The old method names and result shapes stay.
    • ConstraintDiagnosticsReport gets three new defaulted fields (ResidualSummary and ExclusionRecord blocks). They show in to_dict and summary only when they are not empty.
  • Fix found by a regression test: GeologicalFeature.evaluate_gradient overwrote its result array in the fault branch and crashed with a shape mismatch for faulted features.
  • COMPAT.md has the S5 notices. ROADMAP.md records the misfit decision.

Behaviour changes

  • Models built with nelements get an exact support extent. Before, set_nelements shrank it. 78 of 611 keys of the 3D structured-support golden file changed. They were reviewed and regenerated under C-004. The 2D golden file and the loop_interpolation golden file are unchanged. No tolerance changed.
  • The gradient misfit changes meaning where it was wrong (the position columns were normalised). COMPAT.md has a notice.

Test plan

  • ruff check LoopStructural packages: pass
  • pytest packages/loop_common/tests packages/loop_interpolation/tests: 1021 passed, 47 skipped, 2 xfailed
  • pytest (root): 2218 passed, 4 skipped
  • New tests: test_resize_paths.py (40 cells; 24 fail without the fix), test_cell_centre_sampling.py, test_diagnostics_frames.py (149 cells), test_residual_exclusion_report.py. Pre-fix evidence is in verification.md.
  • 11 wave reviews pass. The end review (Opus) found one blocker (a fault builder counted as stale in every case) and one major problem. Both are fixed with regression tests, and the recheck passed.
  • Rollback check: see verification.md ("S5 rollback checks").
  • Reviewer: decide the open finding below.

Known limitation (open decision)

For a faulted feature, the new physical residual methods evaluate through the feature. That applies the faults a second time to stored positions that were already fault-restored. The two frames are compared, so the residual is wrong: 0.080 measured, where the true value is 0.0004 to 0.0018. The old methods had the same behaviour, so it is not a regression. The proposed fix is to evaluate the interpolator directly at the stored positions, with no fault step. This goes against plan decision 8, so it is not in this pull request. FR-023 and FR-024 hold only for features with no fault.

Notes

  • 11 minor review findings stay open. They are in specs/005-coordinate-frame-correctness/run-state.json. Two to look at: a BOM was added at line 1 of _structured_grid_3d.py, and _structured_grid_2d.py has format-only hunks.
  • set_nelements passes a cell count to the nsteps setter, as it did before (1000 elements on a unit cube give 729 cells).
  • PLI assembles no gradient rows (P1Interpolator.add_gradient_constraints is pass).
  • black --check was run on each file by the workers, not on the whole repository.
  • Tests that need pyevtk or loopstructuralvisualisation skip when those are missing.

Base automatically changed from feat/005-s4-world-locations to master November 5, 2026 22:35
@lachlangrose
lachlangrose force-pushed the feat/005-s5-diagnostics-and-resize branch from 67739bb to 181c3ee Compare November 5, 2026 22:41
@lachlangrose
lachlangrose merged commit e1c10ef into master Nov 5, 2026
38 checks passed
@lachlangrose
lachlangrose deleted the feat/005-s5-diagnostics-and-resize branch November 5, 2026 22:49
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.

1 participant