use super::crac::{Crac, InstantKind, State};
use super::evaluate::SecurityResult;
use super::linear::ObjectiveUnit;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CostlyOptions {
pub violation_penalty: f64,
pub violation_threshold: f64,
}
impl Default for CostlyOptions {
fn default() -> Self {
Self {
violation_penalty: 1000.0,
violation_threshold: 0.0,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Costly {
pub options: CostlyOptions,
}
impl Costly {
pub fn violation(
&self,
crac: &Crac,
result: &SecurityResult,
perimeter: &[State],
unit: ObjectiveUnit,
) -> f64 {
let mut preventive: Option<f64> = None;
let mut worst: Option<f64> = None;
for p in result
.perimeters
.iter()
.filter(|p| perimeter.contains(&p.state))
{
let total: f64 = p
.cnecs
.iter()
.filter(|c| crac.flow_cnecs[c.cnec].optimized)
.map(|c| {
let margin = match unit {
ObjectiveUnit::Megawatt => c.margin_mw,
ObjectiveUnit::Ampere => c.margin_a,
};
(self.options.violation_threshold - margin).max(0.0)
})
.sum();
match crac.instants[p.state.instant].kind {
InstantKind::Preventive | InstantKind::Outage => {
preventive = Some(preventive.unwrap_or(0.0) + total);
}
InstantKind::Auto | InstantKind::Curative => {
worst = Some(worst.map_or(total, |w: f64| w.max(total)));
}
}
}
let total = match (preventive, worst) {
(Some(a), Some(b)) => a.max(b),
(Some(a), None) | (None, Some(a)) => a,
(None, None) => 0.0,
};
self.options.violation_penalty * total
}
pub fn activation(&self, crac: &Crac, activated: &[usize], moved: &[(usize, f64)]) -> f64 {
let network: f64 = activated
.iter()
.filter_map(|&i| crac.network_actions.get(i))
.filter_map(|a| a.activation_cost)
.sum();
let range: f64 = moved
.iter()
.filter_map(|&(i, distance)| Some((crac.range_actions.get(i)?, distance)))
.map(|(a, distance)| {
let variation = a.variation_cost.map_or(0.0, |c| {
if distance >= 0.0 {
c.up * distance
} else {
c.down * -distance
}
});
a.activation_cost.unwrap_or(0.0) + variation
})
.sum();
network + range
}
pub fn cost(
&self,
crac: &Crac,
result: &SecurityResult,
perimeter: &[State],
unit: ObjectiveUnit,
activated: &[usize],
moved: &[(usize, f64)],
) -> f64 {
self.violation(crac, result, perimeter, unit) + self.activation(crac, activated, moved)
}
}