#[must_use]
#[inline]
pub fn reaction_heat_release(enthalpy_j_per_mol: f64, molar_rate_mol_per_s: f64) -> f64 {
-enthalpy_j_per_mol * molar_rate_mol_per_s
}
#[must_use]
#[inline]
pub fn activation_energy_to_rate_factor(
activation_energy_j_per_mol: f64,
temperature_k: f64,
) -> f64 {
const R: f64 = 8.314; if temperature_k <= 0.0 {
return 0.0;
}
(-activation_energy_j_per_mol / (R * temperature_k)).exp()
}
#[must_use]
#[inline]
pub fn equilibrium_to_gibbs(equilibrium_constant: f64, temperature_k: f64) -> f64 {
const R: f64 = 8.314;
if equilibrium_constant <= 0.0 || temperature_k <= 0.0 {
return 0.0;
}
-R * temperature_k * equilibrium_constant.ln()
}
#[must_use]
pub fn atomic_number_to_valence(atomic_number: u8) -> u8 {
match atomic_number {
1 => 1,
2 => 2, 3..=4 => atomic_number - 2, 5..=10 => atomic_number - 2, 11..=12 => atomic_number - 10, 13..=18 => atomic_number - 10, _ => {
2
}
}
}
#[must_use]
#[inline]
pub fn ionization_to_bond_energy_estimate(ionization_energy_ev: f64) -> f64 {
(0.5 * ionization_energy_ev).max(0.0)
}
#[must_use]
pub fn electrochemical_current_density(
cell_potential_v: f64,
equilibrium_potential_v: f64,
exchange_current_density_a_m2: f64,
temperature_k: f64,
n_electrons: u32,
) -> f64 {
const F: f64 = 96_485.332; const R: f64 = 8.314; if temperature_k <= 0.0 {
return 0.0;
}
let eta = cell_potential_v - equilibrium_potential_v; let n = n_electrons as f64;
exchange_current_density_a_m2 * n * F * eta / (R * temperature_k)
}
#[must_use]
#[inline]
pub fn ionic_concentration_to_conductivity(concentration_mol_per_l: f64) -> f64 {
let c_mol_m3 = concentration_mol_per_l * 1000.0;
let lambda_m = 0.01; c_mol_m3 * lambda_m
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reaction_heat_exothermic() {
let q = reaction_heat_release(-100_000.0, 0.1);
assert!((q - 10_000.0).abs() < 0.1);
}
#[test]
fn reaction_heat_endothermic() {
let q = reaction_heat_release(50_000.0, 0.1);
assert!((q - (-5_000.0)).abs() < 0.1);
}
#[test]
fn arrhenius_factor_room_temp() {
let f = activation_energy_to_rate_factor(50_000.0, 298.0);
assert!(f > 1e-10 && f < 1e-8);
}
#[test]
fn arrhenius_factor_zero_temp() {
assert_eq!(activation_energy_to_rate_factor(50_000.0, 0.0), 0.0);
}
#[test]
fn gibbs_from_equilibrium() {
let g = equilibrium_to_gibbs(1.0, 298.0);
assert!(g.abs() < 0.01);
}
#[test]
fn gibbs_favorable() {
let g = equilibrium_to_gibbs(100.0, 298.0);
assert!(g < 0.0);
}
#[test]
fn valence_carbon() {
assert_eq!(atomic_number_to_valence(6), 4);
}
#[test]
fn valence_sodium() {
assert_eq!(atomic_number_to_valence(11), 1);
}
#[test]
fn valence_chlorine() {
assert_eq!(atomic_number_to_valence(17), 7);
}
#[test]
fn valence_transition_metal() {
assert_eq!(atomic_number_to_valence(26), 2);
}
#[test]
fn bond_energy_estimate() {
let d = ionization_to_bond_energy_estimate(13.6);
assert!((d - 6.8).abs() < 0.01);
}
#[test]
fn electrochemical_current_basic() {
let j = electrochemical_current_density(0.1, 0.0, 1.0, 298.0, 2);
assert!(j > 0.0);
}
#[test]
fn electrochemical_current_zero_overpotential() {
let j = electrochemical_current_density(0.5, 0.5, 1.0, 298.0, 1);
assert!(j.abs() < 0.01);
}
#[test]
fn electrochemical_current_zero_temp() {
assert_eq!(electrochemical_current_density(0.1, 0.0, 1.0, 0.0, 1), 0.0);
}
#[test]
fn conductivity_basic() {
let k = ionic_concentration_to_conductivity(1.0);
assert!((k - 10.0).abs() < 0.01);
}
}