# CLAUDE.md Guidance for Claude Code (and any AI agent) working in this subdirectory. See also: the parent repo's `CLAUDE.md` (living-documentation rule — update this file when new knowledge is created) and `claude_memory/` for session notes that haven't yet earned a place here. ## What this is A 10-state point kinetic equation (PKE) model of a PWR coupled with lumped-parameter thermal-hydraulics, plus mode-specific continuous controllers. Implements the *plant* and the *tactical* layer of the HAHACS methodology — see `../thesis/3-research-approach/approach.tex` sections on transitory, stabilizing, and expulsory modes. The model is being developed for hybrid-systems reachability analysis. The end goal is barrier-certificate and reachability methods (in `../reachability/`) to prove each continuous mode satisfies its obligations under bounded `Q_sg(t)` variations. ## Naming convention (thesis-aligned) Continuous state and control-theory notation matches the thesis: | Symbol | Meaning | |---|---| | `t` | time [s] | | `x` | continuous state vector, `[n; C1..C6; T_f; T_c; T_cold]` | | `plant` | parameter struct from `pke_params()` (was `p` — renamed to avoid collision with `p_i` predicates) | | `u` | control input: external rod reactivity [dk/k] | | `Q_sg` | bounded disturbance: SG heat removal [W], as a function handle `Q_sg(t)` | | `ref` | reference/setpoint struct (e.g. `ref.T_avg`) | `T_avg = T_c` (algebraic alias); `T_hot = 2*T_c - T_cold` (linear coolant profile assumption). ## Running From inside MATLAB: ```matlab main % runs the default closed-loop scenario ``` From a terminal (figures appear as their own windows): ```bash matlab -nodesktop -nosplash -r "main" # drops at >> prompt; `exit` to quit matlab -r "main" & # full IDE, backgrounded matlab -batch "main" # headless sanity check (no figures shown) ``` `main.m` configures the scenario (plant, `Q_sg`, ref, tspan), picks a controller, and calls `pke_solver`. Tested on MATLAB R2025b; works on any MATLAB with `ode15s` (R2020b or newer). ## Architecture ``` plant-model/ pke_params.m plant parameters and derived steady state pke_initial_conditions.m analytic equilibrium x0 from plant pke_th_rhs.m dynamics: dx/dt = f(t, x, plant, Q_sg, u) pke_solver.m closed-loop driver; takes a controller fn handle plot_pke_results.m 4-panel results plot load_profile.m canned Q_sg demand shapes main.m entry point — scenario config + run controllers/ ctrl_null.m u = 0 (baseline, no feedback) ctrl_operation.m stabilizing: P on T_avg (future: ctrl_heatup, ctrl_scram, ctrl_shutdown) ``` **Controller contract:** ```matlab u = ctrl_(t, x, plant, ref) ``` Pure function. Returns scalar `u` (external rod reactivity in `dk/k`). All four signature args are required even if unused — lets the solver swap controllers by function handle without caring which one it is. **Solver contract:** ```matlab [t, X, U] = pke_solver(plant, Q_sg, ctrl_fn, ref, tspan) ``` Builds the closed-loop RHS internally, calls `ode15s`, then reconstructs the control trajectory `U` by re-evaluating `ctrl_fn` at each returned time step. For event-driven or hysteretic controllers, this reconstruction may miss interior solver evaluations — revisit if / when that matters. ## Key design decisions - **`Q_sg` is the disturbance, never an actuator.** Cold leg temperature is a dynamic state resulting from SG heat removal — the reachability formulation needs `Q_sg ∈ [Q_min, Q_max]` as a bounded disturbance, not a control input. - **`u` is explicit.** `pke_th_rhs` takes `u` directly instead of reading `p.rho_ext(t)` from the params struct. This decouples plant from controller and matches the thesis's `f(x, u)` formulation. - **Controller gains live in the controller file.** Rough-out phase — we'll lift to a config struct once we're tuning more than one mode. The gain in `ctrl_operation` (`Kp = 1e-4 /K`) is chosen to roughly double the effective moderator coefficient, not for precision tracking. - **`ode15s` is required** because the system is stiff: `Lambda` (~10⁻⁴ s) vs thermal time constants (~10–100 s). ## Conventions - One function per file, each file has a single responsibility. - Internal model uses SI (W, kg, °C); all printed/plotted temperatures in °F. - Reference setpoints in SI (so `ref.T_avg` is in °C). - Controllers are pure functions — no persistent state. If a mode ever needs integral action, augment `x` rather than hiding state in globals. ## For reachability work (next chapter) - `pke_th_rhs(t, x, plant, Q_sg, u)` is the `ẋ = f(x, u)` with `Q_sg` as the disturbance `w`. For a given mode, substitute `u = ctrl_(t, x, plant, ref)` to get the closed-loop `ẋ = f_cl(x, w)`. - Linearize around `x0` from `pke_initial_conditions(plant)` for `A, B, B_w` matrices when a linear reach set is enough. - Safe regions come from the FRET spec's guards (see `../fret-pipeline/specs/synthesis_config_v3.json`) — these define `X_entry`, `X_exit`, `X_safe` per the thesis approach. - Do NOT try to verify the whole hybrid system at once. Pick one mode, compute its reach set, discharge the per-mode obligation. The compositionality argument in the thesis is what makes this tractable.