use integral_core::operator::operator_into;
use integral_core::os::MAX_L;
pub use integral_core::operator::{Factor, Operator, Term};
use crate::integrals::{place_block, to_func_1e};
use crate::shell::Basis;
use crate::IntegralError;
#[derive(Debug, Clone, PartialEq)]
pub struct OperatorMatrix {
nao: usize,
re: Vec<f64>,
im: Vec<f64>,
}
impl OperatorMatrix {
#[must_use]
pub fn nao(&self) -> usize {
self.nao
}
#[must_use]
pub fn real(&self) -> &[f64] {
&self.re
}
#[must_use]
pub fn imag(&self) -> &[f64] {
&self.im
}
#[must_use]
pub fn max_abs_imag(&self) -> f64 {
self.im.iter().fold(0.0_f64, |m, &v| m.max(v.abs()))
}
#[must_use]
pub fn max_abs_real(&self) -> f64 {
self.re.iter().fold(0.0_f64, |m, &v| m.max(v.abs()))
}
}
impl Basis {
pub fn int1e(&self, op: &Operator) -> Result<OperatorMatrix, IntegralError> {
let deg = op.degree();
for s in self.shells() {
if s.l() + deg > MAX_L {
return Err(IntegralError::OperatorMomentumTooHigh {
l: s.l(),
degree: deg,
max: MAX_L,
});
}
}
let n = self.nao();
let offs = self.offsets();
let mut re = vec![0.0; n * n];
let mut im = vec![0.0; n * n];
let shells = self.shells();
for (si, sa) in shells.iter().enumerate() {
for (sj, sb) in shells.iter().enumerate() {
let (na, nb) = (sa.n_cart(), sb.n_cart());
let mut br = vec![0.0; na * nb];
let mut bi = vec![0.0; na * nb];
for pi in 0..sa.n_prim() {
for pj in 0..sb.n_prim() {
let scale = sa.primitive_coeff(pi) * sb.primitive_coeff(pj);
operator_into(op, sa.prim(pi), sb.prim(pj), scale, &mut br, &mut bi);
}
}
let br = to_func_1e(br, sa, sb);
let bi = to_func_1e(bi, sa, sb);
let nbf = sb.n_func();
place_block(&mut re, n, offs[si], offs[sj], &br, nbf);
place_block(&mut im, n, offs[si], offs[sj], &bi, nbf);
}
}
Ok(OperatorMatrix { nao: n, re, im })
}
}