use metrology::C;
use crate::integrate_log;
pub fn comoving_distance(z: f64, h0: f64, omega_m: f64) -> f64 {
C / h0 * integrate_log(1.0, 1.0 + z, 2000, |x| 1.0 / (omega_m * x * x * x + 1.0 - omega_m).sqrt())
}
pub fn angular_diameter_distance(z1: f64, z2: f64, h0: f64, omega_m: f64) -> f64 {
(comoving_distance(z2, h0, omega_m) - comoving_distance(z1, h0, omega_m)) / (1.0 + z2)
}
pub fn time_delay_distance(zd: f64, zs: f64, h0: f64, omega_m: f64) -> f64 {
let (dd, ds, dds) = (angular_diameter_distance(0.0, zd, h0, omega_m), angular_diameter_distance(0.0, zs, h0, omega_m), angular_diameter_distance(zd, zs, h0, omega_m));
(1.0 + zd) * dd * ds / dds
}
#[cfg(test)]
mod tests {
use super::*;
use crate::H100;
use metrology::MPC;
#[test]
fn the_two_closed_forms() {
let h0 = 0.7 * H100;
for z in [0.1, 1.0, 3.0] {
let eds = 2.0 * C / h0 * (1.0 - 1.0 / (1.0f64 + z).sqrt());
assert!((comoving_distance(z, h0, 1.0) / eds - 1.0).abs() < 1e-13, "z = {z}");
assert!((comoving_distance(z, h0, 0.0) / (C * z / h0) - 1.0).abs() < 1e-14, "z = {z}");
}
assert_eq!(comoving_distance(0.0, h0, 0.3), 0.0);
}
#[test]
fn h0licow() {
let lenses = [
(0.6304, 1.394, 5156.0, 296.0, 236.0),
(0.295, 0.654, 2096.0, 98.0, 83.0),
(0.4546, 1.693, 2707.0, 183.0, 168.0),
(0.745, 1.789, 5769.0, 589.0, 471.0),
(0.6575, 1.662, 4784.0, 399.0, 248.0),
(0.311, 1.722, 1470.0, 137.0, 127.0),
];
let (mut sum, mut weights) = (0.0, 0.0);
for (zd, zs, ddt, up, down) in lenses {
let h = 70.0 * time_delay_distance(zd, zs, 0.7 * H100, 0.3) / MPC / ddt;
let sigma = h * 0.5 * (up + down) / ddt;
sum += h / (sigma * sigma);
weights += 1.0 / (sigma * sigma);
}
let (h0, sigma) = (sum / weights, weights.powf(-0.5));
assert!((h0 - 73.3).abs() < 0.1 && (sigma - 1.75).abs() < 0.1, "{h0} ± {sigma}");
}
}