feat: add 3D reacting mixing-layer example (H2/N2-air, Mach 1.5) + hcid=371 - #1758
feat: add 3D reacting mixing-layer example (H2/N2-air, Mach 1.5) + hcid=371#1758ecisneros8 wants to merge 17 commits into
Conversation
mpirun is not the correct MPI launcher on NCSA DeltaAI; srun (matching delta.mako's working pattern) is required for batch submissions to succeed.
The dai-gpu module set never set LD_LIBRARY_PATH for libnvToolsExt.so.1, which nvfortran's OpenACC/CUDA runtime links against but the loaded cudatoolkit/25.5_12.9 module doesn't provide (only the SDK's bundled CUDA 11.8 tree ships it), causing GPU binaries to fail to launch with a missing shared library error.
…1.5) New hcid=371 (3dHardcodedIC.fpp): extends hcid=370's 3D extrusion of a 2D flamelet profile with a closed-form spanwise (z) modulation of the in-plane velocity perturbation, so the IC has genuine 3D content from step 0 without relying on mixlayer_perturb (whose fixed wavenumber range is meaningless at this case's millimeter length scale). New example examples/3D_reacting_mixing_layer/: a supersonic (Mach_c=1.5) temporally-evolving H2/N2-air mixing layer initialized from a 1-D flamelet solve (flamelet_ic.py), diluted to X_H2=0.5 (pure H2's high sound speed otherwise forces an unphysically extreme velocity split to reach Mach_c=1.5), with Unity-Lewis transport to match the flamelet solve's own diffusivity assumption. Validated over 165k+ steps with no numerical instability.
z_cc(p) - z_cc(0) is a per-rank quantity: s_mpi_decompose_computational_domain overwrites p and z_domain with this rank's slab before the grid is built, so the imposed wavenumber scaled with num_procs_z and the IC depended on the decomposition. It also fell one cell short of L_z, leaving the modulation discontinuous across the periodic z wrap even on one rank. Use p_glb cells of the uniform cell width instead, and correct the comment and case.md: only the cross-stream component is modulated, and the spanwise component is set from it, not the full in-plane perturbation.
The 3D extrusion read only bounds-checked its row indices, so a file that is merely too fine stays in range and silently supplies a corner of itself. Check spacing and alignment up front, as hcid=274 already does for its full-field read.
perturb_xy defaulted seed=None, so np.random.default_rng drew from OS entropy. IC/ is gitignored and regenerated on every checkout, which made the example irreproducible run to run. Make the seed a required argument, set it in case.py, and key the IC cache on it. Also bin the phase blocks relative to x_coord[0] (binning the raw coordinate clipped every x < 0 into block 0, leaving two of five blocks unused), write the IC with savetxt rather than ~1.6M per-element writes, and record the mechanism's provenance in sandiego.yaml.
The Example sweep caps 3D cases to 25^3 while case.py writes its IC at the declared 210x560. Offsets rounded to zero, so the run read file rows 1-26 in x and y: a pure-oxidizer sliver where the perturbation mollifier is identically zero. Both hcid=371 statements then operated on zeros, and the golden covered nothing. Skip it in the Example sweep like the 2D siblings and register it under Chemistry with --scale 0.05, which drives case.py's own grid so the IC matches. The new golden carries nonzero spanwise momentum at step 0.
The literal 25.5 path breaks silently when dai-all's nvidia module bumps. Prefer $NVHPC_ROOT, keep the validated path as the fallback, and drop the trailing colon when LD_LIBRARY_PATH is empty.
Covers the stream conditions, grid, hcid=371's spanwise modulation, the seeded IC and its cache, and the --scale/--hot flags.
web.eng.ucsd.edu serves an untrusted certificate, so lychee fails on the link the 3D_reacting_mixing_layer README cites. Same treatment as the HPE Cray docs entry.
# Conflicts: # .lychee.toml
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1758 +/- ##
==========================================
- Coverage 61.67% 60.25% -1.43%
==========================================
Files 84 84
Lines 21619 21846 +227
Branches 3196 3218 +22
==========================================
- Hits 13334 13163 -171
- Misses 6093 6280 +187
- Partials 2192 2403 +211 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
draft for now until ci settles |
Lines of Code
|
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds a new 3D temporal reacting mixing-layer example (H2/N2–air, Mc=1.5) initialized from a flamelet-generated file IC and introduces hcid=371 to add true spanwise 3D content at t=0; also includes two NCSA DeltaAI toolchain fixes.
Changes:
- Add
examples/3D_reacting_mixing_layerincluding flamelet IC generator, mechanism file, and documentation. - Implement and validate
hcid=371(3D extrusion + spanwise modulation) and register it in validation/tests/docs. - Fix DeltaAI launcher/module environment issues (
srunandLD_LIBRARY_PATHforlibnvToolsExt.so.1).
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| toolchain/templates/deltaai.mako | Switch MPI launcher from mpirun to srun for DeltaAI compatibility |
| toolchain/modules | Add LD_LIBRARY_PATH entry to locate libnvToolsExt.so.1 under NVHPC CUDA runtime |
| toolchain/mfc/test/cases.py | Register new 3D example and add a chemistry golden test entry for it |
| toolchain/mfc/case_validator.py | Add 371 to the list of extrusion HCIDs requiring file params |
| tests/3C77E5DD/golden-metadata.txt | Add golden metadata for a new test case |
| src/common/include/ExtrusionHardcodedIC.fpp | Add stricter file spacing/alignment checks for extrusion ICs |
| src/common/include/3dHardcodedIC.fpp | Implement hcid=371 spanwise modulation based on global z extent |
| examples/3D_reacting_mixing_layer/sandiego.yaml | Add San Diego H2/O2/N2 mechanism YAML used by the new example |
| examples/3D_reacting_mixing_layer/flamelet_ic.py | Add 3D flamelet IC generator and hcid=370-format file writer |
| examples/3D_reacting_mixing_layer/case.py | Add runnable case definition that generates/uses IC files and selects hcid=371 |
| examples/3D_reacting_mixing_layer/README.md | Document the new example setup, IC details, and run instructions |
| docs/documentation/case.md | Document case(371) behavior and usage |
| .lychee.toml | Exclude mechanism URL from link checking due to certificate issues |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (nrows > yRows) then | ||
| if (abs((x_coords(yRows + 1) - x_coords(1)) - x_step) > 1.e-6_wp*abs(x_step)) & | ||
| & call s_mpi_abort("Hardcoded IC extrusion: file x-spacing does not match the run grid; regenerate the IC for this grid.") | ||
| end if | ||
| if (yRows > 1) then | ||
| if (abs((y_coords(2) - y_coords(1)) - y_step) > 1.e-6_wp*abs(y_step)) & | ||
| & call s_mpi_abort("Hardcoded IC extrusion: file y-spacing does not match the run grid; regenerate the IC for this grid.") | ||
| end if |
| domain_length = x_coord[-1] - x_coord[0] | ||
| domain_height = cross_coord[-1] - cross_coord[0] | ||
|
|
||
| stream_coord = x_coord[:, None] # (nx, 1) | ||
| flame_coord = cross_coord[None, :] # (1, ny) | ||
| dx = x_coord[1] - x_coord[0] | ||
| dy = cross_coord[1] - cross_coord[0] |
| domain_length = x_coord[-1] - x_coord[0] | ||
| domain_height = cross_coord[-1] - cross_coord[0] | ||
|
|
||
| stream_coord = x_coord[:, None] # (nx, 1) | ||
| flame_coord = cross_coord[None, :] # (1, ny) | ||
| dx = x_coord[1] - x_coord[0] | ||
| dy = cross_coord[1] - cross_coord[0] |
| conditions = [phase_jitter[x_int] < 0.33, (phase_jitter[x_int] > 0.33) * (phase_jitter[x_int] < 0.66), phase_jitter[x_int] > 0.66] | ||
| f = np.select(conditions, [1, -1, 0]) | ||
|
|
||
| k_x = 2 / domain_length |
| @: HardcodedReadValues() | ||
| zlen371 = real(p_glb + 1, wp)*(z_cb(0) - z_cb(-1)) | ||
| kz371 = 2._wp*pi/zlen371 | ||
| q_prim_vf(eqn_idx%mom%beg + 1)%sf(i, j, k) = q_prim_vf(eqn_idx%mom%beg + 1)%sf(i, j, k)*(1._wp + 0.5_wp*cos(kz371*z_cc(k))) | ||
| q_prim_vf(eqn_idx%mom%end)%sf(i, j, k) = 0.5_wp*q_prim_vf(eqn_idx%mom%beg + 1)%sf(i, j, k)*sin(kz371*z_cc(k) + pi/3._wp) |
| # File-based IC (hcid=273/274/371) sized to the full grid; the Example | ||
| # suite's m/n/p cap breaks it. Covered by the Chemistry golden tests. | ||
| "2D_reacting_mixing_layer", | ||
| "2D_spatial_reacting_mixing_layer", | ||
| "3D_reacting_mixing_layer", |
Description
Adds a new 3D temporally-evolving reacting mixing-layer example (H2/N2-air, convective
Mach 1.5) initialized from a 1D flamelet solve, plus a new hardcoded IC (
hcid=371) thatextends
hcid=370's 3D extrusion of a 2D profile with a closed-form spanwise (z)modulation of the in-plane velocity perturbation, giving the IC genuine 3D content from
step 0 instead of staying z-invariant. Also registers
hcid=371incase_validator.py's extrusion-hcid check and documents it incase.md.Two unrelated NCSA DeltaAI cluster fixes are included: the batch template was using
mpirun, which is not the correct launcher on DeltaAI (srunis, matchingdelta.mako's working pattern), and thedai-gpumodule set never setLD_LIBRARY_PATHforlibnvToolsExt.so.1, which nvfortran's OpenACC/CUDA runtimerequires but the loaded
cudatoolkitmodule doesn't provide.Type of change (delete unused ones)
Testing
./mfc.sh precheck -j 8passes (formatting, spelling, toolchain/source lint, docreferences, parameter docs, example case validation).
./mfc.sh build -j 8builds all three targets (pre_process,simulation,post_process) cleanly —hcid=371lives in the sharedsrc/common/include/3dHardcodedIC.fpp, included by bothpre_processandsimulation../mfc.sh test -j 8: full suite passes (681 tests, plus the new3D -> Example -> reacting_mixing_layergolden generated and added intests/2E1858B2/).(not part of the regression suite at that step count — the golden covers the
standard 50-step example smoke test). No CPU-vs-GPU comparison run was done.
hcid=371is only used viapre_process'sicpppatches in this example (noimmersed boundaries), so it hasn't been exercised through the IB patch path in
src/simulation/m_ib_patches.fpp, which also includes this shared file.srunbatch submission andsuccessful GPU binary launch after the
LD_LIBRARY_PATHfix).Checklist
Check these like this
[x]to indicate which of the below applies.See the developer guide for full coding standards.
GPU changes (expand if you modified
src/simulation/)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