use crate::constants::cosmic::{HUBBLE_CONSTANT_SI, OMEGA_BARYON, OMEGA_MATTER};
use crate::constants::physical::{C, G, K_B, SIGMA_SB};
use std::f64::consts::PI;
pub fn ionization_fraction_equilibrium(
n_h_cm3: f64,
gamma_ion_s: f64,
alpha_rec_cm3_s: f64,
t_gas_k: f64,
) -> f64 {
let alpha = recombination_coefficient_case_b(t_gas_k);
let alpha_eff = if alpha_rec_cm3_s > 0.0 {
alpha_rec_cm3_s
} else {
alpha
};
let discriminant = (gamma_ion_s / (alpha_eff * n_h_cm3)).min(1e20);
discriminant / (1.0 + discriminant)
}
pub fn recombination_coefficient_case_b(t_gas_k: f64) -> f64 {
2.6e-13 * (t_gas_k / 1e4).powf(-0.76)
}
pub fn photoionization_rate_dm_annihilation(
sigma_v_cm3_s: f64,
rho_dm_gev_cm3: f64,
m_dm_gev: f64,
f_ion: f64,
e_ion_ev: f64,
) -> f64 {
let n_dm = rho_dm_gev_cm3 / m_dm_gev;
let energy_rate = 0.5 * n_dm * n_dm * sigma_v_cm3_s * 2.0 * m_dm_gev * 1e9;
f_ion * energy_rate / (e_ion_ev * 1e6)
}
pub fn photoionization_rate_dm_decay(
gamma_decay_s: f64,
rho_dm_gev_cm3: f64,
m_dm_gev: f64,
f_ion: f64,
e_ion_ev: f64,
) -> f64 {
let n_dm = rho_dm_gev_cm3 / m_dm_gev;
let energy_rate = n_dm * gamma_decay_s * m_dm_gev * 1e9;
f_ion * energy_rate / (e_ion_ev * 1e6)
}
pub fn optical_depth_reionization(x_e_fn: &dyn Fn(f64) -> f64, z_max: f64, n_steps: usize) -> f64 {
let sigma_t = 6.652e-29;
let n_h0 = 1.9e-7;
let dz = z_max / n_steps as f64;
let mut tau = 0.0;
for i in 0..n_steps {
let z = (i as f64 + 0.5) * dz;
let x_e = x_e_fn(z);
let h_z =
HUBBLE_CONSTANT_SI * (OMEGA_MATTER * (1.0 + z).powi(3) + (1.0 - OMEGA_MATTER)).sqrt();
let n_e = x_e * n_h0 * (1.0 + z).powi(3);
tau += sigma_t * n_e * C / h_z * dz / (1.0 + z);
}
tau
}
pub fn clumping_factor(z: f64) -> f64 {
let c = 26.2917;
let d = 6.14;
c * ((1.0 + z) / d).powf(-1.1)
}
pub fn ionizing_photon_rate_dm(
sigma_v_cm3_s: f64,
rho_dm_gev_cm3: f64,
m_dm_gev: f64,
f_gamma: f64,
) -> f64 {
let n_dm = rho_dm_gev_cm3 / m_dm_gev;
0.5 * n_dm * n_dm * sigma_v_cm3_s * f_gamma
}
pub fn stromgren_radius_dm_kpc(q_ion_s: f64, n_h_cm3: f64, alpha_rec: f64) -> f64 {
let r_cm = (3.0 * q_ion_s / (4.0 * PI * n_h_cm3 * n_h_cm3 * alpha_rec)).powf(1.0 / 3.0);
r_cm / 3.0857e21
}
pub fn reionization_redshift_approx(n_ion_per_baryon: f64, f_esc: f64, c_hii: f64) -> f64 {
let f_eff = n_ion_per_baryon * f_esc;
if f_eff < 1.0 {
return 6.0;
}
6.0 + 4.0 * ((f_eff / c_hii).ln()).max(0.0)
}
pub fn dm_heating_igm_temperature(
t_igm_k: f64,
sigma_v_cm3_s: f64,
rho_dm_gev_cm3: f64,
m_dm_gev: f64,
f_heat: f64,
n_b_cm3: f64,
dt_s: f64,
) -> f64 {
let n_dm = rho_dm_gev_cm3 / m_dm_gev;
let heat_rate_ev_cm3_s = 0.5 * n_dm * n_dm * sigma_v_cm3_s * 2.0 * m_dm_gev * 1e9 * f_heat;
let heat_per_baryon_ev = heat_rate_ev_cm3_s / n_b_cm3 * dt_s;
let delta_t = heat_per_baryon_ev * 1.602e-19 / (1.5 * K_B);
t_igm_k + delta_t
}
pub fn neutral_fraction_post_reionization(z: f64, z_reion: f64) -> f64 {
if z > z_reion {
return 1.0;
}
1e-4 * ((1.0 + z) / 4.0).powi(4)
}
pub fn lyman_alpha_optical_depth(x_hi: f64, z: f64) -> f64 {
let tau_gp = 7.16e5 * ((1.0 + z) / 10.0).powf(1.5);
tau_gp * x_hi
}
pub fn bubble_size_distribution_peak_mpc(z: f64, xi_ion: f64) -> f64 {
let r_0 = 5.0;
r_0 * (xi_ion / 40.0).powf(1.0 / 3.0) * ((1.0 + z) / 8.0).powf(-1.0)
}
pub fn mean_baryon_density_kg_m3(z: f64) -> f64 {
let rho_crit = 3.0 * HUBBLE_CONSTANT_SI * HUBBLE_CONSTANT_SI / (8.0 * PI * G);
rho_crit * OMEGA_BARYON * (1.0 + z).powi(3)
}
pub fn dm_annihilation_effective_temperature(
sigma_v_cm3_s: f64,
rho_dm_gev_cm3: f64,
m_dm_gev: f64,
r_sphere_m: f64,
) -> f64 {
let n_dm = rho_dm_gev_cm3 / m_dm_gev;
let power_density_gev = 0.5 * n_dm * n_dm * sigma_v_cm3_s * 2.0 * m_dm_gev;
let luminosity_w = power_density_gev * 1.602e-10 * 1e6 * 4.0 / 3.0 * PI * r_sphere_m.powi(3);
let area = 4.0 * PI * r_sphere_m * r_sphere_m;
(luminosity_w / (SIGMA_SB * area)).powf(0.25)
}