Dane Sabo fbbaebff9f julia migration: port MATLAB to Julia, delete MATLAB, rename julia-port -> code
Full toolchain port. Numerical equivalence verified against MATLAB:
- main_mode_sweep.jl: every mode's final state matches MATLAB to 3-4 dp
- reach_operation.jl: per-halfspace margins match MATLAB exactly
- barrier_lyapunov.jl: per-halfspace bounds match (best Qbar from sweep
  yields max|dT_c| = 33.228 K either side)
- barrier_compare_OL_CL.jl: OL gamma 1.038e13, CL gamma 1.848e4
  matching the MATLAB result; LQR helps by ~20,000x on every halfspace.

Phase summary:
  Phase 1: pke_solver.jl, plot_pke_results.jl (Plots.jl), main_mode_sweep.jl
  Phase 2: reach_linear.jl, reach_operation.jl, barrier_lyapunov.jl,
           barrier_compare_OL_CL.jl, load_predicates.jl
  Phase 3 (this commit): delete plant-model/ entirely, delete reach
           code from reachability/ keeping predicates.json + docs,
           git mv julia-port/ -> code/, update root README + CLAUDE,
           write code/CLAUDE.md and code/README.md, update reach
           README + WALKTHROUGH file paths, journal preamble note
           that pre-port entries reference MATLAB paths.

Why now: prompt-neutron stiffness in nonlinear reach made it clear we
need TMJets, which is Julia. Already had the Julia plant model
working and matching MATLAB. Two languages = two sources of truth =
two places to drift. One language, one truth.

Manifest.toml gitignored. .mat results gitignored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 21:44:59 -04:00

99 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Reachability
Continuous-mode verification for the PWR_HYBRID_3 hybrid controller.
## Soundness status: APPROXIMATE
The current linear-reach results are **not a sound reach tube for
the physical plant**. They are sound over-approximations of the
*linearized* closed-loop system ($A_{\mathrm{cl}} = A - BK$ around
$x_{\mathrm{op}}$) under bounded disturbance. The linear model is
itself an approximation of the nonlinear plant (`../code/src/pke_th_rhs.jl`),
and that approximation error is not currently bounded or inflated
into the tube.
Two paths to upgrade to a sound result:
1. **Nonlinear reach directly** — TMJets (Taylor-model integration)
via ReachabilityAnalysis.jl. Currently limited to ~10-second
horizons by prompt-neutron stiffness; needs a reduced-order PKE
(prompt-jump approximation) to extend to mode-obligation horizons.
2. **Linear reach + Taylor-remainder inflation** — compute an upper
bound on `||f_nl(x, u) - (A x + B u)||` over the reach set and
inflate the linear tube by that bound. Cheaper, still rigorous.
Both are thesis-blocking for any safety claim. The current
5-orders-of-margin buffer (reach envelope ~0.03 K against a
5 K safety band on $T_c$) means linearization error would have to
be huge to invalidate the conclusion — but that's vibes, not a proof.
## Related open issues
- **Saturation semantics.** `ctrl_heatup.jl` uses `clamp(u, u_min, u_max)`.
Saturation is formally a 3-mode piecewise-affine system. For
heatup reach this must be handled as (a) hybrid locations, or
(b) proven dormant via reach on `u_unsat`. Not modeled in the
current artifacts (operation-mode LQR saturation is dormant in
practice but the proof is implicit).
- **Parametric uncertainty in α_f, α_c.** Real plants have α drift
with burnup (~20%), boron (α_c ranges 10×), xenon. The
feedback-linearization in `ctrl_heatup` assumes exact α; a robust
treatment would make α an interval and propagate parametric reach.
Currently idealized.
## What's here
**Per-mode only.** Following the compositionality argument in the
thesis: verify each continuous mode separately, let the DRC handle
discrete switching.
Files:
- `predicates.json` — single source of truth for predicate
concretizations. Three groups:
- `operational_deadbands` — soft bands used by DRC for mode
transitions (`t_avg_above_min`, `t_avg_in_range`, `p_above_crit`).
- `safety_limits` — hard one-sided halfspaces (fuel centerline,
trip setpoints, subcooling, heatup-rate bounds).
- `mode_invariants``inv1_holds`, `inv2_holds` as conjunctions
of safety limits.
- `mode_boundaries` — per-mode $X_{\mathrm{entry}}$, $X_{\mathrm{safe}}$,
$X_{\mathrm{exit}}$, $T_{\min}$, $T_{\max}$.
- `WALKTHROUGH.md` — standalone document explaining the reach-obligation
taxonomy, per-mode entry/exit definitions, current results, soundness
status. Read this for the full story.
The reach code itself lives in `../code/`:
- `../code/src/reach_linear.jl` — hand-rolled box reach propagator.
- `../code/src/load_predicates.jl` — reads `predicates.json`.
- `../code/scripts/reach_operation.jl` — operation-mode linear reach.
- `../code/scripts/barrier_lyapunov.jl` — Lyapunov barrier attempt.
- `../code/scripts/barrier_compare_OL_CL.jl` — OL vs CL comparison.
- `../code/scripts/reach_heatup_nonlinear.jl` — TMJets nonlinear reach
(heatup, saturation-disabled, 10-second horizon cap).
## Running
```bash
cd code
julia --project=. scripts/reach_operation.jl
julia --project=. scripts/barrier_lyapunov.jl
julia --project=. scripts/barrier_compare_OL_CL.jl
julia --project=. scripts/reach_heatup_nonlinear.jl
```
Results save here as `*.mat` (gitignored).
## What this does NOT do yet
- Any sound reach tube (see top of this file).
- Nonlinear reach on horizons > 10 s (needs reduced-order PKE).
- Shutdown, scram, initialization reach.
- Hybrid-system level verification (mode switching validity).
- Parametric robustness to α_f, α_c drift.
- Polytopic or SOS barriers — the canonical quadratic Lyapunov
barrier fails structurally on this plant (see `WALKTHROUGH.md`
and the OL-vs-CL comparison script).