1use powerio_core::ComponentId;
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
14#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
15#[serde(rename_all = "snake_case")]
16#[non_exhaustive]
17pub enum ScucDeviceKind {
18 Producer,
19 Consumer,
20}
21
22#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
24#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
25#[non_exhaustive]
26pub struct ScucStartupCostAdjustment {
27 pub cost: f64,
29 pub maximum_down_time: f64,
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
35#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
36#[non_exhaustive]
37pub struct ScucStartupLimit {
38 pub start_time: f64,
40 pub end_time: f64,
42 pub maximum_startups: u64,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
47#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
48#[non_exhaustive]
49pub struct ScucEnergyRequirement {
50 pub start_time: f64,
52 pub end_time: f64,
54 pub energy: f64,
56}
57
58#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
60#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
61#[non_exhaustive]
62pub struct ScucInitialCommitment {
63 pub accumulated_up_time: f64,
65 pub accumulated_down_time: f64,
67}
68
69#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
71#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
72#[non_exhaustive]
73pub struct ScucRampLimits {
74 pub up: f64,
75 pub down: f64,
76 pub startup: f64,
77 pub shutdown: f64,
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
82#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
83#[non_exhaustive]
84pub struct ScucReserveLimits {
85 pub regulation_up: f64,
86 pub regulation_down: f64,
87 pub synchronized: f64,
88 pub nonsynchronized: f64,
89 pub ramping_up_online: f64,
90 pub ramping_down_online: f64,
91 pub ramping_up_offline: f64,
92 pub ramping_down_offline: f64,
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
97#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
98#[serde(rename_all = "snake_case", tag = "kind")]
99#[non_exhaustive]
100pub enum ScucReactiveCapability {
101 None,
102 Linear {
103 reactive_power_at_zero_active_power: f64,
105 slope: f64,
106 },
107 Bounded {
108 reactive_power_at_zero_active_power_min: f64,
110 reactive_power_at_zero_active_power_max: f64,
112 slope_min: f64,
113 slope_max: f64,
114 },
115}
116
117#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
119#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
120#[non_exhaustive]
121pub struct ScucEnergyCostBlock {
122 pub marginal_cost: f64,
124 pub block_size: f64,
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
130#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
131#[non_exhaustive]
132pub struct ScucReserveCosts {
133 pub regulation_up: f64,
134 pub regulation_down: f64,
135 pub synchronized: f64,
136 pub nonsynchronized: f64,
137 pub ramping_up_online: f64,
138 pub ramping_down_online: f64,
139 pub ramping_up_offline: f64,
140 pub ramping_down_offline: f64,
141 pub reactive_up: f64,
142 pub reactive_down: f64,
143}
144
145#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
147#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
148#[non_exhaustive]
149pub struct ScucDevicePeriod {
150 pub on_status_min: bool,
151 pub on_status_max: bool,
152 pub active_power_min: f64,
154 pub active_power_max: f64,
156 pub reactive_power_min: f64,
158 pub reactive_power_max: f64,
160 pub energy_cost_blocks: Vec<ScucEnergyCostBlock>,
161 pub reserve_costs: ScucReserveCosts,
162}
163
164#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
166#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
167#[non_exhaustive]
168pub struct ScucDevice {
169 pub id: ComponentId,
171 pub kind: ScucDeviceKind,
172 pub on_cost: f64,
174 pub startup_cost: f64,
176 pub startup_cost_adjustments: Vec<ScucStartupCostAdjustment>,
177 pub shutdown_cost: f64,
179 pub startup_limits: Vec<ScucStartupLimit>,
180 pub energy_upper_bounds: Vec<ScucEnergyRequirement>,
181 pub energy_lower_bounds: Vec<ScucEnergyRequirement>,
182 pub minimum_up_time: f64,
184 pub minimum_down_time: f64,
186 pub ramp_limits: ScucRampLimits,
187 pub reserve_limits: ScucReserveLimits,
188 pub initial_on_status: bool,
190 pub initial_commitment: ScucInitialCommitment,
191 pub reactive_capability: ScucReactiveCapability,
192 pub periods: Vec<ScucDevicePeriod>,
194}
195
196#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
198#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
199#[non_exhaustive]
200pub struct ScucShunt {
201 pub id: ComponentId,
202 pub conductance_per_step: f64,
204 pub susceptance_per_step: f64,
206 pub step_min: i64,
207 pub step_max: i64,
208 pub initial_step: i64,
209}
210
211#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
213#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
214#[non_exhaustive]
215pub struct ScucBranchSwitchingCost {
216 pub id: ComponentId,
218 pub connection_cost: f64,
220 pub disconnection_cost: f64,
222}
223
224#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
226#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
227#[non_exhaustive]
228pub struct ScucTransformerControl {
229 pub id: ComponentId,
230 pub tap_ratio_min: f64,
232 pub tap_ratio_max: f64,
234 pub phase_shift_min: f64,
236 pub phase_shift_max: f64,
237}
238
239#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
241#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
242#[non_exhaustive]
243pub struct ScucActiveReserveZone {
244 pub id: ComponentId,
245 pub buses: Vec<ComponentId>,
247 pub regulation_up_requirement_fraction: f64,
248 pub regulation_down_requirement_fraction: f64,
249 pub synchronized_requirement_fraction: f64,
250 pub nonsynchronized_requirement_fraction: f64,
251 pub ramping_up_requirement: Vec<f64>,
252 pub ramping_down_requirement: Vec<f64>,
253 pub regulation_up_violation_cost: f64,
254 pub regulation_down_violation_cost: f64,
255 pub synchronized_violation_cost: f64,
256 pub nonsynchronized_violation_cost: f64,
257 pub ramping_up_violation_cost: f64,
258 pub ramping_down_violation_cost: f64,
259}
260
261#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
263#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
264#[non_exhaustive]
265pub struct ScucReactiveReserveZone {
266 pub id: ComponentId,
267 pub buses: Vec<ComponentId>,
269 pub reactive_up_requirement: Vec<f64>,
270 pub reactive_down_requirement: Vec<f64>,
271 pub reactive_up_violation_cost: f64,
272 pub reactive_down_violation_cost: f64,
273}
274
275#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
277#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
278#[non_exhaustive]
279pub struct ScucContingency {
280 pub id: ComponentId,
281 pub components: Vec<ComponentId>,
283}
284
285#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
287#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
288#[non_exhaustive]
289pub struct ScucViolationCosts {
290 pub active_power_balance: f64,
292 pub reactive_power_balance: f64,
294 pub branch_thermal_limit: f64,
296 pub energy_requirement: f64,
298}
299
300#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
302#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
303#[non_exhaustive]
304pub struct ScucInputs {
305 pub interval_durations: Vec<f64>,
307 pub devices: Vec<ScucDevice>,
308 pub shunts: Vec<ScucShunt>,
309 pub branch_switching_costs: Vec<ScucBranchSwitchingCost>,
310 pub transformer_controls: Vec<ScucTransformerControl>,
311 pub active_reserve_zones: Vec<ScucActiveReserveZone>,
312 pub reactive_reserve_zones: Vec<ScucReactiveReserveZone>,
313 pub contingencies: Vec<ScucContingency>,
314 pub violation_costs: ScucViolationCosts,
315}
316
317impl ScucInputs {
318 pub fn producers(&self) -> impl Iterator<Item = &ScucDevice> {
320 self.devices
321 .iter()
322 .filter(|device| device.kind == ScucDeviceKind::Producer)
323 }
324
325 pub fn consumers(&self) -> impl Iterator<Item = &ScucDevice> {
327 self.devices
328 .iter()
329 .filter(|device| device.kind == ScucDeviceKind::Consumer)
330 }
331
332 #[must_use]
334 pub fn device(&self, uid: &str) -> Option<&ScucDevice> {
335 self.devices
336 .iter()
337 .find(|device| device.id.local_id() == uid)
338 }
339
340 #[must_use]
342 pub fn shunt(&self, uid: &str) -> Option<&ScucShunt> {
343 self.shunts.iter().find(|shunt| shunt.id.local_id() == uid)
344 }
345
346 #[must_use]
348 pub fn contingency(&self, uid: &str) -> Option<&ScucContingency> {
349 self.contingencies
350 .iter()
351 .find(|contingency| contingency.id.local_id() == uid)
352 }
353
354 #[must_use]
356 pub fn interval_durations(&self) -> &[f64] {
357 &self.interval_durations
358 }
359}