Skip to content

Commit cb58059

Browse files
sbryngelsonclaude
andcommitted
Add CLAUDE.md and .claude/rules/ for Claude Code guidance
Adds project-level instructions for Claude Code interactive sessions and automated PR reviews. Core CLAUDE.md covers commands, development workflow contract, architecture, and critical rules. Domain-specific knowledge (Fortran conventions, GPU/MPI patterns, parameter system, common pitfalls) lives in modular .claude/rules/ files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 38f0457 commit cb58059

5 files changed

Lines changed: 410 additions & 0 deletions

File tree

.claude/rules/common-pitfalls.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Common Pitfalls
2+
3+
## Array Bounds
4+
- Arrays use non-unity lower bounds with ghost cells
5+
- Riemann solver indexing: left state at `j`, right state at `j+1`
6+
- Off-by-one errors in ghost cell regions are a common source of bugs
7+
8+
## Blast Radius
9+
- `src/common/` is shared by ALL three executables (pre_process, simulation, post_process)
10+
- Any change to common/ requires testing all three targets
11+
- Public subroutine signature changes affect all callers across all targets
12+
- Parameter default changes affect all existing case files
13+
14+
## Physics Consistency
15+
- Pressure formula MUST match `model_eqns` setting
16+
- Model-specific conservative ↔ primitive conversion paths exist
17+
- Volume fractions must sum to 1.0
18+
- Boundary condition symmetry requirements must be maintained
19+
20+
## Compiler-Specific Issues
21+
- Code must compile on gfortran, nvfortran, Cray ftn, and Intel ifx
22+
- Each compiler has different strictness levels and warning behavior
23+
- Fypp macros must expand correctly for both GPU and CPU builds
24+
- GPU builds only work with nvfortran, Cray ftn, and AMD flang
25+
26+
## Test Golden Files
27+
- Tests compare output against golden files in `tests/<hash>/golden.txt`
28+
- If your change intentionally modifies output, regenerate golden files:
29+
`./mfc.sh test --generate --only <affected_tests> -j 8`
30+
- Do not regenerate ALL golden files unless you understand every output change
31+
- Golden file diffs are compared with tolerance, not exact match
32+
33+
## PR Checklist
34+
Before submitting a PR:
35+
- [ ] `./mfc.sh format -j 8` (auto-format)
36+
- [ ] `./mfc.sh precheck -j 8` (5 CI lint checks)
37+
- [ ] `./mfc.sh build -j 8` (compiles)
38+
- [ ] `./mfc.sh test --only <relevant> -j 8` (tests pass)
39+
- [ ] If adding parameters: all 3 locations updated
40+
- [ ] If modifying `src/common/`: all three targets tested
41+
- [ ] If changing output: golden files regenerated for affected tests
42+
- [ ] One logical change per commit
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Fortran Conventions
2+
3+
## File Format
4+
- Source files use `.fpp` extension (Fortran + Fypp preprocessor macros)
5+
- Fypp preprocesses `.fpp``.f90` at build time via CMake
6+
- Fypp supports conditional compilation, code generation, and regex macros
7+
8+
## Module Structure
9+
Every Fortran module follows this pattern:
10+
- File: `m_<feature>.fpp`
11+
- Module: `module m_<feature>`
12+
- `implicit none` required
13+
- Explicit `intent(in)`, `intent(out)`, or `intent(inout)` on ALL subroutine/function arguments
14+
- Initialization subroutine: `s_initialize_<feature>_module`
15+
- Finalization subroutine: `s_finalize_<feature>_module`
16+
17+
## Naming
18+
- Modules: `m_<feature>`
19+
- Public subroutines: `s_<verb>_<noun>`
20+
- Public functions: `f_<verb>_<noun>`
21+
- Private/local variables: no prefix required
22+
- Constants: descriptive names, not ALL_CAPS
23+
24+
## Forbidden Patterns
25+
These are caught by `./mfc.sh precheck` (source lint step 4/5):
26+
- `dsqrt`, `dexp`, `dlog`, `dble`, `dabs` → use `sqrt`, `exp`, `log`, `real(..., wp)`
27+
- `real(8)`, `real(4)` → use `wp` or `stp` kind parameters
28+
- `goto`, `COMMON` blocks, global `save` variables
29+
- `stop`, `error stop` → use `call s_mpi_abort()`
30+
- Raw `!$acc` or `!$omp` directives → use Fypp GPU_* macros from `parallel_macros.fpp`
31+
32+
## Precision Types
33+
- `wp` (working precision): used for computation. Double by default.
34+
- `stp` (storage precision): used for I/O. Double by default.
35+
- In single-precision mode (`--single`): both become single.
36+
- In mixed-precision mode (`--mixed`): wp=double, stp=single.
37+
- MPI type matching: `mpi_p` must match `wp`, `mpi_io_p` must match `stp`.
38+
- Always use generic intrinsics: `sqrt` not `dsqrt`, `abs` not `dabs`.
39+
- Cast with `real(..., wp)` or `real(..., stp)`, never `dble(...)`.
40+
41+
## Size Guidelines (soft)
42+
- Subroutine: ≤500 lines
43+
- Helper routine: ≤150 lines
44+
- Function: ≤100 lines
45+
- File: ≤1000 lines
46+
- Arguments: ≤6 preferred

.claude/rules/gpu-and-mpi.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# GPU and MPI Patterns
2+
3+
## GPU Offloading Architecture
4+
5+
Only `src/simulation/` is GPU-accelerated. Pre/post_process run on CPU only.
6+
7+
MFC uses a **backend-agnostic GPU abstraction** via Fypp macros. The same source code
8+
compiles to either OpenACC or OpenMP target offload depending on the build flag:
9+
10+
- `./mfc.sh build --gpu acc` → OpenACC backend (NVIDIA nvfortran, Cray ftn)
11+
- `./mfc.sh build --gpu mp` → OpenMP target offload backend (Cray ftn, AMD flang)
12+
- `./mfc.sh build` (no --gpu) → CPU-only, GPU macros expand to plain Fortran
13+
14+
### Macro Layers (in src/common/include/)
15+
- `parallel_macros.fpp`**Use these.** Generic `GPU_*` macros that dispatch to the
16+
correct backend based on `MFC_OpenACC` / `MFC_OpenMP` compile definitions.
17+
- `acc_macros.fpp` — OpenACC-specific `ACC_*` implementations (do not call directly)
18+
- `omp_macros.fpp` — OpenMP target offload `OMP_*` implementations (do not call directly)
19+
- OMP macros generate **compiler-specific** directives: NVIDIA uses `target teams loop`,
20+
Cray uses `target teams distribute parallel do simd`, AMD uses
21+
`target teams distribute parallel do`
22+
- `shared_parallel_macros.fpp` — Shared helpers (collapse, private, reduction generators)
23+
24+
### Key GPU Macros (always use the `GPU_*` prefix)
25+
- `@:GPU_PARALLEL_LOOP(collapse=N, private=[...], reduction=[...], reductionOp='+')`
26+
Parallel loop over GPU threads. Most common GPU macro.
27+
- `@:END_GPU_PARALLEL_LOOP()` — Required closing for GPU_PARALLEL_LOOP.
28+
- `@:GPU_PARALLEL(code, ...)` — GPU parallel region (wraps code block).
29+
- `@:GPU_LOOP(collapse=N, ...)` — Inner loop within a GPU parallel region.
30+
- `@:GPU_DATA(code, copy=..., create=..., ...)` — Scoped data region.
31+
- `@:GPU_ENTER_DATA(create=[...])` — Allocate device memory (unscoped).
32+
- `@:GPU_EXIT_DATA(delete=[...])` — Free device memory.
33+
- `@:GPU_UPDATE(host=[...])` — Copy device → host (before MPI send).
34+
- `@:GPU_UPDATE(device=[...])` — Copy host → device (after MPI receive).
35+
- `@:GPU_ROUTINE(function_name=..., nohost=True/False)` — Mark routine for device.
36+
- `@:GPU_DECLARE(copyin=[...], link=[...])` — Declare device-resident data.
37+
- `@:GPU_ATOMIC(atomic='update')` — Atomic operation on device.
38+
- `@:GPU_WAIT()` — Synchronization barrier.
39+
- `@:GPU_HOST_DATA(code, use_device_addr=[...])` — Host code with device pointers.
40+
41+
NEVER write raw `!$acc` or `!$omp` directives. Always use `GPU_*` Fypp macros.
42+
The precheck source lint will catch raw directives and fail.
43+
44+
### Memory Management Macros (from macros.fpp)
45+
- `@:ALLOCATE(var1, var2, ...)` — Fortran allocate + `GPU_ENTER_DATA(create=...)`
46+
- `@:DEALLOCATE(var1, var2, ...)``GPU_EXIT_DATA(delete=...)` + Fortran deallocate
47+
- Every `@:ALLOCATE` MUST have a matching `@:DEALLOCATE` in finalization
48+
- Conditional allocation MUST have conditional deallocation
49+
50+
### GPU Field Setup (Cray-specific, from macros.fpp)
51+
- `@:ACC_SETUP_VFs(...)` / `@:ACC_SETUP_SFs(...)` — GPU pointer setup for vector/scalar fields
52+
- These compile only for Cray (`_CRAYFTN`); other compilers skip them
53+
54+
### Compiler-Backend Matrix
55+
| Compiler | `--gpu acc` (OpenACC) | `--gpu mp` (OpenMP) | CPU-only |
56+
|-----------------|----------------------|---------------------|----------|
57+
| GNU gfortran | No | No | Yes |
58+
| NVIDIA nvfortran| Yes (primary) | Yes | Yes |
59+
| Cray ftn (CCE) | Yes | Yes (primary) | Yes |
60+
| Intel ifx | No | No | Yes |
61+
| AMD flang | No | Yes | Yes |
62+
63+
## Preprocessor Defines (`#ifdef` / `#ifndef`)
64+
65+
Raw `#ifdef` / `#ifndef` preprocessor guards are **normal and expected** in MFC.
66+
They are NOT the same as raw `!$acc`/`!$omp` pragmas (which are forbidden).
67+
68+
Use `#ifdef` for feature, target, compiler, and library gating:
69+
70+
### Feature gating
71+
- `MFC_MPI` — MPI-enabled build (`--mpi` flag, default ON)
72+
- `MFC_OpenACC` — OpenACC GPU backend (`--gpu acc`)
73+
- `MFC_OpenMP` — OpenMP target offload backend (`--gpu mp`)
74+
- `MFC_GPU` — Any GPU build (either OpenACC or OpenMP)
75+
- `MFC_DEBUG` — Debug build (`--debug`)
76+
- `MFC_SINGLE_PRECISION` — Single-precision mode (`--single`)
77+
- `MFC_MIXED_PRECISION` — Mixed-precision mode (`--mixed`)
78+
79+
### Target gating (for code in `src/common/` shared across executables)
80+
- `MFC_PRE_PROCESS` — Only in pre_process builds
81+
- `MFC_SIMULATION` — Only in simulation builds
82+
- `MFC_POST_PROCESS` — Only in post_process builds
83+
84+
### Compiler gating (for compiler-specific workarounds)
85+
- `_CRAYFTN` — Cray Fortran compiler
86+
- `__NVCOMPILER_GPU_UNIFIED_MEM` — NVIDIA unified memory (GH-200 / `--unified`)
87+
- `__PGI` — Legacy PGI/NVIDIA compiler
88+
- `__INTEL_COMPILER` — Intel compiler
89+
- `FRONTIER_UNIFIED` — Frontier HPC unified memory
90+
91+
### Library-specific code
92+
- FFTW (`m_fftw.fpp`) uses heavy `#ifdef` gating for `MFC_GPU` and `__PGI`
93+
- CUDA Fortran (`cudafor` module) is gated behind `__NVCOMPILER_GPU_UNIFIED_MEM`
94+
- SILO/HDF5 interfaces may have conditional paths
95+
96+
When adding new `#ifdef` blocks, always provide an `#else` or `#endif` path so
97+
the code compiles in all configurations (CPU-only, GPU-ACC, GPU-OMP, with/without MPI).
98+
99+
## MPI
100+
101+
### Halo Exchange
102+
- Pack/unpack offset calculations are error-prone — verify carefully
103+
- Buffer sizing depends on dimensionality and QBMM state
104+
- GPU coherence: always `GPU_UPDATE(host=...)` before MPI send,
105+
`GPU_UPDATE(device=...)` after MPI receive
106+
107+
### Error Handling
108+
- Use `call s_mpi_abort()` for fatal errors, never `stop` or `error stop`
109+
- MPI must be finalized before program exit

.claude/rules/parameter-system.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Parameter System
2+
3+
## Overview
4+
MFC has ~3,300 simulation parameters defined in Python and read by Fortran via namelist files.
5+
6+
## Parameter Flow: Python → Fortran
7+
8+
1. **Definition**: `toolchain/mfc/params/definitions.py` — source of truth
9+
- Parameters are indexed families: `patch_icpp(i)%attr`, `fluid_pp(i)%attr`, etc.
10+
- Each has type, default, constraints, and tags
11+
12+
2. **Validation**: `toolchain/mfc/case_validator.py`
13+
- JSON schema validation via fastjsonschema
14+
- Physics constraint checking (e.g., volume fractions sum to 1)
15+
- Dependency validation (required/recommended params)
16+
17+
3. **Input Generation**: `toolchain/mfc/run/input.py`
18+
- Python case dict → Fortran namelist `.inp` file
19+
- Format: `&user_inputs / ... / &end`
20+
21+
4. **Fortran Reading**: `src/*/m_start_up.fpp`
22+
- Reads `&user_inputs` namelist
23+
- Each parameter must be declared in the namelist statement
24+
25+
## Adding a New Parameter (3-location checklist)
26+
27+
YOU MUST update all 3 locations. Missing any causes silent failures.
28+
29+
1. **`toolchain/mfc/params/definitions.py`**: Add parameter with type, default, constraints
30+
2. **`src/*/m_start_up.fpp`**: Add to the Fortran `namelist` declaration in the relevant
31+
target(s). If the param is used by simulation only, add it there. If shared, add to
32+
all three targets' m_start_up.fpp.
33+
3. **`toolchain/mfc/case_validator.py`**: Add validation rules if the parameter has
34+
physics constraints. Include `PHYSICS_DOCS` entry with title, category, explanation.
35+
36+
## Case Files
37+
- Case files are Python scripts (`.py`) that define a dict of parameters
38+
- Validated with `./mfc.sh validate case.py`
39+
- Examples in `examples/` directory
40+
- Create new cases with `./mfc.sh new <name>`
41+
- Search parameters with `./mfc.sh params <query>`
42+
43+
## Analytical Initial Conditions
44+
String expressions in parameters become Fortran code via `case.py.__get_analytic_ic_fpp()`.
45+
These are compiled into the binary, so syntax errors cause build failures, not runtime errors.

0 commit comments

Comments
 (0)