pub(crate) fn angle_window(angle_min_rad: f64, angle_max_rad: f64) -> f64 {
if angle_min_rad == 0.0 && angle_max_rad == 0.0 {
return std::f64::consts::PI;
}
angle_min_rad.abs().max(angle_max_rad.abs())
}
pub(crate) struct ThermalLimits {
pub synthesize_unrated: bool,
pub power_scale: f64,
pub admittance_scale: f64,
}
impl ThermalLimits {
pub(crate) fn of(
&self,
branch: &powerio::Branch,
angle_min_rad: f64,
angle_max_rad: f64,
from: &powerio::Bus,
to: &powerio::Bus,
) -> f64 {
if self.synthesize_unrated && branch.rate_a <= 0.0 {
let window = angle_window(angle_min_rad, angle_max_rad);
branch.synthesize_rate_a(window, (from.vmin, from.vmax), (to.vmin, to.vmax))
* self.admittance_scale
} else {
branch.rate_a * self.power_scale
}
}
}
#[cfg(test)]
mod tests {
use super::angle_window;
#[test]
fn the_window_is_the_wider_of_the_two_magnitudes() {
let window = 30.0_f64.to_radians();
assert!((angle_window(-window, window) - window).abs() < 1e-15);
assert!((angle_window(0.1, window) - window).abs() < 1e-15);
assert!((angle_window(-window, 0.1) - window).abs() < 1e-15);
}
#[test]
fn a_zero_pair_states_no_constraint() {
assert!((angle_window(0.0, 0.0) - std::f64::consts::PI).abs() < 1e-15);
}
}