Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief orbital transformations
10 : !> \par History
11 : !> None
12 : !> \author Joost VandeVondele (09.2002)
13 : ! **************************************************************************************************
14 : MODULE qs_ot_minimizer
15 :
16 : USE cp_dbcsr_api, ONLY: dbcsr_add,&
17 : dbcsr_copy,&
18 : dbcsr_dot,&
19 : dbcsr_get_info,&
20 : dbcsr_init_random,&
21 : dbcsr_p_type,&
22 : dbcsr_scale,&
23 : dbcsr_set
24 : USE cp_log_handling, ONLY: cp_get_default_logger,&
25 : cp_logger_get_default_unit_nr,&
26 : cp_logger_type
27 : USE kinds, ONLY: dp,&
28 : int_8
29 : USE mathlib, ONLY: diamat_all
30 : USE preconditioner, ONLY: apply_preconditioner
31 : USE qs_ot, ONLY: qs_ot_get_derivative,&
32 : qs_ot_get_derivative_ref
33 : USE qs_ot_types, ONLY: qs_ot_type
34 : #include "./base/base_uses.f90"
35 :
36 : IMPLICIT NONE
37 :
38 : PRIVATE
39 :
40 : PUBLIC :: ot_mini
41 :
42 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_ot_minimizer'
43 :
44 : CONTAINS
45 : !
46 : ! the minimizer interface
47 : ! should present all possible modes of minimization
48 : ! these include CG SD DIIS
49 : !
50 : !
51 : ! IN the case of nspin != 1 we have a gradient that is distributed over different qs_ot_env.
52 : ! still things remain basically the same, since there are no constraints between the different qs_ot_env
53 : ! we only should take care that the various scalar products are taken over the full vectors.
54 : ! all the information needed and collected can be stored in the fist qs_ot_env only
55 : ! (indicating that the data type for the gradient/position and minization should be separated)
56 : !
57 : ! **************************************************************************************************
58 : !> \brief ...
59 : !> \param qs_ot_env ...
60 : !> \param matrix_hc ...
61 : ! **************************************************************************************************
62 76816 : SUBROUTINE ot_mini(qs_ot_env, matrix_hc)
63 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
64 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_hc
65 :
66 : CHARACTER(len=*), PARAMETER :: routineN = 'ot_mini'
67 :
68 : INTEGER :: handle, ispin, nspin
69 : LOGICAL :: do_ener, do_ks
70 : REAL(KIND=dp) :: tmp
71 :
72 76816 : CALL timeset(routineN, handle)
73 :
74 76816 : nspin = SIZE(qs_ot_env)
75 :
76 76816 : do_ks = qs_ot_env(1)%settings%ks
77 76816 : do_ener = qs_ot_env(1)%settings%do_ener
78 :
79 76816 : qs_ot_env(1)%OT_METHOD_FULL = ""
80 :
81 : ! compute the gradient for the variables x
82 76816 : IF (.NOT. qs_ot_env(1)%energy_only) THEN
83 59413 : qs_ot_env(1)%gradient = 0.0_dp
84 125637 : DO ispin = 1, nspin
85 66224 : IF (do_ks) THEN
86 129596 : SELECT CASE (qs_ot_env(1)%settings%ot_algorithm)
87 : CASE ("TOD")
88 : CALL qs_ot_get_derivative(matrix_hc(ispin)%matrix, qs_ot_env(ispin)%matrix_x, &
89 : qs_ot_env(ispin)%matrix_sx, &
90 63372 : qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
91 : CASE ("REF")
92 : CALL qs_ot_get_derivative_ref(matrix_hc(ispin)%matrix, &
93 : qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_sx, &
94 2852 : qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
95 : CASE DEFAULT
96 66224 : CPABORT("ALGORITHM NYI")
97 : END SELECT
98 : END IF
99 : ! and also the gradient along the direction
100 125637 : IF (qs_ot_env(1)%use_dx) THEN
101 61488 : IF (do_ks) THEN
102 61488 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
103 61488 : qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
104 61488 : IF (qs_ot_env(1)%settings%do_rotation) THEN
105 1388 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
106 1388 : qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + 0.5_dp*tmp
107 : END IF
108 : END IF
109 61488 : IF (do_ener) THEN
110 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
111 0 : qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
112 : END IF
113 : ELSE
114 4736 : IF (do_ks) THEN
115 4736 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
116 4736 : qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
117 4736 : IF (qs_ot_env(1)%settings%do_rotation) THEN
118 0 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
119 0 : qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - 0.5_dp*tmp
120 : END IF
121 : END IF
122 4736 : IF (do_ener) THEN
123 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
124 0 : qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
125 : END IF
126 : END IF
127 : END DO
128 : END IF
129 :
130 113008 : SELECT CASE (qs_ot_env(1)%settings%OT_METHOD)
131 : CASE ("CG")
132 36192 : IF (current_point_is_fine(qs_ot_env)) THEN
133 18807 : qs_ot_env(1)%OT_METHOD_FULL = "OT CG"
134 18807 : CALL ot_new_cg_direction(qs_ot_env)
135 18807 : qs_ot_env(1)%line_search_count = 0
136 : ELSE
137 17385 : qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
138 : END IF
139 36192 : CALL do_line_search(qs_ot_env)
140 : CASE ("SD")
141 42 : IF (current_point_is_fine(qs_ot_env)) THEN
142 24 : qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
143 24 : CALL ot_new_sd_direction(qs_ot_env)
144 24 : qs_ot_env(1)%line_search_count = 0
145 : ELSE
146 18 : qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
147 : END IF
148 42 : CALL do_line_search(qs_ot_env)
149 : CASE ("DIIS")
150 40406 : qs_ot_env(1)%OT_METHOD_FULL = "OT DIIS"
151 40406 : CALL ot_diis_step(qs_ot_env)
152 : CASE ("BROY")
153 176 : qs_ot_env(1)%OT_METHOD_FULL = "OT BROY"
154 176 : CALL ot_broyden_step(qs_ot_env)
155 : CASE DEFAULT
156 76816 : CPABORT("OT_METHOD NYI")
157 : END SELECT
158 :
159 76816 : CALL timestop(handle)
160 :
161 76816 : END SUBROUTINE ot_mini
162 :
163 : !
164 : ! checks if the current point is a good point for finding a new direction
165 : ! or if we should improve the line_search, if it is used
166 : !
167 : ! **************************************************************************************************
168 : !> \brief ...
169 : !> \param qs_ot_env ...
170 : !> \return ...
171 : ! **************************************************************************************************
172 36234 : FUNCTION current_point_is_fine(qs_ot_env) RESULT(res)
173 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
174 : LOGICAL :: res
175 :
176 36234 : res = .FALSE.
177 :
178 : ! only if we have a gradient it can be fine
179 36234 : IF (.NOT. qs_ot_env(1)%energy_only) THEN
180 :
181 : ! we have not yet started with the line search
182 18831 : IF (qs_ot_env(1)%line_search_count .EQ. 0) THEN
183 36234 : res = .TRUE.
184 : RETURN
185 : END IF
186 :
187 15882 : IF (qs_ot_env(1)%line_search_might_be_done) THEN
188 : ! here we put the more complicated logic later
189 15882 : res = .TRUE.
190 15882 : RETURN
191 : END IF
192 :
193 : END IF
194 :
195 : END FUNCTION current_point_is_fine
196 :
197 : !
198 : ! performs various kinds of line searches
199 : !
200 : ! **************************************************************************************************
201 : !> \brief ...
202 : !> \param qs_ot_env ...
203 : ! **************************************************************************************************
204 36234 : SUBROUTINE do_line_search(qs_ot_env)
205 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
206 :
207 36618 : SELECT CASE (qs_ot_env(1)%settings%line_search_method)
208 : CASE ("GOLD")
209 384 : CALL do_line_search_gold(qs_ot_env)
210 : CASE ("3PNT")
211 1168 : CALL do_line_search_3pnt(qs_ot_env)
212 : CASE ("2PNT")
213 34672 : CALL do_line_search_2pnt(qs_ot_env)
214 : CASE ("NONE")
215 10 : CALL do_line_search_none(qs_ot_env)
216 : CASE DEFAULT
217 36234 : CPABORT("NYI")
218 : END SELECT
219 36234 : END SUBROUTINE do_line_search
220 :
221 : ! **************************************************************************************************
222 : !> \brief moves x adding the right amount (ds) of the gradient or search direction
223 : !> \param ds ...
224 : !> \param qs_ot_env ...
225 : !> \par History
226 : !> 08.2004 created [ Joost VandeVondele ] copied here from a larger number of subroutines
227 : ! **************************************************************************************************
228 36234 : SUBROUTINE take_step(ds, qs_ot_env)
229 : REAL(KIND=dp) :: ds
230 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
231 :
232 : CHARACTER(len=*), PARAMETER :: routineN = 'take_step'
233 :
234 : INTEGER :: handle, ispin, nspin
235 : LOGICAL :: do_ener, do_ks
236 :
237 36234 : CALL timeset(routineN, handle)
238 :
239 36234 : nspin = SIZE(qs_ot_env)
240 :
241 36234 : do_ks = qs_ot_env(1)%settings%ks
242 36234 : do_ener = qs_ot_env(1)%settings%do_ener
243 :
244 : ! now update x to take into account this new step
245 : ! either dx or -gx is the direction to use
246 36234 : IF (qs_ot_env(1)%use_dx) THEN
247 36222 : IF (do_ks) THEN
248 79302 : DO ispin = 1, nspin
249 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_dx, &
250 43080 : alpha_scalar=1.0_dp, beta_scalar=ds)
251 79302 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
252 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, qs_ot_env(ispin)%rot_mat_dx, &
253 2010 : alpha_scalar=1.0_dp, beta_scalar=ds)
254 : END IF
255 : END DO
256 : END IF
257 36222 : IF (do_ener) THEN
258 0 : DO ispin = 1, nspin
259 0 : qs_ot_env(ispin)%ener_x = qs_ot_env(ispin)%ener_x + ds*qs_ot_env(ispin)%ener_dx
260 : END DO
261 : END IF
262 : ELSE
263 12 : IF (do_ks) THEN
264 24 : DO ispin = 1, nspin
265 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_gx, &
266 12 : alpha_scalar=1.0_dp, beta_scalar=-ds)
267 24 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
268 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, qs_ot_env(ispin)%rot_mat_gx, &
269 0 : alpha_scalar=1.0_dp, beta_scalar=-ds)
270 : END IF
271 : END DO
272 : END IF
273 12 : IF (do_ener) THEN
274 0 : DO ispin = 1, nspin
275 0 : qs_ot_env(ispin)%ener_x = qs_ot_env(ispin)%ener_x - ds*qs_ot_env(ispin)%ener_gx
276 : END DO
277 : END IF
278 : END IF
279 36234 : CALL timestop(handle)
280 36234 : END SUBROUTINE take_step
281 :
282 : ! implements a golden ratio search as a robust way of minimizing
283 : ! **************************************************************************************************
284 : !> \brief ...
285 : !> \param qs_ot_env ...
286 : ! **************************************************************************************************
287 384 : SUBROUTINE do_line_search_gold(qs_ot_env)
288 :
289 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
290 :
291 : CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_gold'
292 : REAL(KIND=dp), PARAMETER :: gold_sec = 0.3819_dp
293 :
294 : INTEGER :: count, handle
295 : REAL(KIND=dp) :: ds
296 :
297 384 : CALL timeset(routineN, handle)
298 :
299 384 : qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
300 384 : count = qs_ot_env(1)%line_search_count
301 384 : qs_ot_env(1)%line_search_might_be_done = .FALSE.
302 384 : qs_ot_env(1)%energy_only = .TRUE.
303 :
304 384 : IF (count + 1 .GT. SIZE(qs_ot_env(1)%OT_pos)) THEN
305 : ! should not happen, we pass with a warning first
306 : ! you can increase the size of OT_pos and the like in qs_ot_env
307 0 : CPABORT("MAX ITER EXCEEDED : FATAL")
308 : END IF
309 :
310 384 : IF (qs_ot_env(1)%line_search_count .EQ. 1) THEN
311 30 : qs_ot_env(1)%line_search_left = 1
312 30 : qs_ot_env(1)%line_search_right = 0
313 30 : qs_ot_env(1)%line_search_mid = 1
314 30 : qs_ot_env(1)%ot_pos(1) = 0.0_dp
315 30 : qs_ot_env(1)%ot_energy(1) = qs_ot_env(1)%etotal
316 30 : qs_ot_env(1)%ot_pos(2) = qs_ot_env(1)%ds_min/gold_sec
317 : ELSE
318 354 : qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
319 : ! it's essentially a book keeping game.
320 : ! keep left on the left, keep (bring) right on the right
321 : ! and mid in between these two
322 354 : IF (qs_ot_env(1)%line_search_right .EQ. 0) THEN ! we do not yet have the right bracket
323 40 : IF (qs_ot_env(1)%ot_energy(count - 1) .LT. qs_ot_env(1)%ot_energy(count)) THEN
324 26 : qs_ot_env(1)%line_search_right = count
325 : qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) + &
326 : (qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) - &
327 26 : qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))*gold_sec
328 : ELSE
329 14 : qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
330 14 : qs_ot_env(1)%line_search_mid = count
331 14 : qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ot_pos(count)/gold_sec ! expand
332 : END IF
333 : ELSE
334 : ! first determine where we are and construct the new triplet
335 314 : IF (qs_ot_env(1)%ot_pos(count) .LT. qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) THEN
336 140 : IF (qs_ot_env(1)%ot_energy(count) .LT. qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
337 42 : qs_ot_env(1)%line_search_right = qs_ot_env(1)%line_search_mid
338 42 : qs_ot_env(1)%line_search_mid = count
339 : ELSE
340 98 : qs_ot_env(1)%line_search_left = count
341 : END IF
342 : ELSE
343 174 : IF (qs_ot_env(1)%ot_energy(count) .LT. qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
344 66 : qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
345 66 : qs_ot_env(1)%line_search_mid = count
346 : ELSE
347 108 : qs_ot_env(1)%line_search_right = count
348 : END IF
349 : END IF
350 : ! now find the new point in the largest section
351 314 : IF ((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
352 : - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) .GT. &
353 : (qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
354 : - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left))) THEN
355 : qs_ot_env(1)%ot_pos(count + 1) = &
356 : qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) + &
357 : gold_sec*(qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
358 154 : - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))
359 : ELSE
360 : qs_ot_env(1)%ot_pos(count + 1) = &
361 : qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left) + &
362 : gold_sec*(qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
363 160 : - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left))
364 : END IF
365 : ! check for termination
366 : IF (((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_right) &
367 : - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) .LT. &
368 314 : qs_ot_env(1)%ds_min*qs_ot_env(1)%settings%gold_target) .AND. &
369 : ((qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid) &
370 : - qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_left)) .LT. &
371 : qs_ot_env(1)%ds_min*qs_ot_env(1)%settings%gold_target)) THEN
372 20 : qs_ot_env(1)%energy_only = .FALSE.
373 20 : qs_ot_env(1)%line_search_might_be_done = .TRUE.
374 : END IF
375 : END IF
376 : END IF
377 384 : ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
378 384 : qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
379 :
380 384 : CALL take_step(ds, qs_ot_env)
381 :
382 384 : CALL timestop(handle)
383 :
384 384 : END SUBROUTINE do_line_search_gold
385 :
386 : ! **************************************************************************************************
387 : !> \brief ...
388 : !> \param qs_ot_env ...
389 : ! **************************************************************************************************
390 1168 : SUBROUTINE do_line_search_3pnt(qs_ot_env)
391 :
392 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
393 :
394 : CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_3pnt'
395 :
396 : INTEGER :: count, handle
397 : REAL(KIND=dp) :: denom, ds, fa, fb, fc, nom, pos, val, &
398 : xa, xb, xc
399 :
400 1168 : CALL timeset(routineN, handle)
401 :
402 1168 : qs_ot_env(1)%line_search_might_be_done = .FALSE.
403 1168 : qs_ot_env(1)%energy_only = .TRUE.
404 :
405 : ! a three point interpolation based on the energy
406 1168 : qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
407 1168 : count = qs_ot_env(1)%line_search_count
408 1168 : qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
409 404 : SELECT CASE (count)
410 : CASE (1)
411 404 : qs_ot_env(1)%ot_pos(count) = 0.0_dp
412 404 : qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*0.8_dp
413 : CASE (2)
414 388 : IF (qs_ot_env(1)%OT_energy(count) .GT. qs_ot_env(1)%OT_energy(count - 1)) THEN
415 40 : qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*0.5_dp
416 : ELSE
417 348 : qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*1.4_dp
418 : END IF
419 : CASE (3)
420 376 : xa = qs_ot_env(1)%OT_pos(1)
421 376 : xb = qs_ot_env(1)%OT_pos(2)
422 376 : xc = qs_ot_env(1)%OT_pos(3)
423 376 : fa = qs_ot_env(1)%OT_energy(1)
424 376 : fb = qs_ot_env(1)%OT_energy(2)
425 376 : fc = qs_ot_env(1)%OT_energy(3)
426 376 : nom = (xb - xa)**2*(fb - fc) - (xb - xc)**2*(fb - fa)
427 376 : denom = (xb - xa)*(fb - fc) - (xb - xc)*(fb - fa)
428 376 : IF (ABS(denom) .LE. 1.0E-18_dp*MAX(ABS(fb - fc), ABS(fb - fa))) THEN
429 : pos = xb
430 : ELSE
431 376 : pos = xb - 0.5_dp*nom/denom ! position of the stationary point
432 : END IF
433 : val = (pos - xa)*(pos - xb)*fc/((xc - xa)*(xc - xb)) + &
434 : (pos - xb)*(pos - xc)*fa/((xa - xb)*(xa - xc)) + &
435 376 : (pos - xc)*(pos - xa)*fb/((xb - xc)*(xb - xa))
436 376 : IF (val .LT. fa .AND. val .LE. fb .AND. val .LE. fc) THEN ! OK, we go to a minimum
437 : ! we take a guard against too large steps
438 : qs_ot_env(1)%OT_pos(count + 1) = MAX(MAXVAL(qs_ot_env(1)%OT_pos(1:3))*0.01_dp, &
439 1880 : MIN(pos, MAXVAL(qs_ot_env(1)%OT_pos(1:3))*4.0_dp))
440 : ELSE ! just take an extended step
441 0 : qs_ot_env(1)%OT_pos(count + 1) = MAXVAL(qs_ot_env(1)%OT_pos(1:3))*2.0_dp
442 : END IF
443 376 : qs_ot_env(1)%energy_only = .FALSE.
444 376 : qs_ot_env(1)%line_search_might_be_done = .TRUE.
445 : CASE DEFAULT
446 1168 : CPABORT("NYI")
447 : END SELECT
448 1168 : ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
449 1168 : qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
450 :
451 1168 : CALL take_step(ds, qs_ot_env)
452 :
453 1168 : CALL timestop(handle)
454 :
455 1168 : END SUBROUTINE do_line_search_3pnt
456 :
457 : ! **************************************************************************************************
458 : !> \brief ...
459 : !> \param qs_ot_env ...
460 : ! **************************************************************************************************
461 34672 : SUBROUTINE do_line_search_2pnt(qs_ot_env)
462 :
463 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
464 :
465 : CHARACTER(len=*), PARAMETER :: routineN = 'do_line_search_2pnt'
466 :
467 : INTEGER :: count, handle
468 : REAL(KIND=dp) :: a, b, c, ds, pos, val, x0, x1
469 :
470 34672 : CALL timeset(routineN, handle)
471 :
472 34672 : qs_ot_env(1)%line_search_might_be_done = .FALSE.
473 34672 : qs_ot_env(1)%energy_only = .TRUE.
474 :
475 : ! a three point interpolation based on the energy
476 34672 : qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
477 34672 : count = qs_ot_env(1)%line_search_count
478 34672 : qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
479 18387 : SELECT CASE (count)
480 : CASE (1)
481 18387 : qs_ot_env(1)%ot_pos(count) = 0.0_dp
482 18387 : qs_ot_env(1)%ot_grad(count) = qs_ot_env(1)%gradient
483 18387 : qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*1.0_dp
484 : CASE (2)
485 16285 : x0 = 0.0_dp
486 16285 : c = qs_ot_env(1)%ot_energy(1)
487 16285 : b = qs_ot_env(1)%ot_grad(1)
488 16285 : x1 = qs_ot_env(1)%ot_pos(2)
489 16285 : a = (qs_ot_env(1)%ot_energy(2) - b*x1 - c)/(x1**2)
490 16285 : IF (a .LE. 0.0_dp) a = 1.0E-15_dp
491 16285 : pos = -b/(2.0_dp*a)
492 16285 : val = a*pos**2 + b*pos + c
493 16285 : qs_ot_env(1)%energy_only = .FALSE.
494 16285 : qs_ot_env(1)%line_search_might_be_done = .TRUE.
495 16285 : IF (val .LT. qs_ot_env(1)%ot_energy(1) .AND. val .LE. qs_ot_env(1)%ot_energy(2)) THEN
496 : ! we go to a minimum, but ...
497 : ! we take a guard against too large steps
498 : qs_ot_env(1)%OT_pos(count + 1) = MAX(MAXVAL(qs_ot_env(1)%OT_pos(1:2))*0.01_dp, &
499 65012 : MIN(pos, MAXVAL(qs_ot_env(1)%OT_pos(1:2))*4.0_dp))
500 : ELSE ! just take an extended step
501 128 : qs_ot_env(1)%OT_pos(count + 1) = MAXVAL(qs_ot_env(1)%OT_pos(1:2))*2.0_dp
502 : END IF
503 : CASE DEFAULT
504 34672 : CPABORT("NYI")
505 : END SELECT
506 34672 : ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
507 34672 : qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
508 :
509 34672 : CALL take_step(ds, qs_ot_env)
510 :
511 34672 : CALL timestop(handle)
512 :
513 34672 : END SUBROUTINE do_line_search_2pnt
514 :
515 : ! **************************************************************************************************
516 : !> \brief ...
517 : !> \param qs_ot_env ...
518 : ! **************************************************************************************************
519 10 : SUBROUTINE do_line_search_none(qs_ot_env)
520 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
521 :
522 10 : CALL take_step(qs_ot_env(1)%ds_min, qs_ot_env)
523 :
524 10 : END SUBROUTINE do_line_search_none
525 :
526 : !
527 : ! creates a new SD direction, using the preconditioner if associated
528 : ! also updates the gradient for line search
529 : !
530 :
531 : ! **************************************************************************************************
532 : !> \brief ...
533 : !> \param qs_ot_env ...
534 : ! **************************************************************************************************
535 24 : SUBROUTINE ot_new_sd_direction(qs_ot_env)
536 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
537 :
538 : CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_sd_direction'
539 :
540 : INTEGER :: handle, ispin, itmp, k, n, nener, nspin
541 : LOGICAL :: do_ener, do_ks
542 : REAL(KIND=dp) :: tmp
543 : TYPE(cp_logger_type), POINTER :: logger
544 :
545 24 : CALL timeset(routineN, handle)
546 :
547 : !***SCP
548 :
549 24 : nspin = SIZE(qs_ot_env)
550 24 : logger => cp_get_default_logger()
551 24 : do_ks = qs_ot_env(1)%settings%ks
552 24 : do_ener = qs_ot_env(1)%settings%do_ener
553 :
554 24 : IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
555 20 : IF (.NOT. qs_ot_env(1)%use_dx) CPABORT("use dx")
556 20 : qs_ot_env(1)%gnorm = 0.0_dp
557 20 : IF (do_ks) THEN
558 40 : DO ispin = 1, nspin
559 : CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
560 20 : qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx)
561 20 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
562 40 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
563 : END DO
564 20 : IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
565 0 : logger => cp_get_default_logger()
566 0 : WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
567 : END IF
568 40 : DO ispin = 1, nspin
569 40 : CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, -1.0_dp)
570 : END DO
571 20 : IF (qs_ot_env(1)%settings%do_rotation) THEN
572 0 : DO ispin = 1, nspin
573 : ! right now no preconditioner yet
574 0 : CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
575 0 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
576 : ! added 0.5, because we have (antisymmetry) only half the number of variables
577 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
578 : END DO
579 0 : DO ispin = 1, nspin
580 0 : CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, -1.0_dp)
581 : END DO
582 : END IF
583 : END IF
584 20 : IF (do_ener) THEN
585 0 : DO ispin = 1, nspin
586 0 : qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
587 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_dx, qs_ot_env(ispin)%ener_gx)
588 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
589 0 : qs_ot_env(ispin)%ener_dx = -qs_ot_env(ispin)%ener_dx
590 : END DO
591 : END IF
592 : ELSE
593 4 : qs_ot_env(1)%gnorm = 0.0_dp
594 4 : IF (do_ks) THEN
595 8 : DO ispin = 1, nspin
596 4 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
597 8 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
598 : END DO
599 4 : IF (qs_ot_env(1)%settings%do_rotation) THEN
600 0 : DO ispin = 1, nspin
601 0 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
602 : ! added 0.5, because we have (antisymmetry) only half the number of variables
603 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
604 : END DO
605 : END IF
606 : END IF
607 4 : IF (do_ener) THEN
608 0 : DO ispin = 1, nspin
609 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
610 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
611 : END DO
612 : END IF
613 : END IF
614 :
615 24 : k = 0
616 24 : n = 0
617 24 : nener = 0
618 24 : IF (do_ks) THEN
619 24 : CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
620 48 : DO ispin = 1, nspin
621 24 : CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
622 48 : k = k + itmp
623 : END DO
624 : END IF
625 24 : IF (do_ener) THEN
626 0 : DO ispin = 1, nspin
627 0 : nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
628 : END DO
629 : END IF
630 : ! Handling the case of no free variables to optimize
631 24 : IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener /= 0) THEN
632 22 : qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener))
633 22 : qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
634 : ELSE
635 2 : qs_ot_env(1)%delta = 0.0_dp
636 2 : qs_ot_env(1)%gradient = 0.0_dp
637 : END IF
638 :
639 24 : CALL timestop(handle)
640 :
641 24 : END SUBROUTINE ot_new_sd_direction
642 :
643 : !
644 : ! creates a new CG direction. Implements Polak-Ribierre variant
645 : ! using the preconditioner if associated
646 : ! also updates the gradient for line search
647 : !
648 : ! **************************************************************************************************
649 : !> \brief ...
650 : !> \param qs_ot_env ...
651 : ! **************************************************************************************************
652 18807 : SUBROUTINE ot_new_cg_direction(qs_ot_env)
653 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
654 :
655 : CHARACTER(len=*), PARAMETER :: routineN = 'ot_new_cg_direction'
656 :
657 : INTEGER :: handle, ispin, itmp, k, n, nener, nspin
658 : LOGICAL :: do_ener, do_ks
659 : REAL(KIND=dp) :: beta_pr, gnorm_cross, test_down, tmp
660 : TYPE(cp_logger_type), POINTER :: logger
661 :
662 18807 : CALL timeset(routineN, handle)
663 :
664 18807 : nspin = SIZE(qs_ot_env)
665 18807 : logger => cp_get_default_logger()
666 :
667 18807 : do_ks = qs_ot_env(1)%settings%ks
668 18807 : do_ener = qs_ot_env(1)%settings%do_ener
669 :
670 18807 : gnorm_cross = 0.0_dp
671 18807 : IF (do_ks) THEN
672 41437 : DO ispin = 1, nspin
673 22630 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
674 41437 : gnorm_cross = gnorm_cross + tmp
675 : END DO
676 18807 : IF (qs_ot_env(1)%settings%do_rotation) THEN
677 1992 : DO ispin = 1, nspin
678 1022 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
679 : ! added 0.5, because we have (antisymmetry) only half the number of variables
680 1992 : gnorm_cross = gnorm_cross + 0.5_dp*tmp
681 : END DO
682 : END IF
683 : END IF
684 18807 : IF (do_ener) THEN
685 0 : DO ispin = 1, nspin
686 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
687 0 : gnorm_cross = gnorm_cross + tmp
688 : END DO
689 : END IF
690 :
691 18807 : IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
692 :
693 28441 : DO ispin = 1, nspin
694 : CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
695 28441 : qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
696 : END DO
697 12549 : qs_ot_env(1)%gnorm = 0.0_dp
698 12549 : IF (do_ks) THEN
699 28441 : DO ispin = 1, nspin
700 15892 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
701 28441 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
702 : END DO
703 12549 : IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
704 0 : WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
705 : END IF
706 28441 : DO ispin = 1, nspin
707 28441 : CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
708 : END DO
709 12549 : IF (qs_ot_env(1)%settings%do_rotation) THEN
710 1944 : DO ispin = 1, nspin
711 : ! right now no preconditioner yet
712 998 : CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
713 998 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old, tmp)
714 : ! added 0.5, because we have (antisymmetry) only half the number of variables
715 1944 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
716 : END DO
717 1944 : DO ispin = 1, nspin
718 1944 : CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx_old)
719 : END DO
720 : END IF
721 : END IF
722 12549 : IF (do_ener) THEN
723 0 : DO ispin = 1, nspin
724 0 : qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
725 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
726 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
727 0 : qs_ot_env(ispin)%ener_gx = qs_ot_env(ispin)%ener_gx_old
728 : END DO
729 : END IF
730 : ELSE
731 6258 : IF (do_ks) THEN
732 6258 : qs_ot_env(1)%gnorm = 0.0_dp
733 12996 : DO ispin = 1, nspin
734 6738 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
735 6738 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
736 12996 : CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
737 : END DO
738 6258 : IF (qs_ot_env(1)%settings%do_rotation) THEN
739 48 : DO ispin = 1, nspin
740 24 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
741 : ! added 0.5, because we have (antisymmetry) only half the number of variables
742 24 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
743 48 : CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
744 : END DO
745 : END IF
746 : END IF
747 6258 : IF (do_ener) THEN
748 0 : DO ispin = 1, nspin
749 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
750 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
751 0 : qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
752 : END DO
753 : END IF
754 : END IF
755 :
756 18807 : k = 0
757 18807 : n = 0
758 18807 : nener = 0
759 18807 : IF (do_ks) THEN
760 18807 : CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
761 41437 : DO ispin = 1, nspin
762 22630 : CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
763 41437 : k = k + itmp
764 : END DO
765 : END IF
766 18807 : IF (do_ener) THEN
767 0 : DO ispin = 1, nspin
768 0 : nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
769 : END DO
770 : END IF
771 : ! Handling the case of no free variables to optimize
772 18807 : IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener /= 0) THEN
773 18673 : qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener))
774 18673 : beta_pr = (qs_ot_env(1)%gnorm - gnorm_cross)/qs_ot_env(1)%gnorm_old
775 : ELSE
776 134 : qs_ot_env(1)%delta = 0.0_dp
777 134 : beta_pr = 0.0_dp
778 : END IF
779 18807 : beta_pr = MAX(beta_pr, 0.0_dp) ! reset to SD
780 :
781 18807 : test_down = 0.0_dp
782 18807 : IF (do_ks) THEN
783 41437 : DO ispin = 1, nspin
784 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx, &
785 22630 : alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
786 22630 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
787 22630 : test_down = test_down + tmp
788 41437 : IF (qs_ot_env(1)%settings%do_rotation) THEN
789 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx, &
790 1022 : alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
791 1022 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
792 1022 : test_down = test_down + 0.5_dp*tmp
793 : END IF
794 : END DO
795 : END IF
796 18807 : IF (do_ener) THEN
797 0 : DO ispin = 1, nspin
798 0 : qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - qs_ot_env(ispin)%ener_gx
799 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
800 0 : test_down = test_down + tmp
801 : END DO
802 : END IF
803 :
804 18807 : IF (test_down .GE. 0.0_dp) THEN ! reset to SD
805 597 : beta_pr = 0.0_dp
806 597 : IF (do_ks) THEN
807 1353 : DO ispin = 1, nspin
808 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx, &
809 756 : alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
810 1353 : IF (qs_ot_env(1)%settings%do_rotation) THEN
811 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
812 10 : qs_ot_env(ispin)%rot_mat_gx, alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
813 : END IF
814 : END DO
815 : END IF
816 597 : IF (do_ener) THEN
817 0 : DO ispin = 1, nspin
818 0 : qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - qs_ot_env(ispin)%ener_gx
819 : END DO
820 : END IF
821 : END IF
822 : ! since we change the direction we have to adjust the gradient
823 18807 : qs_ot_env(1)%gradient = beta_pr*qs_ot_env(1)%gradient - qs_ot_env(1)%gnorm
824 18807 : qs_ot_env(1)%gnorm_old = qs_ot_env(1)%gnorm
825 :
826 18807 : CALL timestop(handle)
827 :
828 18807 : END SUBROUTINE ot_new_cg_direction
829 :
830 : ! **************************************************************************************************
831 : !> \brief ...
832 : !> \param qs_ot_env ...
833 : ! **************************************************************************************************
834 40406 : SUBROUTINE ot_diis_step(qs_ot_env)
835 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
836 :
837 : CHARACTER(len=*), PARAMETER :: routineN = 'ot_diis_step'
838 :
839 : INTEGER :: diis_bound, diis_m, handle, i, info, &
840 : ispin, itmp, j, k, n, nener, nspin
841 : LOGICAL :: do_ener, do_ks, do_ot_sd
842 : REAL(KIND=dp) :: overlap, tmp, tr_xnew_gx, tr_xold_gx
843 : TYPE(cp_logger_type), POINTER :: logger
844 :
845 40406 : CALL timeset(routineN, handle)
846 :
847 40406 : logger => cp_get_default_logger()
848 :
849 40406 : do_ks = qs_ot_env(1)%settings%ks
850 40406 : do_ener = qs_ot_env(1)%settings%do_ener
851 40406 : nspin = SIZE(qs_ot_env)
852 :
853 40406 : diis_m = qs_ot_env(1)%settings%diis_m
854 :
855 40406 : IF (qs_ot_env(1)%diis_iter .LT. diis_m) THEN
856 25356 : diis_bound = qs_ot_env(1)%diis_iter + 1
857 : ELSE
858 : diis_bound = diis_m
859 : END IF
860 :
861 40406 : j = MOD(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
862 :
863 : ! copy the position and the error vector in the diis buffers
864 :
865 40406 : IF (do_ks) THEN
866 83800 : DO ispin = 1, nspin
867 43394 : CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
868 83800 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
869 366 : CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, qs_ot_env(ispin)%rot_mat_x)
870 : END IF
871 : END DO
872 : END IF
873 40406 : IF (do_ener) THEN
874 0 : DO ispin = 1, nspin
875 0 : qs_ot_env(ispin)%ener_h_x(j, :) = qs_ot_env(ispin)%ener_x(:)
876 : END DO
877 : END IF
878 40406 : IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
879 35674 : qs_ot_env(1)%gnorm = 0.0_dp
880 35674 : IF (do_ks) THEN
881 74336 : DO ispin = 1, nspin
882 : CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
883 38662 : qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix)
884 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
885 38662 : tmp)
886 74336 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
887 : END DO
888 35674 : IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
889 0 : WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
890 : END IF
891 74336 : DO ispin = 1, nspin
892 74336 : CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(j)%matrix, -qs_ot_env(1)%ds_min)
893 : END DO
894 35674 : IF (qs_ot_env(1)%settings%do_rotation) THEN
895 732 : DO ispin = 1, nspin
896 366 : CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, qs_ot_env(ispin)%rot_mat_gx)
897 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
898 366 : tmp)
899 732 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
900 : END DO
901 732 : DO ispin = 1, nspin
902 732 : CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, -qs_ot_env(1)%ds_min)
903 : END DO
904 : END IF
905 : END IF
906 35674 : IF (do_ener) THEN
907 0 : DO ispin = 1, nspin
908 0 : qs_ot_env(ispin)%ener_h_e(j, :) = qs_ot_env(ispin)%ener_gx(:)
909 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(j, :), qs_ot_env(ispin)%ener_gx(:))
910 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
911 0 : qs_ot_env(ispin)%ener_h_e(j, :) = -qs_ot_env(1)%ds_min*qs_ot_env(ispin)%ener_h_e(j, :)
912 : END DO
913 : END IF
914 : ELSE
915 4732 : qs_ot_env(1)%gnorm = 0.0_dp
916 4732 : IF (do_ks) THEN
917 9464 : DO ispin = 1, nspin
918 4732 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
919 4732 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
920 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
921 9464 : qs_ot_env(ispin)%matrix_gx, alpha_scalar=0.0_dp, beta_scalar=-qs_ot_env(1)%ds_min)
922 : END DO
923 4732 : IF (qs_ot_env(1)%settings%do_rotation) THEN
924 0 : DO ispin = 1, nspin
925 0 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
926 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
927 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
928 0 : qs_ot_env(ispin)%rot_mat_gx, alpha_scalar=0.0_dp, beta_scalar=-qs_ot_env(1)%ds_min)
929 : END DO
930 : END IF
931 : END IF
932 4732 : IF (do_ener) THEN
933 0 : DO ispin = 1, nspin
934 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_gx(:))
935 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
936 0 : qs_ot_env(ispin)%ener_h_e(j, :) = -qs_ot_env(1)%ds_min*qs_ot_env(ispin)%ener_gx(:)
937 : END DO
938 : END IF
939 : END IF
940 40406 : k = 0
941 40406 : n = 0
942 40406 : nener = 0
943 40406 : IF (do_ks) THEN
944 40406 : CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
945 83800 : DO ispin = 1, nspin
946 43394 : CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
947 83800 : k = k + itmp
948 : END DO
949 : END IF
950 40406 : IF (do_ener) THEN
951 0 : DO ispin = 1, nspin
952 0 : nener = nener + SIZE(qs_ot_env(ispin)%ener_x)
953 : END DO
954 : END IF
955 : ! Handling the case of no free variables to optimize
956 40406 : IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener /= 0) THEN
957 40380 : qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8) + nener))
958 40380 : qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
959 : ELSE
960 26 : qs_ot_env(1)%delta = 0.0_dp
961 26 : qs_ot_env(1)%gradient = 0.0_dp
962 : END IF
963 :
964 : ! make the diis matrix and solve it
965 243885 : DO i = 1, diis_bound
966 : ! I think there are two possible options, with and without preconditioner
967 : ! as a metric
968 : ! the second option seems most logical to me, and it seems marginally faster
969 : ! in some of the tests
970 : IF (.FALSE.) THEN
971 : qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
972 : IF (do_ks) THEN
973 : DO ispin = 1, nspin
974 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
975 : qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
976 : tmp)
977 : qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
978 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
979 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
980 : qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
981 : tmp)
982 : qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + 0.5_dp*tmp
983 : END IF
984 : END DO
985 : END IF
986 : IF (do_ener) THEN
987 : DO ispin = 1, nspin
988 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_e(j, :), qs_ot_env(ispin)%ener_h_e(i, :))
989 : qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) + tmp
990 : END DO
991 : END IF
992 : ELSE
993 203479 : qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
994 203479 : IF (do_ks) THEN
995 423214 : DO ispin = 1, nspin
996 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
997 : qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
998 219735 : tmp)
999 219735 : qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
1000 423214 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1001 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, &
1002 : qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
1003 1976 : tmp)
1004 1976 : qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*0.5_dp*tmp
1005 : END IF
1006 : END DO
1007 : END IF
1008 203479 : IF (do_ener) THEN
1009 0 : DO ispin = 1, nspin
1010 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_h_e(i, :))
1011 0 : qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
1012 : END DO
1013 : END IF
1014 : END IF
1015 203479 : qs_ot_env(1)%ls_diis(j, i) = qs_ot_env(1)%ls_diis(i, j)
1016 203479 : qs_ot_env(1)%ls_diis(i, diis_bound + 1) = 1.0_dp
1017 203479 : qs_ot_env(1)%ls_diis(diis_bound + 1, i) = 1.0_dp
1018 243885 : qs_ot_env(1)%c_diis(i) = 0.0_dp
1019 : END DO
1020 40406 : qs_ot_env(1)%ls_diis(diis_bound + 1, diis_bound + 1) = 0.0_dp
1021 40406 : qs_ot_env(1)%c_diis(diis_bound + 1) = 1.0_dp
1022 : ! put in buffer, dgesv destroys
1023 3073138 : qs_ot_env(1)%lss_diis = qs_ot_env(1)%ls_diis
1024 :
1025 : CALL DGESV(diis_bound + 1, 1, qs_ot_env(1)%lss_diis, diis_m + 1, qs_ot_env(1)%ipivot, &
1026 40406 : qs_ot_env(1)%c_diis, diis_m + 1, info)
1027 :
1028 40406 : IF (info .NE. 0) THEN
1029 0 : do_ot_sd = .TRUE.
1030 0 : WRITE (cp_logger_get_default_unit_nr(logger), *) "Singular DIIS matrix"
1031 : ELSE
1032 40406 : do_ot_sd = .FALSE.
1033 40406 : IF (do_ks) THEN
1034 83800 : DO ispin = 1, nspin
1035 : ! OK, add the vectors now
1036 43394 : CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
1037 263129 : DO i = 1, diis_bound
1038 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1039 : qs_ot_env(ispin)%matrix_h_e(i)%matrix, &
1040 263129 : alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1041 : END DO
1042 263129 : DO i = 1, diis_bound
1043 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1044 : qs_ot_env(ispin)%matrix_h_x(i)%matrix, &
1045 263129 : alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1046 : END DO
1047 83800 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1048 366 : CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
1049 2342 : DO i = 1, diis_bound
1050 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
1051 : qs_ot_env(ispin)%rot_mat_h_e(i)%matrix, &
1052 2342 : alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1053 : END DO
1054 2342 : DO i = 1, diis_bound
1055 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
1056 : qs_ot_env(ispin)%rot_mat_h_x(i)%matrix, &
1057 2342 : alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1058 : END DO
1059 : END IF
1060 : END DO
1061 : END IF
1062 40406 : IF (do_ener) THEN
1063 0 : DO ispin = 1, nspin
1064 0 : qs_ot_env(ispin)%ener_x(:) = 0.0_dp
1065 0 : DO i = 1, diis_bound
1066 : qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
1067 0 : + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_e(i, :)
1068 : END DO
1069 0 : DO i = 1, diis_bound
1070 : qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
1071 0 : + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_x(i, :)
1072 : END DO
1073 : END DO
1074 : END IF
1075 40406 : qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
1076 40406 : IF (qs_ot_env(1)%settings%safer_diis) THEN
1077 : ! now, final check, is the step in fact in the direction of the -gradient ?
1078 : ! if not we're walking towards a sadle point, and should avoid that
1079 : ! the direction of the step is x_new-x_old
1080 40406 : tr_xold_gx = 0.0_dp
1081 40406 : tr_xnew_gx = 0.0_dp
1082 40406 : IF (do_ks) THEN
1083 83800 : DO ispin = 1, nspin
1084 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
1085 43394 : qs_ot_env(ispin)%matrix_gx, tmp)
1086 43394 : tr_xold_gx = tr_xold_gx + tmp
1087 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, &
1088 43394 : qs_ot_env(ispin)%matrix_gx, tmp)
1089 43394 : tr_xnew_gx = tr_xnew_gx + tmp
1090 83800 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1091 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
1092 366 : qs_ot_env(ispin)%rot_mat_gx, tmp)
1093 366 : tr_xold_gx = tr_xold_gx + 0.5_dp*tmp
1094 : CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_x, &
1095 366 : qs_ot_env(ispin)%rot_mat_gx, tmp)
1096 366 : tr_xnew_gx = tr_xnew_gx + 0.5_dp*tmp
1097 : END IF
1098 : END DO
1099 : END IF
1100 40406 : IF (do_ener) THEN
1101 0 : DO ispin = 1, nspin
1102 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_h_x(j, :), qs_ot_env(ispin)%ener_gx(:))
1103 0 : tr_xold_gx = tr_xold_gx + tmp
1104 0 : tmp = DOT_PRODUCT(qs_ot_env(ispin)%ener_x(:), qs_ot_env(ispin)%ener_gx(:))
1105 0 : tr_xnew_gx = tr_xnew_gx + tmp
1106 : END DO
1107 : END IF
1108 40406 : overlap = (tr_xnew_gx - tr_xold_gx)
1109 : ! OK, bad luck, take a SD step along the preconditioned gradient
1110 40406 : IF (overlap .GT. 0.0_dp) THEN
1111 : do_ot_sd = .TRUE.
1112 : END IF
1113 : END IF
1114 : END IF
1115 :
1116 : IF (do_ot_sd) THEN
1117 832 : qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
1118 832 : IF (do_ks) THEN
1119 1774 : DO ispin = 1, nspin
1120 942 : CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
1121 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1122 : qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
1123 942 : 1.0_dp, 1.0_dp)
1124 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1125 : qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
1126 942 : 1.0_dp, 1.0_dp)
1127 1774 : IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1128 28 : CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
1129 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
1130 : qs_ot_env(ispin)%rot_mat_h_e(j)%matrix, &
1131 28 : 1.0_dp, 1.0_dp)
1132 : CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_x, &
1133 : qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
1134 28 : 1.0_dp, 1.0_dp)
1135 : END IF
1136 : END DO
1137 : END IF
1138 832 : IF (do_ener) THEN
1139 0 : DO ispin = 1, nspin
1140 0 : qs_ot_env(ispin)%ener_x(:) = 0._dp
1141 0 : qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_e(j, :)
1142 0 : qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_x(j, :)
1143 : END DO
1144 : END IF
1145 : END IF
1146 :
1147 40406 : CALL timestop(handle)
1148 :
1149 40406 : END SUBROUTINE ot_diis_step
1150 :
1151 : ! **************************************************************************************************
1152 : !> \brief Energy minimizer by Broyden's method
1153 : !> \param qs_ot_env variable to control minimizer behaviour
1154 : !> \author Kurt Baarman (09.2010)
1155 : ! **************************************************************************************************
1156 176 : SUBROUTINE ot_broyden_step(qs_ot_env)
1157 : TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
1158 :
1159 : INTEGER :: diis_bound, diis_m, i, ispin, itmp, j, &
1160 : k, n, nspin
1161 176 : INTEGER, ALLOCATABLE, DIMENSION(:) :: circ_index
1162 : LOGICAL :: adaptive_sigma, do_ener, do_ks, &
1163 : enable_flip, forget_history
1164 : REAL(KIND=dp) :: beta, eta, gamma, omega, sigma, &
1165 : sigma_dec, sigma_min, tmp, tmp2
1166 176 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: f, x
1167 176 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: G, S
1168 : TYPE(cp_logger_type), POINTER :: logger
1169 :
1170 176 : eta = qs_ot_env(1)%settings%broyden_eta
1171 176 : omega = qs_ot_env(1)%settings%broyden_omega
1172 176 : sigma_dec = qs_ot_env(1)%settings%broyden_sigma_decrease
1173 176 : sigma_min = qs_ot_env(1)%settings%broyden_sigma_min
1174 176 : forget_history = qs_ot_env(1)%settings%broyden_forget_history
1175 176 : adaptive_sigma = qs_ot_env(1)%settings%broyden_adaptive_sigma
1176 176 : enable_flip = qs_ot_env(1)%settings%broyden_enable_flip
1177 :
1178 176 : do_ks = qs_ot_env(1)%settings%ks
1179 176 : do_ener = qs_ot_env(1)%settings%do_ener
1180 :
1181 176 : beta = qs_ot_env(1)%settings%broyden_beta
1182 176 : gamma = qs_ot_env(1)%settings%broyden_gamma
1183 176 : IF (adaptive_sigma) THEN
1184 176 : IF (qs_ot_env(1)%broyden_adaptive_sigma .LT. 0.0_dp) THEN
1185 6 : sigma = qs_ot_env(1)%settings%broyden_sigma
1186 : ELSE
1187 : sigma = qs_ot_env(1)%broyden_adaptive_sigma
1188 : END IF
1189 : ELSE
1190 0 : sigma = qs_ot_env(1)%settings%broyden_sigma
1191 : END IF
1192 :
1193 : ! simplify our life....
1194 176 : IF (do_ener .OR. .NOT. do_ks .OR. qs_ot_env(1)%settings%do_rotation) THEN
1195 0 : CPABORT("Not yet implemented")
1196 : END IF
1197 : !
1198 176 : nspin = SIZE(qs_ot_env)
1199 :
1200 176 : diis_m = qs_ot_env(1)%settings%diis_m
1201 :
1202 176 : IF (qs_ot_env(1)%diis_iter .LT. diis_m) THEN
1203 84 : diis_bound = qs_ot_env(1)%diis_iter + 1
1204 : ELSE
1205 92 : diis_bound = diis_m
1206 : END IF
1207 :
1208 : ! We want x:s, f:s and one random vector
1209 176 : k = 2*diis_bound + 1
1210 704 : ALLOCATE (S(k, k))
1211 528 : ALLOCATE (G(k, k))
1212 528 : ALLOCATE (f(k))
1213 352 : ALLOCATE (x(k))
1214 528 : ALLOCATE (circ_index(diis_bound))
1215 30400 : G = 0.0
1216 2272 : DO i = 1, k
1217 2272 : G(i, i) = sigma
1218 : END DO
1219 30400 : S = 0.0
1220 :
1221 176 : j = MOD(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
1222 :
1223 352 : DO ispin = 1, nspin
1224 352 : CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
1225 : END DO
1226 :
1227 176 : IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
1228 176 : qs_ot_env(1)%gnorm = 0.0_dp
1229 352 : DO ispin = 1, nspin
1230 : CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
1231 176 : qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix)
1232 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
1233 176 : tmp)
1234 352 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
1235 : END DO
1236 176 : IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
1237 0 : WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
1238 : END IF
1239 352 : DO ispin = 1, nspin
1240 352 : CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(j)%matrix, -1.0_dp)
1241 : END DO
1242 : ELSE
1243 0 : qs_ot_env(1)%gnorm = 0.0_dp
1244 0 : DO ispin = 1, nspin
1245 0 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
1246 0 : qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
1247 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_h_e(j)%matrix, &
1248 0 : qs_ot_env(ispin)%matrix_gx, alpha_scalar=0.0_dp, beta_scalar=-1.0_dp)
1249 : END DO
1250 : END IF
1251 :
1252 176 : k = 0
1253 : n = 0
1254 176 : CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
1255 352 : DO ispin = 1, nspin
1256 176 : CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
1257 352 : k = k + itmp
1258 : END DO
1259 :
1260 : ! Handling the case of no free variables to optimize
1261 176 : IF (INT(n, KIND=int_8)*INT(k, KIND=int_8) /= 0) THEN
1262 176 : qs_ot_env(1)%delta = SQRT(ABS(qs_ot_env(1)%gnorm)/(INT(n, KIND=int_8)*INT(k, KIND=int_8)))
1263 176 : qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
1264 : ELSE
1265 0 : qs_ot_env(1)%delta = 0.0_dp
1266 0 : qs_ot_env(1)%gradient = 0.0_dp
1267 : END IF
1268 :
1269 176 : IF (diis_bound == diis_m) THEN
1270 816 : DO i = 1, diis_bound
1271 816 : circ_index(i) = MOD(j + i - 1, diis_m) + 1
1272 : END DO
1273 : ELSE
1274 320 : DO i = 1, diis_bound
1275 320 : circ_index(i) = i
1276 : END DO
1277 : END IF
1278 :
1279 30400 : S = 0.0_dp
1280 352 : DO ispin = 1, nspin
1281 176 : CALL dbcsr_init_random(qs_ot_env(ispin)%matrix_x)
1282 1136 : DO i = 1, diis_bound
1283 : CALL dbcsr_dot( &
1284 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1285 960 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, tmp)
1286 960 : S(i, i) = S(i, i) + tmp
1287 : CALL dbcsr_dot( &
1288 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1289 960 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, tmp)
1290 960 : S(i + diis_bound, i + diis_bound) = S(i + diis_bound, i + diis_bound) + tmp
1291 : CALL dbcsr_dot( &
1292 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1293 960 : qs_ot_env(ispin)%matrix_x, tmp)
1294 960 : S(i, 2*diis_bound + 1) = S(i, 2*diis_bound + 1) + tmp
1295 960 : S(i, 2*diis_bound + 1) = S(2*diis_bound + 1, i)
1296 : CALL dbcsr_dot( &
1297 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1298 960 : qs_ot_env(ispin)%matrix_x, tmp)
1299 960 : S(i + diis_bound, 2*diis_bound + 1) = S(i + diis_bound, 2*diis_bound + 1) + tmp
1300 960 : S(i + diis_bound, 2*diis_bound + 1) = S(2*diis_bound + 1, diis_bound + i)
1301 3494 : DO k = (i + 1), diis_bound
1302 : CALL dbcsr_dot( &
1303 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1304 : qs_ot_env(ispin)%matrix_h_x(circ_index(k))%matrix, &
1305 2534 : tmp)
1306 2534 : S(i, k) = S(i, k) + tmp
1307 2534 : S(k, i) = S(i, k)
1308 : CALL dbcsr_dot( &
1309 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1310 : qs_ot_env(ispin)%matrix_h_e(circ_index(k))%matrix, &
1311 2534 : tmp)
1312 2534 : S(diis_bound + i, diis_bound + k) = S(diis_bound + i, diis_bound + k) + tmp
1313 3494 : S(diis_bound + k, diis_bound + i) = S(diis_bound + i, diis_bound + k)
1314 : END DO
1315 7164 : DO k = 1, diis_bound
1316 : CALL dbcsr_dot( &
1317 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1318 6028 : qs_ot_env(ispin)%matrix_h_e(circ_index(k))%matrix, tmp)
1319 6028 : S(i, k + diis_bound) = S(i, k + diis_bound) + tmp
1320 6988 : S(k + diis_bound, i) = S(i, k + diis_bound)
1321 : END DO
1322 : END DO
1323 176 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_x, tmp)
1324 352 : S(2*diis_bound + 1, 2*diis_bound + 1) = S(2*diis_bound + 1, 2*diis_bound + 1) + tmp
1325 : END DO
1326 :
1327 : ! normalize
1328 176 : k = 2*diis_bound + 1
1329 176 : tmp = SQRT(S(k, k))
1330 2272 : S(k, :) = S(k, :)/tmp
1331 2272 : S(:, k) = S(:, k)/tmp
1332 :
1333 176 : IF (diis_bound .GT. 1) THEN
1334 162 : tmp = 0.0_dp
1335 162 : tmp2 = 0.0_dp
1336 162 : i = diis_bound
1337 324 : DO ispin = 1, nspin
1338 : ! dot product of differences
1339 : CALL dbcsr_dot( &
1340 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1341 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1342 162 : tmp)
1343 162 : tmp2 = tmp2 + tmp
1344 : CALL dbcsr_dot( &
1345 : qs_ot_env(ispin)%matrix_h_x(circ_index(i - 1))%matrix, &
1346 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1347 162 : tmp)
1348 162 : tmp2 = tmp2 - tmp
1349 : CALL dbcsr_dot( &
1350 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1351 : qs_ot_env(ispin)%matrix_h_e(circ_index(i - 1))%matrix, &
1352 162 : tmp)
1353 162 : tmp2 = tmp2 - tmp
1354 : CALL dbcsr_dot( &
1355 : qs_ot_env(ispin)%matrix_h_x(circ_index(i - 1))%matrix, &
1356 : qs_ot_env(ispin)%matrix_h_e(circ_index(i - 1))%matrix, &
1357 162 : tmp)
1358 324 : tmp2 = tmp2 + tmp
1359 : END DO
1360 162 : qs_ot_env(1)%c_broy(i - 1) = tmp2
1361 : END IF
1362 :
1363 176 : qs_ot_env(1)%energy_h(j) = qs_ot_env(1)%etotal
1364 :
1365 : ! If we went uphill, do backtracking line search
1366 1136 : i = MINLOC(qs_ot_env(1)%energy_h(1:diis_bound), dim=1)
1367 176 : IF (i .NE. j) THEN
1368 26 : sigma = sigma_dec*sigma
1369 26 : qs_ot_env(1)%OT_METHOD_FULL = "OT BTRK"
1370 52 : DO ispin = 1, nspin
1371 26 : CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
1372 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1373 : qs_ot_env(ispin)%matrix_h_x(i)%matrix, &
1374 26 : alpha_scalar=1.0_dp, beta_scalar=(1.0_dp - gamma))
1375 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1376 : qs_ot_env(ispin)%matrix_h_x(circ_index(diis_bound))%matrix, &
1377 52 : alpha_scalar=1.0_dp, beta_scalar=gamma)
1378 : END DO
1379 : ELSE
1380 : ! Construct G
1381 778 : DO i = 2, diis_bound
1382 9208 : f = 0.0
1383 9208 : x = 0.0
1384 : ! f is df_i
1385 628 : x(i) = 1.0
1386 628 : x(i - 1) = -1.0
1387 : ! x is dx_i
1388 628 : f(diis_bound + i) = 1.0
1389 628 : f(diis_bound + i - 1) = -1.0
1390 628 : tmp = 1.0_dp
1391 : ! We want a pos def Hessian
1392 628 : IF (enable_flip) THEN
1393 628 : IF (qs_ot_env(1)%c_broy(i - 1) .GT. 0) THEN
1394 : !qs_ot_env(1)%OT_METHOD_FULL="OT FLIP"
1395 2 : tmp = -1.0_dp
1396 : END IF
1397 : END IF
1398 :
1399 : ! get dx-Gdf
1400 391524 : x(:) = tmp*x - MATMUL(G, f)
1401 : ! dfSdf
1402 : ! we calculate matmul(S, f) twice. They're small...
1403 391524 : tmp = DOT_PRODUCT(f, MATMUL(S, f))
1404 : ! NOTE THAT S IS SYMMETRIC !!!
1405 391524 : f(:) = MATMUL(S, f)/tmp
1406 : ! the spread is an outer vector product
1407 130658 : G(:, :) = G + SPREAD(x, dim=2, ncopies=SIZE(f))*SPREAD(f, dim=1, ncopies=SIZE(x))
1408 : END DO
1409 1856 : f = 0.0_dp
1410 150 : f(2*diis_bound) = 1.0_dp
1411 94380 : x(:) = -beta*MATMUL(G, f)
1412 :
1413 : ! OK, add the vectors now, this sums up to the proposed step
1414 300 : DO ispin = 1, nspin
1415 150 : CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
1416 928 : DO i = 1, diis_bound
1417 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1418 : qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1419 928 : alpha_scalar=1.0_dp, beta_scalar=-x(i + diis_bound))
1420 : END DO
1421 1078 : DO i = 1, diis_bound
1422 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1423 : qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1424 928 : alpha_scalar=1.0_dp, beta_scalar=x(i))
1425 : END DO
1426 : END DO
1427 :
1428 150 : IF (adaptive_sigma) THEN
1429 150 : tmp = new_sigma(G, S, diis_bound)
1430 : !tmp = tmp * qs_ot_env ( 1 ) % settings % broyden_sigma
1431 150 : tmp = tmp*eta
1432 150 : sigma = MIN(omega*sigma, tmp)
1433 : END IF
1434 :
1435 : ! compute the inner product of direction of the step and gradient
1436 150 : tmp = 0.0_dp
1437 300 : DO ispin = 1, nspin
1438 : CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
1439 : qs_ot_env(ispin)%matrix_x, &
1440 150 : tmp2)
1441 300 : tmp = tmp + tmp2
1442 : END DO
1443 :
1444 300 : DO ispin = 1, nspin
1445 : ! if the direction of the step is not in direction of the gradient,
1446 : ! change step sign
1447 300 : IF (tmp .GE. 0.0_dp) THEN
1448 8 : qs_ot_env(1)%OT_METHOD_FULL = "OT TURN"
1449 8 : IF (forget_history) THEN
1450 0 : qs_ot_env(1)%diis_iter = 0
1451 : END IF
1452 8 : sigma = sigma*sigma_dec
1453 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1454 : qs_ot_env(ispin)%matrix_h_x(circ_index(diis_bound))%matrix, &
1455 8 : alpha_scalar=-1.0_dp, beta_scalar=1.0_dp)
1456 : ELSE
1457 : CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, &
1458 : qs_ot_env(ispin)%matrix_h_x(circ_index(diis_bound))%matrix, &
1459 142 : alpha_scalar=1.0_dp, beta_scalar=1.0_dp)
1460 : END IF
1461 : END DO
1462 : END IF
1463 :
1464 : ! get rid of S, G, f, x, circ_index for next round
1465 176 : DEALLOCATE (S, G, f, x, circ_index)
1466 :
1467 : ! update for next round
1468 176 : qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
1469 176 : qs_ot_env(1)%broyden_adaptive_sigma = MAX(sigma, sigma_min)
1470 :
1471 352 : END SUBROUTINE ot_broyden_step
1472 :
1473 : ! **************************************************************************************************
1474 : !> \brief ...
1475 : !> \param G ...
1476 : !> \param S ...
1477 : !> \param n ...
1478 : !> \return ...
1479 : ! **************************************************************************************************
1480 150 : FUNCTION new_sigma(G, S, n) RESULT(sigma)
1481 : !
1482 : ! Calculate new sigma from eigenvalues of full size G by Arnoldi.
1483 : !
1484 : ! **************************************************************************************************
1485 :
1486 : REAL(KIND=dp), DIMENSION(:, :) :: G, S
1487 : INTEGER :: n
1488 : REAL(KIND=dp) :: sigma
1489 :
1490 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigv
1491 150 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: H
1492 :
1493 600 : ALLOCATE (H(n, n))
1494 150 : CALL hess_G(G, S, H, n)
1495 450 : ALLOCATE (eigv(n))
1496 150 : CALL diamat_all(H(1:n, 1:n), eigv)
1497 :
1498 : SELECT CASE (1)
1499 : CASE (1)
1500 : ! This estimator seems to work well. No theory.
1501 1836 : sigma = SUM(ABS(eigv**2))/SUM(ABS(eigv))
1502 : CASE (2)
1503 : ! Estimator based on Frobenius norm minimizer
1504 : sigma = SUM(ABS(eigv))/MAX(1, SIZE(eigv))
1505 : CASE (3)
1506 : ! Estimator based on induced 2-norm
1507 : sigma = (MAXVAL(ABS(eigv)) + MINVAL(ABS(eigv)))*0.5_dp
1508 : END SELECT
1509 :
1510 150 : DEALLOCATE (H, eigv)
1511 150 : END FUNCTION new_sigma
1512 :
1513 : ! **************************************************************************************************
1514 : !> \brief ...
1515 : !> \param G ...
1516 : !> \param S ...
1517 : !> \param H ...
1518 : !> \param n ...
1519 : ! **************************************************************************************************
1520 150 : SUBROUTINE hess_G(G, S, H, n)
1521 : !
1522 : ! Make a hessenberg out of G into H. Cf Arnoldi.
1523 : ! Inner product is weighted by S.
1524 : ! Possible lucky breakdown at n.
1525 : !
1526 : ! **************************************************************************************************
1527 : REAL(KIND=dp), DIMENSION(:, :) :: G, S, H
1528 : INTEGER :: n
1529 :
1530 : INTEGER :: i, j, k
1531 : REAL(KIND=dp) :: tmp
1532 150 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: v
1533 150 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: Q
1534 :
1535 150 : i = SIZE(G, 1)
1536 150 : k = SIZE(H, 1)
1537 600 : ALLOCATE (Q(i, k))
1538 450 : ALLOCATE (v(i))
1539 5682 : H = 0.0_dp
1540 11214 : Q = 0.0_dp
1541 :
1542 1856 : Q(:, 1) = 1.0_dp
1543 27846 : tmp = SQRT(DOT_PRODUCT(Q(:, 1), MATMUL(S, Q(:, 1))))
1544 11214 : Q(:, :) = Q(:, :)/tmp
1545 :
1546 914 : DO i = 1, k
1547 162368 : v(:) = MATMUL(G, Q(:, i))
1548 3476 : DO j = 1, i
1549 658356 : H(j, i) = DOT_PRODUCT(Q(:, j), MATMUL(S, v))
1550 41072 : v(:) = v - H(j, i)*Q(:, j)
1551 : END DO
1552 914 : IF (i .LT. k) THEN
1553 147286 : tmp = DOT_PRODUCT(v, MATMUL(S, v))
1554 622 : IF (tmp .LE. 0.0_dp) THEN
1555 0 : n = i
1556 0 : EXIT
1557 : END IF
1558 622 : tmp = SQRT(tmp)
1559 : ! Lucky breakdown
1560 622 : IF (ABS(tmp) .LT. 1e-9_dp) THEN
1561 4 : n = i
1562 4 : EXIT
1563 : END IF
1564 618 : H(i + 1, i) = tmp
1565 9048 : Q(:, i + 1) = v/H(i + 1, i)
1566 : END IF
1567 : END DO
1568 :
1569 150 : DEALLOCATE (Q, v)
1570 150 : END SUBROUTINE hess_G
1571 :
1572 5364 : END MODULE qs_ot_minimizer
|