#[must_use]
#[inline]
pub fn cp_to_surface_pressure(cp: f64, dynamic_pressure_pa: f64, static_pressure_pa: f64) -> f64 {
static_pressure_pa + cp * dynamic_pressure_pa
}
#[must_use]
#[inline]
pub fn freestream_dynamic_pressure(velocity_ms: f64, density_kg_m3: f64) -> f64 {
0.5 * density_kg_m3 * velocity_ms * velocity_ms
}
#[must_use]
#[inline]
pub fn aero_coefficients_to_forces(
cl: f64,
cd: f64,
dynamic_pressure_pa: f64,
reference_area_m2: f64,
) -> (f64, f64) {
let lift = cl * dynamic_pressure_pa * reference_area_m2;
let drag = cd * dynamic_pressure_pa * reference_area_m2;
(lift, drag)
}
#[must_use]
#[inline]
pub fn wind_to_freestream(wind_velocity_ms: f64) -> f64 {
wind_velocity_ms.clamp(-340.0, 340.0) }
#[must_use]
#[inline]
pub fn temperature_to_water_viscosity(temperature_k: f64) -> f64 {
let t = temperature_k.clamp(273.0, 373.0);
let a = 2.414e-5;
let b = 247.8;
let c = 140.0;
a * 10.0_f64.powf(b / (t - c))
}
#[must_use]
pub fn heat_to_buoyancy_forcing(
heat_power_w: f64,
fluid_volume_m3: f64,
density_kg_m3: f64,
specific_heat_j_per_kg_k: f64,
expansion_coeff_per_k: f64,
dt_s: f64,
) -> f64 {
if fluid_volume_m3 <= 0.0 || specific_heat_j_per_kg_k <= 0.0 {
return 0.0;
}
let delta_t =
heat_power_w * dt_s / (density_kg_m3 * specific_heat_j_per_kg_k * fluid_volume_m3);
density_kg_m3 * 9.81 * expansion_coeff_per_k * delta_t
}
#[must_use]
#[inline]
pub fn tke_to_eddy_diffusivity(tke: f64, turbulent_length_scale_m: f64) -> f64 {
if tke <= 0.0 {
return 0.0;
}
let c_mu_quarter = 0.5477; let pr_t = 0.85;
c_mu_quarter * tke.sqrt() * turbulent_length_scale_m / pr_t
}
#[must_use]
#[inline]
pub fn velocity_to_acoustic_source_strength(velocity_ms: f64, speed_of_sound: f64) -> f64 {
if speed_of_sound <= 0.0 {
return 0.0;
}
let mach = velocity_ms.abs() / speed_of_sound;
mach.powi(8) }
#[must_use]
#[inline]
pub fn tke_to_broadband_noise_db(tke: f64) -> f64 {
if tke <= 0.0 {
return 0.0;
}
let u_rms = (2.0 / 3.0 * tke).sqrt();
let v_ref = 5e-8;
if u_rms <= v_ref {
return 0.0;
}
20.0 * (u_rms / v_ref).log10()
}
#[must_use]
#[inline]
pub fn wave_height_to_acoustic_pressure(
wave_height_m: f64,
frequency_hz: f64,
speed_of_sound: f64,
) -> f64 {
if speed_of_sound <= 0.0 || frequency_hz <= 0.0 {
return 0.0;
}
let rho = 1.225; let g = 9.81;
let k = 2.0 * std::f64::consts::PI * frequency_hz / speed_of_sound;
rho * g * wave_height_m.abs() * k * wave_height_m.abs()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cp_to_pressure_stagnation() {
let p = cp_to_surface_pressure(1.0, 500.0, 101325.0);
assert!((p - 101825.0).abs() < 0.1);
}
#[test]
fn dynamic_pressure_basic() {
let q = freestream_dynamic_pressure(10.0, 1.225);
assert!((q - 61.25).abs() < 0.01);
}
#[test]
fn aero_forces_basic() {
let (lift, drag) = aero_coefficients_to_forces(1.0, 0.05, 100.0, 10.0);
assert!((lift - 1000.0).abs() < 0.1);
assert!((drag - 50.0).abs() < 0.1);
}
#[test]
fn wind_to_freestream_clamps() {
assert_eq!(wind_to_freestream(500.0), 340.0);
assert_eq!(wind_to_freestream(-500.0), -340.0);
}
#[test]
fn water_viscosity_room_temp() {
let mu = temperature_to_water_viscosity(293.0);
assert!(mu > 0.0005 && mu < 0.002, "got {mu}");
}
#[test]
fn water_viscosity_decreases_with_temp() {
let cold = temperature_to_water_viscosity(280.0);
let hot = temperature_to_water_viscosity(350.0);
assert!(cold > hot);
}
#[test]
fn buoyancy_forcing_positive() {
let f = heat_to_buoyancy_forcing(1000.0, 1.0, 1000.0, 4186.0, 2.1e-4, 1.0);
assert!(f > 0.0);
}
#[test]
fn buoyancy_forcing_zero_volume() {
assert_eq!(
heat_to_buoyancy_forcing(1000.0, 0.0, 1000.0, 4186.0, 2.1e-4, 1.0),
0.0
);
}
#[test]
fn eddy_diffusivity_zero_tke() {
assert_eq!(tke_to_eddy_diffusivity(0.0, 1.0), 0.0);
}
#[test]
fn eddy_diffusivity_positive() {
let alpha = tke_to_eddy_diffusivity(1.0, 0.1);
assert!(alpha > 0.0);
}
#[test]
fn acoustic_source_strength_subsonic() {
let s = velocity_to_acoustic_source_strength(34.3, 343.0); assert!((s - 1e-8).abs() < 1e-9); }
#[test]
fn acoustic_source_zero_velocity() {
assert_eq!(velocity_to_acoustic_source_strength(0.0, 343.0), 0.0);
}
#[test]
fn tke_noise_zero() {
assert_eq!(tke_to_broadband_noise_db(0.0), 0.0);
}
#[test]
fn tke_noise_increases_with_tke() {
let low = tke_to_broadband_noise_db(1.0);
let high = tke_to_broadband_noise_db(10.0);
assert!(high > low);
}
#[test]
fn wave_acoustic_pressure_positive() {
let p = wave_height_to_acoustic_pressure(0.1, 100.0, 343.0);
assert!(p > 0.0);
}
#[test]
fn wave_acoustic_pressure_zero_freq() {
assert_eq!(wave_height_to_acoustic_pressure(0.1, 0.0, 343.0), 0.0);
}
}