Skip to content

Commit d6c84ef

Browse files
Merge branch 'fix/spelling-typos-1498' of https://github.com/engineer-scientist/Multiphase-Flow-Code into fix/spelling-typos-1498
2 parents 59d0194 + 2d662ab commit d6c84ef

312 files changed

Lines changed: 21181 additions & 13094 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/rules/common-pitfalls.md

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ covered in `docs/documentation/contributing.md`.
1414
bubbles and IB. Read that routine for the current value rather than assuming one.
1515
- Riemann solvers: left state at `j`, right state at `j+1`.
1616
- All equation indices live in the `eqn_idx` struct (`eqn_idx_info` in
17-
`m_derived_types.fpp`, populated in `m_global_parameters.fpp`): `%cont`, `%mom`, `%E`,
17+
`m_derived_types.fpp`, populated by `s_initialize_eqn_idx` in `m_global_parameters_common.fpp`): `%cont`, `%mom`, `%E`,
1818
`%adv`, plus optional ranges (`%bub`, `%stress`, `%species`, `%B`, ...). The old
1919
`contxb`/`momxb` shorthands are gone. Index positions depend on `model_eqns` and
2020
enabled features — changing either moves ALL indices; never hard-code one.
@@ -42,17 +42,40 @@ covered in `docs/documentation/contributing.md`.
4242
- Adding one: `_r()` definition + `_nv()` `NAMELIST_VARS` registration in
4343
`toolchain/mfc/params/definitions.py`; `case_validator.py` only if physics-constrained
4444
(with a `PHYSICS_DOCS` entry). Fortran declarations and namelist bindings are
45-
auto-generated at CMake configure time — re-run cmake (or `./mfc.sh build`) after editing.
46-
- Still manual: array variables and derived-type members (declare in
47-
`src/*/m_global_parameters.fpp` / the relevant type), and case-optimization parameters
48-
(`CASE_OPT_PARAMS` + the `#:else` block in `src/simulation/m_global_parameters.fpp`).
49-
Gotcha: under `--case-optimization` those are baked into the binary and dropped from
50-
the namelist, so changing one needs a *rebuild*, not a case edit.
45+
auto-generated at build time (ninja-tracked custom command) — re-run cmake (or `./mfc.sh build`) after editing.
46+
- Still manual: derived-type `TYPE` member definitions in `src/common/m_derived_types.fpp`;
47+
default-value assignments in `s_assign_default_values_to_user_inputs`; the
48+
`CASE_OPT_EXTRA_LINES` literal in `toolchain/mfc/params/generators/fortran_gen.py` (covers `num_dims`,
49+
`num_vels`, `weno_polyn`, `muscl_polyn`, `weno_num_stencils`, `wenojs`);
50+
multi-variable declaration lines (`bc_x/y/z`, `x/y/z_domain`, `x/y/z_output`, post's
51+
`G`); and the MPI broadcast residue in `m_mpi_proxy` (computed variables that are not
52+
namelist-bound: `m_glb`/`n_glb`/`p_glb`, `cfl_dt`, `bc_io`, and complex struct-member
53+
array loops — these cannot be auto-generated and stay hand-listed). Everything else — scalar declarations, plain arrays (`FORTRAN_ARRAY_DIMS`
54+
table in `definitions.py`), derived-type namelist declarations including `GPU_DECLARE`
55+
lines and Doxygen descs (`TYPED_DECLS` table in `definitions.py`), the simulation
56+
case-optimization declaration block, and the per-target MPI broadcast lists for all
57+
namelist-registry scalars (`generated_bcast.fpp`) — is regenerated at build time by a
58+
ninja-tracked custom command (editing `params/*.py` triggers regeneration automatically).
59+
Gotcha: ADDING a new file under `toolchain/mfc/params/` needs one reconfigure
60+
(the custom command's DEPENDS list is globbed at configure time). Under `--case-optimization` the baked-in constants are dropped from the
61+
namelist, so changing one needs a *rebuild*, not a case edit.
62+
- Shared-state pattern: namelist declarations (`#:include 'generated_decls.fpp'`), the
63+
`eqn_idx`/`sys_size`/`b_size`/`tensor_size` state variables, and the common defaults
64+
core all live in `src/common/m_global_parameters_common.fpp`. Each per-target
65+
`m_global_parameters.fpp` does `use m_global_parameters_common` (default-public), so
66+
`use m_global_parameters` continues to work for all downstream modules without change.
67+
Sim-only declarations (GPU_DECLARE, Re_idx allocation) stay in
68+
`m_global_parameters_common` behind `#ifdef MFC_SIMULATION`. Generated includes
69+
(`generated_decls.fpp`, `generated_bcast.fpp`, `generated_case_opt_decls.fpp`) must exist for every target — the build
70+
emits stubs where the content is sim-only, so a common file that includes one will
71+
compile for pre/post too.
5172
- Runtime checks (`@:PROHIBIT`) go where they run: shared →
5273
`src/common/m_checker_common.fpp`; simulation-only → `src/simulation/m_checker.fpp`;
5374
pre/post-only → `src/{pre,post}_process/m_checker.fpp` (their `s_check_inputs` are
5475
currently empty — that IS the right place, not m_checker_common).
55-
- Analytic ICs are compiled into the binary (syntax error = build failure, not runtime).
76+
- Analytic ICs are compiled into the binary. Expressions are AST-validated at case load
77+
(syntax errors and unknown variables are immediate, named errors; bare `e` is not a
78+
variable — write `exp(1.0)`).
5679
Each IC variable maps to an `eqn_idx%…` expression in `QPVF_IDX_VARS`
5780
(`toolchain/mfc/case.py`); a new patch-settable conserved variable means updating that
5881
map AND the Fortran `eqn_idx` builder to agree — a mismatch is a silent wrong index.

.github/scripts/prebuild-case-optimization.sh

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,44 @@ case "$cluster" in
2222
*) echo "ERROR: Unknown cluster '$cluster'"; exit 1 ;;
2323
esac
2424

25+
# Optional sharding (format "i/N", e.g. "1/2"), set by submit-slurm-job.sh's
26+
# [shard] argument via $job_shard: shard i builds every Nth case of the sorted
27+
# case list. Unset = build all cases in one job (default; other clusters).
28+
shard="${job_shard:-}"
29+
if [ -n "$shard" ]; then
30+
# Validate full shape: must be exactly "digits/digits" — one slash with
31+
# non-empty, purely numeric, non-leading-zero parts on both sides.
32+
# Split first, then validate each part independently so that inputs like
33+
# "1/" "/2" "//" "1/2/3" "a/b" "12" are all caught before any arithmetic.
34+
shard_idx="${shard%%/*}"
35+
shard_count="${shard##*/}"
36+
# Reject if no slash (idx and count are equal and equal to the whole string)
37+
case "$shard_idx" in
38+
''|*[!0-9]*|0*) echo "ERROR: bad shard '$shard' (expected i/N)"; exit 1 ;;
39+
esac
40+
case "$shard_count" in
41+
''|*[!0-9]*|0*) echo "ERROR: bad shard '$shard' (expected i/N)"; exit 1 ;;
42+
esac
43+
# Confirm the string is exactly "idx/count" — catches "12" (no slash) and
44+
# "1/2/3" (extra slash, where idx=1 and count=2/3 would have failed above,
45+
# but this is an extra safety net).
46+
if [ "$shard" != "$shard_idx/$shard_count" ]; then
47+
echo "ERROR: bad shard '$shard' (expected i/N)"; exit 1
48+
fi
49+
if [ "$shard_idx" -lt 1 ] || [ "$shard_idx" -gt "$shard_count" ]; then
50+
echo "ERROR: bad shard '$shard' (expected i/N with 1 <= i <= N)"; exit 1
51+
fi
52+
fi
53+
2554
# Phoenix starts fresh (no prior dep build); other clusters pre-build deps via
2655
# build.sh first, so we must preserve them and only clean MFC target staging.
56+
# Sharded jobs share one workspace and run concurrently, so the workflow
57+
# cleans once before submitting them — cleaning here would wipe a sibling
58+
# shard's in-progress build.
2759
if [ "$cluster" = "phoenix" ]; then
2860
source .github/scripts/clean-build.sh
2961
clean_build
30-
else
62+
elif [ -z "$shard" ]; then
3163
find build/staging -maxdepth 1 -regex '.*/[0-9a-f]+' -type d -exec rm -rf {} + 2>/dev/null || true
3264
find build/install -maxdepth 1 -regex '.*/[0-9a-f]+' -type d -exec rm -rf {} + 2>/dev/null || true
3365
fi
@@ -40,7 +72,49 @@ case "$job_interface" in
4072
*) echo "ERROR: prebuild requires gpu interface (acc or omp)"; exit 1 ;;
4173
esac
4274

75+
# Case-optimized simulation builds land in per-case hash-named staging dirs,
76+
# but syscheck/pre_process/post_process hash identically across these cases.
77+
# Concurrent shards must not build those shared staging dirs simultaneously:
78+
# shard 1 builds them first and drops a done marker; other shards wait for it,
79+
# after which their builds no-op in the shared dirs.
80+
if [ -n "$shard" ] && [ "$shard_count" -gt 1 ]; then
81+
shared_marker_done="build/.prebuild-shared-targets-done"
82+
shared_marker_failed="build/.prebuild-shared-targets-failed"
83+
set -- benchmarks/*/case.py
84+
first_case="$1"
85+
if [ "$shard_idx" -eq 1 ]; then
86+
# Remove both markers at the start so reruns and manual invocations
87+
# never observe stale state from a prior run.
88+
rm -f "$shared_marker_done" "$shared_marker_failed"
89+
echo "=== Shard 1/$shard_count: building shared targets ==="
90+
# Write the failure marker if the build exits non-zero so other shards
91+
# can detect the failure immediately instead of waiting 90 minutes.
92+
trap 'touch "$shared_marker_failed"' ERR
93+
./mfc.sh build -i "$first_case" -t syscheck pre_process post_process --case-optimization $gpu_opts -j 8
94+
trap - ERR
95+
touch "$shared_marker_done"
96+
else
97+
echo "=== Shard $shard_idx/$shard_count: waiting for shard 1 to build shared targets ==="
98+
waited=0
99+
until [ -f "$shared_marker_done" ]; do
100+
if [ -f "$shared_marker_failed" ]; then
101+
echo "ERROR: shard 1 failed to build shared targets; see shard 1 log"; exit 1
102+
fi
103+
if [ "$waited" -ge 5400 ]; then
104+
echo "ERROR: timed out waiting for $shared_marker_done"; exit 1
105+
fi
106+
sleep 30
107+
waited=$((waited + 30))
108+
done
109+
fi
110+
fi
111+
112+
idx=0
43113
for case in benchmarks/*/case.py; do
114+
idx=$((idx + 1))
115+
if [ -n "$shard" ] && [ $(((idx - 1) % shard_count)) -ne $((shard_idx - 1)) ]; then
116+
continue
117+
fi
44118
echo "=== Pre-building: $case ==="
45119
./mfc.sh run "$case" --case-optimization $gpu_opts -j 8 --dry-run
46120
done

.github/scripts/run_parallel_benchmarks.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ bash "${SCRIPT_DIR}/run_monitored_slurm_job.sh" "$pr_job_id" "pr/${job_slug}.out
6262
if [ "$pr_exit" -ne 0 ]; then
6363
echo "PR job exited with code: $pr_exit"
6464
tail -n 50 "pr/${job_slug}.out" 2>/dev/null || echo " Could not read PR log"
65+
# The PR benchmark run genuinely failed (cases crashed/hung/SIGTERM'd, not a
66+
# monitor false-positive -- run_monitored_slurm_job.sh re-checks sacct). Fail
67+
# the job instead of falling through to the YAML-exists check, which would let
68+
# a broken PR pass green as long as a partial YAML was written. Scoped to PR
69+
# only: a master/baseline infra flake stays a warning and does not red-cross.
70+
exit 1
6571
else
6672
echo "PR job completed successfully"
6773
fi

.github/scripts/submit-slurm-job.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ case "$cluster" in
5252
account="CFD154"
5353
job_prefix="MFC"
5454
qos="hackathon"
55-
extra_sbatch=""
55+
# Let each job's slurmstepd broker its own steps instead of routing
56+
# every srun through slurmctld. The in-job test suite launches ~1700+
57+
# srun steps per allocation, which congests the Frontier controller.
58+
extra_sbatch="#SBATCH --stepmgr"
5659
test_time="01:59:00"
5760
bench_time="01:59:00"
5861
gpu_partition_dynamic=false
@@ -62,7 +65,7 @@ case "$cluster" in
6265
account="CFD154"
6366
job_prefix="MFC"
6467
qos="hackathon"
65-
extra_sbatch=""
68+
extra_sbatch="#SBATCH --stepmgr"
6669
test_time="01:59:00"
6770
bench_time="01:59:00"
6871
gpu_partition_dynamic=false

.github/workflows/test.yml

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,19 @@ jobs:
156156
# Replaces the container: directive so we can free disk space first.
157157
# Uses "docker run -d ... sleep infinity" + "docker exec" to preserve
158158
# installed packages and env vars across steps.
159+
# Retry the pull: nvcr.io intermittently times out ("context deadline
160+
# exceeded") under load, and ~30 matrix jobs hit it at once. Pulls
161+
# resume completed layers, so retries are cheap.
159162
- name: Pull NVHPC container
160163
if: matrix.nvhpc
161-
run: docker pull "$NVHPC_IMAGE"
164+
run: |
165+
for attempt in 1 2 3 4 5; do
166+
docker pull "$NVHPC_IMAGE" && exit 0
167+
echo "docker pull failed (attempt $attempt/5); retrying in $((attempt * 30))s..."
168+
sleep $((attempt * 30))
169+
done
170+
echo "::error::Failed to pull $NVHPC_IMAGE after 5 attempts"
171+
exit 1
162172
163173
- name: Start NVHPC container
164174
if: matrix.nvhpc
@@ -392,6 +402,13 @@ jobs:
392402
cluster_name: 'Oak Ridge | Frontier (AMD)'
393403
device: 'cpu'
394404
interface: 'none'
405+
shard: '1/2'
406+
- runner: 'frontier'
407+
cluster: 'frontier_amd'
408+
cluster_name: 'Oak Ridge | Frontier (AMD)'
409+
device: 'cpu'
410+
interface: 'none'
411+
shard: '2/2'
395412
runs-on:
396413
group: phoenix
397414
labels: ${{ matrix.runner }}
@@ -410,7 +427,7 @@ jobs:
410427

411428
- name: Fetch Dependencies
412429
if: matrix.cluster != 'phoenix'
413-
timeout-minutes: 60
430+
timeout-minutes: 120
414431
run: bash .github/workflows/${{ matrix.cluster }}/build.sh ${{ matrix.device }} ${{ matrix.interface }}
415432

416433
- name: Build
@@ -513,7 +530,22 @@ jobs:
513530

514531
- name: Pre-Build (SLURM)
515532
if: matrix.cluster == 'frontier_amd'
516-
run: bash .github/scripts/submit-slurm-job.sh .github/scripts/prebuild-case-optimization.sh gpu ${{ matrix.interface }} ${{ matrix.cluster }}
533+
# AMD flang is slow enough that one serial pre-build job exceeds its
534+
# walltime, so split the case list across two concurrent SLURM jobs.
535+
# The shards share this workspace and skip their in-job staging clean,
536+
# so clean once here on the login node before submitting.
537+
run: |
538+
find build/staging -maxdepth 1 -regex '.*/[0-9a-f]+' -type d -exec rm -rf {} + 2>/dev/null || true
539+
find build/install -maxdepth 1 -regex '.*/[0-9a-f]+' -type d -exec rm -rf {} + 2>/dev/null || true
540+
rm -f build/.prebuild-shared-targets-done
541+
bash .github/scripts/submit-slurm-job.sh .github/scripts/prebuild-case-optimization.sh gpu ${{ matrix.interface }} ${{ matrix.cluster }} 1/2 &
542+
pid1=$!
543+
bash .github/scripts/submit-slurm-job.sh .github/scripts/prebuild-case-optimization.sh gpu ${{ matrix.interface }} ${{ matrix.cluster }} 2/2 &
544+
pid2=$!
545+
rc=0
546+
wait "$pid1" || rc=1
547+
wait "$pid2" || rc=1
548+
exit $rc
517549
518550
- name: Build & Run Case-Optimization Tests
519551
if: matrix.cluster != 'phoenix' && matrix.cluster != 'frontier_amd'
@@ -536,6 +568,8 @@ jobs:
536568
if: always()
537569
run: |
538570
for f in prebuild-case-optimization-${{ matrix.device }}-${{ matrix.interface }}.out \
571+
prebuild-case-optimization-${{ matrix.device }}-${{ matrix.interface }}-1-of-2.out \
572+
prebuild-case-optimization-${{ matrix.device }}-${{ matrix.interface }}-2-of-2.out \
539573
run-case-optimization-${{ matrix.device }}-${{ matrix.interface }}.out; do
540574
[ -f "$f" ] && echo "=== $f ===" && cat "$f"
541575
done
@@ -546,5 +580,5 @@ jobs:
546580
with:
547581
name: case-opt-${{ strategy.job-index }}-${{ matrix.cluster }}-${{ matrix.interface }}
548582
path: |
549-
prebuild-case-optimization-${{ matrix.device }}-${{ matrix.interface }}.out
583+
prebuild-case-optimization-${{ matrix.device }}-${{ matrix.interface }}*.out
550584
run-case-optimization-${{ matrix.device }}-${{ matrix.interface }}.out

0 commit comments

Comments
 (0)