darkmatter 0.0.1

Dark matter simulation engine — gravitational fields, particle dynamics, halo stability, and cosmological constants
Documentation
use std::f64::consts::PI;

pub fn dn_dgamma_bb(e_gamma_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_gamma_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    let a = 0.73;
    let b = 7.64;
    let c = 0.26;
    let n0 = 0.42;
    n0 * x.powf(-1.5) * (-b * x).exp() * (1.0 + a * x.ln()).powi(2)
        / (m_dm_gev * (1.0 + c * (-x.ln()).powi(2)))
}

pub fn dn_dgamma_tautau(e_gamma_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_gamma_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    let n0 = 0.27;
    let a = 2.2;
    let b = 6.8;
    n0 * x.powf(-1.3) * (-b * x.powf(0.7)).exp() * (1.0 + a * x) / m_dm_gev
}

pub fn dn_dgamma_ww(e_gamma_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_gamma_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 || m_dm_gev < 80.4 {
        return 0.0;
    }
    let n0 = 0.50;
    let b = 7.2;
    n0 * x.powf(-1.5) * (-b * x).exp() / m_dm_gev
}

pub fn dn_dgamma_mumu(e_gamma_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_gamma_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    let alpha = 1.0 / 137.0;
    2.0 * alpha / (3.0 * PI * m_dm_gev) * ((1.0 - x) / x) * (1.0 + (1.0 - x).powi(2)) / (2.0 * x)
}

pub fn positron_spectrum_bb(e_positron_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_positron_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    let n0 = 0.60;
    let alpha_e = 1.8;
    let beta_e = 5.5;
    n0 * x.powf(-alpha_e) * (-beta_e * x).exp() / m_dm_gev
}

pub fn positron_spectrum_tautau(e_positron_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_positron_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    let n0 = 0.33;
    let a = 1.5;
    let b = 4.6;
    n0 * x.powf(-a) * (-b * x.powf(0.8)).exp() / m_dm_gev
}

pub fn antiproton_spectrum_bb(e_pbar_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_pbar_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 || m_dm_gev < 10.0 {
        return 0.0;
    }
    let n0 = 0.17;
    let a = 1.2;
    let b = 9.0;
    n0 * x.powf(-a) * (-b * x).exp() * (1.0 - x).powi(3) / m_dm_gev
}

pub fn antiproton_spectrum_ww(e_pbar_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_pbar_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 || m_dm_gev < 80.4 {
        return 0.0;
    }
    let n0 = 0.20;
    let a = 1.3;
    let b = 8.5;
    n0 * x.powf(-a) * (-b * x).exp() * (1.0 - x).powi(2) / m_dm_gev
}

pub fn neutrino_spectrum_bb(e_nu_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_nu_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    let n0 = 0.55;
    let a = 1.6;
    let b = 6.0;
    n0 * x.powf(-a) * (-b * x).exp() / m_dm_gev
}

pub fn neutrino_spectrum_tautau(e_nu_gev: f64, m_dm_gev: f64) -> f64 {
    let x = e_nu_gev / m_dm_gev;
    if x <= 0.0 || x >= 1.0 {
        return 0.0;
    }
    0.18 * (1.0 - x).powi(2) * x.powf(-0.8) / m_dm_gev
}

pub fn total_photon_yield_bb(m_dm_gev: f64, n_steps: usize) -> f64 {
    let e_min = 1e-3_f64;
    let e_max = m_dm_gev * 0.999;
    let d_log_e = (e_max / e_min).ln() / n_steps as f64;
    let mut yield_total = 0.0;
    for i in 0..n_steps {
        let log_e = e_min.ln() + (i as f64 + 0.5) * d_log_e;
        let e = log_e.exp();
        let dn = dn_dgamma_bb(e, m_dm_gev);
        yield_total += dn * e * d_log_e;
    }
    yield_total
}

pub fn total_photon_yield_tautau(m_dm_gev: f64, n_steps: usize) -> f64 {
    let e_min = 1e-3_f64;
    let e_max = m_dm_gev * 0.999;
    let d_log_e = (e_max / e_min).ln() / n_steps as f64;
    let mut yield_total = 0.0;
    for i in 0..n_steps {
        let log_e = e_min.ln() + (i as f64 + 0.5) * d_log_e;
        let e = log_e.exp();
        let dn = dn_dgamma_tautau(e, m_dm_gev);
        yield_total += dn * e * d_log_e;
    }
    yield_total
}

pub fn differential_flux_gamma(
    dn_de: f64,
    sigma_v_cm3_s: f64,
    j_factor_gev2_cm5: f64,
    m_dm_gev: f64,
) -> f64 {
    sigma_v_cm3_s * j_factor_gev2_cm5 * dn_de / (8.0 * PI * m_dm_gev * m_dm_gev)
}

pub fn differential_flux_decay(
    dn_de: f64,
    decay_rate_s: f64,
    d_factor_gev_cm2: f64,
    m_dm_gev: f64,
) -> f64 {
    decay_rate_s * d_factor_gev_cm2 * dn_de / (4.0 * PI * m_dm_gev)
}

pub fn integrated_flux_above_threshold(
    m_dm_gev: f64,
    sigma_v_cm3_s: f64,
    j_factor_gev2_cm5: f64,
    e_threshold_gev: f64,
    channel: &str,
    n_steps: usize,
) -> f64 {
    let e_max = m_dm_gev * 0.999;
    if e_threshold_gev >= e_max {
        return 0.0;
    }
    let d_log_e = (e_max / e_threshold_gev).ln() / n_steps as f64;
    let mut flux = 0.0;
    for i in 0..n_steps {
        let log_e = e_threshold_gev.ln() + (i as f64 + 0.5) * d_log_e;
        let e = log_e.exp();
        let dn = match channel {
            "bb" => dn_dgamma_bb(e, m_dm_gev),
            "tautau" => dn_dgamma_tautau(e, m_dm_gev),
            "ww" => dn_dgamma_ww(e, m_dm_gev),
            "mumu" => dn_dgamma_mumu(e, m_dm_gev),
            _ => 0.0,
        };
        flux +=
            differential_flux_gamma(dn, sigma_v_cm3_s, j_factor_gev2_cm5, m_dm_gev) * e * d_log_e;
    }
    flux
}

pub fn branching_ratio_weighted_spectrum(
    e_gamma_gev: f64,
    m_dm_gev: f64,
    br_bb: f64,
    br_tautau: f64,
    br_ww: f64,
) -> f64 {
    br_bb * dn_dgamma_bb(e_gamma_gev, m_dm_gev)
        + br_tautau * dn_dgamma_tautau(e_gamma_gev, m_dm_gev)
        + br_ww * dn_dgamma_ww(e_gamma_gev, m_dm_gev)
}