(git:6344619)
Loading...
Searching...
No Matches
qs_scf_subspace.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief History management and matrix combination for ADIIS.
10! **************************************************************************************************
12
13 USE cp_dbcsr_api, ONLY: dbcsr_add,&
19 USE ieee_arithmetic, ONLY: ieee_is_finite
20 USE kinds, ONLY: dp
29#include "./base/base_uses.f90"
30
31 IMPLICIT NONE
32
33 PRIVATE
34
35 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_scf_subspace'
36
37 INTEGER, PARAMETER, PUBLIC :: scf_subspace_invalid_history = 100
38
41
42CONTAINS
43
44! **************************************************************************************************
45!> \brief Adapt candidate regularization from two evaluated states; no trial KS builds.
46!> \param buffer Paired physical states, including the newest evaluated density.
47!> \param shift Current occupied-space level shift in hartree.
48! **************************************************************************************************
49 SUBROUTINE qs_scf_subspace_update_shift(buffer, shift)
50 TYPE(qs_scf_subspace_buffer_type), INTENT(IN) :: buffer
51 REAL(kind=dp), INTENT(INOUT) :: shift
52
53 INTEGER :: newest, previous
54 REAL(kind=dp) :: actual, predicted, tolerance
55
56 ! Only pure ADIIS steps measure the response to this regularization.
57 IF (buffer%nstored < 2 .OR. buffer%diis_weight > 0.0_dp) RETURN
58 newest = maxloc(buffer%generation, dim=1)
59 previous = maxloc(buffer%generation, dim=1, &
60 mask=buffer%generation < buffer%generation(newest))
61 ! T_ij = Tr(P_i F_j). Compare actual progress with the linear model at P_previous.
62 actual = buffer%state_energy(newest) - buffer%state_energy(previous)
63 predicted = buffer%pf_metric(newest, previous) - buffer%pf_metric(previous, previous)
64 tolerance = 64.0_dp*epsilon(1.0_dp)*max(1.0_dp, &
65 abs(buffer%state_energy(newest)), abs(buffer%state_energy(previous)), &
66 abs(buffer%pf_metric(newest, previous)), abs(buffer%pf_metric(previous, previous)))
67 IF (actual > tolerance .OR. predicted > tolerance) THEN
68 ! An uphill endpoint still contains useful curvature information: retain the history.
69 shift = 2.0_dp*shift
70 ELSE IF (predicted < -tolerance) THEN
71 IF (actual > 0.25_dp*predicted) shift = 2.0_dp*shift
72 IF (actual < 0.75_dp*predicted) shift = 0.5_dp*shift
73 ELSE
74 ! Do not maintain a large penalty when changes fall below energy resolution.
75 shift = 0.5_dp*shift
76 END IF
77 cpassert(ieee_is_finite(shift))
78
79 END SUBROUTINE qs_scf_subspace_update_shift
80
81! **************************************************************************************************
82!> \brief Restart the ADIIS history from the current strictly paired P, F[P] state.
83!> \param buffer Persistent SCF subspace history.
84!> \param fock Current raw F[P], indexed by spin and real-space cell.
85!> \param density Current input P that generated fock, with matching indices.
86!> \param state_energy ...
87!> \param restarted Whether the current state was stored successfully.
88!> \param density_aux Optional replicated density coordinates for a separately represented term.
89!> \param fock_aux Conjugate potential for the same state; contributes SUM(density_aux*fock_aux) to Tr(PF).
90! **************************************************************************************************
91 SUBROUTINE qs_scf_subspace_restart(buffer, fock, density, state_energy, restarted, density_aux, fock_aux)
92
93 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
94 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: fock, density
95 REAL(kind=dp), INTENT(IN) :: state_energy
96 LOGICAL, INTENT(OUT) :: restarted
97 REAL(dp), INTENT(IN), OPTIONAL :: density_aux(:, :), fock_aux(:, :)
98
99 restarted = .false.
101 CALL qs_scf_subspace_push(buffer, fock, density, state_energy, restarted, density_aux, fock_aux)
102 IF (.NOT. restarted) RETURN
103
104 buffer%coefficients = 0.0_dp
105 buffer%coefficients(1) = 1.0_dp
106 buffer%last_status = simplex_qp_success
107 buffer%last_restart = .true.
108 buffer%use_combined_fock = .false.
109 buffer%last_objective = 0.0_dp
110 buffer%last_old_fock_weight = 0.0_dp
111
112 END SUBROUTINE qs_scf_subspace_restart
113
114! **************************************************************************************************
115!> \brief Append one accepted, evaluated P,F[P] state to the ADIIS history.
116!>
117!> The SCF driver owns state acceptance. Trial endpoints and arbitrary initial guesses
118!> must not call this routine.
119!> \param buffer Persistent SCF subspace history.
120!> \param fock Current raw F[P], indexed by spin and real-space cell.
121!> \param density Current input P that generated fock, with matching indices.
122!> \param state_energy ...
123!> \param pushed Whether the state was stored successfully.
124!> \param density_aux Optional replicated density coordinates for a separately represented term.
125!> \param fock_aux Conjugate potential for the same state; contributes SUM(density_aux*fock_aux) to Tr(PF).
126! **************************************************************************************************
127 SUBROUTINE qs_scf_subspace_push(buffer, fock, density, state_energy, pushed, density_aux, fock_aux)
128
129 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
130 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: fock, density
131 REAL(kind=dp), INTENT(IN) :: state_energy
132 LOGICAL, INTENT(OUT) :: pushed
133 REAL(dp), INTENT(IN), OPTIONAL :: density_aux(:, :), fock_aux(:, :)
134
135 LOGICAL :: storage_valid
136
137 pushed = .false.
138 buffer%use_combined_fock = .false.
139 buffer%last_restart = .false.
140 buffer%last_objective = 0.0_dp
141 buffer%last_old_fock_weight = 0.0_dp
142 IF (ALLOCATED(buffer%coefficients)) buffer%coefficients = 0.0_dp
143
144 IF (buffer%nbuffer < 1) THEN
145 buffer%last_status = scf_subspace_invalid_history
146 RETURN
147 END IF
148 IF (buffer%ncall < 0 .OR. buffer%nstored < 0 .OR. buffer%nstored > buffer%nbuffer .OR. &
149 buffer%nstored /= min(buffer%ncall, buffer%nbuffer)) THEN
150 buffer%last_status = scf_subspace_invalid_history
151 RETURN
152 END IF
153
154 CALL ensure_matrix_storage(buffer, fock, density, storage_valid)
155 IF (.NOT. storage_valid) THEN
156 buffer%last_status = scf_subspace_invalid_history
157 RETURN
158 END IF
159
160 cpassert(PRESENT(density_aux) .EQV. PRESENT(fock_aux))
161 IF (PRESENT(density_aux)) THEN
162 cpassert(all(shape(density_aux) == shape(fock_aux)))
163 IF (.NOT. ALLOCATED(buffer%density_aux)) THEN
164 cpassert(buffer%nstored == 0)
165 ALLOCATE (buffer%density_aux(SIZE(density_aux, 1), SIZE(density_aux, 2), buffer%nbuffer), &
166 buffer%fock_aux(SIZE(density_aux, 1), SIZE(density_aux, 2), buffer%nbuffer), &
167 buffer%combined_aux(SIZE(density_aux, 1), SIZE(density_aux, 2)))
168 END IF
169 cpassert(all(shape(buffer%combined_aux) == shape(density_aux)))
170 ELSE
171 cpassert(.NOT. ALLOCATED(buffer%density_aux))
172 END IF
173 CALL push_paired_state(buffer, fock, density, state_energy, pushed, density_aux, fock_aux)
174 IF (.NOT. pushed) THEN
175 buffer%last_status = simplex_qp_nonfinite_input
176 RETURN
177 END IF
178 buffer%last_status = simplex_qp_success
179
180 END SUBROUTINE qs_scf_subspace_push
181
182! **************************************************************************************************
183!> \brief Solve the ADIIS model from previously accepted history and form an effective KS matrix.
184!> \param buffer Persistent SCF subspace history.
185! **************************************************************************************************
186 SUBROUTINE qs_scf_subspace_build(buffer)
187
188 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
189
190 INTEGER :: i, j, m, physical
191 INTEGER, ALLOCATABLE, DIMENSION(:) :: slots
192 LOGICAL :: model_valid, solver_usable
193 REAL(kind=dp) :: coefficient_sum, model_delta, &
194 model_tolerance
195 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: difference, linear
196 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: chronological_pf, hessian
197
198 buffer%use_combined_fock = .false.
199 buffer%last_restart = .false.
200 buffer%last_objective = 0.0_dp
201 buffer%last_old_fock_weight = 0.0_dp
202 IF (ALLOCATED(buffer%coefficients)) buffer%coefficients = 0.0_dp
203
204 IF (buffer%nbuffer < 1 .OR. buffer%nstored < 1) THEN
205 buffer%last_status = scf_subspace_invalid_history
206 RETURN
207 END IF
208 IF (buffer%ncall < 0 .OR. buffer%nstored < 0 .OR. buffer%nstored > buffer%nbuffer .OR. &
209 buffer%nstored /= min(buffer%ncall, buffer%nbuffer)) THEN
210 buffer%last_status = scf_subspace_invalid_history
211 RETURN
212 END IF
213
214 IF (.NOT. ASSOCIATED(buffer%fock) .OR. .NOT. ASSOCIATED(buffer%density) .OR. &
215 .NOT. ASSOCIATED(buffer%combined_fock)) THEN
216 buffer%last_status = scf_subspace_invalid_history
217 RETURN
218 END IF
219 IF (.NOT. ALLOCATED(buffer%generation) .OR. .NOT. ALLOCATED(buffer%pf_metric) .OR. &
220 .NOT. ALLOCATED(buffer%coefficients) .OR. .NOT. ALLOCATED(buffer%state_energy)) THEN
221 buffer%last_status = scf_subspace_invalid_history
222 RETURN
223 END IF
224 IF (SIZE(buffer%generation) /= buffer%nbuffer .OR. &
225 SIZE(buffer%pf_metric, 1) /= buffer%nbuffer .OR. SIZE(buffer%pf_metric, 2) /= buffer%nbuffer .OR. &
226 SIZE(buffer%coefficients) /= buffer%nbuffer .OR. SIZE(buffer%state_energy) /= buffer%nbuffer .OR. &
227 count(buffer%generation > 0) /= buffer%nstored .OR. any(buffer%generation < 0)) THEN
228 buffer%last_status = scf_subspace_invalid_history
229 RETURN
230 END IF
231
232 m = buffer%nstored
233 ALLOCATE (slots(m), chronological_pf(m, m), hessian(m, m), linear(m))
234 CALL chronological_slots(buffer, slots)
235
236 DO i = 1, m
237 DO j = 1, m
238 chronological_pf(i, j) = buffer%pf_metric(slots(i), slots(j))
239 END DO
240 END DO
241
242 CALL qs_scf_subspace_build_adiis_model(chronological_pf, m, hessian, linear, model_valid)
243
244 buffer%coefficients = 0.0_dp
245 IF (.NOT. model_valid) THEN
246 CALL restart_newest_after_failure(buffer, scf_subspace_invalid_history)
247 RETURN
248 END IF
249
250 CALL simplex_quadratic_minimize(hessian, linear, buffer%coefficients(1:m), &
251 buffer%last_objective, buffer%last_status, preferred_index=m)
252
253 solver_usable = buffer%last_status == simplex_qp_success .OR. &
254 buffer%last_status == simplex_qp_pairwise_stationary
255 IF (.NOT. solver_usable) THEN
256 CALL restart_newest_after_failure(buffer, buffer%last_status)
257 RETURN
258 END IF
259 IF (.NOT. ieee_is_finite(buffer%last_objective) .OR. &
260 .NOT. all(ieee_is_finite(buffer%coefficients(1:m)))) THEN
261 CALL restart_newest_after_failure(buffer, simplex_qp_nonfinite_input)
262 RETURN
263 END IF
264
265 coefficient_sum = sum(buffer%coefficients(1:m))
266 IF (minval(buffer%coefficients(1:m)) < -100.0_dp*epsilon(1.0_dp) .OR. &
267 abs(coefficient_sum - 1.0_dp) > 1000.0_dp*epsilon(1.0_dp)) THEN
268 CALL restart_newest_after_failure(buffer, scf_subspace_invalid_history)
269 RETURN
270 END IF
271
272 ALLOCATE (difference(m))
273 difference(:) = buffer%coefficients(1:m)
274 difference(m) = difference(m) - 1.0_dp
275 model_delta = 0.5_dp*dot_product(difference, matmul(hessian, difference)) + &
276 dot_product(difference, hessian(:, m) + linear)
277 model_tolerance = 1000.0_dp*epsilon(1.0_dp)*real(m, kind=dp)* &
278 max(1.0_dp, maxval(abs(hessian)), maxval(abs(linear)))
279 IF (.NOT. ieee_is_finite(model_delta) .OR. model_delta > model_tolerance) THEN
280 IF (ieee_is_finite(model_delta)) THEN
281 CALL restart_newest_after_failure(buffer, scf_subspace_invalid_history)
282 ELSE
283 CALL restart_newest_after_failure(buffer, simplex_qp_nonfinite_input)
284 END IF
285 RETURN
286 END IF
287
288 buffer%last_old_fock_weight = max(0.0_dp, 1.0_dp - buffer%coefficients(m))
289 IF (buffer%last_old_fock_weight <= 100.0_dp*epsilon(1.0_dp)) RETURN
290
291 CALL zero_fock_combination(buffer)
292 DO j = 1, m
293 physical = slots(j)
294 IF (buffer%coefficients(j) <= 0.0_dp) cycle
295 CALL add_fock_to_combination(buffer, physical, buffer%coefficients(j))
296 END DO
297 buffer%use_combined_fock = .true.
298
299 END SUBROUTINE qs_scf_subspace_build
300
301! **************************************************************************************************
302!> \brief Retain only the newest accepted state after an unusable ADIIS model.
303!> \param buffer Persistent SCF subspace history.
304!> \param failure_status Status code that caused the restart.
305! **************************************************************************************************
306 SUBROUTINE restart_newest_after_failure(buffer, failure_status)
307
308 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
309 INTEGER, INTENT(IN) :: failure_status
310
311 INTEGER :: icell, ispin, newest
312 REAL(kind=dp) :: contribution, newest_energy, newest_pf
313
314 IF (buffer%nstored < 1) THEN
315 buffer%last_status = failure_status
316 RETURN
317 END IF
318 IF (count(buffer%generation > 0) /= buffer%nstored) THEN
319 buffer%last_status = failure_status
320 RETURN
321 END IF
322 newest = maxloc(buffer%generation, dim=1)
323 newest_energy = buffer%state_energy(newest)
324 newest_pf = 0.0_dp
325 DO icell = 1, SIZE(buffer%fock, 3)
326 DO ispin = 1, SIZE(buffer%fock, 2)
327 CALL dbcsr_dot(buffer%density(newest, ispin, icell)%matrix, &
328 buffer%fock(newest, ispin, icell)%matrix, contribution)
329 newest_pf = newest_pf + contribution
330 END DO
331 END DO
332 IF (ALLOCATED(buffer%density_aux)) THEN
333 newest_pf = newest_pf + sum(buffer%density_aux(:, :, newest)*buffer%fock_aux(:, :, newest))
334 END IF
335 IF (.NOT. ieee_is_finite(newest_energy) .OR. .NOT. ieee_is_finite(newest_pf)) THEN
336 buffer%last_status = failure_status
337 RETURN
338 END IF
339
340 buffer%ncall = 1
341 buffer%nstored = 1
342 buffer%generation = 0
343 buffer%generation(newest) = 1
344 buffer%state_energy = huge(1.0_dp)
345 buffer%state_energy(newest) = newest_energy
346 buffer%pf_metric = 0.0_dp
347 buffer%pf_metric(newest, newest) = newest_pf
348 buffer%coefficients = 0.0_dp
349 buffer%coefficients(1) = 1.0_dp
350 buffer%last_status = failure_status
351 buffer%last_restart = .true.
352 buffer%use_combined_fock = .false.
353 buffer%last_objective = 0.0_dp
354 buffer%last_old_fock_weight = 0.0_dp
355 buffer%diis_weight = 0.0_dp
356
357 END SUBROUTINE restart_newest_after_failure
358
359! **************************************************************************************************
360!> \brief Allocate matrix and scalar storage lazily from current matrix templates.
361!> \param buffer Persistent SCF subspace history.
362!> \param fock Current Fock-matrix templates.
363!> \param density Current density-matrix templates.
364!> \param valid Whether dimensions and existing allocation match.
365! **************************************************************************************************
366 SUBROUTINE ensure_matrix_storage(buffer, fock, density, valid)
367
368 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
369 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: fock, density
370 LOGICAL, INTENT(OUT) :: valid
371
372 INTEGER :: icell, islot, ispin, ncell, nspin
373
374 valid = ASSOCIATED(fock) .AND. ASSOCIATED(density)
375 IF (.NOT. valid) RETURN
376 nspin = SIZE(fock, 1)
377 ncell = SIZE(fock, 2)
378 valid = nspin > 0 .AND. ncell > 0 .AND. &
379 SIZE(density, 1) == nspin .AND. SIZE(density, 2) == ncell
380 IF (.NOT. valid) RETURN
381 DO icell = 1, ncell
382 DO ispin = 1, nspin
383 valid = ASSOCIATED(fock(ispin, icell)%matrix) .AND. &
384 ASSOCIATED(density(ispin, icell)%matrix)
385 IF (.NOT. valid) RETURN
386 END DO
387 END DO
388
389 IF (ASSOCIATED(buffer%fock)) THEN
390 valid = SIZE(buffer%fock, 1) == buffer%nbuffer .AND. &
391 SIZE(buffer%fock, 2) == nspin .AND. SIZE(buffer%fock, 3) == ncell
392 IF (.NOT. valid) RETURN
393 valid = ASSOCIATED(buffer%density)
394 IF (.NOT. valid) RETURN
395 valid = SIZE(buffer%density, 1) == buffer%nbuffer .AND. &
396 SIZE(buffer%density, 2) == nspin .AND. SIZE(buffer%density, 3) == ncell
397 IF (.NOT. valid) RETURN
398 valid = ASSOCIATED(buffer%combined_fock)
399 IF (.NOT. valid) RETURN
400 valid = SIZE(buffer%combined_fock, 1) == nspin .AND. &
401 SIZE(buffer%combined_fock, 2) == ncell
402 IF (.NOT. valid) RETURN
403 valid = ALLOCATED(buffer%generation) .AND. ALLOCATED(buffer%pf_metric) .AND. &
404 ALLOCATED(buffer%coefficients) .AND. ALLOCATED(buffer%state_energy)
405 IF (.NOT. valid) RETURN
406 valid = SIZE(buffer%generation) == buffer%nbuffer .AND. &
407 SIZE(buffer%pf_metric, 1) == buffer%nbuffer .AND. &
408 SIZE(buffer%pf_metric, 2) == buffer%nbuffer .AND. &
409 SIZE(buffer%coefficients) == buffer%nbuffer .AND. &
410 SIZE(buffer%state_energy) == buffer%nbuffer
411 IF (.NOT. valid) RETURN
412 DO icell = 1, ncell
413 DO ispin = 1, nspin
414 valid = ASSOCIATED(buffer%combined_fock(ispin, icell)%matrix)
415 IF (.NOT. valid) RETURN
416 DO islot = 1, buffer%nbuffer
417 valid = ASSOCIATED(buffer%fock(islot, ispin, icell)%matrix) .AND. &
418 ASSOCIATED(buffer%density(islot, ispin, icell)%matrix)
419 IF (.NOT. valid) RETURN
420 END DO
421 END DO
422 END DO
423 RETURN
424 END IF
425
426 valid = .NOT. ASSOCIATED(buffer%density) .AND. &
427 .NOT. ASSOCIATED(buffer%combined_fock) .AND. .NOT. ALLOCATED(buffer%generation) .AND. &
428 .NOT. ALLOCATED(buffer%pf_metric) .AND. .NOT. ALLOCATED(buffer%coefficients) .AND. &
429 .NOT. ALLOCATED(buffer%state_energy)
430 IF (.NOT. valid) RETURN
431
432 ALLOCATE (buffer%fock(buffer%nbuffer, nspin, ncell))
433 ALLOCATE (buffer%density(buffer%nbuffer, nspin, ncell))
434 ALLOCATE (buffer%combined_fock(nspin, ncell))
435 ALLOCATE (buffer%generation(buffer%nbuffer), buffer%state_energy(buffer%nbuffer))
436 ALLOCATE (buffer%pf_metric(buffer%nbuffer, buffer%nbuffer), buffer%coefficients(buffer%nbuffer))
437 buffer%generation = 0
438 buffer%state_energy = huge(1.0_dp)
439 buffer%pf_metric = 0.0_dp
440 buffer%coefficients = 0.0_dp
441
442 DO icell = 1, ncell
443 DO ispin = 1, nspin
444 DO islot = 1, buffer%nbuffer
445 ALLOCATE (buffer%fock(islot, ispin, icell)%matrix)
446 CALL dbcsr_create(buffer%fock(islot, ispin, icell)%matrix, &
447 template=fock(ispin, icell)%matrix)
448 ALLOCATE (buffer%density(islot, ispin, icell)%matrix)
449 CALL dbcsr_create(buffer%density(islot, ispin, icell)%matrix, &
450 template=density(ispin, icell)%matrix)
451 END DO
452 ALLOCATE (buffer%combined_fock(ispin, icell)%matrix)
453 CALL dbcsr_create(buffer%combined_fock(ispin, icell)%matrix, &
454 template=fock(ispin, icell)%matrix)
455 END DO
456 END DO
457
458 END SUBROUTINE ensure_matrix_storage
459
460! **************************************************************************************************
461!> \brief Atomically append one strictly paired P, F[P] state.
462!> \param buffer Persistent SCF subspace history.
463!> \param fock Current raw F[P].
464!> \param density Current P.
465!> \param state_energy ...
466!> \param pushed Whether all scalar checks passed and the state was committed.
467!> \param density_aux Optional replicated density coordinates for a separately represented term.
468!> \param fock_aux Conjugate potential for the same state; contributes SUM(density_aux*fock_aux) to Tr(PF).
469! **************************************************************************************************
470 SUBROUTINE push_paired_state(buffer, fock, density, state_energy, pushed, density_aux, fock_aux)
471
472 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
473 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: fock, density
474 REAL(kind=dp), INTENT(IN) :: state_energy
475 LOGICAL, INTENT(OUT) :: pushed
476 REAL(dp), INTENT(IN), OPTIONAL :: density_aux(:, :), fock_aux(:, :)
477
478 INTEGER :: icell, islot, ispin, target_slot
479 LOGICAL :: retained
480 REAL(kind=dp) :: current_current
481 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: current_old, old_current
482
483 pushed = .false.
484 IF (.NOT. ieee_is_finite(state_energy)) RETURN
485
486 ! Keep the baseline deterministic and auditable: fill empty slots in physical
487 ! order, then evict the oldest accepted state. Energy remains metadata.
488 target_slot = qs_scf_subspace_fifo_slot(buffer%generation)
489 IF (target_slot <= 0) RETURN
490
491 ALLOCATE (current_old(buffer%nbuffer), old_current(buffer%nbuffer))
492 current_old = 0.0_dp
493 old_current = 0.0_dp
494
495 CALL paired_matrix_dot(density, fock, current_current)
496 IF (PRESENT(density_aux)) current_current = current_current + sum(density_aux*fock_aux)
497 IF (.NOT. ieee_is_finite(current_current)) RETURN
498
499 DO islot = 1, buffer%nbuffer
500 retained = buffer%generation(islot) > 0 .AND. islot /= target_slot
501 IF (.NOT. retained) cycle
502 CALL history_current_dot(buffer, islot, fock, density, old_current(islot), current_old(islot))
503 IF (PRESENT(density_aux)) THEN
504 old_current(islot) = old_current(islot) + sum(buffer%density_aux(:, :, islot)*fock_aux)
505 current_old(islot) = current_old(islot) + sum(density_aux*buffer%fock_aux(:, :, islot))
506 END IF
507 IF (.NOT. ieee_is_finite(old_current(islot)) .OR. &
508 .NOT. ieee_is_finite(current_old(islot))) RETURN
509 END DO
510
511 DO icell = 1, SIZE(fock, 2)
512 DO ispin = 1, SIZE(fock, 1)
513 CALL dbcsr_copy(buffer%fock(target_slot, ispin, icell)%matrix, fock(ispin, icell)%matrix)
514 CALL dbcsr_copy(buffer%density(target_slot, ispin, icell)%matrix, density(ispin, icell)%matrix)
515 END DO
516 END DO
517
518 IF (PRESENT(density_aux)) THEN
519 buffer%density_aux(:, :, target_slot) = density_aux
520 buffer%fock_aux(:, :, target_slot) = fock_aux
521 END IF
522 buffer%pf_metric(target_slot, :) = 0.0_dp
523 buffer%pf_metric(:, target_slot) = 0.0_dp
524 buffer%pf_metric(target_slot, target_slot) = current_current
525 DO islot = 1, buffer%nbuffer
526 retained = buffer%generation(islot) > 0 .AND. islot /= target_slot
527 IF (.NOT. retained) cycle
528 buffer%pf_metric(islot, target_slot) = old_current(islot)
529 buffer%pf_metric(target_slot, islot) = current_old(islot)
530 END DO
531
532 buffer%ncall = buffer%ncall + 1
533 buffer%generation(target_slot) = buffer%ncall
534 buffer%state_energy(target_slot) = state_energy
535 buffer%nstored = min(buffer%nstored + 1, buffer%nbuffer)
536 pushed = .true.
537
538 END SUBROUTINE push_paired_state
539
540! **************************************************************************************************
541!> \brief Compute Tr(P F), summed across every spin and real-space cell.
542!> \param density Density matrices.
543!> \param fock Fock matrices.
544!> \param value Summed trace contraction.
545! **************************************************************************************************
546 SUBROUTINE paired_matrix_dot(density, fock, value)
547
548 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: density, fock
549 REAL(kind=dp), INTENT(OUT) :: value
550
551 INTEGER :: icell, ispin
552 REAL(kind=dp) :: contribution
553
554 value = 0.0_dp
555 DO icell = 1, SIZE(fock, 2)
556 DO ispin = 1, SIZE(fock, 1)
557 CALL dbcsr_dot(density(ispin, icell)%matrix, fock(ispin, icell)%matrix, contribution)
558 value = value + contribution
559 END DO
560 END DO
561
562 END SUBROUTINE paired_matrix_dot
563
564! **************************************************************************************************
565!> \brief Compute both cross contractions between one old and the current state.
566!> \param buffer Persistent SCF subspace history.
567!> \param islot Physical old-history slot.
568!> \param current_fock Current F[P].
569!> \param current_density Current P.
570!> \param old_current Tr(P_old F_current).
571!> \param current_old Tr(P_current F_old).
572! **************************************************************************************************
573 SUBROUTINE history_current_dot(buffer, islot, current_fock, current_density, old_current, current_old)
574
575 TYPE(qs_scf_subspace_buffer_type), INTENT(IN) :: buffer
576 INTEGER, INTENT(IN) :: islot
577 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: current_fock, current_density
578 REAL(kind=dp), INTENT(OUT) :: old_current, current_old
579
580 INTEGER :: icell, ispin
581 REAL(kind=dp) :: contribution
582
583 old_current = 0.0_dp
584 current_old = 0.0_dp
585 DO icell = 1, SIZE(current_fock, 2)
586 DO ispin = 1, SIZE(current_fock, 1)
587 CALL dbcsr_dot(buffer%density(islot, ispin, icell)%matrix, &
588 current_fock(ispin, icell)%matrix, contribution)
589 old_current = old_current + contribution
590 CALL dbcsr_dot(current_density(ispin, icell)%matrix, &
591 buffer%fock(islot, ispin, icell)%matrix, contribution)
592 current_old = current_old + contribution
593 END DO
594 END DO
595
596 END SUBROUTINE history_current_dot
597
598! **************************************************************************************************
599!> \brief Return physical slots ordered from oldest to newest.
600!> \param buffer Persistent SCF subspace history.
601!> \param slots Chronologically ordered physical slot indices.
602! **************************************************************************************************
603 PURE SUBROUTINE chronological_slots(buffer, slots)
604
605 TYPE(qs_scf_subspace_buffer_type), INTENT(IN) :: buffer
606 INTEGER, DIMENSION(:), INTENT(OUT) :: slots
607
608 INTEGER :: i, islot, j, tmp
609
610 j = 0
611 DO islot = 1, buffer%nbuffer
612 IF (buffer%generation(islot) <= 0) cycle
613 j = j + 1
614 IF (j <= SIZE(slots)) slots(j) = islot
615 END DO
616
617 ! The ADIIS model uses the most recent state as its expansion point, so
618 ! return physical slots ordered by insertion generation with the newest
619 ! state last. The history size is small, making insertion sort sufficient.
620 DO i = 2, SIZE(slots)
621 tmp = slots(i)
622 j = i - 1
623 DO WHILE (j >= 1)
624 IF (buffer%generation(slots(j)) <= buffer%generation(tmp)) EXIT
625 slots(j + 1) = slots(j)
626 j = j - 1
627 END DO
628 slots(j + 1) = tmp
629 END DO
630
631 END SUBROUTINE chronological_slots
632
633! **************************************************************************************************
634!> \brief Zero the effective KS-matrix combination.
635!> \param buffer Persistent SCF subspace history and combination target.
636! **************************************************************************************************
637 SUBROUTINE zero_fock_combination(buffer)
638
639 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
640
641 INTEGER :: icell, ispin
642
643 IF (ALLOCATED(buffer%combined_aux)) buffer%combined_aux(:, :) = 0.0_dp
644 DO icell = 1, SIZE(buffer%combined_fock, 2)
645 DO ispin = 1, SIZE(buffer%combined_fock, 1)
646 CALL dbcsr_set(buffer%combined_fock(ispin, icell)%matrix, 0.0_dp)
647 END DO
648 END DO
649
650 END SUBROUTINE zero_fock_combination
651
652! **************************************************************************************************
653!> \brief Add one physical history slot to the effective KS-matrix combination.
654!> \param buffer Persistent SCF subspace history and combination target.
655!> \param physical Physical history slot.
656!> \param coefficient Weight of this history matrix.
657! **************************************************************************************************
658 SUBROUTINE add_fock_to_combination(buffer, physical, coefficient)
659
660 TYPE(qs_scf_subspace_buffer_type), INTENT(INOUT) :: buffer
661 INTEGER, INTENT(IN) :: physical
662 REAL(kind=dp), INTENT(IN) :: coefficient
663
664 INTEGER :: icell, ispin
665
666 IF (ALLOCATED(buffer%combined_aux)) THEN
667 buffer%combined_aux(:, :) = buffer%combined_aux + coefficient*buffer%fock_aux(:, :, physical)
668 END IF
669 DO icell = 1, SIZE(buffer%combined_fock, 2)
670 DO ispin = 1, SIZE(buffer%combined_fock, 1)
671 CALL dbcsr_add(buffer%combined_fock(ispin, icell)%matrix, &
672 buffer%fock(physical, ispin, icell)%matrix, &
673 alpha_scalar=1.0_dp, beta_scalar=coefficient)
674 END DO
675 END DO
676
677 END SUBROUTINE add_fock_to_combination
678
679END MODULE qs_scf_subspace
subroutine, public dbcsr_copy(matrix_b, matrix_a, name, keep_sparsity, keep_imaginary)
...
subroutine, public dbcsr_set(matrix, alpha)
...
subroutine, public dbcsr_add(matrix_a, matrix_b, alpha_scalar, beta_scalar)
...
subroutine, public dbcsr_dot(matrix_a, matrix_b, trace)
Computes the dot product of two matrices, also known as the trace of their matrix product.
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Small, matrix-free mathematical kernels used by ADIIS.
integer, parameter, public simplex_qp_success
subroutine, public qs_scf_subspace_build_adiis_model(pf_metric, newest, hessian, linear, valid)
Construct the canonical ADIIS model relative to the newest history entry.
integer, parameter, public simplex_qp_nonfinite_input
subroutine, public simplex_quadratic_minimize(hessian, linear, coeff, objective, status, preferred_index)
Minimize a quadratic model over the probability simplex.
pure integer function, public qs_scf_subspace_fifo_slot(generation)
Select the next physical slot for a strict FIFO history.
integer, parameter, public simplex_qp_pairwise_stationary
Data types for the ADIIS SCF subspace accelerator.
pure subroutine, public qs_scf_subspace_buffer_clear(buffer)
Clear logical history while retaining allocated matrix storage.
History management and matrix combination for ADIIS.
subroutine, public qs_scf_subspace_push(buffer, fock, density, state_energy, pushed, density_aux, fock_aux)
Append one accepted, evaluated P,F[P] state to the ADIIS history.
subroutine, public qs_scf_subspace_restart(buffer, fock, density, state_energy, restarted, density_aux, fock_aux)
Restart the ADIIS history from the current strictly paired P, F[P] state.
integer, parameter, public scf_subspace_invalid_history
subroutine, public qs_scf_subspace_build(buffer)
Solve the ADIIS model from previously accepted history and form an effective KS matrix.
subroutine, public qs_scf_subspace_update_shift(buffer, shift)
Adapt candidate regularization from two evaluated states; no trial KS builds.
History buffer holding strictly paired P and F[P] SCF states.