darkmatter 0.0.1

Dark matter simulation engine — gravitational fields, particle dynamics, halo stability, and cosmological constants
Documentation
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
}