use metrology::{C, G};
use core::f64::consts::PI;
pub fn beam_acceleration(power: f64, rho: f64) -> f64 {
4.0 * G * power / (C.powi(3) * rho)
}
pub fn beam_tidal(power: f64, rho: f64) -> f64 {
-4.0 * G * power / (C.powi(3) * rho * rho)
}
pub fn beam_velocity_kick(energy: f64, rho: f64) -> f64 {
4.0 * G * energy / (C.powi(3) * rho)
}
pub fn spinning_rod_power(m: f64, l: f64, omega: f64) -> f64 {
2.0 / 45.0 * G * m * m * l.powi(4) * omega.powi(6) / C.powi(5)
}
pub fn rotor_power(delta_i: f64, omega: f64) -> f64 {
32.0 / 5.0 * G / C.powi(5) * delta_i * delta_i * omega.powi(6)
}
pub fn rotor_wavelength(omega: f64) -> f64 {
PI * C / omega
}
pub fn rotor_force(m_test: f64, m_point: f64, n: usize, radius: f64, d: f64, phi: f64, z: f64) -> f64 {
const STEPS: usize = 720;
let (cx, cy) = (d * phi.cos(), d * phi.sin());
let (mut re, mut im) = (0.0, 0.0);
for i in 0..STEPS {
let theta = 2.0 * PI * i as f64 / STEPS as f64;
let fx: f64 = (0..n).map(|j| {
let a = theta + 2.0 * PI * j as f64 / n as f64;
let (x, y) = (cx + radius * a.cos(), cy + radius * a.sin());
G * m_test * m_point * x / (x * x + y * y + z * z).powf(1.5)
}).sum();
let (s, c) = (n as f64 * theta).sin_cos();
re += fx * c;
im -= fx * s;
}
2.0 * re.hypot(im) / STEPS as f64
}
pub fn free_mass_displacement(force: f64, mass: f64, f: f64) -> f64 {
force / (mass * (2.0 * PI * f).powi(2))
}
pub fn sector_rotor_strength(b: f64, rho: f64, alpha: f64, r_max: f64, r_min: f64) -> f64 {
G * b * rho * alpha.sin() * (r_max.powi(4) - r_min.powi(4)) / (32.0 * PI * PI)
}
pub fn sector_rotor_geometry(d: f64, phi: f64, z: f64) -> f64 {
let zz = 1.0 + (z / d).powi(2);
((15.0 / zz - 6.0).powi(2) * phi.cos().powi(2) + 36.0 * phi.sin().powi(2)).sqrt() * zz.powf(-2.5) / d.powi(4)
}
pub fn weinberg_efficiency(m: f64, vs: f64, l: f64, gamma_heat: f64) -> f64 {
64.0 * G * m * vs.powi(4) / (15.0 * l * l * C.powi(5) * gamma_heat)
}
pub fn wave_flux(h: f64, f: f64) -> f64 {
let w = 2.0 * PI * f;
C.powi(3) * w * w * h * h / (32.0 * PI * G)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn beam_fixtures() {
assert!((beam_acceleration(1e15, 1e-3) / 9.91e-18 - 1.0).abs() < 2e-3);
assert!((beam_acceleration(3.8e12, 1e-4) / 3.77e-19 - 1.0).abs() < 2e-3);
assert!((beam_velocity_kick(100.0, 1e-3) / 9.9e-31 - 1.0).abs() < 0.01);
assert!((beam_tidal(1e15, 1e-3) / -9.91e-15 - 1.0).abs() < 2e-3);
assert!((beam_tidal(1e15, 1e-3) * 1e-3 / -beam_acceleration(1e15, 1e-3) - 1.0).abs() < 1e-12);
}
#[test]
fn misner_thorne_wheeler_rod() {
let p = spinning_rod_power(4.9e5, 20.0, 28.0);
assert!((p / 2.27e-29 - 1.0).abs() < 0.01, "{p:e}");
assert!((rotor_wavelength(28.0) / 3.36e7 - 1.0).abs() < 0.01);
let i = 4.9e5 * 400.0 / 12.0;
assert!((rotor_power(i, 28.0) / p - 1.0).abs() < 1e-12);
}
#[test]
fn flux_scales_as_h_squared() {
assert!((wave_flux(1e-21, 100.0) / 1.5853e-3 - 1.0).abs() < 1e-4);
assert!((wave_flux(2e-21, 100.0) / wave_flux(1e-21, 100.0) - 4.0).abs() < 1e-12);
}
#[test]
fn newtonian_calibrators() {
let (mirror, m, d, phi, z) = (39.680, 1.0558, 1.1802, 52.24f64.to_radians(), 0.010);
assert!((rotor_force(mirror, m, 2, 0.06033, d, phi, z) / 19.10e-12 - 1.0).abs() < 1e-3);
assert!((rotor_force(mirror, m, 3, 0.10478, d, phi, z) / 9.017e-12 - 1.0).abs() < 1e-3);
let x = free_mass_displacement(19.16e-12, 39.68, 15.60);
assert!((x / 5.026e-17 - 1.0).abs() < 1e-3 && (x / 3995.0 / 1.258e-20 - 1.0).abs() < 1e-3);
let rp = sector_rotor_strength(0.052, 2800.0, 45f64.to_radians(), 0.190, 0.055) * sector_rotor_geometry(1.32, 0.241, 0.643);
assert!((rp / 3.33101e-14 - 1.0).abs() < 1e-5);
assert!((weinberg_efficiency(1000.0, 5e3, 1.5, 2.0 * PI * 1e3 / 1e6) / 5.19887e-33 - 1.0).abs() < 1e-5);
}
#[test]
fn rotor_and_flux_conventions() {
let (m, l, r) = (4.9e5, 20.0, 1.0);
assert!((rotor_power(m * (l * l / 12.0 + r * r / 4.0) - m * r * r / 2.0, 28.0) / 2.23378e-29 - 1.0).abs() < 1e-5);
assert!((wave_flux(1e-22, 1e3) / 1.58532e-3 - 1.0).abs() < 1e-5);
let hdot = 2.0 * PI * 250.0 * 1e-21;
assert!((C.powi(3) * hdot * hdot / (16.0 * PI * G) / wave_flux(1e-21, 250.0) - 2.0).abs() < 1e-12);
}
}