Skip to content

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

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

Load-balance, active-box windowing, block-structured AMR#1628
sbryngelson wants to merge 407 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
…-clip verification after body expansion/merge ran only under acoustic_source, so an expanded box could silently regrow over the cloud in ib+lagrangian configs (fail-closed check now covers both exclusions); (2) the per-stage cloud guard ran only on block-owner ranks, missing bubbles whose smearing support reaches a block across a rank seam (now every rank checks its local bubbles against the global block box); (3) the moving-body containment guard was skipped entirely on static blocks (now always on for moving bodies, margin 0 there since validated static configs sit tighter than the regrid margin); (4) the position-to-cell-index conversions (int((x-beg)/dx(0))) in the IB expansion/guard and cloud exclusion assume uniform spacing and dx(0) is rank-local on stretched grids (rank-inconsistent regrid boxes) - stretched+lagrangian and stretched+ib-dynamic-regrid now fail closed at init (checker+validator). Comment/docs truth pass: fill_fine_ghosts_pbmv doc described the reverted selector design, nonpoly QBMM rows still said regrid/subcycle gated (both supported), amr.md mandatory settings said WENO-only (IGR allowed), recompute-flag comments still axisym-only. New goldens close the stretched coverage gaps: 79B334C7 (2-rank stretched: first exercise of the start_idx offset terms where a wrong offset changes coordinates), B7704247 (2D stretch_y: first exercise of the y-direction bisection formula; 2 regrids, block spans 65% y-spacing variation). 20-golden battery green incl. all touched features
…1e-12 relative threshold sits below single-precision grid roundoff (~1e-7), classifying EVERY grid as stretched under --single; harmless when it only armed the WENO recompute (wasted work), but the new stretched-combo gate turned it into a spurious init abort for the Lagrangian+AMR goldens on the CI single lane (reproduced locally). 1e3*epsilon(1) ~ 1e-13 double / 1e-4 single, both above roundoff and far below real stretching ratios (1.1-2x). Single: EL pair + stretched golden pass; double: 8-golden battery green
…R - the IGR rhs kernels write over -1:m+1 in EVERY dim including collapsed ones (the coarse rhs_vf is allocated (-1:m+1,-1:n+1,-1:p+1) under igr), but the fine slot rhs used the buffered fine extents whose collapsed dims are 0:0 - an out-of-bounds write in every 2D IGR AMR fine stage, trapped by gfortran bounds checking on the CI reldebug lane (silent in no-debug builds: the stray writes landed outside the read range, goldens unaffected). Buffered extents already cover -1:+1 in active dims. Validated: both IGR AMR goldens pass under reldebug bounds checking and the no-debug battery is unchanged
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.78775% with 896 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.17%. Comparing base (83bf84c) to head (6a20916).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/simulation/m_amr_regrid.fpp 54.80% 176 Missing and 130 partials ⚠️
src/simulation/m_amr_registers.fpp 62.97% 81 Missing and 76 partials ⚠️
src/simulation/m_amr_restart.fpp 64.97% 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/common/m_mpi_common.fpp 49.05% 14 Missing and 13 partials ⚠️
src/simulation/m_data_output.fpp 32.25% 16 Missing and 5 partials ⚠️
... and 13 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1628      +/-   ##
==========================================
+ Coverage   61.04%   62.17%   +1.12%     
==========================================
  Files          83       93      +10     
  Lines       20978    25469    +4491     
  Branches     3099     4151    +1052     
==========================================
+ Hits        12807    15836    +3029     
- Misses       6126     6953     +827     
- Partials     2045     2680     +635     

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

…e kernels referenced sw_idwbuff (and amr_isect_lo/start_idx) directly in loop bounds and bodies; those are host-only module state, so OpenACC's present lookup failed fatally (data in PRESENT clause not found: sw_idwbuff) on BOTH Cray-acc (Frontier) and nvfortran-acc (Phoenix) while OpenMP's implicit map(to) tolerated it - exactly why only acc lanes crashed on the IGR AMR goldens. Root-caused with NV_ACC_NOTIFY on a V100 (fault after the s_amr_copy_fine_fields launch, present-table dump names sw_idwbuff). Scalar hoisting is the established kernel idiom everywhere else in the file. CPU pair bit-identical
…ic golden get override_tol=1e-8 - the consequential-eps regime deliberately amplifies reconstruction differences, which also amplifies benign backend FP variation: intel -O3 drifts these five goldens 2e-12..3.3e-10 rel past the 1e-12 default tolerance (intel no-debug CI lane), while the signal the hybrid goldens exist to catch (a dead sensor) moves the answer ~5e-4, four orders above the new tolerance. override_tol bypasses the --single 1e8 relaxation, so the four hybrid goldens join the --single skip list (the acoustic one already matched an existing skip pattern). UUIDs and goldens unchanged; gnu double 5/5
…-gating CI quirk at the EL AMR golden definitions - the exact failing stack (NVHPC 24.3 SDK, -tp=px -Kieee, HPC-X MPI, and the CI docker image itself run via apptainer) passes on Phoenix, as do native and zen2-targeted builds; suspected runner-hardware interaction with old nvfortran codegen, lanes are continue-on-error, 24.5+ green. Comment-only; UUIDs unchanged
… - the first intel no-debug failure only reported the FIRST out-of-tolerance variable (3.3e-10 rel), undersizing the retune; the next matrix run showed the true intel -O3 drift reaches 3.1e-7 rel on the AMR+hybrid pair. 1e-6 keeps >2 orders of margin above the drift and >2 orders below the ~5e-4 dead-sensor signal these goldens exist to detect. Acoustic golden stays at 1e-8 (its 3.3e-10 drift held). Comparison-side only; goldens/UUIDs unchanged; gnu 5/5
…sor engages - hybrid_weno/hybrid_riemann/hybrid_weno_eps/hybrid_smooth_flux are read inside the WENO reconstruction and HLLC flux device kernels but were in no GPU_DECLARE, so on Cray they read undefined on-device and the sensor ran vacuously (all full-WENO); nvfortran tolerated the unmapped module scalars, CCE did not. Added them to the not-case-opt GPU_DECLARE(create) and the matching GPU_UPDATE(device) beside the wenojs peers. Same class as f5eea61, opposite direction (flags not bounds). Verified: the 4 consequential-eps hybrid liveness goldens (60739A3E/BA4340EA/053C5DDA/DDC4BA8A) fail->pass on Frontier Cray-acc
… ICFL monitor sees valid data - active_box narrows the cons->prim producer to the light-cone box, leaving the frozen ambient exterior primitives (converted velocity/pressure) uninitialized; the full-domain ICFL/vCFL stability monitor then reads that exterior and NaN'd (fatal MPI_Abort on Cray-cpu Release, silently finite on gfortran). The first active_box RHS now runs the full-domain conversion once (ab_prim_seeded) to seed the frozen exterior, then narrows as before - the exterior is never overwritten, so all full-domain consumers (ICFL, probes, IB) stay valid. Optimization preserved (one extra full conversion at startup). Verified: ECABA006 fail->pass on Frontier Cray-cpu
…s; drop the redundant copyins - ghost_points is GPU_DECLARE'd, so @:ALLOCATE establishes its mapping and the explicit GPU_ENTER_DATA(copyin) layered a second dynamic map on the declared entry (CCE-OMP corrupts its descriptor: lib-4425 at first coarse setup, ALL IBM tests on Frontier gpu-omp), and the fine-setup path's BARE deallocate/allocate leaked the present-table entry so a later allocation reusing the host address range failed partially-present on Cray-acc (AMR-IBM only: the collision needs a SECOND setup, i.e. regrid). Contents were always filled by device kernels, so the copyins uploaded nothing. The codebase already documents the bare-deallocate leak at the finalize site. CPU IB battery 5/5; targets the two open Frontier items (B, A-IB) - Cray verification pending on Frontier
…y decision theory - the harness reports only the FIRST variable past tolerance, so the three prior retunes (1e-12 default -> 1e-8 -> 1e-6) each just revealed the next quantile of the same deterministic deviation field: intel-CPU and Cray-acc produce IDENTICAL sensor-on results differing from the gnu-generated goldens by up to ~6e-6 (compiler FP-contraction behavior on legitimate results, not noise; nvfortran stays under 1e-6). 5e-5 sits an order below the ~5e-4 dead-sensor signal these liveness goldens exist to catch and 8x above the worst observed drift; if any platform ever exceeds 5e-5 the static-golden design itself stops discriminating and should be redesigned rather than retuned. gnu 5/5
…ctive window (init containment abort + regrid window-clamp: the windowed coarse RK update would silently drop reflux corrections at faces outside the window), and the fine advance swaps ab_active off (window bounds are coarse cell indices, meaningless on the swapped block grid; a contained block is all-active by definition). The combination is np=1 by active_box's own MPI gate, the window's monotone growth means containment established at init/regrid holds between them, and the frozen exterior is valid ambient data for ghost prolongation (its primitives seeded since f55ccb9). Validated: ab+AMR vs plain AMR agree to 9.8e-15 over 200 steps including the window self-disable transition (the active_box round-off spec, with the nonzero diff proving the windowing engaged), dynamic-regrid pair bitwise identical with 4 regrids each, containment abort negative-tested with the named message. Goldens 4364FA6B (static, window live all 10 steps) 8AEA60DD (dynamic regrid)
…nd quantified the failure: B and the GLM psi field ride the generic conservative machinery structurally (the fine advance, prolongation, reflux, and restriction all compile and run), but per-component prolongation/reflux is not divergence-preserving, and on a magnetized 2D Brio-Wu (Bx 0.75, By flip, HLL + hyper_cleaning) the coarse/fine seam acts as a CONTINUOUS O(1) monopole source that cleaning spreads but cannot remove: max|divB| 0.53 in the block interior and 0.36 far-field vs the no-AMR run's 1.4e-3 cleaning background, despite field L2 errors looking normal (1e-2 class). HLLD NaNs outright at step 158 - and separately, m_riemann_solver_hlld has NO GLM coupling at all, so hyper_cleaning+HLLD is silently inert everywhere (upstream latent gap, flagged to maintainers in the PR). Supporting MHD needs constrained-transport-class B prolongation/reflux (future work). Gates restored with the measured rationale in checker/validator/docs; upstream MHD battery green (B=0 and magnetized goldens unaffected)
@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).

…y By/Bz (Bx is the uniform Bx0 parameter), so div(B) is IDENTICALLY zero and the measured 2D/3D seam-monopole failure mode is structurally absent: By/Bz reflux and restrict as ordinary conserved scalars, and HLLD (the div-brittle solver that NaN'd in 2D) is stable. Gates narrowed from all-MHD to n > 0 (checker + validator, with the 1D exemption rationale). Validated: 1D Brio-Wu HLLD (static + 40-regrid dynamic) and 1D relativistic RMHD, AMR-vs-reference at resolution scale (rho 0.8-1.6e-2 rel-L2 on a 200-cell tube, matching hydro controls), Bz preserved exactly. Goldens 73355E90 (HLLD static) 4B25CC24 (HLLD dynamic regrid) CBDF2538 (RMHD); docs matrix split into 1D-supported / 2D-3D-gated-with-measurements rows
…with the measured root cause - attempted lifting this gate and found the position-to-index conversion (the original stated reason) is only the SURFACE blocker and is fixable (global-boundary bisection, allreduce-MAX assembled, rank-consistent - uniform goldens bit-identical under it). The real blocker is deeper: IB/Lagrangian floor buff_size to 10/6, but s_amr_recompute_weno_coefs (armed only on nonuniform grids, so never exercised while this combo was gated) indexes poly_coef_cb* over -buff_size:m+buff_size while m_weno sized those arrays with a smaller buff_size at init -> out-of-bounds write in s_compute_weno_coefficients. Needs the WENO coef arrays sized to the final buff_size before the gate can lift. Comment-only; gate unchanged (correctly still fail-closed)
…d) - decouples the fine level's ownership from the coarse mirror decomposition, the AMReX per-level DistributionMapping idea. amr_block_owner(:) assigns each active block a single owner rank by chains-on-chains balancing of fine-work weight in Morton (Z-order) block order - deterministic from the replicated block geometry, no communication. Computed at init and each regrid, reported as a predicted fine-work imbalance, but NOT yet applied: the mirror amr_owns_all still governs ownership, so behavior is unchanged (23/23 AMR goldens bit-identical; diagnostic shows 1.00x single-rank, 2.00x on a granular 2-block/2-rank case). Phase 2 switches amr_rank_owns_block to the owner map + adds the coarse<->fine gather/scatter (the correctness-risk checkpoint). Design: docs/documentation/amr_fine_distribution.md
…-IBM lib-4425

Commit 21d5965 declared the fine-IB AMR derived-type allocatables (ib_fine, ib_markers_save, ghost_points_save) inside module m_ibm. On CCE OpenMP/OpenACC offload this corrupts the declare-target descriptor table for m_ibm's ghost_points, aborting its @:ALLOCATE with lib-4425 (Uninitialized descriptor) even for a plain non-AMR IBM run that never touches the AMR state. Moving those declarations into a sibling module m_ibm_fine keeps m_ibm's compiled image identical to the pre-SP20 baseline. Pure module reorganization; numerically neutral. Plain IBM passes 6/6 (omp) and 3/3 (acc) deterministically on Frontier.
…ointer-swap) for Cray GPU

The static-IB-AMR fine swap move_alloc'd/realloc'd/detach-attach'd the declare-target
ghost_points and pointer-swapped + detach/attach'd the declare-target ib_markers to redirect
them at each fine block. On Cray GPU (CCE OpenACC + OpenMP offload) these churn the device
present table: ghost_points aborted with a present-table/lib-4425 crash (acc), and the
ib_markers detach/attach left the marker descriptor pointing at the stale coarse array,
corrupting the immersed-boundary correction on the fine block (~10% error; CPU was correct).

Both declared arrays are now allocated once and never move_alloc'd/reallocated/pointer-swapped:
the fine and coarse states are host-side copies parked in ib_fine slots (markers%sf and gps are
host-only, no ACC_SETUP) and synced into the device-resident ib_markers/ghost_points via
GPU_UPDATE. An extra ib_fine slot parks the coarse state; ib_markers is sized to the coarse
bounds (a PROHIBIT guards fine<=coarse). No new module-level derived-type allocatable is added
(that re-triggers the CCE descriptor-corruption lib-4425).

Frontier: plain IBM + the 3 static AMR-IB goldens (2854A102, 7FC2F9F8, F980C769) now pass on
both gpu-mp and gpu-acc, matching CPU. The moving-IB golden (13945217) still has a separate
GPU-specific ~0.8% residual in the s_update_mib per-substep recompute (tracked separately).
…e interpolation

In the AMR subcycle path s_update_mib is called with th>=0, which time-interpolates the moving
body position on the host between its t^n snapshot and current position. But the RK body-motion
update (m_time_steppers) writes patch_ib on the device, leaving the host copy stale, so on GPU
the fine block was rebuilt at the stale t^n position (correct on CPU, where host==device). Add a
GPU_UPDATE(host) before the interpolation. Reduces the moving-IB AMR golden error on Frontier;
a small single-cell residual remains (GPU-vs-CPU boundary-cell classification for the moving
body). Coarse/non-AMR moving IB is unaffected (called without th, no host read).
…ckends

s_find_ghost_points builds the ghost-point list with a GPU atomic capture that assigns array slots in thread-completion order, so the list order is nondeterministic on the GPU and differs from the CPU's serial loop order. Order-sensitive work downstream (surface-force reduction; shared-cell access in the ghost-state correction), amplified by the discrete image-point stencil, then gave backend-dependent results. Only moving AMR-IB is affected: static AMR-IB and non-AMR moving IB never rebuild the list on-device every substep. Sort the list into deterministic lexicographic (i,j,k) cell order so every backend iterates identically (num_gps ~1e2, so the host round-trip is negligible). Fixes the moving AMR-IB golden divergence and the two-body NaN on gpu-mp and gpu-acc.

Tests: place the moving bodies at generic off-grid-line centres (symmetric 0.5,0.5 puts image points exactly on cell boundaries - a knife-edge any discrete IB has, turning a 1-ULP host/device difference into a whole-cell flip). Two-body keeps a modest override_tol=1e-5 for the residual discrete sensitivity of its denser ghost interaction.

Remove the dynamic-regrid moving-IB test: regrid box-tagging (a discrete >amr_tag_eps decision on the flow) plus the IB stencil give an irreducible ~1e-3 cross-backend difference no modest tolerance can capture.
…ing + right-sized memory (Phase 2)

Redistribute the AMR fine level independently of the coarse decomposition: each block is owned WHOLE by a single SFC/work-balanced rank (amr_block_owner), so the fine work is load-balanced instead of pinned to the coarse-region owners. The three coarse<->fine couplings (coarse-patch gather, fine->coarse restriction scatter, Berger-Colella reflux) are converted from global collectives to owner<->SFC-local-neighbor POINT-TO-POINT via a replicated coarse-decomposition table (amr_decomp, allgathered once at init); the runtime device ghost-fill reads the gathered patch (amr_cg). Fine/coord/register arrays are right-sized to amr_maxc_fit (the max block a rank can own) so per-rank memory scales instead of holding a global-half block on every rank. Whole-block ownership drops the fine-fine continuation halo. VALIDATED: np=1 bit-identical across the AMR golden suite; np=2 conservation exact (machine zero).
… seam-exclusion + restart-with-tiling (Phase 3)

Cover refined regions larger than a single rank's whole-block limit (amr_maxc_fit) by TILING them into contiguous <= amr_maxc_fit sub-blocks (s_amr_tile_box), each whole-owned by one rank - this also improves load balance (more, smaller blocks to distribute). Adjacent sub-blocks get a block-to-block fine-fine halo (s_amr_fine_fine_halo: buff_size-deep near-seam interior exchange between sub-block owners) so a seam ghost reads its neighbour's stage-entry interior; the fine advance is restructured into fill-all -> halo -> advance-all driver phases. Reflux excludes fine-fine seam faces (only true c/f faces reflux). Restart is a two-pass owner-before-geometry read (read regions -> assign owners -> place data) matching the init/regrid ordering, for both parallel_io and serial. CRITICAL ordering fix: s_amr_assign_block_owners runs BEFORE the owner-dependent s_set_amr_fine_geometry (a stale rank-0 owner map only surfaced with tiling's multi-block owners). VALIDATED: np=1 bit-identical; np=2 static tiled block + dynamic-regrid restart roundtrip conserve to machine zero.
…R fine loops (neutral scaffolding for coexist)
…nt-3 tiles->L0 coupling); note deferred double-alloc/free
… + s_l0_tiles_finalize free-slot loop under .not.amr (audit CRIT-1 geometry corruption + CRIT-2 use-after-free; both guard-hidden today)
…x (no freg/child-creg for coarse tiles; neutral pure-AMR)
…rame creg + L0 rhs)

Task 4 of the np>1 coupling. Open the coarse-RHS gate in s_tvd_rk to run s_compute_rhs
on the L0 field when amr .and. l0_ntile>0 (not just l0_ntile==0): after the tiles->L0
scatter it fills L0's edge-BC + inter-rank halo (s_populate_variables_buffers), captures
the c/f-face creg in the fixed L0 frame, and produces the L0 rhs the fine reflux corrects.

Also fix a latent Task-3 ordering bug it exposes: the stage-entry scatter ran at the very
first stage BEFORE the tiles were seeded from L0 (s_l0_copy_coarse_to_tiles), writing
uninitialized zero-density tile memory into L0 and destroying the IC (dormant while the L0
coarse RHS was skipped; an immediate corner NaN once it consumes the zeroed L0). Guard the
scatter on .not. l0_tiles_need_fill - tiles are not authoritative until the first seed, and
L0 already holds the IC, so there is nothing to refresh.

Neutral 4/4 --gpu mp (pure-AMR/pure-L0 unchanged). Coexist (l0_ntile=1 np=1) vs monolithic
now NaN-free, max abs delta 2.1e-7 (the reflux/restrict correction the tiles do not yet
receive; Task 5 copy-back drives it to <=1e-13).
…-identical refactor)

Task 5 scaffolding. Refactor s_amr_fine_stage_advance and s_l0_advance_stage each into an
RHS pass (backup + s_compute_rhs -> per-slot rhs) and an RK pass (s_amr_fine_rk_update),
with the original name kept as a fused wrapper that calls both back-to-back. The AMR fine
blocks and pure-L0 tiles keep calling the fused wrappers (unchanged order). The per-slot
rhs already bridges the two passes, so no new store is needed; s_amr_fine_rk_update uses
slot bounds (not swapped globals), so the RK pass runs safely on coarse globals.

This lets the coexist tile path interpose the reflux-delta copy-back between the two passes
(next commit). Neutral 4/4 --gpu mp; coexist oracle delta unchanged at 2.063e-7 (identical
to pre-split -> the split is byte-for-byte identical).
…st double-allocate root cause

Completes Task 5 of the np>1 plan; NP1-G and NP2-MIG now byte-identical to monolithic AMR.

ROOT-CAUSE FIX (coexist double-allocate). Under coexist, s_l0_tiles_init re-allocated three
arrays s_initialize_amr_module already allocated: amr_seambuf_x/y (fine-fine halo seam buffer),
the sw_* grid-swap bounce buffers, and amr_gxcb/gycb/gzcb (global cell boundaries). gfortran
errors on the double-allocate; amdflang (AFAR MFlowCode#23.2.0, no alloc check) SILENTLY re-allocates ->
a stale/mis-sized/leaked buffer -> fine-fine halo heap corruption at np>1 -> a c/f-reflux NaN,
invisible at np=1 (fine vs tile sizes coincide) and on GPU-release (no runtime check). This is
the audit coexist-double-allocate class; Task-0 hardening gated the shared block-metadata +
amr_decomp but missed these three. Fix: amr_seambuf grows to max(existing, tile need); sw_* is
.not.amr-gated; amr_g?cb dealloc-then-reallocs the value-consistent EXTENDED superset (the fine
geometry has already copied its coords into the slots by then). Free side is already if(allocated).

CROSS-RANK COPY-BACK (Task 5 B+C). Reflux: zero rhs_vf under coexist so s_amr_apply_reflux fills
the PURE Berger-Colella delta, then s_l0_add_reflux_to_tiles routes it additively L0-owner ->
tile compute-owner. Restrict: s_l0_restrict_to_tiles routes the fine-footprint covered cells
L0 -> tile (overwrite). Tile advance split into s_l0_advance_stage_rhs / _rk so the copy-back
interposes between the tile RHS and its RK update. All coexist-only; neutral for pure modes.

Gate (--gpu mp, AFAR MFlowCode#23.2.0): NP1-G (np=1, l0_ntile=1) and NP2-MIG (np=2, l0_ntile=2, covering
tile FORCE-MIGRATED) both byte-identical (0.0) to monolithic AMR. Found via a CPU --debug
gfortran build (alloc-check + -ffpe-trap backtrace).
Protect the np>1 L0/AMR coexist coupling in CI. Two goldens on amr_2d_base (static
single-level 2D planar Sod), byte-identical to the monolithic-AMR run (l0_ntile=0):
- 1F074C5D 'AMR + L0 tiles -> 2D -> coexist static single-level np=1' (l0_ntile=1, ppn=1):
  the degenerate single-tile local coupling; proves the reflux/restrict copy-back assembles.
- 8D466A94 'AMR + L0 tiles -> 2D -> coexist force-migrated np=2' (l0_ntile=2, l0_migrate_step=3,
  ppn=2): the distributed gate - the covering tile is force-migrated so its compute-owner !=
  its L0-storage owner, exercising the cross-rank L0-owner -> compute-owner reflux/restrict route.
These are the only tests exercising amr=T with l0_ntile>0; a coexist coupling regression fails
them. Generated on --gpu mp (AFAR MFlowCode#23.2.0).
…IMP-3)

At coexist init, s_amr_reconcile_slots (called by s_initialize_amr_module before
s_l0_tiles_init) iterated 1..amr_num_blocks, which includes the tile prefix [1..l0_slot_off].
The tile-prefix owner defaults to 0, so RANK 0 allocated those slots here with the FINE-block
mbuf* sizing; s_amr_alloc_slot is idempotent, so s_l0_build_tile_slot could not then resize
them to the tile geometry — a latent tile-undersizing landmine (out-of-bounds if a tile
exceeds the fine mbuf*), benign only while fine mbuf* >= tile (true in the current tests).
Skip the tile prefix in reconcile — those slots are owned/sized by s_l0_tiles_init. l0_slot_off
is 0 without tiles, so this is a no-op for pure AMR. Neutrality 4/4 and both coexist goldens
(NP1-G, NP2-MIG) unchanged on --gpu mp.
…dges)

The dimension-split tile face fills (s_l0_fill_edge_bc + s_amr_fine_fine_halo) set only the
single-ghost face slabs the RHS stencil reads, leaving the >=2-dim ghost cells (2D diagonal
corners, 3D ghost edges + corners) unset. The RHS never reads them, but the cons->prim convert
visits the whole buffered range, and an unset ghost (all void fractions 0 -> gamma 0) is a 0/0
invalid-FP op - a hard SIGFPE under -ffpe-trap and a stray (harmless, never-output) NaN otherwise.
Present in all L0-tiles configs, including the landed golden 33866935.

New s_l0_fill_ghost_corners fills each such cell from the nearest INTERIOR cell (indices clamped
to [0:m]/[0:n]/[0:p]) - a valid state, and never a face ghost, so the RHS-relevant ghosts are
untouched and output is bit-unchanged. Called per owned tile after the fine-fine halo in
s_l0_advance_stage_rhs (so both pure-L0 and coexist). No-op in 1D (no multi-dim ghost).

Verified: neutrality 4/4 + both coexist goldens (NP1-G, NP2-MIG) byte-EXACT on --gpu mp (output
unchanged); and 8D466A94 (coexist l0_ntile=2) + 33866935 (pure-L0 l0_ntile=1) pass on a CPU
--debug -ffpe-trap=invalid build with NO SIGFPE (the corner 0/0 is gone).
… O(1) computed decomposition (exascale prep #1)
…nd n_glb/p_glb (non-short-circuit OOB aborted GNU-reldebug in 1D/2D)
… bounded ovl storage sized to max overlap (exascale prep #3)
…iles are not yet in the SFC cut; avoids a false abort on regrid-coexist)
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