frequenz_microgrid_component_graph/
component_category.rs1use crate::ComponentGraphConfig;
8use crate::graph_traits::Node;
9use std::fmt::Display;
10
11#[derive(Clone, Copy, Debug, PartialEq)]
13pub enum InverterType {
14 Unspecified,
15 Pv,
16 Battery,
17 Hybrid,
18}
19
20impl Display for InverterType {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 InverterType::Unspecified => write!(f, "Unspecified"),
24 InverterType::Pv => write!(f, "Pv"),
25 InverterType::Battery => write!(f, "Battery"),
26 InverterType::Hybrid => write!(f, "Hybrid"),
27 }
28 }
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
33pub enum BatteryType {
34 Unspecified,
35 LiIon,
36 NaIon,
37}
38
39impl Display for BatteryType {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 match self {
42 BatteryType::Unspecified => write!(f, "Unspecified"),
43 BatteryType::LiIon => write!(f, "LiIon"),
44 BatteryType::NaIon => write!(f, "NaIon"),
45 }
46 }
47}
48
49#[derive(Clone, Copy, Debug, PartialEq)]
51pub enum EvChargerType {
52 Unspecified,
53 Ac,
54 Dc,
55 Hybrid,
56}
57
58impl Display for EvChargerType {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 match self {
61 EvChargerType::Unspecified => write!(f, "Unspecified"),
62 EvChargerType::Ac => write!(f, "AC"),
63 EvChargerType::Dc => write!(f, "DC"),
64 EvChargerType::Hybrid => write!(f, "Hybrid"),
65 }
66 }
67}
68
69#[derive(Clone, Copy, Debug, PartialEq)]
75pub enum ComponentCategory {
76 Unspecified,
77 GridConnectionPoint,
78 Meter,
79 Inverter(InverterType),
80 Converter,
81 Battery(BatteryType),
82 EvCharger(EvChargerType),
83 Breaker,
84 Precharger,
85 Chp,
86 Electrolyzer,
87 PowerTransformer,
88 Hvac,
89 Plc,
90 CryptoMiner,
91 StaticTransferSwitch,
92 UninterruptiblePowerSupply,
93 CapacitorBank,
94 WindTurbine,
95 SteamBoiler,
96}
97
98impl Display for ComponentCategory {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 match self {
101 ComponentCategory::Unspecified => write!(f, "Unspecified"),
102 ComponentCategory::GridConnectionPoint => write!(f, "GridConnectionPoint"),
103 ComponentCategory::Meter => write!(f, "Meter"),
104 ComponentCategory::Battery(battery_type) => write!(f, "Battery({battery_type})"),
105 ComponentCategory::Inverter(inverter_type) => write!(f, "{inverter_type}Inverter"),
106 ComponentCategory::EvCharger(ev_charger_type) => {
107 write!(f, "EVCharger({ev_charger_type})")
108 }
109 ComponentCategory::Converter => write!(f, "Converter"),
110 ComponentCategory::CryptoMiner => write!(f, "CryptoMiner"),
111 ComponentCategory::Electrolyzer => write!(f, "Electrolyzer"),
112 ComponentCategory::Chp => write!(f, "CHP"),
113 ComponentCategory::Precharger => write!(f, "Precharger"),
114 ComponentCategory::Hvac => write!(f, "HVAC"),
115 ComponentCategory::Breaker => write!(f, "Breaker"),
116 ComponentCategory::PowerTransformer => write!(f, "PowerTransformer"),
117 ComponentCategory::Plc => write!(f, "PLC"),
118 ComponentCategory::StaticTransferSwitch => write!(f, "StaticTransferSwitch"),
119 ComponentCategory::UninterruptiblePowerSupply => {
120 write!(f, "UninterruptiblePowerSupply")
121 }
122 ComponentCategory::CapacitorBank => write!(f, "CapacitorBank"),
123 ComponentCategory::WindTurbine => write!(f, "WindTurbine"),
124 ComponentCategory::SteamBoiler => write!(f, "SteamBoiler"),
125 }
126 }
127}
128
129impl ComponentCategory {
130 pub(crate) fn is_passthrough(self) -> bool {
143 use ComponentCategory as C;
144 matches!(
145 self,
146 C::Converter
147 | C::Breaker
148 | C::Precharger
149 | C::Electrolyzer
150 | C::PowerTransformer
151 | C::Hvac
152 | C::Plc
153 | C::CryptoMiner
154 | C::StaticTransferSwitch
155 | C::UninterruptiblePowerSupply
156 | C::CapacitorBank
157 )
158 }
159}
160
161pub(crate) trait CategoryPredicates: Node {
163 fn is_unspecified(&self) -> bool {
164 self.category() == ComponentCategory::Unspecified
165 }
166
167 fn is_grid(&self) -> bool {
168 self.category() == ComponentCategory::GridConnectionPoint
169 }
170
171 fn is_meter(&self) -> bool {
172 self.category() == ComponentCategory::Meter
173 }
174
175 fn is_battery(&self) -> bool {
176 matches!(self.category(), ComponentCategory::Battery(_))
177 }
178
179 fn is_inverter(&self) -> bool {
180 matches!(self.category(), ComponentCategory::Inverter(_))
181 }
182
183 fn is_battery_inverter(&self, config: &ComponentGraphConfig) -> bool {
184 match self.category() {
185 ComponentCategory::Inverter(InverterType::Battery) => true,
186 ComponentCategory::Inverter(InverterType::Unspecified) => {
187 config.allow_unspecified_inverters
188 }
189 _ => false,
190 }
191 }
192
193 fn is_pv_inverter(&self) -> bool {
194 self.category() == ComponentCategory::Inverter(InverterType::Pv)
195 }
196
197 fn is_hybrid_inverter(&self) -> bool {
198 self.category() == ComponentCategory::Inverter(InverterType::Hybrid)
199 }
200
201 fn is_unspecified_inverter(&self, config: &ComponentGraphConfig) -> bool {
202 match self.category() {
203 ComponentCategory::Inverter(InverterType::Unspecified) => {
204 !config.allow_unspecified_inverters
205 }
206 _ => false,
207 }
208 }
209
210 fn is_ev_charger(&self) -> bool {
211 matches!(self.category(), ComponentCategory::EvCharger(_))
212 }
213
214 fn is_chp(&self) -> bool {
215 self.category() == ComponentCategory::Chp
216 }
217
218 fn is_wind_turbine(&self) -> bool {
219 self.category() == ComponentCategory::WindTurbine
220 }
221
222 fn is_steam_boiler(&self) -> bool {
223 self.category() == ComponentCategory::SteamBoiler
224 }
225}
226
227impl<T: Node> CategoryPredicates for T {}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234
235 #[test]
239 fn test_is_passthrough_classification() {
240 for c in [
243 ComponentCategory::Converter,
244 ComponentCategory::Breaker,
245 ComponentCategory::Precharger,
246 ComponentCategory::Electrolyzer,
247 ComponentCategory::PowerTransformer,
248 ComponentCategory::Hvac,
249 ComponentCategory::Plc,
250 ComponentCategory::CryptoMiner,
251 ComponentCategory::StaticTransferSwitch,
252 ComponentCategory::UninterruptiblePowerSupply,
253 ComponentCategory::CapacitorBank,
254 ] {
255 assert!(c.is_passthrough(), "{c} should be a pass-through");
256 }
257
258 for c in [
260 ComponentCategory::Unspecified,
261 ComponentCategory::GridConnectionPoint,
262 ComponentCategory::Meter,
263 ComponentCategory::Inverter(InverterType::Battery),
264 ComponentCategory::Inverter(InverterType::Pv),
265 ComponentCategory::Inverter(InverterType::Hybrid),
266 ComponentCategory::Inverter(InverterType::Unspecified),
267 ComponentCategory::Battery(BatteryType::LiIon),
268 ComponentCategory::Battery(BatteryType::NaIon),
269 ComponentCategory::Battery(BatteryType::Unspecified),
270 ComponentCategory::EvCharger(EvChargerType::Ac),
271 ComponentCategory::EvCharger(EvChargerType::Dc),
272 ComponentCategory::EvCharger(EvChargerType::Hybrid),
273 ComponentCategory::EvCharger(EvChargerType::Unspecified),
274 ComponentCategory::Chp,
275 ComponentCategory::WindTurbine,
276 ] {
277 assert!(!c.is_passthrough(), "{c} should not be a pass-through");
278 }
279 }
280}