Dane Sabo d2997c2861 plant-model: add shutdown/heatup/scram controllers and LQR, linearize
Fill out the DRC mode set with ctrl_shutdown (u = -5*beta), ctrl_scram
(u = -8*beta), and ctrl_heatup (feedback-linearizing P on ramped T_avg
reference, saturated u, no integrator). Add ctrl_operation_lqr as a
full-state-feedback counterpart to ctrl_operation — K cached, closed-loop
essentially perfect under the 100%->80% Q_sg step where plain P has ~5F
overshoot.

Add pke_linearize for numerical (A, B, B_w) Jacobians at any operating
point; test_linearize confirms ~4e-4 rel err vs nonlinear sim for a
5% Q_sg step. Extend pke_solver with an optional x0 argument so each
mode can start from a plausible IC.

main_mode_sweep.m exercises all five modes back-to-back and saves the
4-panel plots. CLAUDE.md updated with model-validity-range note (trust
region is ~+/-50C around operating point; true cold shutdown is out of
scope for the linear feedback coefficients).

Hacker-Split: build out control layer end-to-end for reachability.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:52:03 -04:00

7.5 KiB
Raw Blame History

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_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 (~10100 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.

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) with Q_sg as the disturbance w. For a given mode, substitute u = 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.mat by test_linearize.m.
  • 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. 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.m is cached in a persistent variable. If you change Q_lqr or R_lqr or mutate plant, restart MATLAB to clear the cache.
  • ctrl_heatup.m uses 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.m uses this IC.