Skip to content

fix: point transformations, fault-frame validation and backend matrix, stage S6 (spec 005) - #403

Merged
lachlangrose merged 26 commits into
masterfrom
feat/005-s6-validation-and-matrix
Nov 6, 2026
Merged

lachlangrose merged 26 commits into
masterfrom
feat/005-s6-validation-and-matrix

Conversation

@lachlangrose

Copy link
Copy Markdown
Member

Summary

Stage S6 of spec 005 (coordinate and fault-frame correctness), the last stage: auxiliary point transformations, fault-frame validation on R2, the backend and capability matrix, and the golden review (FR-025 to FR-027, FR-029, FR-030; SC-004, SC-010, SC-014, SC-015, SC-018). The spec, plan and tasks are in specs/005-coordinate-frame-correctness/. All 20 S6 tasks (T089 to T108) are done. The branch adds the "Spec 005 complete" line to ROADMAP.md.

Changes

  • One EuclideanTransformation (FR-025, SC-010):
    • The class now lives in loop_common.math. LoopStructural.utils re-exports it, and both import paths keep working.
    • The loop_common copy could not be imported at all (from . import getLogger). That import is fixed.
    • inverse_transform failed on ordinary point clouds and an existing test asserted the bug. It is rewritten, and that test is replaced.
    • Four more defects of the class are fixed: 3D fit, the sign of the fitted angle for lines between -45 and 0 degrees, the reversed z in the 3D matrix, and fit silently needing scikit-learn (it now raises a clear ImportError). ROADMAP.md and COMPAT.md record the behaviour change for 3D users.
    • A one-dimensional point raises ValueError. Untransformed columns stay exactly unchanged. fit with fewer than 2 rows sets the angle to 0.
  • Fault residuals (FR-026, FR-023 follow-up): _value_residuals_fresh and _gradient_cosines_fresh evaluate the interpolator directly at the stored positions. Before, they also applied the faults, a second time, to positions that were already fault-restored. For a faulted feature the residual compared two frames (0.080 measured, true value 0.0004 to 0.0018). This reverses S5 decision 8 for these two private methods. For a feature with no faults and no regions, numbers do not change.
  • R2 validation (FR-026, FR-027, SC-004): new tests compare values, gradients, residuals and displacement against analytic references. Integration error, fault-plane samples and outside-support behaviour are assessed apart from smooth interpolation error. The zero-gradient protection is tested. Spec clarification C-019 replaces the R2 "test-side trishear evaluator" text with the library displacement paths, used on both frames.
  • Backend matrix (FR-030, SC-018): tests/fixtures/backend_matrix.py defines 15 cells, 11 mandatory and 4 optional. It reads the junit files of the gate runs. A skipped or missing mandatory case is a violation. An optional cell with a missing dependency is excluded and names the dependency. The two recording-stub cells (native-boundary, surfe-boundary) are mandatory and listed apart. They are not a native or Surfe result.
  • Smaller: the BOM that S5 added to _structured_grid_3d.py is removed. test_p0_surfe_nans.py now skips on surfepy, the module the Surfe wheel installs. Four importorskip("sklearn") lines are removed from tests/unit/utils/test_transformation.py, because scikit-learn is a root dependency and a mandatory cell must not skip.

Behaviour changes

  • 3D EuclideanTransformation.fit, the fitted-angle sign and the z direction change numbers for current 3D users. COMPAT.md has a migration notice.
  • fit without scikit-learn raises ImportError. It does not hide the missing dependency.
  • fit now logs through the loop_common logger. A pickle made after this change stores the loop_common.math._transformation path, so an older release cannot load it. Old pickles still load.
  • The residual methods of faulted features give correct numbers (see above).

Test plan

  • ruff check LoopStructural packages: pass
  • pytest packages/loop_common/tests: 418 passed
  • pytest packages/loop_interpolation/tests: 615 passed, 47 skipped, 2 xfailed
  • pytest (root): 2781 passed, 30 skipped (21 min 28 s). 30 skips: 14 native, 12 Surfe, 3 io modules and 1 for pyevtk.
  • python -m tests.fixtures.backend_matrix on the three junit files: exit 0. 9 non-stub mandatory cells passed and 0 mandatory cells skipped. Excluded optional cells: native-extension (loop_interpolation_core), surfe-extension (surfepy), export-pyevtk (pyevtk). display-viewer passed, because its dependencies are installed.
  • Rollback check against the S5 merge: see verification.md ("S6 rollback checks").
  • Wave reviews pass (10). The end review (Opus) found no blocker and no major problem.

Decisions for review

  • Error bounds above the planned cap: the measured errors of the faulted residual tests are above the plan cap of 1e-2. The bound is 2 times the measured maximum: value FDI 5.11e-3, value PLI 3.8e-2, cosine FDI 1.1e-2, cosine PLI 1.7e-2. Each bound still fails on the pre-fix value of 0.083 to 0.099. The maintainer accepted this.
  • One relaxed golden tolerance (SC-015): the gradient atol in packages/loop_interpolation/tests/golden/test_golden.py is 1e-4, not 1e-5. It comes from the S1 pull request (fix: coordinate and fault-frame correctness, stage S1 (spec 005) #392), has a code comment, and no S6 commit touches it. verification.md records it as accepted. The maintainer accepted this.

Notes

  • 24 minor review findings stay open (specs/005-coordinate-frame-correctness/run-state.json). The main ones: backend_matrix.main exits 0 for a plain failed cell (a pytest failure still fails the gate); a selector check in the matrix tests is weak; fit accepts 0 rows and gives a NaN translation; a BOM came back in tests/unit/utils/test_transformation.py; an older ROADMAP.md note still says the module was "deliberately kept local".
  • Two library defects outside spec 005 are noted in COMPAT.md as known issues: P2Interpolator.add_gradient_constraints raises ValueError for a P2 foliation with gradient rows, and outside the support the FDI gradient is exactly 0 while the PLI gradient is NaN.
  • The root test run grew from 937 s to 1289 s since S5. The cause is not investigated.
  • No black --check run for the whole repository.
  • The P2 fit accuracy (P2 value-only fit of an affine field is about 100 times less accurate than FDI and PLI (misses 1e-8 in every frame) #399) is outside spec 005.

@lachlangrose
lachlangrose merged commit 6ec0263 into master Nov 6, 2026
47 checks passed
@lachlangrose
lachlangrose deleted the feat/005-s6-validation-and-matrix branch November 6, 2026 06:17
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