use crate::constants::physical::G;
use std::f64::consts::PI;
pub fn velocity_dependent_cross_section(
v_km_s: f64,
sigma_0_cm2_g: f64,
v_ref_km_s: f64,
power_index: f64,
) -> f64 {
sigma_0_cm2_g * (v_km_s / v_ref_km_s).powf(power_index)
}
pub fn yukawa_cross_section(alpha_chi: f64, m_chi_gev: f64, m_phi_gev: f64, v_km_s: f64) -> f64 {
let v_si = v_km_s * 1e3;
let c = 3e8;
let beta = v_si / c;
let m_chi_kg = m_chi_gev * 1.782_661_92e-27;
let mu = m_chi_kg / 2.0;
let hbar = 1.054_571_817e-34;
let a = m_phi_gev / (2.0 * alpha_chi * m_chi_gev);
let b = m_chi_gev * beta / (2.0 * m_phi_gev);
if b < 0.1 {
let born_factor = a * a / (1.0 + a * a);
let sigma = 8.0 * PI * alpha_chi * alpha_chi
/ (m_phi_gev * m_phi_gev * 1.782_661_92e-27 * 1.782_661_92e-27)
* born_factor
* hbar
* hbar
/ (v_si * v_si * mu * mu + 1e-100);
return sigma * 1e4;
}
let ln_term = (1.0 + b * b).ln();
4.0 * PI * alpha_chi * alpha_chi
/ (m_chi_gev * m_chi_gev * 1.782_661_92e-27 * 1.782_661_92e-27 * beta.powi(4) * c.powi(4))
* (ln_term - b * b / (1.0 + b * b))
* hbar
* hbar
* 1e4
}
pub fn gravothermal_collapse_timescale(
rho_core_kg_m3: f64,
sigma_v_km_s: f64,
r_core_kpc: f64,
sigma_over_m_cm2_g: f64,
) -> f64 {
let sigma_v = sigma_v_km_s * 1e3;
let r_core = r_core_kpc * 3.0857e19;
let kappa = sigma_over_m_cm2_g * 1e-1 * rho_core_kg_m3 * sigma_v;
if kappa < 1e-50 {
return f64::INFINITY;
}
150.0 * sigma_v / (G * rho_core_kg_m3 * r_core * kappa)
}
pub fn core_radius_sidm(
rho_s_kg_m3: f64,
r_s_kpc: f64,
sigma_over_m_cm2_g: f64,
age_gyr: f64,
) -> f64 {
let t = age_gyr * 3.156e16;
let sigma_v = (4.0 * PI * G * rho_s_kg_m3 * (r_s_kpc * 3.0857e19).powi(2) / 3.0).sqrt();
let rate = sigma_over_m_cm2_g * 1e-1 * rho_s_kg_m3 * sigma_v;
let n_scatter = rate * t;
r_s_kpc * n_scatter.min(10.0).sqrt() * 0.5
}
pub fn isothermal_core_density(sigma_v_km_s: f64, r_core_kpc: f64) -> f64 {
let sigma_v = sigma_v_km_s * 1e3;
let r_core = r_core_kpc * 3.0857e19;
9.0 * sigma_v * sigma_v / (4.0 * PI * G * r_core * r_core)
}
pub fn sidm_heat_conductivity(
sigma_over_m_cm2_g: f64,
rho_kg_m3: f64,
sigma_v_km_s: f64,
mean_free_path_kpc: f64,
) -> f64 {
let sigma_v = sigma_v_km_s * 1e3;
let mfp = mean_free_path_kpc * 3.0857e19;
let l_eff = mfp.min(1.0 / (sigma_over_m_cm2_g * 1e-1 * rho_kg_m3 + 1e-100));
rho_kg_m3 * sigma_v * l_eff * sigma_v * sigma_v / 3.0
}
pub fn mean_free_path_kpc(sigma_over_m_cm2_g: f64, rho_kg_m3: f64) -> f64 {
let sigma_si = sigma_over_m_cm2_g * 1e-1;
1.0 / (sigma_si * rho_kg_m3 + 1e-100) / 3.0857e19
}
pub fn scattering_rate_per_gyr(sigma_over_m_cm2_g: f64, rho_kg_m3: f64, sigma_v_km_s: f64) -> f64 {
let sigma_si = sigma_over_m_cm2_g * 1e-1;
let sigma_v = sigma_v_km_s * 1e3;
sigma_si * rho_kg_m3 * sigma_v * 3.156e16
}
pub fn core_collapse_criterion(
sigma_over_m_cm2_g: f64,
rho_core_kg_m3: f64,
sigma_v_km_s: f64,
t_age_gyr: f64,
) -> bool {
let rate = scattering_rate_per_gyr(sigma_over_m_cm2_g, rho_core_kg_m3, sigma_v_km_s);
rate * t_age_gyr > 300.0
}
pub fn evaporation_rate(
sigma_over_m_cm2_g: f64,
m_sub_solar: f64,
rho_host_kg_m3: f64,
v_rel_km_s: f64,
r_sub_kpc: f64,
) -> f64 {
let sigma_si = sigma_over_m_cm2_g * 1e-1;
let v_rel = v_rel_km_s * 1e3;
let r_sub = r_sub_kpc * 3.0857e19;
let m_sub = m_sub_solar * 1.989e30;
let v_esc = (2.0 * G * m_sub / r_sub).sqrt();
let frac = (-v_esc * v_esc / (2.0 * v_rel * v_rel)).exp();
sigma_si * rho_host_kg_m3 * v_rel * PI * r_sub * r_sub * frac
}
pub fn bullet_cluster_offset_kpc(
sigma_over_m_cm2_g: f64,
sigma_dm_kg_m2: f64,
v_collision_km_s: f64,
) -> f64 {
let tau = sigma_over_m_cm2_g * 1e-1 * sigma_dm_kg_m2 / 1.989e30;
let v = v_collision_km_s * 1e3;
tau * v / 3.0857e19 * 1e-6
}
pub fn drag_deceleration(sigma_over_m_cm2_g: f64, rho_target_kg_m3: f64, v_rel_km_s: f64) -> f64 {
let sigma_si = sigma_over_m_cm2_g * 1e-1;
sigma_si * rho_target_kg_m3 * (v_rel_km_s * 1e3).powi(2)
}