Add spatially supported body force + reacting mixing-layer examples#1657
Add spatially supported body force + reacting mixing-layer examples#1657ecisneros8 wants to merge 13 commits into
Conversation
Adds bf_spatial_support / spatial_bf%{amp,x_centroid,y_centroid,
conv_vel,sigma,freq(1:8),phase(1:8)}, an alternative body force that
seeds a downstream instability at a fixed streamwise location with a
ladder of forcing frequencies, rather than forcing the whole domain
uniformly like the existing k/w/p/g body force. Advects with the mean
flow along x (MFC's streamwise direction by convention for this
forcing) via a conv_vel*t term; the cross-stream (y) component does
not advect.
Adds two hardcoded-IC patches for loading externally-computed profiles that the existing extrusion patches (hcid=170/270/370) can't represent: - hcid=273: like hcid=270's 1D-to-2D extrusion, but also carries a nonzero mean velocity along the extruded axis (needed for a temporally-evolving mixing layer's mean shear, which hcid=270 always zeros). - hcid=274: a full (x, y) field with no extrusion axis at all, for cases like a spatially-evolving mixing layer where the profile varies along both directions and no single axis is homogeneous. examples/2D_reacting_mixing_layer (hcid=273) and examples/2D_spatial_reacting_mixing_layer (hcid=274) generate their initial conditions inline in case.py from a 1-D flamelet solve (Cantera + Pyrometheus), and the spatial example combines this with bf_spatial_support to seed a downstream instability on a reacting H2/air mixing layer. Both are registered as golden-file regression tests.
Batch template (toolchain/templates/isaac.mako) and module/environment registration (toolchain/modules, toolchain/bootstrap/modules.sh) for the University of Tennessee Knoxville's Isaac cluster, following the existing per-cluster pattern used by the other supported systems.
hcid=273/274 read an external IC file sized to the full (m_glb+1)*(n_glb+1) grid, but the Example suite caps m/n to ~25x25 after case.py writes that file, so the grid and IC file disagree (hcid=274 reads a wrong partial slice -> VCFL=Inf abort). Same file-IC-vs-grid-cap issue 2D_hardcoded_ic is skipped for. Coverage remains via the explicit Chemistry golden tests.
…xing-layer # Conflicts: # toolchain/pyproject.toml
Its bf_spatial_support Fourier-mode forcing amplifies roundoff past a portable single-golden tolerance across the compiler/arch lane matrix (the temporal case holds 1e-12 everywhere and keeps flamelet-IC + chemistry coverage). Also removes the now-orphaned tests/56F8C4BC golden.
🤖 4-Panel AI ReviewAutomated multi-agent review of this PR's net contribution ( Context: the earlier CI failures (example-smoke crash, missing/flaky goldens) and the 🚫 Blocker1. 🔴 Major2. 3. Spatial forcing injects momentum but adds no energy work term ( 4. 5. Zero regression coverage for the headline feature. The only new golden is the temporal case ( 6. Golden provenance is untraceable. 7. Isaac cluster: GPU template with no GPU module. 8. 🟡 Minor
⚪ Nit
✅ Verified clean (for confidence)
Panels: A Fortran-correctness · B silent-failures · C toolchain/params/tests · D examples/docs. Blocker 1 and Major 3 code-verified against HEAD |
- bodyForces gate now includes bf_spatial_support (m_start_up): the feature
was inert for its own example, which sets only bf_spatial_support -- the
forcing was never computed or added to the RHS (Blocker).
- Add the u*f energy work term to the spatial forcing (m_body_forces), matching
the bf_x/y/z convention so momentum injection is energy-consistent.
- Validate hcid=274 external IC files against the run grid (2dHardcodedIC):
reject a file whose origin/spacing/line-count disagree with the grid instead
of silently reading a wrong partial slice (the VCFL=Inf failure class).
- Guard bf_spatial_support to 2D in m_checker (it forces mom%beg/mom%beg+1).
- Allocate/deallocate spbf_source_{x,y} only when bf_spatial_support (m_rhs).
- Fix integer literals (2 -> 2._wp) and a misleading MPI-bcast comment.
- IC cache now keys on mode (--hot/cold) + physical params, not just line count, so a stale IC isn't silently reused across a mode/parameter change. - Refuse to write a non-finite flamelet IC (fail at generation, not as a downstream VCFL=Inf). - Declare jax and scipy in pyproject.toml (used by the flamelet IC solve; previously only transitively present). - Isaac template: drop the copied-from-Bridges2 GPU block (no i-gpu module exists) and the stray 'source ~/.bashrc'; load CPU modules. - Add spatial_bf%* parameter descriptions; fix case.md k_x[y,z] typo and the hcid=273 'mean velocity' wording (it's a velocity profile).
✅ Review fixes appliedAddressed the 4-panel review above in two commits (
Intentionally not changed:
Fixes authored and verified against HEAD |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #1657 +/- ##
==========================================
- Coverage 59.53% 59.48% -0.06%
==========================================
Files 83 83
Lines 21119 21263 +144
Branches 3132 3147 +15
==========================================
+ Hits 12574 12648 +74
- Misses 6439 6503 +64
- Partials 2106 2112 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…n test - m_checker used num_dims, which is not yet set when s_check_inputs runs, so the guard false-aborted every bf_spatial_support run (CASE FILE ERROR / errorcode 22). Use n/p (as the other checks do): require n>0 and p==0. - Re-add the '2D -> Chemistry -> Spatial Reacting Mixing Layer' golden test now that the feature actually runs (blocker + this fix). Held to override_tol=1e-7: the Fourier forcing plus the ~3e-9 cross-compiler/arch drift these reacting cases already show (GNU-13-Linux vs GCC-15-macOS) exceed the 1e-12 default. - Golden generated and round-trip verified locally (both mixing-layer tests pass).
Correction + spatial golden added (
|
…4/mac CI The macOS CI lane is arm64. On the temporal case a GCC-15 arm64 build diverges from the GNU-13-Linux golden by up to 6.65e-8 (rel) on a momentum component after 50 stiff chemistry steps, so the 1e-12 default is not portable there. Hold both reacting mixing-layer goldens to override_tol=1e-6 (measured drift 6.65e-8, ~15x margin; still catches real regressions, which shift these fields by far more). Both pass locally on arm64.
…e key) - hcid=274 grid check false-aborted every non-origin MPI rank: it compared the file's global origin to the rank-local x_cc(0). Replace with a decomposition- safe alignment test (x_cc(0) must be an integer number of cells from the file origin), which holds on every rank and still rejects a shifted/mismatched IC. The serial golden tests couldn't catch this (ppn=1). Spacing/line-count checks unchanged. - Spatial example never called write_cache_key, so its .cache_key.json was never written and the IC regenerated every run (cache fix was half-wired). Add the call, mirroring the temporal example. - gitignore .cache_key.json; document hcid=274's grid-match requirement in case.md; clarify spatial_bf%sigma description (exp(-sigma*r^2), larger=narrower).
🤖 4-Panel AI Review — Round 2 (post-fix)Re-ran the 4-panel review against HEAD after the fixes (scope 🔴 Found + fixed1. hcid=274 grid check false-aborted every non-origin MPI rank ( 2. Spatial example's cache was permanently inert ( 🟡 Also fixed
🟠 Flagged, not fixed here
✅ Re-verified cleanEnergy Verified: |
…e energy term case.md described the spatial_bf parameters but not the user-facing constraints: the forcing is 2D-only (rejected at startup otherwise), x is the streamwise axis (only that component advects via conv_vel*t), and the divergence-free source carries a u*f work term into the energy equation.
Description
Adds a spatially supported body force (Wei & Freund, JFM 2005), two reacting H2/air mixing-layer examples built on it, the two hardcoded-IC patches those examples need, and support for UTK's Isaac cluster.
1. Spatially supported body force (
bf_spatial_support)An alternative to MFC's existing
k/w/p/gbody force. Rather than forcing the whole domain uniformly, it seeds a downstream instability at a fixed streamwise location with a ladder of forcing frequencies, advecting with the mean flow alongxvia aconv_vel*tterm (the cross-streamycomponent does not advect). The source is constructed from a streamfunction, so it is divergence-free, and the correspondingu·fwork term is added to the energy equation, matching the existingbf_x/y/zconvention (momentum injection stays energy-consistent).2D only — the forcing writes
mom%beg/mom%beg+1;m_checkerrejects 1D/3D cases withbf_spatial_support.New parameters — registered in
toolchain/mfc/params/definitions.py, typed via the newspbf_parametersderived type (src/common/m_derived_types.fpp), broadcast inm_mpi_proxy:bf_spatial_supportspatial_bf%ampspatial_bf%x_centroidspatial_bf%y_centroidspatial_bf%conv_velconv_vel*t)spatial_bf%sigmaexp(-sigma*r^2)(larger = narrower)spatial_bf%freq(1:8)spatial_bf%phase(1:8)Implementation:
src/simulation/m_body_forces.fpp; source arraysspbf_source_{x,y}allocated inm_rhs.fpp(only when the feature is on).2. Hardcoded-IC patches for externally-computed profiles
Two new
hcidpatches (src/common/include/2dHardcodedIC.fpp) for ICs the existing extrusion patches (170/270/370) can't represent:hcid=273— likehcid=270's 1D→2D extrusion, but also carries a nonzero streamwise velocity profile along the extruded axis (whichhcid=270always zeros). Themom%begdata column is repurposed to carry it.hcid=274— a full(x, y)field with no extrusion axis: one data file per variable,(m_glb+1)*(n_glb+1)lines each in x-major order, all primitive variables read directly.hcid=274validates the file against the run grid (line count, grid alignment, and uniform cell spacing) and aborts with a clear message on a mismatch, rather than silently reading a wrong slice. The alignment check is MPI-decomposition-safe. Regenerate the IC whenever the grid changes.3. Examples
examples/2D_reacting_mixing_layer(hcid=273) — temporally-evolving reacting H2/air mixing layer.examples/2D_spatial_reacting_mixing_layer(hcid=274+bf_spatial_support) — spatially-evolving mixing layer; the body force seeds a downstream instability.Both generate their ICs inline in
case.pyfrom a 1-D flamelet solve (Cantera + Pyrometheus). By default they use the cheap cold (non-reacting, mollified) profile socase.pyloads fast underprecheck/run; pass--hotfor the full flamelet Newton/BDF solve;--scale <1shrinks the grid. The generatedIC/is cached and keyed on grid size +--hot/cold mode + the governing physical parameters, so a stale IC is never silently reused. A non-finite solve is rejected at generation time rather than surfacing later as a solver blow-up.Dependencies:
cantera,pyrometheus == 1.1.1, plusjaxandscipy(declared intoolchain/pyproject.toml).4. UTK Isaac cluster support
Batch template (
toolchain/templates/isaac.mako) + module/environment registration (toolchain/modules,toolchain/bootstrap/modules.sh), following the existing per-cluster pattern. CPU-only, matching the modules defined for the system.Type of change
Testing
./mfc.sh formatand./mfc.sh precheck(all 7 CI lint checks) — clean.pre_process+simulationbuild clean; both registered golden tests pass locally.master; the one conflict (pyrometheuspin) resolved to== 1.1.1, which satisfies both master'sget_creation_destruction_ratesneed and this PR's use ofpyrometheus.flamelets.Regression coverage
Both mixing-layer cases are registered Chemistry golden tests:
2D -> Chemistry -> Reacting Mixing LayerC4EB58A82D -> Chemistry -> Spatial Reacting Mixing Layer56F8C4BCbf_spatial_supportforcing kernel, chemistryBoth use
override_tol=1e-6. Rationale: these reacting mixing-layer cases drift across compiler/arch — a GCC-15 arm64 build (the macOS CI lane's architecture) diverges from the GNU-13-Linux golden by up to 6.65e-8 (rel) on a momentum component after 50 stiff chemistry steps — so the 1e-12 default is not portable. 1e-6 clears that with ~15× margin while still catching real regressions, which shift these fields by far more.Both examples are excluded from the auto-generated Example smoke suite. That suite caps
m/nto ~25×25 aftercase.pyhas written its external IC file, which desyncs the run grid from the file — the same file-IC-vs-grid-cap incompatibility that2D_hardcoded_icis already skipped for.Checklist
docs/documentation/case.md:hcid=273/274incl. the grid-match requirement, and the Body Forces section)See the developer guide for full coding standards.
GPU changes (
src/simulation/was modified)GPU_DECLARE/GPU_UPDATEdirectives are in place for thespbf_source_{x,y}arrays and the forcing scalars, but CPU/GPU parity forbf_spatial_support(including the new energy work term) has not been confirmed — flagging for reviewer attention. Likewise, the goldens run atppn=1, so the MPI-decomposed hcid=274 path is not exercised by CI; a multi-rank run would be worth a look before merge.AI code reviews
Reviews are not retriggered automatically. To request a review, comment on the PR:
@claude full review— Claude full review (also triggers on PR open/reopen/ready)claude-full-review— Claude full review via label