use crate::constants::physical::G;
pub fn circular_velocity_dm(enclosed_mass: f64, r: f64) -> f64 {
(G * enclosed_mass / r).sqrt()
}
pub fn total_rotation_velocity(v_disk: f64, v_bulge: f64, v_gas: f64, v_dm: f64) -> f64 {
(v_disk * v_disk + v_bulge * v_bulge + v_gas * v_gas + v_dm * v_dm).sqrt()
}
pub fn disk_velocity_exponential(v_max_disk: f64, r: f64, r_d: f64) -> f64 {
let y = r / (2.0 * r_d);
let i0 = crate::utils::math::bessel_i0(y);
let i1 = crate::utils::math::bessel_i1(y);
let k0 = crate::utils::math::bessel_k0(y);
let k1 = crate::utils::math::bessel_k1(y);
v_max_disk * (2.0 * y * y * (i0 * k0 - i1 * k1)).sqrt()
}
pub fn bulge_velocity_hernquist(total_mass: f64, r: f64, a: f64) -> f64 {
(G * total_mass * r / ((r + a) * (r + a))).sqrt()
}
pub fn nfw_rotation_velocity(rho_s: f64, r_s: f64, r: f64) -> f64 {
let m = crate::halos::profiles::nfw_enclosed_mass(r, rho_s, r_s);
(G * m / r).sqrt()
}
pub fn isothermal_rotation_velocity(sigma_v: f64) -> f64 {
(2.0_f64).sqrt() * sigma_v
}
pub fn burkert_rotation_velocity(rho_0: f64, r_0: f64, r: f64) -> f64 {
let m = crate::halos::profiles::burkert_enclosed_mass(r, rho_0, r_0);
(G * m / r).sqrt()
}
#[derive(Clone, Debug, PartialEq)]
pub struct RotationCurveData {
pub radii: Vec<f64>,
pub velocities: Vec<f64>,
pub errors: Vec<f64>,
}
impl RotationCurveData {
pub fn new(radii: Vec<f64>, velocities: Vec<f64>, errors: Vec<f64>) -> Self {
Self {
radii,
velocities,
errors,
}
}
pub fn chi_squared_nfw(&self, rho_s: f64, r_s: f64, v_baryon: &[f64]) -> f64 {
self.radii
.iter()
.zip(self.velocities.iter())
.zip(self.errors.iter())
.zip(v_baryon.iter())
.map(|(((r, v_obs), err), v_bar)| {
let v_dm = nfw_rotation_velocity(rho_s, r_s, *r);
let v_model = (v_dm * v_dm + v_bar * v_bar).sqrt();
let diff = v_obs - v_model;
diff * diff / (err * err)
})
.sum()
}
}