#[allow(dead_code)]
const GPU_HESSIAN_THRESHOLD: usize = 5;
pub fn generate_hessian_displacements(
positions: &[[f64; 3]],
step_size: f64,
) -> (Vec<Vec<[f64; 3]>>, usize) {
let n_atoms = positions.len();
let n_dof = 3 * n_atoms;
let mut displaced = Vec::with_capacity(2 * n_dof);
for dof in 0..n_dof {
let atom = dof / 3;
let coord = dof % 3;
let mut plus = positions.to_vec();
plus[atom][coord] += step_size;
displaced.push(plus);
let mut minus = positions.to_vec();
minus[atom][coord] -= step_size;
displaced.push(minus);
}
(displaced, 2 * n_dof)
}
pub fn assemble_hessian_from_energies(
energies: &[f64],
e_ref: f64,
step_size: f64,
) -> Vec<Vec<f64>> {
let n_dof = energies.len() / 2;
let h2 = step_size * step_size;
let mut hessian = vec![vec![0.0; n_dof]; n_dof];
for i in 0..n_dof {
let e_plus = energies[2 * i];
let e_minus = energies[2 * i + 1];
hessian[i][i] = (e_plus - 2.0 * e_ref + e_minus) / h2;
}
for i in 0..n_dof {
for j in (i + 1)..n_dof {
let e_pi = energies[2 * i];
let e_mi = energies[2 * i + 1];
let e_pj = energies[2 * j];
let e_mj = energies[2 * j + 1];
let h_ij = ((e_pi + e_pj) - (e_mi + e_mj)) / (4.0 * h2)
- 0.5 * (hessian[i][i] + hessian[j][j])
+ e_ref / h2;
hessian[i][j] = h_ij;
hessian[j][i] = h_ij;
}
}
hessian
}
#[cfg(feature = "parallel")]
pub fn evaluate_displacements_parallel<F>(displacements: &[Vec<[f64; 3]>], energy_fn: F) -> Vec<f64>
where
F: Fn(&[[f64; 3]]) -> f64 + Sync,
{
use rayon::prelude::*;
displacements
.par_iter()
.map(|geom| energy_fn(geom))
.collect()
}
pub fn evaluate_displacements_sequential<F>(
displacements: &[Vec<[f64; 3]>],
energy_fn: F,
) -> Vec<f64>
where
F: Fn(&[[f64; 3]]) -> f64,
{
displacements.iter().map(|geom| energy_fn(geom)).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_displacement_count() {
let positions = vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
let (disps, n) = generate_hessian_displacements(&positions, 0.005);
assert_eq!(n, 12); assert_eq!(disps.len(), 12);
}
#[test]
fn test_hessian_harmonic() {
let h = 0.001;
let energies = vec![
0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), ];
let hessian = assemble_hessian_from_energies(&energies, 0.0, h);
assert!((hessian[0][0] - 1.0).abs() < 0.01);
}
}