Insert essential boundary values in the rotated solve's field copy-back - #500
Conversation
Essential-BC DOFs are absent from the global vector, so the rotated path's per-field globalToLocal scatter left them at ZERO in the output fields wherever the Dirichlet datum was non-zero. The solve itself was always right -- the residual path inserts the values internally -- but every field-based diagnostic (projection, Integral, evaluate, renders) read a garbage boundary strip. Measured: far-field sigma_xy of 0.79 for a true 1.00, and a projected stress row off by 3x one fault length out. Invisible to every earlier rotated test because their Dirichlet walls were homogeneous: zero was accidentally the datum. Fix: petsc_dm_insert_boundary_values in cython/petsc_discretisation.pyx -- wrapping DMPlexInsertBoundaryValues, which petsc4py does not expose; the same insertion the consistent-boundary-flux paths already use (issues #407/#411) -- called per field after the scatter in _finalize_rotated_solution. The regression test drives an inhomogeneous lid with rotated free-slip sides and asserts the FIELD carries the wall values. The tell that found it: the divergence theorem, Integral(2 e_xy) against its own boundary term. The rotated boundary's prescribed datum and the sigma_nn reaction recovery were never affected (both live in the global vector). Fixes #497. Underworld development team with AI support from Claude Code Claude-Session: https://claude.ai/code/session_01WDKP73LD3dCFQSNgEXbbw9
|
Adversarial self-review, scope and hazards:
Underworld development team with AI support from Claude Code |
There was a problem hiding this comment.
Pull request overview
This PR fixes a rotated free-slip solve copy-back defect where inhomogeneous essential (Dirichlet) boundary values were missing from the per-field local vectors after scattering from the composite global solution, leading to incorrect field-based diagnostics near Dirichlet boundaries.
Changes:
- Adds a Cython shim
petsc_dm_insert_boundary_values()wrappingDMPlexInsertBoundaryValues()(not exposed by petsc4py) to insert essential BC values into local vectors. - Updates the rotated solve finalization to call this insertion after the global-to-local scatter for each field.
- Adds a regression test ensuring inhomogeneous Dirichlet wall values are preserved in the output field after a rotated solve.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/test_1018_rotated_freeslip.py | Adds a regression test that fails if rotated copy-back drops inhomogeneous Dirichlet values. |
| src/underworld3/utilities/rotated_bc.py | Inserts essential BC values into each field local vector after scatter in _finalize_rotated_solution. |
| src/underworld3/cython/petsc_discretisation.pyx | Introduces petsc_dm_insert_boundary_values() as a Python-level wrapper around DMPlexInsertBoundaryValues. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from underworld3.cython.petsc_discretisation import \ | ||
| petsc_dm_insert_boundary_values |
Adversarial review — PR #500 (rotated copy-back: insert essential boundary values)Verdict: DEFECTS — the diagnosis and the regression test are right, but the chosen What we verified
CRITICAL — segfault when the Dirichlet datum references a MeshVariableThe insertion runs on the per-field sub-DM from Repro (scratchpad/aux_probe.py): the regression-test setup with the lid datum changed The repo already owns the correct tool. minor
nit
Gate
Gate infrastructure note (not a PR finding): without the ignore, the gate dies |
… per sub-DM The adversarial review found the per-field insertion segfaults whenever an essential datum references another MeshVariable: the BC kernel dereferences the auxiliary vector, which lives on the solver's full DM, not on the createFieldDecomposition sub-DMs. The repo already owns the correct implementation — _scatter_global_to_fields runs the boundary FEM on the parent local vector and then splits per field, with the identical cache-invalidation tail — so _finalize_rotated_solution now delegates to it and the new cython shim is withdrawn. Verified: the MeshVariable-datum repro completes with wall error 8.9e-16 (was SIGSEGV), the regression test and the full rotated suite pass (19/19), and np2 is clean including ranks owning zero wall nodes. A TODO(BUG) at the call site records the #410 time=PETSC_MIN_REAL insertion defect shared with the native copy-back. Underworld development team with AI support from Claude Code
|
Response commit abae746 — the CRITICAL is fixed by switching sides, not by patching the shim:
The two review minors that are repo-infrastructure rather than this PR (test_1018 is in no CI batch; Underworld development team with AI support from Claude Code |
Fixes #497.
Essential-BC DOFs are absent from the global vector, so the rotated path's per-field
globalToLocalscatter left them at zero in the output fields wherever the Dirichlet datum was non-zero. The solve itself was always correct — the residual path inserts the values internally — but every field-based diagnostic (projection,uw.maths.Integral,uw.function.evaluate, renders) read a garbage boundary strip. Measured on the split-node fault study: far-field sigma_xy of 0.79 for a true 1.00, and a projected stress row off by 3x one fault length out. Every existing rotated test used homogeneous Dirichlet on the other walls, so zero was accidentally the right value — which is how this survived.Fix:
petsc_dm_insert_boundary_valuesincython/petsc_discretisation.pyx— wrappingDMPlexInsertBoundaryValues, which petsc4py does not expose; the same insertion the consistent-boundary-flux paths already use internally (cf. #407/#411) — called per field after the scatter in_finalize_rotated_solution.Not affected (both live in the global vector): the rotated boundary's own prescribed datum (
add_rotated_freeslip_bc(conds != 0, ...), the free-surface path), and the sigma_nn / dynamic-topography reaction recovery.Regression test:
test_rotated_solve_fields_carry_inhomogeneous_dirichlet_wallsintests/test_1018_rotated_freeslip.py— an inhomogeneous lid with rotated free-slip sides, asserting the FIELD carries the wall values; it fails without the fix. The change is a verbatim cherry-pick of 08f8603 fromfeature/fault-split-node, where the full rotated suite (19 tests) and the fault-contact suites run green with it.The tell that found it, for the record: the divergence theorem —
Integral(2 e_xy) dAagainst its own boundary term.Underworld development team with AI support from Claude Code