use crate::newton::ProgressMonitor;
use crate::pfopt::MPOpt;
use powers::{d_imis_dv, SBus};
use anyhow::Result;
use full::slice::norm_inf;
use num_complex::Complex64;
use sparsetools::coo::Coo;
use sparsetools::csr::{CCSR, CSR};
use spsolve::Solver;
use std::iter::zip;
pub(crate) fn newtonpf_i_polar(
y_bus: &CSR<usize, Complex64>,
s_bus_fn: &dyn SBus,
v0: &[Complex64],
_ref: &[usize],
pv: &[usize],
pq: &[usize],
solver: &dyn Solver<usize, f64>,
mpopt: &MPOpt,
progress: Option<&dyn ProgressMonitor>,
) -> Result<(Vec<Complex64>, bool, usize)> {
let pv_pq = [pv, pq].concat();
let tol = mpopt.pf.tolerance;
let max_it = mpopt.pf.max_it_nr;
let mut converged = false;
let mut i = 0;
let mut v = v0.to_vec();
let mut va: Vec<f64> = v.iter().map(|v| v.arg()).collect();
let mut vm: Vec<f64> = v.iter().map(|v| v.norm()).collect();
let nb = v0.len();
let npv = pv.len();
let npq = pq.len();
let (j1, j2) = (0, npv); let (j3, j4) = (j2, j2 + npq); let (j5, j6) = (j4, j4 + npv); let (j7, j8) = (j6, j6 + npv); let j1_j2: Vec<usize> = (j1..j2).collect();
let j3_j4: Vec<usize> = (j3..j4).collect();
let j5_j6: Vec<usize> = (j5..j6).collect();
let j7_j8: Vec<usize> = (j7..j8).collect();
let mut s_bus = s_bus_fn.s_bus(&vm);
let mis: Vec<Complex64> = {
let i_bus: Vec<Complex64> = y_bus * &v;
pv.iter().for_each(|&i| {
s_bus[i].im = (v[i] * i_bus[i]).conj().im;
});
zip(&v, zip(&i_bus, &s_bus))
.map(|(i_bus, (s_bus, v))| i_bus - (s_bus / v).conj())
.collect()
};
let f = [
pv_pq.iter().map(|&i| mis[i].re).collect::<Vec<_>>(),
pv_pq.iter().map(|&i| mis[i].im).collect::<Vec<_>>(),
]
.concat();
let norm_f = norm_inf(&f);
if let Some(pm) = progress {
pm.update(i, norm_f); }
if norm_f < tol {
converged = true;
log::info!("Converged!");
}
fn compose(j: [[&Coo<usize, f64>; 3]; 2]) -> Result<Coo<usize, f64>> {
let j1x = Coo::h_stack3(j[0][0], j[0][1], j[0][2])?;
let j2x = Coo::h_stack3(j[1][0], j[1][1], j[1][2])?;
Coo::v_stack(&j1x, &j2x)
}
while !converged && i < max_it {
i = i + 1;
let d_imis_d_q = Coo::new(
nb,
nb,
pv.to_vec(),
pv.to_vec(),
pv.iter().map(|&i| Complex64::i() / v[i].conj()).collect(),
)?
.to_csr();
let (d_imis_d_va, d_imis_d_vm) = d_imis_dv(&s_bus, &y_bus, &v, false)?;
let j11 = d_imis_d_va.select(Some(&pv_pq), Some(&pv_pq))?.real();
let j12 = d_imis_d_q.select(Some(&pv_pq), Some(pv))?.real();
let j13 = d_imis_d_vm.select(Some(&pv_pq), Some(pq))?.real();
let j21 = d_imis_d_va.select(Some(&pv_pq), Some(&pv_pq))?.imag();
let j22 = d_imis_d_q.select(Some(&pv_pq), Some(pv))?.imag();
let j23 = d_imis_d_vm.select(Some(&pv_pq), Some(pq))?.imag();
let jac = compose([
[&j11.to_coo(), &j12.to_coo(), &j13.to_coo()],
[&j21.to_coo(), &j22.to_coo(), &j23.to_coo()],
])?
.to_csc();
let dx = {
let mut neg_f: Vec<f64> = f.iter().map(|f| -f).collect();
solver.solve(
jac.cols(),
jac.rowidx(),
jac.colptr(),
jac.values(),
&mut neg_f,
false,
)?;
neg_f
};
if npv != 0 {
(0..npv).for_each(|i| va[pv[i]] += dx[j1_j2[i]]);
(0..npv).for_each(|i| s_bus[pv[i]].im += dx[j5_j6[i]]);
}
if npq != 0 {
(0..npq).for_each(|i| va[pq[i]] += dx[j3_j4[i]]);
(0..npq).for_each(|i| vm[pq[i]] += dx[j7_j8[i]]);
}
v = zip(vm, va)
.map(|(vm, va)| Complex64::from_polar(vm, va))
.collect();
va = v.iter().map(|v| v.arg()).collect();
vm = v.iter().map(|v| v.norm()).collect();
let i_bus = y_bus * &v;
let mis: Vec<_> = zip(&v, zip(&i_bus, &s_bus))
.map(|(i_bus, (s_bus, v))| i_bus - (s_bus / v).conj())
.collect();
let f = [
pv_pq.iter().map(|&i| mis[i].re).collect::<Vec<f64>>(),
pv_pq.iter().map(|&i| mis[i].im).collect::<Vec<f64>>(),
]
.concat();
let norm_f = norm_inf(&f);
if let Some(pm) = progress {
pm.update(i, norm_f);
}
if norm_f < tol {
converged = true;
log::info!(
"Newton's method power flow (current balance, polar) converged in {} iterations.",
i
);
}
}
if !converged {
log::info!(
"Newton's method power flow (current balance, polar) did not converge in {} iterations.",
i
);
}
Ok((v, converged, i))
}
pub(crate) fn newtonpf_i_cart(
y_bus: &CSR<usize, Complex64>,
s_bus_fn: &dyn SBus,
v0: &[Complex64],
_ref: &[usize],
pv: &[usize],
pq: &[usize],
solver: &dyn Solver<usize, f64>,
mpopt: &MPOpt,
progress: Option<&dyn ProgressMonitor>,
) -> Result<(Vec<Complex64>, bool, usize)> {
let pv_pq = [pv, pq].concat();
let tol = mpopt.pf.tolerance;
let max_it = mpopt.pf.max_it_nr;
let mut converged = false;
let mut i = 0;
let mut v = v0.to_vec();
let vm: Vec<f64> = v.iter().map(|v| v.norm()).collect();
let nb = v0.len();
let npv = pv.len();
let npq = pq.len();
let (j1, j2) = (0, npv); let (j3, j4) = (j2, j2 + npq); let (j5, j6) = (j4, j4 + npv); let (j7, j8) = (j6, j6 + npq); let (j9, j10) = (j8, j8 + npv); let j1_j2: Vec<usize> = (j1..j2).collect();
let j3_j4: Vec<usize> = (j3..j4).collect();
let j5_j6: Vec<usize> = (j5..j6).collect();
let j7_j8: Vec<usize> = (j7..j8).collect();
let j9_j10: Vec<usize> = (j9..j10).collect();
let mut s_bus = s_bus_fn.s_bus(&vm);
let mis: Vec<_> = {
let i_bus: Vec<Complex64> = y_bus * &v;
pv.iter()
.for_each(|&i| s_bus[i].im = (v[i] * i_bus[i]).conj().im);
zip(&v, zip(&i_bus, &s_bus))
.map(|(i_bus, (s_bus, v))| i_bus - (s_bus / v).conj())
.collect()
};
let f: Vec<_> = [
pv_pq.iter().map(|&i| mis[i].re).collect::<Vec<_>>(),
pv_pq.iter().map(|&i| mis[i].im).collect(),
pv.iter()
.map(|&i| (v[i] * v[i].conj()).re - (vm[i] * vm[i]))
.collect(),
]
.concat();
let norm_f = norm_inf(&f);
if let Some(pm) = progress {
pm.update(i, norm_f); }
if norm_f < tol {
converged = true;
log::info!("Converged!");
}
while !converged && i < max_it {
i = i + 1;
let d_imis_d_q = Coo::new(
nb,
nb,
pv.to_vec(),
pv.to_vec(),
pv.iter().map(|&i| Complex64::i() / v[i].conj()).collect(),
)?
.to_csr();
let d_v2_d_vr = Coo::new(
npv,
npv + npq,
(0..npv).collect(),
(npq..npq + npv).collect(),
pv.iter().map(|&i| 2.0 * v[i].re).collect(),
)?
.to_csr();
let d_v2_d_vi = Coo::new(
npv,
npv + npq,
(0..npv).collect(),
(npq..npq + npv).collect(),
pv.iter().map(|&i| 2.0 * v[i].im).collect(),
)?
.to_csr();
let (d_imis_d_vr, d_imis_d_vi) = d_imis_dv(&s_bus, &y_bus, &v, true)?;
let j11 = d_imis_d_q.select(Some(pv), Some(pv))?.real();
let j12 = d_imis_d_vr.select(Some(&pv_pq), Some(&pv_pq))?.real();
let j13 = d_imis_d_vi.select(Some(&pv_pq), Some(&pv_pq))?.real();
let j21 = d_imis_d_q.select(Some(&pv_pq), Some(&pv))?.imag();
let j22 = d_imis_d_vr.select(Some(&pv_pq), Some(&pv_pq))?.imag();
let j23 = d_imis_d_vi.select(Some(&pv_pq), Some(&pv_pq))?.imag();
let j31 = CSR::with_size(npv, npv);
let j32 = d_v2_d_vr;
let j33 = d_v2_d_vi;
let jac = Coo::compose3([
[&j11.to_coo(), &j12.to_coo(), &j13.to_coo()],
[&j21.to_coo(), &j22.to_coo(), &j23.to_coo()],
[&j31.to_coo(), &j32.to_coo(), &j33.to_coo()],
])?
.to_csc();
let dx = {
let mut neg_f: Vec<f64> = f.iter().map(|f| -f).collect();
solver.solve(
jac.cols(),
jac.rowidx(),
jac.colptr(),
jac.values(),
&mut neg_f,
false,
)?;
neg_f
};
if npv != 0 {
for i in 0..npv {
v[pv[i]] += Complex64::new(dx[j5_j6[i]], dx[j9_j10[i]]);
s_bus[pv[i]].im += dx[j1_j2[i]];
}
}
if npq != 0 {
for i in 0..npq {
v[pq[i]] += Complex64::new(dx[j3_j4[i]], dx[j7_j8[i]]);
}
}
let i_bus = y_bus * &v;
let mis: Vec<_> = zip(&v, zip(&i_bus, &s_bus))
.map(|(i_bus, (s_bus, v))| i_bus - (s_bus / v).conj())
.collect();
let f: Vec<_> = [
pv_pq.iter().map(|&i| mis[i].re).collect::<Vec<_>>(),
pv_pq.iter().map(|&i| mis[i].im).collect(),
pv.iter()
.map(|&i| (v[i] * v[i].conj()).re - (vm[i] * vm[i]))
.collect(),
]
.concat();
let norm_f = norm_inf(&f);
if let Some(pm) = progress {
pm.update(i, norm_f);
}
if norm_f < tol {
converged = true;
log::info!(
"Newton's method power flow (current balance, cartesian) converged in {} iterations.",
i
);
}
}
if !converged {
log::info!(
"Newton's method power flow (current balance, cartesian) did not converge in {} iterations.",
i
);
}
Ok((v, converged, i))
}
pub(crate) fn newtonpf_i_hybrid(
y_bus: &CSR<usize, Complex64>,
s_bus_fn: &dyn SBus,
v0: &[Complex64],
_ref: &[usize],
pv: &[usize],
pq: &[usize],
_solver: &dyn Solver<usize, f64>,
mpopt: &MPOpt,
progress: Option<&dyn ProgressMonitor>,
) -> Result<(Vec<Complex64>, bool, usize)> {
let pv_pq = [pv, pq].concat();
let tol = mpopt.pf.tolerance;
let max_it = mpopt.pf.max_it_nr;
let mut converged = false;
let mut i = 0;
let v = v0.to_vec();
let vm: Vec<_> = v.iter().map(|v| v.norm()).collect();
let npv = pv.len();
let npq = pq.len();
let (_j1, j2) = (0, npv); let (_j3, j4) = (j2, j2 + npq); let (_j5, j6) = (j4, j4 + npv); let (_j7, _j8) = (j6, j6 + npq);
let mut s_bus = s_bus_fn.s_bus(&vm);
let mis: Vec<_> = {
let i_bus: Vec<Complex64> = y_bus * &v;
pv.iter()
.for_each(|&i| s_bus[i].im = (v[i] * i_bus[i]).conj().im);
zip(&v, zip(&i_bus, &s_bus))
.map(|(i_bus, (s_bus, v))| i_bus - (s_bus / v).conj())
.collect()
};
let f = [
pv_pq.iter().map(|&i| mis[i].re).collect::<Vec<_>>(),
pv_pq.iter().map(|&i| mis[i].im).collect::<Vec<_>>(),
]
.concat();
let norm_f = norm_inf(&f);
if let Some(pm) = progress {
pm.update(i, norm_f); }
if norm_f < tol {
converged = true;
log::info!("Converged!");
}
while !converged && i < max_it {
i = i + 1;
}
unimplemented!("newtonpf_i_hybrid")
}