use core::f64::consts::PI;
use metrology::{ALPHA, C, E_CHARGE, EPS_0, HBAR, KEV, M_E, MU_0};
const MEC2_KEV: f64 = M_E * C * C / KEV;
pub const E_SCHWINGER: f64 = M_E * M_E * C * C * C / (E_CHARGE * HBAR);
pub const B_SCHWINGER: f64 = E_SCHWINGER / C;
pub const Z_CRITICAL: f64 = 173.0;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Intensity {
Linear,
Peak,
}
impl Intensity {
fn factor(self) -> f64 {
match self {
Intensity::Linear => 0.5,
Intensity::Peak => 1.0,
}
}
}
pub fn critical_intensity(conv: Intensity) -> f64 {
conv.factor() * EPS_0 * C * E_SCHWINGER * E_SCHWINGER
}
pub fn peak_field(intensity: f64, conv: Intensity) -> f64 {
(intensity / (conv.factor() * EPS_0 * C)).sqrt()
}
pub fn schwinger_rate(e: f64) -> f64 {
ALPHA * EPS_0 * e * e / (PI * PI * HBAR) * (-PI * E_SCHWINGER / e).exp()
}
pub fn vacuum_decay_rate(e: f64) -> f64 {
let x = PI * E_SCHWINGER / e;
ALPHA * EPS_0 * e * e / (PI * PI * HBAR) * (1..200).map(|n| (-(n as f64) * x).exp() / (n * n) as f64).sum::<f64>()
}
pub fn schwinger_exponent(e: f64) -> f64 {
PI * E_SCHWINGER / e
}
pub fn a0(intensity: f64, wavelength: f64, conv: Intensity) -> f64 {
let omega = 2.0 * PI * C / wavelength;
E_CHARGE * peak_field(intensity, conv) / (M_E * C * omega)
}
pub fn chi_e(energy_gev: f64, a0: f64, photon_ev: f64, angle: f64) -> f64 {
let gamma = energy_gev * 1e6 / MEC2_KEV;
let beta = (1.0 - 1.0 / (gamma * gamma)).sqrt();
(1.0 + beta * angle.cos()) * gamma * a0 * photon_ev / (MEC2_KEV * 1e3)
}
pub fn ritus_narozhny(chi: f64) -> f64 {
ALPHA * chi.powf(2.0 / 3.0)
}
pub fn breit_wheeler_suppression(chi: f64) -> f64 {
(-8.0 / (3.0 * chi)).exp()
}
pub fn birefringence(b: f64) -> Option<f64> {
let a_e = 2.0 * ALPHA * ALPHA * HBAR.powi(3) / (45.0 * MU_0 * M_E.powi(4) * C.powi(5));
(b <= 0.1 * B_SCHWINGER).then_some(3.0 * a_e * b * b)
}
pub fn euler_heisenberg_fraction(e: f64) -> f64 {
ALPHA / (45.0 * PI) * (e / E_SCHWINGER).powi(2)
}
pub fn dirac_1s_binding(z: f64) -> Option<f64> {
let x = z * ALPHA;
(x < 1.0).then(|| MEC2_KEV * (1.0 - (1.0 - x * x).sqrt()))
}
pub fn graphene_critical_field(gap_ev: f64, v_f: f64) -> f64 {
(gap_ev * E_CHARGE).powi(2) / (E_CHARGE * HBAR * v_f)
}
#[cfg(test)]
mod tests {
use super::*;
fn close(a: f64, b: f64, rel: f64) -> bool {
(a / b - 1.0).abs() < rel
}
#[test]
fn critical_fields() {
assert!(close(E_SCHWINGER, 1.32329e18, 1e-5) && close(B_SCHWINGER, 4.41401e9, 1e-5));
assert!(close(critical_intensity(Intensity::Peak) * 1e-4, 4.64811e29, 1e-4));
assert!(close(critical_intensity(Intensity::Linear) * 1e-4, 2.32406e29, 1e-4));
}
#[test]
fn pair_production() {
let prefactor = ALPHA * EPS_0 * E_SCHWINGER * E_SCHWINGER / (PI * PI * HBAR);
assert!(close(prefactor, 1.08704e56, 1e-4));
assert!(close(PI * prefactor * 1e-6, 3.415e50, 1e-3));
assert!(close(vacuum_decay_rate(E_SCHWINGER) / schwinger_rate(E_SCHWINGER), 1.011016, 1e-5));
assert!(close(schwinger_rate(0.05 * E_SCHWINGER), 1.4017e26, 1e-3));
assert!(close(schwinger_rate(0.01 * E_SCHWINGER), 3.9683e-85, 1e-3));
}
#[test]
fn lasers_and_accelerators() {
let i = 1.1e27;
assert!(close(a0(i, 0.8e-6, Intensity::Linear), 226.84, 1e-4) && close(a0(i, 0.8e-6, Intensity::Peak), 160.40, 1e-4));
assert!(close(E_SCHWINGER / peak_field(i, Intensity::Linear), 1454.0, 1e-3));
assert!(close(schwinger_exponent(9.104e14), 4566.0, 1e-3));
assert!(close(chi_e(16.5, 7.9, 1.55, 17.2f64.to_radians()), 1.5127, 1e-3));
assert!(close(ritus_narozhny(1604.18), 1.0, 1e-4));
assert!(close(breit_wheeler_suppression(1.0), 6.9483e-2, 1e-4));
}
#[test]
fn vacuum_optics_and_heavy_atoms() {
assert!(close(birefringence(2.5).unwrap(), 2.48375e-23, 1e-4));
assert!(birefringence(B_SCHWINGER).is_none());
assert!(close(euler_heisenberg_fraction(0.1 * E_SCHWINGER), 5.16e-7, 2e-3));
assert!(close(dirac_1s_binding(82.0).unwrap(), 101.581, 1e-4) && close(dirac_1s_binding(92.0).unwrap(), 132.28, 1e-4));
assert!(dirac_1s_binding(138.0).is_none());
assert!(close(graphene_critical_field(0.2, 1e6), 6.077e7, 1e-3));
}
}