qsim_elements/
load.rs

1//! Load element — power consumption
2
3use qsim_core::{GridElement, StateStore};
4use serde::{Deserialize, Serialize};
5
6/// A load connected to a bus
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Load {
9    /// Connected bus index
10    pub bus: usize,
11    /// Active power consumption (MW, positive = consumption)
12    pub active_power: f64,
13    /// Reactive power consumption (MVAr, positive = consumption)
14    pub reactive_power: f64,
15    /// Load status (true = in service)
16    pub in_service: bool,
17}
18
19impl Load {
20    /// Create a new load
21    pub fn new(bus: usize, active_power: f64, reactive_power: f64) -> Self {
22        Self {
23            bus,
24            active_power,
25            reactive_power,
26            in_service: true,
27        }
28    }
29
30    /// Create a purely resistive load
31    pub fn resistive(bus: usize, active_power: f64) -> Self {
32        Self::new(bus, active_power, 0.0)
33    }
34
35    /// Create a load with power factor
36    pub fn with_power_factor(bus: usize, apparent_power: f64, power_factor: f64) -> Self {
37        let active_power = apparent_power * power_factor;
38        let reactive_power = apparent_power * (1.0 - power_factor.powi(2)).sqrt();
39        Self::new(bus, active_power, reactive_power)
40    }
41}
42
43impl GridElement for Load {
44    fn element_type(&self) -> &'static str {
45        "Load"
46    }
47
48    fn apply(&self, state: &mut StateStore) {
49        if self.in_service && self.bus < state.bus_count() {
50            // Loads consume power (negative injection)
51            state.active_power[self.bus] -= self.active_power;
52            state.reactive_power[self.bus] -= self.reactive_power;
53        }
54    }
55}