use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
#[cfg(feature = "rsparse")]
use crate::basic::ecs::network::PowerFlowSolver;
use crate::basic::ecs::{elements::*, network::apply_permutation};
use super::systems::{PowerFlowMat, init_states};
use crate::prelude::ecs::network::SolverStage::*;
#[derive(Message, Default, Debug, Clone, Copy)]
pub struct VoltageChangeEvent;
#[derive(Message, Default, Debug, Clone, Copy)]
pub struct SBusChangeEvent;
#[derive(Message, Default, Debug, Clone, Copy)]
pub struct FullRebuildEvent;
#[derive(Message, Default, Debug, Clone, Copy)]
pub struct NodeTypeChangeEvent;
#[derive(Default, Debug, Clone, Copy)]
pub struct SimStateFlags {
pub full_dirty: bool,
pub structure_dirty: bool,
pub admit_dirty: bool,
pub injection_dirty: bool,
pub voltage_dirty: bool,
}
#[derive(Resource, Default, Clone, Copy)]
pub struct LastStructureAction {
pub full_rebuild: bool,
}
pub fn event_update(
mut e_sbus: MessageReader<SBusChangeEvent>,
mut e_vbus: MessageReader<VoltageChangeEvent>,
mut e_full: MessageReader<FullRebuildEvent>,
mut e_node_type: MessageReader<NodeTypeChangeEvent>,
) -> SimStateFlags {
let mut flags = SimStateFlags::default();
if !e_full.is_empty() {
flags.full_dirty = true;
}
if !e_node_type.is_empty() {
flags.structure_dirty = true;
}
if !e_sbus.is_empty() {
flags.injection_dirty = true;
}
if !e_vbus.is_empty() {
flags.voltage_dirty = true;
}
e_full.clear();
e_node_type.clear();
e_sbus.clear();
e_vbus.clear();
flags
}
pub fn reset_solvers(world: &mut World) {
use crate::basic::solver::*;
if let Some(mut solver) = world.get_resource_mut::<PowerFlowSolver>() {
solver.solver.reset();
}
}
pub fn sbus_pu_update(mut pfmat: ResMut<PowerFlowMat>, sbus: Query<(&BusID, &SBusInjPu)>) {
for (bus_id, s) in sbus {
let idx = pfmat.reorder_index(bus_id.0 as usize);
pfmat.s_bus[idx] = s.0;
}
}
pub fn vbus_pu_update(mut pfmat: ResMut<PowerFlowMat>, vbus: Query<(&BusID, &VBusPu)>) {
for (bus_id, s) in vbus {
let idx = pfmat.reorder_index(bus_id.0 as usize);
pfmat.v_bus_init[idx] = s.0;
}
}
pub fn structure_update(world: &mut World) {
let flags = world.run_system_cached(event_update).unwrap();
world.insert_resource(LastStructureAction { full_rebuild: flags.full_dirty });
if flags.full_dirty {
let _ = world.try_run_schedule(super::pf_init::PFInit);
return;
}
if !world.contains_resource::<PowerFlowMat>() {
return;
}
if flags.structure_dirty || flags.admit_dirty {
world.run_system_cached(reset_solvers).unwrap();
world.run_system_cached(init_states).unwrap();
world.run_system_cached(apply_permutation).unwrap();
} else {
if flags.injection_dirty {
world.run_system_cached(sbus_pu_update).unwrap();
}
if flags.voltage_dirty {
world.run_system_cached(vbus_pu_update).unwrap();
}
}
}
#[derive(Default)]
pub struct StructureUpdatePlugin;
impl Plugin for StructureUpdatePlugin {
fn build(&self, app: &mut App) {
app.add_message::<VoltageChangeEvent>();
app.add_message::<SBusChangeEvent>();
app.add_message::<FullRebuildEvent>();
app.add_message::<NodeTypeChangeEvent>();
app.add_message::<super::mutation::ParamDiff>();
app.init_resource::<LastStructureAction>();
app.add_schedule(super::pf_init::build_pf_init_schedule());
app.add_systems(
Update,
super::mutation::consume_param_diffs
.after(BeforeSolve)
.before(structure_update),
);
app.add_systems(Update, structure_update.after(BeforeSolve).before(Solve));
}
}