darkmatter 0.0.2

Dark matter simulation engine — gravitational fields, particle dynamics, halo stability, and cosmological constants
Documentation
use crate::constants::physical::{C, K_B};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DarkMatterParticle {
    pub mass_kg: f64,
    pub position: [f64; 3],
    pub velocity: [f64; 3],
}

impl DarkMatterParticle {
    pub fn new(mass_kg: f64, position: [f64; 3], velocity: [f64; 3]) -> Self {
        Self {
            mass_kg,
            position,
            velocity,
        }
    }

    pub fn kinetic_energy(&self) -> f64 {
        let v2 = self.velocity[0] * self.velocity[0]
            + self.velocity[1] * self.velocity[1]
            + self.velocity[2] * self.velocity[2];
        0.5 * self.mass_kg * v2
    }

    pub fn speed(&self) -> f64 {
        let v2 = self.velocity[0] * self.velocity[0]
            + self.velocity[1] * self.velocity[1]
            + self.velocity[2] * self.velocity[2];
        v2.sqrt()
    }

    pub fn lorentz_factor(&self) -> f64 {
        let v = self.speed();
        let beta = v / C;
        1.0 / (1.0 - beta * beta).sqrt()
    }

    pub fn relativistic_mass(&self) -> f64 {
        self.mass_kg * self.lorentz_factor()
    }

    pub fn momentum(&self) -> [f64; 3] {
        [
            self.mass_kg * self.velocity[0],
            self.mass_kg * self.velocity[1],
            self.mass_kg * self.velocity[2],
        ]
    }

    pub fn advance(&mut self, dt: f64, acceleration: [f64; 3]) {
        self.velocity[0] += acceleration[0] * dt;
        self.velocity[1] += acceleration[1] * dt;
        self.velocity[2] += acceleration[2] * dt;
        self.position[0] += self.velocity[0] * dt;
        self.position[1] += self.velocity[1] * dt;
        self.position[2] += self.velocity[2] * dt;
    }

    pub fn distance_to(&self, other: &DarkMatterParticle) -> f64 {
        let dx = self.position[0] - other.position[0];
        let dy = self.position[1] - other.position[1];
        let dz = self.position[2] - other.position[2];
        (dx * dx + dy * dy + dz * dz).sqrt()
    }
}

pub fn maxwell_boltzmann_speed_rms(temperature: f64, mass_kg: f64) -> f64 {
    (3.0 * K_B * temperature / mass_kg).sqrt()
}

pub fn maxwell_boltzmann_speed_peak(temperature: f64, mass_kg: f64) -> f64 {
    (2.0 * K_B * temperature / mass_kg).sqrt()
}

pub fn velocity_dispersion_1d(temperature: f64, mass_kg: f64) -> f64 {
    (K_B * temperature / mass_kg).sqrt()
}

pub fn jeans_mass(temperature: f64, particle_mass_kg: f64, density: f64) -> f64 {
    let cs = velocity_dispersion_1d(temperature, particle_mass_kg);
    let g = crate::constants::physical::G;
    let pi = std::f64::consts::PI;
    (pi / 6.0) * density * (pi * cs * cs / (g * density)).powf(1.5)
}

pub fn free_streaming_length(mass_gev: f64, temperature_k: f64) -> f64 {
    let mass_kg = crate::constants::physical::gev_to_kg(mass_gev);
    let v_th = maxwell_boltzmann_speed_rms(temperature_k, mass_kg);
    let t_eq = crate::constants::cosmic::REDSHIFT_MATTER_RADIATION_EQ;
    let h_si = crate::constants::cosmic::HUBBLE_CONSTANT_SI;
    v_th / (h_si * (1.0 + t_eq).sqrt())
}