use_thermodynamics/
lib.rs1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::fmt;
7
8pub mod prelude;
9
10pub const IDEAL_GAS_CONSTANT: f64 = 8.314_462_618_153_24;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ThermodynamicsError {
14 NonPositiveTemperature,
15 NonPositiveVolume,
16}
17
18impl fmt::Display for ThermodynamicsError {
19 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match self {
21 Self::NonPositiveTemperature => {
22 formatter.write_str("temperature must be greater than zero kelvin")
23 },
24 Self::NonPositiveVolume => formatter.write_str("volume must be greater than zero"),
25 }
26 }
27}
28
29impl std::error::Error for ThermodynamicsError {}
30
31#[must_use]
32pub const fn celsius_to_kelvin(celsius: f64) -> f64 {
33 celsius + 273.15
34}
35
36#[must_use]
37pub const fn heat_energy(mass: f64, specific_heat_capacity: f64, delta_temperature: f64) -> f64 {
38 mass * specific_heat_capacity * delta_temperature
39}
40
41pub fn ideal_gas_pressure(
49 moles: f64,
50 temperature_kelvin: f64,
51 volume: f64,
52) -> Result<f64, ThermodynamicsError> {
53 if temperature_kelvin <= 0.0 {
54 Err(ThermodynamicsError::NonPositiveTemperature)
55 } else if volume <= 0.0 {
56 Err(ThermodynamicsError::NonPositiveVolume)
57 } else {
58 Ok((moles * IDEAL_GAS_CONSTANT * temperature_kelvin) / volume)
59 }
60}
61
62#[cfg(test)]
63#[allow(clippy::float_cmp)]
64mod tests {
65 use super::{
66 IDEAL_GAS_CONSTANT, ThermodynamicsError, celsius_to_kelvin, heat_energy, ideal_gas_pressure,
67 };
68
69 #[test]
70 fn thermodynamics_helpers_cover_common_calculations() -> Result<(), ThermodynamicsError> {
71 let pressure = ideal_gas_pressure(2.0, 300.0, 3.0)?;
72 let expected = (2.0 * IDEAL_GAS_CONSTANT * 300.0) / 3.0;
73
74 assert!((pressure - expected).abs() < 1.0e-12);
75 assert_eq!(celsius_to_kelvin(0.0), 273.15);
76 assert_eq!(heat_energy(2.0, 4.0, 5.0), 40.0);
77 Ok(())
78 }
79
80 #[test]
81 fn ideal_gas_pressure_requires_positive_state() {
82 assert_eq!(
83 ideal_gas_pressure(1.0, 0.0, 1.0),
84 Err(ThermodynamicsError::NonPositiveTemperature)
85 );
86 assert_eq!(
87 ideal_gas_pressure(1.0, 300.0, 0.0),
88 Err(ThermodynamicsError::NonPositiveVolume)
89 );
90 }
91}