use crate::user_data::UserData;
use num_complex::Complex64;
use sparsetools::coo::{CCoo, Coo};
use sparsetools::csc::{CCSC, CSC};
use std::iter::zip;
use sundials::nvector::NVector;
use sundials::sunmatrix::SparseMatrix;
#[allow(non_snake_case)]
pub(super) fn jac(
u: &NVector,
_fu: &mut NVector,
J: &mut SparseMatrix,
user_data: &Option<UserData>,
_tmp1: &NVector,
_tmp2: &NVector,
) -> i32 {
let user_data = user_data.as_ref().unwrap();
let nb = user_data.a.len();
let Sb = user_data.s_base;
let yd = u.as_slice();
let n = yd.len();
let mut A = sparsetools::dok::DoK::new(n, n);
for ld in &user_data.loads {
let a = user_data.a[&ld.i];
let v = user_data.v[&ld.i];
let k = 0.0;
A.add(a, v, (ld.pl / Sb) * k).unwrap();
A.add(v, v, (ld.ql / Sb) * k).unwrap();
}
for sh in &user_data.fixed_shunts {
let a = user_data.a[&sh.i];
let v = user_data.v[&sh.i];
let gs = sh.gl / Sb;
let bs = sh.bl / Sb;
let dV2 = 2.0 * yd[v];
let dPdV = dV2 * gs;
let dQdV = -dV2 * bs;
A.add(a, v, dPdV).unwrap();
A.add(v, v, dQdV).unwrap();
}
for (i, g) in user_data.generators.iter().enumerate() {
let u = 1.0;
let a = user_data.a[&g.i];
let v = user_data.v[&g.i];
let q = user_data.q[&i];
A.set(v, v, -1e-6).unwrap();
A.set(v, q, -u).unwrap();
A.set(q, v, u).unwrap();
A.set(q, q, u - 1.0 - 1e-6).unwrap();
if g.i == user_data.slack {
let p = user_data.p[&i];
A.set(a, p, -u).unwrap();
A.set(p, a, u).unwrap();
A.set(p, p, u - 1.0 - 1e-6).unwrap();
}
}
let L = line_jac(nb, yd, &user_data.y_mat.to_csc());
for (r, c, v) in L {
A.add(r, c, v).unwrap();
}
println!("J:\n{}", A.to_csr().to_table());
let nnz = J.nnz();
if nnz < A.nnz() {
J.reallocate(A.nnz()).unwrap();
}
let (colptrs, rowvals, nz) = J.index_pointers_values_data_mut();
let Ac = A.to_csc();
zip(colptrs, Ac.colptr()).for_each(|colptr| {
*colptr.0 = *colptr.1 as i64;
});
zip(rowvals, Ac.rowidx()).for_each(|rowval| {
*rowval.0 = *rowval.1 as i64;
});
nz.copy_from_slice(Ac.values());
0
}
#[allow(non_snake_case)]
fn line_jac(nb: usize, yd: &[f64], Y: &CSC<usize, Complex64>) -> Coo<usize, f64> {
let Vn: Vec<Complex64> = yd[..nb]
.iter()
.map(|yd| Complex64::from_polar(1.0, *yd))
.collect();
let Vc: Vec<Complex64> = zip(&yd[nb..2 * nb], &Vn)
.map(|(yd, vn)| Complex64::new(*yd, 0.0) * vn)
.collect();
let Ic = Y * &Vc;
let diagVn = CSC::with_diagonal(Vn);
let diagVc = CSC::with_diagonal(Vc);
let diagIc = CSC::with_diagonal(Ic);
let dS: Coo<usize, Complex64> = {
let dScsc = Y * &diagVn;
let dScsc = &diagVc * &dScsc.conj();
let temp = diagIc.conj() * &diagVn;
let dScsc = dScsc + temp;
dScsc.to_coo()
};
let dR: Coo<usize, Complex64> = {
let dRcsc = diagIc;
let mut temp = Y * &diagVc;
temp.values_mut().iter_mut().for_each(|v| *v = -*v);
let dRcsc = dRcsc + temp;
let dRcsc = diagVc.conj() * &dRcsc;
dRcsc.to_coo()
};
let J = Coo::compose([[&dR.imag(), &dS.real()], [&dR.real(), &dS.imag()]]).unwrap();
J
}