const C: f64 = 299792.458;
fn integrate<F>(f: F, a: f64, b: f64, n: usize) -> f64
where
F: Fn(f64) -> f64,
{
let h = (b - a) / n as f64;
let s = (1..n).map(|i| f(a + i as f64 * h)).sum::<f64>();
h / 2.0 * (f(a) + f(b) + 2.0 * s)
}
pub struct Cosmo<'a> {
pub h0: f64,
pub omega_m: f64,
pub omega_lambda: f64,
pub omega_k: f64,
pub name: Option<&'a str>,
}
impl<'a> Cosmo<'a> {
pub fn new(h0: f64, omega_m: f64, omega_lambda: f64, name: Option<&'a str>) -> Self {
let omega_k = 1.0 - omega_m - omega_lambda;
Self {
h0,
omega_m,
omega_lambda,
omega_k,
name,
}
}
pub fn planck18() -> Self {
let h0 = 67.66;
let omega_m = 0.3103;
let omega_lambda = 0.6897;
let omega_k = 1.0 - omega_m - omega_lambda;
Self {
h0,
omega_m,
omega_lambda,
omega_k,
name: Some("Planck18"),
}
}
pub fn luminosity_distance(&self, redshift: f64) -> f64 {
let integrand = |z: f64| {
1.0 / (self.omega_m * (1.0 + z).powi(3)
+ self.omega_k * (1.0 + z).powi(2)
+ self.omega_lambda)
.sqrt()
};
let d_h = C / self.h0;
let d_c = d_h * integrate(&integrand, 0.0, redshift, 1000);
let d_m = d_c / (1.0 + redshift);
let d_lum = (1.0 + redshift).powi(2) * d_m;
d_lum
}
pub fn dm(&self, z: f64) -> f64 {
let lumdist = self.luminosity_distance(z);
5.0 * ((lumdist * 1.0e6) / 10.0).log10()
}
pub fn angular_diameter_distance(&self, z: f64) -> f64 {
let lumdist = self.luminosity_distance(z);
if z > 0.01 {
lumdist / (1.0 + z).powi(2)
} else {
lumdist
}
}
}