use core::f64::consts::PI;
use crate::aneutronic::Q_PB11;
use crate::fusion::KEV;
pub fn collector_efficiency(stages: usize, shift: f64) -> f64 {
let (n, e_max) = (800usize, 40.0);
let h = (e_max - shift) / n as f64;
let flux: Vec<(f64, f64)> = (0..n).map(|i| {
let e = shift + (i as f64 + 0.5) * h;
(e, (e - shift) * (-(e - shift)).exp())
}).collect();
let total: f64 = flux.iter().map(|(e, f)| e * f).sum();
let eff = |v: &[f64]| flux.iter().map(|(e, f)| f * v.iter().copied().filter(|x| x <= e).fold(0.0, f64::max)).sum::<f64>() / total;
let mut v: Vec<f64> = (0..stages).map(|k| shift + (k + 1) as f64).collect();
let mut step = 0.5;
while step > 0.01 {
let mut improved = false;
for k in 0..stages {
for d in [-step, step] {
let mut w = v.clone();
w[k] = (w[k] + d).max(0.0);
w.sort_by(f64::total_cmp);
if eff(&w) > eff(&v) + 1e-9 {
v = w;
improved = true;
}
}
}
if !improved {
step /= 2.0;
}
}
eff(&v)
}
pub fn q_eng_magnetic(q_sci: f64, eta_c: f64, eta_d: f64) -> f64 {
eta_c * eta_d * (q_sci + 1.0)
}
pub fn q_eng_inertial(gain: f64, eta_c: f64, eta_d: f64) -> f64 {
eta_c * eta_d * gain
}
pub fn pulsed_breakeven(eta_rec: f64, eta_dc: f64, f_ch: f64) -> f64 {
(1.0 - eta_rec) / (eta_dc * f_ch)
}
pub fn laser_pb11_gain(alphas_per_sr: f64, laser_energy: f64) -> f64 {
4.0 * PI * alphas_per_sr / 3.0 * Q_PB11 * 1e3 * KEV / laser_energy
}
#[cfg(test)]
mod tests {
use super::*;
fn close(a: f64, b: f64, rel: f64) -> bool {
(a / b - 1.0).abs() < rel
}
#[test]
fn collectors() {
for (stages, shift, expect) in [(1, 0.0, 0.419), (2, 0.0, 0.593), (8, 0.0, 0.824), (8, 5.0, 0.951)] {
let e = collector_efficiency(stages, shift);
assert!((e - expect).abs() < 0.003, "{stages} {shift}: {e}");
}
}
#[test]
fn plants() {
assert!(close(1.0 / (0.4 * 0.7) - 1.0, 2.571, 1e-3));
assert!((q_eng_magnetic(1.0 / (0.4 * 0.5) - 1.0, 0.4, 0.5) - 1.0).abs() < 1e-12);
assert!(close(0.4 * 8.6 / 400.0, 0.0086, 1e-9));
assert!(close(q_eng_inertial(140.0, 0.4, 0.07), 3.92, 1e-3));
assert!(close(pulsed_breakeven(0.95, 0.9, 0.95), 0.05848, 1e-3));
assert!(close(pulsed_breakeven(0.6, 0.9, 0.95), 0.4678, 1e-3));
}
#[test]
fn laser_proton_boron() {
assert!(close(laser_pb11_gain(5e9, 1.4e3), 2.081e-5, 2e-3));
assert!(close(laser_pb11_gain(1.7e9, 550.0), 1.801e-5, 2e-3));
}
}