Three caveats surfaced during walkthrough lived only in the conversation transcript before this commit. Now they live where future agents and future-me will actually see them: - reach_operation.m and reachability/README.md state prominently that the current reach tube is an over-approximation of the LINEAR model, not a sound tube for the nonlinear plant. Thesis-blocking for a real safety claim. Upgrade paths documented. - ctrl_heatup.m header and plant-model/CLAUDE.md note that the feedback-linearization u_ff assumes exact alpha_f, alpha_c. Real plants drift (burnup ~20%, boron ~10x, xenon). Robust treatment = parametric reach with alpha as an interval. - ctrl_heatup.m header and plant-model/CLAUDE.md note that sat() is formally a 3-mode piecewise-affine sub-system. Operation-mode LQR is dormant (trivially); heatup will need either a dormancy proof or explicit hybrid modeling. README.md top-level now has a run-commands table for the reach artifacts and a pointer to the soundness status. Hacker-Split: raise caveats from transcript to artifact so the work is actually reviewable by people who weren't in the room. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.8 KiB
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:
main % runs the default closed-loop scenario
From a terminal (figures appear as their own windows):
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_linearize.m numerical (A, B, B_w) at any x_star
pke_solver.m closed-loop driver (optional x0 arg)
plot_pke_results.m 4-panel results plot
load_profile.m canned Q_sg demand shapes
main.m entry point — single-mode scenarios
main_mode_sweep.m runs all DRC modes back-to-back
test_linearize.m sanity-check Jacobians vs nonlinear sim
controllers/
ctrl_null.m u = 0 (baseline, no feedback)
ctrl_shutdown.m hot standby: u = -5*beta (constant)
ctrl_heatup.m ramp T_avg: feedback lin. + P on ramp, saturated u
ctrl_operation.m stabilizing: P on T_avg
ctrl_operation_lqr.m full-state LQR around x_op (persistent-cached K)
ctrl_scram.m emergency: u = -8*beta (constant)
Controller contract:
u = ctrl_<mode>(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:
[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_sgis the disturbance, never an actuator. Cold leg temperature is a dynamic state resulting from SG heat removal — the reachability formulation needsQ_sg ∈ [Q_min, Q_max]as a bounded disturbance, not a control input.uis explicit.pke_th_rhstakesudirectly instead of readingp.rho_ext(t)from the params struct. This decouples plant from controller and matches the thesis'sf(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. ode15sis 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_avgis in °C). - Controllers are pure functions — no persistent state. If a mode ever
needs integral action, augment
xrather than hiding state in globals.
Model validity range
The feedback coefficients alpha_f, alpha_c are linear slopes taken
about the full-power operating point (T_f0, T_c0). They become
unphysical when extrapolated far from that reference — e.g. at true
cold shutdown (~50 C everywhere), the model predicts ~+5 $ intrinsic
reactivity that real reactors do not exhibit because temperature
coefficients saturate and flip sign in the cold-unborated state.
Trust range: roughly ±50 C around the operating point. "Shutdown" in this demo means hot standby (~290 C, n≈0), not cold shutdown. Extending to cold-shutdown semantics requires piecewise-linear or table-lookup temperature coefficients and is out of scope for the running example.
For reachability work
pke_th_rhs(t, x, plant, Q_sg, u)is theẋ = f(x, u)withQ_sgas the disturbancew. For a given mode, substituteu = ctrl_<mode>(t, x, plant, ref)to get the closed-loopẋ = f_cl(x, w).- Use
pke_linearize(plant, x_star, u_star, Q_star)for(A, B, B_w)at any operating point; returns central-finite-difference Jacobians. The result at the full-power point is saved to../reachability/linearization_at_op.matbytest_linearize.m. - Safe regions come from the FRET spec's guards (see
../fret-pipeline/specs/synthesis_config_v3.json) — these defineX_entry,X_exit,X_safeper the thesis approach. Numerical predicate thresholds still need to be pinned (see../claude_memory/notes for the discussion). - 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.
- First reach set is in
../reachability/reach_operation.m(operation mode under LQR); a Lyapunov-ellipsoid barrier-cert attempt is in../reachability/barrier_lyapunov.m.
For control design
- The LQR gain in
ctrl_operation_lqr.mis cached in a persistent variable. If you changeQ_lqrorR_lqror mutateplant, restart MATLAB to clear the cache. ctrl_heatup.muses feedback linearization + saturated P. No integrator on purpose — adding PI would double the plant's intrinsic thermal-mass integration and make anti-windup a hybrid mode, both bad for reach.- Starting heatup from a truly zero-power IC produces a large lag +
power-spike overshoot in the simulation. Physical resolution: the
reactor should be taken critical in shutdown mode (at ~0.1% power)
before DRC transitions to heatup.
main_mode_sweep.muses this IC.
Robustness caveats (idealized in current artifacts)
- α_f, α_c are treated as known exactly. In reality α_f drifts
~20% over burnup; α_c spans ~10x across soluble-boron dilution over
a cycle; xenon adds 2-3 $ reactivity on its own timescale. The
feedback-linearization in
ctrl_heatup.massumes the controller's α matches the plant's; if not, the cleanrho_total = Kp*eproperty degrades toKp*e + delta*alpha*dT, and the P term must absorb the residual. Stabilization still holds but reach analysis should eventually treat α as a bounded parametric uncertainty. - Saturation is a hybrid sub-mode. The
sat(u, u_min, u_max)inctrl_heatup.mis formally piecewise affine. Current reach treats it as dormant (true for operation/LQR, near-true for the demo heatup trajectory). A rigorous heatup reach has to model the saturation regions explicitly. - Linear-model reach is not sound for the nonlinear plant. The
reach artifacts in
../reachability/use the linearization; the result is a sound over-approximation of the LINEAR model's reach, not of the plant's. To upgrade: nonlinear reach directly, or linear reach + Taylor-remainder inflation. See../reachability/README.md§ Soundness status.