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>
60 lines
1.7 KiB
Julia
60 lines
1.7 KiB
Julia
"""
|
|
pke_th_rhs!(dx, x, t, plant, Q_sg, u)
|
|
|
|
In-place ODE RHS for the coupled PKE + thermal-hydraulics model.
|
|
Matches ../plant-model/pke_th_rhs.m term-for-term.
|
|
|
|
State x = [n, C1..C6, T_f, T_c, T_cold].
|
|
|
|
Arguments:
|
|
- `dx` : 10-element mutable output
|
|
- `x` : 10-element state
|
|
- `t` : time [s]
|
|
- `plant`: parameter NamedTuple from `pke_params`
|
|
- `Q_sg`: callable `Q_sg(t)` returning SG heat removal [W]
|
|
- `u` : scalar external reactivity [dk/k]
|
|
"""
|
|
function pke_th_rhs!(dx, x, t, plant, Q_sg, u)
|
|
n = x[1]
|
|
T_f = x[8]
|
|
T_c = x[9]
|
|
T_cold = x[10]
|
|
T_hot = 2 * T_c - T_cold
|
|
|
|
Qsg_t = Q_sg(t)
|
|
|
|
rho = u +
|
|
plant.alpha_f * (T_f - plant.T_f0) +
|
|
plant.alpha_c * (T_c - plant.T_c0)
|
|
|
|
# Neutronics
|
|
dx[1] = (rho - plant.beta) / plant.Lambda * n +
|
|
plant.lambda_i[1]*x[2] + plant.lambda_i[2]*x[3] +
|
|
plant.lambda_i[3]*x[4] + plant.lambda_i[4]*x[5] +
|
|
plant.lambda_i[5]*x[6] + plant.lambda_i[6]*x[7]
|
|
|
|
# Precursors
|
|
for i in 1:6
|
|
dx[1+i] = (plant.beta_i[i] / plant.Lambda) * n - plant.lambda_i[i] * x[1+i]
|
|
end
|
|
|
|
# Thermal-hydraulics
|
|
dx[8] = (plant.P0 * n - plant.hA * (T_f - T_c)) / (plant.M_f * plant.c_f)
|
|
dx[9] = (plant.hA * (T_f - T_c) - 2 * plant.W * plant.c_c * (T_c - T_cold)) /
|
|
(plant.M_c * plant.c_c)
|
|
dx[10] = (plant.W * plant.c_c * (T_hot - T_cold) - Qsg_t) /
|
|
(plant.M_sg * plant.c_c)
|
|
|
|
return nothing
|
|
end
|
|
|
|
"""
|
|
Convenience: allocating version (returns dx as a new vector). Useful in
|
|
scripts and tests; for hot-loop reachability use the in-place version.
|
|
"""
|
|
function pke_th_rhs(x, t, plant, Q_sg, u)
|
|
dx = similar(x)
|
|
pke_th_rhs!(dx, x, t, plant, Q_sg, u)
|
|
return dx
|
|
end
|