use anyhow::Result;
use full::slice::norm_inf;
use sparsetools::csr::CSR;
use spsolve::Solver;
use std::iter::zip;
pub(crate) fn dc_pf(
b_mat: &CSR<usize, f64>,
p_bus: &[f64],
va0: &[f64],
ref_: &[usize],
pv: &[usize],
pq: &[usize],
solver: &dyn Solver<usize, f64>,
) -> Result<(Vec<f64>, bool)> {
let va_threshold = 1e5;
let mut va = va0.to_vec();
let mut success = true;
let pvpq = [pv, pq].concat();
let b_pvpq = b_mat.select(Some(&pvpq), Some(&pvpq))?;
let b_ref = b_mat.select(Some(&pvpq), Some(ref_))?;
let p_bus_pvpq: Vec<f64> = pvpq.iter().map(|&i| p_bus[i]).collect();
let va_ref: Vec<f64> = ref_.iter().map(|&i| va0[i]).collect();
let mut rhs: Vec<f64> = zip(p_bus_pvpq, b_ref * &va_ref)
.map(|(p_bus, p_ref)| p_bus - p_ref)
.collect();
let va_pvpq = {
solver.solve(
b_pvpq.cols(),
b_pvpq.colidx(),
b_pvpq.rowptr(),
b_pvpq.values(),
&mut rhs,
true,
)?;
rhs
};
pvpq.iter()
.enumerate()
.for_each(|(i, &j)| va[j] = va_pvpq[i]);
if norm_inf(&va) > va_threshold {
success = false;
}
Ok((va, success))
}