use crate::fluid::{Fluid, G};
#[derive(Debug, Clone)]
pub struct CapillaryRise {
pub fluid: Fluid,
pub radius_m: f64,
pub contact_angle_deg: f64,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CapillaryResult {
pub height_m: f64,
pub capillary_pressure_pa: f64,
pub hydrostatic_pressure_pa: f64,
}
impl CapillaryRise {
pub fn new(fluid: Fluid, radius_m: f64, contact_angle_deg: f64) -> Self {
Self {
fluid,
radius_m,
contact_angle_deg,
}
}
pub fn calculate(&self) -> CapillaryResult {
let cos_theta = cos_deg(self.contact_angle_deg);
let capillary_pressure_pa =
2.0 * self.fluid.surface_tension_n_m * cos_theta / self.radius_m;
let height_m = capillary_pressure_pa / (self.fluid.density_kg_m3 * G);
let hydrostatic_pressure_pa = self.fluid.density_kg_m3 * G * height_m;
CapillaryResult {
height_m,
capillary_pressure_pa,
hydrostatic_pressure_pa,
}
}
}
#[inline]
fn cos_deg(deg: f64) -> f64 {
let rad = deg * core::f64::consts::PI / 180.0;
rad.cos()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fluid::Fluid;
#[test]
fn test_capillary_rise_1mm_water_20c() {
let fluid = Fluid::water(20.0);
let calc = CapillaryRise::new(fluid, 0.001, 0.0);
let result = calc.calculate();
assert!(
(result.height_m - 0.01486).abs() < 0.001,
"height = {:.5} m",
result.height_m
);
}
#[test]
fn test_capillary_depression_mercury() {
let fluid = Fluid::custom(20.0, 13_534.0, 1.526e-3, 0.4865, 0.16);
let calc = CapillaryRise::new(fluid, 0.001, 140.0);
let result = calc.calculate();
assert!(result.height_m < 0.0, "Mercury should be depressed: {}", result.height_m);
}
#[test]
fn test_capillary_pressure_positive_wetting() {
let fluid = Fluid::water(20.0);
let calc = CapillaryRise::new(fluid, 0.001, 0.0);
let result = calc.calculate();
assert!(result.capillary_pressure_pa > 0.0);
}
}