66#include "./base/base_uses.f90"
72 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'bse_davidson'
75 REAL(KIND=
dp),
PARAMETER,
PRIVATE :: deg_thresh = 1.0e-6_dp
77 REAL(KIND=
dp),
PARAMETER,
PRIVATE :: ortho_tol = 1.0e-8_dp
83 INTEGER,
PARAMETER,
PRIVATE :: driver_tda = 1, driver_mk = 2, driver_os = 3
108 INTEGER,
INTENT(IN) :: unit_nr
109 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
110 INTENT(OUT) :: exc_ens
113 CHARACTER(LEN=*),
PARAMETER :: routinen =
'bse_davidson_tda'
115 INTEGER :: block_size, handle, iter, k, m, m_max, &
116 n_act, n_cand, n_dependent, n_kernel, &
117 n_ov, n_req, n_restart, n_want, nt
118 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: selected
119 LOGICAL :: all_conv, has_prev, stalled
120 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: conv, need
121 REAL(kind=
dp) :: dev, t_iter
122 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: de,
diag, res, theta, theta_prev, &
124 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: coef_restart, coef_restart_cand, &
125 coef_ritz, coef_ritz_theta, red_block
128 TYPE(
cp_fm_type) :: fm_az, fm_red_a, fm_work, fm_z
131 CALL timeset(routinen, handle)
136 para_env => mv_env%para_env
138 cpassert(mv_env%blacs_env%num_pe(2) == 1)
140 NULLIFY (diag_blacs_env)
143 CALL davidson_sizes(bse_env, n_ov, unit_nr, n_want, n_act, block_size)
145 ALLOCATE (
diag(n_ov))
148 CALL subspace_ceiling(bse_env, mv_env, driver_tda, n_act, block_size, unit_nr, m_max)
151 CALL cp_fm_create(fm_z, fm_struct, name=
"fm_Z_davidson", set_zero=.true.)
152 CALL cp_fm_create(fm_az, fm_struct, name=
"fm_AZ_davidson", set_zero=.true.)
155 CALL cp_fm_create(fm_work, fm_struct, name=
"fm_work_davidson", set_zero=.true.)
159 nrow_global=m_max, ncol_global=m_max)
160 CALL cp_fm_create(fm_red_a, fm_struct, name=
"fm_red_A_davidson", set_zero=.true.)
164 ALLOCATE (coef_ritz(m_max, n_act), coef_restart_cand(m_max, 2*n_act), coef_ritz_theta(m_max, n_act))
165 ALLOCATE (coef_restart(m_max, 2*n_act))
166 ALLOCATE (theta(m_max), theta_prev(n_act), res(n_act), de(n_act), conv(n_act), need(n_act), &
168 coef_restart_cand(:, :) = 0.0_dp
169 theta_prev(:) = 0.0_dp
175 IF (bse_env%num_guess_transitions > 0)
THEN
176 CALL initial_guess_subblock(mv_env, bse_env,
diag, n_act, m_max, deg_thresh, fm_z, m, theta_sub, &
179 CALL initial_guess(
diag, n_act, m_max, deg_thresh, fm_z, m)
182 IF (extension_deviation(fm_z, fm_z, 0, m, para_env) > ortho_tol)
THEN
183 cpabort(
"BSE Davidson: the initial guess is not orthonormal")
188 CALL reduced_gram_blocks(fm_z, m, fm_az, 1, m, block_size, para_env, fm_red_a)
190 CALL print_iteration_header(
'Block Davidson iterations within the TDA:', unit_nr)
193 DO iter = 1, bse_env%max_iter
197 CALL solve_reduced(fm_red_a, m, n_act, para_env, diag_blacs_env, theta, coef_ritz)
201 IF (m + block_size > m_max .AND. m > n_act .AND. m < n_ov)
THEN
202 coef_restart_cand(1:m, 1:n_act) = coef_ritz(1:m, 1:n_act)
204 IF (has_prev) n_cand = 2*n_act
205 CALL restart_basis(coef_restart_cand, m, n_cand, 2*n_act, coef_restart, k)
206 CALL rotate_in_place(fm_z, m, coef_restart, k, fm_work, fm_az)
207 CALL reduced_rotate(fm_red_a, m, coef_restart, k, para_env, diag_blacs_env)
209 n_restart = n_restart + 1
210 CALL solve_reduced(fm_red_a, m, n_act, para_env, diag_blacs_env, theta, coef_ritz)
215 coef_ritz_theta(1:m, k) = coef_ritz(1:m, k)*theta(k)
217 CALL subspace_rotate(fm_az, m, coef_ritz(1:m, 1:n_act), n_act, fm_work, 1.0_dp, 0.0_dp)
218 CALL subspace_rotate(fm_z, m, coef_ritz_theta(1:m, 1:n_act), n_act, fm_work, -1.0_dp, 1.0_dp)
219 CALL column_norms(fm_work, 1, n_act, para_env, res)
221 CALL convergence_step(bse_env, theta, theta_prev, res, m, n_ov, n_want, iter, t_iter, unit_nr, &
222 de, conv, n_req, need)
223 all_conv = .NOT. any(need)
226 IF (iter == bse_env%max_iter)
EXIT
229 CALL select_roots(bse_env, need, res, min(block_size, m_max - m), selected, nt)
230 CALL davidson_corrections(fm_work, selected(1:nt), theta,
diag, fm_z, m + 1)
231 CALL extend_orthonormal(fm_z, m, nt, para_env, n_dependent)
234 IF (nt == 0 .AND. stalled)
THEN
235 cpabort(
"BSE Davidson: correction vectors vanished before convergence")
239 IF (extension_deviation(fm_z, fm_z, m, nt, para_env) > ortho_tol)
THEN
240 cpabort(
"BSE Davidson: the basis lost orthonormality")
245 n_kernel = n_kernel + nt
248 ALLOCATE (red_block(m + nt, nt))
249 CALL subspace_gram(fm_z, 1, m + nt, fm_az, m + 1, nt, para_env, red_block)
250 CALL reduced_extend(fm_red_a, red_block, m, nt)
251 DEALLOCATE (red_block)
255 coef_restart_cand(:, n_act + 1:2*n_act) = 0.0_dp
256 coef_restart_cand(1:m, n_act + 1:2*n_act) = coef_ritz(1:m, 1:n_act)
258 theta_prev(:) = theta(1:n_act)
262 IF (.NOT. all_conv)
CALL abort_unconverged(theta, res, conv, need, n_req, unit_nr)
263 IF (bse_env%bse_debug_print)
CALL print_tracked_roots(theta, res, n_want, n_act, unit_nr)
265 IF (bse_env%bse_debug_print)
THEN
266 dev = orthonormality_deviation(fm_z, fm_z, m, block_size, para_env)
267 IF (unit_nr > 0)
THEN
268 WRITE (unit_nr,
'(T2,A10,T13,A,T63,ES18.6)')
'BSE|DEBUG|', &
269 'Max deviation of the basis from orthonormality', dev
273 IF (
ALLOCATED(theta_sub))
CALL check_guess_bound(theta_sub, theta, n_req, unit_nr)
274 CALL print_summary(iter, n_kernel, n_restart, n_want, n_req, n_act, n_ov, unit_nr, n_dependent=n_dependent)
276 ALLOCATE (exc_ens(n_want))
277 exc_ens(:) = theta(1:n_want)
279 CALL cp_fm_create(fm_x, fm_struct, name=
"fm_X_davidson", set_zero=.true.)
282 CALL subspace_rotate(fm_z, m, coef_ritz(1:m, 1:n_want), n_want, fm_x, 1.0_dp, 0.0_dp)
289 DEALLOCATE (coef_ritz, coef_restart_cand, coef_ritz_theta, coef_restart, theta, theta_prev, res, de, conv, &
290 need, selected,
diag)
291 IF (
ALLOCATED(theta_sub))
DEALLOCATE (theta_sub)
293 CALL timestop(handle)
323 INTEGER,
INTENT(IN) :: unit_nr
324 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
325 INTENT(OUT) :: exc_ens
327 INTEGER,
INTENT(OUT) :: abba_status
328 REAL(kind=
dp),
INTENT(OUT) :: ab_margin
329 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_x_tda
331 CHARACTER(LEN=*),
PARAMETER :: routinen =
'bse_davidson_abba_mk'
333 INTEGER :: block_size, guess_col, handle, iter, k, m, m_max, n_act, n_cand, n_dependent, &
334 n_guess_cols, n_kernel, n_ov, n_req, n_restart, n_seed, n_want, nrow_local, nt, nt_guess
335 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: selected
336 LOGICAL :: all_conv, has_prev, stalled
337 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: conv, need
338 REAL(kind=
dp) :: dev, t_iter
339 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: de,
diag, diag_sq, omega, omega_prev, &
340 omega_sq, res, theta, theta_sub
341 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: coef_restart, coef_restart_cand, &
342 coef_ritz, coef_x, coef_x_omega, &
346 TYPE(
cp_fm_type) :: fm_metric, fm_metric_vec, fm_mw, &
347 fm_red_m, fm_scratch, fm_v, fm_w, &
351 CALL timeset(routinen, handle)
360 para_env => mv_env%para_env
362 cpassert(mv_env%blacs_env%num_pe(2) == 1)
364 NULLIFY (diag_blacs_env)
367 CALL davidson_sizes(bse_env, n_ov, unit_nr, n_want, n_act, block_size)
369 ALLOCATE (
diag(n_ov))
372 CALL subspace_ceiling(bse_env, mv_env, driver_mk, n_act, block_size, unit_nr, m_max)
375 CALL cp_fm_create(fm_v, fm_struct, name=
"fm_V_davidson", set_zero=.true.)
376 CALL cp_fm_create(fm_w, fm_struct, name=
"fm_W_davidson", set_zero=.true.)
377 CALL cp_fm_create(fm_mw, fm_struct, name=
"fm_MW_davidson", set_zero=.true.)
380 CALL cp_fm_create(fm_work, fm_struct, name=
"fm_work_davidson", set_zero=.true.)
383 CALL cp_fm_create(fm_scratch, fm_struct, name=
"fm_scratch_davidson", set_zero=.true.)
387 nrow_global=m_max, ncol_global=m_max)
388 CALL cp_fm_create(fm_red_m, fm_struct, name=
"fm_red_M_davidson", set_zero=.true.)
393 ALLOCATE (coef_ritz(m_max, n_act), coef_restart_cand(m_max, 2*n_act), coef_restart(m_max, 2*n_act))
394 ALLOCATE (coef_x(m_max, n_act), coef_y(m_max, n_act), coef_x_omega(m_max, n_act))
395 ALLOCATE (theta(m_max), omega(n_act), omega_prev(n_act), res(n_act), de(n_act), conv(n_act), &
396 need(n_act), selected(n_act))
397 coef_restart_cand(:, :) = 0.0_dp
398 omega_prev(:) = 0.0_dp
409 IF (
PRESENT(fm_x_tda))
THEN
411 n_seed = min(n_seed, n_act)
414 IF (bse_env%num_guess_transitions > 0)
THEN
415 CALL initial_guess_subblock(mv_env, bse_env,
diag, n_act, m_max, deg_thresh, fm_v, n_guess_cols, theta_sub, &
416 unit_nr, n_seed, abba_status, ab_margin)
418 CALL initial_guess(
diag, n_act, m_max, deg_thresh, fm_v, n_guess_cols, n_seed)
421 ALLOCATE (diag_sq(n_ov))
422 diag_sq(:) =
diag(:)**2
427 DO WHILE (guess_col <= n_guess_cols)
428 nt_guess = min(block_size, n_guess_cols - guess_col + 1)
430 IF (guess_col > m + 1)
THEN
433 CALL extend_basis_mk(mv_env, fm_v, fm_w, fm_mw, fm_scratch, m, nt, n_kernel, n_dependent, abba_status, &
435 IF (abba_status /=
abba_ok)
EXIT
436 guess_col = guess_col + nt_guess
440 IF (abba_status ==
abba_ok)
THEN
441 fm_v%local_data(1:nrow_local, m + 1:n_guess_cols) = 0.0_dp
443 CALL reduced_gram_blocks(fm_w, m, fm_mw, 1, m, block_size, para_env, fm_red_m)
445 CALL print_iteration_header(
'Block Davidson iterations for ABBA, (A+B)(A-B) x = E^2 x:', unit_nr)
447 DO iter = 1, bse_env%max_iter
451 CALL solve_reduced(fm_red_m, m, n_act, para_env, diag_blacs_env, theta, coef_ritz)
455 IF (m + block_size > m_max .AND. m > n_act .AND. m < n_ov)
THEN
456 coef_restart_cand(1:m, 1:n_act) = coef_ritz(1:m, 1:n_act)
458 IF (has_prev) n_cand = 2*n_act
459 CALL restart_basis(coef_restart_cand, m, n_cand, 2*n_act, coef_restart, k)
460 CALL rotate_in_place(fm_v, m, coef_restart, k, fm_work, fm_w, fm_mw)
461 CALL reduced_rotate(fm_red_m, m, coef_restart, k, para_env, diag_blacs_env)
463 n_restart = n_restart + 1
464 CALL solve_reduced(fm_red_m, m, n_act, para_env, diag_blacs_env, theta, coef_ritz)
468 IF (theta(1) <= 0.0_dp)
THEN
469 CALL cp_abort(__location__, &
470 "BSE Davidson (MK_DAVIDSON): negative squared excitation energy. Matrix "// &
471 "(A+B) is not positive definite, or the basis lost its orthonormality.")
473 omega(:) = sqrt(theta(1:n_act))
477 coef_y(1:m, k) = coef_ritz(1:m, k)/sqrt(omega(k))
478 coef_x_omega(1:m, k) = coef_ritz(1:m, k)*omega(k)*sqrt(omega(k))
480 CALL subspace_rotate(fm_mw, m, coef_y(1:m, 1:n_act), n_act, fm_work, 1.0_dp, 0.0_dp)
481 CALL subspace_rotate(fm_v, m, coef_x_omega(1:m, 1:n_act), n_act, fm_work, -1.0_dp, 1.0_dp)
482 CALL column_norms(fm_work, 1, n_act, para_env, res)
484 CALL convergence_step(bse_env, omega, omega_prev, res, m, n_ov, n_want, iter, t_iter, unit_nr, &
485 de, conv, n_req, need)
486 all_conv = .NOT. any(need)
489 IF (iter == bse_env%max_iter)
EXIT
492 CALL select_roots(bse_env, need, res, min(block_size, m_max - m), selected, nt)
493 CALL davidson_corrections(fm_work, selected(1:nt), theta, diag_sq, fm_v, m + 1)
494 CALL extend_basis_mk(mv_env, fm_v, fm_w, fm_mw, fm_scratch, m, nt, n_kernel, n_dependent, abba_status, &
496 IF (abba_status /=
abba_ok)
EXIT
499 IF (nt == 0 .AND. stalled)
THEN
500 cpabort(
"BSE Davidson: correction vectors vanished before convergence")
506 ALLOCATE (red_block(m + nt, nt))
507 CALL subspace_gram(fm_w, 1, m + nt, fm_mw, m + 1, nt, para_env, red_block)
508 CALL reduced_extend(fm_red_m, red_block, m, nt)
509 DEALLOCATE (red_block)
513 coef_restart_cand(:, n_act + 1:2*n_act) = 0.0_dp
514 coef_restart_cand(1:m, n_act + 1:2*n_act) = coef_ritz(1:m, 1:n_act)
516 omega_prev(:) = omega(:)
521 IF (abba_status ==
abba_ok)
THEN
522 IF (.NOT. all_conv)
CALL abort_unconverged(omega, res, conv, need, n_req, unit_nr)
523 IF (bse_env%bse_debug_print)
CALL print_tracked_roots(omega, res, n_want, n_act, unit_nr)
525 IF (bse_env%bse_debug_print)
THEN
526 dev = orthonormality_deviation(fm_v, fm_w, m, block_size, para_env)
527 IF (unit_nr > 0)
THEN
528 WRITE (unit_nr,
'(T2,A10,T13,A,T63,ES18.6)')
'BSE|DEBUG|', &
529 'Max deviation of the basis from orthonormality', dev
537 nrow_global=m, ncol_global=m)
538 CALL cp_fm_create(fm_metric, fm_struct, name=
"bse_basis_metric")
539 CALL cp_fm_create(fm_metric_vec, fm_struct, name=
"bse_basis_metric_vectors")
541 CALL reduced_gram_blocks(fm_v, m, fm_v, 1, m, block_size, para_env, fm_metric)
542 ALLOCATE (omega_sq(m))
545 ab_margin = 1.0_dp/omega_sq(m)
546 DEALLOCATE (omega_sq)
550 IF (
ALLOCATED(theta_sub))
CALL check_guess_bound(theta_sub, omega, n_req, unit_nr)
551 CALL print_summary(iter, n_kernel, n_restart, n_want, n_req, n_act, n_ov, unit_nr, ab_margin, n_dependent)
555 ALLOCATE (exc_ens(n_want))
556 exc_ens(:) = omega(1:n_want)
558 coef_x(1:m, k) = coef_ritz(1:m, k)*sqrt(omega(k))
559 coef_y(1:m, k) = coef_ritz(1:m, k)/sqrt(omega(k))
562 CALL cp_fm_create(fm_x, fm_struct, name=
"fm_X_davidson", set_zero=.true.)
563 CALL cp_fm_create(fm_y, fm_struct, name=
"fm_Y_davidson", set_zero=.true.)
565 CALL subspace_rotate(fm_w, m, coef_y(1:m, 1:n_want), n_want, fm_x, 0.5_dp, 0.0_dp)
566 CALL subspace_rotate(fm_v, m, coef_x(1:m, 1:n_want), n_want, fm_x, 0.5_dp, 1.0_dp)
567 CALL subspace_rotate(fm_w, m, coef_y(1:m, 1:n_want), n_want, fm_y, 0.5_dp, 0.0_dp)
568 CALL subspace_rotate(fm_v, m, coef_x(1:m, 1:n_want), n_want, fm_y, -0.5_dp, 1.0_dp)
578 DEALLOCATE (coef_ritz, coef_restart_cand, coef_x, coef_y, coef_x_omega, coef_restart, theta, omega, omega_prev, &
579 res, de, conv, need, selected,
diag, diag_sq)
580 IF (
ALLOCATED(theta_sub))
DEALLOCATE (theta_sub)
582 CALL timestop(handle)
613 INTEGER,
INTENT(IN) :: unit_nr
614 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
615 INTENT(OUT) :: exc_ens
617 INTEGER,
INTENT(OUT) :: abba_status
618 REAL(kind=
dp),
INTENT(OUT) :: ab_margin
619 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_x_tda
621 CHARACTER(LEN=*),
PARAMETER :: routinen =
'bse_davidson_abba_os'
623 INTEGER :: block_size, guess_col, handle, iter, k, m, m_max, n_act, n_cand, n_dependent, &
624 n_guess_cols, n_kernel, n_ov, n_pair, n_req, n_restart, n_seed, n_want, nrow_local, nt, &
625 nt_guess, nt_l, nt_r, nt_sel
626 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: selected
627 LOGICAL :: all_conv, has_prev, stalled
628 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: conv, need
629 REAL(kind=
dp) :: dev, kr_min, t_iter
630 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: de,
diag, omega, omega_prev, res, res_l, &
632 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: coef_left, coef_restart, &
633 coef_restart_cand, coef_right, &
634 coef_work, red_block_k, red_block_m
637 TYPE(
cp_fm_type) :: fm_b, fm_kb, fm_mb, fm_red_k, fm_red_m, &
641 CALL timeset(routinen, handle)
651 para_env => mv_env%para_env
653 cpassert(mv_env%blacs_env%num_pe(2) == 1)
655 NULLIFY (diag_blacs_env)
658 CALL davidson_sizes(bse_env, n_ov, unit_nr, n_want, n_act, block_size)
660 ALLOCATE (
diag(n_ov))
663 CALL subspace_ceiling(bse_env, mv_env, driver_os, n_act, block_size, unit_nr, m_max)
666 CALL cp_fm_create(fm_b, fm_struct, name=
"fm_b_davidson", set_zero=.true.)
667 CALL cp_fm_create(fm_mb, fm_struct, name=
"fm_Mb_davidson", set_zero=.true.)
668 CALL cp_fm_create(fm_kb, fm_struct, name=
"fm_Kb_davidson", set_zero=.true.)
672 CALL cp_fm_create(fm_work, fm_struct, name=
"fm_work_davidson", set_zero=.true.)
675 CALL cp_fm_create(fm_scratch, fm_struct, name=
"fm_scratch_davidson", set_zero=.true.)
679 nrow_global=m_max, ncol_global=m_max)
680 CALL cp_fm_create(fm_red_m, fm_struct, name=
"fm_red_M_davidson", set_zero=.true.)
681 CALL cp_fm_create(fm_red_k, fm_struct, name=
"fm_red_K_davidson", set_zero=.true.)
686 ALLOCATE (coef_right(m_max, n_act), coef_left(m_max, n_act), coef_work(m_max, n_act))
687 ALLOCATE (coef_restart_cand(m_max, 4*n_act), coef_restart(m_max, 4*n_act))
688 ALLOCATE (omega(n_act), omega_prev(n_act), res(n_act), res_l(n_act), de(n_act), conv(n_act), &
689 need(n_act), selected(n_act))
690 coef_restart_cand(:, :) = 0.0_dp
691 omega_prev(:) = 0.0_dp
703 IF (
PRESENT(fm_x_tda))
THEN
705 n_seed = min(n_seed, n_act)
709 IF (bse_env%num_guess_transitions > 0)
THEN
710 CALL initial_guess_subblock(mv_env, bse_env,
diag, n_act, m_max, deg_thresh, fm_b, n_guess_cols, theta_sub, &
711 unit_nr, n_seed, abba_status, ab_margin, n_pair)
713 CALL initial_guess(
diag, n_act, m_max, deg_thresh, fm_b, n_guess_cols, n_seed)
715 n_guess_cols = n_guess_cols + n_pair
720 DO WHILE (guess_col <= n_guess_cols)
721 nt_guess = min(2*block_size, n_guess_cols - guess_col + 1)
723 IF (guess_col > m + 1)
THEN
726 CALL extend_basis_os(mv_env, fm_b, fm_mb, fm_kb, fm_scratch, m, nt, n_kernel, n_dependent)
727 guess_col = guess_col + nt_guess
731 IF (abba_status ==
abba_ok)
THEN
732 fm_b%local_data(1:nrow_local, m + 1:n_guess_cols) = 0.0_dp
734 CALL reduced_gram_blocks(fm_b, m, fm_mb, 1, m, block_size, para_env, fm_red_m)
735 CALL reduced_gram_blocks(fm_b, m, fm_kb, 1, m, block_size, para_env, fm_red_k)
737 CALL print_iteration_header(
'Block Davidson iterations for ABBA, Olsen-Stratmann paired subspace:', &
740 DO iter = 1, bse_env%max_iter
744 CALL solve_reduced_paired(fm_red_m, fm_red_k, m, n_act, para_env, omega, coef_right, coef_left, kr_min, &
745 abba_status, diag_blacs_env)
748 IF (abba_status /=
abba_ok)
EXIT
753 IF (m + 2*block_size > m_max .AND. m > 2*n_act .AND. m < n_ov)
THEN
754 coef_restart_cand(1:m, 1:n_act) = coef_right(1:m, :)
755 coef_restart_cand(1:m, n_act + 1:2*n_act) = coef_left(1:m, :)
757 IF (has_prev) n_cand = 4*n_act
758 CALL restart_basis(coef_restart_cand, m, n_cand, m_max - 2*block_size, coef_restart, k)
759 CALL rotate_in_place(fm_b, m, coef_restart, k, fm_work, fm_mb, fm_kb)
760 CALL reduced_rotate(fm_red_m, m, coef_restart, k, para_env, diag_blacs_env)
761 CALL reduced_rotate(fm_red_k, m, coef_restart, k, para_env, diag_blacs_env)
763 n_restart = n_restart + 1
764 CALL solve_reduced_paired(fm_red_m, fm_red_k, m, n_act, para_env, omega, coef_right, coef_left, kr_min, &
765 abba_status, diag_blacs_env)
767 IF (abba_status /=
abba_ok)
EXIT
773 coef_work(1:m, k) = coef_left(1:m, k)*omega(k)
775 CALL subspace_rotate(fm_mb, m, coef_right(1:m, 1:n_act), n_act, fm_work, 1.0_dp, 0.0_dp)
776 CALL subspace_rotate(fm_b, m, coef_work(1:m, 1:n_act), n_act, fm_work, -1.0_dp, 1.0_dp)
778 coef_work(1:m, k) = coef_right(1:m, k)*omega(k)
780 CALL subspace_rotate(fm_kb, m, coef_left(1:m, 1:n_act), n_act, fm_work, 1.0_dp, 0.0_dp, n_act + 1)
781 CALL subspace_rotate(fm_b, m, coef_work(1:m, 1:n_act), n_act, fm_work, -1.0_dp, 1.0_dp, n_act + 1)
782 CALL column_norms(fm_work, 1, n_act, para_env, res)
783 CALL column_norms(fm_work, n_act + 1, n_act, para_env, res_l)
784 res(:) = max(res(:), res_l(:))
786 CALL convergence_step(bse_env, omega, omega_prev, res, m, n_ov, n_want, iter, t_iter, unit_nr, &
787 de, conv, n_req, need)
788 all_conv = .NOT. any(need)
791 IF (iter == bse_env%max_iter)
EXIT
796 CALL select_roots(bse_env, need, res, min(block_size, (m_max - m + 1)/2), selected, nt_sel)
798 CALL davidson_corrections(fm_work, selected(1:nt_r), omega,
diag, fm_b, m + 1)
799 CALL extend_basis_os(mv_env, fm_b, fm_mb, fm_kb, fm_scratch, m, nt_r, n_kernel, n_dependent)
800 nt_l = min(nt_sel, m_max - m - nt_r)
801 CALL davidson_corrections(fm_work, selected(1:nt_l), omega,
diag, fm_b, m + nt_r + 1, n_act)
802 CALL extend_basis_os(mv_env, fm_b, fm_mb, fm_kb, fm_scratch, m + nt_r, nt_l, n_kernel, n_dependent)
806 IF (nt == 0 .AND. stalled)
THEN
807 cpabort(
"BSE Davidson: correction vectors vanished before convergence")
813 ALLOCATE (red_block_m(m + nt, nt), red_block_k(m + nt, nt))
814 CALL subspace_gram(fm_b, 1, m + nt, fm_mb, m + 1, nt, para_env, red_block_m)
815 CALL subspace_gram(fm_b, 1, m + nt, fm_kb, m + 1, nt, para_env, red_block_k)
816 CALL reduced_extend(fm_red_m, red_block_m, m, nt)
817 CALL reduced_extend(fm_red_k, red_block_k, m, nt)
818 DEALLOCATE (red_block_m, red_block_k)
822 coef_restart_cand(:, 2*n_act + 1:4*n_act) = 0.0_dp
823 coef_restart_cand(1:m, 2*n_act + 1:3*n_act) = coef_right(1:m, :)
824 coef_restart_cand(1:m, 3*n_act + 1:4*n_act) = coef_left(1:m, :)
826 omega_prev(:) = omega(:)
831 IF (abba_status ==
abba_ok)
THEN
832 IF (.NOT. all_conv)
CALL abort_unconverged(omega, res, conv, need, n_req, unit_nr)
833 IF (bse_env%bse_debug_print)
CALL print_tracked_roots(omega, res, n_want, n_act, unit_nr)
835 IF (bse_env%bse_debug_print)
THEN
836 dev = orthonormality_deviation(fm_b, fm_b, m, block_size, para_env)
837 IF (unit_nr > 0)
THEN
838 WRITE (unit_nr,
'(T2,A10,T13,A,T63,ES18.6)')
'BSE|DEBUG|', &
839 'Max deviation of the basis from orthonormality', dev
843 IF (
ALLOCATED(theta_sub))
CALL check_guess_bound(theta_sub, omega, n_req, unit_nr)
844 CALL print_summary(iter, n_kernel, n_restart, n_want, n_req, n_act, n_ov, unit_nr, ab_margin, n_dependent)
847 ALLOCATE (exc_ens(n_want))
848 exc_ens(:) = omega(1:n_want)
850 CALL cp_fm_create(fm_x, fm_struct, name=
"fm_X_davidson", set_zero=.true.)
851 CALL cp_fm_create(fm_y, fm_struct, name=
"fm_Y_davidson", set_zero=.true.)
853 coef_work(1:m, 1:n_want) = 0.5_dp*(coef_right(1:m, 1:n_want) + coef_left(1:m, 1:n_want))
854 CALL subspace_rotate(fm_b, m, coef_work(1:m, 1:n_want), n_want, fm_x, 1.0_dp, 0.0_dp)
855 coef_work(1:m, 1:n_want) = 0.5_dp*(coef_right(1:m, 1:n_want) - coef_left(1:m, 1:n_want))
856 CALL subspace_rotate(fm_b, m, coef_work(1:m, 1:n_want), n_want, fm_y, 1.0_dp, 0.0_dp)
867 DEALLOCATE (coef_right, coef_left, coef_work, coef_restart_cand, coef_restart, omega, omega_prev, res, res_l, &
868 de, conv, need, selected,
diag)
869 IF (
ALLOCATED(theta_sub))
DEALLOCATE (theta_sub)
871 CALL timestop(handle)
892 SUBROUTINE extend_basis_mk(mv_env, fm_V, fm_W, fm_MW, fm_scratch, m, nt, n_kernel, n_dependent, abba_status, &
896 TYPE(
cp_fm_type),
INTENT(IN) :: fm_v, fm_w, fm_mw, fm_scratch
897 INTEGER,
INTENT(IN) :: m
898 INTEGER,
INTENT(INOUT) :: nt, n_kernel, n_dependent, abba_status
899 REAL(kind=
dp),
INTENT(INOUT) :: ab_margin
901 CHARACTER(LEN=*),
PARAMETER :: routinen =
'extend_basis_mk'
905 CALL timeset(routinen, handle)
908 CALL extend_orthonormal(fm_v, m, nt, mv_env%para_env, n_dependent, fm_w)
913 CALL columns_axpy(-1.0_dp, fm_scratch, 1, fm_w, m + 1, nt)
914 n_kernel = n_kernel + nt
917 CALL cholqr2_metric(fm_v, fm_w, m + 1, nt, mv_env%para_env, abba_status, ab_margin)
919 IF (abba_status ==
abba_ok)
THEN
921 IF (extension_deviation(fm_v, fm_w, m, nt, mv_env%para_env) > ortho_tol)
THEN
922 cpabort(
"BSE Davidson: the basis lost orthonormality in the (A-B) inner product")
926 CALL columns_axpy(1.0_dp, fm_scratch, 1, fm_mw, m + 1, nt)
927 n_kernel = n_kernel + nt
931 CALL timestop(handle)
933 END SUBROUTINE extend_basis_mk
949 SUBROUTINE cholqr2_metric(fm_T, fm_KT, first_col, nt, para_env, abba_status, eig_min)
952 INTEGER,
INTENT(IN) :: first_col, nt
954 INTEGER,
INTENT(INOUT) :: abba_status
955 REAL(kind=
dp),
INTENT(INOUT) :: eig_min
957 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cholqr2_metric'
959 INTEGER :: handle, info, ipass, k, n_ov, n_pass, &
961 REAL(kind=
dp) :: shift
962 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigval
963 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: chol_factor, gram, gram_raw
965 CALL timeset(routinen, handle)
966 CALL cp_fm_get_info(fm_t, nrow_local=nrow_local, nrow_global=n_ov)
967 ALLOCATE (gram_raw(nt, nt), gram(nt, nt), chol_factor(nt, nt), eigval(nt))
971 DO WHILE (ipass < n_pass)
974 CALL subspace_gram(fm_t, first_col, nt, fm_kt, first_col, nt, para_env, gram_raw)
975 gram(:, :) = 0.5_dp*(gram_raw(:, :) + transpose(gram_raw(:, :)))
976 chol_factor(:, :) = gram(:, :)
978 IF (para_env%is_source())
CALL dpotrf(
'U', nt, chol_factor, nt, info)
979 CALL para_env%bcast(info)
981 IF (n_pass == 3)
THEN
982 CALL cp_abort(__location__, &
983 "BSE Davidson: orthonormalisation in the (A-B) inner product broke down")
985 chol_factor(:, :) = gram(:, :)
987 IF (para_env%is_source())
CALL diamat_all(chol_factor, eigval)
988 CALL para_env%bcast(eigval)
989 IF (eigval(1) < 0.0_dp)
THEN
997 shift = 11.0_dp*(real(n_ov,
dp)*real(nt,
dp) + real(nt,
dp)*real(nt + 1,
dp))* &
998 epsilon(1.0_dp)*norm2(gram)
999 chol_factor(:, :) = gram(:, :)
1001 chol_factor(k, k) = chol_factor(k, k) + shift
1003 IF (para_env%is_source())
CALL dpotrf(
'U', nt, chol_factor, nt, info)
1004 CALL para_env%bcast(info)
1006 CALL cp_abort(__location__, &
1007 "BSE Davidson: orthonormalisation in the (A-B) inner product broke down")
1011 CALL para_env%bcast(chol_factor)
1012 IF (nrow_local > 0)
THEN
1013 CALL dtrsm(
'R',
'U',
'N',
'N', nrow_local, nt, 1.0_dp, chol_factor, nt, &
1014 fm_t%local_data(:, first_col:first_col + nt - 1),
SIZE(fm_t%local_data, 1))
1015 CALL dtrsm(
'R',
'U',
'N',
'N', nrow_local, nt, 1.0_dp, chol_factor, nt, &
1016 fm_kt%local_data(:, first_col:first_col + nt - 1),
SIZE(fm_kt%local_data, 1))
1020 DEALLOCATE (gram_raw, gram, chol_factor, eigval)
1021 CALL timestop(handle)
1023 END SUBROUTINE cholqr2_metric
1049 SUBROUTINE solve_reduced_paired(fm_red_M, fm_red_K, m, n_act, para_env, omega, coef_right, coef_left, kr_min, &
1050 abba_status, blacs_env)
1052 TYPE(
cp_fm_type),
INTENT(IN) :: fm_red_m, fm_red_k
1053 INTEGER,
INTENT(IN) :: m, n_act
1055 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: omega
1056 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT) :: coef_right, coef_left
1057 REAL(kind=
dp),
INTENT(OUT) :: kr_min
1058 INTEGER,
INTENT(INOUT) :: abba_status
1061 CHARACTER(LEN=*),
PARAMETER :: routinen =
'solve_reduced_paired'
1064 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: kappa, lambda
1066 TYPE(
cp_fm_type) :: fm_h, fm_h_eigvec, fm_k_eigvec, &
1067 fm_k_sqrt, fm_l, fm_mr, fm_r, fm_work
1069 CALL timeset(routinen, handle)
1071 cpassert(n_act <= m)
1076 ALLOCATE (kappa(m), lambda(m))
1079 nrow_global=m, ncol_global=m)
1080 CALL cp_fm_create(fm_k_eigvec, fm_struct, name=
"bse_paired_U")
1081 CALL cp_fm_create(fm_k_sqrt, fm_struct, name=
"bse_paired_S")
1082 CALL cp_fm_create(fm_mr, fm_struct, name=
"bse_paired_Mr")
1083 CALL cp_fm_create(fm_h, fm_struct, name=
"bse_paired_H")
1084 CALL cp_fm_create(fm_h_eigvec, fm_struct, name=
"bse_paired_T")
1085 CALL cp_fm_create(fm_work, fm_struct, name=
"bse_paired_work")
1090 CALL symmetrise_in_place(fm_work, fm_k_eigvec)
1095 IF (kappa(1) <= 0.0_dp)
THEN
1101 CALL parallel_gemm(
'N',
'T', m, m, m, 1.0_dp, fm_work, fm_k_eigvec, 0.0_dp, fm_k_sqrt)
1105 CALL symmetrise_in_place(fm_mr, fm_h_eigvec)
1106 CALL parallel_gemm(
'N',
'N', m, m, m, 1.0_dp, fm_mr, fm_k_sqrt, 0.0_dp, fm_work)
1107 CALL parallel_gemm(
'N',
'N', m, m, m, 1.0_dp, fm_k_sqrt, fm_work, 0.0_dp, fm_h)
1112 IF (lambda(1) <= 0.0_dp)
THEN
1113 CALL cp_abort(__location__, &
1114 "BSE Davidson (OLSEN_STRATMANN): negative squared excitation energy. Matrix "// &
1115 "(A+B) is not positive definite on the trial space, or the basis lost its "// &
1118 omega(1:n_act) = sqrt(lambda(1:n_act))
1123 nrow_global=m, ncol_global=n_act)
1124 CALL cp_fm_create(fm_r, fm_struct, name=
"bse_paired_R")
1125 CALL cp_fm_create(fm_l, fm_struct, name=
"bse_paired_L")
1127 CALL parallel_gemm(
'N',
'N', m, n_act, m, 1.0_dp, fm_k_sqrt, fm_h_eigvec, 0.0_dp, fm_r)
1129 CALL parallel_gemm(
'N',
'N', m, n_act, m, 1.0_dp, fm_mr, fm_r, 0.0_dp, fm_l)
1132 coef_right(:, :) = 0.0_dp
1133 coef_left(:, :) = 0.0_dp
1146 DEALLOCATE (kappa, lambda)
1147 CALL timestop(handle)
1149 END SUBROUTINE solve_reduced_paired
1167 SUBROUTINE extend_basis_os(mv_env, fm_b, fm_Mb, fm_Kb, fm_scratch, m, nt, n_kernel, n_dependent)
1170 TYPE(
cp_fm_type),
INTENT(IN) :: fm_b, fm_mb, fm_kb, fm_scratch
1171 INTEGER,
INTENT(IN) :: m
1172 INTEGER,
INTENT(INOUT) :: nt, n_kernel, n_dependent
1174 CHARACTER(LEN=*),
PARAMETER :: routinen =
'extend_basis_os'
1178 CALL timeset(routinen, handle)
1180 CALL extend_orthonormal(fm_b, m, nt, mv_env%para_env, n_dependent)
1184 IF (extension_deviation(fm_b, fm_b, m, nt, mv_env%para_env) > ortho_tol)
THEN
1185 cpabort(
"BSE Davidson: the basis lost orthonormality")
1190 CALL columns_axpy(-1.0_dp, fm_scratch, 1, fm_kb, m + 1, nt)
1191 CALL columns_axpy(1.0_dp, fm_scratch, 1, fm_mb, m + 1, nt)
1192 n_kernel = n_kernel + nt
1195 CALL timestop(handle)
1197 END SUBROUTINE extend_basis_os
1218 SUBROUTINE convergence_step(bse_env, energies, energies_prev, res, m, n_ov, n_want, iter, t_iter, unit_nr, &
1219 dE, conv, n_req, need)
1222 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: energies, energies_prev, res
1223 INTEGER,
INTENT(IN) :: m, n_ov, n_want, iter
1224 REAL(kind=
dp),
INTENT(IN) :: t_iter
1225 INTEGER,
INTENT(IN) :: unit_nr
1226 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: de
1227 LOGICAL,
DIMENSION(:),
INTENT(OUT) :: conv
1228 INTEGER,
INTENT(OUT) :: n_req
1229 LOGICAL,
DIMENSION(:),
INTENT(OUT) :: need
1234 de(:) = abs(energies(1:n_act) - energies_prev(1:n_act))
1235 CALL convergence_flags(bse_env, de, res, conv)
1236 n_req = multiplet_end(energies, n_want, n_act, deg_thresh)
1238 IF (m == n_ov) conv(:) = .true.
1239 CALL roots_in_need(conv, energies, res, n_req, need)
1241 CALL print_iteration(iter, m, count(conv(1:n_want)), &
1242 max(maxval(res(1:n_req)), maxval(res, mask=need)), &
1243 maxval(de(1:n_req)), energies(1),
m_walltime() - t_iter, unit_nr)
1245 END SUBROUTINE convergence_step
1255 SUBROUTINE convergence_flags(bse_env, dE, res, conv)
1258 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: de, res
1259 LOGICAL,
DIMENSION(:),
INTENT(OUT) :: conv
1263 DO k = 1,
SIZE(conv)
1264 SELECT CASE (bse_env%convergence_criterion)
1266 conv(k) = de(k) < bse_env%eps_energy
1268 conv(k) = res(k) < bse_env%eps_res
1270 conv(k) = de(k) < bse_env%eps_energy .OR. res(k) < bse_env%eps_res
1272 conv(k) = de(k) < bse_env%eps_energy .AND. res(k) < bse_env%eps_res
1276 END SUBROUTINE convergence_flags
1287 PURE FUNCTION multiplet_end(energies, n_first, n_limit, thresh)
RESULT(n_last)
1289 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: energies
1290 INTEGER,
INTENT(IN) :: n_first, n_limit
1291 REAL(kind=
dp),
INTENT(IN) :: thresh
1295 DO WHILE (n_last < n_limit)
1296 IF (energies(n_last + 1) - energies(n_last) >= thresh)
EXIT
1300 END FUNCTION multiplet_end
1312 SUBROUTINE roots_in_need(conv, energies, res, n_req, need)
1314 LOGICAL,
DIMENSION(:),
INTENT(IN) :: conv
1315 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: energies, res
1316 INTEGER,
INTENT(IN) :: n_req
1317 LOGICAL,
DIMENSION(:),
INTENT(OUT) :: need
1321 DO k = 1,
SIZE(need)
1322 need(k) = .NOT. conv(k)
1323 IF (k > n_req) need(k) = need(k) .AND. energies(k) - res(k) < energies(n_req)
1326 END SUBROUTINE roots_in_need
1337 SUBROUTINE select_roots(bse_env, need, res, n_max, selected, nt)
1340 LOGICAL,
DIMENSION(:),
INTENT(IN) :: need
1341 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: res
1342 INTEGER,
INTENT(IN) :: n_max
1343 INTEGER,
DIMENSION(:),
INTENT(OUT) :: selected
1344 INTEGER,
INTENT(OUT) :: nt
1350 DO k = 1,
SIZE(need)
1351 IF (.NOT. need(k)) cycle
1354 res(k) < bse_env%eps_res) cycle
1355 IF (nt == n_max)
EXIT
1360 END SUBROUTINE select_roots
1367 SUBROUTINE print_iteration_header(title, unit_nr)
1369 CHARACTER(LEN=*),
INTENT(IN) :: title
1370 INTEGER,
INTENT(IN) :: unit_nr
1372 IF (unit_nr > 0)
THEN
1373 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1374 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', title
1375 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1376 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
1377 '|r| in a.u., energies in eV, t the wall time of the iteration'
1378 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1379 WRITE (unit_nr,
'(T2,A4,T7,A5,T14,A8,T24,A6,T33,A12,T47,A12,T61,A12,T74,A7)')
'BSE|', &
1380 'Iter.',
'Z-space',
'Conv.',
'Max |r|',
'Max dE',
'Lowest E',
't (s)'
1383 END SUBROUTINE print_iteration_header
1396 SUBROUTINE print_iteration(iter, m, n_conv, max_res, max_dE, lowest_E, t_iter, unit_nr)
1398 INTEGER,
INTENT(IN) :: iter, m, n_conv
1399 REAL(kind=
dp),
INTENT(IN) :: max_res, max_de, lowest_e, t_iter
1400 INTEGER,
INTENT(IN) :: unit_nr
1402 IF (unit_nr > 0)
THEN
1403 WRITE (unit_nr,
'(T2,A4,T7,I5,T14,I8,T24,I6,T33,ES12.4,T47,ES12.4,T61,F12.6,T74,F7.2)') &
1404 'BSE|', iter, m, n_conv, max_res, max_de*
evolt, lowest_e*
evolt, t_iter
1407 END SUBROUTINE print_iteration
1418 SUBROUTINE abort_unconverged(energies, res, conv, need, n_req, unit_nr)
1420 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: energies, res
1421 LOGICAL,
DIMENSION(:),
INTENT(IN) :: conv, need
1422 INTEGER,
INTENT(IN) :: n_req, unit_nr
1426 IF (unit_nr > 0)
THEN
1427 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1428 WRITE (unit_nr,
'(T2,A4,T7,A12,T30,A11,T50,A10,T67,A14)')
'BSE|', &
1429 'Excitation n',
'Energy (eV)',
'|r| (a.u.)',
'Converged'
1430 DO k = 1,
SIZE(need)
1431 IF (k > n_req .AND. .NOT. need(k)) cycle
1432 WRITE (unit_nr,
'(T2,A4,T7,I12,T27,F14.6,T46,ES14.4,T67,L14)')
'BSE|', &
1433 k, energies(k)*
evolt, res(k), conv(k)
1437 cpabort(
"BSE Davidson: MAX_ITER reached before convergence")
1439 END SUBROUTINE abort_unconverged
1449 SUBROUTINE print_tracked_roots(energies, res, n_want, n_act, unit_nr)
1451 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: energies, res
1452 INTEGER,
INTENT(IN) :: n_want, n_act, unit_nr
1456 IF (unit_nr > 0)
THEN
1457 WRITE (unit_nr,
'(T2,A10,T13,A13,T27,A9,T45,A18,T67,A14)')
'BSE|DEBUG|', &
1458 'Tracked state',
'Requested',
'Energy (eV)',
'|r| (a.u.)'
1460 WRITE (unit_nr,
'(T2,A10,T13,I13,T27,L9,T45,F18.10,T67,ES14.4)')
'BSE|DEBUG|', &
1461 k, k <= n_want, energies(k)*
evolt, res(k)
1465 END SUBROUTINE print_tracked_roots
1481 SUBROUTINE print_summary(iter, n_kernel, n_restart, n_want, n_req, n_act, n_ov, unit_nr, ab_margin, &
1484 INTEGER,
INTENT(IN) :: iter, n_kernel, n_restart, n_want, &
1485 n_req, n_act, n_ov, unit_nr
1486 REAL(kind=
dp),
INTENT(IN),
OPTIONAL :: ab_margin
1487 INTEGER,
INTENT(IN),
OPTIONAL :: n_dependent
1489 IF (unit_nr > 0)
THEN
1490 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1491 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Davidson iterations', iter
1492 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Kernel applications', n_kernel
1493 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Thick restarts', n_restart
1494 IF (
PRESENT(n_dependent))
THEN
1495 IF (n_dependent > 0)
THEN
1496 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Correction vectors dropped as dependent', n_dependent
1499 IF (
PRESENT(ab_margin))
THEN
1500 WRITE (unit_nr,
'(T2,A4,T7,A,T65,F16.6)')
'BSE|', &
1501 'A-B margin on the trial space (eV)', ab_margin*
evolt
1503 IF (n_req > n_want)
THEN
1504 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
1505 'Note: the requested states end inside a degenerate multiplet.'
1507 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1510 IF (n_req > n_want .AND. n_req == n_act .AND. n_act < n_ov .AND. unit_nr > 0)
THEN
1511 CALL cp_warn(__location__, &
1512 "BSE Davidson: the degenerate group at NUM_EXC_EN reaches the last buffer state, "// &
1513 "further members may lie above it. Increase BSE_ITERAT%NUM_BUFFER_STATES.")
1516 END SUBROUTINE print_summary
1527 SUBROUTINE davidson_sizes(bse_env, n_ov, unit_nr, n_want, n_act, block_size)
1530 INTEGER,
INTENT(IN) :: n_ov, unit_nr
1531 INTEGER,
INTENT(OUT) :: n_want, n_act, block_size
1533 IF (bse_env%num_exc_en < 1) cpabort(
"BSE_ITERAT%NUM_EXC_EN must be at least 1")
1534 IF (bse_env%num_buffer_states < 0) cpabort(
"BSE_ITERAT%NUM_BUFFER_STATES must not be negative")
1535 IF (bse_env%block_size < 1 .AND. bse_env%block_size /= -1)
THEN
1536 cpabort(
"BSE_ITERAT%BLOCK_SIZE must be at least 1, or -1 for the default")
1538 IF (bse_env%max_iter < 1) cpabort(
"BSE_ITERAT%MAX_ITER must be at least 1")
1540 n_want = bse_env%num_exc_en
1541 IF (n_want > n_ov)
THEN
1542 IF (unit_nr > 0)
CALL cp_warn(__location__, &
1543 "BSE_ITERAT%NUM_EXC_EN exceeds the number of transitions and is reduced to it.")
1546 n_act = min(n_want + bse_env%num_buffer_states, n_ov)
1547 block_size = bse_env%block_size
1549 IF (block_size == -1) block_size = min(32, n_act)
1550 IF (block_size > n_act)
THEN
1551 IF (unit_nr > 0)
CALL cp_warn(__location__, &
1552 "BSE_ITERAT%BLOCK_SIZE exceeds the number of tracked states and is reduced to it.")
1556 END SUBROUTINE davidson_sizes
1570 SUBROUTINE subspace_ceiling(bse_env, mv_env, driver, n_act, block_size, unit_nr, m_max)
1574 INTEGER,
INTENT(IN) :: driver, n_act, block_size, unit_nr
1575 INTEGER,
INTENT(OUT) :: m_max
1577 CHARACTER(LEN=16) :: bud_str, fac_str, mem_str
1578 INTEGER :: m_floor, m_hi, m_lo, m_mid, m_start, &
1579 min_fac, n_ri_max, nb
1580 LOGICAL :: from_free, over, skipped
1581 REAL(kind=
dp) :: budget_gb, dist_gb, mem_avail_gb, repl_gb
1586 IF (driver == driver_os)
THEN
1591 WRITE (fac_str,
'(I16)') min_fac
1594 IF (bse_env%max_subspace_factor == -1)
THEN
1596 ELSE IF (bse_env%max_subspace_factor >= min_fac)
THEN
1597 m_start = bse_env%max_subspace_factor*n_act
1599 CALL cp_abort(__location__, &
1600 "BSE_ITERAT%MAX_SUBSPACE_FACTOR must be at least "//trim(adjustl(fac_str))// &
1601 " (or -1) for the chosen solver")
1603 m_floor = min(min_fac*n_act, mv_env%n_ov)
1604 m_start = min(max(m_start, m_floor), mv_env%n_ov)
1609 SELECT CASE (driver)
1617 IF (mv_env%block_cols > 0) nb = min(nb, mv_env%block_cols)
1618 n_ri_max = mv_env%n_ri_loc
1619 CALL mv_env%para_env%max(n_ri_max)
1622 from_free = bse_env%memory_budget_gb < 0.0_dp
1624 budget_gb = bse_env%memory_budget_gb
1628 skipped = mem_avail_gb <= 0.0_dp
1629 IF (skipped .AND. bse_env%memory_check /=
bse_memcheck_off .AND. unit_nr > 0)
THEN
1630 CALL cp_warn(__location__,
"BSE Davidson: free memory not detectable, memory check skipped")
1634 CALL davidson_footprint(driver, mv_env, m_max, n_act, block_size, nb, n_ri_max, dist_gb, repl_gb)
1635 over = .NOT. skipped .AND. bse_env%memory_check /=
bse_memcheck_off .AND. &
1636 dist_gb + repl_gb > budget_gb
1639 CALL davidson_footprint(driver, mv_env, m_floor, n_act, block_size, nb, n_ri_max, dist_gb, repl_gb)
1640 IF (dist_gb + repl_gb > budget_gb)
THEN
1641 WRITE (mem_str,
'(F16.3)') dist_gb + repl_gb
1642 WRITE (bud_str,
'(F16.3)') budget_gb
1643 CALL cp_abort(__location__, &
1644 "BSE Davidson: not enough memory for the smallest subspace of "//trim(adjustl(fac_str))// &
1645 " vectors per state: "//trim(adjustl(mem_str))//
" GB per MPI rank, the budget is "// &
1646 trim(adjustl(bud_str))//
" GB. Raise MEMORY_BUDGET_GB or use more MPI ranks.")
1651 DO WHILE (m_hi - m_lo > 1)
1652 m_mid = (m_lo + m_hi)/2
1653 CALL davidson_footprint(driver, mv_env, m_mid, n_act, block_size, nb, n_ri_max, dist_gb, repl_gb)
1654 IF (dist_gb + repl_gb <= budget_gb)
THEN
1661 CALL davidson_footprint(driver, mv_env, m_max, n_act, block_size, nb, n_ri_max, dist_gb, repl_gb)
1664 IF (unit_nr > 0)
THEN
1665 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1666 IF (bse_env%max_subspace_factor == -1)
THEN
1667 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Maximum subspace dimension (20 x buffered states)', &
1670 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Maximum subspace dimension (MAX_SUBSPACE_FACTOR)', &
1673 IF (m_max < m_start)
THEN
1674 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Maximum subspace dimension after the memory check', &
1677 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory per MPI rank at the subspace ceiling (GB)'
1678 WRITE (unit_nr,
'(T2,A4,T9,A,T67,F14.3)')
'BSE|',
'Distributed arrays', dist_gb
1679 WRITE (unit_nr,
'(T2,A4,T9,A,T67,F14.3)')
'BSE|',
'Replicated arrays', repl_gb
1680 WRITE (unit_nr,
'(T2,A4,T9,A,T67,F14.3)')
'BSE|',
'Total', dist_gb + repl_gb
1681 IF (.NOT. skipped)
THEN
1683 WRITE (unit_nr,
'(T2,A4,T7,A,T67,F14.3)')
'BSE|',
'Fraction of the free memory made available', &
1686 WRITE (unit_nr,
'(T2,A4,T7,A,T67,F14.3)')
'BSE|',
'Memory budget per MPI rank (GB)', budget_gb
1688 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
1690 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: OFF'
1691 ELSE IF (skipped)
THEN
1692 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: skipped, free memory not detectable'
1694 SELECT CASE (bse_env%memory_check)
1697 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: WARN, the total exceeds the budget'
1699 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: within the budget, no WARN raised'
1703 WRITE (unit_nr,
'(T2,A4,T7,A,I0,A,I0)')
'BSE|', &
1704 'Memory check: CLAMP applied, subspace ceiling reduced from ', m_start,
' to ', m_max
1706 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: within the budget, no CLAMP applied'
1710 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: ABORT, the total exceeds the budget'
1712 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|',
'Memory check: within the budget, no ABORT raised'
1719 WRITE (mem_str,
'(F16.3)') dist_gb + repl_gb
1720 WRITE (bud_str,
'(F16.3)') budget_gb
1721 SELECT CASE (bse_env%memory_check)
1723 IF (unit_nr > 0)
CALL cp_warn(__location__, &
1724 "BSE Davidson: the solver's arrays at the subspace ceiling need "// &
1725 trim(adjustl(mem_str))//
" GB per MPI rank, above the budget of "// &
1726 trim(adjustl(bud_str))//
" GB.")
1728 IF (unit_nr > 0)
CALL cp_warn(__location__, &
1729 "BSE Davidson: subspace ceiling reduced to fit the memory budget; raise "// &
1730 "MEMORY_BUDGET_GB or lower MAX_SUBSPACE_FACTOR to silence this.")
1732 CALL cp_abort(__location__, &
1733 "BSE Davidson: the solver's arrays at the subspace ceiling need "//trim(adjustl(mem_str))// &
1734 " GB per MPI rank, the budget is "//trim(adjustl(bud_str))//
" GB. Raise MEMORY_BUDGET_GB, "// &
1735 "lower MAX_SUBSPACE_FACTOR, or set MEMORY_CHECK CLAMP.")
1739 END SUBROUTINE subspace_ceiling
1757 SUBROUTINE davidson_footprint(driver, mv_env, m, n_act, block_size, nb, n_ri, dist_GB, repl_GB)
1759 INTEGER,
INTENT(IN) :: driver
1761 INTEGER,
INTENT(IN) :: m, n_act, block_size, nb, n_ri
1762 REAL(kind=
dp),
INTENT(OUT) :: dist_gb, repl_gb
1764 INTEGER :: c_coef, n_basis, n_mv, n_red, n_scratch, &
1765 n_solve, n_virt, n_work
1766 REAL(kind=
dp) :: m_real, n_ov_real
1772 SELECT CASE (driver)
1775 n_work = min(2*n_act, m)
1784 n_work = min(2*n_act, m)
1785 n_scratch = block_size
1793 n_work = max(2*n_act, min(4*n_act, m))
1794 n_scratch = 2*block_size
1802 cpabort(
"BSE Davidson: unknown driver in the memory estimate")
1806 m_real = real(m,
dp)
1807 n_ov_real = real(mv_env%n_ov,
dp)
1808 dist_gb = 8.0e-9_dp*(n_ov_real*real(n_basis*m + n_work + n_scratch,
dp) + real(n_red + n_solve,
dp)*m_real*m_real)/ &
1809 REAL(mv_env%para_env%num_pe,
dp)
1810 repl_gb = 8.0e-9_dp*(real(c_coef,
dp)*m_real*real(n_act,
dp) + m_real*real(block_size,
dp) + &
1811 REAL(n_mv,
dp)*n_ov_real*
REAL(nb, dp) +
REAL(n_ri,
dp)*
REAL(nb, dp) + &
1812 REAL(n_virt,
dp)*
REAL(mv_env%virt,
dp)**2)
1814 END SUBROUTINE davidson_footprint
1828 SUBROUTINE initial_guess(diag, n_guess, n_max, deg_thresh_diag, fm_Z, n_used, n_given)
1830 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) ::
diag
1831 INTEGER,
INTENT(IN) :: n_guess, n_max
1832 REAL(kind=
dp),
INTENT(IN) :: deg_thresh_diag
1834 INTEGER,
INTENT(OUT) :: n_used
1835 INTEGER,
INTENT(IN),
OPTIONAL :: n_given
1837 INTEGER :: iloc, k, k_first, n_ov, nrow_local
1838 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: diag_order
1839 INTEGER,
DIMENSION(:),
POINTER :: row_indices
1840 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: diag_sorted
1843 ALLOCATE (diag_sorted(n_ov), diag_order(n_ov))
1844 diag_sorted(:) =
diag(:)
1845 CALL sort(diag_sorted, n_ov, diag_order)
1847 n_used = multiplet_end(diag_sorted, n_guess, n_max, deg_thresh_diag)
1850 IF (
PRESENT(n_given)) k_first = n_given + 1
1852 CALL cp_fm_get_info(fm_z, nrow_local=nrow_local, row_indices=row_indices)
1853 DO k = k_first, n_used
1854 DO iloc = 1, nrow_local
1855 IF (row_indices(iloc) == diag_order(k)) fm_z%local_data(iloc, k) = 1.0_dp
1859 DEALLOCATE (diag_sorted, diag_order)
1861 END SUBROUTINE initial_guess
1887 SUBROUTINE initial_guess_subblock(mv_env, bse_env, diag, n_guess, n_max, deg_thresh_diag, fm_Z, n_used, &
1888 theta_sub, unit_nr, n_given, abba_status, ab_margin, n_pair)
1892 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) ::
diag
1893 INTEGER,
INTENT(IN) :: n_guess, n_max
1894 REAL(kind=
dp),
INTENT(IN) :: deg_thresh_diag
1896 INTEGER,
INTENT(OUT) :: n_used
1897 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
1898 INTENT(OUT) :: theta_sub
1899 INTEGER,
INTENT(IN) :: unit_nr
1900 INTEGER,
INTENT(IN),
OPTIONAL :: n_given
1901 INTEGER,
INTENT(OUT),
OPTIONAL :: abba_status
1902 REAL(kind=
dp),
INTENT(OUT),
OPTIONAL :: ab_margin
1903 INTEGER,
INTENT(OUT),
OPTIONAL :: n_pair
1905 CHARACTER(LEN=*),
PARAMETER :: routinen =
'initial_guess_subblock'
1907 INTEGER :: handle, iloc, k, k_first, n_ov, n_sub, &
1909 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: diag_order, rank_in_block
1910 INTEGER,
DIMENSION(:),
POINTER :: row_indices
1912 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: diag_sorted, eig_k
1913 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: a_sub, b_sub, eigvec_h, eigvec_k, &
1914 guess_x, guess_y, h_sub, k_mhalf, &
1915 k_phalf, k_sub, m_sub
1918 CALL timeset(routinen, handle)
1920 IF (
PRESENT(n_pair)) n_pair = 0
1921 para_env => mv_env%para_env
1923 n_sub = min(n_ov, max(bse_env%num_guess_transitions, n_guess))
1924 ALLOCATE (diag_sorted(n_ov), diag_order(n_ov), rank_in_block(n_ov))
1925 diag_sorted(:) =
diag(:)
1926 CALL sort(diag_sorted, n_ov, diag_order)
1928 ALLOCATE (a_sub(n_sub, n_sub), guess_x(n_sub, n_sub), theta_sub(n_sub))
1930 IF (
PRESENT(abba_status))
THEN
1932 ALLOCATE (b_sub(n_sub, n_sub), k_sub(n_sub, n_sub), m_sub(n_sub, n_sub), h_sub(n_sub, n_sub), &
1933 eigvec_k(n_sub, n_sub), eigvec_h(n_sub, n_sub), k_phalf(n_sub, n_sub), &
1934 k_mhalf(n_sub, n_sub), eig_k(n_sub))
1937 k_sub(:, :) = a_sub(:, :) - b_sub(:, :)
1938 CALL solve_replicated(k_sub, n_sub, para_env, eig_k, eigvec_k)
1939 ab_margin = eig_k(1)
1940 IF (eig_k(1) <= 0.0_dp)
THEN
1946 k_phalf(:, k) = eigvec_k(:, k)*sqrt(eig_k(k))
1947 k_mhalf(:, k) = eigvec_k(:, k)/sqrt(eig_k(k))
1949 k_phalf(:, :) = matmul(k_phalf, transpose(eigvec_k))
1950 k_mhalf(:, :) = matmul(k_mhalf, transpose(eigvec_k))
1952 m_sub(:, :) = 2.0_dp*a_sub(:, :) - k_sub(:, :)
1953 h_sub(:, :) = matmul(k_phalf, matmul(m_sub, k_phalf))
1954 CALL solve_replicated(h_sub, n_sub, para_env, theta_sub, eigvec_h)
1956 IF (theta_sub(1) <= 0.0_dp)
THEN
1957 cpabort(
"BSE Davidson: the guess block gives a non-positive squared excitation energy")
1959 theta_sub(:) = sqrt(theta_sub(:))
1960 guess_x(:, :) = matmul(k_mhalf, eigvec_h)
1961 IF (
PRESENT(n_pair))
THEN
1963 ALLOCATE (guess_y(n_sub, n_sub))
1964 guess_y(:, :) = matmul(k_sub, guess_x)
1966 guess_y(:, k) = guess_y(:, k)/theta_sub(k)
1970 DEALLOCATE (b_sub, k_sub, m_sub, h_sub, eigvec_k, eigvec_h, k_phalf, k_mhalf, eig_k)
1973 CALL solve_replicated(a_sub, n_sub, para_env, theta_sub, guess_x)
1978 IF (
PRESENT(n_given)) k_first = n_given + 1
1980 n_top = min(n_max, n_sub)
1982 IF (
PRESENT(n_pair)) n_top = min(n_top, (n_max + k_first - 1)/2)
1983 n_used = multiplet_end(theta_sub, n_guess, n_top, deg_thresh_diag)
1985 rank_in_block(:) = 0
1987 rank_in_block(diag_order(k)) = k
1989 CALL cp_fm_get_info(fm_z, nrow_local=nrow_local, row_indices=row_indices)
1990 DO k = k_first, n_used
1991 DO iloc = 1, nrow_local
1992 IF (rank_in_block(row_indices(iloc)) > 0) fm_z%local_data(iloc, k) = guess_x(rank_in_block(row_indices(iloc)), k)
1995 IF (
PRESENT(n_pair))
THEN
1996 n_pair = min(n_used - k_first + 1, n_max - n_used)
1998 DO iloc = 1, nrow_local
1999 IF (rank_in_block(row_indices(iloc)) > 0)
THEN
2000 fm_z%local_data(iloc, n_used + k) = guess_y(rank_in_block(row_indices(iloc)), k_first + k - 1)
2006 IF (unit_nr > 0)
THEN
2007 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Transitions in the exact guess block', n_sub
2008 IF (bse_env%bse_debug_print)
THEN
2009 WRITE (unit_nr,
'(T2,A10,T13,A,T67,F14.6)')
'BSE|DEBUG|', &
2010 'Lowest Ritz value of the guess block (eV)', theta_sub(1)*
evolt
2015 DEALLOCATE (diag_sorted, diag_order, rank_in_block, a_sub, guess_x)
2016 IF (
ALLOCATED(guess_y))
DEALLOCATE (guess_y)
2018 CALL timestop(handle)
2020 END SUBROUTINE initial_guess_subblock
2030 SUBROUTINE check_guess_bound(theta_sub, energies, n_req, unit_nr)
2032 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: theta_sub, energies
2033 INTEGER,
INTENT(IN) :: n_req, unit_nr
2035 REAL(kind=
dp) :: excess
2037 excess = maxval(energies(1:n_req) - theta_sub(1:n_req))
2038 IF (unit_nr > 0)
THEN
2039 WRITE (unit_nr,
'(T2,A4,T7,A,T65,F16.6)')
'BSE|', &
2040 'Largest excess over the guess-block bound (eV)', excess*
evolt
2042 IF (excess > deg_thresh .AND. unit_nr > 0)
THEN
2043 CALL cp_warn(__location__, &
2044 "A converged BSE state lies above the upper bound given by the guess block, "// &
2045 "so a lower state was missed. Raise BSE_ITERAT%NUM_GUESS_TRANSITIONS or "// &
2046 "BSE_ITERAT%NUM_BUFFER_STATES.")
2049 END SUBROUTINE check_guess_bound
2063 SUBROUTINE solve_reduced(fm_red, m, n_vec, para_env, blacs_env, theta, coef_ritz)
2066 INTEGER,
INTENT(IN) :: m, n_vec
2069 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: theta
2070 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT) :: coef_ritz
2072 CHARACTER(LEN=*),
PARAMETER :: routinen =
'solve_reduced'
2074 INTEGER :: handle, n_get
2075 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigval
2076 TYPE(
cp_fm_type) :: fm_reduced_eigvec, fm_reduced_sym
2078 CALL timeset(routinen, handle)
2080 CALL reduced_live_block(fm_red, m, para_env, blacs_env,
"bse_reduced", fm_reduced_sym)
2081 CALL cp_fm_create(fm_reduced_eigvec, fm_reduced_sym%matrix_struct, name=
"bse_reduced_vectors")
2083 CALL symmetrise_in_place(fm_reduced_sym, fm_reduced_eigvec)
2084 ALLOCATE (eigval(m))
2089 theta(1:m) = eigval(:)
2090 coef_ritz(:, :) = 0.0_dp
2091 n_get = min(m, n_vec)
2098 CALL timestop(handle)
2100 END SUBROUTINE solve_reduced
2112 SUBROUTINE solve_replicated(mat, m, para_env, theta, coef)
2114 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: mat
2115 INTEGER,
INTENT(IN) :: m
2117 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: theta
2118 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT) :: coef
2120 CHARACTER(LEN=*),
PARAMETER :: routinen =
'solve_replicated'
2123 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigval
2124 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: mat_sym
2126 CALL timeset(routinen, handle)
2128 ALLOCATE (mat_sym(m, m), eigval(m))
2129 mat_sym(:, :) = 0.5_dp*(mat(1:m, 1:m) + transpose(mat(1:m, 1:m)))
2131 IF (para_env%is_source())
CALL diamat_all(mat_sym, eigval)
2132 CALL para_env%bcast(mat_sym)
2133 CALL para_env%bcast(eigval)
2136 theta(1:m) = eigval(:)
2138 coef(1:m, 1:m) = mat_sym(:, :)
2139 DEALLOCATE (mat_sym, eigval)
2141 CALL timestop(handle)
2143 END SUBROUTINE solve_replicated
2150 SUBROUTINE symmetrise_in_place(fm_a, fm_scratch)
2152 TYPE(
cp_fm_type),
INTENT(IN) :: fm_a, fm_scratch
2157 END SUBROUTINE symmetrise_in_place
2172 SUBROUTINE restart_basis(cand, m, n_cand, n_cap, coef_restart, n_new)
2174 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: cand
2175 INTEGER,
INTENT(IN) :: m, n_cand, n_cap
2176 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT) :: coef_restart
2177 INTEGER,
INTENT(OUT) :: n_new
2179 CHARACTER(LEN=*),
PARAMETER :: routinen =
'restart_basis'
2180 REAL(kind=
dp),
PARAMETER :: coef_norm_drop = 1.0e-8_dp
2182 INTEGER :: handle, ipass, j, k
2183 REAL(kind=
dp) :: norm
2184 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: basis
2186 CALL timeset(routinen, handle)
2189 ALLOCATE (basis(m, min(n_cap, n_cand)))
2192 IF (n_new == n_cap)
EXIT
2193 basis(:, n_new + 1) = cand(1:m, k)
2198 basis(:, n_new + 1) = basis(:, n_new + 1) - &
2199 dot_product(basis(:, j), basis(:, n_new + 1))*basis(:, j)
2201 norm = norm2(basis(:, n_new + 1))
2202 IF (norm < coef_norm_drop)
EXIT
2203 basis(:, n_new + 1) = basis(:, n_new + 1)/norm
2206 IF (norm < coef_norm_drop) cycle
2209 coef_restart(:, :) = 0.0_dp
2210 coef_restart(1:m, 1:n_new) = basis(:, 1:n_new)
2213 CALL timestop(handle)
2215 END SUBROUTINE restart_basis
2229 SUBROUTINE subspace_rotate(fm_V, nv, coef, nc, fm_out, alpha, beta, out_col)
2232 INTEGER,
INTENT(IN) :: nv
2233 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
2235 INTEGER,
INTENT(IN) :: nc
2237 REAL(kind=
dp),
INTENT(IN) :: alpha, beta
2238 INTEGER,
INTENT(IN),
OPTIONAL :: out_col
2240 CHARACTER(LEN=*),
PARAMETER :: routinen =
'subspace_rotate'
2242 INTEGER :: handle, nrow_local, o_col
2244 CALL timeset(routinen, handle)
2247 IF (
PRESENT(out_col)) o_col = out_col
2249 IF (nrow_local > 0)
THEN
2250 CALL dgemm(
'N',
'N', nrow_local, nc, nv, alpha, fm_v%local_data,
SIZE(fm_v%local_data, 1), &
2251 coef,
SIZE(coef, 1), beta, fm_out%local_data(:, o_col:o_col + nc - 1),
SIZE(fm_out%local_data, 1))
2254 CALL timestop(handle)
2256 END SUBROUTINE subspace_rotate
2269 SUBROUTINE rotate_in_place(fm_V, m, coef, nq, fm_work, fm_V2, fm_V3)
2272 INTEGER,
INTENT(IN) :: m
2273 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: coef
2274 INTEGER,
INTENT(IN) :: nq
2276 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_v2, fm_v3
2278 CALL rotate_one(fm_v)
2279 IF (
PRESENT(fm_v2))
CALL rotate_one(fm_v2)
2280 IF (
PRESENT(fm_v3))
CALL rotate_one(fm_v3)
2288 SUBROUTINE rotate_one(fm)
2292 INTEGER :: nrow_local
2294 CALL subspace_rotate(fm, m, coef(1:m, 1:nq), nq, fm_work, 1.0_dp, 0.0_dp)
2297 fm%local_data(1:nrow_local, nq + 1:m) = 0.0_dp
2299 END SUBROUTINE rotate_one
2301 END SUBROUTINE rotate_in_place
2312 SUBROUTINE columns_axpy(alpha, fm_U, u0, fm_T, t0, n)
2314 REAL(kind=
dp),
INTENT(IN) :: alpha
2316 INTEGER,
INTENT(IN) :: u0
2318 INTEGER,
INTENT(IN) :: t0, n
2320 INTEGER :: nrow_local
2323 fm_t%local_data(1:nrow_local, t0:t0 + n - 1) = fm_t%local_data(1:nrow_local, t0:t0 + n - 1) + &
2324 alpha*fm_u%local_data(1:nrow_local, u0:u0 + n - 1)
2326 END SUBROUTINE columns_axpy
2340 SUBROUTINE subspace_gram(fm_U, u0, nu, fm_V, v0, nv, para_env, gram)
2343 INTEGER,
INTENT(IN) :: u0, nu
2345 INTEGER,
INTENT(IN) :: v0, nv
2347 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
2350 CHARACTER(LEN=*),
PARAMETER :: routinen =
'subspace_gram'
2352 INTEGER :: handle, nrow_local
2354 CALL timeset(routinen, handle)
2358 IF (nrow_local > 0)
THEN
2359 CALL dgemm(
'T',
'N', nu, nv, nrow_local, 1.0_dp, &
2360 fm_u%local_data(:, u0:u0 + nu - 1),
SIZE(fm_u%local_data, 1), &
2361 fm_v%local_data(:, v0:v0 + nv - 1),
SIZE(fm_v%local_data, 1), &
2362 0.0_dp, gram,
SIZE(gram, 1))
2364 CALL para_env%sum(gram)
2366 CALL timestop(handle)
2368 END SUBROUTINE subspace_gram
2383 SUBROUTINE reduced_gram_blocks(fm_U, nu, fm_V, v0, nv, nb, para_env, fm_red)
2386 INTEGER,
INTENT(IN) :: nu
2388 INTEGER,
INTENT(IN) :: v0, nv, nb
2392 CHARACTER(LEN=*),
PARAMETER :: routinen =
'reduced_gram_blocks'
2394 INTEGER :: c0, handle, nc
2395 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: gram_block
2397 CALL timeset(routinen, handle)
2399 ALLOCATE (gram_block(nu, nb))
2400 DO c0 = v0, v0 + nv - 1, nb
2401 nc = min(nb, v0 + nv - c0)
2402 CALL subspace_gram(fm_u, 1, nu, fm_v, c0, nc, para_env, gram_block(:, 1:nc))
2405 DEALLOCATE (gram_block)
2407 CALL timestop(handle)
2409 END SUBROUTINE reduced_gram_blocks
2419 SUBROUTINE reduced_extend(fm_red, red_block, m, nt)
2422 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: red_block
2423 INTEGER,
INTENT(IN) :: m, nt
2426 IF (m > 0)
CALL cp_fm_set_submatrix(fm_red, red_block(1:m, :), m + 1, 1, nt, m, transpose=.true.)
2428 END SUBROUTINE reduced_extend
2439 SUBROUTINE reduced_live_block(fm_red, m, para_env, blacs_env, name, fm_live)
2442 INTEGER,
INTENT(IN) :: m
2445 CHARACTER(LEN=*),
INTENT(IN) :: name
2452 nrow_global=m, ncol_global=m)
2457 END SUBROUTINE reduced_live_block
2469 SUBROUTINE reduced_rotate(fm_red, m, coef_restart, k, para_env, blacs_env)
2472 INTEGER,
INTENT(IN) :: m
2473 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: coef_restart
2474 INTEGER,
INTENT(IN) :: k
2478 CHARACTER(LEN=*),
PARAMETER :: routinen =
'reduced_rotate'
2482 TYPE(
cp_fm_type) :: fm_gq, fm_live, fm_q, fm_qgq
2484 CALL timeset(routinen, handle)
2486 CALL reduced_live_block(fm_red, m, para_env, blacs_env,
"bse_reduced_live", fm_live)
2489 nrow_global=m, ncol_global=k)
2490 CALL cp_fm_create(fm_q, fm_struct, name=
"bse_restart_basis")
2491 CALL cp_fm_create(fm_gq, fm_struct, name=
"bse_reduced_GQ")
2494 nrow_global=k, ncol_global=k)
2495 CALL cp_fm_create(fm_qgq, fm_struct, name=
"bse_reduced_QGQ")
2500 CALL parallel_gemm(
'N',
'N', m, k, m, 1.0_dp, fm_live, fm_q, 0.0_dp, fm_gq)
2501 CALL parallel_gemm(
'T',
'N', k, k, m, 1.0_dp, fm_q, fm_gq, 0.0_dp, fm_qgq)
2510 CALL timestop(handle)
2512 END SUBROUTINE reduced_rotate
2523 FUNCTION orthonormality_deviation(fm_U, fm_V, m, nb, para_env)
RESULT(dev)
2526 INTEGER,
INTENT(IN) :: m, nb
2528 REAL(kind=
dp) :: dev
2530 INTEGER :: c0, l, nc
2531 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: gram_block
2533 ALLOCATE (gram_block(m, nb))
2536 nc = min(nb, m - c0 + 1)
2537 CALL subspace_gram(fm_u, 1, m, fm_v, c0, nc, para_env, gram_block(:, 1:nc))
2539 gram_block(c0 + l - 1, l) = gram_block(c0 + l - 1, l) - 1.0_dp
2541 dev = max(dev, maxval(abs(gram_block(:, 1:nc))))
2543 DEALLOCATE (gram_block)
2545 END FUNCTION orthonormality_deviation
2556 SUBROUTINE column_norms(fm_T, first_col, nt, para_env, norms)
2559 INTEGER,
INTENT(IN) :: first_col, nt
2561 REAL(kind=
dp),
DIMENSION(:),
INTENT(OUT) :: norms
2563 INTEGER :: k, nrow_local
2568 norms(k) = sum(fm_t%local_data(1:nrow_local, first_col + k - 1)**2)
2570 CALL para_env%sum(norms)
2571 norms(:) = sqrt(norms(:))
2573 END SUBROUTINE column_norms
2586 SUBROUTINE davidson_corrections(fm_R, selected, theta, diag, fm_Z, first_col, r_offset)
2589 INTEGER,
DIMENSION(:),
INTENT(IN) :: selected
2590 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: theta,
diag
2592 INTEGER,
INTENT(IN) :: first_col
2593 INTEGER,
INTENT(IN),
OPTIONAL :: r_offset
2595 CHARACTER(LEN=*),
PARAMETER :: routinen =
'davidson_corrections'
2596 REAL(kind=
dp),
PARAMETER :: eref_scale = 0.99_dp, threshold = 16.0_dp*epsilon(1.0_dp)
2598 INTEGER :: handle, iloc, it, k, nrow_local, r_off
2599 INTEGER,
DIMENSION(:),
POINTER :: row_indices
2600 REAL(kind=
dp) :: denom
2602 CALL timeset(routinen, handle)
2605 IF (
PRESENT(r_offset)) r_off = r_offset
2606 CALL cp_fm_get_info(fm_z, nrow_local=nrow_local, row_indices=row_indices)
2607 DO it = 1,
SIZE(selected)
2609 DO iloc = 1, nrow_local
2610 denom =
diag(row_indices(iloc)) - theta(k)
2613 IF (abs(denom) < threshold) denom = denom + (1.0_dp - eref_scale)*theta(k)
2614 fm_z%local_data(iloc, first_col + it - 1) = fm_r%local_data(iloc, r_off + k)/denom
2618 CALL timestop(handle)
2620 END SUBROUTINE davidson_corrections
2634 SUBROUTINE project_out(fm_T, first_col, nt, fm_V, nv, para_env, fm_dual)
2637 INTEGER,
INTENT(IN) :: first_col, nt
2639 INTEGER,
INTENT(IN) :: nv
2641 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_dual
2643 CHARACTER(LEN=*),
PARAMETER :: routinen =
'project_out'
2645 INTEGER :: handle, ipass, nrow_local
2646 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: coeff
2648 IF (nt == 0 .OR. nv == 0)
RETURN
2649 CALL timeset(routinen, handle)
2651 ALLOCATE (coeff(nv, nt))
2653 IF (
PRESENT(fm_dual))
THEN
2654 CALL subspace_gram(fm_dual, 1, nv, fm_t, first_col, nt, para_env, coeff)
2656 CALL subspace_gram(fm_v, 1, nv, fm_t, first_col, nt, para_env, coeff)
2658 IF (nrow_local > 0)
THEN
2659 CALL dgemm(
'N',
'N', nrow_local, nt, nv, -1.0_dp, &
2660 fm_v%local_data,
SIZE(fm_v%local_data, 1), coeff, nv, 1.0_dp, &
2661 fm_t%local_data(:, first_col:first_col + nt - 1),
SIZE(fm_t%local_data, 1))
2665 CALL timestop(handle)
2667 END SUBROUTINE project_out
2677 SUBROUTINE drop_small_columns(fm_T, first_col, nt, para_env)
2680 INTEGER,
INTENT(IN) :: first_col
2681 INTEGER,
INTENT(INOUT) :: nt
2684 REAL(kind=
dp),
PARAMETER :: col_norm_drop = 1.0e-10_dp
2686 INTEGER :: k, n_kept, nrow_local
2687 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: norms
2691 ALLOCATE (norms(nt))
2692 CALL column_norms(fm_t, first_col, nt, para_env, norms)
2696 IF (norms(k) < col_norm_drop) cycle
2698 fm_t%local_data(1:nrow_local, first_col + n_kept - 1) = &
2699 fm_t%local_data(1:nrow_local, first_col + k - 1)/norms(k)
2701 fm_t%local_data(1:nrow_local, first_col + n_kept:first_col + nt - 1) = 0.0_dp
2705 END SUBROUTINE drop_small_columns
2721 SUBROUTINE cholqr2(fm_T, first_col, nt, para_env, ok, n_dropped)
2724 INTEGER,
INTENT(IN) :: first_col
2725 INTEGER,
INTENT(INOUT) :: nt
2727 LOGICAL,
INTENT(OUT) :: ok
2728 INTEGER,
INTENT(OUT),
OPTIONAL :: n_dropped
2730 CHARACTER(LEN=*),
PARAMETER :: routinen =
'cholqr2'
2731 REAL(kind=
dp),
PARAMETER :: eig_drop_rel = 1.0e-10_dp
2733 INTEGER :: handle, info, ipass, k, n_drop_calls, &
2735 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eig
2736 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: chol_factor, gram, gram_eigvec, t_reduced
2739 IF (
PRESENT(n_dropped)) n_dropped = 0
2741 CALL timeset(routinen, handle)
2743 ALLOCATE (gram(nt, nt), chol_factor(nt, nt))
2747 DO WHILE (ipass < 2)
2750 CALL subspace_gram(fm_t, first_col, nt, fm_t, first_col, nt, para_env, gram)
2751 chol_factor(:, :) = gram(:, :)
2753 IF (para_env%is_source())
CALL dpotrf(
'U', nt, chol_factor, nt, info)
2754 CALL para_env%bcast(info)
2756 n_drop_calls = n_drop_calls + 1
2757 IF (n_drop_calls > 2)
THEN
2763 ALLOCATE (eig(nt), gram_eigvec(nt, nt))
2764 CALL solve_replicated(gram, nt, para_env, eig, gram_eigvec)
2765 n_keep = count(eig > eig_drop_rel*eig(nt))
2766 IF (n_keep == 0)
THEN
2768 DEALLOCATE (eig, gram_eigvec)
2772 gram_eigvec(:, nt - n_keep + k) = gram_eigvec(:, nt - n_keep + k)/sqrt(eig(nt - n_keep + k))
2774 IF (nrow_local > 0)
THEN
2775 ALLOCATE (t_reduced(nrow_local, n_keep))
2776 CALL dgemm(
'N',
'N', nrow_local, n_keep, nt, 1.0_dp, &
2777 fm_t%local_data(:, first_col:first_col + nt - 1),
SIZE(fm_t%local_data, 1), &
2778 gram_eigvec(:, nt - n_keep + 1:nt), nt, 0.0_dp, t_reduced, nrow_local)
2779 fm_t%local_data(1:nrow_local, first_col:first_col + n_keep - 1) = t_reduced(:, :)
2780 fm_t%local_data(1:nrow_local, first_col + n_keep:first_col + nt - 1) = 0.0_dp
2781 DEALLOCATE (t_reduced)
2783 IF (
PRESENT(n_dropped)) n_dropped = n_dropped + nt - n_keep
2785 DEALLOCATE (eig, gram_eigvec, gram, chol_factor)
2786 ALLOCATE (gram(nt, nt), chol_factor(nt, nt))
2791 CALL para_env%bcast(chol_factor)
2792 IF (nrow_local > 0)
THEN
2793 CALL dtrsm(
'R',
'U',
'N',
'N', nrow_local, nt, 1.0_dp, chol_factor, nt, &
2794 fm_t%local_data(:, first_col:first_col + nt - 1),
SIZE(fm_t%local_data, 1))
2798 DEALLOCATE (gram, chol_factor)
2799 CALL timestop(handle)
2801 END SUBROUTINE cholqr2
2814 SUBROUTINE extend_orthonormal(fm_V, m, nt, para_env, n_dependent, fm_dual)
2817 INTEGER,
INTENT(IN) :: m
2818 INTEGER,
INTENT(INOUT) :: nt
2820 INTEGER,
INTENT(INOUT) :: n_dependent
2821 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_dual
2823 INTEGER :: n_dropped
2826 CALL project_out(fm_v, m + 1, nt, fm_v, m, para_env, fm_dual)
2827 CALL drop_small_columns(fm_v, m + 1, nt, para_env)
2828 CALL cholqr2(fm_v, m + 1, nt, para_env, ok, n_dropped)
2830 IF (.NOT. ok) cpabort(
"BSE Davidson: orthonormalisation broke down")
2831 n_dependent = n_dependent + n_dropped
2833 END SUBROUTINE extend_orthonormal
2845 FUNCTION extension_deviation(fm_V, fm_dual, nv, nt, para_env)
RESULT(dev)
2847 TYPE(
cp_fm_type),
INTENT(IN) :: fm_v, fm_dual
2848 INTEGER,
INTENT(IN) :: nv, nt
2850 REAL(kind=
dp) :: dev
2853 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: gram
2857 ALLOCATE (gram(nv + nt, nt))
2858 CALL subspace_gram(fm_v, 1, nv + nt, fm_dual, nv + 1, nt, para_env, gram)
2860 gram(nv + k, k) = gram(nv + k, k) - 1.0_dp
2862 dev = maxval(abs(gram))
2865 END FUNCTION extension_deviation
2884 TYPE(
cp_fm_type),
INTENT(IN) :: fm_a_explicit
2885 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: exc_ens
2888 INTEGER,
INTENT(IN) :: unit_nr
2889 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_b_explicit, fm_y
2891 CHARACTER(LEN=*),
PARAMETER :: routinen =
'bse_davidson_refcheck'
2893 INTEGER :: diag_info, handle, k, n_ov, n_ref, n_want
2894 REAL(kind=
dp) :: min_overlap
2895 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: ref_ens
2896 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: diff_ref, sum_ref, x_dav, x_ref, y_dav, &
2898 TYPE(
cp_fm_type) :: fm_c, fm_eigvec, fm_inv_sqrt_a_minus_b, &
2899 fm_sqrt_a_minus_b, fm_work
2901 CALL timeset(routinen, handle)
2904 cpassert(
PRESENT(fm_b_explicit) .EQV.
PRESENT(fm_y))
2905 IF (unit_nr > 0)
THEN
2906 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
2907 IF (
PRESENT(fm_b_explicit))
THEN
2908 WRITE (unit_nr,
'(T2,A10,T13,A)')
'BSE|DEBUG|',
'Reference check against the explicit A and B'
2910 WRITE (unit_nr,
'(T2,A10,T13,A)')
'BSE|DEBUG|',
'Reference check against the explicit A'
2914 n_want =
SIZE(exc_ens)
2915 ALLOCATE (ref_ens(n_ov))
2917 IF (
PRESENT(fm_b_explicit))
THEN
2919 fm_inv_sqrt_a_minus_b, unit_nr, bse_env, 0.0_dp)
2922 IF (diag_info /= 0) cpabort(
"Reference diagonalization of C failed in the BSE Davidson check")
2923 IF (ref_ens(1) <= 0.0_dp)
THEN
2924 CALL cp_abort(__location__, &
2925 "Reference matrix C has a non-positive eigenvalue in the BSE Davidson check")
2927 ref_ens(:) = sqrt(ref_ens(:))
2929 n_ref = multiplet_end(ref_ens, n_want, n_ov, deg_thresh)
2930 ALLOCATE (sum_ref(n_ov, n_ref), diff_ref(n_ov, n_ref))
2932 CALL parallel_gemm(
"N",
"N", n_ov, n_ref, n_ov, 1.0_dp, fm_sqrt_a_minus_b, fm_eigvec, 0.0_dp, &
2935 CALL parallel_gemm(
"N",
"N", n_ov, n_ref, n_ov, 1.0_dp, fm_inv_sqrt_a_minus_b, fm_eigvec, &
2943 ALLOCATE (x_ref(n_ov, n_ref), y_ref(n_ov, n_ref), y_dav(n_ov, n_want))
2945 sum_ref(:, k) = sum_ref(:, k)/sqrt(ref_ens(k))
2946 diff_ref(:, k) = diff_ref(:, k)*sqrt(ref_ens(k))
2948 x_ref(:, :) = 0.5_dp*(sum_ref(:, :) + diff_ref(:, :))
2949 y_ref(:, :) = 0.5_dp*(sum_ref(:, :) - diff_ref(:, :))
2950 DEALLOCATE (sum_ref, diff_ref)
2954 CALL cp_fm_create(fm_work, fm_a_explicit%matrix_struct)
2956 CALL cp_fm_create(fm_eigvec, fm_a_explicit%matrix_struct)
2958 IF (diag_info /= 0) cpabort(
"Reference diagonalization of A failed in the BSE Davidson check")
2961 n_ref = multiplet_end(ref_ens, n_want, n_ov, deg_thresh)
2962 ALLOCATE (x_ref(n_ov, n_ref))
2967 ALLOCATE (x_dav(n_ov, n_want))
2971 CALL min_multiplet_overlap(ref_ens, n_want, n_ref, x_ref, x_dav, min_overlap, y_ref, y_dav)
2972 CALL print_refcheck(maxval(abs(exc_ens(:) - ref_ens(1:n_want))), min_overlap, unit_nr)
2974 DEALLOCATE (ref_ens, x_ref, x_dav)
2975 IF (
ALLOCATED(y_ref))
DEALLOCATE (y_ref, y_dav)
2977 CALL timestop(handle)
2995 SUBROUTINE min_multiplet_overlap(ref_ens, n_want, n_ref, X_ref, X_dav, min_overlap, Y_ref, Y_dav)
2997 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: ref_ens
2998 INTEGER,
INTENT(IN) :: n_want, n_ref
2999 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: x_ref, x_dav
3000 REAL(kind=
dp),
INTENT(OUT) :: min_overlap
3001 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN), &
3002 OPTIONAL :: y_ref, y_dav
3004 INTEGER :: info, lwork, mult_first, mult_last, &
3006 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: sing_vals, work
3007 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: overlap
3008 REAL(kind=
dp),
DIMENSION(1, 1) :: dummy
3010 min_overlap = 1.0_dp
3012 DO WHILE (mult_first <= n_want)
3013 mult_last = multiplet_end(ref_ens, mult_first, n_ref, deg_thresh)
3014 mult_last_dav = min(mult_last, n_want)
3015 ALLOCATE (overlap(mult_last - mult_first + 1, mult_last_dav - mult_first + 1), sing_vals(mult_last_dav - mult_first + 1))
3016 overlap(:, :) = matmul(transpose(x_ref(:, mult_first:mult_last)), x_dav(:, mult_first:mult_last_dav))
3017 IF (
PRESENT(y_ref))
THEN
3018 overlap(:, :) = overlap(:, :) - matmul(transpose(y_ref(:, mult_first:mult_last)), y_dav(:, mult_first:mult_last_dav))
3021 lwork = 5*(mult_last - mult_first + 1) + 10
3022 ALLOCATE (work(lwork))
3023 CALL dgesvd(
'N',
'N', mult_last - mult_first + 1, mult_last_dav - mult_first + 1, overlap, mult_last - mult_first + 1, sing_vals, &
3024 dummy, 1, dummy, 1, work, lwork, info)
3025 IF (info /= 0) cpabort(
"SVD failed in the BSE Davidson check")
3026 min_overlap = min(min_overlap, minval(sing_vals))
3027 DEALLOCATE (overlap, sing_vals, work)
3028 mult_first = mult_last + 1
3031 END SUBROUTINE min_multiplet_overlap
3039 SUBROUTINE print_refcheck(dev_E, min_overlap, unit_nr)
3041 REAL(kind=
dp),
INTENT(IN) :: dev_e, min_overlap
3042 INTEGER,
INTENT(IN) :: unit_nr
3044 IF (unit_nr > 0)
THEN
3045 WRITE (unit_nr,
'(T2,A10,T13,A,T63,ES18.6)')
'BSE|DEBUG|', &
3046 'Max energy deviation vs full diagonalization (eV)', dev_e*
evolt
3047 WRITE (unit_nr,
'(T2,A10,T13,A,T63,F18.12)')
'BSE|DEBUG|', &
3048 'Min subspace overlap vs full diagonalization', min_overlap
3051 END SUBROUTINE print_refcheck
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
collects all references to literature in CP2K as new algorithms / method are included from literature...
integer, save, public olsen1988
integer, save, public fukaya2014
integer, save, public davidson1975
integer, save, public bai2012
integer, save, public stathopoulos1998
integer, save, public stratmann1998
integer, save, public vecharynski2017
Block Davidson solvers for the lowest excitations of the Bethe-Salpeter equation on top of the matrix...
subroutine, public bse_davidson_abba_os(mv_env, bse_env, unit_nr, exc_ens, fm_x, fm_y, abba_status, ab_margin, fm_x_tda)
Block Davidson with thick restart for the NUM_EXC_EN lowest solutions of the full problem in the pair...
integer, parameter, public abba_ok
integer, parameter, public abba_indefinite
subroutine, public bse_davidson_abba_mk(mv_env, bse_env, unit_nr, exc_ens, fm_x, fm_y, abba_status, ab_margin, fm_x_tda)
Block Davidson with thick restart for the NUM_EXC_EN lowest solutions of the full problem,...
subroutine, public bse_davidson_tda(mv_env, bse_env, unit_nr, exc_ens, fm_x)
Block Davidson with thick restart for the NUM_EXC_EN lowest solutions of sum_jb A_ia,...
subroutine, public bse_davidson_refcheck(fm_a_explicit, exc_ens, fm_x, bse_env, unit_nr, fm_b_explicit, fm_y)
Debug check of a Davidson result against the full diagonalization of the explicit matrices: energies,...
Routines for the full diagonalization of GW + Bethe-Salpeter for computing electronic excitations.
subroutine, public create_hermitian_form_of_abba(fm_a, fm_b, fm_c, fm_sqrt_a_minus_b, fm_inv_sqrt_a_minus_b, unit_nr, bse_env, diag_est)
Construct Matrix C=(A-B)^0.5 (A+B) (A-B)^0.5 to solve full BSE matrix as a hermitian problem (cf....
Matrix-free application of the BSE matrices A and B to trial vectors from RI slabs that are sliced al...
subroutine, public bse_matvec_subblock(mv_env, ia_list, a_sub, b_sub)
Exact A (and B) on a list of transitions, replicated on every rank, A_kl = δ_kl (ε_a-ε_i) + α sum_P B...
subroutine, public bse_matvec_apply(mv_env, fm_z, first_col, ncol, fm_az, fm_bz, first_col_bz)
Applies A (and B) to ncol trial vectors without forming an N_ov x N_ov object, (A Z)_ia = (ε_a-ε_i) Z...
subroutine, public bse_matvec_diagonal(mv_env, precond_kind, diag)
Diagonal used by the Davidson correction, either ε_a-ε_i or the full diagonal A_ia,...
real(kind=dp), parameter, public mem_fraction
subroutine, public bse_matvec_vector_struct(mv_env, ncol_global, fm_struct)
Matrix structure of a block of trial vectors: rows ia distributed, all columns local.
The BSE environment: the settings of the &BSE section and the state a GW path prepares for the solver...
methods related to the blacs parallel environment
subroutine, public cp_blacs_env_release(blacs_env)
releases the given blacs_env
subroutine, public cp_blacs_env_create(blacs_env, para_env, blacs_grid_layout, blacs_repeatable, row_major, grid_2d)
allocates and initializes a type that represent a blacs context
Basic linear algebra operations for full matrices.
subroutine, public cp_fm_column_scale(matrixa, scaling)
scales column i of matrix a with scaling(i)
subroutine, public cp_fm_transpose(matrix, matrixt)
transposes a matrix matrixt = matrix ^ T
subroutine, public cp_fm_scale_and_add(alpha, matrix_a, beta, matrix_b)
calc A <- alpha*A + beta*B optimized for alpha == 1.0 (just add beta*B) and beta == 0....
used for collecting some of the diagonalization schemes available for cp_fm_type. cp_fm_power also mo...
subroutine, public choose_eigv_solver(matrix, eigenvectors, eigenvalues, info)
Choose the Eigensolver depending on which library is available ELPA seems to be unstable for small sy...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_set_submatrix(fm, new_values, start_row, start_col, n_rows, n_cols, alpha, beta, transpose)
sets a submatrix of a full matrix fm(start_row:start_row+n_rows,start_col:start_col+n_cols) = alpha*o...
subroutine, public cp_fm_to_fm_submat(msource, mtarget, nrow, ncol, s_firstrow, s_firstcol, t_firstrow, t_firstcol)
copy just a part ot the matrix
subroutine, public cp_fm_set_all(matrix, alpha, beta)
set all elements of a matrix to the same value, and optionally the diagonal to a different one
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
subroutine, public cp_fm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
gets a submatrix of a full matrix op(target_m)(1:n_rows,1:n_cols) =fm(start_row:start_row+n_rows,...
Defines the basic variable types.
integer, parameter, public dp
Machine interface based on Fortran 2003 and POSIX.
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
Collection of simple mathematical functions and subroutines.
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...
subroutine, public diag(n, a, d, v)
Diagonalize matrix a. The eigenvalues are returned in vector d and the eigenvectors are returned in m...
Interface to the message passing library MPI.
subroutine, public mp_mem_avail_per_rank_gb(comm, mem_avail_gb)
Memory that is currently free on the node, per MPI rank of that node, in GB.
basic linear algebra operations for full matrixes
Definition of physical constants:
real(kind=dp), parameter, public evolt
All kind of helpful little routines.
RI slabs of one spin channel, every rank holding n_ri_loc whole RI slices.
Settings of the &BSE section (read_bse_section, re-read by prepare_bse_env, normalised in place by ad...
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
stores all the informations relevant to an mpi environment