use nalgebra::DMatrix;
use super::basis::{BasisFunction, BasisSet};
use super::gaussian_integrals::overlap_primitive;
pub fn build_overlap_matrix(basis: &BasisSet) -> DMatrix<f64> {
let n = basis.n_basis;
let mut s = DMatrix::zeros(n, n);
for i in 0..n {
s[(i, i)] = contracted_overlap(&basis.functions[i], &basis.functions[i]);
for j in (i + 1)..n {
let s_ij = contracted_overlap(&basis.functions[i], &basis.functions[j]);
s[(i, j)] = s_ij;
s[(j, i)] = s_ij;
}
}
s
}
fn contracted_overlap(bf_a: &BasisFunction, bf_b: &BasisFunction) -> f64 {
let mut s = 0.0;
for prim_a in &bf_a.primitives {
let norm_a = BasisFunction::normalization(
prim_a.alpha,
bf_a.angular[0],
bf_a.angular[1],
bf_a.angular[2],
);
for prim_b in &bf_b.primitives {
let norm_b = BasisFunction::normalization(
prim_b.alpha,
bf_b.angular[0],
bf_b.angular[1],
bf_b.angular[2],
);
let s_prim = overlap_primitive(
prim_a.alpha,
&bf_a.center,
bf_a.angular,
prim_b.alpha,
&bf_b.center,
bf_b.angular,
);
s += norm_a * prim_a.coefficient * norm_b * prim_b.coefficient * s_prim;
}
}
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_overlap_diagonal_positive() {
let basis = BasisSet::sto3g(&[1, 1], &[[0.0, 0.0, 0.0], [1.4, 0.0, 0.0]]);
let s = build_overlap_matrix(&basis);
for i in 0..basis.n_basis {
assert!(
s[(i, i)] > 0.0,
"S[{0},{0}] = {1} should be > 0",
i,
s[(i, i)]
);
}
}
#[test]
fn test_overlap_symmetric() {
let basis = BasisSet::sto3g(
&[8, 1, 1],
&[[0.0, 0.0, 0.0], [1.43, 1.11, 0.0], [-1.43, 1.11, 0.0]],
);
let s = build_overlap_matrix(&basis);
for i in 0..basis.n_basis {
for j in 0..basis.n_basis {
assert!(
(s[(i, j)] - s[(j, i)]).abs() < 1e-14,
"S not symmetric at ({}, {})",
i,
j
);
}
}
}
#[test]
fn test_overlap_h2_reasonable() {
let basis = BasisSet::sto3g(&[1, 1], &[[0.0, 0.0, 0.0], [1.4, 0.0, 0.0]]);
let s = build_overlap_matrix(&basis);
assert!(s[(0, 1)] > 0.0 && s[(0, 1)] < 1.0);
}
}