thermalcomfort/lib.rs
1//! # Thermal Comfort Library
2//!
3//! A comprehensive Rust port of the pythermalcomfort Python package for thermal comfort calculations.
4//! This library is `no_std` compatible and can run in WASM environments.
5//!
6//! This library provides tools for calculating thermal comfort indices, heat/cold stress metrics,
7//! and thermophysiological responses using multiple models including:
8//!
9//! - PMV/PPD (Predicted Mean Vote and Predicted Percentage Dissatisfied) - ISO 7730 & ASHRAE 55
10//! - Adaptive comfort models (ASHRAE 55 and EN 16798)
11//! - UTCI (Universal Thermal Climate Index)
12//! - SET (Standard Effective Temperature)
13//! - Heat stress indices (WBGT, Heat Index, etc.)
14//! - And many more...
15//!
16//! ## Example
17//!
18//! ```
19//! use thermalcomfort::{pmv_ppd_iso, v_relative, Temperature, Speed, Humidity, MetabolicRate, ClothingInsulation};
20//!
21//! let tdb = Temperature::from_celsius(25.0);
22//! let tr = Temperature::from_celsius(25.0);
23//! let rh = Humidity::from_percent(50.0);
24//! let v = Speed::from_meters_per_second(0.1);
25//! let met = MetabolicRate::from_met(1.4);
26//! let clo = ClothingInsulation::from_clo(0.5);
27//!
28//! // Calculate relative air speed
29//! let vr = v_relative(v, met);
30//!
31//! // Calculate PMV and PPD
32//! let result = pmv_ppd_iso(
33//! tdb,
34//! tr,
35//! vr,
36//! rh,
37//! met,
38//! clo,
39//! Default::default()
40//! );
41//! ```
42
43#![no_std]
44
45pub mod constants;
46pub mod models;
47pub mod numerical;
48pub mod psychrometrics;
49pub mod utilities;
50
51// Re-export commonly used items
52pub use models::pmv::{PmvPpdResult, pmv_ppd_iso};
53pub use utilities::{
54 CLO_INDIVIDUAL_GARMENTS, CLO_TYPICAL_ENSEMBLES, clo_individual_garment, clo_typical_ensemble,
55 v_relative,
56};
57
58// Re-export measurements types for convenience
59// Users should import these from thermalcomfort instead of directly from measurements
60pub use measurements::{Area, Humidity, Length, Mass, Power, Pressure, Speed, Temperature};
61
62/// Clothing insulation measurement.
63///
64/// Represents thermal resistance of clothing per unit body surface area.
65/// 1 clo = 0.155 m²·K/W ≈ the insulation of a typical business suit.
66///
67/// # Constructors
68///
69/// - [`from_clo(0.5)`](ClothingInsulation::from_clo) — primary; clo values found in ASHRAE 55 / ISO 7730 clothing tables
70/// - [`from_tog(0.775)`](ClothingInsulation::from_tog) — tog units common in bedding industry (1 clo = 1.55 tog)
71/// - [`from_m2_k_per_w(0.0775)`](ClothingInsulation::from_m2_k_per_w) — SI thermal resistance (1 clo = 0.155 m²·K/W)
72///
73/// # Common Values (clo)
74///
75/// | Ensemble | clo |
76/// |----------|-----|
77/// | Nude | ≈ 0 |
78/// | Light summer (shorts, t-shirt) | 0.3–0.5 |
79/// | Typical business suit | 1.0 |
80/// | Heavy winter clothing | 1.5 |
81///
82/// # Examples
83///
84/// ```
85/// use thermalcomfort::ClothingInsulation;
86///
87/// let clo = ClothingInsulation::from_clo(1.0);
88/// assert!((clo.as_m2_k_per_w() - 0.155).abs() < 1e-10);
89/// assert!((clo.as_tog() - 1.55).abs() < 1e-10);
90/// ```
91#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
92pub struct ClothingInsulation(f64);
93
94impl ClothingInsulation {
95 /// Create from clo units (1 clo = 0.155 m²·K/W)
96 #[inline]
97 pub const fn from_clo(value: f64) -> Self {
98 Self(value)
99 }
100
101 /// Create from tog units (1 clo = 1.55 tog)
102 #[inline]
103 pub fn from_tog(value: f64) -> Self {
104 Self(value / 1.55)
105 }
106
107 /// Create from SI thermal resistance (m²·K/W) (1 clo = 0.155 m²·K/W)
108 #[inline]
109 pub fn from_m2_k_per_w(value: f64) -> Self {
110 Self(value / 0.155)
111 }
112
113 /// Get value in clo units
114 #[inline]
115 pub const fn as_clo(&self) -> f64 {
116 self.0
117 }
118
119 /// Get value in tog units (1 clo = 1.55 tog)
120 #[inline]
121 pub fn as_tog(&self) -> f64 {
122 self.0 * 1.55
123 }
124
125 /// Get value in SI thermal resistance (m²·K/W) (1 clo = 0.155 m²·K/W)
126 #[inline]
127 pub fn as_m2_k_per_w(&self) -> f64 {
128 self.0 * 0.155
129 }
130}
131
132impl Default for ClothingInsulation {
133 fn default() -> Self {
134 Self(0.0)
135 }
136}
137
138/// Metabolic rate measurement.
139///
140/// Represents metabolic heat production per unit body surface area.
141/// 1 met = 58.15 W/m², the resting metabolic rate of a seated person.
142///
143/// # Constructors
144///
145/// - [`from_met(1.4)`](MetabolicRate::from_met) — primary; met values found in ASHRAE 55 / ISO 7730 activity tables
146/// - [`from_w_per_m2(81.41)`](MetabolicRate::from_w_per_m2) — SI heat flux per body surface area (1 met = 58.15 W/m²)
147/// - [`from_btu_per_h_ft2(25.76)`](MetabolicRate::from_btu_per_h_ft2) — Imperial equivalent (1 met = 18.4 Btu/(h·ft²))
148///
149/// # Common Values (met)
150///
151/// | Activity | met |
152/// |----------|-----|
153/// | Seated, quiet | 1.0 |
154/// | Standing, relaxed | 1.2 |
155/// | Walking 3.2 km/h | 2.0 |
156/// | Heavy work | 3.0+ |
157///
158/// # Examples
159///
160/// ```
161/// use thermalcomfort::MetabolicRate;
162///
163/// let met = MetabolicRate::from_met(1.0);
164/// assert!((met.as_w_per_m2() - 58.15).abs() < 1e-10);
165/// ```
166#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
167pub struct MetabolicRate(f64);
168
169impl MetabolicRate {
170 /// Conversion factor: 1 met = 58.15 W/m²
171 pub const MET_TO_W_M2: f64 = 58.15;
172
173 /// Conversion factor: 1 met = 18.4 Btu/(h·ft²)
174 pub const MET_TO_BTU_H_FT2: f64 = 18.4;
175
176 /// Create from met units (1 met = 58.15 W/m²)
177 #[inline]
178 pub const fn from_met(value: f64) -> Self {
179 Self(value)
180 }
181
182 /// Create from W/m² (1 met = 58.15 W/m²)
183 #[inline]
184 pub fn from_w_per_m2(value: f64) -> Self {
185 Self(value / Self::MET_TO_W_M2)
186 }
187
188 /// Create from Btu/(h·ft²) (1 met = 18.4 Btu/(h·ft²))
189 #[inline]
190 pub fn from_btu_per_h_ft2(value: f64) -> Self {
191 Self(value / Self::MET_TO_BTU_H_FT2)
192 }
193
194 /// Get value in met units
195 #[inline]
196 pub const fn as_met(&self) -> f64 {
197 self.0
198 }
199
200 /// Get value in W/m² (1 met = 58.15 W/m²)
201 #[inline]
202 pub fn as_w_per_m2(&self) -> f64 {
203 self.0 * Self::MET_TO_W_M2
204 }
205
206 /// Get value in Btu/(h·ft²) (1 met = 18.4 Btu/(h·ft²))
207 #[inline]
208 pub fn as_btu_per_h_ft2(&self) -> f64 {
209 self.0 * Self::MET_TO_BTU_H_FT2
210 }
211}
212
213impl Default for MetabolicRate {
214 fn default() -> Self {
215 Self(0.0)
216 }
217}
218
219/// Biological sex for physiological calculations
220///
221/// Used in models that differentiate physiological responses by sex,
222/// such as PET (basal metabolism) and ridge regression (body temperature prediction).
223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
224pub enum Sex {
225 Male,
226 Female,
227}
228
229impl Sex {
230 /// Get numeric value (0.0 for Male, 1.0 for Female)
231 ///
232 /// Used internally by ridge regression and other models.
233 pub fn as_value(&self) -> f64 {
234 match self {
235 Sex::Male => 0.0,
236 Sex::Female => 1.0,
237 }
238 }
239}