use metrology::R_GAS;
pub const GAMMA: f64 = 1.4;
pub const MOLAR_MASS: f64 = 0.028_964_4;
pub const G0: f64 = 9.81;
pub fn sound_speed(t: f64) -> f64 {
(GAMMA * R_GAS * t / MOLAR_MASS).sqrt()
}
pub fn acoustic_cutoff(c: f64) -> f64 {
GAMMA * G0 / (2.0 * c)
}
pub fn buoyancy_frequency(c: f64) -> f64 {
(GAMMA - 1.0).sqrt() * G0 / c
}
pub fn vertical_wavenumber_sq(omega: f64, kh: f64, c: f64) -> f64 {
let (wa, n) = (acoustic_cutoff(c), buoyancy_frequency(c));
(omega * omega - wa * wa) / (c * c) - kh * kh * (1.0 - n * n / (omega * omega))
}
pub fn wave_growth(z: f64, scale_height: f64, ceiling: f64) -> Option<f64> {
(z <= ceiling).then(|| (z / (2.0 * scale_height)).exp())
}
pub fn pressure_to_mass(dp: f64) -> f64 {
dp / G0
}
pub fn forced_ocean_response(speed: f64, depth: f64) -> f64 {
let gh = G0 * depth;
gh / (speed * speed - gh)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn isothermal_values_at_250_kelvin() {
let c = sound_speed(250.0);
assert!((c - 316.97).abs() < 0.01, "{c}");
assert!((acoustic_cutoff(c) - 0.02167).abs() < 1e-5);
assert!((buoyancy_frequency(c) - 0.01958).abs() < 1e-5);
assert!((sound_speed(252.0) / 318.2 - 1.0).abs() < 1e-3);
}
#[test]
fn the_lamb_wave_is_trapped() {
let c = sound_speed(250.0);
for kh in [1e-6, 1e-5, 1e-4] {
let kz2 = vertical_wavenumber_sq(c * kh, kh, c);
let expect = (buoyancy_frequency(c).powi(2) - acoustic_cutoff(c).powi(2)) / (c * c);
assert!(kz2 < 0.0 && (kz2 / expect - 1.0).abs() < 1e-9, "{kz2:e}");
}
assert!(vertical_wavenumber_sq(0.1, 1e-5, c) > 0.0);
assert!((pressure_to_mass(100.0) - 10.19).abs() < 0.01);
}
#[test]
fn ocean_response_limits() {
assert!((forced_ocean_response(1e-3, 4000.0) + 1.0).abs() < 1e-9); assert!((forced_ocean_response(318.2, 4000.0) - 0.6328).abs() < 1e-4);
assert!((forced_ocean_response(318.2, 5000.0) - 0.9396).abs() < 1e-4);
}
#[test]
fn waves_grow_then_dissipate() {
assert!((wave_growth(100e3, 7e3, 150e3).unwrap() / 1265.0 - 1.0).abs() < 1e-3);
assert!(wave_growth(300e3, 7e3, 150e3).is_none());
assert!((wave_growth(0.0, 7e3, 150e3).unwrap() - 1.0).abs() < 1e-12);
let v0: f64 = 780.0 / (1.2 * 318.0);
assert!((v0 - 2.04).abs() < 0.01);
}
}