#[allow(dead_code)]
pub fn reynolds_number(rho: f64, v: f64, l: f64, mu: f64) -> f64 {
rho * v * l / mu
}
#[allow(dead_code)]
pub fn mach_number(v: f64, c_sound: f64) -> f64 {
v / c_sound
}
#[allow(dead_code)]
pub fn froude_number(v: f64, g: f64, l: f64) -> f64 {
v / (g * l).sqrt()
}
#[allow(dead_code)]
pub fn strouhal_number(f: f64, l: f64, v: f64) -> f64 {
f * l / v
}
#[allow(dead_code)]
pub fn weber_number(rho: f64, v: f64, l: f64, sigma: f64) -> f64 {
rho * v * v * l / sigma
}
#[allow(dead_code)]
pub fn knudsen_number(lambda_mfp: f64, l: f64) -> f64 {
lambda_mfp / l
}
#[allow(dead_code)]
pub fn nusselt_number(h: f64, l: f64, k_thermal: f64) -> f64 {
h * l / k_thermal
}
#[allow(dead_code)]
pub fn prandtl_number(mu: f64, cp: f64, k: f64) -> f64 {
mu * cp / k
}
#[allow(dead_code)]
pub fn grashof_number(g: f64, beta: f64, delta_t: f64, l: f64, nu: f64) -> f64 {
g * beta * delta_t * l * l * l / (nu * nu)
}
#[allow(dead_code)]
pub fn peclet_number(v: f64, l: f64, d: f64) -> f64 {
v * l / d
}
#[allow(dead_code)]
pub fn rayleigh_number(g: f64, beta: f64, delta_t: f64, l: f64, nu: f64, alpha: f64) -> f64 {
g * beta * delta_t * l * l * l / (nu * alpha)
}
#[allow(dead_code)]
pub fn biot_number(h: f64, l: f64, k_s: f64) -> f64 {
h * l / k_s
}
#[allow(dead_code)]
pub fn euler_number(delta_p: f64, rho: f64, v: f64) -> f64 {
delta_p / (rho * v * v)
}
#[allow(dead_code)]
pub fn stokes_number(t_p: f64, v: f64, l: f64) -> f64 {
t_p * v / l
}
#[allow(dead_code)]
pub fn archimedes_number(g: f64, l: f64, rho_f: f64, rho_p: f64, mu: f64) -> f64 {
g * l * l * l * rho_f * (rho_p - rho_f) / (mu * mu)
}
#[cfg(test)]
mod tests {
use super::*;
const RHO_WATER: f64 = 1000.0; const MU_WATER: f64 = 1e-3; const NU_WATER: f64 = 1e-6;
const C_SOUND_AIR: f64 = 343.0; const G: f64 = 9.81;
#[test]
fn test_reynolds_pipe_flow() {
let re = reynolds_number(RHO_WATER, 1.0, 0.01, MU_WATER);
assert!((re - 10_000.0).abs() < 1.0);
}
#[test]
fn test_reynolds_proportional_to_velocity() {
let re1 = reynolds_number(1.0, 1.0, 1.0, 1.0);
let re2 = reynolds_number(1.0, 2.0, 1.0, 1.0);
assert!((re2 - 2.0 * re1).abs() < 1e-12);
}
#[test]
fn test_mach_subsonic() {
let ma = mach_number(100.0, C_SOUND_AIR);
assert!(ma < 1.0, "100 m/s in air is subsonic");
assert!((ma - 100.0 / 343.0).abs() < 1e-10);
}
#[test]
fn test_mach_sonic() {
let ma = mach_number(C_SOUND_AIR, C_SOUND_AIR);
assert!((ma - 1.0).abs() < 1e-12);
}
#[test]
fn test_mach_supersonic() {
let ma = mach_number(2.0 * C_SOUND_AIR, C_SOUND_AIR);
assert!((ma - 2.0).abs() < 1e-12);
}
#[test]
fn test_froude_number_open_channel() {
let fr = froude_number(3.0, G, 1.0);
let expected = 3.0 / G.sqrt();
assert!((fr - expected).abs() < 1e-10);
}
#[test]
fn test_froude_critical_flow() {
let l = 2.0;
let v = (G * l).sqrt();
let fr = froude_number(v, G, l);
assert!((fr - 1.0).abs() < 1e-10);
}
#[test]
fn test_strouhal_cylinder() {
let st = strouhal_number(2.0, 0.1, 1.0);
assert!((st - 0.2).abs() < 1e-12);
}
#[test]
fn test_nusselt_number_basic() {
let nu = nusselt_number(100.0, 0.5, 0.6);
assert!((nu - 100.0 * 0.5 / 0.6).abs() < 1e-10);
}
#[test]
fn test_prandtl_water() {
let pr = prandtl_number(MU_WATER, 4182.0, 0.598);
assert!(
pr > 6.0 && pr < 8.0,
"Prandtl for water should be ~7, got {pr}"
);
}
#[test]
fn test_prandtl_air() {
let pr = prandtl_number(1.81e-5, 1005.0, 0.0257);
assert!(
pr > 0.6 && pr < 0.8,
"Prandtl for air should be ~0.71, got {pr}"
);
}
#[test]
fn test_grashof_number_positive_delta_t() {
let gr = grashof_number(G, 3.4e-3, 10.0, 0.1, NU_WATER);
assert!(gr > 0.0);
}
#[test]
fn test_grashof_scales_with_l_cubed() {
let gr1 = grashof_number(G, 1e-3, 10.0, 1.0, 1e-6);
let gr2 = grashof_number(G, 1e-3, 10.0, 2.0, 1e-6);
assert!((gr2 - 8.0 * gr1).abs() < 1e-6 * gr1.abs());
}
#[test]
fn test_weber_number_basic() {
let we = weber_number(1000.0, 1.0, 0.01, 0.072);
assert!((we - 1000.0 * 0.01 / 0.072).abs() < 0.1);
}
#[test]
fn test_knudsen_continuum_limit() {
let kn = knudsen_number(70e-9, 1.0);
assert!(kn < 1e-6, "Kn should be tiny in continuum regime");
}
#[test]
fn test_knudsen_free_molecular() {
let kn = knudsen_number(1.0, 1.0);
assert!((kn - 1.0).abs() < 1e-12);
}
#[test]
fn test_peclet_number_basic() {
let pe = peclet_number(1.0, 1.0, 1e-3);
assert!((pe - 1000.0).abs() < 1e-10);
}
#[test]
fn test_peclet_proportional_to_velocity() {
let pe1 = peclet_number(1.0, 1.0, 1.0);
let pe2 = peclet_number(3.0, 1.0, 1.0);
assert!((pe2 - 3.0 * pe1).abs() < 1e-12);
}
#[test]
fn test_rayleigh_number_positive() {
let ra = rayleigh_number(G, 3.4e-3, 10.0, 0.1, NU_WATER, 1.4e-7);
assert!(ra > 0.0);
}
#[test]
fn test_biot_number_small_lump() {
let bi = biot_number(10.0, 0.005, 200.0); assert!(bi < 0.1, "Bi = {bi} should be < 0.1");
}
#[test]
fn test_biot_number_large() {
let bi = biot_number(1000.0, 0.1, 1.0);
assert!(bi > 1.0);
}
#[test]
fn test_euler_number_definition() {
let eu = euler_number(100.0, 1.0, 10.0);
assert!((eu - 1.0).abs() < 1e-12);
}
#[test]
fn test_stokes_number_unity() {
let stk = stokes_number(1.0, 1.0, 1.0);
assert!((stk - 1.0).abs() < 1e-12);
}
#[test]
fn test_stokes_number_small() {
let stk = stokes_number(1e-6, 1.0, 0.1);
assert!(stk < 1e-4);
}
#[test]
fn test_archimedes_number_positive_buoyancy() {
let ar = archimedes_number(G, 0.01, 1000.0, 2500.0, MU_WATER);
assert!(ar > 0.0);
}
#[test]
fn test_archimedes_number_negative_buoyancy() {
let ar = archimedes_number(G, 0.01, 1000.0, 500.0, MU_WATER);
assert!(ar < 0.0);
}
#[test]
fn test_all_dimensionless_finite() {
assert!(reynolds_number(1.0, 1.0, 1.0, 1.0).is_finite());
assert!(mach_number(1.0, 1.0).is_finite());
assert!(froude_number(1.0, 1.0, 1.0).is_finite());
assert!(strouhal_number(1.0, 1.0, 1.0).is_finite());
assert!(nusselt_number(1.0, 1.0, 1.0).is_finite());
assert!(prandtl_number(1.0, 1.0, 1.0).is_finite());
assert!(grashof_number(1.0, 1.0, 1.0, 1.0, 1.0).is_finite());
assert!(weber_number(1.0, 1.0, 1.0, 1.0).is_finite());
assert!(knudsen_number(1.0, 1.0).is_finite());
assert!(peclet_number(1.0, 1.0, 1.0).is_finite());
}
#[test]
fn test_reynolds_turbulent_threshold() {
let re_laminar = reynolds_number(1000.0, 0.1, 0.01, 1e-3); let re_turbulent = reynolds_number(1000.0, 1.0, 0.01, 1e-3); assert!(re_laminar < 4000.0);
assert!(re_turbulent > 4000.0);
}
}