Skip to content

fix: coordinate and fault-frame correctness, stage S1 (spec 005) - #392

Merged
lachlangrose merged 15 commits into
masterfrom
feat/005-coordinate-frame-correctness
Nov 4, 2026
Merged

lachlangrose merged 15 commits into
masterfrom
feat/005-coordinate-frame-correctness

Conversation

@lachlangrose

Copy link
Copy Markdown
Member

Summary

This pull request implements stage S1 of spec 005 (coordinate and fault-frame correctness). The spec is in specs/005-coordinate-frame-correctness/. All 17 S1 tasks are done. Stages S2 to S6 are not planned yet (OP1).

Modelling observations, reference geometry and public queries stay in world coordinates. Local assembly uses the computational frame. Each boundary converts points and directions one time only.

Changes

  • Rigid transforms (loop_common.geometry): new validate_rigid_rotation and RigidRotationError. BoundingBox.set_local_transform and StructuredGrid3DGeometry.rotation_xy reject scale, shear, reflection and non-finite matrices, and keep the prior state. New BoundingBox.local_enclosure.
  • Support resize: the origin and maximum setters stored a cell count as the node count, so the support lost one cell. They now enclose the requested bounds (FR-014).
  • Interpolator: new public world_to_local_points, local_to_world_points, world_to_local_vectors and local_to_world_vectors methods.
  • Reference constraints: orthogonal, equality and inequality references are sampled at world points, and the rows are installed in the target-local basis. Invalid rows are counted in builder.excluded_rows. The support uses the local enclosure of the world box, and the restored-point expansion works in world space.
  • Fault frame:
    • An explicit fault_center is a world point; the factory does not project it.
    • An inferred centre keeps its elevation.
    • The slip is made orthogonal to the normal, and a slip parallel to the normal raises ValueError.
    • One extent-direction row is added at the centre.
    • The requested fault_buffer and force_mesh_geometry are kept; the factory no longer replaces them with the default 0.2 buffer.
    • fault_ellipsoid uses the world centre.
    • The caller's normal array is not changed.
  • COMPAT.md: a new migration notice.

Golden change

packages/loop_common/tests/data/structured_support_reference.npz: 27 resize values change (after_origin and after_maximum nsteps and maximum). The old values did not enclose the requested bounds. All other keys keep their old values. The full record is in verification.md ("Golden review").

Test plan

  • ruff check LoopStructural packages: pass
  • pytest (root): 1206 passed, 5 skipped, in 867 s. Before S1: 755 passed, 5 skipped.
  • pytest packages/loop_common/tests packages/loop_interpolation/tests: 912 passed, 47 skipped, 2 xfailed
  • New analytic tests: test_rigid_transform_contract.py (42), test_reference_constraint_frames.py (312), test_fault_frame_analytic.py (55), test_fault_buffer_bounds.py (84). They take about 5 minutes.
  • Before S1 (commit ebc7c699), the new tests fail as expected, and the rollback tests pass. See verification.md.
  • Reviewer: decide where the R2/R5 matrix runs in CI (OP2). It is in the default pytest run now.

Notes

  • black --check reports 2 changed files that are not Black-clean: _fault_segment.py and _discrete_interpolator.py. Neither file was Black-clean before this change, and only the task lines were changed.
  • 7 minor review findings stay open, most of them weak test assertions. They are listed in specs/005-coordinate-frame-correctness/run-state.json.
  • builder.build() ignores the top-level rtol, atol and maxiter arguments and gives no warning (they must go in solver_kwargs). This is not changed here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XADRvJLjMM6vnWTMwVqi61

…p (wave 3)

T005: validate the local transform and add BoundingBox.local_enclosure.
T006: repair the support resize node count and validate rotation_xy.
Regenerate the structured support golden file (27 resize values).
T008: add the public world/local conversion methods.
T012: keep the requested buffer, the 3D inferred centre, the in-plane
slip and one extent row at the centre.
Correct two test setups (T003 dimensions, T011 slip row scale).
T009: sample add_inequality_feature at world nodes.
T010: sample orthogonal and equality references at world points, install
target-local rows, count excluded rows, use the local enclosure for the
support, and expand the support for restored points in world space.
Correct the T007 affine residual test: compute the exact field without
cancellation at large world coordinates. The tolerance is not changed.
… (wave 5)

T013: do not project an explicit fault centre, because it is a world
point (FR-010). Do not replace the requested fault buffer with the
default 0.2 buffer.
Correct the T011 test setup: give the SC-003 CG settings through
solver_kwargs. The builder ignored the top-level values.
T015: record the golden review. test__fault_builder.py encodes no S1
defect. Record the 27 changed values of the structured support golden
file.
T016: add the S1 migration notice to COMPAT.md.
…e (wave 7)

T017: fill verification.md with the pre-fix failures at ebc7c69, the post-fix results, the backend matrix, the rollback check and the S1 test time.
Copy the fault normal and slip so the array of the caller does not change (T012).
Use the world fault centre in FaultSegment.fault_ellipsoid with no second conversion (T013).
Add regression tests for both (T011 file).
Keep only the 27 FR-014 changes in the structured support golden file (T006).
Correct the FR ranges in the verification.md titles (T017).
Record the final checks and the open minor review findings in run-state.json.
Put the anisotropy reset (#394) and the ignored solver settings (#393) out of scope. Close OP2: the R2 and R5 matrix stays in the default pytest run.
The gradient amplifies solver noise by about 1/h, so it needs a looser
limit than the value. Report max |dgrad| in the failure message.
@lachlangrose lachlangrose mentioned this pull request Nov 4, 2026
2 tasks done
@lachlangrose
lachlangrose force-pushed the feat/005-coordinate-frame-correctness branch from d8f0b06 to 82ff968 Compare November 4, 2026 06:16
@lachlangrose
lachlangrose changed the base branch from master to chore/lint-baseline-python-checks November 4, 2026 06:16
Base automatically changed from chore/lint-baseline-python-checks to master November 4, 2026 07:16
…-frame-correctness

# Conflicts:
#	packages/loop_interpolation/tests/golden/test_golden.py
@lachlangrose
lachlangrose merged commit 03a6e58 into master Nov 4, 2026
46 checks passed
@lachlangrose
lachlangrose deleted the feat/005-coordinate-frame-correctness branch November 4, 2026 09:12
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