Fault networks in parallel: keep the multigrid tail through the split, gauge the weak plane on owned probes - #669
Conversation
…eak-plane gauge answers only for owned probes Two defects on the finite-width network path, both silent. The split realisation ran every velocity solve on algebraic multigrid. build() adopted the base's geometric tail before splitting, and the split child did not inherit it (only Mesh.add_fault's wrapper does), so the adoption was lost and the rotated path fell back to GAMG without a word. build() now adopts the tail on the FINAL mesh, and split_faults hands a mesh-owned tail to its child the way add_fault does (the FAC zone is not inherited: a split needs no patch). net.solve() reports a fallback to algebraic multigrid so the substitution cannot decline quietly again. Serial, np=2 and np=4 all run the crossing-patches fixture on the geometric tail to the same slips (Main 0.17567 / Cross_1 0.00335 / Cross_2 0.00295). The weak-plane gauge reported 3x the true slip at np=2. Its probes sit in the band, which lives on one rank under gather-first placement; evaluate() answers for any point it is handed, extrapolating from the nearest local cell when the point is not in the local mesh (#641), so the band-less rank returned a far-field extrapolation and the max across ranks took it. The gauge now masks each probe pair by ownership. Every rank still evaluates every probe: the call is collective, and skipping it on a rank-local test is the conditional-collective hang (measured: peers spin at 100%). A whole-domain integral of v.v agrees with serial to eight digits at np=2 and np=4, so the solve was never wrong; the gauge was. The previous parallel port of the FAC patch smoother is not in this change: with it on, the np=2 weak-plane velocity solve stalled at a flat residual. Whole-level smoothing on the adopted tail is the parallel configuration for now. ptest_0863 gains the weak-plane case (np=2 and np=4 checked) and pins the velocity preconditioner in both realisations; test_0863 pins it in serial. Underworld development team with AI support from Claude Code
|
Adversarial review (we read the diff against the measurements, looking for what it does not cover).
None of these change the answer on the fixture. Item 1 is the one to watch when placement stops gathering. |
There was a problem hiding this comment.
🟢 Approval recommended
The changes are targeted, align with existing MG-tail inheritance patterns, and are reinforced by expanded serial/MPI tests and documentation.
Pull request overview
Fixes two parallel-only correctness regressions in the finite-width 3‑D fault-network workflow: (1) geometric multigrid “tail” metadata being dropped across network splitting (leading to silent GAMG fallback), and (2) weak-plane slip gauges over-reading in parallel due to non-owned probe evaluation/extrapolation on ranks that don’t own the band region.
Changes:
- Ensure the final network mesh (and split children) retain/adopt the base mesh’s geometric-MG hierarchy so velocity solves consistently run with the intended custom-FMG preconditioner.
- Make weak-plane slip gauges rank-local by masking probe pairs based on point ownership after collective evaluation, eliminating parallel over-read.
- Extend tests (serial + MPI) and update docs to codify the parallel behavior and constraints.
File summaries
| File | Description |
|---|---|
src/underworld3/meshing/fault_network.py |
Adopt MG hierarchy on the final built mesh; add GAMG fallback reporting; mask weak-plane gauge probes by rank ownership. |
src/underworld3/utilities/fault_split.py |
Propagate mesh-owned MG tail metadata through split_faults() children (matching Mesh.add_fault behavior). |
tests/test_0863_fault_network_3d_width.py |
Add assertion that split realisation uses custom-FMG (guards against silent GAMG fallback). |
tests/parallel/ptest_0863_fault_network_3d_width_parallel.py |
Add weak-plane MPI test and assert split solve uses custom-FMG; validate gauge behavior and a partition-independent integral. |
docs/advanced/fault-networks.md |
Document rank-local gauge semantics and clarify MG tail + gather-first placement implications for parallel runs. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| info = solve_with_fault(solver, **kwargs) | ||
| if info.get("velocity_pc") == "GAMG": | ||
| uw.pprint( | ||
| "[FaultNetwork.solve] the velocity block ran on ALGEBRAIC " | ||
| "multigrid: this mesh owns no geometric tail, or it was " | ||
| "not engaged. Production runs want the FMG tail — " | ||
| "build(width=...) adopts it from its own base " | ||
| "automatically.") |
Two silent defects on the finite-width fault-network path, found while measuring the 3-D network at np=2 and np=4 after #664.
The split ran on algebraic multigrid.
build()adopted the base mesh's geometric tail and then split, and the split child did not inherit the tail (onlyMesh.add_faultpasses it on). The rotated path fell back to GAMG without saying so. Nowbuild()adopts the tail on the final mesh,split_faultshands a mesh-owned tail to its child asadd_faultdoes, andnet.solve()reports any fallback to algebraic multigrid.The weak-plane gauge over-read by 3x in parallel. Its probe points sit in the band, and the band lives on one rank under gather-first placement.
evaluate()answers for every point it is handed, extrapolating from the nearest local cell for points outside the local mesh (#641), so the band-less rank reported a far-field extrapolation and the max across ranks took it. The gauge now masks each probe pair by ownership, after evaluating on every rank. Evaluating only the owned probes hangs the job: the call is collective, and a rank-local skip leaves the peers spinning. A whole-domain integral of v.v agreed with serial to eight digits throughout, so the solve was never wrong.Measured on the crossing-patches fixture (h = 0.08, w = 0.04, margin 0.5):
Parallel is a correctness mode for this path, not a speed-up: the placed region is one rank's, and the solve is not faster than serial. The docs say so now.
Not in this change: the earlier parallel port of the FAC patch smoother. With it on, the np=2 weak-plane velocity solve stalls at a flat residual; whole-level smoothing on the adopted tail is the parallel configuration.
Tests:
ptest_0863gains the weak-plane case and pins the velocity preconditioner in both realisations (np=2 and np=4 run green);test_0863pins it in serial (9 passed).Underworld development team with AI support from Claude Code