sciforge 0.0.3

A comprehensive scientific computing library in pure Rust with zero dependencies
Documentation
use super::nuclide::{AMU_TO_MEV, BOLTZMANN_KEV, Nuclide};
use crate::constants::{BARN, FERMI, MEV_TO_J};

pub fn q_value(reactants: &[&Nuclide], products: &[&Nuclide]) -> f64 {
    let mass_in: f64 = reactants.iter().map(|n| n.atomic_mass_amu()).sum();
    let mass_out: f64 = products.iter().map(|n| n.atomic_mass_amu()).sum();
    (mass_in - mass_out) * AMU_TO_MEV
}

pub fn coulomb_barrier(z1: u32, z2: u32, a1: u32, a2: u32) -> f64 {
    let e2 = 1.44;
    let r0 = 1.2;
    let r = r0 * ((a1 as f64).powf(1.0 / 3.0) + (a2 as f64).powf(1.0 / 3.0));
    e2 * z1 as f64 * z2 as f64 / r
}

pub fn gamow_peak(z1: u32, z2: u32, reduced_mass_amu: f64, temperature_k: f64) -> f64 {
    let kt = BOLTZMANN_KEV * temperature_k * 1e-3;
    let eg = 0.978 * (z1 as f64 * z2 as f64).powi(2) * reduced_mass_amu;
    (eg * kt * kt / 4.0).powf(1.0 / 3.0)
}

pub fn gamow_window_width(z1: u32, z2: u32, reduced_mass_amu: f64, temperature_k: f64) -> f64 {
    let e0 = gamow_peak(z1, z2, reduced_mass_amu, temperature_k);
    let kt = BOLTZMANN_KEV * temperature_k * 1e-3;
    4.0 * (e0 * kt / 3.0).sqrt()
}

pub fn reduced_mass_amu(m1: f64, m2: f64) -> f64 {
    m1 * m2 / (m1 + m2)
}

pub fn astrophysical_s_factor(
    cross_section_barn: f64,
    energy_kev: f64,
    z1: u32,
    z2: u32,
    mu_amu: f64,
) -> f64 {
    let eta = 0.1575 * z1 as f64 * z2 as f64 * (mu_amu / energy_kev).sqrt();
    let sommerfeld = (-2.0 * std::f64::consts::PI * eta).exp();
    if sommerfeld < 1e-300 {
        return 0.0;
    }
    cross_section_barn * energy_kev / sommerfeld
}

pub fn sommerfeld_parameter(z1: u32, z2: u32, energy_kev: f64, mu_amu: f64) -> f64 {
    0.1575 * z1 as f64 * z2 as f64 * (mu_amu / energy_kev).sqrt()
}

pub fn penetration_factor(z1: u32, z2: u32, energy_kev: f64, mu_amu: f64) -> f64 {
    let eta = sommerfeld_parameter(z1, z2, energy_kev, mu_amu);
    let two_pi_eta = 2.0 * std::f64::consts::PI * eta;
    if two_pi_eta > 700.0 {
        return 0.0;
    }
    two_pi_eta / (two_pi_eta.exp() - 1.0)
}

pub fn thermonuclear_rate(
    s_factor_kev_barn: f64,
    z1: u32,
    z2: u32,
    mu_amu: f64,
    temperature_k: f64,
) -> f64 {
    let kt = BOLTZMANN_KEV * temperature_k;
    let t9 = temperature_k / 1e9;
    let tau = 42.487 * (z1 as f64 * z2 as f64).powi(2) * mu_amu / t9;
    let tau_third = tau.powf(1.0 / 3.0);
    let prefactor = 7.831e9 / (mu_amu * t9 * t9).powf(1.0 / 6.0);
    let _ = kt;
    prefactor * s_factor_kev_barn * (-3.0 * tau_third).exp()
}

pub fn pp_rate_estimate(temperature_k: f64, density_g_cm3: f64, x_h: f64) -> f64 {
    let t9 = temperature_k / 1e9;
    let t9_13 = t9.powf(1.0 / 3.0);
    3.38e-18 * density_g_cm3 * x_h * x_h * t9.powf(-2.0 / 3.0) * (-3.381 / t9_13).exp()
}

pub fn triple_alpha_rate_estimate(temperature_k: f64, density_g_cm3: f64, y_he: f64) -> f64 {
    let t9 = temperature_k / 1e9;
    5.09e8 * density_g_cm3 * density_g_cm3 * y_he.powi(3) * t9.powf(-3.0) * (-4.4027 / t9).exp()
}

pub fn c12_alpha_rate_estimate(temperature_k: f64) -> f64 {
    let t9 = temperature_k / 1e9;
    let t9_13 = t9.powf(1.0 / 3.0);
    1.04e8 * t9.powf(-2.0 / 3.0) * (-32.12 / t9_13 - (t9 / 3.496).powi(2)).exp()
        + 1.76e8 * t9.powf(-2.0 / 3.0) * (-32.12 / t9_13).exp()
}

pub fn reaction_mean_free_path(cross_section_barn: f64, number_density_per_cm3: f64) -> f64 {
    1.0 / (cross_section_barn * 1e-24 * number_density_per_cm3)
}

pub fn nuclear_reaction_lifetime(
    cross_section_barn: f64,
    number_density_per_cm3: f64,
    velocity_cm_s: f64,
) -> f64 {
    1.0 / (cross_section_barn * 1e-24 * number_density_per_cm3 * velocity_cm_s)
}

pub fn maxwell_averaged_velocity(temperature_k: f64, mu_amu: f64) -> f64 {
    let mu_kg = mu_amu * crate::constants::AMU_TO_KG;
    (8.0 * crate::constants::K_B * temperature_k / (std::f64::consts::PI * mu_kg)).sqrt()
}

pub fn cross_section_barn_to_si(sigma_barn: f64) -> f64 {
    sigma_barn * BARN
}

pub fn nuclear_radius_fermi(a: u32) -> f64 {
    1.2 * FERMI * (a as f64).powf(1.0 / 3.0)
}

pub fn nuclear_volume(a: u32) -> f64 {
    let r = nuclear_radius_fermi(a);
    4.0 / 3.0 * std::f64::consts::PI * r.powi(3)
}

pub fn q_value_to_joules(q_mev: f64) -> f64 {
    q_mev * MEV_TO_J
}

pub fn geometric_cross_section(a1: u32, a2: u32) -> f64 {
    let r1 = 1.2 * FERMI * (a1 as f64).powf(1.0 / 3.0);
    let r2 = 1.2 * FERMI * (a2 as f64).powf(1.0 / 3.0);
    std::f64::consts::PI * (r1 + r2).powi(2)
}

pub fn geometric_cross_section_barn(a1: u32, a2: u32) -> f64 {
    geometric_cross_section(a1, a2) / BARN
}