(git:374b731)
Loading...
Searching...
No Matches
qs_ot_minimizer.F
Go to the documentation of this file.
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! **************************************************************************************************
15
19 USE dbcsr_api, ONLY: dbcsr_add,&
20 dbcsr_copy,&
21 dbcsr_dot,&
22 dbcsr_get_info,&
23 dbcsr_init_random,&
24 dbcsr_p_type,&
25 dbcsr_scale,&
26 dbcsr_set
27 USE kinds, ONLY: dp,&
28 int_8
29 USE mathlib, ONLY: diamat_all
31 USE qs_ot, ONLY: qs_ot_get_derivative,&
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
44CONTAINS
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 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 CALL timeset(routinen, handle)
73
74 nspin = SIZE(qs_ot_env)
75
76 do_ks = qs_ot_env(1)%settings%ks
77 do_ener = qs_ot_env(1)%settings%do_ener
78
79 qs_ot_env(1)%OT_METHOD_FULL = ""
80
81 ! compute the gradient for the variables x
82 IF (.NOT. qs_ot_env(1)%energy_only) THEN
83 qs_ot_env(1)%gradient = 0.0_dp
84 DO ispin = 1, nspin
85 IF (do_ks) THEN
86 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 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 qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin))
95 CASE DEFAULT
96 cpabort("ALGORITHM NYI")
97 END SELECT
98 END IF
99 ! and also the gradient along the direction
100 IF (qs_ot_env(1)%use_dx) THEN
101 IF (do_ks) THEN
102 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
103 qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
104 IF (qs_ot_env(1)%settings%do_rotation) THEN
105 CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
106 qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + 0.5_dp*tmp
107 END IF
108 END IF
109 IF (do_ener) THEN
110 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
111 qs_ot_env(1)%gradient = qs_ot_env(1)%gradient + tmp
112 END IF
113 ELSE
114 IF (do_ks) THEN
115 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
116 qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - tmp
117 IF (qs_ot_env(1)%settings%do_rotation) THEN
118 CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
119 qs_ot_env(1)%gradient = qs_ot_env(1)%gradient - 0.5_dp*tmp
120 END IF
121 END IF
122 IF (do_ener) THEN
123 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
124 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 SELECT CASE (qs_ot_env(1)%settings%OT_METHOD)
131 CASE ("CG")
132 IF (current_point_is_fine(qs_ot_env)) THEN
133 qs_ot_env(1)%OT_METHOD_FULL = "OT CG"
134 CALL ot_new_cg_direction(qs_ot_env)
135 qs_ot_env(1)%line_search_count = 0
136 ELSE
137 qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
138 END IF
139 CALL do_line_search(qs_ot_env)
140 CASE ("SD")
141 IF (current_point_is_fine(qs_ot_env)) THEN
142 qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
143 CALL ot_new_sd_direction(qs_ot_env)
144 qs_ot_env(1)%line_search_count = 0
145 ELSE
146 qs_ot_env(1)%OT_METHOD_FULL = "OT LS"
147 END IF
148 CALL do_line_search(qs_ot_env)
149 CASE ("DIIS")
150 qs_ot_env(1)%OT_METHOD_FULL = "OT DIIS"
151 CALL ot_diis_step(qs_ot_env)
152 CASE ("BROY")
153 qs_ot_env(1)%OT_METHOD_FULL = "OT BROY"
154 CALL ot_broyden_step(qs_ot_env)
155 CASE DEFAULT
156 cpabort("OT_METHOD NYI")
157 END SELECT
158
159 CALL timestop(handle)
160
161 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 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 res = .false.
177
178 ! only if we have a gradient it can be fine
179 IF (.NOT. qs_ot_env(1)%energy_only) THEN
180
181 ! we have not yet started with the line search
182 IF (qs_ot_env(1)%line_search_count .EQ. 0) THEN
183 res = .true.
184 RETURN
185 END IF
186
187 IF (qs_ot_env(1)%line_search_might_be_done) THEN
188 ! here we put the more complicated logic later
189 res = .true.
190 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 SUBROUTINE do_line_search(qs_ot_env)
205 TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
206
207 SELECT CASE (qs_ot_env(1)%settings%line_search_method)
208 CASE ("GOLD")
209 CALL do_line_search_gold(qs_ot_env)
210 CASE ("3PNT")
211 CALL do_line_search_3pnt(qs_ot_env)
212 CASE ("2PNT")
213 CALL do_line_search_2pnt(qs_ot_env)
214 CASE ("NONE")
215 CALL do_line_search_none(qs_ot_env)
216 CASE DEFAULT
217 cpabort("NYI")
218 END SELECT
219 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 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 CALL timeset(routinen, handle)
238
239 nspin = SIZE(qs_ot_env)
240
241 do_ks = qs_ot_env(1)%settings%ks
242 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 IF (qs_ot_env(1)%use_dx) THEN
247 IF (do_ks) THEN
248 DO ispin = 1, nspin
249 CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_dx, &
250 alpha_scalar=1.0_dp, beta_scalar=ds)
251 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 alpha_scalar=1.0_dp, beta_scalar=ds)
254 END IF
255 END DO
256 END IF
257 IF (do_ener) THEN
258 DO ispin = 1, nspin
259 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 IF (do_ks) THEN
264 DO ispin = 1, nspin
265 CALL dbcsr_add(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_gx, &
266 alpha_scalar=1.0_dp, beta_scalar=-ds)
267 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 alpha_scalar=1.0_dp, beta_scalar=-ds)
270 END IF
271 END DO
272 END IF
273 IF (do_ener) THEN
274 DO ispin = 1, nspin
275 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 CALL timestop(handle)
280 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 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 CALL timeset(routinen, handle)
298
299 qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
300 count = qs_ot_env(1)%line_search_count
301 qs_ot_env(1)%line_search_might_be_done = .false.
302 qs_ot_env(1)%energy_only = .true.
303
304 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 cpabort("MAX ITER EXCEEDED : FATAL")
308 END IF
309
310 IF (qs_ot_env(1)%line_search_count .EQ. 1) THEN
311 qs_ot_env(1)%line_search_left = 1
312 qs_ot_env(1)%line_search_right = 0
313 qs_ot_env(1)%line_search_mid = 1
314 qs_ot_env(1)%ot_pos(1) = 0.0_dp
315 qs_ot_env(1)%ot_energy(1) = qs_ot_env(1)%etotal
316 qs_ot_env(1)%ot_pos(2) = qs_ot_env(1)%ds_min/gold_sec
317 ELSE
318 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 IF (qs_ot_env(1)%line_search_right .EQ. 0) THEN ! we do not yet have the right bracket
323 IF (qs_ot_env(1)%ot_energy(count - 1) .LT. qs_ot_env(1)%ot_energy(count)) THEN
324 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 qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid))*gold_sec
328 ELSE
329 qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
330 qs_ot_env(1)%line_search_mid = count
331 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 IF (qs_ot_env(1)%ot_pos(count) .LT. qs_ot_env(1)%ot_pos(qs_ot_env(1)%line_search_mid)) THEN
336 IF (qs_ot_env(1)%ot_energy(count) .LT. qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
337 qs_ot_env(1)%line_search_right = qs_ot_env(1)%line_search_mid
338 qs_ot_env(1)%line_search_mid = count
339 ELSE
340 qs_ot_env(1)%line_search_left = count
341 END IF
342 ELSE
343 IF (qs_ot_env(1)%ot_energy(count) .LT. qs_ot_env(1)%ot_energy(qs_ot_env(1)%line_search_mid)) THEN
344 qs_ot_env(1)%line_search_left = qs_ot_env(1)%line_search_mid
345 qs_ot_env(1)%line_search_mid = count
346 ELSE
347 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 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 - 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 - 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 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 qs_ot_env(1)%energy_only = .false.
373 qs_ot_env(1)%line_search_might_be_done = .true.
374 END IF
375 END IF
376 END IF
377 ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
378 qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
379
380 CALL take_step(ds, qs_ot_env)
381
382 CALL timestop(handle)
383
384 END SUBROUTINE do_line_search_gold
385
386! **************************************************************************************************
387!> \brief ...
388!> \param qs_ot_env ...
389! **************************************************************************************************
390 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 CALL timeset(routinen, handle)
401
402 qs_ot_env(1)%line_search_might_be_done = .false.
403 qs_ot_env(1)%energy_only = .true.
404
405 ! a three point interpolation based on the energy
406 qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
407 count = qs_ot_env(1)%line_search_count
408 qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
409 SELECT CASE (count)
410 CASE (1)
411 qs_ot_env(1)%ot_pos(count) = 0.0_dp
412 qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*0.8_dp
413 CASE (2)
414 IF (qs_ot_env(1)%OT_energy(count) .GT. qs_ot_env(1)%OT_energy(count - 1)) THEN
415 qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*0.5_dp
416 ELSE
417 qs_ot_env(1)%OT_pos(count + 1) = qs_ot_env(1)%ds_min*1.4_dp
418 END IF
419 CASE (3)
420 xa = qs_ot_env(1)%OT_pos(1)
421 xb = qs_ot_env(1)%OT_pos(2)
422 xc = qs_ot_env(1)%OT_pos(3)
423 fa = qs_ot_env(1)%OT_energy(1)
424 fb = qs_ot_env(1)%OT_energy(2)
425 fc = qs_ot_env(1)%OT_energy(3)
426 nom = (xb - xa)**2*(fb - fc) - (xb - xc)**2*(fb - fa)
427 denom = (xb - xa)*(fb - fc) - (xb - xc)*(fb - fa)
428 IF (abs(denom) .LE. 1.0e-18_dp*max(abs(fb - fc), abs(fb - fa))) THEN
429 pos = xb
430 ELSE
431 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 (pos - xc)*(pos - xa)*fb/((xb - xc)*(xb - xa))
436 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 min(pos, maxval(qs_ot_env(1)%OT_pos(1:3))*4.0_dp))
440 ELSE ! just take an extended step
441 qs_ot_env(1)%OT_pos(count + 1) = maxval(qs_ot_env(1)%OT_pos(1:3))*2.0_dp
442 END IF
443 qs_ot_env(1)%energy_only = .false.
444 qs_ot_env(1)%line_search_might_be_done = .true.
445 CASE DEFAULT
446 cpabort("NYI")
447 END SELECT
448 ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
449 qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
450
451 CALL take_step(ds, qs_ot_env)
452
453 CALL timestop(handle)
454
455 END SUBROUTINE do_line_search_3pnt
456
457! **************************************************************************************************
458!> \brief ...
459!> \param qs_ot_env ...
460! **************************************************************************************************
461 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 CALL timeset(routinen, handle)
471
472 qs_ot_env(1)%line_search_might_be_done = .false.
473 qs_ot_env(1)%energy_only = .true.
474
475 ! a three point interpolation based on the energy
476 qs_ot_env(1)%line_search_count = qs_ot_env(1)%line_search_count + 1
477 count = qs_ot_env(1)%line_search_count
478 qs_ot_env(1)%ot_energy(count) = qs_ot_env(1)%etotal
479 SELECT CASE (count)
480 CASE (1)
481 qs_ot_env(1)%ot_pos(count) = 0.0_dp
482 qs_ot_env(1)%ot_grad(count) = qs_ot_env(1)%gradient
483 qs_ot_env(1)%ot_pos(count + 1) = qs_ot_env(1)%ds_min*1.0_dp
484 CASE (2)
485 x0 = 0.0_dp
486 c = qs_ot_env(1)%ot_energy(1)
487 b = qs_ot_env(1)%ot_grad(1)
488 x1 = qs_ot_env(1)%ot_pos(2)
489 a = (qs_ot_env(1)%ot_energy(2) - b*x1 - c)/(x1**2)
490 IF (a .LE. 0.0_dp) a = 1.0e-15_dp
491 pos = -b/(2.0_dp*a)
492 val = a*pos**2 + b*pos + c
493 qs_ot_env(1)%energy_only = .false.
494 qs_ot_env(1)%line_search_might_be_done = .true.
495 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 min(pos, maxval(qs_ot_env(1)%OT_pos(1:2))*4.0_dp))
500 ELSE ! just take an extended step
501 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 cpabort("NYI")
505 END SELECT
506 ds = qs_ot_env(1)%OT_pos(count + 1) - qs_ot_env(1)%OT_pos(count)
507 qs_ot_env(1)%ds_min = qs_ot_env(1)%OT_pos(count + 1)
508
509 CALL take_step(ds, qs_ot_env)
510
511 CALL timestop(handle)
512
513 END SUBROUTINE do_line_search_2pnt
514
515! **************************************************************************************************
516!> \brief ...
517!> \param qs_ot_env ...
518! **************************************************************************************************
519 SUBROUTINE do_line_search_none(qs_ot_env)
520 TYPE(qs_ot_type), DIMENSION(:), POINTER :: qs_ot_env
521
522 CALL take_step(qs_ot_env(1)%ds_min, qs_ot_env)
523
524 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 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 CALL timeset(routinen, handle)
546
547!***SCP
548
549 nspin = SIZE(qs_ot_env)
550 logger => cp_get_default_logger()
551 do_ks = qs_ot_env(1)%settings%ks
552 do_ener = qs_ot_env(1)%settings%do_ener
553
554 IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
555 IF (.NOT. qs_ot_env(1)%use_dx) cpabort("use dx")
556 qs_ot_env(1)%gnorm = 0.0_dp
557 IF (do_ks) THEN
558 DO ispin = 1, nspin
559 CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
560 qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx)
561 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
562 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
563 END DO
564 IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
565 logger => cp_get_default_logger()
566 WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
567 END IF
568 DO ispin = 1, nspin
569 CALL dbcsr_scale(qs_ot_env(ispin)%matrix_dx, -1.0_dp)
570 END DO
571 IF (qs_ot_env(1)%settings%do_rotation) THEN
572 DO ispin = 1, nspin
573 ! right now no preconditioner yet
574 CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_dx, qs_ot_env(ispin)%rot_mat_gx)
575 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 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
578 END DO
579 DO ispin = 1, nspin
580 CALL dbcsr_scale(qs_ot_env(ispin)%rot_mat_dx, -1.0_dp)
581 END DO
582 END IF
583 END IF
584 IF (do_ener) THEN
585 DO ispin = 1, nspin
586 qs_ot_env(ispin)%ener_dx = qs_ot_env(ispin)%ener_gx
587 tmp = dot_product(qs_ot_env(ispin)%ener_dx, qs_ot_env(ispin)%ener_gx)
588 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
589 qs_ot_env(ispin)%ener_dx = -qs_ot_env(ispin)%ener_dx
590 END DO
591 END IF
592 ELSE
593 qs_ot_env(1)%gnorm = 0.0_dp
594 IF (do_ks) THEN
595 DO ispin = 1, nspin
596 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
597 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
598 END DO
599 IF (qs_ot_env(1)%settings%do_rotation) THEN
600 DO ispin = 1, nspin
601 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 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
604 END DO
605 END IF
606 END IF
607 IF (do_ener) THEN
608 DO ispin = 1, nspin
609 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
610 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
611 END DO
612 END IF
613 END IF
614
615 k = 0
616 n = 0
617 nener = 0
618 IF (do_ks) THEN
619 CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
620 DO ispin = 1, nspin
621 CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
622 k = k + itmp
623 END DO
624 END IF
625 IF (do_ener) THEN
626 DO ispin = 1, nspin
627 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 IF (int(n, kind=int_8)*int(k, kind=int_8) + nener /= 0) THEN
632 qs_ot_env(1)%delta = sqrt(abs(qs_ot_env(1)%gnorm)/(int(n, kind=int_8)*int(k, kind=int_8) + nener))
633 qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
634 ELSE
635 qs_ot_env(1)%delta = 0.0_dp
636 qs_ot_env(1)%gradient = 0.0_dp
637 END IF
638
639 CALL timestop(handle)
640
641 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 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 CALL timeset(routinen, handle)
663
664 nspin = SIZE(qs_ot_env)
665 logger => cp_get_default_logger()
666
667 do_ks = qs_ot_env(1)%settings%ks
668 do_ener = qs_ot_env(1)%settings%do_ener
669
670 gnorm_cross = 0.0_dp
671 IF (do_ks) THEN
672 DO ispin = 1, nspin
673 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
674 gnorm_cross = gnorm_cross + tmp
675 END DO
676 IF (qs_ot_env(1)%settings%do_rotation) THEN
677 DO ispin = 1, nspin
678 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 gnorm_cross = gnorm_cross + 0.5_dp*tmp
681 END DO
682 END IF
683 END IF
684 IF (do_ener) THEN
685 DO ispin = 1, nspin
686 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
687 gnorm_cross = gnorm_cross + tmp
688 END DO
689 END IF
690
691 IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
692
693 DO ispin = 1, nspin
694 CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
695 qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
696 END DO
697 qs_ot_env(1)%gnorm = 0.0_dp
698 IF (do_ks) THEN
699 DO ispin = 1, nspin
700 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old, tmp)
701 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
702 END DO
703 IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
704 WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
705 END IF
706 DO ispin = 1, nspin
707 CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx_old)
708 END DO
709 IF (qs_ot_env(1)%settings%do_rotation) THEN
710 DO ispin = 1, nspin
711 ! right now no preconditioner yet
712 CALL dbcsr_copy(qs_ot_env(ispin)%rot_mat_gx_old, qs_ot_env(ispin)%rot_mat_gx)
713 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 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
716 END DO
717 DO ispin = 1, nspin
718 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 IF (do_ener) THEN
723 DO ispin = 1, nspin
724 qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
725 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx_old)
726 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
727 qs_ot_env(ispin)%ener_gx = qs_ot_env(ispin)%ener_gx_old
728 END DO
729 END IF
730 ELSE
731 IF (do_ks) THEN
732 qs_ot_env(1)%gnorm = 0.0_dp
733 DO ispin = 1, nspin
734 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
735 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
736 CALL dbcsr_copy(qs_ot_env(ispin)%matrix_gx_old, qs_ot_env(ispin)%matrix_gx)
737 END DO
738 IF (qs_ot_env(1)%settings%do_rotation) THEN
739 DO ispin = 1, nspin
740 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 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
743 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 IF (do_ener) THEN
748 DO ispin = 1, nspin
749 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_gx)
750 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
751 qs_ot_env(ispin)%ener_gx_old = qs_ot_env(ispin)%ener_gx
752 END DO
753 END IF
754 END IF
755
756 k = 0
757 n = 0
758 nener = 0
759 IF (do_ks) THEN
760 CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
761 DO ispin = 1, nspin
762 CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
763 k = k + itmp
764 END DO
765 END IF
766 IF (do_ener) THEN
767 DO ispin = 1, nspin
768 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 IF (int(n, kind=int_8)*int(k, kind=int_8) + nener /= 0) THEN
773 qs_ot_env(1)%delta = sqrt(abs(qs_ot_env(1)%gnorm)/(int(n, kind=int_8)*int(k, kind=int_8) + nener))
774 beta_pr = (qs_ot_env(1)%gnorm - gnorm_cross)/qs_ot_env(1)%gnorm_old
775 ELSE
776 qs_ot_env(1)%delta = 0.0_dp
777 beta_pr = 0.0_dp
778 END IF
779 beta_pr = max(beta_pr, 0.0_dp) ! reset to SD
780
781 test_down = 0.0_dp
782 IF (do_ks) THEN
783 DO ispin = 1, nspin
784 CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx, &
785 alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
786 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_dx, tmp)
787 test_down = test_down + tmp
788 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 alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
791 CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_dx, tmp)
792 test_down = test_down + 0.5_dp*tmp
793 END IF
794 END DO
795 END IF
796 IF (do_ener) THEN
797 DO ispin = 1, nspin
798 qs_ot_env(ispin)%ener_dx = beta_pr*qs_ot_env(ispin)%ener_dx - qs_ot_env(ispin)%ener_gx
799 tmp = dot_product(qs_ot_env(ispin)%ener_gx, qs_ot_env(ispin)%ener_dx)
800 test_down = test_down + tmp
801 END DO
802 END IF
803
804 IF (test_down .GE. 0.0_dp) THEN ! reset to SD
805 beta_pr = 0.0_dp
806 IF (do_ks) THEN
807 DO ispin = 1, nspin
808 CALL dbcsr_add(qs_ot_env(ispin)%matrix_dx, qs_ot_env(ispin)%matrix_gx, &
809 alpha_scalar=beta_pr, beta_scalar=-1.0_dp)
810 IF (qs_ot_env(1)%settings%do_rotation) THEN
811 CALL dbcsr_add(qs_ot_env(ispin)%rot_mat_dx, &
812 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 IF (do_ener) THEN
817 DO ispin = 1, nspin
818 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 qs_ot_env(1)%gradient = beta_pr*qs_ot_env(1)%gradient - qs_ot_env(1)%gnorm
824 qs_ot_env(1)%gnorm_old = qs_ot_env(1)%gnorm
825
826 CALL timestop(handle)
827
828 END SUBROUTINE ot_new_cg_direction
829
830! **************************************************************************************************
831!> \brief ...
832!> \param qs_ot_env ...
833! **************************************************************************************************
834 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 CALL timeset(routinen, handle)
846
847 logger => cp_get_default_logger()
848
849 do_ks = qs_ot_env(1)%settings%ks
850 do_ener = qs_ot_env(1)%settings%do_ener
851 nspin = SIZE(qs_ot_env)
852
853 diis_m = qs_ot_env(1)%settings%diis_m
854
855 IF (qs_ot_env(1)%diis_iter .LT. diis_m) THEN
856 diis_bound = qs_ot_env(1)%diis_iter + 1
857 ELSE
858 diis_bound = diis_m
859 END IF
860
861 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 IF (do_ks) THEN
866 DO ispin = 1, nspin
867 CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
868 IF (qs_ot_env(ispin)%settings%do_rotation) THEN
869 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 IF (do_ener) THEN
874 DO ispin = 1, nspin
875 qs_ot_env(ispin)%ener_h_x(j, :) = qs_ot_env(ispin)%ener_x(:)
876 END DO
877 END IF
878 IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
879 qs_ot_env(1)%gnorm = 0.0_dp
880 IF (do_ks) THEN
881 DO ispin = 1, nspin
882 CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
883 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 tmp)
886 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
887 END DO
888 IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
889 WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
890 END IF
891 DO ispin = 1, nspin
892 CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(j)%matrix, -qs_ot_env(1)%ds_min)
893 END DO
894 IF (qs_ot_env(1)%settings%do_rotation) THEN
895 DO ispin = 1, nspin
896 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 tmp)
899 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + 0.5_dp*tmp
900 END DO
901 DO ispin = 1, nspin
902 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 IF (do_ener) THEN
907 DO ispin = 1, nspin
908 qs_ot_env(ispin)%ener_h_e(j, :) = qs_ot_env(ispin)%ener_gx(:)
909 tmp = dot_product(qs_ot_env(ispin)%ener_h_e(j, :), qs_ot_env(ispin)%ener_gx(:))
910 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
911 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 qs_ot_env(1)%gnorm = 0.0_dp
916 IF (do_ks) THEN
917 DO ispin = 1, nspin
918 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
919 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 qs_ot_env(ispin)%matrix_gx, alpha_scalar=0.0_dp, beta_scalar=-qs_ot_env(1)%ds_min)
922 END DO
923 IF (qs_ot_env(1)%settings%do_rotation) THEN
924 DO ispin = 1, nspin
925 CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_gx, qs_ot_env(ispin)%rot_mat_gx, tmp)
926 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 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 IF (do_ener) THEN
933 DO ispin = 1, nspin
934 tmp = dot_product(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_gx(:))
935 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
936 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 k = 0
941 n = 0
942 nener = 0
943 IF (do_ks) THEN
944 CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
945 DO ispin = 1, nspin
946 CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
947 k = k + itmp
948 END DO
949 END IF
950 IF (do_ener) THEN
951 DO ispin = 1, nspin
952 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 IF (int(n, kind=int_8)*int(k, kind=int_8) + nener /= 0) THEN
957 qs_ot_env(1)%delta = sqrt(abs(qs_ot_env(1)%gnorm)/(int(n, kind=int_8)*int(k, kind=int_8) + nener))
958 qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
959 ELSE
960 qs_ot_env(1)%delta = 0.0_dp
961 qs_ot_env(1)%gradient = 0.0_dp
962 END IF
963
964 ! make the diis matrix and solve it
965 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 qs_ot_env(1)%ls_diis(i, j) = 0.0_dp
994 IF (do_ks) THEN
995 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 tmp)
999 qs_ot_env(1)%ls_diis(i, j) = qs_ot_env(1)%ls_diis(i, j) - qs_ot_env(1)%ds_min*tmp
1000 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 tmp)
1004 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 IF (do_ener) THEN
1009 DO ispin = 1, nspin
1010 tmp = dot_product(qs_ot_env(ispin)%ener_gx(:), qs_ot_env(ispin)%ener_h_e(i, :))
1011 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 qs_ot_env(1)%ls_diis(j, i) = qs_ot_env(1)%ls_diis(i, j)
1016 qs_ot_env(1)%ls_diis(i, diis_bound + 1) = 1.0_dp
1017 qs_ot_env(1)%ls_diis(diis_bound + 1, i) = 1.0_dp
1018 qs_ot_env(1)%c_diis(i) = 0.0_dp
1019 END DO
1020 qs_ot_env(1)%ls_diis(diis_bound + 1, diis_bound + 1) = 0.0_dp
1021 qs_ot_env(1)%c_diis(diis_bound + 1) = 1.0_dp
1022 ! put in buffer, dgesv destroys
1023 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 qs_ot_env(1)%c_diis, diis_m + 1, info)
1027
1028 IF (info .NE. 0) THEN
1029 do_ot_sd = .true.
1030 WRITE (cp_logger_get_default_unit_nr(logger), *) "Singular DIIS matrix"
1031 ELSE
1032 do_ot_sd = .false.
1033 IF (do_ks) THEN
1034 DO ispin = 1, nspin
1035 ! OK, add the vectors now
1036 CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
1037 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 alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1041 END DO
1042 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 alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1046 END DO
1047 IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1048 CALL dbcsr_set(qs_ot_env(ispin)%rot_mat_x, 0.0_dp)
1049 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 alpha_scalar=1.0_dp, beta_scalar=qs_ot_env(1)%c_diis(i))
1053 END DO
1054 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 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 IF (do_ener) THEN
1063 DO ispin = 1, nspin
1064 qs_ot_env(ispin)%ener_x(:) = 0.0_dp
1065 DO i = 1, diis_bound
1066 qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
1067 + qs_ot_env(1)%c_diis(i)*qs_ot_env(ispin)%ener_h_e(i, :)
1068 END DO
1069 DO i = 1, diis_bound
1070 qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) &
1071 + 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 qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
1076 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 tr_xold_gx = 0.0_dp
1081 tr_xnew_gx = 0.0_dp
1082 IF (do_ks) THEN
1083 DO ispin = 1, nspin
1084 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_h_x(j)%matrix, &
1085 qs_ot_env(ispin)%matrix_gx, tmp)
1086 tr_xold_gx = tr_xold_gx + tmp
1087 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, &
1088 qs_ot_env(ispin)%matrix_gx, tmp)
1089 tr_xnew_gx = tr_xnew_gx + tmp
1090 IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1091 CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_h_x(j)%matrix, &
1092 qs_ot_env(ispin)%rot_mat_gx, tmp)
1093 tr_xold_gx = tr_xold_gx + 0.5_dp*tmp
1094 CALL dbcsr_dot(qs_ot_env(ispin)%rot_mat_x, &
1095 qs_ot_env(ispin)%rot_mat_gx, tmp)
1096 tr_xnew_gx = tr_xnew_gx + 0.5_dp*tmp
1097 END IF
1098 END DO
1099 END IF
1100 IF (do_ener) THEN
1101 DO ispin = 1, nspin
1102 tmp = dot_product(qs_ot_env(ispin)%ener_h_x(j, :), qs_ot_env(ispin)%ener_gx(:))
1103 tr_xold_gx = tr_xold_gx + tmp
1104 tmp = dot_product(qs_ot_env(ispin)%ener_x(:), qs_ot_env(ispin)%ener_gx(:))
1105 tr_xnew_gx = tr_xnew_gx + tmp
1106 END DO
1107 END IF
1108 overlap = (tr_xnew_gx - tr_xold_gx)
1109 ! OK, bad luck, take a SD step along the preconditioned gradient
1110 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 qs_ot_env(1)%OT_METHOD_FULL = "OT SD"
1118 IF (do_ks) THEN
1119 DO ispin = 1, nspin
1120 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 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 1.0_dp, 1.0_dp)
1127 IF (qs_ot_env(ispin)%settings%do_rotation) THEN
1128 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 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 1.0_dp, 1.0_dp)
1135 END IF
1136 END DO
1137 END IF
1138 IF (do_ener) THEN
1139 DO ispin = 1, nspin
1140 qs_ot_env(ispin)%ener_x(:) = 0._dp
1141 qs_ot_env(ispin)%ener_x(:) = qs_ot_env(ispin)%ener_x(:) + qs_ot_env(ispin)%ener_h_e(j, :)
1142 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 CALL timestop(handle)
1148
1149 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 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 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 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: f, x
1167 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: g, s
1168 TYPE(cp_logger_type), POINTER :: logger
1169
1170 eta = qs_ot_env(1)%settings%broyden_eta
1171 omega = qs_ot_env(1)%settings%broyden_omega
1172 sigma_dec = qs_ot_env(1)%settings%broyden_sigma_decrease
1173 sigma_min = qs_ot_env(1)%settings%broyden_sigma_min
1174 forget_history = qs_ot_env(1)%settings%broyden_forget_history
1175 adaptive_sigma = qs_ot_env(1)%settings%broyden_adaptive_sigma
1176 enable_flip = qs_ot_env(1)%settings%broyden_enable_flip
1177
1178 do_ks = qs_ot_env(1)%settings%ks
1179 do_ener = qs_ot_env(1)%settings%do_ener
1180
1181 beta = qs_ot_env(1)%settings%broyden_beta
1182 gamma = qs_ot_env(1)%settings%broyden_gamma
1183 IF (adaptive_sigma) THEN
1184 IF (qs_ot_env(1)%broyden_adaptive_sigma .LT. 0.0_dp) THEN
1185 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 sigma = qs_ot_env(1)%settings%broyden_sigma
1191 END IF
1192
1193 ! simplify our life....
1194 IF (do_ener .OR. .NOT. do_ks .OR. qs_ot_env(1)%settings%do_rotation) THEN
1195 cpabort("Not yet implemented")
1196 END IF
1197 !
1198 nspin = SIZE(qs_ot_env)
1199
1200 diis_m = qs_ot_env(1)%settings%diis_m
1201
1202 IF (qs_ot_env(1)%diis_iter .LT. diis_m) THEN
1203 diis_bound = qs_ot_env(1)%diis_iter + 1
1204 ELSE
1205 diis_bound = diis_m
1206 END IF
1207
1208 ! We want x:s, f:s and one random vector
1209 k = 2*diis_bound + 1
1210 ALLOCATE (s(k, k))
1211 ALLOCATE (g(k, k))
1212 ALLOCATE (f(k))
1213 ALLOCATE (x(k))
1214 ALLOCATE (circ_index(diis_bound))
1215 g = 0.0
1216 DO i = 1, k
1217 g(i, i) = sigma
1218 END DO
1219 s = 0.0
1220
1221 j = mod(qs_ot_env(1)%diis_iter, diis_m) + 1 ! index in the circular array
1222
1223 DO ispin = 1, nspin
1224 CALL dbcsr_copy(qs_ot_env(ispin)%matrix_h_x(j)%matrix, qs_ot_env(ispin)%matrix_x)
1225 END DO
1226
1227 IF (ASSOCIATED(qs_ot_env(1)%preconditioner)) THEN
1228 qs_ot_env(1)%gnorm = 0.0_dp
1229 DO ispin = 1, nspin
1230 CALL apply_preconditioner(qs_ot_env(ispin)%preconditioner, &
1231 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 tmp)
1234 qs_ot_env(1)%gnorm = qs_ot_env(1)%gnorm + tmp
1235 END DO
1236 IF (qs_ot_env(1)%gnorm .LT. 0.0_dp) THEN
1237 WRITE (cp_logger_get_default_unit_nr(logger), *) "WARNING Preconditioner not positive definite !"
1238 END IF
1239 DO ispin = 1, nspin
1240 CALL dbcsr_scale(qs_ot_env(ispin)%matrix_h_e(j)%matrix, -1.0_dp)
1241 END DO
1242 ELSE
1243 qs_ot_env(1)%gnorm = 0.0_dp
1244 DO ispin = 1, nspin
1245 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, qs_ot_env(ispin)%matrix_gx, tmp)
1246 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 qs_ot_env(ispin)%matrix_gx, alpha_scalar=0.0_dp, beta_scalar=-1.0_dp)
1249 END DO
1250 END IF
1251
1252 k = 0
1253 n = 0
1254 CALL dbcsr_get_info(qs_ot_env(1)%matrix_x, nfullrows_total=n)
1255 DO ispin = 1, nspin
1256 CALL dbcsr_get_info(qs_ot_env(ispin)%matrix_x, nfullcols_total=itmp)
1257 k = k + itmp
1258 END DO
1259
1260 ! Handling the case of no free variables to optimize
1261 IF (int(n, kind=int_8)*int(k, kind=int_8) /= 0) THEN
1262 qs_ot_env(1)%delta = sqrt(abs(qs_ot_env(1)%gnorm)/(int(n, kind=int_8)*int(k, kind=int_8)))
1263 qs_ot_env(1)%gradient = -qs_ot_env(1)%gnorm
1264 ELSE
1265 qs_ot_env(1)%delta = 0.0_dp
1266 qs_ot_env(1)%gradient = 0.0_dp
1267 END IF
1268
1269 IF (diis_bound == diis_m) THEN
1270 DO i = 1, diis_bound
1271 circ_index(i) = mod(j + i - 1, diis_m) + 1
1272 END DO
1273 ELSE
1274 DO i = 1, diis_bound
1275 circ_index(i) = i
1276 END DO
1277 END IF
1278
1279 s = 0.0_dp
1280 DO ispin = 1, nspin
1281 CALL dbcsr_init_random(qs_ot_env(ispin)%matrix_x)
1282 DO i = 1, diis_bound
1283 CALL dbcsr_dot( &
1284 qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1285 qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, tmp)
1286 s(i, i) = s(i, i) + tmp
1287 CALL dbcsr_dot( &
1288 qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, &
1289 qs_ot_env(ispin)%matrix_h_e(circ_index(i))%matrix, tmp)
1290 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 qs_ot_env(ispin)%matrix_x, tmp)
1294 s(i, 2*diis_bound + 1) = s(i, 2*diis_bound + 1) + tmp
1295 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 qs_ot_env(ispin)%matrix_x, tmp)
1299 s(i + diis_bound, 2*diis_bound + 1) = s(i + diis_bound, 2*diis_bound + 1) + tmp
1300 s(i + diis_bound, 2*diis_bound + 1) = s(2*diis_bound + 1, diis_bound + i)
1301 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 tmp)
1306 s(i, k) = s(i, k) + tmp
1307 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 tmp)
1312 s(diis_bound + i, diis_bound + k) = s(diis_bound + i, diis_bound + k) + tmp
1313 s(diis_bound + k, diis_bound + i) = s(diis_bound + i, diis_bound + k)
1314 END DO
1315 DO k = 1, diis_bound
1316 CALL dbcsr_dot( &
1317 qs_ot_env(ispin)%matrix_h_x(circ_index(i))%matrix, &
1318 qs_ot_env(ispin)%matrix_h_e(circ_index(k))%matrix, tmp)
1319 s(i, k + diis_bound) = s(i, k + diis_bound) + tmp
1320 s(k + diis_bound, i) = s(i, k + diis_bound)
1321 END DO
1322 END DO
1323 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_x, qs_ot_env(ispin)%matrix_x, tmp)
1324 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 k = 2*diis_bound + 1
1329 tmp = sqrt(s(k, k))
1330 s(k, :) = s(k, :)/tmp
1331 s(:, k) = s(:, k)/tmp
1332
1333 IF (diis_bound .GT. 1) THEN
1334 tmp = 0.0_dp
1335 tmp2 = 0.0_dp
1336 i = diis_bound
1337 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 tmp)
1343 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 tmp)
1348 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 tmp)
1353 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 tmp)
1358 tmp2 = tmp2 + tmp
1359 END DO
1360 qs_ot_env(1)%c_broy(i - 1) = tmp2
1361 END IF
1362
1363 qs_ot_env(1)%energy_h(j) = qs_ot_env(1)%etotal
1364
1365 ! If we went uphill, do backtracking line search
1366 i = minloc(qs_ot_env(1)%energy_h(1:diis_bound), dim=1)
1367 IF (i .NE. j) THEN
1368 sigma = sigma_dec*sigma
1369 qs_ot_env(1)%OT_METHOD_FULL = "OT BTRK"
1370 DO ispin = 1, nspin
1371 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 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 alpha_scalar=1.0_dp, beta_scalar=gamma)
1378 END DO
1379 ELSE
1380 ! Construct G
1381 DO i = 2, diis_bound
1382 f = 0.0
1383 x = 0.0
1384 ! f is df_i
1385 x(i) = 1.0
1386 x(i - 1) = -1.0
1387 ! x is dx_i
1388 f(diis_bound + i) = 1.0
1389 f(diis_bound + i - 1) = -1.0
1390 tmp = 1.0_dp
1391 ! We want a pos def Hessian
1392 IF (enable_flip) THEN
1393 IF (qs_ot_env(1)%c_broy(i - 1) .GT. 0) THEN
1394 !qs_ot_env(1)%OT_METHOD_FULL="OT FLIP"
1395 tmp = -1.0_dp
1396 END IF
1397 END IF
1398
1399 ! get dx-Gdf
1400 x(:) = tmp*x - matmul(g, f)
1401 ! dfSdf
1402 ! we calculate matmul(S, f) twice. They're small...
1403 tmp = dot_product(f, matmul(s, f))
1404 ! NOTE THAT S IS SYMMETRIC !!!
1405 f(:) = matmul(s, f)/tmp
1406 ! the spread is an outer vector product
1407 g(:, :) = g + spread(x, dim=2, ncopies=SIZE(f))*spread(f, dim=1, ncopies=SIZE(x))
1408 END DO
1409 f = 0.0_dp
1410 f(2*diis_bound) = 1.0_dp
1411 x(:) = -beta*matmul(g, f)
1412
1413 ! OK, add the vectors now, this sums up to the proposed step
1414 DO ispin = 1, nspin
1415 CALL dbcsr_set(qs_ot_env(ispin)%matrix_x, 0.0_dp)
1416 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 alpha_scalar=1.0_dp, beta_scalar=-x(i + diis_bound))
1420 END DO
1421 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 alpha_scalar=1.0_dp, beta_scalar=x(i))
1425 END DO
1426 END DO
1427
1428 IF (adaptive_sigma) THEN
1429 tmp = new_sigma(g, s, diis_bound)
1430 !tmp = tmp * qs_ot_env ( 1 ) % settings % broyden_sigma
1431 tmp = tmp*eta
1432 sigma = min(omega*sigma, tmp)
1433 END IF
1434
1435 ! compute the inner product of direction of the step and gradient
1436 tmp = 0.0_dp
1437 DO ispin = 1, nspin
1438 CALL dbcsr_dot(qs_ot_env(ispin)%matrix_gx, &
1439 qs_ot_env(ispin)%matrix_x, &
1440 tmp2)
1441 tmp = tmp + tmp2
1442 END DO
1443
1444 DO ispin = 1, nspin
1445 ! if the direction of the step is not in direction of the gradient,
1446 ! change step sign
1447 IF (tmp .GE. 0.0_dp) THEN
1448 qs_ot_env(1)%OT_METHOD_FULL = "OT TURN"
1449 IF (forget_history) THEN
1450 qs_ot_env(1)%diis_iter = 0
1451 END IF
1452 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 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 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 DEALLOCATE (s, g, f, x, circ_index)
1466
1467 ! update for next round
1468 qs_ot_env(1)%diis_iter = qs_ot_env(1)%diis_iter + 1
1469 qs_ot_env(1)%broyden_adaptive_sigma = max(sigma, sigma_min)
1470
1471 END SUBROUTINE ot_broyden_step
1472
1473! **************************************************************************************************
1474!> \brief ...
1475!> \param G ...
1476!> \param S ...
1477!> \param n ...
1478!> \return ...
1479! **************************************************************************************************
1480 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 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: h
1492
1493 ALLOCATE (h(n, n))
1494 CALL hess_g(g, s, h, n)
1495 ALLOCATE (eigv(n))
1496 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 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 DEALLOCATE (h, eigv)
1511 END FUNCTION new_sigma
1512
1513! **************************************************************************************************
1514!> \brief ...
1515!> \param G ...
1516!> \param S ...
1517!> \param H ...
1518!> \param n ...
1519! **************************************************************************************************
1520 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 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: v
1533 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: q
1534
1535 i = SIZE(g, 1)
1536 k = SIZE(h, 1)
1537 ALLOCATE (q(i, k))
1538 ALLOCATE (v(i))
1539 h = 0.0_dp
1540 q = 0.0_dp
1541
1542 q(:, 1) = 1.0_dp
1543 tmp = sqrt(dot_product(q(:, 1), matmul(s, q(:, 1))))
1544 q(:, :) = q(:, :)/tmp
1545
1546 DO i = 1, k
1547 v(:) = matmul(g, q(:, i))
1548 DO j = 1, i
1549 h(j, i) = dot_product(q(:, j), matmul(s, v))
1550 v(:) = v - h(j, i)*q(:, j)
1551 END DO
1552 IF (i .LT. k) THEN
1553 tmp = dot_product(v, matmul(s, v))
1554 IF (tmp .LE. 0.0_dp) THEN
1555 n = i
1556 EXIT
1557 END IF
1558 tmp = sqrt(tmp)
1559 ! Lucky breakdown
1560 IF (abs(tmp) .LT. 1e-9_dp) THEN
1561 n = i
1562 EXIT
1563 END IF
1564 h(i + 1, i) = tmp
1565 q(:, i + 1) = v/h(i + 1, i)
1566 END IF
1567 END DO
1568
1569 DEALLOCATE (q, v)
1570 END SUBROUTINE hess_g
1571
1572END MODULE qs_ot_minimizer
various routines to log and control the output. The idea is that decisions about where to log should ...
recursive integer function, public cp_logger_get_default_unit_nr(logger, local, skip_not_ionode)
asks the default unit number of the given logger. try to use cp_logger_get_unit_nr
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
Calculation of the incomplete Gamma function F_n(t) for multi-center integrals over Cartesian Gaussia...
Definition gamma.F:15
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public int_8
Definition kinds.F:54
integer, parameter, public dp
Definition kinds.F:34
Collection of simple mathematical functions and subroutines.
Definition mathlib.F:15
subroutine, public diamat_all(a, eigval, dac)
Diagonalize the symmetric n by n matrix a using the LAPACK library. Only the upper triangle of matrix...
Definition mathlib.F:372
computes preconditioners, and implements methods to apply them currently used in qs_ot
orbital transformations
subroutine, public ot_mini(qs_ot_env, matrix_hc)
...
orbital transformations
Definition qs_ot_types.F:15
orbital transformations
Definition qs_ot.F:15
subroutine, public qs_ot_get_derivative_ref(matrix_hc, matrix_x, matrix_sx, matrix_gx, qs_ot_env)
...
Definition qs_ot.F:704
subroutine, public qs_ot_get_derivative(matrix_hc, matrix_x, matrix_sx, matrix_gx, qs_ot_env)
...
Definition qs_ot.F:1074
Exchange and Correlation functional calculations.
Definition xc.F:17
type of a logger, at the moment it contains just a print level starting at which level it should be l...