use std::fmt;
use crate::types::Bus;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct BusOverride {
pub bus: usize,
pub p_spec: Option<f64>,
pub q_spec: Option<f64>,
pub voltage_mag: Option<f64>,
}
impl BusOverride {
pub fn new(bus: usize) -> Self {
Self {
bus,
..Default::default()
}
}
pub fn p(mut self, p_spec: f64) -> Self {
self.p_spec = Some(p_spec);
self
}
pub fn q(mut self, q_spec: f64) -> Self {
self.q_spec = Some(q_spec);
self
}
pub fn vm(mut self, voltage_mag: f64) -> Self {
self.voltage_mag = Some(voltage_mag);
self
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Scenario {
pub bus_overrides: Vec<BusOverride>,
pub branch_outages: Vec<usize>,
}
impl Scenario {
pub fn new(bus_overrides: Vec<BusOverride>) -> Self {
Self {
bus_overrides,
branch_outages: Vec::new(),
}
}
}
pub fn uniform_load_scaling(buses_template: &[Bus], factor: f64) -> Scenario {
let overrides = buses_template
.iter()
.filter(|b| b.p_spec != 0.0 || b.q_spec != 0.0)
.map(|b| {
BusOverride::new(b.idx)
.p(b.p_spec * factor)
.q(b.q_spec * factor)
})
.collect();
Scenario::new(overrides)
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BatchError {
OutagesUnsupported { scenario: usize },
BusOutOfRange {
scenario: usize,
bus: usize,
n_buses: usize,
},
BranchOutOfRange {
scenario: usize,
branch: usize,
n_branches: usize,
},
ThreadPool(String),
DcSingular,
}
impl fmt::Display for BatchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BatchError::OutagesUnsupported { scenario } => write!(
f,
"scenario {scenario} requests branch outages, which `solve` cannot honor from a \
finished Y-bus — use `BatchSolver::solve_contingencies`, which takes the branch \
lists"
),
BatchError::BusOutOfRange {
scenario,
bus,
n_buses,
} => write!(
f,
"scenario {scenario} overrides bus {bus}, but the template has only {n_buses} bus(es)"
),
BatchError::BranchOutOfRange {
scenario,
branch,
n_branches,
} => write!(
f,
"scenario {scenario} outages branch {branch}, but the network has only \
{n_branches} branch(es)"
),
BatchError::ThreadPool(e) => write!(f, "building the rayon thread pool failed: {e}"),
BatchError::DcSingular => write!(
f,
"the reduced susceptance matrix is singular, so no DC scenario can be solved"
),
}
}
}
impl std::error::Error for BatchError {}