use crate::constants::physical::G;
use std::f64::consts::PI;
pub fn chandrasekhar_friction_acceleration(
m_satellite: f64,
rho_background: f64,
v_sat_km_s: f64,
sigma_v_km_s: f64,
coulomb_log: f64,
) -> f64 {
let v = v_sat_km_s * 1e3;
let sigma = sigma_v_km_s * 1e3;
let x = v / (sigma * 2.0_f64.sqrt());
let erf_x = crate::utils::math::erf_approx(x);
let derf = 2.0 * x / PI.sqrt() * (-x * x).exp();
let factor = erf_x - derf;
-4.0 * PI * G * G * m_satellite * rho_background * coulomb_log * factor / (v * v * v)
}
pub fn coulomb_logarithm(m_host: f64, m_sat: f64, r: f64, v: f64) -> f64 {
let b_max = r * m_host / (m_host + m_sat);
let b_min = G * m_sat / (v * v);
if b_min >= b_max || b_min <= 0.0 {
return 1.0;
}
(b_max / b_min).ln()
}
pub fn dynamical_friction_timescale_gyr(
m_satellite_solar: f64,
m_host_solar: f64,
r_orbit_kpc: f64,
v_circ_km_s: f64,
coulomb_log: f64,
) -> f64 {
let m_sat = m_satellite_solar * 1.989e30;
let m_host = m_host_solar * 1.989e30;
let r = r_orbit_kpc * 3.0857e19;
let v = v_circ_km_s * 1e3;
let tau = 1.17 * r * r * v / (G * m_sat * coulomb_log) * (m_host / m_sat);
tau / 3.156e16
}
pub fn orbital_decay_radius(
r_initial_kpc: f64,
t_gyr: f64,
m_satellite_solar: f64,
m_host_solar: f64,
v_circ_km_s: f64,
coulomb_log: f64,
) -> f64 {
let tau = dynamical_friction_timescale_gyr(
m_satellite_solar,
m_host_solar,
r_initial_kpc,
v_circ_km_s,
coulomb_log,
);
if tau < 1e-20 {
return 0.0;
}
r_initial_kpc * (1.0 - t_gyr / tau).max(0.0).powf(0.5)
}
pub fn velocity_dependent_friction(
m_satellite: f64,
rho_background: f64,
v_sat_km_s: f64,
sigma_v_km_s: f64,
coulomb_log: f64,
power_index: f64,
) -> f64 {
let base = chandrasekhar_friction_acceleration(
m_satellite,
rho_background,
v_sat_km_s,
sigma_v_km_s,
coulomb_log,
);
let v_ratio = v_sat_km_s / sigma_v_km_s;
base * v_ratio.powf(power_index)
}
pub fn friction_energy_loss_per_orbit(
m_satellite_solar: f64,
rho_avg_kg_m3: f64,
v_orbit_km_s: f64,
sigma_v_km_s: f64,
r_orbit_kpc: f64,
coulomb_log: f64,
) -> f64 {
let m_sat = m_satellite_solar * 1.989e30;
let v = v_orbit_km_s * 1e3;
let r = r_orbit_kpc * 3.0857e19;
let a_fric = chandrasekhar_friction_acceleration(
m_sat,
rho_avg_kg_m3,
v_orbit_km_s,
sigma_v_km_s,
coulomb_log,
);
let orbit_period_s = 2.0 * PI * r / v;
a_fric.abs() * m_sat * v * orbit_period_s
}
pub fn sinking_timescale_isothermal_gyr(
r_kpc: f64,
v_circ_km_s: f64,
m_sat_solar: f64,
coulomb_log: f64,
) -> f64 {
let r = r_kpc * 3.0857e19;
let v = v_circ_km_s * 1e3;
let m_sat = m_sat_solar * 1.989e30;
let sigma = v / 2.0_f64.sqrt();
let rho = sigma * sigma / (2.0 * PI * G * r * r);
let a = chandrasekhar_friction_acceleration(
m_sat,
rho,
v_circ_km_s,
v_circ_km_s / 2.0_f64.sqrt(),
coulomb_log,
);
if a.abs() < 1e-100 {
return f64::INFINITY;
}
(v / a.abs()) / 3.156e16
}
pub fn friction_in_cored_halo(
m_satellite: f64,
rho_core: f64,
r_core_kpc: f64,
v_sat_km_s: f64,
r_sat_kpc: f64,
) -> f64 {
let r_c = r_core_kpc * 3.0857e19;
let r = r_sat_kpc * 3.0857e19;
let v = v_sat_km_s * 1e3;
if r < r_c {
let enclosed_mass = 4.0 / 3.0 * PI * rho_core * r.powi(3);
let coulomb_log = (r_c / (G * m_satellite / (v * v))).ln().max(1.0);
-4.0 * PI * G * G * m_satellite * rho_core * coulomb_log / (v * v) * enclosed_mass
/ (enclosed_mass + m_satellite)
} else {
let coulomb_log = (r / (G * m_satellite / (v * v))).ln().max(1.0);
chandrasekhar_friction_acceleration(
m_satellite,
rho_core,
v_sat_km_s,
v_sat_km_s / 2.0_f64.sqrt(),
coulomb_log,
)
}
}
pub fn core_stalling_radius_kpc(
m_satellite_solar: f64,
rho_core_kg_m3: f64,
r_core_kpc: f64,
) -> f64 {
let m_sat = m_satellite_solar * 1.989e30;
let r_core = r_core_kpc * 3.0857e19;
let m_enclosed_core = 4.0 / 3.0 * PI * rho_core_kg_m3 * r_core.powi(3);
let r_stall = r_core * (m_sat / m_enclosed_core).powf(1.0 / 3.0);
r_stall / 3.0857e19
}