darkmatter 0.0.1

Dark matter simulation engine — gravitational fields, particle dynamics, halo stability, and cosmological constants
Documentation
use std::f64::consts::PI;

pub fn erf_approx(x: f64) -> f64 {
    let t = 1.0 / (1.0 + 0.3275911 * x.abs());
    let poly = t
        * (0.254829592
            + t * (-0.284496736 + t * (1.421413741 + t * (-1.453152027 + t * 1.061405429))));
    let sign = if x < 0.0 { -1.0 } else { 1.0 };
    sign * (1.0 - poly * (-x * x).exp())
}

pub fn bessel_i0(x: f64) -> f64 {
    let ax = x.abs();
    if ax < 3.75 {
        let t = (x / 3.75).powi(2);
        1.0 + t
            * (3.5156229
                + t * (3.0899424
                    + t * (1.2067492 + t * (0.2659732 + t * (0.0360768 + t * 0.0045813)))))
    } else {
        let t = 3.75 / ax;
        (ax.exp() / ax.sqrt())
            * (0.39894228
                + t * (0.01328592
                    + t * (0.00225319
                        + t * (-0.00157565
                            + t * (0.00916281
                                + t * (-0.02057706
                                    + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))))
    }
}

pub fn bessel_i1(x: f64) -> f64 {
    let ax = x.abs();
    if ax < 3.75 {
        let t = (x / 3.75).powi(2);
        x * (0.5
            + t * (0.87890594
                + t * (0.51498869
                    + t * (0.15084934 + t * (0.02658733 + t * (0.00301532 + t * 0.00032411))))))
    } else {
        let t = 3.75 / ax;
        let result = (ax.exp() / ax.sqrt())
            * (0.39894228
                + t * (-0.03988024
                    + t * (-0.00362018
                        + t * (0.00163801
                            + t * (-0.01031555
                                + t * (0.02282967
                                    + t * (-0.02895312
                                        + t * (0.01787654 + t * (-0.00420059)))))))));
        if x < 0.0 { -result } else { result }
    }
}

pub fn bessel_k0(x: f64) -> f64 {
    if x <= 2.0 {
        let t = x * x / 4.0;
        -x.ln() * bessel_i0(x)
            + (-0.57721566
                + t * (0.42278420
                    + t * (0.23069756
                        + t * (0.03488590 + t * (0.00262698 + t * (0.00010750 + t * 0.00000740))))))
    } else {
        let t = 2.0 / x;
        ((-x).exp() / x.sqrt())
            * (1.25331414
                + t * (-0.07832358
                    + t * (0.02189568
                        + t * (-0.01062446
                            + t * (0.00587872 + t * (-0.00251540 + t * 0.00053208))))))
    }
}

pub fn bessel_k1(x: f64) -> f64 {
    if x <= 2.0 {
        let t = x * x / 4.0;
        x.ln() * bessel_i1(x)
            + (1.0 / x)
                * (1.0
                    + t * (0.15443144
                        + t * (-0.67278579
                            + t * (-0.18156897
                                + t * (-0.01919402 + t * (-0.00110404 + t * (-0.00004686)))))))
    } else {
        let t = 2.0 / x;
        ((-x).exp() / x.sqrt())
            * (1.25331414
                + t * (0.23498619
                    + t * (-0.03655620
                        + t * (0.01504268
                            + t * (-0.00780353 + t * (0.00325614 + t * (-0.00068245)))))))
    }
}

pub fn nfw_density(r: f64, rho_s: f64, r_s: f64) -> f64 {
    let x = r / r_s;
    rho_s / (x * (1.0 + x) * (1.0 + x))
}

pub fn nfw_enclosed_mass(r: f64, rho_s: f64, r_s: f64) -> f64 {
    let x = r / r_s;
    4.0 * PI * rho_s * r_s * r_s * r_s * ((1.0 + x).ln() - x / (1.0 + x))
}