use core::f64::consts::PI;
use geopotential::Field;
use metrology::{C, EPS_0, G};
pub const ELECTRON_GRAVITATIONAL_COUPLING: f64 = G * metrology::M_E * metrology::M_E / (metrology::HBAR * C);
pub const GM_PERMITTIVITY: f64 = 1.0 / (4.0 * PI * G);
pub const GM_PERMEABILITY: f64 = 4.0 * PI * G / (C * C);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Convention {
Mashhoon,
RuggieroTartaglia,
MaxwellSi,
}
pub fn equatorial_field(j: f64, r: f64, convention: Convention) -> f64 {
let mashhoon = G * j / (C * r.powi(3));
match convention {
Convention::Mashhoon => mashhoon,
Convention::RuggieroTartaglia => 2.0 * mashhoon,
Convention::MaxwellSi => G * j / (2.0 * C * C * r.powi(3)),
}
}
pub fn force_per_mass(v: f64, b: f64, convention: Convention) -> f64 {
match convention {
Convention::Mashhoon => 2.0 * v * b / C,
Convention::RuggieroTartaglia => v * b / C,
Convention::MaxwellSi => 4.0 * v * b,
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GravitomagneticDipole {
pub j: f64,
}
impl Field for GravitomagneticDipole {
fn potential(&self, r: f64, lat: f64, _lon: f64) -> f64 {
G * self.j / C * lat.sin() / (r * r)
}
fn vector(&self, r: f64, lat: f64, _lon: f64) -> [f64; 3] {
let k = G * self.j / (C * r.powi(3));
[-k * lat.cos(), 0.0, 2.0 * k * lat.sin()]
}
}
pub fn extremal_charge_to_mass() -> f64 {
(4.0 * PI * EPS_0 * G).sqrt()
}
pub fn wgc_ratio(q: f64, m: f64) -> f64 {
q / (m * extremal_charge_to_mass())
}
pub fn blackett_beta(mu: f64, j: f64) -> f64 {
2.0 * mu / (extremal_charge_to_mass() * j)
}
pub fn blackett_moment(j: f64, beta: f64) -> f64 {
beta / 2.0 * extremal_charge_to_mass() * j
}
#[cfg(test)]
mod tests {
use super::*;
use metrology::{E_CHARGE, M_E, M_P};
fn close(a: f64, b: f64, rel: f64) -> bool {
(a / b - 1.0).abs() < rel
}
#[test]
fn earth_dipole() {
let earth = GravitomagneticDipole { j: 5.86e33 };
let r = 6.371e6;
assert!(close(earth.magnitude(r, 0.0, 0.0), 5.044_984e-6, 1e-6));
assert!(close(earth.magnitude(r, 0.0, 0.0) / C, 1.682_83e-14, 1e-5)); let (lat, h) = (0.4, 1e-5);
let up = -(earth.potential(r * (1.0 + h), lat, 0.0) - earth.potential(r * (1.0 - h), lat, 0.0)) / (2.0 * r * h);
let north = -(earth.potential(r, lat + h, 0.0) - earth.potential(r, lat - h, 0.0)) / (2.0 * h * r);
let [n, e, u] = earth.vector(r, lat, 0.0);
assert!(close(u, up, 1e-8) && close(n, north, 1e-8) && e == 0.0);
}
#[test]
fn conventions_agree() {
let (j, r, v) = (5.86e33, 6.371e6, 7.9e3);
let forces = [Convention::Mashhoon, Convention::RuggieroTartaglia, Convention::MaxwellSi].map(|c| force_per_mass(v, equatorial_field(j, r, c), c));
assert!(close(forces[0], 2.658_864e-10, 1e-6));
assert!(close(forces[1], forces[0], 1e-12) && close(forces[2], forces[0], 1e-12));
assert!(close(1.0 / (GM_PERMITTIVITY * GM_PERMEABILITY).sqrt(), C, 1e-12));
assert!(close(GM_PERMITTIVITY, 1.192_297e9, 1e-6) && close(GM_PERMEABILITY, 9.331_99e-27, 1e-5));
}
#[test]
fn blackett_and_extremal_ratio() {
assert!(close(extremal_charge_to_mass(), 8.617_52e-11, 1e-5));
assert!(close(ELECTRON_GRAVITATIONAL_COUPLING, 1.751_81e-45, 1e-5));
assert!(close(metrology::ALPHA / ELECTRON_GRAVITATIONAL_COUPLING, 4.165_57e42, 1e-4));
assert!(close(wgc_ratio(E_CHARGE, M_E), 2.040_98e21, 1e-5) && close(wgc_ratio(E_CHARGE, M_P), 1.111_55e18, 1e-5));
assert!(close(blackett_beta(7.91e22, 5.87e33), 0.312_742, 1e-5));
assert!(close(blackett_beta(7.690e22, 5.87e33), 0.304_044, 1e-5));
assert!(close(blackett_moment(5.87e33, blackett_beta(7.91e22, 5.87e33)), 7.91e22, 1e-12));
}
}