# Nuclei NAD
## Purpose
`nucleide-nuclei`: canonical nucid representation, element/naming tables,
name dialects, particle and reaction-name registries, and static nuclear
reference data (`src/data/`) — plus two runtime-parsed packs: the EPA FGR 15
external-dosimetry tables (`src/fgr15.rs`) and the IAEA IRDFF-II
dosimetry-response pack (`src/irdff.rs`, v1 foil subset + v2 extension).
## Ownership
This file owns the FGR 15 and IRDFF-II modules' distribution and parsing
contracts.
Nucid conventions, dialects, and the vendored TSV tables stay documented in
`src/lib.rs`, `src/dialects.rs`, and `src/data.rs` (change those docs with
the code).
## Local Contracts
- **Nothing from the EPA FGR 15 file is committed to the repository**: no
TSV extracts, no fixture copies, no generated tables. The zip is fetched
at runtime by `python/nucleide/data.py::fetch_fgr15`, pinned to the
SHA-256 in `python/nucleide/data.py` (`FGR15_SHA256`), and member text is
passed to `fgr15::parse_table` (no network or HTTP in this crate).
- **Tests use synthetic hand-built tables only** (see `fgr15.rs` tests and
`tests/test_fgr15.py`), in the exact `Table_4_*.DAT` layout. Never copy
real EPA content into a test.
- **Parsing is strict and loud**: data rows are `Symbol-A[letter]` +
exactly six finite floats; element separators, dashed separators, and
blank lines are structural; BOM/zero-width characters are stripped; rows
are never silently skipped, duplicates error, and the row total must equal
the caller's `expected_rows` (1,252 for the published tables). The units
string is recorded verbatim from the header — never hardcode a units
wording.
- **Isomer names** follow the repo-wide `mnopqrstuvxyz` letter convention
(`m` → state 1, `n` → state 2); the FGR 15 spelling (`Ba-137m`,
`Sb-124n`) is the module's public name dialect.
- **Screening-level only** — not for safety decisions (EPA screening
context; say so in user-facing docs and docstrings).
- **Nothing from the IAEA IRDFF-II files is committed to the repository**
(same distribution contract as FGR 15): the `IRDFF-II_g725.zip` is fetched
at runtime by `python/nucleide/data.py::fetch_irdff`, pinned to the
SHA-256 in `python/nucleide/data.py` (`IRDFF_SHA256`), and member text is
passed to `irdff::parse_g725` (no network or HTTP in this crate). The v1
pack covers the eight named foil reactions (`V1_REACTIONS`, `MF=3`
sections only) over the SAND-II 725-group structure; the v2 extension
(`V2_REACTIONS`) adds the 26 further named `MF=3` dosimetry sections of the
same pinned zip (same URL + SHA-256, same cache, same loud
offline/mismatch errors). `MF=10` isomer sections stay out of the
registry. Rows feed `unfold.sandii`/`staysl`/`gravel` unchanged.
- **IRDFF tests use synthetic hand-built sections only** (see `irdff.rs`
tests), in the exact `MF=3` layout. Never copy real IAEA content into a
test. The head card's `L2` field is `0` on most sections but `99` on three
sections of the pinned file (notably v1's `56Fe(n,p)`); the parser accepts
`0` or `99` there and rejects anything else loudly.
## Work Guidance
- Extend `fgr15.rs` (parser, scenario/age enums, `Fgr15Table`) rather than
`data.rs` — FGR 15 is runtime-parsed, not a vendored TSV.
- A new EPA revision means: update `FGR15_URL`/`FGR15_SHA256` in
`python/nucleide/data.py`, bump the row-count expectation if the nuclide
census changed, and refresh the spots in
`validation/nuclear_data_vs_refs.py` together, in one change.
- Out of scope for v1: `Nuclide_Coefficients/` 28-tissue tables,
`Mono_Coefficients/` monoenergetic photons, biokinetic modeling.
## Verification
- `cargo test -p nucleide-nuclei` (synthetic fgr15/irdff tests live
in-module).
- `ruff format --check`, `ruff check`, and `mypy` clean for the Python
facade (`python/nucleide/nuclei.py`, `python/nucleide/data.py`) and
`tests/test_fgr15.py`.
- `python3 scripts/gen-reference.py --check` after touching the facade.
## Child NAD Index
None.