use crate::H100;
use core::f64::consts::PI;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Convention {
OneSided,
TwoSidedLrr2025,
}
impl Convention {
fn hc_factor(self) -> f64 {
match self {
Convention::OneSided => 1.0,
Convention::TwoSidedLrr2025 => core::f64::consts::FRAC_1_SQRT_2,
}
}
}
pub fn hc_from_omega(omega: f64, f: f64, h: f64, convention: Convention) -> f64 {
let h0 = h * H100;
(3.0 * h0 * h0 * omega / (2.0 * PI * PI)).sqrt() / f * convention.hc_factor()
}
pub fn omega_from_hc(hc: f64, f: f64, h: f64, convention: Convention) -> f64 {
let h0 = h * H100;
let hc = hc / convention.hc_factor();
2.0 * PI * PI * f * f * hc * hc / (3.0 * h0 * h0)
}
pub fn sh_from_hc(hc: f64, f: f64) -> f64 {
hc * hc / f
}
pub fn hc_from_sh(sh: f64, f: f64) -> f64 {
(f * sh).sqrt()
}
pub fn omega_from_sh(sh: f64, f: f64, h: f64) -> f64 {
let h0 = h * H100;
2.0 * PI * PI * f.powi(3) * sh / (3.0 * h0 * h0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prefactors_and_round_trips() {
assert!((hc_from_omega(1.0, 1.0, 1.0, Convention::OneSided) / 1.2634e-18 - 1.0).abs() < 1e-4);
assert!((hc_from_omega(1.0, 1.0, 1.0, Convention::TwoSidedLrr2025) / 8.934e-19 - 1.0).abs() < 1e-4);
for conv in [Convention::OneSided, Convention::TwoSidedLrr2025] {
let hc = hc_from_omega(3.7e-9, 2.3e-8, 0.674, conv);
assert!((omega_from_hc(hc, 2.3e-8, 0.674, conv) / 3.7e-9 - 1.0).abs() < 1e-12);
}
let sh = sh_from_hc(2.0e-20, 100.0);
assert!((hc_from_sh(sh, 100.0) / 2.0e-20 - 1.0).abs() < 1e-12);
assert!((omega_from_sh(sh, 100.0, 0.7) / omega_from_hc(2.0e-20, 100.0, 0.7, Convention::OneSided) - 1.0).abs() < 1e-12);
}
#[test]
fn nanograv_amplitude() {
let f = 1.0 / metrology::YEAR;
assert!((omega_from_hc(2.4e-15, f, 1.0, Convention::OneSided) / 3.62e-9 - 1.0).abs() < 2e-3);
}
}