mod eeq_tests {
use sci_form::charges_eeq::*;
fn ethanol_atoms() -> (Vec<u8>, Vec<[f64; 3]>) {
let elements = vec![6, 6, 8, 1, 1, 1, 1, 1, 1];
let positions = vec![
[0.0, 0.0, 0.0], [1.54, 0.0, 0.0], [2.42, 1.18, 0.0], [-0.63, 0.89, 0.0], [-0.63, -0.45, 0.89], [-0.63, -0.45, -0.89], [1.95, -0.52, 0.89], [1.95, -0.52, -0.89], [3.37, 1.01, 0.0], ];
(elements, positions)
}
#[test]
fn e5_1a_charge_neutrality() {
let (elements, positions) = ethanol_atoms();
let config = EeqConfig::default();
let result = compute_eeq_charges(&elements, &positions, &config);
assert!(
result.total_charge.abs() < 0.01,
"Total charge = {:.6}, expected 0",
result.total_charge
);
}
#[test]
fn e5_1b_coordination_numbers() {
let (elements, positions) = ethanol_atoms();
let cn = fractional_coordination(&elements, &positions);
assert!(cn[0] > 1.0, "C1 CN = {}", cn[0]);
assert!(cn[2] > 0.5, "O CN = {}", cn[2]);
}
#[test]
fn e5_1c_oxygen_most_negative() {
let (elements, positions) = ethanol_atoms();
let config = EeqConfig::default();
let result = compute_eeq_charges(&elements, &positions, &config);
let o_charge = result.charges[2];
assert!(o_charge < 0.0, "O charge = {}", o_charge);
for (i, &q) in result.charges.iter().enumerate() {
if i != 2 {
assert!(
o_charge <= q + 0.01,
"O ({:.3}) should be ≤ atom {} ({:.3})",
o_charge,
i,
q
);
}
}
}
#[test]
fn e5_1d_hydrogen_positive() {
let (elements, positions) = ethanol_atoms();
let config = EeqConfig::default();
let result = compute_eeq_charges(&elements, &positions, &config);
for i in 3..9 {
assert!(
result.charges[i] > -0.1,
"H{} charge = {}",
i,
result.charges[i]
);
}
}
#[test]
fn e5_2a_energy_finite() {
let (elements, positions) = ethanol_atoms();
let config = EeqConfig::default();
let result = compute_eeq_energy(&elements, &positions, &config);
assert!(result.electrostatic_energy.is_finite());
}
#[test]
fn e5_2b_gradient_nonzero() {
let (elements, positions) = ethanol_atoms();
let config = EeqConfig::default();
let grad = compute_eeq_gradient(&elements, &positions, &config);
let norm: f64 = grad
.iter()
.map(|g| g[0] * g[0] + g[1] * g[1] + g[2] * g[2])
.sum::<f64>()
.sqrt();
assert!(norm > 0.0, "Gradient norm = 0");
}
#[test]
fn e5_3a_charged_system() {
let elements = vec![6, 8, 8, 1];
let positions = vec![
[0.0, 0.0, 0.0],
[1.25, 0.0, 0.0],
[-1.25, 0.0, 0.0],
[0.0, 1.09, 0.0],
];
let config = EeqConfig {
total_charge: -1.0,
..Default::default()
};
let result = compute_eeq_charges(&elements, &positions, &config);
assert!(
(result.total_charge - (-1.0)).abs() < 0.01,
"Total charge = {:.4}, expected -1",
result.total_charge
);
}
#[test]
fn e5_3b_water_charge_comparison() {
let elements = vec![8, 1, 1];
let positions = vec![[0.0, 0.0, 0.0], [0.757, 0.586, 0.0], [-0.757, 0.586, 0.0]];
let config = EeqConfig::default();
let eeq = compute_eeq_charges(&elements, &positions, &config);
assert!(
eeq.charges[0] < -0.05 && eeq.charges[0] > -1.0,
"O charge = {:.4}, out of expected range",
eeq.charges[0]
);
}
}