use core::f64::consts::PI;
use metrology::G;
pub const MICROGAL: f64 = 1e-8;
pub const EOTVOS: f64 = 1e-9;
pub fn sphere(a: f64, depth: f64, density_contrast: f64, offset: f64) -> (f64, f64) {
let dm = 4.0 / 3.0 * PI * a.powi(3) * density_contrast;
let (x, z) = (offset, depth);
let s2 = x * x + z * z;
(G * dm * z / s2.powf(1.5), G * dm * (2.0 * z * z - x * x) / s2.powf(2.5))
}
pub fn cylinder(a: f64, depth: f64, density_contrast: f64, offset: f64) -> (f64, f64) {
let lambda = PI * a * a * density_contrast;
let (x, z) = (offset, depth);
let s2 = x * x + z * z;
(2.0 * G * lambda * z / s2, 2.0 * G * lambda * (z * z - x * x) / (s2 * s2))
}
pub fn averaging_time(asd: f64, target: f64) -> f64 {
(asd / target).powi(2)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn buried_bodies() {
let (gz, gradient) = cylinder(1.0, 1.9, -2000.0, 0.0);
assert!((gz / MICROGAL + 44.14).abs() < 0.01 && (gradient / EOTVOS + 232.3).abs() < 0.1);
assert!(cylinder(1.0, 1.9, -2000.0, 2.5).1 > 0.0);
let void = sphere(5.0, 20.0, -2700.0, 0.0);
assert!((void.0 / MICROGAL + 23.59).abs() < 0.01 && (void.1 / EOTVOS + 23.59).abs() < 0.01);
assert!(sphere(5.0, 20.0, 0.0, 3.0) == (0.0, 0.0));
assert!((sphere(5.0, 20.0, -5400.0, 3.0).0 / sphere(5.0, 20.0, -2700.0, 3.0).0 - 2.0).abs() < 1e-12);
let dm = 4.0 / 3.0 * PI * 125.0 * 2700.0;
assert!((sphere(5.0, 100.0, 2700.0, 0.0).1 / (2.0 * G * dm / 1e6) - 1.0).abs() < 1e-12);
}
#[test]
fn sensor_averaging() {
assert!((averaging_time(500e-9, 20e-9) - 625.0).abs() < 1e-9);
assert!((500e-9 / 600f64.sqrt() / 20.4e-9 - 1.0).abs() < 0.01);
}
}