Skip to main content

use_conductivity/
lib.rs

1#![forbid(unsafe_code)]
2//! Primitive conductivity helpers.
3//!
4//! Initial calculations assume SI units unless otherwise documented.
5//!
6//! # Examples
7//!
8//! ```rust
9//! use use_conductivity::{
10//!     ElectricalConductivity, ThermalConductivity, conductivity_from_resistivity,
11//!     heat_flow_rate, resistivity_from_conductivity, thermal_resistance,
12//! };
13//!
14//! let thermal = ThermalConductivity::new(50.0).unwrap();
15//! let electrical = ElectricalConductivity::new(5.8e7).unwrap();
16//!
17//! assert_eq!(thermal.watts_per_meter_kelvin(), 50.0);
18//! assert_eq!(electrical.siemens_per_meter(), 5.8e7);
19//! assert_eq!(thermal_resistance(0.1, 2.0, 50.0).unwrap(), 0.001);
20//! assert_eq!(heat_flow_rate(50.0, 2.0, 10.0, 0.1).unwrap(), 10_000.0);
21//! assert_eq!(resistivity_from_conductivity(2.0).unwrap(), 0.5);
22//! assert_eq!(conductivity_from_resistivity(0.5).unwrap(), 2.0);
23//! ```
24
25#[derive(Debug, Clone, Copy, PartialEq)]
26pub struct ThermalConductivity {
27    watts_per_meter_kelvin: f64,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq)]
31pub struct ElectricalConductivity {
32    siemens_per_meter: f64,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum ConductivityError {
37    InvalidConductivity,
38    InvalidArea,
39    InvalidThickness,
40    InvalidTemperatureDifference,
41    InvalidResistivity,
42}
43
44fn validate_positive(value: f64, error: ConductivityError) -> Result<f64, ConductivityError> {
45    if !value.is_finite() || value <= 0.0 {
46        Err(error)
47    } else {
48        Ok(value)
49    }
50}
51
52fn validate_finite(value: f64, error: ConductivityError) -> Result<f64, ConductivityError> {
53    if !value.is_finite() {
54        Err(error)
55    } else {
56        Ok(value)
57    }
58}
59
60impl ThermalConductivity {
61    pub fn new(watts_per_meter_kelvin: f64) -> Result<Self, ConductivityError> {
62        Ok(Self {
63            watts_per_meter_kelvin: validate_positive(
64                watts_per_meter_kelvin,
65                ConductivityError::InvalidConductivity,
66            )?,
67        })
68    }
69
70    #[must_use]
71    pub fn watts_per_meter_kelvin(&self) -> f64 {
72        self.watts_per_meter_kelvin
73    }
74}
75
76impl ElectricalConductivity {
77    pub fn new(siemens_per_meter: f64) -> Result<Self, ConductivityError> {
78        Ok(Self {
79            siemens_per_meter: validate_positive(
80                siemens_per_meter,
81                ConductivityError::InvalidConductivity,
82            )?,
83        })
84    }
85
86    #[must_use]
87    pub fn siemens_per_meter(&self) -> f64 {
88        self.siemens_per_meter
89    }
90}
91
92pub fn thermal_resistance(
93    thickness_m: f64,
94    area_m2: f64,
95    conductivity_w_per_mk: f64,
96) -> Result<f64, ConductivityError> {
97    Ok(
98        validate_positive(thickness_m, ConductivityError::InvalidThickness)?
99            / (validate_positive(area_m2, ConductivityError::InvalidArea)?
100                * validate_positive(
101                    conductivity_w_per_mk,
102                    ConductivityError::InvalidConductivity,
103                )?),
104    )
105}
106
107pub fn heat_flow_rate(
108    conductivity_w_per_mk: f64,
109    area_m2: f64,
110    delta_temp_k: f64,
111    thickness_m: f64,
112) -> Result<f64, ConductivityError> {
113    Ok(validate_positive(
114        conductivity_w_per_mk,
115        ConductivityError::InvalidConductivity,
116    )? * validate_positive(area_m2, ConductivityError::InvalidArea)?
117        * validate_finite(
118            delta_temp_k,
119            ConductivityError::InvalidTemperatureDifference,
120        )?
121        / validate_positive(thickness_m, ConductivityError::InvalidThickness)?)
122}
123
124pub fn resistivity_from_conductivity(conductivity_s_per_m: f64) -> Result<f64, ConductivityError> {
125    Ok(1.0 / validate_positive(conductivity_s_per_m, ConductivityError::InvalidConductivity)?)
126}
127
128pub fn conductivity_from_resistivity(resistivity_ohm_m: f64) -> Result<f64, ConductivityError> {
129    Ok(1.0 / validate_positive(resistivity_ohm_m, ConductivityError::InvalidResistivity)?)
130}
131
132#[cfg(test)]
133mod tests {
134    use super::{
135        ConductivityError, ElectricalConductivity, ThermalConductivity,
136        conductivity_from_resistivity, heat_flow_rate, resistivity_from_conductivity,
137        thermal_resistance,
138    };
139
140    #[test]
141    fn computes_conductivity_and_resistivity_values() {
142        let thermal = ThermalConductivity::new(50.0).unwrap();
143        let electrical = ElectricalConductivity::new(5.8e7).unwrap();
144
145        assert_eq!(thermal.watts_per_meter_kelvin(), 50.0);
146        assert_eq!(electrical.siemens_per_meter(), 5.8e7);
147        assert_eq!(thermal_resistance(0.1, 2.0, 50.0).unwrap(), 0.001);
148        assert_eq!(heat_flow_rate(50.0, 2.0, 10.0, 0.1).unwrap(), 10_000.0);
149        assert_eq!(resistivity_from_conductivity(2.0).unwrap(), 0.5);
150        assert_eq!(conductivity_from_resistivity(0.5).unwrap(), 2.0);
151    }
152
153    #[test]
154    fn allows_negative_temperature_differences_for_heat_flow_direction() {
155        assert_eq!(heat_flow_rate(50.0, 2.0, -10.0, 0.1).unwrap(), -10_000.0);
156    }
157
158    #[test]
159    fn rejects_invalid_conductivity_inputs() {
160        assert_eq!(
161            ThermalConductivity::new(0.0),
162            Err(ConductivityError::InvalidConductivity)
163        );
164        assert_eq!(
165            ElectricalConductivity::new(f64::NAN),
166            Err(ConductivityError::InvalidConductivity)
167        );
168        assert_eq!(
169            thermal_resistance(0.1, 0.0, 50.0),
170            Err(ConductivityError::InvalidArea)
171        );
172        assert_eq!(
173            heat_flow_rate(50.0, 2.0, f64::NAN, 0.1),
174            Err(ConductivityError::InvalidTemperatureDifference)
175        );
176        assert_eq!(
177            conductivity_from_resistivity(-1.0),
178            Err(ConductivityError::InvalidResistivity)
179        );
180    }
181}