19 USE ieee_arithmetic,
ONLY: ieee_is_finite
29#include "./base/base_uses.f90"
35 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'qs_scf_subspace'
51 REAL(kind=
dp),
INTENT(INOUT) :: shift
53 INTEGER :: newest, previous
54 REAL(kind=
dp) :: actual, predicted, tolerance
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))
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
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
77 cpassert(ieee_is_finite(shift))
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(:, :)
101 CALL qs_scf_subspace_push(buffer, fock, density, state_energy, restarted, density_aux, fock_aux)
102 IF (.NOT. restarted)
RETURN
104 buffer%coefficients = 0.0_dp
105 buffer%coefficients(1) = 1.0_dp
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
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(:, :)
135 LOGICAL :: storage_valid
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
144 IF (buffer%nbuffer < 1)
THEN
148 IF (buffer%ncall < 0 .OR. buffer%nstored < 0 .OR. buffer%nstored > buffer%nbuffer .OR. &
149 buffer%nstored /= min(buffer%ncall, buffer%nbuffer))
THEN
154 CALL ensure_matrix_storage(buffer, fock, density, storage_valid)
155 IF (.NOT. storage_valid)
THEN
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)))
169 cpassert(all(shape(buffer%combined_aux) == shape(density_aux)))
171 cpassert(.NOT.
ALLOCATED(buffer%density_aux))
173 CALL push_paired_state(buffer, fock, density, state_energy, pushed, density_aux, fock_aux)
174 IF (.NOT. pushed)
THEN
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, &
195 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: difference, linear
196 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: chronological_pf, hessian
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
204 IF (buffer%nbuffer < 1 .OR. buffer%nstored < 1)
THEN
208 IF (buffer%ncall < 0 .OR. buffer%nstored < 0 .OR. buffer%nstored > buffer%nbuffer .OR. &
209 buffer%nstored /= min(buffer%ncall, buffer%nbuffer))
THEN
214 IF (.NOT.
ASSOCIATED(buffer%fock) .OR. .NOT.
ASSOCIATED(buffer%density) .OR. &
215 .NOT.
ASSOCIATED(buffer%combined_fock))
THEN
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
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
233 ALLOCATE (slots(m), chronological_pf(m, m), hessian(m, m), linear(m))
234 CALL chronological_slots(buffer, slots)
238 chronological_pf(i, j) = buffer%pf_metric(slots(i), slots(j))
244 buffer%coefficients = 0.0_dp
245 IF (.NOT. model_valid)
THEN
251 buffer%last_objective, buffer%last_status, preferred_index=m)
255 IF (.NOT. solver_usable)
THEN
256 CALL restart_newest_after_failure(buffer, buffer%last_status)
259 IF (.NOT. ieee_is_finite(buffer%last_objective) .OR. &
260 .NOT. all(ieee_is_finite(buffer%coefficients(1:m))))
THEN
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
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
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
291 CALL zero_fock_combination(buffer)
294 IF (buffer%coefficients(j) <= 0.0_dp) cycle
295 CALL add_fock_to_combination(buffer, physical, buffer%coefficients(j))
297 buffer%use_combined_fock = .true.
306 SUBROUTINE restart_newest_after_failure(buffer, failure_status)
309 INTEGER,
INTENT(IN) :: failure_status
311 INTEGER :: icell, ispin, newest
312 REAL(kind=
dp) :: contribution, newest_energy, newest_pf
314 IF (buffer%nstored < 1)
THEN
315 buffer%last_status = failure_status
318 IF (count(buffer%generation > 0) /= buffer%nstored)
THEN
319 buffer%last_status = failure_status
322 newest = maxloc(buffer%generation, dim=1)
323 newest_energy = buffer%state_energy(newest)
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
332 IF (
ALLOCATED(buffer%density_aux))
THEN
333 newest_pf = newest_pf + sum(buffer%density_aux(:, :, newest)*buffer%fock_aux(:, :, newest))
335 IF (.NOT. ieee_is_finite(newest_energy) .OR. .NOT. ieee_is_finite(newest_pf))
THEN
336 buffer%last_status = failure_status
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
357 END SUBROUTINE restart_newest_after_failure
366 SUBROUTINE ensure_matrix_storage(buffer, fock, density, valid)
369 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: fock, density
370 LOGICAL,
INTENT(OUT) :: valid
372 INTEGER :: icell, islot, ispin, ncell, nspin
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
383 valid =
ASSOCIATED(fock(ispin, icell)%matrix) .AND. &
384 ASSOCIATED(density(ispin, icell)%matrix)
385 IF (.NOT. valid)
RETURN
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
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
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
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
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)
452 ALLOCATE (buffer%combined_fock(ispin, icell)%matrix)
453 CALL dbcsr_create(buffer%combined_fock(ispin, icell)%matrix, &
454 template=fock(ispin, icell)%matrix)
458 END SUBROUTINE ensure_matrix_storage
470 SUBROUTINE push_paired_state(buffer, fock, density, state_energy, pushed, density_aux, fock_aux)
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(:, :)
478 INTEGER :: icell, islot, ispin, target_slot
480 REAL(kind=
dp) :: current_current
481 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: current_old, old_current
484 IF (.NOT. ieee_is_finite(state_energy))
RETURN
489 IF (target_slot <= 0)
RETURN
491 ALLOCATE (current_old(buffer%nbuffer), old_current(buffer%nbuffer))
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
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))
507 IF (.NOT. ieee_is_finite(old_current(islot)) .OR. &
508 .NOT. ieee_is_finite(current_old(islot)))
RETURN
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)
518 IF (
PRESENT(density_aux))
THEN
519 buffer%density_aux(:, :, target_slot) = density_aux
520 buffer%fock_aux(:, :, target_slot) = fock_aux
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)
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)
538 END SUBROUTINE push_paired_state
546 SUBROUTINE paired_matrix_dot(density, fock, value)
548 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: density, fock
549 REAL(kind=
dp),
INTENT(OUT) ::
value
551 INTEGER :: icell, ispin
552 REAL(kind=
dp) :: contribution
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
562 END SUBROUTINE paired_matrix_dot
573 SUBROUTINE history_current_dot(buffer, islot, current_fock, current_density, old_current, current_old)
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
580 INTEGER :: icell, ispin
581 REAL(kind=
dp) :: contribution
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
596 END SUBROUTINE history_current_dot
603 PURE SUBROUTINE chronological_slots(buffer, slots)
606 INTEGER,
DIMENSION(:),
INTENT(OUT) :: slots
608 INTEGER :: i, islot, j, tmp
611 DO islot = 1, buffer%nbuffer
612 IF (buffer%generation(islot) <= 0) cycle
614 IF (j <=
SIZE(slots)) slots(j) = islot
620 DO i = 2,
SIZE(slots)
624 IF (buffer%generation(slots(j)) <= buffer%generation(tmp))
EXIT
625 slots(j + 1) = slots(j)
631 END SUBROUTINE chronological_slots
637 SUBROUTINE zero_fock_combination(buffer)
641 INTEGER :: icell, ispin
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)
650 END SUBROUTINE zero_fock_combination
658 SUBROUTINE add_fock_to_combination(buffer, physical, coefficient)
661 INTEGER,
INTENT(IN) :: physical
662 REAL(kind=
dp),
INTENT(IN) :: coefficient
664 INTEGER :: icell, ispin
666 IF (
ALLOCATED(buffer%combined_aux))
THEN
667 buffer%combined_aux(:, :) = buffer%combined_aux + coefficient*buffer%fock_aux(:, :, physical)
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)
677 END SUBROUTINE add_fock_to_combination
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.
integer, parameter, public dp
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.