19 USE ieee_arithmetic,
ONLY: ieee_is_finite
29#include "./base/base_uses.f90"
35 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'qs_scf_subspace'
54 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: fock, density
55 REAL(kind=
dp),
INTENT(IN) :: state_energy
56 LOGICAL,
INTENT(OUT) :: restarted
61 IF (.NOT. restarted)
RETURN
63 buffer%coefficients = 0.0_dp
64 buffer%coefficients(1) = 1.0_dp
66 buffer%last_restart = .true.
67 buffer%use_combined_fock = .false.
68 buffer%last_objective = 0.0_dp
69 buffer%last_old_fock_weight = 0.0_dp
87 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: fock, density
88 REAL(kind=
dp),
INTENT(IN) :: state_energy
89 LOGICAL,
INTENT(OUT) :: pushed
91 LOGICAL :: storage_valid
94 buffer%use_combined_fock = .false.
95 buffer%last_restart = .false.
96 buffer%last_objective = 0.0_dp
97 buffer%last_old_fock_weight = 0.0_dp
98 IF (
ALLOCATED(buffer%coefficients)) buffer%coefficients = 0.0_dp
100 IF (buffer%nbuffer < 1)
THEN
104 IF (buffer%ncall < 0 .OR. buffer%nstored < 0 .OR. buffer%nstored > buffer%nbuffer .OR. &
105 buffer%nstored /= min(buffer%ncall, buffer%nbuffer))
THEN
110 CALL ensure_matrix_storage(buffer, fock, density, storage_valid)
111 IF (.NOT. storage_valid)
THEN
116 CALL push_paired_state(buffer, fock, density, state_energy, pushed)
117 IF (.NOT. pushed)
THEN
133 INTEGER :: i, j, m, physical
134 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: slots
135 LOGICAL :: model_valid, solver_usable
136 REAL(kind=
dp) :: coefficient_sum, model_delta, &
138 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: difference, linear
139 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: chronological_pf, hessian
141 buffer%use_combined_fock = .false.
142 buffer%last_restart = .false.
143 buffer%last_objective = 0.0_dp
144 buffer%last_old_fock_weight = 0.0_dp
145 IF (
ALLOCATED(buffer%coefficients)) buffer%coefficients = 0.0_dp
147 IF (buffer%nbuffer < 1 .OR. buffer%nstored < 1)
THEN
151 IF (buffer%ncall < 0 .OR. buffer%nstored < 0 .OR. buffer%nstored > buffer%nbuffer .OR. &
152 buffer%nstored /= min(buffer%ncall, buffer%nbuffer))
THEN
157 IF (.NOT.
ASSOCIATED(buffer%fock) .OR. .NOT.
ASSOCIATED(buffer%density) .OR. &
158 .NOT.
ASSOCIATED(buffer%combined_fock))
THEN
162 IF (.NOT.
ALLOCATED(buffer%generation) .OR. .NOT.
ALLOCATED(buffer%pf_metric) .OR. &
163 .NOT.
ALLOCATED(buffer%coefficients) .OR. .NOT.
ALLOCATED(buffer%state_energy))
THEN
167 IF (
SIZE(buffer%generation) /= buffer%nbuffer .OR. &
168 SIZE(buffer%pf_metric, 1) /= buffer%nbuffer .OR.
SIZE(buffer%pf_metric, 2) /= buffer%nbuffer .OR. &
169 SIZE(buffer%coefficients) /= buffer%nbuffer .OR.
SIZE(buffer%state_energy) /= buffer%nbuffer .OR. &
170 count(buffer%generation > 0) /= buffer%nstored .OR. any(buffer%generation < 0))
THEN
176 ALLOCATE (slots(m), chronological_pf(m, m), hessian(m, m), linear(m))
177 CALL chronological_slots(buffer, slots)
181 chronological_pf(i, j) = buffer%pf_metric(slots(i), slots(j))
187 buffer%coefficients = 0.0_dp
188 IF (.NOT. model_valid)
THEN
194 buffer%last_objective, buffer%last_status, preferred_index=m)
198 IF (.NOT. solver_usable)
THEN
199 CALL restart_newest_after_failure(buffer, buffer%last_status)
202 IF (.NOT. ieee_is_finite(buffer%last_objective) .OR. &
203 .NOT. all(ieee_is_finite(buffer%coefficients(1:m))))
THEN
208 coefficient_sum = sum(buffer%coefficients(1:m))
209 IF (minval(buffer%coefficients(1:m)) < -100.0_dp*epsilon(1.0_dp) .OR. &
210 abs(coefficient_sum - 1.0_dp) > 1000.0_dp*epsilon(1.0_dp))
THEN
215 ALLOCATE (difference(m))
216 difference(:) = buffer%coefficients(1:m)
217 difference(m) = difference(m) - 1.0_dp
218 model_delta = 0.5_dp*dot_product(difference, matmul(hessian, difference)) + &
219 dot_product(difference, hessian(:, m) + linear)
220 model_tolerance = 1000.0_dp*epsilon(1.0_dp)*real(m, kind=
dp)* &
221 max(1.0_dp, maxval(abs(hessian)), maxval(abs(linear)))
222 IF (.NOT. ieee_is_finite(model_delta) .OR. model_delta > model_tolerance)
THEN
223 IF (ieee_is_finite(model_delta))
THEN
231 buffer%last_old_fock_weight = max(0.0_dp, 1.0_dp - buffer%coefficients(m))
232 IF (buffer%last_old_fock_weight <= 100.0_dp*epsilon(1.0_dp))
RETURN
234 CALL zero_fock_combination(buffer)
237 IF (buffer%coefficients(j) <= 0.0_dp) cycle
238 CALL add_fock_to_combination(buffer, physical, buffer%coefficients(j))
240 buffer%use_combined_fock = .true.
249 SUBROUTINE restart_newest_after_failure(buffer, failure_status)
252 INTEGER,
INTENT(IN) :: failure_status
254 INTEGER :: icell, ispin, newest
255 REAL(kind=
dp) :: contribution, newest_energy, newest_pf
257 IF (buffer%nstored < 1)
THEN
258 buffer%last_status = failure_status
261 IF (count(buffer%generation > 0) /= buffer%nstored)
THEN
262 buffer%last_status = failure_status
265 newest = maxloc(buffer%generation, dim=1)
266 newest_energy = buffer%state_energy(newest)
268 DO icell = 1,
SIZE(buffer%fock, 3)
269 DO ispin = 1,
SIZE(buffer%fock, 2)
270 CALL dbcsr_dot(buffer%density(newest, ispin, icell)%matrix, &
271 buffer%fock(newest, ispin, icell)%matrix, contribution)
272 newest_pf = newest_pf + contribution
275 IF (.NOT. ieee_is_finite(newest_energy) .OR. .NOT. ieee_is_finite(newest_pf))
THEN
276 buffer%last_status = failure_status
282 buffer%generation = 0
283 buffer%generation(newest) = 1
284 buffer%state_energy = huge(1.0_dp)
285 buffer%state_energy(newest) = newest_energy
286 buffer%pf_metric = 0.0_dp
287 buffer%pf_metric(newest, newest) = newest_pf
288 buffer%coefficients = 0.0_dp
289 buffer%coefficients(1) = 1.0_dp
290 buffer%last_status = failure_status
291 buffer%last_restart = .true.
292 buffer%use_combined_fock = .false.
293 buffer%diis_state_valid = .false.
294 buffer%last_objective = 0.0_dp
295 buffer%last_old_fock_weight = 0.0_dp
296 buffer%diis_weight = 0.0_dp
298 END SUBROUTINE restart_newest_after_failure
307 SUBROUTINE ensure_matrix_storage(buffer, fock, density, valid)
310 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: fock, density
311 LOGICAL,
INTENT(OUT) :: valid
313 INTEGER :: icell, islot, ispin, ncell, nspin
315 valid =
ASSOCIATED(fock) .AND.
ASSOCIATED(density)
316 IF (.NOT. valid)
RETURN
317 nspin =
SIZE(fock, 1)
318 ncell =
SIZE(fock, 2)
319 valid = nspin > 0 .AND. ncell > 0 .AND. &
320 SIZE(density, 1) == nspin .AND.
SIZE(density, 2) == ncell
321 IF (.NOT. valid)
RETURN
324 valid =
ASSOCIATED(fock(ispin, icell)%matrix) .AND. &
325 ASSOCIATED(density(ispin, icell)%matrix)
326 IF (.NOT. valid)
RETURN
330 IF (
ASSOCIATED(buffer%fock))
THEN
331 valid =
SIZE(buffer%fock, 1) == buffer%nbuffer .AND. &
332 SIZE(buffer%fock, 2) == nspin .AND.
SIZE(buffer%fock, 3) == ncell
333 IF (.NOT. valid)
RETURN
334 valid =
ASSOCIATED(buffer%density)
335 IF (.NOT. valid)
RETURN
336 valid =
SIZE(buffer%density, 1) == buffer%nbuffer .AND. &
337 SIZE(buffer%density, 2) == nspin .AND.
SIZE(buffer%density, 3) == ncell
338 IF (.NOT. valid)
RETURN
339 valid =
ASSOCIATED(buffer%combined_fock)
340 IF (.NOT. valid)
RETURN
341 valid =
SIZE(buffer%combined_fock, 1) == nspin .AND. &
342 SIZE(buffer%combined_fock, 2) == ncell
343 IF (.NOT. valid)
RETURN
344 valid =
ALLOCATED(buffer%generation) .AND.
ALLOCATED(buffer%pf_metric) .AND. &
345 ALLOCATED(buffer%coefficients) .AND.
ALLOCATED(buffer%state_energy)
346 IF (.NOT. valid)
RETURN
347 valid =
SIZE(buffer%generation) == buffer%nbuffer .AND. &
348 SIZE(buffer%pf_metric, 1) == buffer%nbuffer .AND. &
349 SIZE(buffer%pf_metric, 2) == buffer%nbuffer .AND. &
350 SIZE(buffer%coefficients) == buffer%nbuffer .AND. &
351 SIZE(buffer%state_energy) == buffer%nbuffer
352 IF (.NOT. valid)
RETURN
355 valid =
ASSOCIATED(buffer%combined_fock(ispin, icell)%matrix)
356 IF (.NOT. valid)
RETURN
357 DO islot = 1, buffer%nbuffer
358 valid =
ASSOCIATED(buffer%fock(islot, ispin, icell)%matrix) .AND. &
359 ASSOCIATED(buffer%density(islot, ispin, icell)%matrix)
360 IF (.NOT. valid)
RETURN
367 valid = .NOT.
ASSOCIATED(buffer%density) .AND. &
368 .NOT.
ASSOCIATED(buffer%combined_fock) .AND. .NOT.
ALLOCATED(buffer%generation) .AND. &
369 .NOT.
ALLOCATED(buffer%pf_metric) .AND. .NOT.
ALLOCATED(buffer%coefficients) .AND. &
370 .NOT.
ALLOCATED(buffer%state_energy)
371 IF (.NOT. valid)
RETURN
373 ALLOCATE (buffer%fock(buffer%nbuffer, nspin, ncell))
374 ALLOCATE (buffer%density(buffer%nbuffer, nspin, ncell))
375 ALLOCATE (buffer%combined_fock(nspin, ncell))
376 ALLOCATE (buffer%generation(buffer%nbuffer), buffer%state_energy(buffer%nbuffer))
377 ALLOCATE (buffer%pf_metric(buffer%nbuffer, buffer%nbuffer), buffer%coefficients(buffer%nbuffer))
378 buffer%generation = 0
379 buffer%state_energy = huge(1.0_dp)
380 buffer%pf_metric = 0.0_dp
381 buffer%coefficients = 0.0_dp
385 DO islot = 1, buffer%nbuffer
386 ALLOCATE (buffer%fock(islot, ispin, icell)%matrix)
387 CALL dbcsr_create(buffer%fock(islot, ispin, icell)%matrix, &
388 template=fock(ispin, icell)%matrix)
389 ALLOCATE (buffer%density(islot, ispin, icell)%matrix)
390 CALL dbcsr_create(buffer%density(islot, ispin, icell)%matrix, &
391 template=density(ispin, icell)%matrix)
393 ALLOCATE (buffer%combined_fock(ispin, icell)%matrix)
394 CALL dbcsr_create(buffer%combined_fock(ispin, icell)%matrix, &
395 template=fock(ispin, icell)%matrix)
399 END SUBROUTINE ensure_matrix_storage
409 SUBROUTINE push_paired_state(buffer, fock, density, state_energy, pushed)
412 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: fock, density
413 REAL(kind=
dp),
INTENT(IN) :: state_energy
414 LOGICAL,
INTENT(OUT) :: pushed
416 INTEGER :: icell, islot, ispin, target_slot
418 REAL(kind=
dp) :: current_current
419 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: current_old, old_current
422 IF (.NOT. ieee_is_finite(state_energy))
RETURN
427 IF (target_slot <= 0)
RETURN
429 ALLOCATE (current_old(buffer%nbuffer), old_current(buffer%nbuffer))
433 CALL paired_matrix_dot(density, fock, current_current)
434 IF (.NOT. ieee_is_finite(current_current))
RETURN
436 DO islot = 1, buffer%nbuffer
437 retained = buffer%generation(islot) > 0 .AND. islot /= target_slot
438 IF (.NOT. retained) cycle
439 CALL history_current_dot(buffer, islot, fock, density, old_current(islot), current_old(islot))
440 IF (.NOT. ieee_is_finite(old_current(islot)) .OR. &
441 .NOT. ieee_is_finite(current_old(islot)))
RETURN
444 DO icell = 1,
SIZE(fock, 2)
445 DO ispin = 1,
SIZE(fock, 1)
446 CALL dbcsr_copy(buffer%fock(target_slot, ispin, icell)%matrix, fock(ispin, icell)%matrix)
447 CALL dbcsr_copy(buffer%density(target_slot, ispin, icell)%matrix, density(ispin, icell)%matrix)
451 buffer%pf_metric(target_slot, :) = 0.0_dp
452 buffer%pf_metric(:, target_slot) = 0.0_dp
453 buffer%pf_metric(target_slot, target_slot) = current_current
454 DO islot = 1, buffer%nbuffer
455 retained = buffer%generation(islot) > 0 .AND. islot /= target_slot
456 IF (.NOT. retained) cycle
457 buffer%pf_metric(islot, target_slot) = old_current(islot)
458 buffer%pf_metric(target_slot, islot) = current_old(islot)
461 buffer%ncall = buffer%ncall + 1
462 buffer%generation(target_slot) = buffer%ncall
463 buffer%state_energy(target_slot) = state_energy
464 buffer%nstored = min(buffer%nstored + 1, buffer%nbuffer)
467 END SUBROUTINE push_paired_state
475 SUBROUTINE paired_matrix_dot(density, fock, value)
477 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: density, fock
478 REAL(kind=
dp),
INTENT(OUT) ::
value
480 INTEGER :: icell, ispin
481 REAL(kind=
dp) :: contribution
484 DO icell = 1,
SIZE(fock, 2)
485 DO ispin = 1,
SIZE(fock, 1)
486 CALL dbcsr_dot(density(ispin, icell)%matrix, fock(ispin, icell)%matrix, contribution)
487 value =
value + contribution
491 END SUBROUTINE paired_matrix_dot
502 SUBROUTINE history_current_dot(buffer, islot, current_fock, current_density, old_current, current_old)
505 INTEGER,
INTENT(IN) :: islot
506 TYPE(
dbcsr_p_type),
DIMENSION(:, :),
POINTER :: current_fock, current_density
507 REAL(kind=
dp),
INTENT(OUT) :: old_current, current_old
509 INTEGER :: icell, ispin
510 REAL(kind=
dp) :: contribution
514 DO icell = 1,
SIZE(current_fock, 2)
515 DO ispin = 1,
SIZE(current_fock, 1)
516 CALL dbcsr_dot(buffer%density(islot, ispin, icell)%matrix, &
517 current_fock(ispin, icell)%matrix, contribution)
518 old_current = old_current + contribution
519 CALL dbcsr_dot(current_density(ispin, icell)%matrix, &
520 buffer%fock(islot, ispin, icell)%matrix, contribution)
521 current_old = current_old + contribution
525 END SUBROUTINE history_current_dot
532 PURE SUBROUTINE chronological_slots(buffer, slots)
535 INTEGER,
DIMENSION(:),
INTENT(OUT) :: slots
537 INTEGER :: i, islot, j, tmp
540 DO islot = 1, buffer%nbuffer
541 IF (buffer%generation(islot) <= 0) cycle
543 IF (j <=
SIZE(slots)) slots(j) = islot
549 DO i = 2,
SIZE(slots)
553 IF (buffer%generation(slots(j)) <= buffer%generation(tmp))
EXIT
554 slots(j + 1) = slots(j)
560 END SUBROUTINE chronological_slots
566 SUBROUTINE zero_fock_combination(buffer)
570 INTEGER :: icell, ispin
572 DO icell = 1,
SIZE(buffer%combined_fock, 2)
573 DO ispin = 1,
SIZE(buffer%combined_fock, 1)
574 CALL dbcsr_set(buffer%combined_fock(ispin, icell)%matrix, 0.0_dp)
578 END SUBROUTINE zero_fock_combination
586 SUBROUTINE add_fock_to_combination(buffer, physical, coefficient)
589 INTEGER,
INTENT(IN) :: physical
590 REAL(kind=
dp),
INTENT(IN) :: coefficient
592 INTEGER :: icell, ispin
594 DO icell = 1,
SIZE(buffer%combined_fock, 2)
595 DO ispin = 1,
SIZE(buffer%combined_fock, 1)
596 CALL dbcsr_add(buffer%combined_fock(ispin, icell)%matrix, &
597 buffer%fock(physical, ispin, icell)%matrix, &
598 alpha_scalar=1.0_dp, beta_scalar=coefficient)
602 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.
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_restart(buffer, fock, density, state_energy, restarted)
Restart the ADIIS history from the current strictly paired P, F[P] state.
subroutine, public qs_scf_subspace_push(buffer, fock, density, state_energy, pushed)
Append one accepted, evaluated P,F[P] state to the ADIIS history.
History buffer holding strictly paired P and F[P] SCF states.