use crate::constants::cosmic::{
HUBBLE_CONSTANT_SI, OMEGA_BARYON, OMEGA_DM, OMEGA_LAMBDA, OMEGA_MATTER,
};
use crate::constants::physical::{C, G, HBAR, K_B};
use std::f64::consts::PI;
pub const T_CMB_0: f64 = 2.7255;
pub const T_21CM_K: f64 = 0.068;
pub const A_10_S_INV: f64 = 2.85e-15;
pub const FREQ_21CM_MHZ: f64 = 1420.405;
pub fn brightness_temperature_21cm(x_hi: f64, delta_b: f64, t_spin_k: f64, z: f64) -> f64 {
let t_cmb = T_CMB_0 * (1.0 + z);
let factor = 27.0
* x_hi
* (1.0 + delta_b)
* (OMEGA_BARYON * 0.7 * 0.7 / 0.023).sqrt()
* ((1.0 + z) / 10.0 * 0.15 / (OMEGA_MATTER * 0.7 * 0.7)).sqrt();
factor * (1.0 - t_cmb / t_spin_k)
}
pub fn spin_temperature(t_cmb_k: f64, t_gas_k: f64, t_lya_k: f64, x_c: f64, x_alpha: f64) -> f64 {
let inv_t_s = (1.0 / t_cmb_k + x_c / t_gas_k + x_alpha / t_lya_k) / (1.0 + x_c + x_alpha);
1.0 / inv_t_s
}
pub fn collisional_coupling(n_h_cm3: f64, t_gas_k: f64, z: f64) -> f64 {
let kappa_hh = 3.1e-11 * t_gas_k.powf(0.357) * (-32.0 / t_gas_k).exp();
let t_star = T_21CM_K;
4.0 * t_star * n_h_cm3 * kappa_hh / (3.0 * A_10_S_INV * T_CMB_0 * (1.0 + z))
}
pub fn wouthuysen_field_coupling(j_alpha_cm2_s_hz_sr: f64, t_gas_k: f64) -> f64 {
let s_alpha = 1.0 - 0.0631789 / t_gas_k + 0.115995 / (t_gas_k * t_gas_k);
1.81e11 * s_alpha * j_alpha_cm2_s_hz_sr / (1.0 + 2.0 / t_gas_k)
}
pub fn gas_temperature_adiabatic(z: f64, z_dec: f64) -> f64 {
T_CMB_0 * (1.0 + z_dec) * ((1.0 + z) / (1.0 + z_dec)).powi(2)
}
pub fn dm_heating_gas_temperature(t_gas_k: f64, epsilon_heat_ev_s_baryon: f64, dt_s: f64) -> f64 {
let delta_t = epsilon_heat_ev_s_baryon * 1.602e-19 * dt_s / (1.5 * K_B);
t_gas_k + delta_t
}
pub fn dm_baryon_scattering_heating_rate(
sigma_0_cm2: f64,
m_dm_gev: f64,
m_b_gev: f64,
rho_dm_gev_cm3: f64,
t_dm_k: f64,
t_gas_k: f64,
v_rel_km_s: f64,
) -> f64 {
let sigma_si = sigma_0_cm2 * 1e-4;
let m_dm = m_dm_gev * 1.782_661_92e-27;
let m_b = m_b_gev * 1.782_661_92e-27;
let mu = m_dm * m_b / (m_dm + m_b);
let n_dm = rho_dm_gev_cm3 * 1.782_661_92e-27 * 1e6 / m_dm;
let v_th = ((K_B * t_gas_k / m_b + K_B * t_dm_k / m_dm).max(0.0)).sqrt();
let v_rel = v_rel_km_s * 1e3;
let v_eff = (v_rel * v_rel + v_th * v_th).sqrt();
2.0 * mu / (m_dm + m_b) * n_dm * sigma_si * v_eff * K_B * (t_dm_k - t_gas_k)
}
pub fn power_spectrum_21cm(k_mpc: f64, delta_tb: f64, bias_hi: f64, p_matter: f64) -> f64 {
let beam_suppression = (-0.5 * (k_mpc / 100.0).powi(2)).exp();
delta_tb * delta_tb * bias_hi * bias_hi * p_matter * beam_suppression
}
pub fn optical_depth_21cm(n_hi_cm2: f64, t_spin_k: f64) -> f64 {
5.9e-14 * n_hi_cm2 / t_spin_k
}
pub fn observed_frequency_mhz(z: f64) -> f64 {
FREQ_21CM_MHZ / (1.0 + z)
}
pub fn dark_ages_redshift_range() -> (f64, f64) {
(30.0, 200.0)
}
pub fn cosmic_dawn_redshift_range() -> (f64, f64) {
(6.0, 30.0)
}
pub fn global_signal_absorption_trough_mhz(z_trough: f64) -> f64 {
FREQ_21CM_MHZ / (1.0 + z_trough)
}
pub fn dm_21cm_excess_absorption(t_gas_standard_k: f64, t_gas_with_dm_k: f64, t_cmb_k: f64) -> f64 {
let tb_standard = 27.0 * (1.0 - t_cmb_k / t_gas_standard_k);
let tb_dm = 27.0 * (1.0 - t_cmb_k / t_gas_with_dm_k);
tb_dm - tb_standard
}
pub fn hubble_rate_21cm(z: f64) -> f64 {
HUBBLE_CONSTANT_SI
* (OMEGA_DM * (1.0 + z).powi(3) + OMEGA_BARYON * (1.0 + z).powi(3) + OMEGA_LAMBDA).sqrt()
}
pub fn comoving_distance_21cm_mpc(z: f64, n_steps: usize) -> f64 {
let dz = z / n_steps as f64;
let mut dist = 0.0;
for i in 0..n_steps {
let zp = (i as f64 + 0.5) * dz;
let h_z = hubble_rate_21cm(zp);
dist += C / h_z * dz;
}
dist / 3.0857e22
}
pub fn dm_mass_in_21cm_volume_kg(z_min: f64, z_max: f64) -> f64 {
let rho_crit = 3.0 * HUBBLE_CONSTANT_SI.powi(2) / (8.0 * PI * G);
let rho_dm = rho_crit * OMEGA_DM;
let z_mid = 0.5 * (z_min + z_max);
let d_com = C * (z_max - z_min) / hubble_rate_21cm(z_mid);
rho_dm * (1.0 + z_mid).powi(3) * d_com.powi(3)
}
pub fn de_broglie_smoothing_scale_mpc(m_dm_gev: f64, v_km_s: f64) -> f64 {
let m_kg = m_dm_gev * 1.782_661_92e-27;
let v = v_km_s * 1e3;
HBAR / (m_kg * v) / 3.0857e22
}
pub fn matter_density_at_z(z: f64) -> f64 {
let rho_crit = 3.0 * HUBBLE_CONSTANT_SI.powi(2) / (8.0 * PI * G);
rho_crit * OMEGA_MATTER * (1.0 + z).powi(3)
}