You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: relocate the common-pitfalls material into the user docs
The removed .claude/rules/common-pitfalls.md held traps whose failure modes are silent. Its content is redistributed to the docs page that owns each subject rather than to a new page: indexing/ghost-cell and parameter-plumbing traps into contributing.md's Common Pitfalls section, compiler and backend traps into a new Silent-Failure Traps section in gpuParallelization.md, and test-selection traps into testing.md. Material already covered in those pages (Riemann j/j+1 indexing, the add-a-parameter procedure and its still-manual list, the AMD case-opt bound pattern) was dropped rather than duplicated. The testing.md --only bullet described substring matching and is corrected to whole-element matching.
Written with assistance from Claude Code.
Copy file name to clipboardExpand all lines: docs/documentation/contributing.md
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -175,6 +175,9 @@ Both human reviewers and AI code reviewers reference this section.
175
175
176
176
- MFC uses **non-unity lower bounds** (e.g., `idwbuff(1)%%beg:idwbuff(1)%%end` with negative ghost-cell indices). Always verify loop bounds match array declarations.
177
177
-**Riemann solver indexing:** Left states at `j`, right states at `j+1`. Off-by-one here corrupts fluxes.
178
+
-**Grid extents:**`m`, `n`, `p` are cell counts in x, y, z (1D sets `n = p = 0`, 2D sets `p = 0`). The interior is `0:m`, the ghost region `-buff_size:m+buff_size`, and cell boundaries run `x_cb(-1-buff_size:m+buff_size)`. Bounds are carried in `idwint(1:3)` (interior) and `idwbuff(1:3)` (with ghosts).
179
+
-**`buff_size` is not a single formula.** It is set per reconstruction scheme in `s_configure_coordinate_bounds` (`src/common/m_helper_basic.fpp`) and floored higher for Lagrange bubbles and immersed boundaries. Read that routine rather than assuming a value.
180
+
-**Never hard-code an equation index.** They live in the `eqn_idx` struct (`eqn_idx_info` in `src/common/m_derived_types.fpp`, populated by `s_initialize_eqn_idx` in `src/common/m_global_parameters_common.fpp`): `%%cont`, `%%mom`, `%%E`, `%%adv`, plus the optional ranges `%%bub`, `%%stress`, `%%species`, and `%%B`. Index positions depend on `model_eqns` and on which features are enabled, so changing either moves every index.
178
181
179
182
### Precision and Type Safety
180
183
@@ -212,6 +215,14 @@ Both human reviewers and AI code reviewers reference this section.
212
215
- CLI schema in `toolchain/mfc/cli/commands.py` must match argument parsing.
213
216
- Check subprocess calls for shell injection risks and missing error handling.
214
217
218
+
### Parameter Plumbing
219
+
220
+
-**Derived-type parameters are not auto-broadcast.**`generated_bcast.fpp` covers namelist *scalars* only. Each derived type (`chem_params`, `lag_params`, `rburn`) needs a hand-written `_emit_<name>` in `toolchain/mfc/params/generators/fortran_gen.py` plus its call site in that generator's simulation branch, and, if it is read on device, an explicit `$:GPU_UPDATE(device='[name]')` in both the target's `m_global_parameters.fpp` and `src/simulation/m_start_up.fpp` — `GPU_DECLARE` alone does not make it device-resident. Regrouping existing scalars into a derived type silently drops their broadcast, leaving every non-root rank holding the `dflt_real` sentinel. Single-rank golden files cannot catch this, so pair such a change with a `ppn=2` test and confirm it fails without the emitter.
221
+
-**A `patch_ib` member that immersed-boundary ghost-point code reads must also be set in `s_add_cloud_particle`** (`src/simulation/m_particle_cloud.fpp`). `particle_cloud_ibs` is allocated without default initialization, and `s_reduce_ib_patch_array` copies the whole struct into `patch_ib`, overwriting the defaults assigned in `s_assign_default_values_to_user_inputs`. Anything left unset reaches the solver as uninitialized memory, and only where the allocation is not already zero-filled. A platform-only NaN is the signature of this class: a garbage `v_blow` once failed an AMD lane with `ICFL is NaN` while every NVIDIA lane and all local runs passed.
222
+
-**Runtime checks go where they run.** Shared constraints belong in `src/common/m_checker_common.fpp`, simulation-only ones in `src/simulation/m_checker.fpp`, and pre- and post-process ones in their own `m_checker.fpp`. Those two `s_check_inputs` are currently empty; that is still the correct home for their checks, not `m_checker_common`.
223
+
-**Analytic initial conditions are compiled into the binary** and their expressions are AST-validated at case load, so syntax errors and unknown variables surface immediately and by name. Each IC variable maps to an `eqn_idx` expression in `QPVF_IDX_VARS` (`toolchain/mfc/case.py`); adding a patch-settable conserved variable means updating that map and the Fortran `eqn_idx` builder together, because a mismatch is a silent wrong index.
224
+
-**Under `--case-optimization` the baked-in constants are dropped from the namelist**, so changing one requires a rebuild rather than a case-file edit.
225
+
215
226
### Compiler Portability
216
227
217
228
- Any compiler-specific code (`#ifdef __INTEL_COMPILER` etc.) must have fallbacks for all four supported compilers.
Copy file name to clipboardExpand all lines: docs/documentation/testing.md
+33-1Lines changed: 33 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,7 +13,7 @@ A test is considered passing when our error tolerances are met in order to maint
13
13
`./mfc.sh test` has the following unique options:
14
14
-`-l` outputs the full list of tests
15
15
-`--from` (`-f)` and `--to` (`t`) restrict testing to a range of contiguous slugs
16
-
-`--only` (`-o`) restricts testing to a non-contiguous range of tests based on if their trace contains a certain feature
16
+
-`--only` (`-o`) restricts testing to a non-contiguous range of tests whose trace contains a given whole trace element (see [Selection and Execution Pitfalls](#selection-and-execution-pitfalls) for the exact matching rules)
17
17
-`--test-all` (`a`) test post process and ensure the Silo database files are correct
18
18
-`--percent` (`%`) to specify a percentage of the test suite to select at random and test
19
19
-`--max-attempts` (`-m`) the maximum number of attempts to make on a test before considering it failed
@@ -92,6 +92,38 @@ If a trace is empty (that is, the empty string `""`), it will not appear in the
92
92
93
93
Finally, the case is appended to the `cases` list, which will be returned by the `list_cases` function.
94
94
95
+
### Selection and Execution Pitfalls
96
+
97
+
Each of these fails quietly rather than loudly.
98
+
99
+
-**`--only` matches whole trace elements, not substrings**, and it ANDs labels while ORing
100
+
UUIDs (`_filter_only` in `toolchain/mfc/test/test.py`). `--only bubbles` matches nothing,
101
+
because the trace element is `Bubbles`; `--only low_Mach=1 low_Mach=2` asks for cases
102
+
carrying both labels at once and also matches nothing. An empty selection then exits
103
+
**143**, which reads like an external kill rather than an empty filter. Pass UUIDs when
104
+
you want the union of several groups.
105
+
-**Sibling `define_case_d` calls at the same stack level are never combined.** Two switches
106
+
that only matter together therefore get no effective coverage unless one is pushed onto
107
+
the stack and the other defined beneath it — `avg_state=1`, for instance, is only read
108
+
when `wave_speeds=2`. Check reachability before trusting that a flag is tested.
109
+
-**`--no-build` silently runs whatever binary is already on disk**, including one built for
110
+
a different configuration. Chemistry has its own configuration that a plain `./mfc.sh
111
+
build` never produces, so a `--no-build` run can report failures from stale binaries and
112
+
hide real compile breaks. Run chemistry-touching sets without it.
113
+
-**Identify the newest binary by the binary's own mtime**, not by its install directory's:
114
+
a stale configuration's directory can be newer than a fresh build's.
115
+
-**The pre-commit hook lives in the main repository's `.git/hooks/`**, and git exports
116
+
`GIT_DIR` there during a commit, so from a worktree the toolchain lint enumerates the
117
+
other checkout and fails. Run `./mfc.sh precheck` by hand and commit with `--no-verify`.
118
+
-**`/tmp` is node-local.** Scratch does not survive a compute-node change, and its absence
119
+
is silence rather than an error. Keep patches and resource baselines on a shared
120
+
filesystem.
121
+
-**An unexplained golden-file difference is a bug report, not noise to be regenerated
122
+
away.** Regenerate only the affected tests.
123
+
124
+
Tests are generated programmatically in `toolchain/mfc/test/cases.py`; a test's UUID is the
125
+
CRC32 of its trace string, and `./mfc.sh test -l` lists every one.
126
+
95
127
### Testing Post Process
96
128
97
129
To test the post-processing code, append the `-a` or `--test-all` option:
0 commit comments