use bevy_ecs::prelude::*;
use nalgebra::{Complex, SimdComplexField};
use crate::basic::ecs::elements::*;
use crate::basic::ecs::elements::generator::{TargetPMW, TargetQMVar, TargetVmPu};
use super::structure_update::{SBusChangeEvent, VoltageChangeEvent};
#[derive(Message, Debug, Clone, Copy)]
pub enum ParamDiff {
Injection { bus: i64, dp_mw: f64, dq_mvar: f64 },
VoltageMag { bus: i64, vm_pu: f64 },
}
pub fn set_load_p(world: &mut World, entity: Entity, p_mw: f64) -> bool {
let Some(bus) = world.get::<TargetBus>(entity).map(|b| b.0) else { return false; };
let target = -p_mw; let Some(mut p) = world.get_mut::<TargetPMW>(entity) else { return false; };
let old = p.0;
if old == target {
return true; }
p.0 = target;
world.write_message(ParamDiff::Injection { bus, dp_mw: target - old, dq_mvar: 0.0 });
true
}
pub fn set_load_q(world: &mut World, entity: Entity, q_mvar: f64) -> bool {
let Some(bus) = world.get::<TargetBus>(entity).map(|b| b.0) else { return false; };
let target = -q_mvar;
let Some(mut q) = world.get_mut::<TargetQMVar>(entity) else { return false; };
let old = q.0;
if old == target {
return true;
}
q.0 = target;
world.write_message(ParamDiff::Injection { bus, dp_mw: 0.0, dq_mvar: target - old });
true
}
pub fn set_gen_p(world: &mut World, entity: Entity, p_mw: f64) -> bool {
let Some(bus) = world.get::<TargetBus>(entity).map(|b| b.0) else { return false; };
let Some(mut p) = world.get_mut::<TargetPMW>(entity) else { return false; };
let old = p.0;
if old == p_mw {
return true;
}
p.0 = p_mw;
world.write_message(ParamDiff::Injection { bus, dp_mw: p_mw - old, dq_mvar: 0.0 });
true
}
pub fn set_gen_vm(world: &mut World, entity: Entity, vm_pu: f64) -> bool {
let Some(bus) = world.get::<TargetBus>(entity).map(|b| b.0) else { return false; };
let Some(mut vm) = world.get_mut::<TargetVmPu>(entity) else { return false; };
if vm.0 == vm_pu {
return true;
}
vm.0 = vm_pu;
world.write_message(ParamDiff::VoltageMag { bus, vm_pu });
true
}
pub fn consume_param_diffs(
mut diffs: MessageReader<ParamDiff>,
lookup: Option<Res<NodeLookup>>,
common: Option<Res<PFCommonData>>,
mut sbus: Query<&mut SBusInjPu>,
mut vbus: Query<&mut VBusPu>,
mut s_evt: MessageWriter<SBusChangeEvent>,
mut v_evt: MessageWriter<VoltageChangeEvent>,
) {
if diffs.is_empty() {
return;
}
let (Some(lookup), Some(common)) = (lookup, common) else {
diffs.clear();
return; };
let sbase_frac = 1.0 / common.sbase;
let mut s_changed = false;
let mut v_changed = false;
for diff in diffs.read() {
match *diff {
ParamDiff::Injection { bus, dp_mw, dq_mvar } => {
let Some(e) = lookup.get_entity(bus) else { continue; };
if let Ok(mut s) = sbus.get_mut(e) {
s.0 += Complex::new(dp_mw, dq_mvar) * sbase_frac;
s_changed = true;
}
}
ParamDiff::VoltageMag { bus, vm_pu } => {
let Some(e) = lookup.get_entity(bus) else { continue; };
if let Ok(mut v) = vbus.get_mut(e) {
v.0 = v.0.simd_signum() * Complex::new(vm_pu, 0.0);
v_changed = true;
}
}
}
}
if s_changed {
s_evt.write(SBusChangeEvent);
}
if v_changed {
v_evt.write(VoltageChangeEvent);
}
}