use crate::math::constants;
pub fn hydrostatic_pressure(density: f64, g: f64, depth: f64) -> f64 {
density * g * depth
}
pub fn total_pressure(atmospheric_pressure: f64, density: f64, g: f64, depth: f64) -> f64 {
atmospheric_pressure + density * g * depth
}
pub fn pascal_force(f1: f64, a1: f64, a2: f64) -> f64 {
assert!(a1 > 0.0, "a1 must be positive");
f1 * a2 / a1
}
pub fn pressure(force: f64, area: f64) -> f64 {
assert!(area > 0.0, "area must be positive");
force / area
}
pub fn buoyant_force(fluid_density: f64, displaced_volume: f64, g: f64) -> f64 {
fluid_density * displaced_volume * g
}
pub fn fraction_submerged(object_density: f64, fluid_density: f64) -> f64 {
assert!(fluid_density > 0.0, "fluid_density must be positive");
object_density / fluid_density
}
pub fn apparent_weight(mass: f64, object_volume: f64, fluid_density: f64, g: f64) -> f64 {
mass * g - fluid_density * object_volume * g
}
pub fn continuity_velocity(a1: f64, v1: f64, a2: f64) -> f64 {
assert!(a2 > 0.0, "a2 must be positive");
a1 * v1 / a2
}
pub fn flow_rate(area: f64, velocity: f64) -> f64 {
area * velocity
}
pub fn mass_flow_rate(density: f64, area: f64, velocity: f64) -> f64 {
density * area * velocity
}
pub fn bernoulli_pressure(
p1: f64,
density: f64,
v1: f64,
h1: f64,
v2: f64,
h2: f64,
g: f64,
) -> f64 {
p1 + 0.5 * density * (v1 * v1 - v2 * v2) + density * g * (h1 - h2)
}
pub fn torricelli_velocity(g: f64, height: f64) -> f64 {
(2.0 * g * height).sqrt()
}
pub fn venturi_velocity(p1: f64, p2: f64, density: f64, a1: f64, a2: f64) -> f64 {
assert!(density > 0.0, "density must be positive");
assert!(a1 > 0.0, "a1 must be positive");
let ratio = a2 / a1;
(2.0 * (p1 - p2) / (density * (1.0 - ratio * ratio))).sqrt()
}
pub fn drag_force(drag_coefficient: f64, density: f64, area: f64, velocity: f64) -> f64 {
0.5 * drag_coefficient * density * area * velocity * velocity
}
pub fn terminal_velocity(mass: f64, g: f64, density: f64, area: f64, drag_coefficient: f64) -> f64 {
assert!(density > 0.0, "density must be positive");
assert!(area > 0.0, "area must be positive");
assert!(drag_coefficient > 0.0, "drag_coefficient must be positive");
(2.0 * mass * g / (density * area * drag_coefficient)).sqrt()
}
pub fn stokes_drag(dynamic_viscosity: f64, radius: f64, velocity: f64) -> f64 {
6.0 * constants::PI * dynamic_viscosity * radius * velocity
}
pub fn reynolds_number(density: f64, velocity: f64, length: f64, dynamic_viscosity: f64) -> f64 {
assert!(dynamic_viscosity > 0.0, "dynamic_viscosity must be positive");
density * velocity * length / dynamic_viscosity
}
pub fn poiseuille_flow_rate(
radius: f64,
pressure_drop: f64,
dynamic_viscosity: f64,
length: f64,
) -> f64 {
assert!(dynamic_viscosity > 0.0, "dynamic_viscosity must be positive");
assert!(length > 0.0, "length must be positive");
constants::PI * radius.powi(4) * pressure_drop / (8.0 * dynamic_viscosity * length)
}
pub fn surface_tension_force(surface_tension: f64, length: f64) -> f64 {
surface_tension * length
}
pub fn capillary_rise(
surface_tension: f64,
contact_angle_rad: f64,
density: f64,
g: f64,
tube_radius: f64,
) -> f64 {
assert!(density > 0.0, "density must be positive");
assert!(g > 0.0, "g must be positive");
assert!(tube_radius > 0.0, "tube_radius must be positive");
2.0 * surface_tension * contact_angle_rad.cos() / (density * g * tube_radius)
}
pub fn mach_number(velocity: f64, speed_of_sound: f64) -> f64 {
assert!(speed_of_sound > 0.0, "speed_of_sound must be positive");
velocity / speed_of_sound
}
pub fn dynamic_pressure(density: f64, velocity: f64) -> f64 {
0.5 * density * velocity * velocity
}
pub fn stagnation_pressure(static_pressure: f64, dynamic_pressure: f64) -> f64 {
static_pressure + dynamic_pressure
}
pub fn isentropic_pressure_ratio(mach: f64, gamma: f64) -> f64 {
assert!(gamma != 1.0, "gamma must not equal 1.0");
let exponent = -gamma / (gamma - 1.0);
(1.0 + (gamma - 1.0) / 2.0 * mach * mach).powf(exponent)
}
pub fn isentropic_temperature_ratio(mach: f64, gamma: f64) -> f64 {
1.0 / (1.0 + (gamma - 1.0) / 2.0 * mach * mach)
}
pub fn vorticity_2d(dvx_dy: f64, dvy_dx: f64) -> f64 {
dvy_dx - dvx_dy
}
pub fn circulation(vorticity: f64, area: f64) -> f64 {
vorticity * area
}
pub fn kutta_joukowski_lift(density: f64, velocity: f64, circulation: f64) -> f64 {
density * velocity * circulation
}
pub fn kinematic_viscosity(dynamic_viscosity: f64, density: f64) -> f64 {
assert!(density > 0.0, "density must be positive");
dynamic_viscosity / density
}
pub fn pressure_gradient_pipe(
flow_rate: f64,
dynamic_viscosity: f64,
radius: f64,
length: f64,
) -> f64 {
assert!(radius > 0.0, "radius must be positive");
8.0 * dynamic_viscosity * length * flow_rate / (constants::PI * radius.powi(4))
}
pub fn hydraulic_diameter(area: f64, wetted_perimeter: f64) -> f64 {
assert!(wetted_perimeter > 0.0, "wetted_perimeter must be positive");
4.0 * area / wetted_perimeter
}
pub fn darcy_friction_factor_laminar(reynolds: f64) -> f64 {
assert!(reynolds > 0.0, "reynolds must be positive");
64.0 / reynolds
}
pub fn darcy_weisbach_head_loss(
friction_factor: f64,
length: f64,
diameter: f64,
velocity: f64,
g: f64,
) -> f64 {
assert!(diameter > 0.0, "diameter must be positive");
assert!(g > 0.0, "g must be positive");
friction_factor * (length / diameter) * velocity * velocity / (2.0 * g)
}
pub fn buoyancy_velocity(g: f64, beta: f64, delta_temp: f64, length: f64) -> f64 {
(g * beta * delta_temp * length).sqrt()
}
pub fn thermal_expansion_coefficient_ideal_gas(temperature: f64) -> f64 {
assert!(temperature > 0.0, "temperature must be positive");
1.0 / temperature
}
pub fn viscosity_sutherland(mu0: f64, t0: f64, t: f64, s: f64) -> f64 {
assert!(t0 > 0.0, "t0 must be positive");
assert!(t + s != 0.0, "t + s must not be zero");
mu0 * (t / t0).powf(1.5) * (t0 + s) / (t + s)
}
pub fn thermal_conductivity_gas(k0: f64, t0: f64, t: f64, s: f64) -> f64 {
assert!(t0 > 0.0, "t0 must be positive");
assert!(t + s != 0.0, "t + s must not be zero");
k0 * (t / t0).powf(1.5) * (t0 + s) / (t + s)
}
pub fn natural_convection_nu_vertical(rayleigh: f64) -> f64 {
let term = 0.825 + 0.387 * rayleigh.powf(1.0 / 6.0) / 1.1936;
term * term
}
pub fn natural_convection_nu_horizontal_hot(rayleigh: f64) -> f64 {
0.54 * rayleigh.powf(0.25)
}
pub fn marangoni_number(
surface_tension_gradient: f64,
length: f64,
delta_temp: f64,
dynamic_viscosity: f64,
thermal_diffusivity: f64,
) -> f64 {
assert!(dynamic_viscosity > 0.0, "dynamic_viscosity must be positive");
assert!(thermal_diffusivity > 0.0, "thermal_diffusivity must be positive");
-surface_tension_gradient * length * delta_temp
/ (dynamic_viscosity * thermal_diffusivity)
}
pub fn bond_number(density_diff: f64, g: f64, length: f64, surface_tension: f64) -> f64 {
assert!(surface_tension > 0.0, "surface_tension must be positive");
density_diff * g * length * length / surface_tension
}
pub fn weber_number(density: f64, velocity: f64, length: f64, surface_tension: f64) -> f64 {
assert!(surface_tension > 0.0, "surface_tension must be positive");
density * velocity * velocity * length / surface_tension
}
pub fn froude_number(velocity: f64, g: f64, length: f64) -> f64 {
assert!(g > 0.0, "g must be positive");
assert!(length > 0.0, "length must be positive");
velocity / (g * length).sqrt()
}
pub fn archimedes_number(
density_fluid: f64,
density_particle: f64,
diameter: f64,
dynamic_viscosity: f64,
g: f64,
) -> f64 {
assert!(dynamic_viscosity != 0.0, "dynamic_viscosity must not be zero");
g * diameter.powi(3) * density_fluid * (density_particle - density_fluid)
/ (dynamic_viscosity * dynamic_viscosity)
}
pub fn peclet_number(velocity: f64, length: f64, diffusivity: f64) -> f64 {
assert!(diffusivity > 0.0, "diffusivity must be positive");
velocity * length / diffusivity
}
#[cfg(test)]
mod tests {
use super::*;
fn approx(a: f64, b: f64, tol: f64) -> bool {
(a - b).abs() < tol
}
fn approx_rel(a: f64, b: f64, tol: f64) -> bool {
((a - b) / b).abs() < tol
}
#[test]
fn test_hydrostatic_pressure() {
let p = hydrostatic_pressure(1000.0, 9.8, 10.0);
assert!(approx(p, 98000.0, 0.1));
}
#[test]
fn test_buoyant_force() {
let f = buoyant_force(1000.0, 0.001, 9.8);
assert!(approx(f, 9.8, 1e-6));
}
#[test]
fn test_bernoulli() {
let p2 = bernoulli_pressure(100000.0, 1000.0, 2.0, 0.0, 4.0, 0.0, 9.8);
assert!(p2 < 100000.0);
}
#[test]
fn test_torricelli() {
let v = torricelli_velocity(9.8, 5.0);
assert!(approx_rel(v, 9.899, 0.01));
}
#[test]
fn test_drag_force() {
let f = drag_force(0.47, 1.225, 0.01, 10.0);
assert!(approx_rel(f, 0.287875, 0.01));
}
#[test]
fn test_reynolds_number() {
let re = reynolds_number(1000.0, 1.0, 0.1, 0.001);
assert!(approx(re, 100000.0, 1.0));
}
#[test]
fn test_continuity() {
let v2 = continuity_velocity(0.1, 2.0, 0.05);
assert!(approx(v2, 4.0, 1e-9));
}
#[test]
fn test_pascal() {
let f2 = pascal_force(100.0, 0.01, 1.0);
assert!(approx(f2, 10000.0, 1e-6));
}
#[test]
fn test_mach_number() {
let m = mach_number(340.0, 343.0);
assert!(approx_rel(m, 0.99125, 0.01));
}
#[test]
fn test_dynamic_pressure() {
let q = dynamic_pressure(1.225, 50.0);
assert!(approx(q, 1531.25, 0.01));
}
#[test]
fn test_stagnation_pressure() {
let p0 = stagnation_pressure(101325.0, 1531.25);
assert!(approx(p0, 102856.25, 0.01));
}
#[test]
fn test_isentropic_pressure_ratio() {
let ratio = isentropic_pressure_ratio(0.5, 1.4);
assert!(approx_rel(ratio, 0.8430, 0.01));
}
#[test]
fn test_isentropic_temperature_ratio() {
let ratio = isentropic_temperature_ratio(0.5, 1.4);
assert!(approx_rel(ratio, 0.95238, 0.001));
}
#[test]
fn test_vorticity_2d() {
let omega = vorticity_2d(1.0, 3.0);
assert!(approx(omega, 2.0, 1e-9));
}
#[test]
fn test_circulation() {
let gamma = circulation(2.0, 5.0);
assert!(approx(gamma, 10.0, 1e-9));
}
#[test]
fn test_kutta_joukowski_lift() {
let lift = kutta_joukowski_lift(1.225, 50.0, 10.0);
assert!(approx(lift, 612.5, 0.01));
}
#[test]
fn test_kinematic_viscosity() {
let nu = kinematic_viscosity(0.001, 1000.0);
assert!(approx(nu, 1e-6, 1e-12));
}
#[test]
fn test_pressure_gradient_pipe() {
let radius = 0.01;
let mu = 0.001;
let length = 1.0;
let dp = 1000.0;
let q = poiseuille_flow_rate(radius, dp, mu, length);
let dp_back = pressure_gradient_pipe(q, mu, radius, length);
assert!(approx_rel(dp_back, dp, 1e-9));
}
#[test]
fn test_hydraulic_diameter() {
let dh = hydraulic_diameter(0.01, 0.4);
assert!(approx(dh, 0.1, 1e-9));
}
#[test]
fn test_darcy_friction_factor_laminar() {
let f = darcy_friction_factor_laminar(2000.0);
assert!(approx(f, 0.032, 1e-9));
}
#[test]
fn test_darcy_weisbach_head_loss() {
let hl = darcy_weisbach_head_loss(0.032, 10.0, 0.1, 2.0, 9.81);
assert!(approx_rel(hl, 0.6524, 0.01));
}
#[test]
fn test_buoyancy_velocity() {
let v = buoyancy_velocity(9.81, 0.003, 20.0, 1.0);
assert!(approx_rel(v, 0.7673, 0.01));
}
#[test]
fn test_thermal_expansion_coefficient_ideal_gas() {
let beta = thermal_expansion_coefficient_ideal_gas(300.0);
assert!(approx_rel(beta, 0.003333, 0.01));
}
#[test]
fn test_viscosity_sutherland() {
let mu = viscosity_sutherland(1.716e-5, 273.15, 400.0, 110.4);
assert!(approx_rel(mu, 2.272e-5, 0.01));
}
#[test]
fn test_thermal_conductivity_gas() {
let k = thermal_conductivity_gas(0.0241, 273.15, 500.0, 194.0);
assert!(approx_rel(k, 0.04018, 0.02));
}
#[test]
fn test_natural_convection_nu_vertical() {
let nu = natural_convection_nu_vertical(1e9);
assert!(approx_rel(nu, 122.45, 0.02));
}
#[test]
fn test_natural_convection_nu_horizontal_hot() {
let nu = natural_convection_nu_horizontal_hot(1e6);
assert!(approx_rel(nu, 17.076, 0.01));
}
#[test]
fn test_marangoni_number() {
let ma = marangoni_number(-1.5e-4, 0.01, 10.0, 0.001, 1.5e-7);
assert!(approx_rel(ma, 100000.0, 0.01));
}
#[test]
fn test_bond_number() {
let bo = bond_number(1000.0, 9.81, 0.001, 0.0728);
assert!(approx_rel(bo, 0.1348, 0.01));
}
#[test]
fn test_weber_number() {
let we = weber_number(1000.0, 10.0, 0.002, 0.0728);
assert!(approx_rel(we, 2747.3, 0.01));
}
#[test]
fn test_froude_number() {
let fr = froude_number(3.0, 9.81, 1.0);
assert!(approx_rel(fr, 0.9582, 0.01));
}
#[test]
fn test_archimedes_number() {
let ar = archimedes_number(1000.0, 2650.0, 0.001, 0.001, 9.81);
assert!(approx_rel(ar, 16178.5, 0.01));
}
#[test]
fn test_peclet_number() {
let pe = peclet_number(0.1, 0.01, 1.43e-7);
assert!(approx_rel(pe, 6993.0, 0.01));
}
#[test]
fn test_total_pressure() {
let p = total_pressure(101325.0, 1000.0, 9.8, 10.0);
assert!(approx(p, 199325.0, 0.1));
}
#[test]
fn test_pressure() {
let p = pressure(500.0, 0.1);
assert!(approx(p, 5000.0, 1e-9));
}
#[test]
fn test_fraction_submerged() {
let f = fraction_submerged(600.0, 1000.0);
assert!(approx(f, 0.6, 1e-9));
}
#[test]
fn test_apparent_weight() {
let w = apparent_weight(5.0, 0.000633, 1000.0, 9.8);
assert!(approx(w, 42.7966, 1e-3));
}
#[test]
fn test_flow_rate() {
let q = flow_rate(0.01, 3.0);
assert!(approx(q, 0.03, 1e-9));
}
#[test]
fn test_mass_flow_rate() {
let m = mass_flow_rate(1000.0, 0.01, 3.0);
assert!(approx(m, 30.0, 1e-9));
}
#[test]
fn test_venturi_velocity() {
let v = venturi_velocity(200000.0, 180000.0, 1000.0, 0.1, 0.05);
assert!(approx_rel(v, 7.303, 0.001));
}
#[test]
fn test_terminal_velocity() {
let v = terminal_velocity(0.01, 9.8, 1.225, 0.001, 0.47);
assert!(approx_rel(v, 18.449, 0.001));
}
#[test]
fn test_stokes_drag() {
let f = stokes_drag(0.001, 0.001, 0.01);
assert!(approx_rel(f, 1.884956e-7, 1e-4));
}
#[test]
fn test_surface_tension_force() {
let f = surface_tension_force(0.0728, 0.1);
assert!(approx(f, 0.00728, 1e-9));
}
#[test]
fn test_capillary_rise() {
let h = capillary_rise(0.0728, 0.0, 1000.0, 9.8, 0.0005);
assert!(approx_rel(h, 0.029714, 0.001));
}
}