1use approx::assert_abs_diff_eq;
7use rstest::{fixture, rstest};
8
9use dftd3::prelude::*;
10
11#[fixture]
13fn numbers() -> Vec<usize> {
14 vec![1, 1, 6, 5, 1, 15, 8, 17, 13, 15, 5, 1, 9, 15, 1, 15]
15}
16
17#[fixture]
18fn positions() -> Vec<f64> {
19 #[rustfmt::skip]
20 let positions = vec![
21 2.79274810283778, 3.82998228828316, -2.79287054959216,
23 -1.43447454186833, 0.43418729987882, 5.53854345129809,
24 -3.26268343665218, -2.50644032426151, -1.56631149351046,
25 2.14548759959147, -0.88798018953965, -2.24592534506187,
26 -4.30233097423181, -3.93631518670031, -0.48930754109119,
27 0.06107643564880, -3.82467931731366, -2.22333344469482,
28 0.41168550401858, 0.58105573172764, 5.56854609916143,
29 4.41363836635653, 3.92515871809283, 2.57961724984000,
30 1.33707758998700, 1.40194471661647, 1.97530004949523,
31 3.08342709834868, 1.72520024666801, -4.42666116106828,
32 -3.02346932078505, 0.04438199934191, -0.27636197425010,
33 1.11508390868455, -0.97617412809198, 6.25462847718180,
34 0.61938955433011, 2.17903547389232, -6.21279842416963,
35 -2.67491681346835, 3.00175899761859, 1.05038813614845,
36 -4.13181080289514, -2.34226739863660, -3.44356159392859,
37 2.85007173009739, -2.64884892757600, 0.71010806424206,
38 ];
39 positions
40}
41
42#[fixture]
43fn model(numbers: Vec<usize>, positions: Vec<f64>) -> DFTD3Model {
44 DFTD3Model::new(&numbers, &positions, None, None)
45}
46
47#[test]
49fn test_rational_damping_noargs() {
50 assert!(DFTD3RationalDampingParamBuilder::default().build().is_err());
52
53 let builder = DFTD3RationalDampingParamBuilder::default().a1(0.4).a2(5.0);
54 assert!(builder.build().is_err());
55
56 let builder = DFTD3RationalDampingParamBuilder::default().s8(1.0).a2(5.0);
57 assert!(builder.build().is_err());
58
59 let builder = DFTD3RationalDampingParamBuilder::default().s8(1.0).a1(0.4);
60 assert!(builder.build().is_err());
61}
62
63#[test]
64fn test_zero_damping_noargs() {
65 assert!(DFTD3ZeroDampingParamBuilder::default().build().is_err());
67
68 let builder = DFTD3ZeroDampingParamBuilder::default().rs6(1.2);
69 assert!(builder.build().is_err());
70
71 let builder = DFTD3ZeroDampingParamBuilder::default().s8(1.0);
72 assert!(builder.build().is_err());
73}
74
75#[test]
76fn test_modified_rational_damping_noargs() {
77 assert!(DFTD3ModifiedRationalDampingParamBuilder::default().build().is_err());
79
80 let builder = DFTD3ModifiedRationalDampingParamBuilder::default().a1(0.4).a2(5.0);
81 assert!(builder.build().is_err());
82
83 let builder = DFTD3ModifiedRationalDampingParamBuilder::default().s8(1.0).a2(5.0);
84 assert!(builder.build().is_err());
85
86 let builder = DFTD3ModifiedRationalDampingParamBuilder::default().s8(1.0).a1(0.4);
87 assert!(builder.build().is_err());
88}
89
90#[test]
91fn test_modified_zero_damping_noargs() {
92 assert!(DFTD3ModifiedZeroDampingParamBuilder::default().build().is_err());
94
95 let builder = DFTD3ModifiedZeroDampingParamBuilder::default().rs6(1.2).bet(1.0);
96 assert!(builder.build().is_err());
97
98 let builder = DFTD3ModifiedZeroDampingParamBuilder::default().s8(1.0).bet(1.0);
99 assert!(builder.build().is_err());
100
101 let builder = DFTD3ModifiedZeroDampingParamBuilder::default().s8(1.0).rs6(1.2);
102 assert!(builder.build().is_err());
103}
104
105#[test]
106fn test_optimized_power_damping_noargs() {
107 assert!(DFTD3OptimizedPowerDampingParamBuilder::default().build().is_err());
109
110 let builder = DFTD3OptimizedPowerDampingParamBuilder::default().a1(0.3).a2(4.2).bet(1.0);
111 assert!(builder.build().is_err());
112
113 let builder = DFTD3OptimizedPowerDampingParamBuilder::default().s8(1.0).a2(4.2).bet(1.0);
114 assert!(builder.build().is_err());
115
116 let builder = DFTD3OptimizedPowerDampingParamBuilder::default().s8(1.0).a1(0.3).bet(1.0);
117 assert!(builder.build().is_err());
118
119 let builder = DFTD3OptimizedPowerDampingParamBuilder::default().s8(1.0).a1(0.3).a2(4.2);
120 assert!(builder.build().is_err());
121}
122
123#[rstest]
125fn test_structure(numbers: Vec<usize>, positions: Vec<f64>) {
126 let zero_positions = vec![0.0; 24 * 3];
130 assert!(DFTD3Model::new_f(&numbers, &zero_positions, None, None).is_err());
131
132 let bad_numbers = vec![1, 1, 1];
134 assert!(DFTD3Model::new_f(&bad_numbers, &positions, None, None).is_err());
135
136 let bad_positions = vec![0.0; 7];
138 assert!(DFTD3Model::new_f(&numbers, &bad_positions, None, None).is_err());
139
140 let mut inst = DFTD3Model::new(&numbers, &positions, None, None);
142
143 let bad_update_positions = vec![0.0; 7];
145 assert!(inst.update_f(&bad_update_positions, None).is_err());
146
147 let bad_lattice = vec![0.0; 7];
149 assert!(inst.update_f(&positions, Some(&bad_lattice)).is_err());
150
151 let zero_update_positions = vec![0.0; numbers.len() * 3];
153 assert!(inst.update_f(&zero_update_positions, None).is_err());
154}
155
156#[rstest]
158#[case(true, -0.029489232932494884)]
159#[case(false, -0.029589132634178342)]
160fn test_pbe0_d3_bj(model: DFTD3Model, #[case] atm: bool, #[case] expected: f64) {
161 let param = DFTD3RationalDampingParam::load_param("pbe0", atm);
162 let res = model.get_dispersion(¶m, false);
163 assert_abs_diff_eq!(res.energy, expected, epsilon = 1e-8);
164}
165
166#[rstest]
167#[case(true, -0.022714272555175656)]
168#[case(false, -0.022814172019166058)]
169fn test_b3lyp_d3_zero(model: DFTD3Model, #[case] atm: bool, #[case] expected: f64) {
170 let param = DFTD3ZeroDampingParam::load_param("b3lyp", atm);
171 let res = model.get_dispersion(¶m, false);
172 assert_abs_diff_eq!(res.energy, expected, epsilon = 1e-8);
173}
174
175#[rstest]
176#[case(true, -0.06327406660942464)]
177#[case(false, -0.06337396631110809)]
178fn test_pbe_d3_bjm(model: DFTD3Model, #[case] atm: bool, #[case] expected: f64) {
179 let param = DFTD3ModifiedRationalDampingParam::load_param("pbe", atm);
180 let res = model.get_dispersion(¶m, false);
181 assert_abs_diff_eq!(res.energy, expected, epsilon = 1e-8);
182}
183
184#[rstest]
185#[case(true, -0.026013316869036292)]
186#[case(false, -0.026113216333026695)]
187fn test_bp_d3_zerom(model: DFTD3Model, #[case] atm: bool, #[case] expected: f64) {
188 let param = DFTD3ModifiedZeroDampingParam::load_param("bp", atm);
189 let res = model.get_dispersion(¶m, false);
190 assert_abs_diff_eq!(res.energy, expected, epsilon = 1e-8);
191}
192
193#[rstest]
194#[case(true, -0.07681029606751344)]
195#[case(false, -0.07691018779028679)]
196fn test_b97d_d3_op(model: DFTD3Model, #[case] atm: bool, #[case] expected: f64) {
197 let param = DFTD3OptimizedPowerDampingParam::load_param("b97d", atm);
198 let res = model.get_dispersion(¶m, false);
199 assert_abs_diff_eq!(res.energy, expected, epsilon = 1e-8);
200}
201
202#[rstest]
204#[cfg(feature = "gcp")]
205fn test_gcp_empty(numbers: Vec<usize>, positions: Vec<f64>) {
206 let gcp = DFTD3GCP::new(&numbers, &positions, None, None, "", "");
207 let res = gcp.get_counterpoise(false);
208 assert_abs_diff_eq!(res.energy, 0.0, epsilon = 1e-8);
209}
210
211#[rstest]
212#[cfg(feature = "gcp")]
213#[case("b973c", -0.07653225860427701)]
214#[case("pbeh3c", 0.04977771585466725)]
215fn test_gcp_3c(
216 numbers: Vec<usize>,
217 positions: Vec<f64>,
218 #[case] method: &str,
219 #[case] expected: f64,
220) {
221 let gcp = DFTD3GCP::new(&numbers, &positions, None, None, method, "");
222 let res = gcp.get_counterpoise(false);
223 assert_abs_diff_eq!(res.energy, expected, epsilon = 1e-8);
224}
225
226fn test_pair_resolved() {
227 let thr = 1.0e-8;
228
229 let numbers = vec![16, 16, 16, 16, 16, 16, 16, 16];
230 #[rustfmt::skip]
231 let positions = vec![
232 -4.15128787379191, 1.71951973863958, -0.93066267097296,
233 -4.15128787379191, -1.71951973863958, 0.93066267097296,
234 -1.71951973863958, -4.15128787379191, -0.93066267097296,
235 1.71951973863958, -4.15128787379191, 0.93066267097296,
236 4.15128787379191, -1.71951973863958, -0.93066267097296,
237 4.15128787379191, 1.71951973863958, 0.93066267097296,
238 1.71951973863958, 4.15128787379191, -0.93066267097296,
239 -1.71951973863958, 4.15128787379191, 0.93066267097296,
240 ];
241
242 #[rustfmt::skip]
243 let pair_disp2 = [
244 [-0.00000000, -0.00153111, -0.00108052, -0.00032865, -0.00023796, -0.00032865, -0.00108052, -0.00153111],
245 [-0.00153111, -0.00000000, -0.00153111, -0.00108052, -0.00032865, -0.00023796, -0.00032865, -0.00108052],
246 [-0.00108052, -0.00153111, -0.00000000, -0.00153111, -0.00108052, -0.00032865, -0.00023796, -0.00032865],
247 [-0.00032865, -0.00108052, -0.00153111, -0.00000000, -0.00153111, -0.00108052, -0.00032865, -0.00023796],
248 [-0.00023796, -0.00032865, -0.00108052, -0.00153111, -0.00000000, -0.00153111, -0.00108052, -0.00032865],
249 [-0.00032865, -0.00023796, -0.00032865, -0.00108052, -0.00153111, -0.00000000, -0.00153111, -0.00108052],
250 [-0.00108052, -0.00032865, -0.00023796, -0.00032865, -0.00108052, -0.00153111, -0.00000000, -0.00153111],
251 [-0.00153111, -0.00108052, -0.00032865, -0.00023796, -0.00032865, -0.00108052, -0.00153111, -0.00000000],
252 ];
253
254 #[rustfmt::skip]
255 let pair_disp3 = [
256 [0.00000000e-00, 1.08616452e-07, 2.91526483e-07, 3.95872130e-07, 3.18133443e-07, 3.95872130e-07, 2.91526483e-07, 1.08616452e-07],
257 [1.08616452e-07, 0.00000000e-00, 1.08616452e-07, 2.91526483e-07, 3.95872130e-07, 3.18133443e-07, 3.95872130e-07, 2.91526483e-07],
258 [2.91526483e-07, 1.08616452e-07, 0.00000000e-00, 1.08616452e-07, 2.91526483e-07, 3.95872130e-07, 3.18133443e-07, 3.95872130e-07],
259 [3.95872130e-07, 2.91526483e-07, 1.08616452e-07, 0.00000000e-00, 1.08616452e-07, 2.91526483e-07, 3.95872130e-07, 3.18133443e-07],
260 [3.18133443e-07, 3.95872130e-07, 2.91526483e-07, 1.08616452e-07, 0.00000000e-00, 1.08616452e-07, 2.91526483e-07, 3.95872130e-07],
261 [3.95872130e-07, 3.18133443e-07, 3.95872130e-07, 2.91526483e-07, 1.08616452e-07, 0.00000000e-00, 1.08616452e-07, 2.91526483e-07],
262 [2.91526483e-07, 3.95872130e-07, 3.18133443e-07, 3.95872130e-07, 2.91526483e-07, 1.08616452e-07, 0.00000000e-00, 1.08616452e-07],
263 [1.08616452e-07, 2.91526483e-07, 3.95872130e-07, 3.18133443e-07, 3.95872130e-07, 2.91526483e-07, 1.08616452e-07, 0.00000000e-00],
264 ];
265
266 let model = DFTD3Model::new(&numbers, &positions, None, None);
267 let param = DFTD3RationalDampingParamBuilder::default()
268 .a1(0.5545)
269 .s8(2.2609)
270 .a2(3.2297)
271 .build()
272 .unwrap()
273 .new_param();
274
275 let res = model.get_pairwise_dispersion(¶m);
276
277 let expected_pairs2: Vec<f64> = pair_disp2.into_iter().flatten().collect();
279 let expected_pairs3: Vec<f64> = pair_disp3.into_iter().flatten().collect();
280
281 res.pair_energy2.iter().zip(expected_pairs2.iter()).for_each(|(x, y)| {
282 assert_abs_diff_eq!(x, y, epsilon = thr);
283 });
284 res.pair_energy3.iter().zip(expected_pairs3.iter()).for_each(|(x, y)| {
285 assert_abs_diff_eq!(x, y, epsilon = thr);
286 });
287}
288
289fn main() {
290 test_pair_resolved();
291}
292
293#[test]
294fn test() {
295 test_pair_resolved();
296}