42#include "./base/base_uses.f90"
48 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'bse_properties'
58 REAL(kind=
dp),
DIMENSION(3) :: r_e = 0.0_dp, &
65 sigma_e_dir = 0.0_dp, &
66 sigma_h_dir = 0.0_dp, &
68 REAL(kind=
dp),
DIMENSION(3, 3) :: r_e_h = 0.0_dp, &
70 corr_e_h_matrix = 0.0_dp
71 REAL(kind=
dp) :: sigma_e = 0.0_dp, &
73 cov_e_h_sum = 0.0_dp, &
75 diff_r_abs = 0.0_dp, &
76 diff_r_sqr = 0.0_dp, &
78 LOGICAL :: flag_tda = .false.
102 trans_mom_bse, oscill_str, polarizability_residues, &
103 bse_env, homo_red, virtual_red, unit_nr, &
107 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
108 INTENT(IN) :: exc_ens
109 TYPE(
cp_fm_type),
DIMENSION(3) :: fm_dipole_ai_trunc
110 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
111 INTENT(OUT) :: trans_mom_bse
112 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
113 INTENT(OUT) :: oscill_str
114 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
115 INTENT(OUT) :: polarizability_residues
117 INTEGER,
INTENT(IN) :: homo_red, virtual_red, unit_nr
118 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_eigvec_y
120 CHARACTER(LEN=*),
PARAMETER :: routinen =
'get_oscillator_strengths'
122 INTEGER :: handle, idir, jdir, n, n_exc
124 fm_struct_trans_mom_bse
126 TYPE(
cp_fm_type),
DIMENSION(3) :: fm_dipole_mo_trunc_reordered, &
127 fm_dipole_per_dir, fm_trans_mom_bse
129 CALL timeset(routinen, handle)
134 CALL cp_fm_struct_create(fm_struct_dipole_mo_trunc_reordered, fm_eigvec_x%matrix_struct%para_env, &
135 fm_eigvec_x%matrix_struct%context, 1, homo_red*virtual_red)
137 fm_eigvec_x%matrix_struct%context, 1, n_exc)
144 CALL cp_fm_create(fm_dipole_mo_trunc_reordered(idir), matrix_struct=fm_struct_dipole_mo_trunc_reordered, &
145 name=
"dipoles_mo_reordered")
146 CALL cp_fm_set_all(fm_dipole_mo_trunc_reordered(idir), 0.0_dp)
147 CALL fm_general_add_bse(fm_dipole_mo_trunc_reordered(idir), fm_dipole_ai_trunc(idir), 1.0_dp, &
150 unit_nr, [2, 4, 3, 1], bse_env)
155 CALL cp_fm_create(fm_trans_mom_bse(idir), matrix_struct=fm_struct_trans_mom_bse, &
156 name=
"excitonic_dipoles")
161 CALL cp_fm_create(fm_eigvec_xysum, matrix_struct=fm_eigvec_x%matrix_struct, name=
"excit_amplitude_sum")
164 IF (
PRESENT(fm_eigvec_y))
THEN
168 CALL parallel_gemm(
'N',
'N', 1, n_exc, homo_red*virtual_red, sqrt(2.0_dp), &
169 fm_dipole_mo_trunc_reordered(idir), fm_eigvec_xysum, 0.0_dp, fm_trans_mom_bse(idir))
173 ALLOCATE (oscill_str(n_exc))
176 ALLOCATE (trans_mom_bse(3, 1, n_exc))
177 ALLOCATE (polarizability_residues(3, 3, n_exc))
178 trans_mom_bse(:, :, :) = 0.0_dp
188 polarizability_residues(idir, jdir, n) = 2.0_dp*exc_ens(n)*trans_mom_bse(idir, 1, n)*trans_mom_bse(jdir, 1, n)
191 oscill_str(n) = 2.0_dp/3.0_dp*exc_ens(n)*sum(abs(trans_mom_bse(:, 1, n))**2)
203 CALL timestop(handle)
220 info_approximation, unit_nr, bse_env)
222 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
223 INTENT(IN) :: oscill_str
224 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
225 INTENT(IN) :: polarizability_residues
226 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
227 INTENT(IN) :: exc_ens
228 CHARACTER(LEN=10) :: info_approximation
229 INTEGER,
INTENT(IN) :: unit_nr
232 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_and_print_absorption_spectrum'
234 CHARACTER(LEN=10) :: eta_str, width_eta_format_str
235 CHARACTER(LEN=40) :: file_name_crosssection, &
237 INTEGER :: handle, i, idir, j, jdir, k, num_steps, &
238 unit_nr_file, width_eta
239 REAL(kind=
dp) :: eta, freq_end, freq_start, freq_step, &
241 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: abs_cross_section, abs_spectrum
242 REAL(kind=
dp),
DIMENSION(:),
POINTER :: eta_list
244 CALL timeset(routinen, handle)
246 freq_step = bse_env%bse_spectrum_freq_step_size
247 freq_start = bse_env%bse_spectrum_freq_start
248 freq_end = bse_env%bse_spectrum_freq_end
249 eta_list => bse_env%bse_eta_spectrum_list
252 num_steps = nint((freq_end - freq_start)/freq_step) + 1
254 DO k = 1,
SIZE(eta_list)
258 width_eta = max(1, int(log10(eta)) + 1) + 4
259 WRITE (width_eta_format_str,
"(A2,I0,A3)")
'(F', width_eta,
'.3)'
260 WRITE (eta_str, width_eta_format_str) eta*
evolt
262 file_name_spectrum =
'BSE'//trim(adjustl(info_approximation))//
'eta='//trim(eta_str)//
'.spectrum'
263 file_name_crosssection =
'BSE'//trim(adjustl(info_approximation))//
'eta='//trim(eta_str)//
'.crosssection'
267 ALLOCATE (abs_spectrum(num_steps, 11))
268 abs_spectrum(:, :) = 0.0_dp
271 ALLOCATE (abs_cross_section(num_steps, 11))
272 abs_cross_section(:, :) = 0.0_dp
287 omega = freq_start + (i - 1)*freq_step
288 abs_spectrum(i, 1) = omega
289 DO j = 1,
SIZE(oscill_str)
290 abs_spectrum(i, 2) = abs_spectrum(i, 2) - oscill_str(j)* &
291 aimag(1/((omega + cmplx(0.0, eta, kind=
dp))**2 - exc_ens(j)**2))
296 abs_spectrum(i, 2 + (idir - 1)*3 + jdir) = abs_spectrum(i, 2 + (idir - 1)*3 + jdir) &
297 - polarizability_residues(idir, jdir, j)* &
298 aimag(1/((omega + cmplx(0.0, eta, kind=
dp))**2 - exc_ens(j)**2))
306 omega = abs_spectrum(i, 1)
307 abs_cross_section(i, 1) = omega
308 abs_cross_section(i, 2:) = 4.0_dp*
pi*abs_spectrum(i, 2:)*omega/
c_light_au
312 IF (bse_env%bse_debug_print)
THEN
313 IF (unit_nr > 0)
THEN
314 WRITE (unit_nr,
'(T2,A10,T13,A,T65,F16.4)')
'BSE|DEBUG|', &
315 'Averaged dynamical dipole polarizability at 8.2 eV:', &
317 WRITE (unit_nr,
'(T2,A10,T13,A,T65,F16.4)')
'BSE|DEBUG|', &
318 'Averaged photoabsorption cross section at 8.2 eV:', &
319 abs_cross_section(83, 2)
325 IF (bse_env%para_env%is_source())
THEN
326 CALL open_file(file_name_crosssection, unit_number=unit_nr_file, &
327 file_status=
"UNKNOWN", file_action=
"WRITE")
328 WRITE (unit_nr_file,
'(A,A6)')
"# Photoabsorption cross section σ_{µ µ'}(ω) = -4πω/c * Im[ \sum_n "// &
329 "[2 Ω^n d_µ^n d_µ'^n] / [(ω+iη)²- (Ω^n)²] ] from Bethe Salpeter equation for method ", &
330 trim(adjustl(info_approximation))
331 WRITE (unit_nr_file,
'(A20,1X,10(2X,A20,1X))')
"# Frequency (eV)",
"σ_{avg}(ω)",
"σ_xx(ω)", &
332 "σ_xy(ω)",
"σ_xz(ω)",
"σ_yx(ω)",
"σ_yy(ω)",
"σ_yz(ω)",
"σ_zx(ω)", &
335 WRITE (unit_nr_file,
'(11(F20.8,1X))') abs_cross_section(i, 1)*
evolt, abs_cross_section(i, 2:11)
339 DEALLOCATE (abs_cross_section)
341 IF (bse_env%para_env%is_source())
THEN
342 CALL open_file(file_name_spectrum, unit_number=unit_nr_file, &
343 file_status=
"UNKNOWN", file_action=
"WRITE")
344 WRITE (unit_nr_file,
'(A,A6)')
"# Imaginary part of polarizability α_{µ µ'}(ω) = -\sum_n "// &
345 "[2 Ω^n d_µ^n d_µ'^n] / [(ω+iη)²- (Ω^n)²] from Bethe Salpeter equation for method ", &
346 trim(adjustl(info_approximation))
347 WRITE (unit_nr_file,
'(A20,1X,10(2X,A20,1X))')
"# Frequency (eV)",
"Im{α_{avg}(ω)}",
"Im{α_xx(ω)}", &
348 "Im{α_xy(ω)}",
"Im{α_xz(ω)}",
"Im{α_yx(ω)}",
"Im{α_yy(ω)}",
"Im{α_yz(ω)}",
"Im{α_zx(ω)}", &
349 "Im{α_zy(ω)}",
"Im{α_zz(ω)}"
351 WRITE (unit_nr_file,
'(11(F20.8,1X))') abs_spectrum(i, 1)*
evolt, abs_spectrum(i, 2:11)
355 DEALLOCATE (abs_spectrum)
358 IF (unit_nr > 0)
THEN
359 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
360 WRITE (unit_nr,
'(T2,A4,T7,A,A)') &
361 'BSE|',
"Printed optical absorption spectrum to local files, e.g. "
362 WRITE (unit_nr,
'(T2,A4,T7,A)') &
363 'BSE|', file_name_spectrum
364 WRITE (unit_nr,
'(T2,A4,T7,A,A)') &
365 'BSE|',
"as well as photoabsorption cross section to, e.g. "
366 WRITE (unit_nr,
'(T2,A4,T7,A)') &
367 'BSE|', file_name_crosssection
368 WRITE (unit_nr,
'(T2,A4,T7,A52)') &
369 'BSE|',
"using the Eq. (7.51) from C. Ullrichs Book on TDDFT:"
370 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
371 WRITE (unit_nr,
'(T2,A4,T10,A75)') &
372 'BSE|',
"Im{α_{avg}(ω)} = -Im{\sum_{n=1}^{N_exc} \frac{f_n}{(ω+iη)² - (Ω^n)²}}"
373 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
374 WRITE (unit_nr,
'(T2,A4,T7,A)') &
375 'BSE|',
"or for the full polarizability tensor:"
376 WRITE (unit_nr,
'(T2,A4,T10,A)') &
377 'BSE|',
"α_{µ µ'}(ω) = -\sum_n [2 Ω^n d_µ^n d_µ'^n] / [(ω+iη)²- (Ω^n)²]"
378 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
379 WRITE (unit_nr,
'(T2,A4,T7,A)') &
380 'BSE|',
"as well as Eq. (7.48):"
381 WRITE (unit_nr,
'(T2,A4,T10,A)') &
382 'BSE|',
"σ_{µ µ'}(ω) = 4πω Im{α_{µ µ'}(ω)} / c"
383 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
384 WRITE (unit_nr,
'(T2,A4,T7,A)') &
385 'BSE|',
"with transition moments d_µ^n, oscillator strengths f_n,"
386 WRITE (unit_nr,
'(T2,A4,T7,A)') &
387 'BSE|',
"excitation energies Ω^n and the speed of light c."
388 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
389 WRITE (unit_nr,
'(T2,A4,T7,A)') &
390 'BSE|',
"Please note that we adopt an additional minus sign for both quantities,"
391 WRITE (unit_nr,
'(T2,A4,T7,A)') &
392 'BSE|',
"due to the convention for charge vs particle density as done in MolGW:"
393 WRITE (unit_nr,
'(T2,A4,T7,A)') &
394 'BSE|',
"https://doi.org/10.1016/j.cpc.2016.06.019."
395 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
398 CALL timestop(handle)
415 mo_coeff, homo, virtual, &
416 info_approximation, &
421 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_y
422 TYPE(
cp_fm_type),
DIMENSION(:),
INTENT(IN) :: mo_coeff
423 INTEGER,
INTENT(IN) :: homo, virtual
424 CHARACTER(LEN=10) :: info_approximation
425 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: oscill_str
427 INTEGER,
INTENT(IN) :: unit_nr
429 CHARACTER(LEN=*),
PARAMETER :: routinen =
'calculate_NTOs'
430 REAL(kind=
dp),
PARAMETER :: coeff_err = 1.0e-5_dp
432 CHARACTER(LEN=20),
DIMENSION(2) :: nto_name
433 INTEGER :: handle, homo_irred, i, i_nto, info_svd, &
434 j, n_exc, n_nto, nao_full, nao_trunc
435 INTEGER,
DIMENSION(:),
POINTER :: stride
436 LOGICAL :: append_cube, cube_file
437 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigval_svd_squ
438 REAL(kind=
dp),
DIMENSION(:),
POINTER :: eigval_svd
440 fm_struct_nto_holes, &
441 fm_struct_nto_particles, &
443 TYPE(
cp_fm_type) :: fm_eigvl, fm_eigvr_t, fm_m, fm_mo_coeff, fm_nto_coeff_holes, &
444 fm_nto_coeff_particles, fm_nto_set, fm_x_ia, fm_y_ai
445 TYPE(
mo_set_type),
ALLOCATABLE,
DIMENSION(:) :: nto_set
448 CALL timeset(routinen, handle)
449 bse_section => bse_env%bse_section
451 nao_full = bse_env%mos(1)%nao
452 nao_trunc = homo + virtual
454 homo_irred = bse_env%mos(1)%homo
463 fm_x%matrix_struct%para_env, fm_x%matrix_struct%context, &
464 nao_trunc, nao_trunc)
466 fm_x%matrix_struct%para_env, fm_x%matrix_struct%context, &
469 fm_x%matrix_struct%para_env, fm_x%matrix_struct%context, &
472 fm_x%matrix_struct%para_env, fm_x%matrix_struct%context, &
475 CALL cp_fm_create(fm_mo_coeff, matrix_struct=fm_struct_mo_coeff, &
481 nao_full, nao_trunc, &
482 1, homo_irred - homo + 1, &
484 mo_coeff(1)%matrix_struct%context)
487 IF (unit_nr > 0)
THEN
488 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
489 'The Natural Transition Orbital (NTO) pairs φ_I(r_e) and χ_I(r_h) for a fixed'
490 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
491 'excitation index n are obtained by singular value decomposition of T'
492 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
493 WRITE (unit_nr,
'(T2,A4,T15,A)')
'BSE|', &
495 IF (
PRESENT(fm_y))
THEN
496 WRITE (unit_nr,
'(T2,A4,T15,A)')
'BSE|', &
499 WRITE (unit_nr,
'(T2,A4,T15,A)')
'BSE|', &
502 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
503 WRITE (unit_nr,
'(T2,A4,T15,A)')
'BSE|', &
505 WRITE (unit_nr,
'(T2,A4,T15,A)')
'BSE|', &
506 'φ_I(r_e) = \sum_p V_pI ψ_p(r_e)'
507 WRITE (unit_nr,
'(T2,A4,T15,A)')
'BSE|', &
508 'χ_I(r_h) = \sum_p U_pI ψ_p(r_e)'
509 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
510 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
511 'where we have introduced'
512 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
513 WRITE (unit_nr,
'(T2,A4,T7,A,T20,A)') &
514 'BSE|',
"ψ_p:",
"occupied and virtual molecular orbitals,"
515 WRITE (unit_nr,
'(T2,A4,T7,A,T20,A)') &
516 'BSE|',
"φ_I(r_e):",
"NTO state for the electron,"
517 WRITE (unit_nr,
'(T2,A4,T7,A,T20,A)') &
518 'BSE|',
"χ_I(r_h):",
"NTO state for the hole,"
519 WRITE (unit_nr,
'(T2,A4,T7,A,T20,A)') &
520 'BSE|',
"Λ:",
"diagonal matrix of NTO weights λ_I,"
521 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
522 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
523 "The NTOs are calculated with the following settings:"
524 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
525 WRITE (unit_nr,
'(T2,A4,T7,A,T71,I10)')
'BSE|',
'Number of excitations, for which NTOs are computed', &
526 bse_env%num_print_exc_ntos
527 IF (bse_env%eps_nto_osc_str > 0.0_dp)
THEN
528 WRITE (unit_nr,
'(T2,A4,T7,A,T71,F10.3)')
'BSE|',
'Threshold for oscillator strength f^n', &
529 bse_env%eps_nto_osc_str
531 WRITE (unit_nr,
'(T2,A4,T7,A,T71,A10)')
'BSE|',
'Threshold for oscillator strength f^n', &
534 WRITE (unit_nr,
'(T2,A4,T7,A,T72,F10.3)')
'BSE|',
'Threshold for NTO weights (λ_I)^2', &
535 bse_env%eps_nto_eigval
539 IF (unit_nr > 0)
THEN
540 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
541 IF (.NOT.
PRESENT(fm_y))
THEN
542 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
543 'NTOs from solving the BSE within the TDA:'
545 WRITE (unit_nr,
'(T2,A4,T7,A)')
'BSE|', &
546 'NTOs from solving the BSE without the TDA:'
548 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
549 WRITE (unit_nr,
'(T2,A4,T8,A12,T22,A8,T33,A14,T62,A)')
'BSE|', &
550 'Excitation n',
"TDA/ABBA",
"Index of NTO I",
'NTO weights (λ_I)^2'
553 DO j = 1, bse_env%num_print_exc_ntos
554 n_exc = bse_env%bse_nto_state_list_final(j)
556 IF (bse_env%eps_nto_osc_str > 0.0_dp)
THEN
558 IF (oscill_str(n_exc) < bse_env%eps_nto_osc_str)
THEN
560 IF (unit_nr > 0)
THEN
561 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
562 WRITE (unit_nr,
'(T2,A4,T8,I12,T24,A6,T42,A39)')
'BSE|', &
563 n_exc, info_approximation,
"Skipped (Oscillator strength too small)"
570 name=
"single_part_trans_dm")
573 CALL cp_fm_create(fm_nto_coeff_holes, matrix_struct=fm_struct_nto_holes, &
574 name=
"nto_coeffs_holes")
577 CALL cp_fm_create(fm_nto_coeff_particles, matrix_struct=fm_struct_nto_particles, &
578 name=
"nto_coeffs_particles")
583 .false., unit_nr, bse_env)
592 IF (
PRESENT(fm_y))
THEN
595 .true., unit_nr, bse_env)
611 matrix_struct=fm_m%matrix_struct, &
612 name=
"LEFT_SINGULAR_MATRIX")
615 matrix_struct=fm_m%matrix_struct, &
616 name=
"RIGHT_SINGULAR_MATRIX")
619 ALLOCATE (eigval_svd(nao_trunc))
620 eigval_svd(:) = 0.0_dp
622 CALL cp_fm_svd(fm_m, fm_eigvl, fm_eigvr_t, eigval_svd, info_svd)
623 IF (info_svd /= 0)
THEN
624 IF (unit_nr > 0)
THEN
625 CALL cp_warn(__location__, &
626 "SVD for computation of NTOs not successful. "// &
627 "Skipping print of NTOs.")
628 IF (info_svd > 0)
THEN
629 CALL cp_warn(__location__, &
630 "PDGESVD detected heterogeneity. "// &
631 "Decreasing number of MPI ranks might solve this issue.")
640 ALLOCATE (eigval_svd_squ(nao_trunc))
641 eigval_svd_squ(:) = eigval_svd(:)**2
643 IF (.NOT.
PRESENT(fm_y))
THEN
644 IF (abs(sum(eigval_svd_squ) - 1) >= coeff_err)
THEN
645 cpwarn(
"Sum of NTO coefficients deviates from 1!")
651 CALL parallel_gemm(
"N",
"N", nao_full, nao_trunc, nao_trunc, 1.0_dp, fm_mo_coeff, fm_eigvl, 0.0_dp, &
655 CALL parallel_gemm(
"N",
"T", nao_full, nao_trunc, nao_trunc, 1.0_dp, fm_mo_coeff, fm_eigvr_t, 0.0_dp, &
656 fm_nto_coeff_particles)
664 nto_name(1) =
'Hole_coord'
665 nto_name(2) =
'Particle_coord'
666 ALLOCATE (nto_set(2))
669 DO i_nto = 1, nao_trunc
670 IF (eigval_svd_squ(i_nto) > bse_env%eps_nto_eigval)
THEN
678 IF (unit_nr > 0)
THEN
679 WRITE (unit_nr,
'(T2,A4)')
'BSE|'
681 WRITE (unit_nr,
'(T2,A4,T8,I12,T24,A6,T41,I6,T71,F10.5)')
'BSE|', &
682 n_exc, info_approximation, i_nto, eigval_svd_squ(i_nto)
690 CALL allocate_mo_set(nto_set(i), nao_trunc, n_nto, 0, 0.0_dp, 2.0_dp, 0.0_dp)
691 CALL init_mo_set(nto_set(i), fm_ref=fm_nto_set, name=nto_name(i))
697 CALL cp_fm_to_fm(fm_nto_coeff_holes, nto_set(1)%mo_coeff, ncol=n_nto)
698 CALL cp_fm_to_fm(fm_nto_coeff_particles, nto_set(2)%mo_coeff, ncol=n_nto)
707 stride, append_cube, nto_section)
712 DEALLOCATE (eigval_svd)
713 DEALLOCATE (eigval_svd_squ)
727 CALL timestop(handle)
744 fm_multipole_ij_trunc, fm_multipole_ab_trunc, &
745 fm_multipole_ai_trunc, &
746 i_exc, homo, virtual, &
750 DIMENSION(:) :: exc_descr
752 TYPE(
cp_fm_type),
ALLOCATABLE,
DIMENSION(:), &
753 INTENT(IN) :: fm_multipole_ij_trunc, &
754 fm_multipole_ab_trunc, &
755 fm_multipole_ai_trunc
756 INTEGER,
INTENT(IN) :: i_exc, homo, virtual
757 TYPE(
cp_fm_type),
INTENT(IN),
OPTIONAL :: fm_y_ia
759 CHARACTER(LEN=*),
PARAMETER :: routinen =
'get_exciton_descriptors'
761 INTEGER :: handle, i_dir, j_dir
762 INTEGER,
DIMENSION(3) :: mask_quadrupole
764 REAL(kind=
dp) :: norm_x, norm_xpy, norm_y
765 REAL(kind=
dp),
DIMENSION(3) :: r_e_sq_x, r_e_sq_y, r_e_x, r_e_y, &
766 r_h_sq_x, r_h_sq_y, r_h_x, r_h_y
767 REAL(kind=
dp),
DIMENSION(3, 3) :: r_e_h_xx, r_e_h_xy, r_e_h_yy
769 TYPE(
cp_fm_type) :: fm_work_ba, fm_work_ia, fm_work_ia_2
771 CALL timeset(routinen, handle)
772 IF (
PRESENT(fm_y_ia))
THEN
780 mask_quadrupole = [4, 7, 9]
783 context=fm_x_ia%matrix_struct%context, nrow_global=homo, ncol_global=virtual)
785 context=fm_x_ia%matrix_struct%context, nrow_global=virtual, ncol_global=virtual)
795 r_e_h_xx(:, :) = 0.0_dp
796 r_e_h_xy(:, :) = 0.0_dp
797 r_e_h_yy(:, :) = 0.0_dp
804 exc_descr(i_exc)%r_e(:) = 0.0_dp
805 exc_descr(i_exc)%r_h(:) = 0.0_dp
806 exc_descr(i_exc)%r_e_sq(:) = 0.0_dp
807 exc_descr(i_exc)%r_h_sq(:) = 0.0_dp
808 exc_descr(i_exc)%r_e_h(:, :) = 0.0_dp
810 exc_descr(i_exc)%flag_TDA = flag_tda
811 exc_descr(i_exc)%norm_XpY = 0.0_dp
817 IF (.NOT. flag_tda)
THEN
819 norm_xpy = norm_xpy + norm_y
822 exc_descr(i_exc)%norm_XpY = norm_xpy
828 r_h_x(i_dir) = r_h_x(i_dir)/norm_xpy
829 IF (.NOT. flag_tda)
THEN
832 r_h_y(i_dir) = r_h_y(i_dir)/norm_xpy
835 exc_descr(i_exc)%r_h(:) = r_h_x(:) + r_h_y(:)
841 r_e_x(i_dir) = r_e_x(i_dir)/norm_xpy
842 IF (.NOT. flag_tda)
THEN
845 r_e_y(i_dir) = r_e_y(i_dir)/norm_xpy
848 exc_descr(i_exc)%r_e(:) = r_e_x(:) + r_e_y(:)
854 fm_x_ia, r_h_sq_x(i_dir))
855 r_h_sq_x(i_dir) = r_h_sq_x(i_dir)/norm_xpy
856 IF (.NOT. flag_tda)
THEN
859 fm_multipole_ab_trunc(mask_quadrupole(i_dir)), r_h_sq_y(i_dir))
860 r_h_sq_y(i_dir) = r_h_sq_y(i_dir)/norm_xpy
863 exc_descr(i_exc)%r_h_sq(:) = r_h_sq_x(:) + r_h_sq_y(:)
869 fm_multipole_ab_trunc(mask_quadrupole(i_dir)), r_e_sq_x(i_dir))
870 r_e_sq_x(i_dir) = r_e_sq_x(i_dir)/norm_xpy
871 IF (.NOT. flag_tda)
THEN
874 fm_y_ia, r_e_sq_y(i_dir))
875 r_e_sq_y(i_dir) = r_e_sq_y(i_dir)/norm_xpy
878 exc_descr(i_exc)%r_e_sq(:) = r_e_sq_x(:) + r_e_sq_y(:)
894 CALL parallel_gemm(
"N",
"N", homo, virtual, virtual, 1.0_dp, &
895 fm_x_ia, fm_multipole_ab_trunc(i_dir), 0.0_dp, fm_work_ia)
898 fm_multipole_ij_trunc(j_dir), fm_work_ia, 0.0_dp, fm_work_ia_2)
900 CALL cp_fm_trace(fm_x_ia, fm_work_ia_2, r_e_h_xx(i_dir, j_dir))
901 r_e_h_xx(i_dir, j_dir) = r_e_h_xx(i_dir, j_dir)/norm_xpy
902 IF (.NOT. flag_tda)
THEN
907 CALL parallel_gemm(
"N",
"N", homo, virtual, virtual, 1.0_dp, &
908 fm_y_ia, fm_multipole_ab_trunc(j_dir), 0.0_dp, fm_work_ia)
911 fm_multipole_ij_trunc(i_dir), fm_work_ia, 0.0_dp, fm_work_ia_2)
913 CALL cp_fm_trace(fm_y_ia, fm_work_ia_2, r_e_h_yy(i_dir, j_dir))
914 r_e_h_yy(i_dir, j_dir) = r_e_h_yy(i_dir, j_dir)/norm_xpy
928 CALL parallel_gemm(
"T",
"T", virtual, virtual, homo, 1.0_dp, &
929 fm_y_ia, fm_multipole_ai_trunc(i_dir), 0.0_dp, fm_work_ba)
931 CALL parallel_gemm(
"T",
"N", homo, virtual, virtual, 1.0_dp, &
932 fm_multipole_ai_trunc(j_dir), fm_work_ba, 0.0_dp, fm_work_ia)
934 CALL cp_fm_trace(fm_work_ia, fm_x_ia, r_e_h_xy(i_dir, j_dir))
935 r_e_h_xy(i_dir, j_dir) = 2.0_dp*r_e_h_xy(i_dir, j_dir)/norm_xpy
939 exc_descr(i_exc)%r_e_h(:, :) = r_e_h_xx(:, :) + r_e_h_xy(:, :) + r_e_h_yy(:, :)
949 exc_descr(i_exc)%diff_r_abs = sqrt(sum((exc_descr(i_exc)%r_h(:) - exc_descr(i_exc)%r_e(:))**2))
952 exc_descr(i_exc)%sigma_e = sqrt(sum(exc_descr(i_exc)%r_e_sq(:)) - sum(exc_descr(i_exc)%r_e(:)**2))
955 exc_descr(i_exc)%sigma_h = sqrt(sum(exc_descr(i_exc)%r_h_sq(:)) - sum(exc_descr(i_exc)%r_h(:)**2))
959 exc_descr(i_exc)%d_eh_dir(i_dir) = abs(exc_descr(i_exc)%r_h(i_dir) - exc_descr(i_exc)%r_e(i_dir))
960 exc_descr(i_exc)%sigma_e_dir(i_dir) = sqrt(exc_descr(i_exc)%r_e_sq(i_dir) - exc_descr(i_exc)%r_e(i_dir)**2)
961 exc_descr(i_exc)%sigma_h_dir(i_dir) = sqrt(exc_descr(i_exc)%r_h_sq(i_dir) - exc_descr(i_exc)%r_h(i_dir)**2)
966 exc_descr(i_exc)%cov_e_h_sum = 0.0_dp
967 exc_descr(i_exc)%cov_e_h(:, :) = 0.0_dp
968 exc_descr(i_exc)%corr_e_h_matrix(:, :) = 0.0_dp
971 exc_descr(i_exc)%cov_e_h(i_dir, j_dir) = exc_descr(i_exc)%r_e_h(i_dir, j_dir) &
972 - exc_descr(i_exc)%r_e(i_dir)*exc_descr(i_exc)%r_h(j_dir)
973 exc_descr(i_exc)%corr_e_h_matrix(i_dir, j_dir) = &
974 exc_descr(i_exc)%cov_e_h(i_dir, j_dir)/ &
975 (exc_descr(i_exc)%sigma_e_dir(i_dir)*exc_descr(i_exc)%sigma_h_dir(j_dir))
977 exc_descr(i_exc)%cov_e_h_sum = exc_descr(i_exc)%cov_e_h_sum + &
978 exc_descr(i_exc)%r_e_h(i_dir, i_dir) - &
979 exc_descr(i_exc)%r_e(i_dir)*exc_descr(i_exc)%r_h(i_dir)
983 exc_descr(i_exc)%corr_e_h = exc_descr(i_exc)%cov_e_h_sum/(exc_descr(i_exc)%sigma_e*exc_descr(i_exc)%sigma_h)
986 exc_descr(i_exc)%diff_r_sqr = sqrt(exc_descr(i_exc)%diff_r_abs**2 + &
987 exc_descr(i_exc)%sigma_e**2 + exc_descr(i_exc)%sigma_h**2 &
988 - 2*exc_descr(i_exc)%cov_e_h_sum)
991 exc_descr(i_exc)%d_exc_dir(i_dir) = sqrt(exc_descr(i_exc)%d_eh_dir(i_dir)**2 + &
992 exc_descr(i_exc)%sigma_e_dir(i_dir)**2 + &
993 exc_descr(i_exc)%sigma_h_dir(i_dir)**2 - &
994 2*exc_descr(i_exc)%cov_e_h(i_dir, i_dir))
998 exc_descr(i_exc)%r_e_shift(:) = exc_descr(i_exc)%r_e(:)
999 exc_descr(i_exc)%r_h_shift(:) = exc_descr(i_exc)%r_h(:)
1004 CALL timestop(handle)
Routines for computing excitonic properties, e.g. exciton diameter, from the BSE.
subroutine, public compute_and_print_absorption_spectrum(oscill_str, polarizability_residues, exc_ens, info_approximation, unit_nr, bse_env)
Computes and returns absorption spectrum for the frequency range and broadening provided by the user....
subroutine, public get_oscillator_strengths(fm_eigvec_x, exc_ens, fm_dipole_ai_trunc, trans_mom_bse, oscill_str, polarizability_residues, bse_env, homo_red, virtual_red, unit_nr, fm_eigvec_y)
Compute and return BSE dipoles d_r^n = sqrt(2) sum_ia < ψ_i | r | ψ_a > ( X_ia^n + Y_ia^n ) and oscil...
subroutine, public get_exciton_descriptors(exc_descr, fm_x_ia, fm_multipole_ij_trunc, fm_multipole_ab_trunc, fm_multipole_ai_trunc, i_exc, homo, virtual, fm_y_ia)
...
subroutine, public calculate_ntos(fm_x, fm_y, mo_coeff, homo, virtual, info_approximation, oscill_str, bse_env, unit_nr)
...
The BSE environment: the settings of the &BSE section and the state a GW path prepares for the solver...
Auxiliary routines for GW + Bethe-Salpeter for computing electronic excitations.
subroutine, public trace_exciton_descr(fm_a, fm_b, fm_c, alpha)
Computes trace of form Tr{A^T B C} for exciton descriptors.
subroutine, public reshuffle_eigvec(fm_eigvec, fm_eigvec_reshuffled, homo, virtual, n_exc, do_transpose, unit_nr, bse_env)
...
subroutine, public print_bse_nto_cubes(bse_env, mos, istate, info_approximation, stride, append_cube, print_section)
Borrowed from the tddfpt module with slight adaptions.
subroutine, public fm_general_add_bse(fm_out, fm_in, beta, nrow_secidx_in, ncol_secidx_in, nrow_secidx_out, ncol_secidx_out, unit_nr, reordering, bse_env, row_offset, col_offset)
Adds and reorders full matrices with a combined index structure, e.g. adding W_ij,...
Utility routines to open and close files. Tracking of preconnections.
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Basic linear algebra operations for full matrices.
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 cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
decomposes a quadratic matrix into its singular value decomposition
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_to_fm_submat_general(source, destination, nrows, ncols, s_firstrow, s_firstcol, d_firstrow, d_firstcol, global_context)
General copy of a submatrix of fm matrix to a submatrix of another fm matrix. The two matrices can ha...
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
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
basic linear algebra operations for full matrixes
Definition of physical constants:
real(kind=dp), parameter, public c_light_au
real(kind=dp), parameter, public evolt
Definition and initialisation of the mo data type.
subroutine, public init_mo_set(mo_set, fm_pool, fm_ref, fm_struct, name, counter, complex_coeff)
initializes an allocated mo_set. eigenvalues, mo_coeff, occupation_numbers are valid only after this ...
subroutine, public allocate_mo_set(mo_set, nao, nmo, nelectron, n_el_f, maxocc, flexible_electron_count)
Allocates a mo set and partially initializes it (nao,nmo,nelectron, and flexible_electron_count are v...
subroutine, public deallocate_mo_set(mo_set)
Deallocate a wavefunction data structure.
Settings of the &BSE section (read_bse_section, re-read by prepare_bse_env, normalised in place by ad...
keeps the information about the structure of a full matrix