#[must_use]
#[inline]
pub fn mohs_to_vickers(mohs: f64) -> f64 {
if mohs <= 0.0 {
return 0.0;
}
3.0 * mohs.clamp(1.0, 10.0).powf(3.3)
}
#[must_use]
pub fn porosity_to_permeability(porosity: f64, grain_diameter_m: f64) -> f64 {
let phi = porosity.clamp(0.0, 0.99);
let d2 = grain_diameter_m * grain_diameter_m;
let one_minus_phi = 1.0 - phi;
if one_minus_phi <= 0.0 {
return 0.0;
}
d2 * phi.powi(3) / (180.0 * one_minus_phi * one_minus_phi)
}
#[must_use]
#[inline]
pub fn elastic_to_p_wave_velocity(youngs_modulus_pa: f64, density_kg_m3: f64) -> f64 {
if density_kg_m3 <= 0.0 || youngs_modulus_pa <= 0.0 {
return 0.0;
}
let nu = 0.25;
let factor = (1.0 - nu) / ((1.0 + nu) * (1.0 - 2.0 * nu));
(youngs_modulus_pa * factor / density_kg_m3).sqrt()
}
#[must_use]
#[inline]
pub fn depth_to_temperature(
surface_temperature_c: f64,
depth_m: f64,
gradient_c_per_km: f64,
) -> f64 {
surface_temperature_c + gradient_c_per_km * depth_m / 1000.0
}
#[must_use]
#[inline]
pub fn conductivity_to_heat_flow(conductivity_w_per_m_k: f64, gradient_c_per_m: f64) -> f64 {
conductivity_w_per_m_k * gradient_c_per_m
}
#[must_use]
#[inline]
pub fn element_to_oxide_pct(si_pct: f64, al_pct: f64) -> (f64, f64) {
let sio2 = si_pct * 2.139;
let al2o3 = al_pct * 1.889;
(sio2, al2o3)
}
#[must_use]
#[inline]
pub fn grade_to_yield_kg_per_tonne(grade_percent: f64, recovery_fraction: f64) -> f64 {
(grade_percent / 100.0) * recovery_fraction.clamp(0.0, 1.0) * 1000.0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mohs_to_vickers_quartz() {
let hv = mohs_to_vickers(7.0);
assert!(hv > 500.0 && hv < 2000.0, "quartz HV: {hv}");
}
#[test]
fn mohs_to_vickers_talc() {
let hv = mohs_to_vickers(1.0);
assert!(hv < 100.0, "talc HV: {hv}");
}
#[test]
fn mohs_zero() {
assert_eq!(mohs_to_vickers(0.0), 0.0);
}
#[test]
fn porosity_to_permeability_sandstone() {
let k = porosity_to_permeability(0.2, 0.0005);
assert!(k > 1e-14 && k < 1e-10, "sandstone k: {k}");
}
#[test]
fn porosity_zero() {
assert_eq!(porosity_to_permeability(0.0, 0.001), 0.0);
}
#[test]
fn p_wave_granite() {
let vp = elastic_to_p_wave_velocity(50e9, 2700.0);
assert!(vp > 3000.0 && vp < 7000.0, "granite Vp: {vp}");
}
#[test]
fn p_wave_zero_density() {
assert_eq!(elastic_to_p_wave_velocity(50e9, 0.0), 0.0);
}
#[test]
fn depth_temp_surface() {
let t = depth_to_temperature(15.0, 0.0, 30.0);
assert!((t - 15.0).abs() < 0.01);
}
#[test]
fn depth_temp_1km() {
let t = depth_to_temperature(15.0, 1000.0, 30.0);
assert!((t - 45.0).abs() < 0.01);
}
#[test]
fn heat_flow_basic() {
let q = conductivity_to_heat_flow(3.0, 0.03);
assert!((q - 0.09).abs() < 0.001);
}
#[test]
fn element_to_oxide_silicon() {
let (sio2, _) = element_to_oxide_pct(46.7, 0.0);
assert!((sio2 - 99.9).abs() < 1.0);
}
#[test]
fn grade_to_yield_copper() {
let y = grade_to_yield_kg_per_tonne(1.0, 0.9);
assert!((y - 9.0).abs() < 0.01);
}
#[test]
fn grade_to_yield_zero_recovery() {
assert_eq!(grade_to_yield_kg_per_tonne(5.0, 0.0), 0.0);
}
}