frequenz_microgrid/quantity/
energy.rs1use super::Power;
7
8qty_ctor! {
9 #[doc = "A physical quantity representing energy."]
10 Energy => {
11 (from_milliwatthours, as_milliwatthours, "mWh", 1e-3),
12 (from_watthours, as_watthours, "Wh", 1e0),
13 (from_kilowatthours, as_kilowatthours, "kWh", 1e3),
14 (from_megawatthours, as_megawatthours, "MWh", 1e6),
15 (from_gigawatthours, as_gigawatthours, "GWh", 1e9),
16 }
17}
18
19impl std::ops::Div<Power> for Energy {
20 type Output = std::time::Duration;
21
22 fn div(self, power: Power) -> Self::Output {
23 let seconds = (self.as_watthours() / power.as_watts()) * 3600.0;
24 std::time::Duration::from_secs_f32(seconds)
25 }
26}
27
28impl std::ops::Div<std::time::Duration> for Energy {
29 type Output = Power;
30
31 fn div(self, duration: std::time::Duration) -> Self::Output {
32 Power::from_watts(self.as_watthours() * 3600.0 / duration.as_secs_f32())
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use crate::quantity::{Percentage, Power, Quantity as _, test_utils::assert_f32_eq};
39
40 use super::Energy;
41
42 #[test]
43 fn test_energy() {
44 let energy_1 = Energy::from_watthours(1000.0);
45
46 assert_f32_eq(energy_1.as_milliwatthours(), 1_000_000.0);
47 assert_f32_eq(energy_1.as_watthours(), 1000.0);
48 assert_f32_eq(energy_1.as_kilowatthours(), 1.0);
49 assert_f32_eq(energy_1.as_megawatthours(), 0.001);
50 assert_f32_eq(energy_1.as_gigawatthours(), 0.000_001);
51
52 let energy_2 = Energy::from_milliwatthours(1_200_000.0);
53 assert_f32_eq(energy_2.as_watthours(), 1200.0);
54
55 let energy_2 = Energy::from_kilowatthours(1.2);
56 assert_f32_eq(energy_2.as_watthours(), 1200.0);
57
58 let energy_2 = Energy::from_megawatthours(0.0012);
59 assert_f32_eq(energy_2.as_watthours(), 1200.0);
60
61 let energy_2 = Energy::from_gigawatthours(0.000_001_2);
62 assert_f32_eq(energy_2.as_watthours(), 1200.0);
63
64 assert!(energy_1 < energy_2);
65 assert!(energy_2 > energy_1);
66
67 assert_f32_eq((energy_1 + energy_2).as_watthours(), 2200.0);
68 assert_f32_eq((energy_2 - energy_1).as_watthours(), 200.0);
69 assert_f32_eq((energy_2 * 2.0).as_watthours(), 2400.0);
70 assert_f32_eq(
71 (energy_2 * Percentage::from_percentage(50.0)).as_watthours(),
72 600.0,
73 );
74 assert_f32_eq((energy_2 / 3.0).as_watthours(), 400.0);
75 assert_f32_eq(energy_2 / energy_1, 1.2);
76
77 assert_f32_eq(Energy::zero().as_watthours(), 0.0);
78 }
79
80 #[test]
81 fn test_energy_power_duration() {
82 let energy = Energy::from_kilowatthours(1.0);
83 let power = Power::from_kilowatts(0.5);
84
85 let duration = energy / power;
86 assert_f32_eq(duration.as_secs_f32(), 7200.0);
87
88 let power_calculated = energy / duration;
89 assert_f32_eq(power_calculated.as_kilowatts(), 0.5);
90 }
91
92 #[test]
93 fn test_energy_formatting() {
94 let s = |value| Energy::from_watthours(value).to_string();
95 let p = |value, prec| format!("{:.prec$}", Energy::from_watthours(value), prec = prec);
96
97 assert_eq!(s(0.0), "0 mWh");
98 assert_eq!(s(1.558), "1.558 Wh");
99 assert_eq!(p(1.558, 1), "1.6 Wh");
100
101 assert_eq!(s(0.001558), "1.558 mWh");
102 assert_eq!(p(0.001558, 1), "1.6 mWh");
103
104 assert_eq!(s(1.5508), "1.551 Wh");
105 assert_eq!(p(1.5508, 5), "1.5508 Wh");
106
107 assert_eq!(s(0.0015508), "1.551 mWh");
108 assert_eq!(p(0.0015508, 5), "1.5508 mWh");
109
110 assert_eq!(s(1030.04487), "1.03 kWh");
111 assert_eq!(p(1030.04487, 1), "1 kWh");
112
113 assert_eq!(s(2_030_022.0), "2.03 MWh");
114 assert_eq!(s(2_030_022_123.0), "2.03 GWh");
115 assert_eq!(p(2_030_022_123.0, 6), "2.030022 GWh");
116
117 assert_eq!(s(-1.558), "-1.558 Wh");
118 assert_eq!(p(-1.558, 1), "-1.6 Wh");
119
120 assert_eq!(s(-1030.04487), "-1.03 kWh");
121 assert_eq!(p(-1030.04487, 1), "-1 kWh");
122
123 assert_eq!(s(-2_030_022.0), "-2.03 MWh");
124 assert_eq!(p(-2_030_022.0, 1), "-2 MWh");
125
126 assert_eq!(s(-2_030_022_123.0), "-2.03 GWh");
127 assert_eq!(p(-2_030_022_123.0, 6), "-2.030022 GWh");
128 }
129}