use crate::constants::physical::{C, G, K_B};
use std::f64::consts::PI;
pub fn beta_model_density(rho_0: f64, r: f64, r_c: f64, beta: f64) -> f64 {
rho_0 * (1.0 + (r / r_c).powi(2)).powf(-3.0 * beta / 2.0)
}
pub fn beta_model_surface_brightness(s_0: f64, theta: f64, theta_c: f64, beta: f64) -> f64 {
s_0 * (1.0 + (theta / theta_c).powi(2)).powf(-3.0 * beta + 0.5)
}
pub fn beta_model_integrated_mass(rho_0: f64, r_c: f64, beta: f64, r: f64) -> f64 {
let x = r / r_c;
4.0 * PI * rho_0 * r_c.powi(3) * hypergeometric_integral(x, beta)
}
fn hypergeometric_integral(x: f64, beta: f64) -> f64 {
let steps = 500;
let dx = x / steps as f64;
let mut sum = 0.0;
for i in 0..steps {
let xi = (i as f64 + 0.5) * dx;
sum += xi * xi * (1.0 + xi * xi).powf(-3.0 * beta / 2.0) * dx;
}
sum
}
pub fn xray_luminosity_bremsstrahlung(n_e: f64, t_kelvin: f64, volume: f64) -> f64 {
1.4e-27 * t_kelvin.sqrt() * n_e * n_e * volume
}
pub fn cooling_time(n_e: f64, t_kelvin: f64) -> f64 {
let lambda = 1.4e-27 * t_kelvin.sqrt();
1.5 * n_e * K_B * t_kelvin / (n_e * n_e * lambda)
}
pub fn cooling_radius(r_200: f64, t_kelvin: f64, n_e_0: f64, age: f64) -> f64 {
let t_cool_center = cooling_time(n_e_0, t_kelvin);
if t_cool_center > age {
return 0.0;
}
r_200 * (t_cool_center / age).sqrt()
}
pub fn sz_y_parameter(n_e: f64, t_kelvin: f64, path_length: f64) -> f64 {
let sigma_t = 6.6524e-29;
let me_c2 = 0.511e6 * 1.602e-19;
sigma_t / me_c2 * n_e * K_B * t_kelvin * path_length
}
pub fn sz_temperature_decrement(y: f64, t_cmb: f64) -> f64 {
-2.0 * y * t_cmb
}
pub fn sz_kinetic_decrement(tau: f64, v_peculiar: f64, t_cmb: f64) -> f64 {
-tau * v_peculiar / C * t_cmb
}
pub fn sz_relativistic_correction(y: f64, t_e_kev: f64, t_cmb: f64) -> f64 {
let x_e = t_e_kev / 511.0;
-2.0 * y * t_cmb * (1.0 + 3.75 * x_e)
}
pub fn thermal_pressure(n_e: f64, t_kelvin: f64) -> f64 {
n_e * K_B * t_kelvin
}
pub fn entropy_profile(t_kev: f64, n_e_cm3: f64) -> f64 {
t_kev / n_e_cm3.powf(2.0 / 3.0)
}
pub const GAS_MASS_FRACTION_UNIVERSAL: f64 = 0.13;
pub const ICM_METALLICITY_TYPICAL: f64 = 0.3;
pub fn iron_mass_in_icm(m_gas: f64, metallicity_solar: f64) -> f64 {
let iron_solar_mass_fraction = 1.17e-3;
m_gas * metallicity_solar * iron_solar_mass_fraction
}
pub fn hydrostatic_equilibrium_temperature(m_total: f64, r: f64) -> f64 {
let mu = 0.6;
let mp = 1.673e-27;
G * m_total * mu * mp / (2.0 * K_B * r)
}
pub fn comptonization_parameter_integrated(
n_e_profile: impl Fn(f64) -> f64,
t_profile: impl Fn(f64) -> f64,
r_max: f64,
steps: usize,
) -> f64 {
let sigma_t = 6.6524e-29;
let me_c2 = 0.511e6 * 1.602e-19;
let dr = r_max / steps as f64;
let mut y = 0.0;
for i in 0..steps {
let r = (i as f64 + 0.5) * dr;
y += sigma_t * K_B * n_e_profile(r) * t_profile(r) / me_c2 * dr;
}
y
}
pub fn xray_surface_brightness_profile(
n_e_profile: impl Fn(f64) -> f64,
t_profile: impl Fn(f64) -> f64,
r_projected: f64,
r_max: f64,
steps: usize,
) -> f64 {
let dl = r_max / steps as f64;
let mut sb = 0.0;
for i in 0..steps {
let l = (i as f64 + 0.5) * dl;
let r = (r_projected * r_projected + l * l).sqrt();
if r < r_max {
let n_e = n_e_profile(r);
let t = t_profile(r);
sb += 1.4e-27 * t.sqrt() * n_e * n_e * dl;
}
}
2.0 * sb
}
pub fn cooling_flow_mass_rate(l_x: f64, t_kelvin: f64) -> f64 {
let mu = 0.6;
let mp = 1.673e-27;
2.0 * mu * mp * l_x / (5.0 * K_B * t_kelvin)
}
pub fn bondi_accretion_onto_bcg(m_bcg: f64, rho_icm: f64, cs: f64) -> f64 {
4.0 * PI * G * G * m_bcg * m_bcg * rho_icm / (cs * cs * cs)
}