Skip to content

Load-balance, active-box windowing, block-structured AMR - #1628

Open
sbryngelson wants to merge 587 commits into
MFlowCode:masterfrom
sbryngelson:up/mega
Open

Load-balance, active-box windowing, block-structured AMR#1628
sbryngelson wants to merge 587 commits into
MFlowCode:masterfrom
sbryngelson:up/mega

Conversation

@sbryngelson

@sbryngelson sbryngelson commented Jul 3, 2026

Copy link
Copy Markdown
Member

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 new m_box module (byte-identical; covered by the existing suite).

  • Load-balance infrastructurem_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).
  • Active-box windowingm_active_box/active_box: restricts reconstruction/Riemann/RK windows to a light-cone-grown box around non-ambient flow; strict-subset golden-tested.
  • Hybrid reconstruction/flux sensorshybrid_weno and hybrid_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).
  • Block-structured AMRm_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-block pb/mv side-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_subcycle under IGR · stretched grids with Lagrangian/IB-regrid (uniform-spacing index conversions).

Validation evidence

  • Conservation: reflux-exact (~1e-15 defects) across single/multi-fluid, viscous, bubbles, chemistry, phase change, through subcycled + regridding advances.
  • Free-stream preservation: exact (0.0) with subcycling + regrid armed, including 3D, IGR, and Lagrangian configs.
  • Decomposition exactness: np=1 == np=2 element-exact with blocks spanning rank seams (fields byte-identical incl. chemistry species).
  • Methodology: every feature validated by AMR-vs-no-AMR reference comparison with a control experiment calibrating the expected error scale, plus mechanism evidence from run logs (regrid counts, box coordinates, ghost-point counts) — a golden that does not mechanically exercise its path is treated as no coverage. Liveness goldens for the hybrid sensors are deliberately sized so a silently dead sensor fails them (~5e-4 signal vs 5e-5 tolerance) — they caught a real dead-sensor bug on Cray GPU during CI hardening.
  • GPU: full test suite with post-process on 2×V100 — OpenACC 644/644 executed pass, OpenMP offload 643/644 (one slurm launch flake). Speed spot-check (800² 2D blast, 2 ranks): AMR + dynamic regrid costs +3% wall over no-AMR at these sizes; ACC ≈ 12% faster than OMP; acc/omp solutions bitwise identical.
  • CI: one fully green 85-lane matrix on record (all GitHub-hosted lanes: gnu/intel × debug/no-debug/reldebug × double/single/mixed, macos, and the NVHPC 23.11–26.3 compat matrix). Fixes landed during hardening were each reproduced locally in the exact failing configuration first (intel FP drift, single-precision tolerance classification, gfortran bounds-check OOB, OpenACC present-table mapping ×3).

Known issues (all non-gating or in progress)

  • Frontier/Cray, in progress: two device-mapping issues in the IB machinery under CCE (plain-IBM descriptor corruption on gpu-omp; a present-table crash in the AMR-IB swap on gpu-acc). Being fixed with direct Cray iteration; the CCE bench/case-opt lane failures share the same root.
  • NVHPC 24.1/24.3 compat lanes (informational, 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.
  • Accuracy postures documented rather than hidden: multi-fluid alpha-sum deviation bounded ~5.7e-3 at historical block faces during shock crossing (non-growing); viscous prolongation-ghost seam ~1e-6 np-dependence; IGR seam conservation is truncation-order (no reflux capture from the fused IGR kernels — exact-conservation capture is noted future work).

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_validator entries, runtime checker gates, and case.md/amr.md documentation.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/common/m_phase_change.fpp Outdated
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
Comment thread src/simulation/m_sfc_partition.fpp
Comment thread src/simulation/m_sfc_partition.fpp Outdated
Comment thread src/simulation/m_rank_timing.fpp
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.11706% with 954 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.98%. Comparing base (8dfe8c7) to head (4b784a4).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/simulation/m_amr_regrid.fpp 55.60% 167 Missing and 142 partials ⚠️
src/simulation/m_amr_registers.fpp 63.27% 81 Missing and 78 partials ⚠️
src/simulation/m_amr_restart.fpp 65.50% 45 Missing and 24 partials ⚠️
src/post_process/m_data_input.f90 62.04% 38 Missing and 14 partials ⚠️
src/simulation/m_load_balance.fpp 46.80% 42 Missing and 8 partials ⚠️
src/simulation/m_ibm.fpp 71.54% 19 Missing and 16 partials ⚠️
src/simulation/m_load_weight.fpp 21.05% 23 Missing and 7 partials ⚠️
src/simulation/m_sfc_partition.fpp 62.50% 23 Missing and 7 partials ⚠️
src/simulation/m_rhs.fpp 65.06% 24 Missing and 5 partials ⚠️
src/common/m_mpi_common.fpp 47.82% 13 Missing and 11 partials ⚠️
... and 20 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1628      +/-   ##
==========================================
+ Coverage   60.77%   61.98%   +1.21%     
==========================================
  Files          83       93      +10     
  Lines       20872    25637    +4765     
  Branches     3101     4206    +1105     
==========================================
+ Hits        12685    15892    +3207     
- Misses       6121     6993     +872     
- Partials     2066     2752     +686     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sbryngelson

Copy link
Copy Markdown
Member Author

Upstream latent gap found during the MHD+AMR investigation (independent of this PR): m_riemann_solver_hlld.fpp contains no GLM terms, so hyper_cleaning = T with riemann_solver = 4 (HLLD) is silently inert — psi never evolves and no cleaning occurs. The existing hyper_cleaning golden uses HLL, which does carry the GLM coupling, so CI never sees this. Worth either adding GLM terms to HLLD or a validator prohibit on the combination.

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).

@sbryngelson sbryngelson changed the title Experimental performance family (default-off): load-balance infrastructure, active-box windowing, block-structured AMR, hybrid WENO/Riemann sensors Load-balance, active-box windowing, block-structured AMR Jul 21, 2026
…ortran build break)

The s_amr_regrid phase split made old_np an intent(out) dummy of
s_amr_regrid_stash_migrate while two BLOCK-scope declarations (cnt(old_np),
getk(old_np)) use it as an array bound - F2018 bars intent(out) dummies from
restricted (specification) expressions. Local gfortran tolerated it; the CI GNU
lanes (coverage, ubuntu, macos, Phoenix cpu, convergence) all reject it at build.
Mirror the value into a routine-scope local (np_l) captured at the same point and
size the block arrays with that. Regrid goldens pass unchanged.
… same-level block intersection

The gather/scatter coupling scanned all ranks (s_amr_rank_coarse_range + box
intersection) per block per RK stage. The coarse decomposition is static and block
boxes change only at regrid, so cache rank-ascending per-block gather and scatter
lists (amr_ovl_gather/scatter + counts), rebuilt on the same dirty flag as the seam
pairs - flagged before the regrid rebuild so its own gathers consume fresh lists.
Message order and matching unchanged (lists preserve the ascending scan order).

s_amr_check_seam_topology additionally aborts when two SAME-level blocks intersect:
different levels legitimately nest, tiling emits disjoint tiles, and the L1 IB pass
merges overlapping boxes, but the child IB body-bbox expansion has no overlap-merge
pass - intersecting children would restrict and reflux the shared cells twice,
silently breaking conservation. Full AMR suite (57) + LoadBalance + diagnostics
goldens pass.
…king the full block volume"

This reverts commit 4557a27.
…abort on same-level block intersection"

This reverts commit af2d830.
…k only the overlap boxes, drop full-field host pulls"

This reverts commit 276fb37.
…stale-bounds corruption)

The seed-once guard from 2153da6 assumed the device copy of ab_int was dead weight
for non-active_box runs. Under AMR the fine advance swaps idwint to the fine-block
bounds every stage, and CCE OpenACC resolves the convert kernel's loop bounds through
the PRESENT device copy of this module variable - the stale COARSE bounds on the
swapped fine grid drove out-of-range device accesses and a deterministic spurious wave
at every fine-block edge. This is why every AMR golden (and only AMR goldens) failed
on Frontier CCE gpu-acc while CCE cpu/gpu-omp and NVHPC acc stayed green (they
evaluate bounds host-side), and why reverting the slab/gather/cache perf commits
never moved the failing numbers. Restore the unconditional per-call device update
(6 integers) and document the constraint.
…ck only the overlap boxes, drop full-field host pulls"

This reverts commit ab43047.
… abort on same-level block intersection"

This reverts commit 0c01a4f.
…sking the full block volume"

This reverts commit 61b71e4.
Maintainability review follow-up (comment-only, no behavior change): (1) Correct three comments that asserted falsehoods - amr_isect_lo/hi frame is level-dependent (L0 for level-1, parent-fine for level>=2, not a hard-coded 2x); the 'multi-level not yet landed / slots always 1' phrases (multi-level and multi-block ship in this PR); and the L0-reflux 'remaining piece' note (level>=2 blocks reflux to their PARENT via s_amr_reflux_to_parent, implemented). (2) Document the swap contract at the sw_* declarations and in common-pitfalls.md - grid-derived module state a kernel reads on the fine grid must be swapped or refreshed, device copy too (the ab_int regression class); flag amr_rvw as the next candidate; add an AMR note at s_compute_rhs. (3) Complete the TWIN lockstep convention on the q<->pb/mv axis (12 pairs), the coarse RK stage combination (s_tvd_rk <-> the two fine RK updaters), and the freg<->creg capture policy (the 'energy only when not viscous' rule now names all four sites).
The np=1 branches of s_amr_gather_coarse_patch and its pb/mv twin inlined a device kernel byte-identical to s_amr_gather_own_box_device / s_amr_gather_own_box_pbmv_device, which the np>1 path already calls. Replace the inline copies with the shared calls (-30 LOC), removing a drift surface. No behavior change - the surviving kernel is the one already exercised (verified: 21C71558/476AA3A4/1CBACEB5/BCBA6E74/DDD79C8B pass).
s_amr_igr_swap_sigma seeds the fine block's sigma Dirichlet data from the OWNER's LOCAL coarse jac, clamped to the owner's buffer bounds. Unlike q_cons that seed is not P2P-gathered, so a block whose footprint or ghost shell crosses a rank boundary reads clamped edge values instead of the neighbour rank's sigma - a silent wrong answer with zero coverage. Gate to num_procs = 1 (runtime-only, no case_validator mirror) until the sigma seed is distributed. IGR AMR goldens run ppn=1 and are unaffected (6C20B752/660FFBFE pass).
First user-facing example for block-structured AMR: a dense droplet in uniform flow, its interface tracked by a dynamically-regridded, subcycled 2:1 block while smooth regions stay coarse. Exercises the four required AMR settings (amr + initial block, amr_regrid_int > 0, amr_subcycle) plus amr_cluster_eff for the closed-interface case. Validated and smoke-run 150 steps / 15 regrids, clean (no cap, no NaN).
Group the refinement-ratio parameter with the amr_ family so it surfaces under ./mfc.sh params amr and cannot become a breaking rename after merge (reviewer's last fix-before-merge item). Pure mechanical rename of the namelist parameter and its Fortran variable across 8 source files, the param registry/validator/tests, and the AMR docs; the test trace label and golden field values are unchanged (no golden regeneration). Rebuilt all 3 targets; AMR/IGR goldens pass incl. DB9BF199 (the ref_ratio-4 case) and multi-level restart.
Privatize four symbols with no external caller (s_amr_swap_to_fine, s_amr_restore_coarse, s_amr_fill_fine_ghosts, amr_dt_fine) so the audited swap call-sites become a compiler guarantee; narrow m_start_up's bare 'use m_amr' to the five symbols it actually references. t_level stays public (it backs the externally-consumed amr_slots). Build + AMR goldens pass.
amr_block_beg/end note they are 0-based inclusive and required when amr = T; amr_tag_eps states the actual tagging criterion (max axial |rho(i+1)-rho(i-1)|/(2 rho_i)); add amr.md to the lint_docs freshness set (it passes clean).
75AD6885 (multi-level static block) had byte-identical case mods to 4AF96C49 (multi-level restart); restart_check runs the same straight-run golden compare before the restart roundtrip (test.py:547 then :578), so 4AF96C49 fully subsumes it. Removed the stanza + golden dir and folded its description into the surviving test.
Flip restart_check on the existing 3D static-block golden (476AA3A4): the restart reader validates the fine extent per axis, so a z-extent slip would pass every non-restart 3D golden. Reuses the straight-run golden (no new golden); the midpoint roundtrip passes, confirming 3D multi-axis AMR restart round-trips correctly.
Terse pass over the comments in the PR's new AMR/load-balance modules (m_amr, m_amr_regrid, m_amr_restart, m_amr_registers, m_active_box, m_load_balance, m_load_weight, m_sfc_partition, m_rank_timing, m_box): cut filler, redundant restatement, and obvious-code narration, and re-flow the mangled nest_children comments. Comment-only (~37% fewer words, net -124 lines) - every invariant, index/frame convention, compiler-quirk note, TWIN lockstep marker, and trap warning is preserved in substance. Build + 12 AMR/IGR/MHD/load-balance/active-box goldens bit-identical.
… path against it (gather-batching step 1)

s_amr_build_gather_plan computes, before the rebuild box loop, every level-1
box's contributor ranks and message sizes and every level>=2 box's parent
source and size, from the same replicated caches the per-box path reads.
Five always-on asserts in the per-box gathers verify the inline derivation
matches the plan box by box; exchange behavior is unchanged. Step 2's
chunked exchange may trust the plan only because these asserts prove it
reproduces today's message set. Subset 67/67 asserts-clean; two seeded
tripwires (level-1 size, parent size) each aborted at the first rebuild.

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
…th reviewers; amended to parent-position-split sends plus four bindings

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
…it per owned box (gather-batching step 2)

Both families through one chunked plan-then-execute (amr_regrid_gather_batching.md,
amended form): phase A pre-posts every owned box's recvs for the chunk from the plan
(level-1 contributor slices + split level>=2 parent patches, tag = slot, box-order
contiguous request runs); phase B issues the plan-driven sends, deferring a level>=2
send to the child's consume position when the parent shares the chunk (its store is
unbuilt until its own consume - the D1 defect both reviewers found, now also guarded
by an always-on parents-first ASSERT); phase C consumes boxes in order with one
WAITALL per owned box. The parent-field gathers take the child block explicitly
(cblk) instead of reading amr_cur, since phase B runs before the consume geometry.

Validated: AMR subset 67/67 goldens green; XA exchange report line-for-line
identical to the per-box path on the S0-style np=4 tripwire (F1 312 msgs /
468087984 words, F2 1448 / 1400815296, F4-F7 untouched).

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
The step-1 plan asserts were guarded on amr_rg_gather, which nothing sets since
the chunked rebuild landed - the one assert on the chunked path's live route
(parent pack size vs the plan-sized recv) was dead code. Guard on amr_gpl_valid
alone: it is false outside the rebuild box loop, so subcycle and per-step calls
never consult the plan, and a short-packed send (silent truncation on the
receiver) now aborts at the source. Found by MPI-expert review; validated by a
tripwire run with the assert armed (zero trips, XA report identical).

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
Step 2 validated (bit-identity at np=4 and np=8, on-node walls -1.9%/-0.8%);
pg:recv attributed to rebuild dataflow, closing further MPI work on that family;
ladder re-aimed at dead bytes (cov counter -> ring clipping vs T1), the AMReX
weak-scaling bar promoted to now, and the regrid-cadence operating point flagged.

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
The S0/matched benchmark cases carried their density blob as an analytic IC,
which is codegen'd into case.fpp for pre_process AND simulation - so every
switch between bench cases (or from any test-suite case) rewrote case.fpp and
forced a rebuild. hcid 306 reproduces the codegen output VERBATIM (same bare
literals, same parenthesization): pre_process output is bit-identical to the
analytic path (1.5 GB lustre_0.dat cmp), and case.fpp is now invariant across
bench-case geometries (verified np=4 vs np=8 arm shapes), so case switches no
longer rebuild. Also records the matched-tax step-2 rung in the ledger
(7.06x -> 6.81x, payoff 2.23x, measured on the slow node = conservative).

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
Deterministic accounting that partitions each gather family's patch words into
live vs provably-dead: the step-fill's interior core (the ghost-fill kernel
reads only floor(f/rr) +- 1, so region-shrunk-by-1 is never read), the level-1
rebuild's carry-forward-overwritten cells (shrunk by 1 for the minmod stencil,
conservative), and the level>=2 rebuild patch counted live-by-construction.
SUM-allreduced and printed once at finalize. Prices ring/coverage clipping
against T1 migration waves per the expert-audit re-aim; pre-registered rule:
dead > 50% on either family promotes clipping.

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
stepfill 71.2% dead / rb-L1 67.9% dead at np=8 - both clear the pre-registered
50% bar; next code increment is the step-fill ring clip.

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
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
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
s_amr_parent_fill_wave(lev): the per-step level>=2 parent gather - previously a
pooled ISEND + blocking MPI_RECV per box per stage on the majority of boxes - as
one aggregated message per (parent-owner, child-owner) pair per level, levels
ascending. Pair lists derive on all ranks from replicated metadata only; reuses
the I2a wave's scratch; zero new device kernels. s_amr_fine_stage_fill lost its
last caller and is deleted. Regrid chunked, subcycle, and init/static F2 paths
unchanged. Also fixes restart leaving amr_num_levels at 1 until the first regrid
(the per-level driver needs it truthful; the old per-box loop was immune).

Gates: [amr-xa] F2 payload words exact vs baseline, msgs 1646->524, F1 and
F4-F7 byte-identical; live identity headers + per-message length asserts on the
F2 wave; seeded offset-shift arm aborts at the header check; adversarial review
clean (10/10 invariants); local AMR goldens 75/75 incl. multi-level restart np=2
and ppn=4 dynamic regrid.

Claude-Session: https://claude.ai/code/session_01N8xV1fowU5LmyfxCivNLDH
The cross-rank branch of s_amr_fine_fine_halo (one blocking MPI_SENDRECV per pair through two shared seam buffers) becomes one aggregated message per (peer, direction) per call: both owners walk the same replicated pair list ascending, so per-peer offsets agree with no metadata exchange. Same-rank pairs keep the batched device kernel. The shared seam buffers and their tile-grow reconciliation are deleted. Gates: [amr-xa] F6 payload words exact vs baseline (380,849,184), msgs 2646->378; all other families byte-identical; debug identity headers + length asserts clean; seeded header-shift arm aborts; local AMR-75 goldens 75/75.
The last per-box rendezvous chains: the level-1 reflux-face exchange (s_amr_p2p_reflux_faces per box) becomes s_amr_reflux_faces_wave — receives post zero-copy into the freg register host mirrors, owner D2H + multicast ISENDs, one WAITALL, receivers push H2D — and the level>=2 split-ownership freg handoff becomes s_amr_freg_wave. s_amr_reflux_to_parent gains do_xchg so the subcycle path keeps its per-box exchange. Message count is unchanged by design (zero-copy into per-box register slots); the wave removes the O(boxes) rendezvous chain. s_amr_reg_reserve hoists ahead of both waves since the apply can reallocate the registers. Gates: [amr-xa] F5 payload words exact (659,423,232), msgs 6708 unchanged; all other families byte-identical; debug-only companion identity headers + length asserts clean; seeded blk-shift arm aborts at the companion check; local AMR-75 goldens 75/75.
@github-actions

Copy link
Copy Markdown

Lines of Code

File Lines Diff
src/simulation/m_amr.fpp 6079 +6079
src/simulation/m_amr_regrid.fpp 1280 +1280
src/simulation/m_amr_registers.fpp 803 +803
src/simulation/m_amr_restart.fpp 352 +352
src/post_process/m_data_input.f90 643 +235
src/simulation/m_ibm.fpp 1450 +199
src/simulation/m_sfc_partition.fpp 169 +169
src/simulation/m_load_balance.fpp 164 +164
src/simulation/m_phase_timing.fpp 155 +155
src/post_process/m_data_output.fpp 1336 +146
src/simulation/m_amr_xchg_audit.fpp 137 +137
src/simulation/m_riemann_state.fpp 922 -137
src/simulation/m_time_steppers.fpp 961 +133
src/simulation/m_load_weight.fpp 121 +121
src/simulation/m_active_box.fpp 118 +118
src/simulation/m_checker.fpp 242 +94
src/common/m_box.fpp 71 +71
src/simulation/m_start_up.fpp 1273 +53
src/simulation/m_global_parameters.fpp 777 +52
src/simulation/m_rhs.fpp 1562 -52
src/simulation/m_rank_timing.fpp 50 +50
src/simulation/m_data_output.fpp 1448 +46
src/common/m_mpi_common.fpp 1515 +41
src/simulation/m_acoustic_src.fpp 559 +35
src/common/m_phase_change.fpp 304 +27
src/common/include/2dHardcodedIC.fpp 453 +21
src/simulation/m_riemann_solvers.fpp 100 +20
src/simulation/m_bubbles_EL.fpp 1679 +17
src/simulation/m_riemann_solver_lf.fpp 672 +14
src/common/include/macros.fpp 141 +13
src/simulation/m_weno.fpp 1350 +10
src/simulation/m_hypoelastic.fpp 353 +6
src/common/m_constants.fpp 91 +5
src/common/m_derived_types.fpp 447 +4
src/simulation/m_igr.fpp 2339 +4
src/common/include/3dHardcodedIC.fpp 243 +3
src/common/m_boundary_common.fpp 451 +3
src/common/m_global_parameters_common.fpp 255 -3
src/simulation/m_riemann_solver_hll.fpp 543 -3
src/simulation/m_riemann_solver_hllc.fpp 1068 -3
src/simulation/m_riemann_solver_hlld.fpp 200 -3
src/simulation/m_surface_tension.fpp 243 +3
src/post_process/m_start_up.fpp 774 +2
src/simulation/m_cbc.fpp 1122 -2
src/post_process/m_global_parameters.fpp 386 +1
src/simulation/m_bubbles_EE.fpp 269 +1
src/simulation/m_thinc.fpp 313 +1
Directory Lines Diff
common 9946 +185
simulation 36302 +9916
post_process 3753 +384
total 54559 +10485

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants