use core::f64::consts::PI;
use metrology::{C, EV, G, H};
pub const GRAVITON_MASS_GW: f64 = 1.92e-23;
pub const GRAVITON_MASS_EPHEMERIS: f64 = 1.01e-24;
pub const NEUTRINO_DAMPING: f64 = 0.356;
pub fn speed_bounds(delay: f64, d: f64, max_emission: f64) -> (f64, f64) {
(delay * C / d, (delay - max_emission) * C / d)
}
pub fn compton_wavelength(m_ev: f64) -> f64 {
H * C / (m_ev * EV)
}
pub fn speed_deficit(m_ev: f64, f: f64) -> f64 {
0.5 * (m_ev * EV / (H * f)).powi(2)
}
pub fn massive_graviton_delay(m_ev: f64, f: f64, d: f64) -> f64 {
d / C * speed_deficit(m_ev, f)
}
pub fn lens_parameter(m_lens: f64, f: f64) -> f64 {
8.0 * PI * G * m_lens * f / C.powi(3)
}
pub fn point_lens_geometric(y: f64, m_lens: f64) -> (f64, f64, f64) {
let s = (y * y + 4.0).sqrt();
let mu = (y * y + 2.0) / (2.0 * y * s);
let delay = 4.0 * G * m_lens / C.powi(3) * (y * s / 2.0 + ((s + y) / (s - y)).ln());
(0.5 + mu, 0.5 - mu, delay)
}
pub fn wave_optics_peak(w: f64) -> f64 {
PI * w / -(-PI * w).exp_m1()
}
pub fn viscous_damping(eta: f64, omega: f64, tau: f64) -> Option<f64> {
(omega * tau <= 1.0).then(|| 16.0 * PI * G * eta / (C * C))
}
#[cfg(test)]
mod tests {
use super::*;
use metrology::{MPC, SOLAR_MASS};
fn close(a: f64, b: f64, rel: f64) -> bool {
(a / b - 1.0).abs() < rel
}
#[test]
fn graviton_mass() {
assert!(close(compton_wavelength(GRAVITON_MASS_GW), 6.45751e16, 1e-5));
assert!(close(compton_wavelength(2.42e-23), 5.12331e16, 1e-5));
assert!(close(compton_wavelength(GRAVITON_MASS_EPHEMERIS), 1.22757e18, 1e-5));
assert!(close(compton_wavelength(3.16e-23), 3.93e16, 1e-2));
assert!(close(speed_deficit(GRAVITON_MASS_GW, 100.0), 1.07766e-21, 1e-5));
assert!(close(massive_graviton_delay(GRAVITON_MASS_GW, 100.0, 1e3 * MPC), 1.10920e-4, 1e-5));
let au = 1.495_978_707e11;
assert!(((-au / compton_wavelength(GRAVITON_MASS_GW)).exp_m1() / -2.3166e-6 - 1.0).abs() < 1e-4);
}
#[test]
fn lensing() {
assert!(close(lens_parameter(100.0 * SOLAR_MASS, 100.0), 1.23791, 1e-5));
assert!(close(1.0 / lens_parameter(SOLAR_MASS, 100.0), 80.7813, 1e-5));
let (plus, minus, delay) = point_lens_geometric(1.0, 1e8 * SOLAR_MASS);
assert!(close(plus, 1.17082, 1e-5) && close(minus, -0.17082, 1e-4) && close(delay, 4098.91, 1e-5));
assert!(close(wave_optics_peak(1.0), 3.28348, 1e-5));
}
#[test]
fn absorption() {
let water = viscous_damping(1e-3, 1e3, 1e-12).unwrap();
assert!(close(water, 3.7328e-29, 1e-4));
assert!(close(C / water / (1e3 * MPC), 2.60277e11, 1e-5));
assert!(close(viscous_damping(1.8e-5, 1e3, 1e-10).unwrap(), 6.71903e-31, 1e-5));
assert!(viscous_damping(1e21, 2.0 * PI, 1e10).is_none());
assert!(close((1.0 - NEUTRINO_DAMPING).sqrt(), 0.802496, 1e-6));
}
}