use crate::constants::physical::{G, HBAR, K_B};
use std::f64::consts::PI;
pub fn fermi_dirac_dm(p_kg_m_s: f64, t_gev: f64, m_dm_gev: f64, mu_gev: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let c = 3e8;
let e = (p_kg_m_s * p_kg_m_s * c * c + m * m * c.powi(4)).sqrt();
let t_j = t_gev * 1.602e-10;
let mu_j = mu_gev * 1.602e-10;
1.0 / ((e - mu_j) / t_j).exp() + 1.0
}
pub fn bose_einstein_dm(p_kg_m_s: f64, t_gev: f64, m_dm_gev: f64, mu_gev: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let c = 3e8;
let e = (p_kg_m_s * p_kg_m_s * c * c + m * m * c.powi(4)).sqrt();
let t_j = t_gev * 1.602e-10;
let mu_j = mu_gev * 1.602e-10;
let exp_val = ((e - mu_j) / t_j).exp();
if exp_val <= 1.0 {
return 0.0;
}
1.0 / (exp_val - 1.0)
}
pub fn number_density_fermionic(t_gev: f64, m_dm_gev: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let c = 3e8;
let t_j = t_gev * 1.602e-10;
if t_j > m * c * c * 10.0 {
3.0 * 1.2021 / (4.0 * PI * PI) * (t_j / (HBAR * c)).powi(3)
} else {
let p_max = (2.0 * m * t_j * 10.0).sqrt();
let n_steps = 200;
let dp = p_max / n_steps as f64;
let mut n = 0.0;
for i in 0..n_steps {
let p = (i as f64 + 0.5) * dp;
let f = fermi_dirac_dm(p, t_gev, m_dm_gev, 0.0);
n += 4.0 * PI * p * p * f * dp / (2.0 * PI * HBAR).powi(3);
}
n
}
}
pub fn number_density_bosonic(t_gev: f64, m_dm_gev: f64) -> f64 {
let c = 3e8;
let m = m_dm_gev * 1.782_661_92e-27;
let t_j = t_gev * 1.602e-10;
if t_j > m * c * c * 10.0 {
1.2021 / (PI * PI) * (t_j / (HBAR * c)).powi(3)
} else {
let p_max = (2.0 * m * t_j * 10.0).sqrt();
let n_steps = 200;
let dp = p_max / n_steps as f64;
let mut n = 0.0;
for i in 0..n_steps {
let p = (i as f64 + 0.5) * dp;
let f = bose_einstein_dm(p, t_gev, m_dm_gev, 0.0);
n += 4.0 * PI * p * p * f * dp / (2.0 * PI * HBAR).powi(3);
}
n
}
}
pub fn tremaine_gunn_bound_ev(sigma_v_km_s: f64, r_halo_kpc: f64) -> f64 {
let sigma_v = sigma_v_km_s * 1e3;
let r = r_halo_kpc * 3.0857e19;
let m_min = (HBAR.powi(3) * 9.0 * PI / (G * r * r * sigma_v)).powf(0.25);
m_min / 1.782_661_92e-36
}
pub fn max_phase_space_density_fermionic(m_dm_gev: f64, g_dm: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
g_dm / (2.0 * PI * HBAR).powi(3) * m * m * m
}
pub fn coarse_grained_phase_space_density(rho_kg_m3: f64, sigma_v_m_s: f64) -> f64 {
rho_kg_m3 / (2.0 * PI * sigma_v_m_s * sigma_v_m_s).powf(1.5)
}
pub fn phase_space_constraint_satisfied(
rho_kg_m3: f64,
sigma_v_km_s: f64,
m_dm_gev: f64,
g_dm: f64,
) -> bool {
let sigma_v = sigma_v_km_s * 1e3;
let q = coarse_grained_phase_space_density(rho_kg_m3, sigma_v);
let q_max = max_phase_space_density_fermionic(m_dm_gev, g_dm);
q <= q_max
}
pub fn liouville_phase_space_density_nfw(rho_0: f64, sigma_v_km_s: f64) -> f64 {
let sigma_v = sigma_v_km_s * 1e3;
rho_0 / (2.0 * PI * sigma_v * sigma_v).powf(1.5)
}
pub fn warm_dm_free_streaming_cutoff_ev(t_dm_gev: f64, m_dm_gev: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let t_j = t_dm_gev * 1.602e-10;
let c = 3e8;
let v_rms = (3.0 * t_j / m).sqrt().min(c);
let k_fs = (4.0 * PI * G * m / v_rms).sqrt() / HBAR;
2.0 * PI / k_fs / 3.0857e22
}
pub fn king_distribution(e_total: f64, sigma_v: f64, rho_0: f64) -> f64 {
if e_total > 0.0 {
return 0.0;
}
let w2 = sigma_v * sigma_v;
rho_0 / (2.0 * PI * w2).powf(1.5) * ((-e_total / w2).exp() - 1.0)
}
pub fn isothermal_distribution(v_m_s: f64, sigma_v_m_s: f64) -> f64 {
let w2 = sigma_v_m_s * sigma_v_m_s;
(2.0 * PI * w2).powf(-1.5) * (-v_m_s * v_m_s / (2.0 * w2)).exp()
}
pub fn degenerate_fermi_pressure(m_dm_gev: f64, rho_kg_m3: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let n = rho_kg_m3 / m;
let p_f = HBAR * (3.0 * PI * PI * n).powf(1.0 / 3.0);
p_f * p_f * n / (5.0 * m)
}
pub fn chandrasekhar_mass_fermionic_dm(m_dm_gev: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let c = 3e8;
let m_pl2 = HBAR * c / G;
let m_ch = m_pl2 / (m * m) * (HBAR / (m * c)).sqrt() * 0.77;
m_ch / 1.989e30
}
pub fn phase_space_temperature(rho_kg_m3: f64, sigma_v_m_s: f64, m_dm_gev: f64) -> f64 {
let m = m_dm_gev * 1.782_661_92e-27;
let t_kinematic = m * sigma_v_m_s * sigma_v_m_s / K_B;
let n = rho_kg_m3 / m;
let lambda_db = HBAR / (m * sigma_v_m_s);
let degeneracy = n * lambda_db.powi(3);
t_kinematic * (1.0 + degeneracy)
}