use std::collections::HashMap;
use surge_network::Network;
use super::indices::CgmesIndices;
use super::types::ObjMap;
pub(crate) fn build_load_response_chars(
objects: &ObjMap,
idx: &CgmesIndices,
network: &mut Network,
) {
let lrc_params: HashMap<String, (f64, f64, f64, f64, f64, f64)> = objects
.iter()
.filter(|(_, o)| o.class == "LoadResponseCharacteristic")
.map(|(lrc_id, o)| {
let pz = o.parse_f64("pConstantImpedance").unwrap_or(0.0);
let pi = o.parse_f64("pConstantCurrent").unwrap_or(0.0);
let pp = o.parse_f64("pConstantPower").unwrap_or(100.0 - pz - pi);
let qz = o.parse_f64("qConstantImpedance").unwrap_or(0.0);
let qi = o.parse_f64("qConstantCurrent").unwrap_or(0.0);
let qp = o.parse_f64("qConstantPower").unwrap_or(100.0 - qz - qi);
(lrc_id.clone(), (pz, pi, pp, qz, qi, qp))
})
.collect();
let mut bus_to_load_idxs: HashMap<u32, Vec<usize>> = HashMap::new();
for (i, load) in network.loads.iter().enumerate() {
bus_to_load_idxs.entry(load.bus).or_default().push(i);
}
for (ec_id, ec_obj) in objects.iter().filter(|(_, o)| {
matches!(
o.class.as_str(),
"EnergyConsumer" | "ConformLoad" | "NonConformLoad"
)
}) {
let lrc_id = ec_obj
.get_ref("LoadResponse")
.or_else(|| ec_obj.get_ref("LoadResponseCharacteristic"));
let Some(lrc_id) = lrc_id else {
continue;
};
let Some(&(pz, pi, pp, qz, qi, qp)) = lrc_params.get(lrc_id) else {
continue;
};
let terms = idx.terminals(ec_id);
let Some(tn_id) = terms.first().and_then(|t| idx.terminal_tn(objects, t)) else {
continue;
};
let Some(bus_num) = idx.tn_bus(tn_id) else {
continue;
};
if let Some(load_idxs) = bus_to_load_idxs.get(&bus_num) {
for &li in load_idxs {
network.loads[li].zip_p_impedance_frac = pz / 100.0;
network.loads[li].zip_p_current_frac = pi / 100.0;
network.loads[li].zip_p_power_frac = pp / 100.0;
network.loads[li].zip_q_impedance_frac = qz / 100.0;
network.loads[li].zip_q_current_frac = qi / 100.0;
network.loads[li].zip_q_power_frac = qp / 100.0;
}
}
tracing::debug!(
ec_id,
bus_num,
lrc_id,
"LoadResponseCharacteristic ZIP set on loads (Wave 27)"
);
}
}