use integral::{Basis, Operator, Shell, ShellKind};
fn two_shell_basis(l: usize, sph: bool) -> Basis {
let kind = if sph {
ShellKind::Spherical
} else {
ShellKind::Cartesian
};
Basis::new(vec![
Shell::with_kind(l, [0.0, 0.0, 0.0], vec![1.2, 0.45], vec![0.6, 0.5], kind).unwrap(),
Shell::with_kind(l, [0.7, -0.3, 0.4], vec![0.9], vec![1.0], kind).unwrap(),
])
}
fn max_abs_diff(a: &[f64], b: &[f64]) -> f64 {
assert_eq!(a.len(), b.len());
a.iter()
.zip(b)
.map(|(x, y)| (x - y).abs())
.fold(0.0_f64, f64::max)
}
const TOL: f64 = 1e-11;
#[test]
fn overlap_equals_dsl_identity_full_l_cart_and_sph() {
let id = Operator::identity();
let mut worst = 0.0_f64;
for &sph in &[false, true] {
for l in 0..=6 {
let basis = two_shell_basis(l, sph);
let bespoke = basis.overlap();
let dsl = basis.int1e(&id).unwrap();
let d = max_abs_diff(&bespoke, dsl.real());
worst = worst.max(d).max(dsl.max_abs_imag());
eprintln!(
"overlap≡identity l={l} sph={sph}: re_diff={d:.2e} im={:.2e}",
dsl.max_abs_imag()
);
}
}
assert!(worst < TOL, "overlap≡identity worst {worst:.3e}");
}
#[test]
fn dipole_equals_dsl_r_full_l_cart_and_sph() {
let origin = [0.15, -0.25, 0.35];
let mut worst = 0.0_f64;
for &sph in &[false, true] {
for l in 0..=5 {
let basis = two_shell_basis(l, sph);
let bespoke = basis.dipole(origin); for (axis, comp) in bespoke.iter().enumerate() {
let dsl = basis.int1e(&Operator::dipole(axis, origin)).unwrap();
let d = max_abs_diff(comp, dsl.real());
worst = worst.max(d).max(dsl.max_abs_imag());
}
eprintln!("dipole≡r l={l} sph={sph}: worst so far {worst:.2e}");
}
}
assert!(worst < TOL, "dipole≡r worst {worst:.3e}");
}
#[test]
fn kinetic_equals_dsl_half_p_dot_p_full_l_cart_and_sph() {
let kin = Operator::kinetic();
let mut worst = 0.0_f64;
for &sph in &[false, true] {
for l in 0..=4 {
let basis = two_shell_basis(l, sph);
let bespoke = basis.kinetic();
let dsl = basis.int1e(&kin).unwrap();
let d = max_abs_diff(&bespoke, dsl.real());
worst = worst.max(d).max(dsl.max_abs_imag());
eprintln!(
"kinetic≡½p·p l={l} sph={sph}: re_diff={d:.2e} im={:.2e}",
dsl.max_abs_imag()
);
}
}
assert!(worst < TOL, "kinetic≡½p·p worst {worst:.3e}");
}
#[test]
fn operator_momentum_too_high_is_clean_error() {
use integral::IntegralError;
let basis = Basis::new(vec![
Shell::new(6, [0.0, 0.0, 0.0], vec![1.0], vec![1.0]).unwrap()
]);
assert_eq!(
basis.int1e(&Operator::kinetic()).unwrap_err(),
IntegralError::OperatorMomentumTooHigh {
l: 6,
degree: 2,
max: 6
}
);
assert_eq!(
basis.int1e(&Operator::dipole(0, [0.0; 3])).unwrap_err(),
IntegralError::OperatorMomentumTooHigh {
l: 6,
degree: 1,
max: 6
}
);
assert!(basis.int1e(&Operator::identity()).is_ok());
}