use crate::engine::os::{GridCoulombPair, GridCoulombScratch};
use crate::integrals::{check_erf_omega, effective_coeffs, place_block, to_func_1e};
use crate::shell::Basis;
use crate::EriKernel;
impl Basis {
#[must_use]
pub fn grid_coulomb(&self, points: &[[f64; 3]]) -> Vec<f64> {
let nao = self.nao();
let mut out = vec![0.0; points.len() * nao * nao];
self.grid_coulomb_into(points, &mut out);
out
}
pub fn grid_coulomb_into(&self, points: &[[f64; 3]], out: &mut [f64]) {
self.grid_kernel_into(points, None, out);
}
#[must_use]
pub fn grid_coulomb_kernel(&self, points: &[[f64; 3]], k: EriKernel) -> Vec<f64> {
let nao = self.nao();
let mut out = vec![0.0; points.len() * nao * nao];
self.grid_coulomb_kernel_into(points, k, &mut out);
out
}
pub fn grid_coulomb_kernel_into(&self, points: &[[f64; 3]], k: EriKernel, out: &mut [f64]) {
match k {
EriKernel::Coulomb => self.grid_kernel_into(points, None, out),
EriKernel::Erf { omega } => {
check_erf_omega(omega);
self.grid_kernel_into(points, Some(omega), out);
}
}
}
fn grid_kernel_into(&self, points: &[[f64; 3]], omega: Option<f64>, out: &mut [f64]) {
let nao = self.nao();
let mm = nao * nao;
assert_eq!(
out.len(),
points.len() * mm,
"grid_coulomb output buffer must be n_points · nao² = {} elements",
points.len() * mm
);
let offs = self.offsets();
let shells = self.shells();
let eff: Vec<Vec<f64>> = shells.iter().map(effective_coeffs).collect();
let mut scratch = GridCoulombScratch::default();
for (si, sa) in shells.iter().enumerate() {
for (sj, sb) in shells.iter().enumerate().take(si + 1) {
let mut prim_pairs = Vec::with_capacity(eff[si].len() * eff[sj].len());
for (pi, &ca) in eff[si].iter().enumerate() {
for (pj, &cb) in eff[sj].iter().enumerate() {
prim_pairs.push((sa.exponents()[pi], sb.exponents()[pj], ca * cb));
}
}
let pair =
GridCoulombPair::new(sa.l(), sb.l(), sa.center(), sb.center(), &prim_pairs);
let (na, nb) = pair.dims();
let (naf, nbf) = (sa.n_func(), sb.n_func());
for (g, &c) in points.iter().enumerate() {
let mut block = vec![0.0; na * nb];
match omega {
None => pair.eval_into(c, &mut scratch, &mut block),
Some(w) => pair.eval_erf_into(c, w, &mut scratch, &mut block),
}
let fb = to_func_1e(block, sa, sb);
let mat = &mut out[g * mm..(g + 1) * mm];
place_block(mat, nao, offs[si], offs[sj], &fb, nbf);
if si != sj {
for a in 0..naf {
for b in 0..nbf {
mat[(offs[sj] + b) * nao + offs[si] + a] = fb[a * nbf + b];
}
}
}
}
}
}
}
}