Load-balance, active-box windowing, block-structured AMR - #1628
Load-balance, active-box windowing, block-structured AMR#1628sbryngelson wants to merge 817 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces an opt-in (“default-off”) family of performance/diagnostic features (load-weight and SFC partition diagnostics, weighted init-time decomposition, rank timing), plus major simulation capabilities (active-box RHS windowing and block-structured AMR) and corresponding post-processing support and documentation/validation updates.
Changes:
- Adds new runtime parameters and toolchain metadata/validation hooks for the experimental performance/AMR feature family.
- Extends the simulation code with new modules for active-box restriction, load-weight diagnostics, SFC partition reporting, rank timing, and AMR integration points (including restart/output plumbing).
- Updates post_process to read/write AMR fine-block overlays and adds/updates golden metadata plus documentation/indexing.
Reviewed changes
Copilot reviewed 82 out of 94 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| toolchain/mfc/params/descriptions.py | Adds user-facing descriptions for new experimental/performance parameters. |
| toolchain/mfc/params/definitions.py | Registers new parameters (AMR, hybrid sensors, load-balance diagnostics) and target applicability. |
| toolchain/mfc/lint_docs.py | Treats new validator checks as non-physics doc checks. |
| tests/F980C769/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/ECABA006/golden-metadata.txt | Adds golden metadata for active-box test coverage. |
| tests/DD4CD8F3/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/CC4213FD/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/BD21A5C0/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/BCBA6E74/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/ACE05393/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/987D9025/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/852CCB81/golden-metadata.txt | Adds golden metadata for AMR-related golden tests. |
| tests/65C375B4/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/4DADE04B/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/454C565F/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/3A474BEE/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/2FC423D3/golden-metadata.txt | Adds golden metadata for a new/updated test. |
| tests/13945217/golden-metadata.txt | Adds golden metadata for moving-IB under AMR test coverage. |
| src/simulation/m_viscous.fpp | Clamps FD coefficient indexing to avoid ghost-region coefficient OOB in IB drag gradient evaluation. |
| src/simulation/m_time_steppers.fpp | Integrates active-box bounds into RK update loops and interleaves AMR fine-stage/subcycle operations. |
| src/simulation/m_start_up.fpp | Wires up new modules (rank timing, active-box, load-weight, SFC partition, AMR) into init/timestep/finalize and restart I/O. |
| src/simulation/m_sfc_partition.fpp | Adds analysis-only SFC tiling + weighted partition prediction and reporting. |
| src/simulation/m_rank_timing.fpp | Adds per-rank wall-time imbalance measurement helpers and reporting. |
| src/simulation/m_load_weight.fpp | Adds per-cell load-weight field construction and rank-level imbalance reporting. |
| src/simulation/m_hypoelastic.fpp | Refactors FD coefficient setup into a callable update routine (supporting AMR grid swaps). |
| src/simulation/m_global_parameters.fpp | Adds AMR working-state mirrors and slot selection helper plus defaults for new parameters. |
| src/simulation/m_data_output.fpp | Adds output/report hooks for load-weight, SFC partition, and rank-time diagnostics. |
| src/simulation/m_checker.fpp | Adds input validation/prohibits for active-box, hybrid sensors, load-balance, and AMR configurations. |
| src/simulation/m_active_box.fpp | Adds active-box initialization/growth and debug envelope checking. |
| src/simulation/m_acoustic_src.fpp | Adds AMR-aware handling of acoustic source support (bounding boxes and overlap abort). |
| src/post_process/m_start_up.fpp | Calls AMR fine-data reader and AMR overlay writer when amr is enabled. |
| src/post_process/m_global_parameters.fpp | Adds default-off amr flag for post_process overlay behavior. |
| src/post_process/m_data_output.fpp | Implements AMR fine-block overlay mesh/variables output (Silo/binary) and multimesh registration. |
| src/common/m_phase_change.fpp | Exposes per-cell Newton iteration count and threads it through relaxation to support load-weighting. |
| src/common/m_global_parameters_common.fpp | Adjusts start_idx lifecycle/allocation and makes load_weight_wrt visible to GPU macros. |
| src/common/m_derived_types.fpp | Introduces a simple t_box type used by new partitioning infrastructure. |
| src/common/m_box.fpp | Adds box/partition arithmetic helpers (equal/weighted splits, box-from-splits). |
| src/common/m_boundary_common.fpp | Skips BC buffer population during AMR fine advance to rely on coarse-driven ghost fill. |
| docs/module_categories.json | Registers new modules under documentation categories. |
| docs/documentation/readme.md | Adds AMR section link to the documentation index. |
| .typos.toml | Adds project-specific abbreviations to the spelling allowlist. |
| D = ((gs_min(lp) - 1.0_wp)*cvs(lp))/((gs_min(vp) - 1.0_wp)*cvs(vp)) | ||
|
|
||
| #ifdef MFC_SIMULATION | ||
| if (relax .and. load_weight_wrt) then |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #1628 +/- ##
==========================================
+ Coverage 61.67% 62.39% +0.72%
==========================================
Files 84 96 +12
Lines 21619 29068 +7449
Branches 3196 4778 +1582
==========================================
+ Hits 13334 18138 +4804
- Misses 6093 7753 +1660
- Partials 2192 3177 +985 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Upstream latent gap found during the MHD+AMR investigation (independent of this PR): Also for the record: MHD+AMR was attempted and re-gated on measured evidence rather than assumption — the coarse/fine seam is a continuous O(1) div(B) source that cleaning spreads but cannot remove (details in the amr.md support matrix row and commit ac203b1). |
|
Advection_AmrCore's IC replaced with S0's periodic blob field; per-rank work exactly flat (76.8M cells/rank/step) and matching MFC's S0 (77.1M/rank). MFC's 1.598x/2.63x doublings now have their target. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
… and amended Two reviewers (consumer lens + state/lifetime lens) both proved the shell claim exact (reach 1 on every branch, zero margin) and both caught the same spec defect: the pull_host gate cannot express lockstep-only, so the scope is now ALL runtime gathers with the subcycle proof recorded. The validation plan is rebuilt around their blindness findings: whole-patch poison (not core - shell holes), MPI_GET_COUNT transport asserts (not tautological recomputation), shadow word accounting (the cov counter is circular with the slab arithmetic), and a boundary-block golden (zero existing coverage). Bindings F1-F11 recorded. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
The attempted boundary-block golden aborts in the existing runtime checker (blocks must sit buff_size inside the domain), and mar <= buff_size for buff_size >= 2, so no valid patch crosses the boundary. The implementation asserts the premise instead of adding a test for an invalid configuration. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
Every runtime consumer of amr_cg (fill_cons/gsta/gstb) reads only floor(f/rr)+-1, so of the gathered patch only the shell - the patch minus the open core [region_lo+1, region_hi-1] - is live; [amr-cov] measured the difference at 71% of stepfill words at np=8. Runtime gathers (level-1 pull_host, level>=2 to_host=.false., subcycle included) now ship/copy <= 6 disjoint shell slabs through fused single-launch kernels; contributors whose box lies in the core send zero-word messages so the owner's request set is unchanged. Rebuild/init gathers, the pbmv twin, and the amr_cg coherence walls are untouched. Validation per docs/documentation/amr_stepfill_ring_clip.md: slab disjointness/ coverage asserts, MPI_GET_COUNT transport asserts on every clipped recv, consumer-frame asserts, mar<=buff_size premise assert, and an MFC_DEBUG whole-patch NaN poison before every clipped write. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
The five shell kernels took their slab bounds as per-launch mapped array dummies (8 arrays each). At the standing LIBOMPTARGET_MEMORY_MANAGER_THRESHOLD=0 default every map is a real hipMalloc/hipFree, and the same-day A/B (rcab-0822: HEAD 407.3 s vs clip 555.8 s at np=4) showed the churn slowing EVERY subsequent kernel launch - rhs +68%/call, rk 3x, restrict +83% - not just the clipped ones. The metadata now lives in a GPU_DECLARE'd 6x8 buffer staged by one 48-int GPU_UPDATE per clipped gather; the kernels read it as a present device array with no per-launch maps. Data path unchanged: same cells, same order, same wire layout. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
Exact-width slices mapped the same pool column with a different extent every call; reverting to the pre-clip full-column map shape removes the last structural mapping difference vs the unclipped path. (The same-day 5-step probe later showed the wall regression is a constant-factor kernel tax present from step one, so this is hygiene, not the fix - the hunt continues with the 3-minute probe as discriminator.) Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
Reverts a797074, bd85c79, dc6d412. The clip itself is proven correct (output bit-identity at np=4/np=8, zero transport-assert trips, wire words -64 to -72%, gather -33% at np=8), but adding its 7 target regions makes amdflang's whole-image device link deterministically regenerate UNTOUCHED kernels with 2.4-4.5x worse ISA (weno scratch 28->140 B, riemann VGPR 128->40 with AccVGPR 8->136, LDS 2048->2560 image-wide), slowing every compute kernel: rhs 22.1->41 ms/call, np=4 wall 407->553 s. Reproduced deterministically in a second tree; independent of -flto-partitions; same AGPR-blowup family as the weno-agpr reproducer. Parked, not abandoned: the re-landing trigger and full evidence live in amr_action_plan.md '2026-08-22 (final)' and the status header of amr_stepfill_ring_clip.md. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
Counts level-1 tags at each regrid that fall outside the pre-regrid level-1 coverage - a feature that evolved unrefined because amr_buf did not cover its drift over amr_regrid_int steps. The first regrid (hierarchy population from the seed block) is skipped; the totals print once at finalize alongside [amr-cov]. The case validator gains a non-fatal advisory when amr_buf < amr_regrid_int (a hard rule would wrongly reject the suite's golden int=5/buf=2-3 low-CFL cases; the runtime count is the per-run truth). Verified on S0 at int=2/buf=4: 2.3M steady-state tags, 0 escaped. This is the validity half of the regrid-cadence ledger item: moving the benchmark cadence toward production intervals now has its evidence instrument. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
spack/rpack allocated (largest-block words) x old_np columns per regrid - GBs at production block counts with nearly every column unused - and rq was O(old_np x num_procs), one of the endstate's forbidden scale terms. Both are now sized to the blocks actually sent/received via dense column maps from a pre-pass that applies the send loop's own destination criterion, and the exact request count. The message set, sizes, tags, and posting order are unchanged: gated on exact [amr-xa] F4 equality (39 msgs, 417682080 words both directions on the S0 np=4 probe), identical [amr-cad] counts, and the 75-case AMR golden subset (75/75). Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
…th (T1/I4b-a) mg:slot measured 57.9 s mean / 90.2 s max at np=8 (5.5% of wall): every 8-16 incremental replica-slot allocs re-staged the whole store through the host. One s_amr_prereserve_stash call per wave grows the store at most once, and s_amr_st_reserve now zeroes only the NEW columns (one full-store host pass saved per growth event). No new device code; store contents byte-identical. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
…ehind cadence Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
…ttach stash-alloc doc Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
XA_NH header words ([site, blk, bl, bh]) ride ahead of every F1/F2/F3 payload under MFC_DEBUG and are verified before unpacking; zero-width in production. Device kernels untouched (offset via argument slices). Gates: 75/75 AMR goldens (production); debug np=8 probe clean with headers live on all 858 F1 + 1646 F2 messages; a seeded consume-order bug aborted with the full expected-vs-got diagnostic. Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
s_amr_stage_fill_wave: F1+F3 per-stage gathers as one aggregated message per (peer, family) per RK stage - all recvs posted, device packs into pool slices via the existing kernels, one WAITALL, box-major consume through the single amr_cg. Replaces the per-box owner-WAITALL / contributor-flush / F3-blocking-SEND chain. Level>=2 keeps the per-box F2 path (I3); subcycle keeps its sites (I8). Gates: [amr-xa] F1 payload words exact vs baseline (msgs 858->381), F2/F4-F7 byte-identical; live identity headers on every wave transfer (F1 np=8, F3 np=2 with real traffic) + per-message length asserts; seeded offset-shift arm aborts at the header check; adversarial review (grow-helper data-loss bug fixed pre-gate). Outstanding at commit time: full-suite goldens job 383666 (baseline worktree). Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
…ing has ever set, whose dead brackets owned instrument rows that could never record (-56 LOC, all 70 AMR tests green)
…er-dispatch not per-byte, a quarter to a third of the gap -- two drafts withdrawn on review, the clustering knobs are inert, the cap-32 work saving belonged to a mesh nobody stepped
… gather consume is bit-identical and saves nothing; the census shows the pooled kernels are not slower, the per-block cost in the consume is non-kernel time; parked on task12/batched-gather
…pk/fill) around the per-block gather consume in both waves, same clock as [mpiwait]
…_OMP_PRESENT_ALLOCATABLE); m_amr.fpp opts in Without it amdflang maps every allocatable array of derived type a kernel touches on every launch, walking and re-attaching each component (~0.3 ms per launch for a 10-component array, linear in components; a per-element mapper generated for the type taxes every kernel in that compilation unit). m_amr opts in after an audit of its 95 kernels (bare module allocatables named: amr_cg, amr_cons_br, both allocated before first use; conditional ones are GPU_DECLARE'd). Not global: a kernel naming an unallocated allocatable variable or component aborts under present (m_variables_conversion's q_T_sf%sf). Step-loop wall -8% at cap 64, -18% at cap 32; restart files byte-identical; 70 AMR goldens; np=2 oracle. Ledger 82. Gated as 00a7c56/dede9e33 on origin/task13/host-profile (squashed here: the intermediate global form does not build).
…f allocatable derived-type arrays; per-file defaultmap(present:allocatable) opt-in for m_amr, -8%/-18% wall, bit-identical, gated
… in every form, null components do not; m_amr re-audited under the corrected rule (comments updated)
…locatable) (audited; the reflux/capture kernels carried 5.6k mapped args per rank-step)
…wrapped them into bare Fortran comment lines and a stray #)
…g at cap 64; the mapper walk was m_amr-specific and the launch-map ranking detects it but does not price it
…he ghost-fill and own-shell kernels, replacing eight per-launch copyin maps (same values, same order; bit-identical by construction)
…tered and confirmed on the ghost-fill launch (-29%/-40% gfill); wall deltas are MPI-wait movement, not claimed
…es and consume the F1 stage-fill wave for all owned blocks in one own-copy, one unpack and one ghost fill per wave (WIP: F1 wired, F2 per-block)
… consume (owner-side parent copy for co-located members, pooled unpack for the rest)
…pyin refreshes them each launch (device-mapped tables were read stale: m=0, wild address, abort)
…'s used receive extent, not the shared pool's doubled allocation
…o column 1 (rebase artefact)
…r's per-block slopes fall as pre-registered; lands as the default-off amr_batched_gather (ledger 81 amended)
…s, one node, one window -- MFC steady-state AMR excess 1.33 s/step vs AMReX 0.39 (3.4x); the 40-step deck sees a third of the steady step; per-rank rhs follows block count
…=0.45 moves one block per rank and equal-count ranks still differ 10% in rhs; block count is a proxy (knob parked)
…- rank rhs follows batch count because the batched advance groups only identical extents; padded grouping pre-registered (-47..-67% batches, ~-0.15 s/step)
…and Morton keys, one line per batch per stage to amr_batch_r<rank>.log under rank_time_wrt
…unit= returns a negative unit so the sign was no sentinel)
…n a batch when padding it to the leader wastes <= that fraction of its cells; bridge load clamps to the member's buffered region, RK update and flux capture use the member's own extents (ledger 88)
…xt (amr_slots is not visible in m_amr_registers)
…ther batch state (visible to m_amr_registers)
…teady marginal step -0.27/-0.38 s/step; identity gate is tolerance + conservation (batching was never bit-identical, ledger 73); amr_bat_pad lands default-off with the per-batch instrument
Lines of Code
|
…wall at the floor) and cap 32 (null) -- an operating-point choice, default stays off
…on the wall (spread closes, moved blocks fragment into single batches), knob stays parked on task20/lb-k2 with all gates green
Summary
An opt-in, default-off family of performance features and the measurement infrastructure they rest on. With all flags at their defaults the only touched production path is
s_mpi_decompose_computational_domain, refactored through the newm_boxmodule (byte-identical; covered by the existing suite).m_box(partition arithmetic),m_load_weight/load_weight_wrt(per-cell load-weight field + imbalance metric),m_sfc_partition/sfc_partition_wrt(Morton-SFC predicted-imbalance diagnostic),m_load_balance/load_balance(weighted static decomposition at init; AMR-fine-work-aware),m_rank_timing/rank_time_wrt(per-rank compute-time diagnostic).m_active_box/active_box: restricts reconstruction/Riemann/RK windows to a light-cone-grown box around non-ambient flow; strict-subset golden-tested.hybrid_wenoandhybrid_riemann(+hybrid_weno_eps,hybrid_smooth_flux): linear-optimal weights / central-or-Rusanov flux in smooth cells, full WENO/HLLC at flagged discontinuities (Jameson sensor, stencil-dilated, per-level under AMR).m_amr+m_amr_registers: two-level 2:1 refined block hierarchy; conservative restriction and conservative-linear prolongation with physics-specific closures; per-stage flux registers with Berger–Colella refluxing; Berger–Rigoutsos multi-block dynamic regrid; optional dt/2 subcycling; multi-rank (single-owner blocks assigned by Morton-SFC work balancing at each regrid, with migration; blocks may span rank seams via P2P coarse↔fine gather/scatter; same-level seam halo; distributed registers); restart (both IO modes, regridded-layout persistence); AMR-aware post-processing (fine blocks visualizable as Silo overlay domains); GPU-resident fine level on both OpenACC and OpenMP offload.Full algorithm and user documentation:
docs/documentation/amr.md(support matrix enforced at runtime by the checker — unsupported combinations abort with named messages, never silently).AMR physics support matrix (abridged; authoritative table in amr.md)
Supported and golden-tested: single- and multi-fluid (5-eq,
mpp_lim) · 6-eq with per-block pressure relaxation · viscous (refluxed) · phase change (relax) · chemistry incl. species diffusion · Euler–Euler bubbles (polytropic/non-polytropic, mono/polydisperse, QBMM incl. non-polytropic with per-blockpb/mvside-state; dynamic regrid + subcycle) · acoustic sources (coarse-grid support with regrid exclusion) · immersed boundaries (multi-body, static or prescribed-motion, incl. dynamic regrid with body-containment expansion and per-substage guards) · 2D axisymmetric (per-block WENO-coefficient recompute) · stretched grids (exact parent-bisection ghost coordinates + per-swap coefficient recompute) · hybrid WENO/Riemann sensors (per-level) · Lagrangian bubbles (cloud excluded from blocks; two-way coupling on the coarse grid; regrid clips around the moving cloud) ·active_box(blocks contained in the growing window; agrees with plain AMR to ~1e-14) · IGR (restriction-only coupling: fine sigma solve seeded/Dirichlet-bounded by the coarse solve; documented truncation-order seam, exact free-stream) · 1D MHD/RMHD (div(B)=0 by construction in 1D; HLL and HLLD, incl. relativistic).Gated with named aborts (documented rationale): surface tension (seam force imbalance is structural — three fixes attempted and diagnosed in amr.md) · 2D/3D MHD (attempted and measured: the c/f seam is a continuous O(1) div(B) source GLM cleaning cannot remove — needs constrained-transport-class B prolongation/reflux) · hyperelasticity · 3D cylindrical (global azimuthal filter) · force-driven IB (
moving_ibm=2) · STL bodies · Riemann-extrapolation BCs (bc=-4) ·amr_subcycleunder IGR · stretched grids with Lagrangian/IB-regrid (uniform-spacing index conversions).Validation evidence
Known issues (all non-gating or in progress)
continue-on-error): an intermittent post-detected NaN on the two Lagrangian+AMR goldens. Exhaustively unreproducible off GitHub's runners — the exact failing stack (NVHPC 24.3 SDK,-tp=px -Kieee, HPC-X MPI, and the CI docker image itself under apptainer) passes elsewhere, as do native/zen2 builds; 24.5+ green. Documented at the golden definitions.Review guide
The commit history is arc-ordered (active-box → load-weight → SFC → weighted decomposition → rank timing → hybrid → m_box → AMR rungs → physics envelope → CI/GPU hardening); reviewing by arc is much easier than by file. The AMR arc builds stepwise: static hierarchy → restriction/prolongation → fine advance → refluxing → regrid → subcycling → multi-rank → GPU → each physics rung with its own validation. Commit messages carry the validation evidence for their change (measured defects, golden UUIDs, repro details for CI fixes).
All parameters ship default-off with
case_validatorentries, runtime checker gates, andcase.md/amr.mddocumentation.