Skip to main content

space_units/quantities/
thermal.rs

1use super::DisplayWithUnit;
2
3// -------------------------
4// Temperature
5// -------------------------
6
7/// A temperature quantity, stored canonically in kelvin (K).
8///
9/// Celsius and Fahrenheit conversions use offset formulas, not simple
10/// scale factors. Addition and subtraction operate on raw kelvin values.
11///
12/// # Construction
13/// ```
14/// use space_units::Temperature;
15/// let t = Temperature::from_c(20.0);
16/// ```
17#[must_use]
18#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
19pub struct Temperature(pub(crate) f64);
20
21/// Display/conversion units for [`Temperature`].
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum TemperatureUnit {
24    /// Kelvin (K) -- SI base unit for temperature.
25    Kelvin,
26    /// Degrees Celsius (degC) -- offset from kelvin by 273.15.
27    Celsius,
28    /// Degrees Fahrenheit (degF) -- offset scale.
29    Fahrenheit,
30    /// Rankine (R) -- absolute scale in Fahrenheit degrees.
31    Rankine,
32}
33
34impl TemperatureUnit {
35    const fn symbol(self) -> &'static str {
36        match self {
37            Self::Kelvin => "K",
38            Self::Celsius => "°C",
39            Self::Fahrenheit => "°F",
40            Self::Rankine => "R",
41        }
42    }
43}
44
45impl Temperature {
46    /// Create from kelvin (K).
47    pub const fn from_k(val: f64) -> Self {
48        Self(val)
49    }
50
51    /// Create from degrees Celsius (degC) -- applies +273.15 offset.
52    pub const fn from_c(val: f64) -> Self {
53        Self(val + 273.15)
54    }
55
56    /// Create from degrees Fahrenheit (degF) -- applies offset conversion.
57    pub const fn from_f(val: f64) -> Self {
58        Self((val - 32.0) * 5.0 / 9.0 + 273.15)
59    }
60
61    /// Create from Rankine (R).
62    pub const fn from_r(val: f64) -> Self {
63        Self(val * 5.0 / 9.0)
64    }
65
66    /// Get value in kelvin (K).
67    pub const fn in_k(self) -> f64 {
68        self.0
69    }
70
71    /// Get value in degrees Celsius (degC).
72    pub const fn in_c(self) -> f64 {
73        self.0 - 273.15
74    }
75
76    /// Get value in degrees Fahrenheit (degF).
77    pub const fn in_f(self) -> f64 {
78        (self.0 - 273.15) * 9.0 / 5.0 + 32.0
79    }
80
81    /// Get value in Rankine (R).
82    pub const fn in_r(self) -> f64 {
83        self.0 * 9.0 / 5.0
84    }
85
86    /// Return a display wrapper that formats this temperature in the given unit.
87    pub const fn display_as(self, unit: TemperatureUnit) -> DisplayWithUnit {
88        let value = match unit {
89            TemperatureUnit::Kelvin => self.0,
90            TemperatureUnit::Celsius => self.in_c(),
91            TemperatureUnit::Fahrenheit => self.in_f(),
92            TemperatureUnit::Rankine => self.in_r(),
93        };
94        DisplayWithUnit {
95            value,
96            symbol: unit.symbol(),
97        }
98    }
99
100    /// Return the absolute value of this temperature.
101    pub fn abs(self) -> Self {
102        Self(self.0.abs())
103    }
104}
105
106impl_quantity_display!(Temperature, "K");
107
108impl_common_ops!(Temperature);
109
110// -------------------------
111// Heat flux
112// -------------------------
113
114/// A heat flux quantity, stored canonically in watts per square meter (W/m²).
115///
116/// # Construction
117/// ```
118/// use space_units::HeatFlux;
119/// let q = HeatFlux::from_solar_flux(1.0); // ~1361 W/m²
120/// ```
121///
122/// # Typed arithmetic
123/// - [`Power`](crate::Power) / [`Area`](crate::Area) → [`HeatFlux`]
124/// - [`HeatFlux`] × [`Area`](crate::Area) → [`Power`](crate::Power)
125#[must_use]
126#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
127pub struct HeatFlux(pub(crate) f64);
128
129/// Display/conversion units for [`HeatFlux`].
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum HeatFluxUnit {
132    /// Watts per square meter (W/m²) -- SI derived unit.
133    WattPerM2,
134    /// Kilowatts per square meter (kW/m²).
135    KiloWattPerM2,
136    /// Solar flux units (~1361 W/m² at 1 AU).
137    SolarFlux,
138}
139
140impl HeatFluxUnit {
141    const fn symbol(self) -> &'static str {
142        match self {
143            Self::WattPerM2 => "W/m^2",
144            Self::KiloWattPerM2 => "kW/m^2",
145            Self::SolarFlux => "solar_flux",
146        }
147    }
148
149    const fn wpm2_per_unit(self) -> f64 {
150        match self {
151            Self::WattPerM2 => 1.0,
152            Self::KiloWattPerM2 => 1e3,
153            Self::SolarFlux => 1_361.0,
154        }
155    }
156}
157
158impl HeatFlux {
159    /// Create from watts per square meter (W/m²).
160    pub const fn from_wpm2(val: f64) -> Self {
161        Self(val)
162    }
163
164    /// Create from kilowatts per square meter (kW/m²).
165    pub const fn from_kwpm2(val: f64) -> Self {
166        Self(val * 1e3)
167    }
168
169    /// Create from solar flux units (~1361 W/m² at 1 AU).
170    pub const fn from_solar_flux(val: f64) -> Self {
171        Self(val * 1_361.0)
172    }
173
174    /// Get value in watts per square meter (W/m²).
175    pub const fn in_wpm2(self) -> f64 {
176        self.0
177    }
178
179    /// Get value in kilowatts per square meter (kW/m²).
180    pub const fn in_kwpm2(self) -> f64 {
181        self.0 / 1e3
182    }
183
184    /// Get value in solar flux units.
185    pub const fn in_solar_flux(self) -> f64 {
186        self.0 / 1_361.0
187    }
188
189    /// Get value in the specified [`HeatFluxUnit`].
190    pub fn in_unit(self, unit: HeatFluxUnit) -> f64 {
191        self.0 / unit.wpm2_per_unit()
192    }
193
194    /// Return a display wrapper that formats this heat flux in the given unit.
195    pub fn display_as(self, unit: HeatFluxUnit) -> DisplayWithUnit {
196        DisplayWithUnit {
197            value: self.in_unit(unit),
198            symbol: unit.symbol(),
199        }
200    }
201
202    /// Return the absolute value of this heat flux.
203    pub fn abs(self) -> Self {
204        Self(self.0.abs())
205    }
206}
207
208impl_quantity_display!(HeatFlux, "W/m²");
209
210impl_common_ops!(HeatFlux);