Load-balance, active-box windowing, block-structured AMR#1628
Load-balance, active-box windowing, block-structured AMR#1628sbryngelson wants to merge 407 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 |
…-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 Report❌ Patch coverage is 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. 🚀 New features to boost your workflow:
|
…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)
|
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). |
…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.
…f+1 (neutral at l0_slot_off=0)
…R fine loops (neutral scaffolding for coexist)
…nt-3 tiles->L0 coupling); note deferred double-alloc/free
…t double-free (Inc3)
…gated) + dev oracle harness
… + 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)
…mic/subcycle/multilevel still blocked)
…te for the L0 RHS + fine fill)
…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).
…on all ranks (exascale prep #1)
… O(1) computed decomposition (exascale prep #1)
…l0-amr; keep both example-skip additions
…nd n_glb/p_glb (non-short-circuit OOB aborted GNU-reldebug in 1D/2D)
…ss-check vs O(P) scan (exascale prep #3)
…rsion, cross-checked (exascale prep #3)
… bounded ovl storage sized to max overlap (exascale prep #3)
…lidate vs amr_block_owner (exascale prep #2)
…iles are not yet in the SFC cut; avoids a false abort on regrid-coexist)
…lance-on np=2 test (unification prep)
…s cartesian) (unification #1)
…wners in coexist (unification #2)
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.