sci_form/gpu/
hessian_gpu.rs1#[allow(dead_code)]
12const GPU_HESSIAN_THRESHOLD: usize = 5;
13
14pub fn generate_hessian_displacements(
20 positions: &[[f64; 3]],
21 step_size: f64,
22) -> (Vec<Vec<[f64; 3]>>, usize) {
23 let n_atoms = positions.len();
24 let n_dof = 3 * n_atoms;
25 let mut displaced = Vec::with_capacity(2 * n_dof);
26
27 for dof in 0..n_dof {
28 let atom = dof / 3;
29 let coord = dof % 3;
30
31 let mut plus = positions.to_vec();
33 plus[atom][coord] += step_size;
34 displaced.push(plus);
35
36 let mut minus = positions.to_vec();
38 minus[atom][coord] -= step_size;
39 displaced.push(minus);
40 }
41
42 (displaced, 2 * n_dof)
43}
44
45pub fn assemble_hessian_from_energies(
54 energies: &[f64],
55 e_ref: f64,
56 step_size: f64,
57) -> Vec<Vec<f64>> {
58 let n_dof = energies.len() / 2;
59 let h2 = step_size * step_size;
60 let mut hessian = vec![vec![0.0; n_dof]; n_dof];
61
62 for i in 0..n_dof {
64 let e_plus = energies[2 * i];
65 let e_minus = energies[2 * i + 1];
66 hessian[i][i] = (e_plus - 2.0 * e_ref + e_minus) / h2;
67 }
68
69 for i in 0..n_dof {
74 for j in (i + 1)..n_dof {
75 let e_pi = energies[2 * i];
76 let e_mi = energies[2 * i + 1];
77 let e_pj = energies[2 * j];
78 let e_mj = energies[2 * j + 1];
79
80 let h_ij = ((e_pi + e_pj) - (e_mi + e_mj)) / (4.0 * h2)
82 - 0.5 * (hessian[i][i] + hessian[j][j])
83 + e_ref / h2;
84
85 hessian[i][j] = h_ij;
86 hessian[j][i] = h_ij;
87 }
88 }
89
90 hessian
91}
92
93#[cfg(feature = "parallel")]
98pub fn evaluate_displacements_parallel<F>(displacements: &[Vec<[f64; 3]>], energy_fn: F) -> Vec<f64>
99where
100 F: Fn(&[[f64; 3]]) -> f64 + Sync,
101{
102 use rayon::prelude::*;
103 displacements
104 .par_iter()
105 .map(|geom| energy_fn(geom))
106 .collect()
107}
108
109pub fn evaluate_displacements_sequential<F>(
111 displacements: &[Vec<[f64; 3]>],
112 energy_fn: F,
113) -> Vec<f64>
114where
115 F: Fn(&[[f64; 3]]) -> f64,
116{
117 displacements.iter().map(|geom| energy_fn(geom)).collect()
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_displacement_count() {
126 let positions = vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
127 let (disps, n) = generate_hessian_displacements(&positions, 0.005);
128 assert_eq!(n, 12); assert_eq!(disps.len(), 12);
130 }
131
132 #[test]
133 fn test_hessian_harmonic() {
134 let h = 0.001;
137 let energies = vec![
138 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), 0.5 * (h * h), ];
145 let hessian = assemble_hessian_from_energies(&energies, 0.0, h);
146 assert!((hessian[0][0] - 1.0).abs() < 0.01);
147 }
148}