Dane Sabo cebf8c167a Initial umbrella repo: thesis + FRET pipeline + plant model with first controllers
Folds three previously-separate pieces into one preliminary-example repo
for the HAHACS thesis:

- thesis/ (submodule) → gitea Thesis.git — the PhD proposal
- fret-pipeline/ — FRET requirements to AIGER controller (was
  ~/Documents/fret_processing/; prior single-commit history abandoned
  per user decision)
- plant-model/ — 10-state PKE + lumped T/H PWR model (was
  ~/Documents/PKE_Playground/; never version-controlled before)
- presentations/2026DICE/ (submodule) → gitea 2026DICE.git
- reachability/, hardware/ — empty placeholders for Thrust 3 and HIL
- docs/architecture.md — how the discrete and continuous layers compose
- claude_memory/ — session notes and scratch knowledge pattern

Plant model refactored to thesis naming (x, plant, u, ref); pke_th_rhs
now takes u as an explicit arg instead of reading rho_ext from the
params struct. First two controllers built to the contract
u = ctrl_<mode>(t, x, plant, ref): ctrl_null (baseline) and
ctrl_operation (stabilizing, proportional on T_avg). Validated under a
100% -> 80% Q_sg step: ctrl_operation reduces steady-state T_avg drift
~47% vs. the unforced plant.

Root CLAUDE.md emphasizes that CLAUDE.md files are living documents and
that any knowledge not captured before a session ends is lost forever;
claude_memory/ holds the session-level notes that haven't stabilized
enough to graduate into a CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 16:24:11 -04:00

5.3 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_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:

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.

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_<mode>(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.