(git:5e7fe52)
Loading...
Searching...
No Matches
qs_ot_minimizer_unittest.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
9 USE ieee_arithmetic, ONLY: ieee_positive_inf,&
10 ieee_quiet_nan,&
11 ieee_value
12 USE kinds, ONLY: dp
13 USE qs_ot_minimizer, ONLY: &
22
23 IMPLICIT NONE
24
25 LOGICAL :: curvature_valid, response_good, valid_response
26 REAL(kind=dp) :: baseline_drop, damping_shift, infinity, &
27 mixed_curvature, &
28 measured_drop, not_a_number, predicted_drop, &
29 response_advantage, response_gain, response_quality, &
30 response_scale, response_weight, residual_ratio, &
31 secant_curvature, sy_damped, yy_damped
32
33 IF (.NOT. broyden_history_restart_required(.true., .false., .true.)) THEN
34 error stop "Mermin Broyden did not restart a non-descent product history"
35 END IF
36 IF (.NOT. broyden_history_restart_required(.true., .true., .false.)) THEN
37 error stop "Explicit Broyden history restart was ignored"
38 END IF
39 IF (broyden_history_restart_required(.false., .true., .true.)) THEN
40 error stop "Broyden history restarted for a descent direction"
41 END IF
42 IF (broyden_history_restart_required(.true., .false., .false.)) THEN
43 error stop "Orbital-only Broyden default behavior changed"
44 END IF
45
46 IF (.NOT. cg_history_restart_required(.true., 0.5_dp + 32.0_dp*epsilon(1.0_dp), 0.5_dp)) THEN
47 error stop "Occupation-preconditioned CG retained unresolved free-energy history"
48 END IF
49 IF (cg_history_restart_required(.true., 0.5_dp + 256.0_dp*epsilon(1.0_dp), 0.5_dp)) THEN
50 error stop "Occupation-preconditioned CG discarded resolved free-energy history"
51 END IF
52 IF (cg_history_restart_required(.false., 0.5_dp, 0.5_dp)) THEN
53 error stop "Conventional CG history changed at an energy plateau"
54 END IF
55 IF (.NOT. cg_history_restart_required(.true., 1.0e6_dp + &
56 32.0_dp*epsilon(1.0_dp)*1.0e6_dp, 1.0e6_dp)) THEN
57 error stop "CG free-energy history restart is not scale aware"
58 END IF
59
60 damping_shift = lbfgs_curvature_damping_shift(0.6_dp, 1.0_dp, 1.0_dp, 0.5_dp)
61 IF (damping_shift /= 0.0_dp) error stop "Well-conditioned L-BFGS curvature was damped"
62
63 damping_shift = lbfgs_curvature_damping_shift(0.1_dp, 1.0_dp, 1.0_dp, 0.5_dp)
64 IF (damping_shift <= 0.0_dp) error stop "Weak L-BFGS curvature was not damped"
65 sy_damped = 0.1_dp + damping_shift
66 yy_damped = 1.0_dp + 2.0_dp*damping_shift*0.1_dp + damping_shift**2
67 IF (sy_damped <= 0.5_dp*sqrt(yy_damped)) THEN
68 error stop "L-BFGS damping did not satisfy the relative-curvature bound"
69 END IF
70
71 damping_shift = lbfgs_curvature_damping_shift(-0.1_dp, 1.0_dp, 1.0_dp, 0.2_dp)
72 IF (damping_shift <= 0.0_dp) error stop "Negative L-BFGS curvature was not regularized"
73
74 IF (lbfgs_curvature_damping_shift(0.1_dp, 0.0_dp, 1.0_dp, 0.5_dp) /= 0.0_dp) THEN
75 error stop "L-BFGS damping accepted a zero-length step"
76 END IF
77
78 IF (lbfgs_history_restart_required(100.0_dp, 1.0_dp)) THEN
79 error stop "L-BFGS history restarted at the exact gradient-growth threshold"
80 END IF
81 IF (.NOT. lbfgs_history_restart_required(100.0001_dp, 1.0_dp)) THEN
82 error stop "L-BFGS history did not restart above the gradient-growth threshold"
83 END IF
84 IF (.NOT. lbfgs_history_restart_required(400.0004_dp, 4.0_dp)) THEN
85 error stop "L-BFGS gradient-growth restart is not scale invariant"
86 END IF
87 IF (lbfgs_history_restart_required(1.0_dp, 0.0_dp)) THEN
88 error stop "L-BFGS history restarted without a valid preceding gradient"
89 END IF
90
91 IF (lbfgs_step_restart_required(1.0e-6_dp*0.1_dp, 0.1_dp)) THEN
92 error stop "L-BFGS step restarted at the exact line-search collapse threshold"
93 END IF
94 IF (.NOT. lbfgs_step_restart_required(0.999e-6_dp*0.1_dp, 0.1_dp)) THEN
95 error stop "L-BFGS step did not restart below the line-search collapse threshold"
96 END IF
97 IF (.NOT. lbfgs_step_restart_required(-0.999e-6_dp*2.5_dp, 2.5_dp)) THEN
98 error stop "L-BFGS step restart does not use the accepted-step magnitude"
99 END IF
100 IF (lbfgs_step_restart_required(0.0_dp, 0.0_dp)) THEN
101 error stop "L-BFGS step restarted without a valid reference step"
102 END IF
103
105 1.0_dp, 4.0_dp, 2.0_dp, 9.0_dp, response_scale, response_weight, valid_response)
106 IF (.NOT. valid_response) error stop "Valid L-BFGS response secant was rejected"
107 IF (abs(response_scale - 1.5_dp) > 1.0e-14_dp) THEN
108 error stop "L-BFGS response secant did not match the H0 direction norm"
109 END IF
110 IF (response_weight /= 1.0_dp) error stop "Well-aligned L-BFGS response secant was damped"
111
113 0.01_dp, 4.0_dp, 2.0_dp, 9.0_dp, response_scale, response_weight, valid_response)
114 IF (.NOT. valid_response) error stop "Dampable L-BFGS response secant was rejected"
115 mixed_curvature = response_weight*response_scale*0.01_dp + &
116 (1.0_dp - response_weight)*2.0_dp
117 IF (abs(mixed_curvature - 0.4_dp) > 1.0e-14_dp) THEN
118 error stop "L-BFGS response secant does not satisfy the Powell curvature bound"
119 END IF
120 IF (response_weight <= 0.0_dp .OR. response_weight >= 1.0_dp) THEN
121 error stop "Weak L-BFGS response secant was not convexly damped"
122 END IF
123
125 -1.0_dp, 4.0_dp, 2.0_dp, 9.0_dp, response_scale, response_weight, valid_response)
126 IF (valid_response) error stop "Non-descent L-BFGS response secant was accepted"
127 IF (response_weight /= 0.0_dp) error stop "Rejected L-BFGS response secant changed H0"
128
130 10.0_dp, 9.6_dp, 1.0_dp, 0.8_dp, 1.0_dp, 1.0_dp, 0.5_dp, 0.1_dp, &
131 predicted_drop, measured_drop, response_quality, residual_ratio, response_good)
132 IF (.NOT. response_good .OR. abs(predicted_drop - 0.375_dp) > 1.0e-14_dp .OR. &
133 abs(measured_drop - 0.4_dp) > 1.0e-14_dp .OR. &
134 abs(response_quality - 0.4_dp/0.375_dp) > 1.0e-14_dp .OR. &
135 abs(residual_ratio - 0.8_dp) > 1.0e-14_dp) THEN
136 error stop "Useful finite Mermin response sample was not accepted"
137 END IF
139 10.0_dp, 9.6_dp, 1.0_dp, 1.5_dp, 1.0_dp, 1.0_dp, 0.5_dp, 0.1_dp, &
140 predicted_drop, measured_drop, response_quality, residual_ratio, response_good)
141 IF (response_good) error stop "Residual-growing finite response sample was accepted"
143 10.0_dp, 9.6_dp, 1.0_dp, 1.05_dp, 1.0_dp, 1.0_dp, 0.5_dp, 0.1_dp, &
144 predicted_drop, measured_drop, response_quality, residual_ratio, response_good)
145 IF (response_good) error stop "Mildly residual-growing finite response sample was accepted"
147 10.0_dp, 9.6_dp, 1.0_dp, 0.8_dp, 0.1_dp, 10.0_dp, 1.0_dp, 0.1_dp, &
148 predicted_drop, measured_drop, response_quality, residual_ratio, response_good)
149 IF (response_good .OR. predicted_drop >= 0.0_dp) THEN
150 error stop "Indefinite non-descent response prediction was accepted"
151 END IF
153 10.0_dp, 9.6_dp, 1.0_dp, 0.8_dp, 1.0_dp, 1.0_dp, 1.0e-10_dp, 0.1_dp, &
154 predicted_drop, measured_drop, response_quality, residual_ratio, response_good)
155 IF (response_good) error stop "Collapsed response line search was accepted"
156
157 CALL ot_mermin_secant_curvature(10.0_dp, 9.6_dp, 1.0_dp, 0.5_dp, &
158 secant_curvature, curvature_valid)
159 IF (.NOT. curvature_valid .OR. abs(secant_curvature - 0.8_dp) > 1.0e-14_dp) THEN
160 error stop "Accepted Mermin secant curvature was not recovered"
161 END IF
162 CALL ot_mermin_secant_curvature(10.0_dp, 9.6_dp, 1.0_dp, 0.0_dp, &
163 secant_curvature, curvature_valid)
164 IF (curvature_valid .OR. secant_curvature /= 0.0_dp) THEN
165 error stop "Collapsed Mermin secant produced a curvature"
166 END IF
167
169 10.0_dp, 9.6_dp, 1.0_dp, 0.8_dp, 1.0_dp, 1.0_dp, 0.5_dp, &
170 response_advantage, residual_ratio, response_good)
171 IF (.NOT. response_good .OR. response_advantage <= 0.0_dp .OR. &
172 abs(residual_ratio - 0.8_dp) > 1.0e-14_dp) THEN
173 error stop "Improved passive finite response prediction was not retained"
174 END IF
176 10.0_dp, 9.6_dp, 1.0_dp, 0.8_dp, 1.0_dp, -1.0_dp, 0.5_dp, &
177 response_advantage, residual_ratio, response_good)
178 IF (response_good .OR. response_advantage >= 0.0_dp) THEN
179 error stop "Worse passive finite response prediction was retained"
180 END IF
181
183 1.0_dp, 1.0_dp, 1.0_dp, 1.0_dp, 2.0_dp, 0.5_dp, &
184 baseline_drop, predicted_drop, response_gain, response_good)
185 IF (.NOT. response_good .OR. abs(baseline_drop - 0.25_dp) > 1.0e-14_dp .OR. &
186 abs(predicted_drop - 0.375_dp) > 1.0e-14_dp .OR. response_gain <= 0.0_dp) THEN
187 error stop "Better coupled Mermin candidate was not preferred"
188 END IF
190 1.0_dp, 1.0_dp, 3.0_dp, 1.0_dp, 2.0_dp, 0.5_dp, &
191 baseline_drop, predicted_drop, response_gain, response_good)
192 IF (response_good .OR. response_gain >= 0.0_dp) THEN
193 error stop "Worse coupled Mermin candidate was preferred"
194 END IF
196 4.0_dp, 4.0_dp, 4.0_dp, 4.0_dp, 8.0_dp, 0.5_dp, &
197 baseline_drop, predicted_drop, response_gain, response_good)
198 IF (.NOT. response_good .OR. abs(response_gain - 1.0_dp/3.0_dp) > 1.0e-14_dp) THEN
199 error stop "Coupled Mermin candidate comparison is not scale invariant"
200 END IF
202 1.0_dp, 1.0_dp, 1.0_dp, 0.0_dp, 2.0_dp, 0.5_dp, &
203 baseline_drop, predicted_drop, response_gain, response_good)
204 IF (response_good) error stop "Coupled Mermin candidate ignored unresolved accepted curvature"
205
206 IF (.NOT. ot_mermin_response_probe(.true., 1.0e-3_dp, 8, 3, 0, 0)) THEN
207 error stop "Uncalibrated finite response probe was not scheduled"
208 END IF
209 IF (ot_mermin_response_probe(.true., 1.0e-3_dp, 8, 2, 0, 0)) THEN
210 error stop "Finite response probe ignored passive accepted-step calibration"
211 END IF
212 IF (ot_mermin_response_probe(.true., 1.0e-3_dp, 7, 3, 0, 0)) THEN
213 error stop "Uncalibrated finite response probe was scheduled too early"
214 END IF
215 IF (.NOT. ot_mermin_response_probe(.true., 1.0e-3_dp, 9, 3, 0, 0)) THEN
216 error stop "Calibrated finite response missed its one-step eligibility window"
217 END IF
218 IF (.NOT. ot_mermin_response_probe(.true., 1.0e-3_dp, 4, 3, 3, 0)) THEN
219 error stop "Calibrated finite response probe did not use the shorter interval"
220 END IF
221 IF (ot_mermin_response_probe(.true., 1.0e-3_dp, 8, 3, 3, 1)) THEN
222 error stop "Finite response cooldown was ignored"
223 END IF
224 IF (ot_mermin_response_probe(.true., 3.0e-3_dp, 8, 3, 3, 0)) THEN
225 error stop "Finite response was probed outside its local residual regime"
226 END IF
227
229 1.0_dp, 5, 3, 0, 6, .true.)) THEN
230 error stop "Pending finite-response shadow was not completed"
231 END IF
233 5.0e-3_dp, 6, 2, 0, 0, .false.)) THEN
234 error stop "Finite response was prepared outside its calibration residual regime"
235 END IF
237 3.0e-3_dp, 4, 2, 0, 0, .false.)) THEN
238 error stop "Finite response did not prepare its initial shadow calibration"
239 END IF
241 1.0e-3_dp, 6, 3, 0, 0, .false.)) THEN
242 error stop "Finite response did not seed the next sparse probe window"
243 END IF
245 1.0e-3_dp, 5, 3, 0, 0, .false.)) THEN
246 error stop "Finite response was prepared between sparse probe windows"
247 END IF
249 1.0e-3_dp, 6, 3, 0, 2, .false.)) THEN
250 error stop "Finite response preparation ignored an active cooldown"
251 END IF
252
253 IF (.NOT. ot_mermin_response_shadow_followup(1.0e-3_dp, 7, 3, 0, 0)) THEN
254 error stop "Finite response did not retain the probe-window seed shadow"
255 END IF
256 IF (.NOT. ot_mermin_response_shadow_followup(1.0e-3_dp, 8, 3, 0, 0)) THEN
257 error stop "Finite response did not retain the paired probe shadow"
258 END IF
259 IF (ot_mermin_response_shadow_followup(1.0e-3_dp, 9, 3, 0, 0)) THEN
260 error stop "Finite response retained a shadow beyond its probe window"
261 END IF
262 IF (.NOT. ot_mermin_response_shadow_followup(3.0e-3_dp, 2, 2, 0, 0)) THEN
263 error stop "Finite response stopped before completing initial calibration"
264 END IF
265
266 IF (qs_scf_kp_ref_refresh_ready(11, 1.0e-4_dp, 1.0e-6_dp, .true.)) THEN
267 error stop "K-point REF refresh accepted insufficient history"
268 END IF
269 IF (qs_scf_kp_ref_refresh_ready(12, 1.0e-4_dp, 1.0e-6_dp, .false.)) THEN
270 error stop "K-point REF refresh accepted a line-search trial point"
271 END IF
272 IF (qs_scf_kp_ref_refresh_ready(12, 0.999e-5_dp, 1.0e-6_dp, .true.)) THEN
273 error stop "K-point REF refresh accepted a converged residual"
274 END IF
275 IF (qs_scf_kp_ref_refresh_ready(12, 2.0001e-4_dp, 1.0e-6_dp, .true.)) THEN
276 error stop "K-point REF refresh accepted a residual outside the asymptotic window"
277 END IF
278 IF (.NOT. qs_scf_kp_ref_refresh_ready(12, 1.0e-4_dp, 1.0e-6_dp, .true.)) THEN
279 error stop "K-point REF refresh rejected a mature asymptotic state"
280 END IF
281 IF (qs_scf_kp_ref_refresh_ready(12, 0.75e-6_dp, 1.0e-6_dp, .true.)) THEN
282 error stop "K-point REF refresh entered the exit window before a physical rebuild"
283 END IF
284 IF (.NOT. qs_scf_kp_ref_refresh_ready(12, 0.75e-6_dp, 1.0e-6_dp, .true., .true.)) THEN
285 error stop "K-point REF refresh rejected a mature exit-only state"
286 END IF
287 IF (.NOT. qs_scf_kp_ref_refresh_ready(12, 5.0e-6_dp, 1.0e-6_dp, .true., .true.)) THEN
288 error stop "K-point REF refresh rejected a stagnant post-rebuild tail"
289 END IF
290 IF (qs_scf_kp_ref_refresh_ready(12, 0.2e-6_dp, 1.0e-6_dp, .true., .true.)) THEN
291 error stop "K-point REF refresh accepted a safely converged exit state"
292 END IF
293 IF (.NOT. all([qs_scf_kp_search_endpoint("OT CG"), &
294 qs_scf_kp_search_endpoint("OT SD"), &
295 qs_scf_kp_search_endpoint("OT DIIS"), &
296 qs_scf_kp_search_endpoint("OT BROY"), &
297 qs_scf_kp_search_endpoint("OT LBFGS")])) THEN
298 error stop "K-point REF refresh rejected a supported minimizer endpoint"
299 END IF
300 IF (qs_scf_kp_search_endpoint("OT LS") .OR. qs_scf_kp_search_endpoint("OT Sync")) THEN
301 error stop "K-point REF refresh counted a non-endpoint OT iteration"
302 END IF
303
304 infinity = ieee_value(0.0_dp, ieee_positive_inf)
305 not_a_number = ieee_value(0.0_dp, ieee_quiet_nan)
306 IF (lbfgs_history_restart_required(infinity, 1.0_dp)) THEN
307 error stop "L-BFGS history restarted for an infinite current gradient"
308 END IF
309 IF (lbfgs_history_restart_required(1.0_dp, infinity)) THEN
310 error stop "L-BFGS history restarted for an infinite preceding gradient"
311 END IF
312 IF (lbfgs_history_restart_required(not_a_number, 1.0_dp)) THEN
313 error stop "L-BFGS history restarted for a NaN current gradient"
314 END IF
315 IF (lbfgs_history_restart_required(1.0_dp, not_a_number)) THEN
316 error stop "L-BFGS history restarted for a NaN preceding gradient"
317 END IF
318 IF (lbfgs_step_restart_required(infinity, 1.0_dp)) THEN
319 error stop "L-BFGS step restarted for an infinite accepted step"
320 END IF
321 IF (lbfgs_step_restart_required(1.0_dp, infinity)) THEN
322 error stop "L-BFGS step restarted for an infinite reference step"
323 END IF
324 IF (lbfgs_step_restart_required(not_a_number, 1.0_dp)) THEN
325 error stop "L-BFGS step restarted for a NaN accepted step"
326 END IF
327 IF (lbfgs_curvature_damping_shift(not_a_number, 1.0_dp, 1.0_dp, 0.5_dp) /= 0.0_dp) THEN
328 error stop "L-BFGS damping accepted NaN curvature"
329 END IF
331 not_a_number, 1.0_dp, 1.0_dp, 1.0_dp, response_scale, response_weight, valid_response)
332 IF (valid_response) error stop "L-BFGS response secant accepted NaN curvature"
333
334END PROGRAM qs_ot_minimizer_unittest
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
orbital transformations
pure subroutine, public lbfgs_response_secant_parameters(g_dot_response, response_norm_sq, g_dot_h0_g, h0_g_norm_sq, response_scale, response_weight, valid)
Normalize and damp an occupation-response secant against the conventional H0 direction.
pure logical function, public ot_mermin_response_preparation_needed(residual, directions, shadow_good_samples, good_samples, cooldown, shadow_pending)
Decide whether the next accepted state needs the dense finite Mermin response.
pure logical function, public ot_mermin_response_probe(available, residual, directions, shadow_good_samples, good_samples, cooldown)
Select a sparse coupled-response probe from accepted-history evidence.
pure subroutine, public ot_mermin_response_assess(reference_energy, current_energy, reference_residual, current_residual, predicted_slope, predicted_curvature, position, default_step, predicted_drop, measured_drop, quality, residual_ratio, good)
Assess a finite-response candidate at its accepted Mermin endpoint.
pure logical function, public ot_mermin_response_shadow_followup(residual, directions, shadow_good_samples, good_samples, cooldown)
Decide whether a prepared conventional direction needs a shadow at its endpoint.
pure elemental logical function, public broyden_history_restart_required(non_descent, forget_history, do_ener)
Decide whether a non-descent Broyden step invalidates its secant history.
pure real(kind=dp) function, public lbfgs_curvature_damping_shift(sy, ss, yy, curvature_tol)
Returns the smallest shift y <- y + shift*s that meets relative L-BFGS curvature.
pure subroutine, public ot_mermin_response_candidate_preferred(baseline_slope, response_slope, response_curvature, accepted_slope, accepted_curvature, position, baseline_drop, response_drop, relative_gain, preferred)
Compare response and conventional directions in one accepted Mermin model.
pure logical function, public lbfgs_history_restart_required(current_gradient_norm_sq, previous_gradient_norm_sq)
Decides whether an L-BFGS history must be discarded after excessive gradient growth.
pure elemental logical function, public cg_history_restart_required(occupation_preconditioned, current_energy, reference_energy)
Decide whether an unresolved accepted energy change invalidates CG conjugacy.
pure subroutine, public ot_mermin_secant_curvature(reference_energy, current_energy, predicted_slope, position, curvature, valid)
Recover the total finite Mermin curvature of an accepted line-search secant.
pure subroutine, public ot_mermin_response_compare(reference_energy, current_energy, reference_residual, current_residual, predicted_slope, shadow_curvature, position, advantage, residual_ratio, good)
Compare an endpoint response shadow with the linear accepted-step model.
pure logical function, public lbfgs_step_restart_required(accepted_step, reference_step)
Decides whether L-BFGS must recover from a collapsed accepted line-search step.
Utility routines for qs_scf.
pure logical function, public qs_scf_kp_search_endpoint(method)
identify an accepted OT search endpoint from its iteration label
pure logical function, public qs_scf_kp_ref_refresh_ready(accepted_searches, residual, eps_scf, base_state, allow_exit_window)
decide whether a mature variable-occupation REF chart should be rebuilt
program qs_ot_minimizer_unittest