Uh oh!
There was an error while loading. Please reload this page.
Fix 3D boundary reaction flux recovery - #404
Conversation
Recover pointwise traction from 3D rotated free-slip reactions by assembling a lumped triangular boundary mass and dividing nodal reactions by that mass. Support P1 traces directly and P2 traces through four-triangle facet subdivision, with global coordinate-based assembly for partition independence and a surface-mass-weighted mean gauge. Add serial and MPI regressions using the Zhong et al. l=2 internal-load shell. The corrected surface and CMB topography coefficients reproduce the reference response and remain invariant across MPI partitions. Retain focused 2D traction and flux coverage.
lmoresi
commented
Jul 24, 2026
Adversarial review (public record) — strong core, but the P2 recovery has a structural defectThanks @gthyagi — the approach is right and most of it verifies beautifully. Full skeptic pass with live probes at np1/np2/np4 (PR branch merged onto current development, dedicated build): What HELD (verified live)
The blocker: P2 pointwise recovery is structurally wrong, and the Zhong test cannot see itOn a straight P2 triangle,
Asks before merge: (a) a consistent surface-mass solve on the P2 trace (M_boundary σ = R), or an explicit P1-only restriction with a clear raise; (b) a pointwise exact-flux box regression — P1 passes it today, P2 fails it today, and it's the test the harmonic fit can't substitute for; (c) docstring updates — Filed separately (pre-existing, exposed by the probes — not blockers here)
The core of this PR — P1 de-smear, global assembly, gauge — is exactly the missing 3D piece and worth landing promptly once the P2 story is honest. Underworld development team with AI support from Claude Code |
Replace the invalid four-subtriangle P2 lumping with the exact six-node triangular surface mass matrix and a sparse consistent solve. Add mass=auto so existing 2D and 3D P1 traces retain lumped recovery while 3D P2 selects the mathematically required consistent operator; reject explicit P2 lumping and unsupported 3D traces. Add pointwise constant-flux P1/P2 tetrahedral-box regressions in serial and MPI, including two- and four-rank partitions. Extend the Zhong l=2 validation to compare all nodes, vertices, and edge midpoints independently, removing the prior all-node cancellation blind spot. Document trace-order behavior, non-triangular limitations, analytic-normal partition guarantees, and the corrected 3D CBF behavior.
gthyagi
commented
Jul 24, 2026
@lmoresi Thank you for the adversarial review. I reproduced the P2 vertex/midpoint defect and pushed Changes
Pointwise box regressionUnit-cube conduction, exact outward Bottom flux
The P2 assertion covers every vertex and edge midpoint. A separate regression verifies that explicit P2 lumping raises. Zhong degree-2 validation
The regression now checks all-node, vertex-only, and midpoint-only coefficients independently, so the previous node-count cancellation cannot pass. Serial, np=2, and np=4 results agree within Focused local validation:
Issues #407 and #408 remain separate as requested: the Zhong rotated-constraint reaction is not affected by #407, and this correctness patch retains the existing global topology reconciliation tracked by #408. |
Allow the serial and MPI Zhong l=2 rotated free-slip diagnostics to accept an optional shell cell size while retaining 0.25 as the regression-test default. Extend the standalone MPI diagnostic output with the selected cell size so manual convergence results are self-describing. This supports serial/MPI comparisons at 1/4, 1/8, and 1/16 resolution without adding costly high-resolution cases to routine CI.
gthyagi
commented
Jul 24, 2026
@lmoresi Follow-up resolution sweep for the exact P2 surface-mass recovery in This is the no-self-gravity Zhong
Observations:
Validation after parameterization:
|
lmoresi
commented
Jul 24, 2026
Adversarial re-review — round 2 (public record): the P2 fix is verified. Approving.@gthyagi — the consistent trace-mass rework is exactly right. Full round-2 findings: The round-1 defect is genuinely fixed
One genuine subtlety found — filed as #414, not a blockerOn CURVED boundaries the P2 vertex values converge only slowly: the vertex basis has zero surface mean, so vertex reactions carry only the O(h) facet-geometry error, and the (correct) consistent solve faithfully reconstructs that error. Measured on a spherical conduction probe: vertex error 93%→55% under one refinement while midpoints go 2.8%→0.7% (superconvergent). Your Zhong vertex-only fit drifts away from the reference with refinement (0.395→0.371) while the midpoint fit converges onto 0.419 — the wide test tolerances absorb this, which is fine, but consumers of pointwise σ_nn on curved boundaries should read midpoints or fitted quantities. A docstring caveat is the ask (#414). Housekeeping from the round
Merging. Thanks for the fast, correct turnaround — the four-subtriangle → consistent-mass pivot was exactly the right call. Underworld development team with AI support from Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Delegate rotated free-slip traction recovery to the boundary-flux auto mass policy introduced by PR underworldcode#404. This selects the exact consistent surface-mass solve for 3D P2 traces while retaining lumped recovery where valid. Document the slower convergence of raw P2 vertex values on faceted curved boundaries and recommend fitted harmonic coefficients or midpoint samples for convergence studies.
…datum fixed (#421) Closes the #421 defect chain, localised by three successive np2 probes: 1. u_n was multi-valued at seam nodes: _surface_normal_velocity point-evaluated the P1 velocity at its OWN nodes, and on-vertex point location mis-locates at process seams (the documented ddt band-aid class). Fixed by direct nodal data reads (the projection has already ghost-synced) — also faster. 2. With that fixed, h_inf remained ~50% multi-valued at seams: the gathered ring holds a seam vertex ONCE PER ADJACENT RANK, and the Taubin filter's roll-stencil treats the copies as two distinct neighbouring nodes (a phantom zero-length segment), smoothing each against a DIFFERENT stencil; each rank then scattered back its own diverged copy. Fix: deduplicate the ring at construction — gather averages seam copies (identical to round-off), all ring operations (filter, tangential transport, arc-length weights, datum gauge) act on unique physical nodes, scatter expands the unique value back to every copy. Ring fields are single-valued across ranks by construction. Measured: prescribed-datum net flux at np2 1.142e-3 vs serial 1.140e-3 (was 5.75e-2, 50x worse than serial). Seam probe shows zero multi-valued ring quantities. The two datum tests are un-skipped and pass at np2 (8 passed with --with-mpi). Also: NotImplementedError guard for dim != 2 (previously a 3D run would proceed with meaningless ring ordering and a stub de-smear — silently wrong; 3D is follow-on work via PR #404's boundary mass), and the background_buoyancy docstring entry. Underworld development team with AI support from Claude Code
Plain-language plan for the post-#435 work: A (land 2D, teaching rebuild, stationarity run), B (nonlinear datum + rotated-path unification, joint session, #438/#403), C (3D, structural, builds on #404 — suggested for Thyagi), plus the deferred/tracked list. 3D is assembly work, not new mathematics: the integrator, datum, carrier and full-density h_inf are dimension-free; the 2D-only pieces and their 3D replacements are tabulated with the #421 seam-dedup lesson carried over. Underworld development team with AI support from Claude Code
…t fix, parallel datum, full-density (Boussinesq) formulation (#435) The free-surface toolkit taken from stiff-surface/small-deformation only to a validated 2D capability. Highlights (measurements in the PR thread): - Arc-length datum gauge + strong rotated material-boundary constraint: net surface flux 4.4e-2 -> 7.0e-5, rate error 6.4x better than the penalty. - Old-frame SL reach-back retired from the manager (#423): the serial T blow-up was an exponential per-cycle loop instability requiring per-step mesh motion; envelope 2.6% -> 17% deformation. Guard test on a no-free-surface reproducer. - Parallel datum fixed (#421): ring seam deduplication + direct nodal velocity reads; np2 flux matches serial to three digits; datum tests live at np2. - Full-density (Boussinesq) formulation: background_buoyancy="analytic" cancels the self-load in the recovered reaction (one sign was the defect; the CBF recovery is exact); topography relaxes at the Cathles rate and equilibria have closed streamlines. Two-reaction reference mode retained. - estimate_dt(advect_scale), deform-aware velocity CFL, 3D NotImplementedError guard, skill + roadmap docs (docs/developer/design/FREE_SURFACE_ROADMAP_2026-07.md). Nonlinear rheology runs with consistent_constraint="penalty" (strong datum through the SNES path is workstream B, #438). 3D is workstream C (#404-based). Underworld development team with AI support from Claude Code
…rface machinery + P1-projected sigma_nn recovery The FreeSurface manager now runs on a 3D spherical shell end to end (first smoke: two full solve/advance steps, physically sensible h_inf). The blanket dim!=2 guard is replaced by per-piece capability checks; the two genuinely 2D-only features (tangential transport, ring Taubin filter) are refused explicitly in 3D. - Surface mean/demean: reduction over OWNED-facet partial trace-mass weights (each facet counted exactly once globally, two scalar allreduces) - no gather, no ordering, dimension-general. The ordered ring survives only for the 2D-only features; its gather/dedup machinery generalises to 3D via lexicographic rounded-coordinate keys (deterministic order + exact same-node grouping; the 2D s-ordering and seam handling are unchanged). - Geometry helpers route through _radial (CYLINDRICAL2D or SPHERICAL): radial height/deform direction on shells, last-axis on boxes - already dimension-general otherwise. - sigma_nn on a 3D P2 trace: new boundary_flux mass="p1" - P1-PROJECTED recovery: fold each edge-midpoint load onto its edge vertices (exact interpolation transpose, load-conserving), de-smear with the sound P1 lumped triangle mass, read midpoints back as the P1 interpolant. Chosen over mass="consistent" because the P2 vertex-integral checkerboard (#404 hold) sits exactly at the vertices the P1 h_inf field consumes. The manager translates its "lumped" default to "p1" on 3D meshes; 2D maps "p1" to the sound lumped line mass. - The interior carrier reads the deform displacement by DIRECT nodal row map (built once; falls back to point evaluation only if the carrier nodes do not coincide with the mesh coordinate nodes) - removes the on-node point-evaluation exposure (#432 class) and a per-step global location. Tests: 2D battery green (test_1018 + 1070 + 1071 serial = 25; 1070 + 1066 np2 = 9). 3D shell smoke in ~/+Simulations/FreeSurface/spherical_fs/. Underworld development team with AI support from Claude Code
…e machinery, and the 2D compatibility-floor fix (#469) * feat(free-surface): FE trace-mass datum gauge from DMPlex facets (dimension-general) _ring_weights becomes the P1 lumped boundary mass accumulated per OWNED facet from the plex (edge length/2 in 2D; triangle area/3 in 3D - the same code is the 3D area-weighted gauge), on live coordinates. Seam weights are assembled by summing per-rank partial contributions (_ring_gather gains op="sum"; ghost facets excluded via the point SF so each facet counts exactly once globally). The quadrature test's invariant changes to the meaningful one: the gauge total equals the FE boundary measure of the deformed POLYGON (BdIntegral), not the ideal-circle arc length. Honest finding from the acceptance rerun: the deformed-ring compatibility floor (rel ~2e-3, 100% pressure-row) SURVIVES this fix at unchanged levels - the demean weighting was not the dominant term. Remaining suspect: the nodal-normal (analytic radial) vs facet-normal mismatch on the deformed polygon - the constraint fixes u.rhat at nodes while the discrete flux functional integrates u.n_facet, and the mismatch involves the free tangential velocity, so no nodal demean of the datum can zero it. Recorded in the acceptance README; formulation question for review. Tests: test_1070 serial (6+1) + np2 (7) + quadrature np4; surface metrics at strong level throughout. Underworld development team with AI support from Claude Code * fix(free-surface): FE-consistent directed flux strip + pressure-gauge quotient convergence — deformed-ring floor resolved The compatibility floor (strong-datum consistent solves stalling honestly at rel ~2e-3 on the deformed ring, residual 100% in the pressure rows) had TWO stacked causes beyond the demean weights, resolved here: 1. The datum's DIRECTED mean: the divergence rows enforce the flux through the deformed FACET normals while the constraint fixes u.n along the nodal (analytic) normal. The datum is now shifted by Phi/S with Phi = BdIntegral(u_n_target * (n_node . Gamma)) and S = BdIntegral(n_node . Gamma) — the same FE surface integral the residual uses (maintainer ruling: strip the mean volume-flux term, computed fully consistently), so the constrained field carries exactly zero discrete net flux. Strong-constraint path only; collective, rank-identical shift. 2. The outer residual is now measured in the pressure-gauge QUOTIENT space when the constant-pressure nullspace is active: the inner KSP projects the constant mode from every increment (the gauge of an enclosed domain), so the outer loop cannot reduce that component and must not measure it — on a deformed faceted boundary it is not exactly zero (free tangential DOFs carry flux through the node-vs-facet normal mismatch) and an unprojected norm floors against the constant offset, stalling the line search. Mirrors PETSc's own projected residual for singular systems. The sigma_nn reaction stash stays unprojected. Measured: power-law annulus FS acceptance now CONVERGES at every step (3, 3, then 1 Newton increment per warm-started step, no warnings) with surface metrics at strong-datum level (err 1.1e-2 ~ isoviscous 7.9e-3, penalty 0.49; net flux 7.4e-4). Tests: test_1018 18/18; test_1070+1071 serial; test_1070+1066 np2 (9). Underworld development team with AI support from Claude Code * feat(free-surface): 3D spherical shell support - dimension-general surface machinery + P1-projected sigma_nn recovery The FreeSurface manager now runs on a 3D spherical shell end to end (first smoke: two full solve/advance steps, physically sensible h_inf). The blanket dim!=2 guard is replaced by per-piece capability checks; the two genuinely 2D-only features (tangential transport, ring Taubin filter) are refused explicitly in 3D. - Surface mean/demean: reduction over OWNED-facet partial trace-mass weights (each facet counted exactly once globally, two scalar allreduces) - no gather, no ordering, dimension-general. The ordered ring survives only for the 2D-only features; its gather/dedup machinery generalises to 3D via lexicographic rounded-coordinate keys (deterministic order + exact same-node grouping; the 2D s-ordering and seam handling are unchanged). - Geometry helpers route through _radial (CYLINDRICAL2D or SPHERICAL): radial height/deform direction on shells, last-axis on boxes - already dimension-general otherwise. - sigma_nn on a 3D P2 trace: new boundary_flux mass="p1" - P1-PROJECTED recovery: fold each edge-midpoint load onto its edge vertices (exact interpolation transpose, load-conserving), de-smear with the sound P1 lumped triangle mass, read midpoints back as the P1 interpolant. Chosen over mass="consistent" because the P2 vertex-integral checkerboard (#404 hold) sits exactly at the vertices the P1 h_inf field consumes. The manager translates its "lumped" default to "p1" on 3D meshes; 2D maps "p1" to the sound lumped line mass. - The interior carrier reads the deform displacement by DIRECT nodal row map (built once; falls back to point evaluation only if the carrier nodes do not coincide with the mesh coordinate nodes) - removes the on-node point-evaluation exposure (#432 class) and a per-step global location. Tests: 2D battery green (test_1018 + 1070 + 1071 serial = 25; 1070 + 1066 np2 = 9). 3D shell smoke in ~/+Simulations/FreeSurface/spherical_fs/. Underworld development team with AI support from Claude Code * test+docs: 3D spherical FreeSurface capability test; changelog for the 3D free surface test_1072: end-to-end shell loop (finite mean-free h_inf under the trace-mass gauge, surface moves toward equilibrium, bounded) + explicit refusal of the 2D-only features. The quantitative benchmarking (analytic Y_lm shell rate, bias convergence, low-Ra spherical convection, 3D parallel) is deliberately delegated to the review pass - evidence and scripts in ~/+Simulations/FreeSurface/spherical_fs/. Underworld development team with AI support from Claude Code * review: response commit — empty-rank surface guard, pressure-gauge observability, trace-mass conservation assert, docstring currency F1: _surface_node_coords guards the surface stratum IS before getIndices() (the house NULL-handle-IS guard every other call site carries) — a rank owning no surface facets segfaulted the whole job at np>=2 under partition asymmetry. Verified: np=2 --with-mpi plume suite 7 passed. F2: the pressure-gauge quotient projection now surfaces what it removes — solver._rotated_pressure_gauge_residual holds the projected component's norm, and a converged solve warns loudly when that component dominates the converged residual (an incompatible wall-normal datum: net boundary flux an enclosed incompressible domain cannot absorb — previously a silent mass-conservation violation). F4: _surface_weights_local asserts the coordinate-key matching conserves the accumulated trace mass exactly — the 0.0 fallback could otherwise drop weights silently and corrupt the datum gauge. F5: docstrings — mass="p1" documented at both recovery entry points; arc-length wording updated to the FE trace-mass gauge it now is. Underworld development team with AI support from Claude Code
Summary
Root cause
The previous 3D branch in
_desmear()returned the raw nodal reaction after subtracting its arithmetic mean. A finite-element nodal reaction is an integrated force, not a pointwise traction. The recovery must solveM_boundary * sigma_nn = Ror, for lumped mass,
sigma_nn[i] = R[i] / m_boundary[i].Without the surface-mass division, recovered 3D topography was mesh-dependent and nearly zero. The arithmetic mean also did not represent the surface integral gauge.
Implementation
For 3D triangular boundaries, the recovery now:
Unsupported 3D mass choices and element traces fail explicitly. The existing 2D implementation is unchanged.
Validation
Zhong et al. degree-2 isoviscous internal-load response,
ri=0.55,rint=0.775,ro=1.0, P2/P1:Focused checks:
This PR intentionally excludes the higher-level spherical-shell geoid and response postprocessing work. It contains only the boundary-flux correction and focused tests.
Context: #248