LCOV - code coverage report
Current view: top level - src - bse_full_diag.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b8e0b09) Lines: 282 295 95.6 %
Date: 2024-08-31 06:31:37 Functions: 6 6 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Routines for the full diagonalization of GW + Bethe-Salpeter for computing
      10             : !> electronic excitations
      11             : !> \par History
      12             : !>      10.2023 created [Maximilian Graml]
      13             : ! **************************************************************************************************
      14             : MODULE bse_full_diag
      15             : 
      16             :    USE bse_util,                        ONLY: comp_eigvec_coeff_BSE,&
      17             :                                               compute_absorption_spectrum,&
      18             :                                               filter_eigvec_contrib,&
      19             :                                               fm_general_add_bse,&
      20             :                                               get_oscillator_strengths
      21             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      22             :                                               cp_blacs_env_release,&
      23             :                                               cp_blacs_env_type
      24             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_scale_and_add
      25             :    USE cp_fm_diag,                      ONLY: choose_eigv_solver,&
      26             :                                               cp_fm_power
      27             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      28             :                                               cp_fm_struct_release,&
      29             :                                               cp_fm_struct_type
      30             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      31             :                                               cp_fm_get_info,&
      32             :                                               cp_fm_release,&
      33             :                                               cp_fm_set_all,&
      34             :                                               cp_fm_to_fm,&
      35             :                                               cp_fm_type
      36             :    USE input_constants,                 ONLY: bse_singlet,&
      37             :                                               bse_triplet
      38             :    USE kinds,                           ONLY: dp
      39             :    USE message_passing,                 ONLY: mp_para_env_type
      40             :    USE mp2_types,                       ONLY: mp2_type
      41             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      42             :    USE physcon,                         ONLY: evolt
      43             :    USE qs_environment_types,            ONLY: qs_environment_type
      44             : #include "./base/base_uses.f90"
      45             : 
      46             :    IMPLICIT NONE
      47             : 
      48             :    PRIVATE
      49             : 
      50             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'bse_full_diag'
      51             : 
      52             :    PUBLIC :: create_A, diagonalize_A, create_B, create_hermitian_form_of_ABBA, &
      53             :              diagonalize_C
      54             : 
      55             : CONTAINS
      56             : 
      57             : ! **************************************************************************************************
      58             : !> \brief Matrix A constructed from GW energies and 3c-B-matrices (cf. subroutine mult_B_with_W)
      59             : !>   A_ia,jb = (ε_a-ε_i) δ_ij δ_ab + α * v_ia,jb - W_ij,ab
      60             : !>   ε_a, ε_i are GW singleparticle energies from Eigenval_reduced
      61             : !>   α is a spin-dependent factor
      62             : !>   v_ia,jb = \sum_P B^P_ia B^P_jb (unscreened Coulomb interaction)
      63             : !>   W_ij,ab = \sum_P \bar{B}^P_ij B^P_ab (screened Coulomb interaction)
      64             : !> \param fm_mat_S_ia_bse ...
      65             : !> \param fm_mat_S_bar_ij_bse ...
      66             : !> \param fm_mat_S_ab_bse ...
      67             : !> \param fm_A ...
      68             : !> \param Eigenval ...
      69             : !> \param unit_nr ...
      70             : !> \param homo ...
      71             : !> \param virtual ...
      72             : !> \param dimen_RI ...
      73             : !> \param mp2_env ...
      74             : !> \param para_env ...
      75             : ! **************************************************************************************************
      76          18 :    SUBROUTINE create_A(fm_mat_S_ia_bse, fm_mat_S_bar_ij_bse, fm_mat_S_ab_bse, &
      77          18 :                        fm_A, Eigenval, unit_nr, &
      78             :                        homo, virtual, dimen_RI, mp2_env, &
      79             :                        para_env)
      80             : 
      81             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S_ia_bse, fm_mat_S_bar_ij_bse, &
      82             :                                                             fm_mat_S_ab_bse
      83             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_A
      84             :       REAL(KIND=dp), DIMENSION(:)                        :: Eigenval
      85             :       INTEGER, INTENT(IN)                                :: unit_nr, homo, virtual, dimen_RI
      86             :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
      87             :       TYPE(mp_para_env_type), INTENT(INOUT)              :: para_env
      88             : 
      89             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'create_A'
      90             : 
      91             :       INTEGER                                            :: a_virt_row, handle, i_occ_row, &
      92             :                                                             i_row_global, ii, j_col_global, jj, &
      93             :                                                             ncol_local_A, nrow_local_A
      94             :       INTEGER, DIMENSION(4)                              :: reordering
      95          18 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices_A, row_indices_A
      96             :       REAL(KIND=dp)                                      :: alpha, eigen_diff
      97             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
      98             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_A, fm_struct_W
      99             :       TYPE(cp_fm_type)                                   :: fm_W
     100             : 
     101          18 :       CALL timeset(routineN, handle)
     102             : 
     103          18 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     104           0 :          WRITE (unit_nr, '(T2,A10,T13,A10)') 'BSE|DEBUG|', 'Creating A'
     105             :       END IF
     106             : 
     107             :       !Determines factor of exchange term, depending on requested spin configuration (cf. input_constants.F)
     108          36 :       SELECT CASE (mp2_env%ri_g0w0%bse_spin_config)
     109             :       CASE (bse_singlet)
     110          18 :          alpha = 2.0_dp
     111             :       CASE (bse_triplet)
     112          18 :          alpha = 0.0_dp
     113             :       END SELECT
     114             : 
     115             :       ! create the blacs env for ij matrices (NOT fm_mat_S_ia_bse%matrix_struct related parallel_gemms!)
     116          18 :       NULLIFY (blacs_env)
     117          18 :       CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=para_env)
     118             : 
     119             :       ! We have to use the same blacs_env for A as for the matrices fm_mat_S_ia_bse from RPA
     120             :       ! Logic: A_ia,jb = (ε_a-ε_i) δ_ij δ_ab + α * v_ia,jb - W_ij,ab
     121             :       ! We create v_ia,jb and W_ij,ab, then we communicate entries from local W_ij,ab
     122             :       ! to the full matrix v_ia,jb. By adding these and the energy diffenences: v_ia,jb -> A_ia,jb
     123             :       ! We use the A matrix already from the start instead of v
     124             :       CALL cp_fm_struct_create(fm_struct_A, context=fm_mat_S_ia_bse%matrix_struct%context, nrow_global=homo*virtual, &
     125          18 :                                ncol_global=homo*virtual, para_env=fm_mat_S_ia_bse%matrix_struct%para_env)
     126          18 :       CALL cp_fm_create(fm_A, fm_struct_A, name="fm_A_iajb")
     127          18 :       CALL cp_fm_set_all(fm_A, 0.0_dp)
     128             : 
     129             :       CALL cp_fm_struct_create(fm_struct_W, context=fm_mat_S_ab_bse%matrix_struct%context, nrow_global=homo**2, &
     130          18 :                                ncol_global=virtual**2, para_env=fm_mat_S_ab_bse%matrix_struct%para_env)
     131          18 :       CALL cp_fm_create(fm_W, fm_struct_W, name="fm_W_ijab")
     132          18 :       CALL cp_fm_set_all(fm_W, 0.0_dp)
     133             : 
     134             :       ! Create A matrix from GW Energies, v_ia,jb and W_ij,ab (different blacs_env!)
     135             :       ! v_ia,jb, which is directly initialized in A (with a factor of alpha)
     136             :       ! v_ia,jb = \sum_P B^P_ia B^P_jb
     137             :       CALL parallel_gemm(transa="T", transb="N", m=homo*virtual, n=homo*virtual, k=dimen_RI, alpha=alpha, &
     138             :                          matrix_a=fm_mat_S_ia_bse, matrix_b=fm_mat_S_ia_bse, beta=0.0_dp, &
     139          18 :                          matrix_c=fm_A)
     140             : 
     141          18 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     142           0 :          WRITE (unit_nr, '(T2,A10,T13,A16)') 'BSE|DEBUG|', 'Allocated A_iajb'
     143             :       END IF
     144             : 
     145             :       !W_ij,ab = \sum_P \bar{B}^P_ij B^P_ab
     146             :       CALL parallel_gemm(transa="T", transb="N", m=homo**2, n=virtual**2, k=dimen_RI, alpha=1.0_dp, &
     147             :                          matrix_a=fm_mat_S_bar_ij_bse, matrix_b=fm_mat_S_ab_bse, beta=0.0_dp, &
     148          18 :                          matrix_c=fm_W)
     149             : 
     150          18 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     151           0 :          WRITE (unit_nr, '(T2,A10,T13,A16)') 'BSE|DEBUG|', 'Allocated W_ijab'
     152             :       END IF
     153             : 
     154             :       ! We start by moving data from local parts of W_ij,ab to the full matrix A_ia,jb using buffers
     155             :       CALL cp_fm_get_info(matrix=fm_A, &
     156             :                           nrow_local=nrow_local_A, &
     157             :                           ncol_local=ncol_local_A, &
     158             :                           row_indices=row_indices_A, &
     159          18 :                           col_indices=col_indices_A)
     160             :       ! Writing -1.0_dp * W_ij,ab to A_ia,jb, i.e. beta = -1.0_dp,
     161             :       ! W_ij,ab: nrow_secidx_in  = homo,    ncol_secidx_in  = virtual
     162             :       ! A_ia,jb: nrow_secidx_out = virtual, ncol_secidx_out = virtual
     163          18 :       reordering = (/1, 3, 2, 4/)
     164             :       CALL fm_general_add_bse(fm_A, fm_W, -1.0_dp, homo, virtual, &
     165          18 :                               virtual, virtual, unit_nr, reordering, mp2_env)
     166             :       !full matrix W is not needed anymore, release it to save memory
     167          18 :       CALL cp_fm_release(fm_W)
     168             : 
     169             :       !Now add the energy differences (ε_a-ε_i) on the diagonal (i.e. δ_ij δ_ab) of A_ia,jb
     170         450 :       DO ii = 1, nrow_local_A
     171             : 
     172         432 :          i_row_global = row_indices_A(ii)
     173             : 
     174       21186 :          DO jj = 1, ncol_local_A
     175             : 
     176       20736 :             j_col_global = col_indices_A(jj)
     177             : 
     178       21168 :             IF (i_row_global == j_col_global) THEN
     179         432 :                i_occ_row = (i_row_global - 1)/virtual + 1
     180         432 :                a_virt_row = MOD(i_row_global - 1, virtual) + 1
     181         432 :                eigen_diff = Eigenval(a_virt_row + homo) - Eigenval(i_occ_row)
     182         432 :                fm_A%local_data(ii, jj) = fm_A%local_data(ii, jj) + eigen_diff
     183             : 
     184             :             END IF
     185             :          END DO
     186             :       END DO
     187             : 
     188          18 :       CALL cp_fm_struct_release(fm_struct_A)
     189          18 :       CALL cp_fm_struct_release(fm_struct_W)
     190             : 
     191          18 :       CALL cp_blacs_env_release(blacs_env)
     192             : 
     193          18 :       CALL timestop(handle)
     194             : 
     195          72 :    END SUBROUTINE create_A
     196             : 
     197             : ! **************************************************************************************************
     198             : !> \brief Matrix B constructed from 3c-B-matrices (cf. subroutine mult_B_with_W)
     199             : !>   B_ia,jb = α * v_ia,jb - W_ib,aj
     200             : !>   α is a spin-dependent factor
     201             : !>   v_ia,jb = \sum_P B^P_ia B^P_jb (unscreened Coulomb interaction)
     202             : !>   W_ib,aj = \sum_P \bar{B}^P_ib B^P_aj (screened Coulomb interaction)
     203             : !> \param fm_mat_S_ia_bse ...
     204             : !> \param fm_mat_S_bar_ia_bse ...
     205             : !> \param fm_B ...
     206             : !> \param homo ...
     207             : !> \param virtual ...
     208             : !> \param dimen_RI ...
     209             : !> \param unit_nr ...
     210             : !> \param mp2_env ...
     211             : ! **************************************************************************************************
     212           6 :    SUBROUTINE create_B(fm_mat_S_ia_bse, fm_mat_S_bar_ia_bse, fm_B, &
     213             :                        homo, virtual, dimen_RI, unit_nr, mp2_env)
     214             : 
     215             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S_ia_bse, fm_mat_S_bar_ia_bse
     216             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_B
     217             :       INTEGER, INTENT(IN)                                :: homo, virtual, dimen_RI, unit_nr
     218             :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
     219             : 
     220             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'create_B'
     221             : 
     222             :       INTEGER                                            :: handle
     223             :       INTEGER, DIMENSION(4)                              :: reordering
     224             :       REAL(KIND=dp)                                      :: alpha
     225             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_v
     226             :       TYPE(cp_fm_type)                                   :: fm_W
     227             : 
     228           6 :       CALL timeset(routineN, handle)
     229             : 
     230           6 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     231           0 :          WRITE (unit_nr, '(T2,A10,T13,A10)') 'BSE|DEBUG|', 'Creating B'
     232             :       END IF
     233             : 
     234             :       ! Determines factor of exchange term, depending on requested spin configuration (cf. input_constants.F)
     235          12 :       SELECT CASE (mp2_env%ri_g0w0%bse_spin_config)
     236             :       CASE (bse_singlet)
     237           6 :          alpha = 2.0_dp
     238             :       CASE (bse_triplet)
     239           6 :          alpha = 0.0_dp
     240             :       END SELECT
     241             : 
     242             :       CALL cp_fm_struct_create(fm_struct_v, context=fm_mat_S_ia_bse%matrix_struct%context, nrow_global=homo*virtual, &
     243           6 :                                ncol_global=homo*virtual, para_env=fm_mat_S_ia_bse%matrix_struct%para_env)
     244           6 :       CALL cp_fm_create(fm_B, fm_struct_v, name="fm_B_iajb")
     245           6 :       CALL cp_fm_set_all(fm_B, 0.0_dp)
     246             : 
     247           6 :       CALL cp_fm_create(fm_W, fm_struct_v, name="fm_W_ibaj")
     248           6 :       CALL cp_fm_set_all(fm_W, 0.0_dp)
     249             : 
     250           6 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     251           0 :          WRITE (unit_nr, '(T2,A10,T13,A16)') 'BSE|DEBUG|', 'Allocated B_iajb'
     252             :       END IF
     253             :       ! v_ia,jb = \sum_P B^P_ia B^P_jb
     254             :       CALL parallel_gemm(transa="T", transb="N", m=homo*virtual, n=homo*virtual, k=dimen_RI, alpha=alpha, &
     255             :                          matrix_a=fm_mat_S_ia_bse, matrix_b=fm_mat_S_ia_bse, beta=0.0_dp, &
     256           6 :                          matrix_c=fm_B)
     257             : 
     258             :       ! W_ib,aj = \sum_P \bar{B}^P_ib B^P_aj
     259             :       CALL parallel_gemm(transa="T", transb="N", m=homo*virtual, n=homo*virtual, k=dimen_RI, alpha=1.0_dp, &
     260             :                          matrix_a=fm_mat_S_bar_ia_bse, matrix_b=fm_mat_S_ia_bse, beta=0.0_dp, &
     261           6 :                          matrix_c=fm_W)
     262             :       ! from W_ib,ja to A_ia,jb (formally: W_ib,aj, but our internal indexorder is different)
     263             :       ! Writing -1.0_dp * W_ib,ja to A_ia,jb, i.e. beta = -1.0_dp,
     264             :       ! W_ib,ja: nrow_secidx_in  = virtual,    ncol_secidx_in  = virtual
     265             :       ! A_ia,jb: nrow_secidx_out = virtual, ncol_secidx_out = virtual
     266           6 :       reordering = (/1, 4, 3, 2/)
     267             :       CALL fm_general_add_bse(fm_B, fm_W, -1.0_dp, virtual, virtual, &
     268           6 :                               virtual, virtual, unit_nr, reordering, mp2_env)
     269             : 
     270           6 :       CALL cp_fm_release(fm_W)
     271           6 :       CALL cp_fm_struct_release(fm_struct_v)
     272           6 :       CALL timestop(handle)
     273             : 
     274          18 :    END SUBROUTINE create_B
     275             : 
     276             :    ! **************************************************************************************************
     277             : !> \brief Construct Matrix C=(A-B)^0.5 (A+B) (A-B)^0.5 to solve full BSE matrix as a hermitian problem
     278             : !>   (cf. Eq. (A7) in F. Furche J. Chem. Phys., Vol. 114, No. 14, (2001)).
     279             : !>   We keep fm_sqrt_A_minus_B and fm_inv_sqrt_A_minus_B for print of singleparticle transitions
     280             : !>   of ABBA as described in Eq. (A10) in F. Furche J. Chem. Phys., Vol. 114, No. 14, (2001).
     281             : !> \param fm_A ...
     282             : !> \param fm_B ...
     283             : !> \param fm_C ...
     284             : !> \param fm_sqrt_A_minus_B ...
     285             : !> \param fm_inv_sqrt_A_minus_B ...
     286             : !> \param homo ...
     287             : !> \param virtual ...
     288             : !> \param unit_nr ...
     289             : !> \param mp2_env ...
     290             : !> \param diag_est ...
     291             : ! **************************************************************************************************
     292          48 :    SUBROUTINE create_hermitian_form_of_ABBA(fm_A, fm_B, fm_C, &
     293             :                                             fm_sqrt_A_minus_B, fm_inv_sqrt_A_minus_B, &
     294             :                                             homo, virtual, unit_nr, mp2_env, diag_est)
     295             : 
     296             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_A, fm_B
     297             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_C, fm_sqrt_A_minus_B, &
     298             :                                                             fm_inv_sqrt_A_minus_B
     299             :       INTEGER, INTENT(IN)                                :: homo, virtual, unit_nr
     300             :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
     301             :       REAL(KIND=dp), INTENT(IN)                          :: diag_est
     302             : 
     303             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'create_hermitian_form_of_ABBA'
     304             : 
     305             :       INTEGER                                            :: dim_mat, handle, n_dependent
     306             :       REAL(KIND=dp), DIMENSION(2)                        :: eigvals_AB_diff
     307             :       TYPE(cp_fm_type)                                   :: fm_A_minus_B, fm_A_plus_B, fm_dummy, &
     308             :                                                             fm_work_product
     309             : 
     310           6 :       CALL timeset(routineN, handle)
     311             : 
     312           6 :       IF (unit_nr > 0) THEN
     313           3 :          WRITE (unit_nr, '(T2,A4,T7,A25,A39,ES6.0,A3)') 'BSE|', 'Diagonalizing aux. matrix', &
     314           6 :             ' with size of A. This will take around ', diag_est, " s."
     315             :       END IF
     316             : 
     317             :       ! Create work matrices, which will hold A+B and A-B and their powers
     318             :       ! C is created afterwards to save memory
     319             :       ! Final result: C = (A-B)^0.5             (A+B)              (A-B)^0.5              EQ.I
     320             :       !                   \_______/             \___/              \______/
     321             :       !               fm_sqrt_A_minus_B      fm_A_plus_B     fm_sqrt_A_minus_B
     322             :       !                    (EQ.Ia)             (EQ.Ib)              (EQ.Ia)
     323             :       ! Intermediate work matrices:
     324             :       ! fm_inv_sqrt_A_minus_B: (A-B)^-0.5                                                 EQ.II
     325             :       ! fm_A_minus_B: (A-B)                                                               EQ.III
     326             :       ! fm_work_product: (A-B)^0.5 (A+B) from (EQ.Ia) and (EQ.Ib)                         EQ.IV
     327           6 :       CALL cp_fm_create(fm_A_plus_B, fm_A%matrix_struct)
     328           6 :       CALL cp_fm_to_fm(fm_A, fm_A_plus_B)
     329           6 :       CALL cp_fm_create(fm_A_minus_B, fm_A%matrix_struct)
     330           6 :       CALL cp_fm_to_fm(fm_A, fm_A_minus_B)
     331           6 :       CALL cp_fm_create(fm_sqrt_A_minus_B, fm_A%matrix_struct)
     332           6 :       CALL cp_fm_set_all(fm_sqrt_A_minus_B, 0.0_dp)
     333           6 :       CALL cp_fm_create(fm_inv_sqrt_A_minus_B, fm_A%matrix_struct)
     334           6 :       CALL cp_fm_set_all(fm_inv_sqrt_A_minus_B, 0.0_dp)
     335             : 
     336           6 :       CALL cp_fm_create(fm_work_product, fm_A%matrix_struct)
     337             : 
     338           6 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     339           0 :          WRITE (unit_nr, '(T2,A10,T13,A19)') 'BSE|DEBUG|', 'Created work arrays'
     340             :       END IF
     341             : 
     342             :       ! Add/Substract B (cf. EQs. Ib and III)
     343           6 :       CALL cp_fm_scale_and_add(1.0_dp, fm_A_plus_B, 1.0_dp, fm_B)
     344           6 :       CALL cp_fm_scale_and_add(1.0_dp, fm_A_minus_B, -1.0_dp, fm_B)
     345             : 
     346             :       ! cp_fm_power will overwrite matrix, therefore we create copies
     347           6 :       CALL cp_fm_to_fm(fm_A_minus_B, fm_inv_sqrt_A_minus_B)
     348             : 
     349             :       ! In order to avoid a second diagonalization (cp_fm_power), we create (A-B)^0.5 (EQ.Ia)
     350             :       ! from (A-B)^-0.5 (EQ.II) by multiplication with (A-B) (EQ.III) afterwards.
     351             : 
     352             :       ! Raise A-B to -0.5_dp, no quenching of eigenvectors, hence threshold=0.0_dp
     353           6 :       CALL cp_fm_create(fm_dummy, fm_A%matrix_struct)
     354             :       ! Create (A-B)^-0.5 (cf. EQ.II)
     355           6 :       CALL cp_fm_power(fm_inv_sqrt_A_minus_B, fm_dummy, -0.5_dp, 0.0_dp, n_dependent, eigvals=eigvals_AB_diff)
     356           6 :       CALL cp_fm_release(fm_dummy)
     357             :       ! Raise an error in case the the matrix A-B is not positive definite (i.e. negative eigenvalues)
     358             :       ! In this case, the procedure for hermitian form of ABBA is not applicable
     359           6 :       IF (eigvals_AB_diff(1) < 0) THEN
     360             :          CALL cp_abort(__LOCATION__, &
     361             :                        "Matrix (A-B) is not positive definite. "// &
     362           0 :                        "Hermitian diagonalization of full ABBA matrix is ill-defined.")
     363             :       END IF
     364             : 
     365             :       ! We keep fm_inv_sqrt_A_minus_B for print of singleparticle transitions of ABBA
     366             :       ! We further create (A-B)^0.5 for the singleparticle transitions of ABBA
     367             :       ! Create (A-B)^0.5= (A-B)^-0.5 * (A-B) (EQ.Ia)
     368           6 :       dim_mat = homo*virtual
     369             :       CALL parallel_gemm("N", "N", dim_mat, dim_mat, dim_mat, 1.0_dp, fm_inv_sqrt_A_minus_B, fm_A_minus_B, 0.0_dp, &
     370           6 :                          fm_sqrt_A_minus_B)
     371             : 
     372             :       ! Compute and store LHS of C, i.e. (A-B)^0.5 (A+B) (EQ.IV)
     373             :       CALL parallel_gemm("N", "N", dim_mat, dim_mat, dim_mat, 1.0_dp, fm_sqrt_A_minus_B, fm_A_plus_B, 0.0_dp, &
     374           6 :                          fm_work_product)
     375             : 
     376             :       ! Release to save memory
     377           6 :       CALL cp_fm_release(fm_A_plus_B)
     378           6 :       CALL cp_fm_release(fm_A_minus_B)
     379             : 
     380             :       ! Now create full
     381           6 :       CALL cp_fm_create(fm_C, fm_A%matrix_struct)
     382           6 :       CALL cp_fm_set_all(fm_C, 0.0_dp)
     383             :       ! Compute C=(A-B)^0.5 (A+B) (A-B)^0.5 (EQ.I)
     384             :       CALL parallel_gemm("N", "N", dim_mat, dim_mat, dim_mat, 1.0_dp, fm_work_product, fm_sqrt_A_minus_B, 0.0_dp, &
     385           6 :                          fm_C)
     386           6 :       CALL cp_fm_release(fm_work_product)
     387             : 
     388           6 :       IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
     389           0 :          WRITE (unit_nr, '(T2,A10,T13,A36)') 'BSE|DEBUG|', 'Filled C=(A-B)^0.5 (A+B) (A-B)^0.5'
     390             :       END IF
     391             : 
     392           6 :       CALL timestop(handle)
     393           6 :    END SUBROUTINE
     394             : 
     395             : ! **************************************************************************************************
     396             : !> \brief Solving eigenvalue equation C Z^n = (Ω^n)^2 Z^n .
     397             : !>   Here, the eigenvectors Z^n relate to X^n via
     398             : !>   Eq. (A10) in F. Furche J. Chem. Phys., Vol. 114, No. 14, (2001).
     399             : !> \param fm_C ...
     400             : !> \param homo ...
     401             : !> \param virtual ...
     402             : !> \param homo_irred ...
     403             : !> \param fm_sqrt_A_minus_B ...
     404             : !> \param fm_inv_sqrt_A_minus_B ...
     405             : !> \param unit_nr ...
     406             : !> \param diag_est ...
     407             : !> \param mp2_env ...
     408             : !> \param qs_env ...
     409             : !> \param mo_coeff ...
     410             : ! **************************************************************************************************
     411           6 :    SUBROUTINE diagonalize_C(fm_C, homo, virtual, homo_irred, &
     412             :                             fm_sqrt_A_minus_B, fm_inv_sqrt_A_minus_B, &
     413           6 :                             unit_nr, diag_est, mp2_env, qs_env, mo_coeff)
     414             : 
     415             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_C
     416             :       INTEGER, INTENT(IN)                                :: homo, virtual, homo_irred
     417             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_sqrt_A_minus_B, fm_inv_sqrt_A_minus_B
     418             :       INTEGER, INTENT(IN)                                :: unit_nr
     419             :       REAL(KIND=dp), INTENT(IN)                          :: diag_est
     420             :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
     421             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     422             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
     423             : 
     424             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'diagonalize_C'
     425             : 
     426             :       INTEGER                                            :: diag_info, handle
     427           6 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: Exc_ens
     428             :       TYPE(cp_fm_type)                                   :: fm_eigvec_X, fm_eigvec_Y, fm_eigvec_Z, &
     429             :                                                             fm_mat_eigvec_transform_diff, &
     430             :                                                             fm_mat_eigvec_transform_sum
     431             : 
     432           6 :       CALL timeset(routineN, handle)
     433             : 
     434           6 :       IF (unit_nr > 0) THEN
     435           3 :          WRITE (unit_nr, '(T2,A4,T7,A17,A22,ES6.0,A3)') 'BSE|', 'Diagonalizing C. ', &
     436           6 :             'This will take around ', diag_est, ' s.'
     437             :       END IF
     438             : 
     439             :       !We have now the full matrix C=(A-B)^0.5 (A+B) (A-B)^0.5
     440             :       !Now: Diagonalize it
     441           6 :       CALL cp_fm_create(fm_eigvec_Z, fm_C%matrix_struct)
     442             : 
     443          18 :       ALLOCATE (Exc_ens(homo*virtual))
     444             : 
     445           6 :       CALL choose_eigv_solver(fm_C, fm_eigvec_Z, Exc_ens, diag_info)
     446           6 :       CPASSERT(diag_info == 0)
     447             :       ! C could have negative eigenvalues, since we do not explicitly check A+B
     448             :       ! for positive definiteness (would make another O(N^6) Diagon. necessary)
     449             :       ! Instead, we include a check here
     450           6 :       IF (Exc_ens(1) < 0) THEN
     451             :          CALL cp_abort(__LOCATION__, &
     452             :                        "Matrix C=(A-B)^0.5 (A+B) (A-B)^0.5 has negative eigenvalues, i.e. "// &
     453           0 :                        "(A+B) is not positive definite.")
     454             :       END IF
     455         294 :       Exc_ens = SQRT(Exc_ens)
     456             : 
     457             :       ! Prepare eigenvector for interpretation of singleparticle transitions
     458             :       ! Compare: F. Furche J. Chem. Phys., Vol. 114, No. 14, (2001)
     459             :       ! We aim for the upper part of the vector (X,Y) for a direct comparison with the TDA result
     460             : 
     461             :       ! Following Furche, we basically use Eqs. (A10): First, we multiply
     462             :       ! the (A-B)^+-0.5 with eigenvectors and then the eigenvalues
     463             :       ! One has to be careful about the index structure, since the eigenvector matrix is not symmetric anymore!
     464             : 
     465             :       ! First, Eq. I from (A10) from Furche: (X+Y)_n = (Ω_n)^-0.5 (A-B)^0.5 T_n
     466           6 :       CALL cp_fm_create(fm_mat_eigvec_transform_sum, fm_C%matrix_struct)
     467           6 :       CALL cp_fm_set_all(fm_mat_eigvec_transform_sum, 0.0_dp)
     468             :       CALL parallel_gemm(transa="N", transb="N", m=homo*virtual, n=homo*virtual, k=homo*virtual, alpha=1.0_dp, &
     469             :                          matrix_a=fm_sqrt_A_minus_B, matrix_b=fm_eigvec_Z, beta=0.0_dp, &
     470           6 :                          matrix_c=fm_mat_eigvec_transform_sum)
     471           6 :       CALL cp_fm_release(fm_sqrt_A_minus_B)
     472           6 :       CALL comp_eigvec_coeff_BSE(fm_mat_eigvec_transform_sum, Exc_ens, -0.5_dp, gamma=2.0_dp, do_transpose=.TRUE.)
     473             : 
     474             :       ! Second, Eq. II from (A10) from Furche: (X-Y)_n = (Ω_n)^0.5 (A-B)^-0.5 T_n
     475           6 :       CALL cp_fm_create(fm_mat_eigvec_transform_diff, fm_C%matrix_struct)
     476           6 :       CALL cp_fm_set_all(fm_mat_eigvec_transform_diff, 0.0_dp)
     477             :       CALL parallel_gemm(transa="N", transb="N", m=homo*virtual, n=homo*virtual, k=homo*virtual, alpha=1.0_dp, &
     478             :                          matrix_a=fm_inv_sqrt_A_minus_B, matrix_b=fm_eigvec_Z, beta=0.0_dp, &
     479           6 :                          matrix_c=fm_mat_eigvec_transform_diff)
     480           6 :       CALL cp_fm_release(fm_inv_sqrt_A_minus_B)
     481           6 :       CALL cp_fm_release(fm_eigvec_Z)
     482           6 :       CALL comp_eigvec_coeff_BSE(fm_mat_eigvec_transform_diff, Exc_ens, 0.5_dp, gamma=2.0_dp, do_transpose=.TRUE.)
     483             : 
     484             :       ! Now, we add the two equations to obtain X_n
     485             :       ! Add overwrites the first argument, therefore we copy it beforehand
     486           6 :       CALL cp_fm_create(fm_eigvec_X, fm_C%matrix_struct)
     487           6 :       CALL cp_fm_to_fm(fm_mat_eigvec_transform_sum, fm_eigvec_X)
     488           6 :       CALL cp_fm_scale_and_add(1.0_dp, fm_eigvec_X, 1.0_dp, fm_mat_eigvec_transform_diff)
     489             : 
     490             :       ! Now, we subtract the two equations to obtain Y_n
     491             :       ! Add overwrites the first argument, therefore we copy it beforehand
     492           6 :       CALL cp_fm_create(fm_eigvec_Y, fm_C%matrix_struct)
     493           6 :       CALL cp_fm_to_fm(fm_mat_eigvec_transform_sum, fm_eigvec_Y)
     494           6 :       CALL cp_fm_scale_and_add(1.0_dp, fm_eigvec_Y, -1.0_dp, fm_mat_eigvec_transform_diff)
     495             : 
     496             :       !Cleanup
     497           6 :       CALL cp_fm_release(fm_mat_eigvec_transform_diff)
     498           6 :       CALL cp_fm_release(fm_mat_eigvec_transform_sum)
     499             : 
     500             :       CALL success_message(Exc_ens, fm_eigvec_X, mp2_env, qs_env, mo_coeff, &
     501             :                            homo, virtual, homo_irred, unit_nr, &
     502           6 :                            .FALSE., fm_eigvec_Y)
     503             : 
     504           6 :       DEALLOCATE (Exc_ens)
     505           6 :       CALL cp_fm_release(fm_eigvec_X)
     506           6 :       CALL cp_fm_release(fm_eigvec_Y)
     507             : 
     508           6 :       CALL timestop(handle)
     509             : 
     510          42 :    END SUBROUTINE diagonalize_C
     511             : 
     512             : ! **************************************************************************************************
     513             : !> \brief Solving hermitian eigenvalue equation A X^n = Ω^n X^n
     514             : !> \param fm_A ...
     515             : !> \param homo ...
     516             : !> \param virtual ...
     517             : !> \param homo_irred ...
     518             : !> \param unit_nr ...
     519             : !> \param diag_est ...
     520             : !> \param mp2_env ...
     521             : !> \param qs_env ...
     522             : !> \param mo_coeff ...
     523             : ! **************************************************************************************************
     524          12 :    SUBROUTINE diagonalize_A(fm_A, homo, virtual, homo_irred, &
     525          12 :                             unit_nr, diag_est, mp2_env, qs_env, mo_coeff)
     526             : 
     527             :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_A
     528             :       INTEGER, INTENT(IN)                                :: homo, virtual, homo_irred, unit_nr
     529             :       REAL(KIND=dp), INTENT(IN)                          :: diag_est
     530             :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
     531             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     532             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
     533             : 
     534             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'diagonalize_A'
     535             : 
     536             :       INTEGER                                            :: diag_info, handle
     537          12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: Exc_ens
     538             :       TYPE(cp_fm_type)                                   :: fm_eigvec
     539             : 
     540          12 :       CALL timeset(routineN, handle)
     541             : 
     542             :       !Continue with formatting of subroutine create_A
     543          12 :       IF (unit_nr > 0) THEN
     544           6 :          WRITE (unit_nr, '(T2,A4,T7,A17,A22,ES6.0,A3)') 'BSE|', 'Diagonalizing A. ', &
     545          12 :             'This will take around ', diag_est, ' s.'
     546             :       END IF
     547             : 
     548             :       !We have now the full matrix A_iajb, distributed over all ranks
     549             :       !Now: Diagonalize it
     550          12 :       CALL cp_fm_create(fm_eigvec, fm_A%matrix_struct)
     551             : 
     552          36 :       ALLOCATE (Exc_ens(homo*virtual))
     553             : 
     554          12 :       CALL choose_eigv_solver(fm_A, fm_eigvec, Exc_ens, diag_info)
     555          12 :       CPASSERT(diag_info == 0)
     556             :       CALL success_message(Exc_ens, fm_eigvec, mp2_env, qs_env, mo_coeff, &
     557          12 :                            homo, virtual, homo_irred, unit_nr, .TRUE.)
     558             : 
     559          12 :       CALL cp_fm_release(fm_eigvec)
     560          12 :       DEALLOCATE (Exc_ens)
     561             : 
     562          12 :       CALL timestop(handle)
     563             : 
     564          36 :    END SUBROUTINE diagonalize_A
     565             : 
     566             : ! **************************************************************************************************
     567             : !> \brief Prints the success message (incl. energies) for full diag of BSE (TDA/full ABBA via flag)
     568             : !> \param Exc_ens ...
     569             : !> \param fm_eigvec_X ...
     570             : !> \param mp2_env ...
     571             : !> \param qs_env ...
     572             : !> \param mo_coeff ...
     573             : !> \param homo ...
     574             : !> \param virtual ...
     575             : !> \param homo_irred ...
     576             : !> \param unit_nr ...
     577             : !> \param flag_TDA ...
     578             : !> \param fm_eigvec_Y ...
     579             : ! **************************************************************************************************
     580          18 :    SUBROUTINE success_message(Exc_ens, fm_eigvec_X, mp2_env, qs_env, mo_coeff, &
     581             :                               homo, virtual, homo_irred, unit_nr, &
     582             :                               flag_TDA, fm_eigvec_Y)
     583             : 
     584             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: Exc_ens
     585             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_eigvec_X
     586             :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
     587             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     588             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
     589             :       INTEGER                                            :: homo, virtual, homo_irred, unit_nr
     590             :       LOGICAL, OPTIONAL                                  :: flag_TDA
     591             :       TYPE(cp_fm_type), INTENT(IN), OPTIONAL             :: fm_eigvec_Y
     592             : 
     593             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'success_message'
     594             : 
     595             :       CHARACTER(LEN=10)                                  :: info_approximation, multiplet
     596             :       INTEGER                                            :: handle, i_exc, k, num_entries
     597          18 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: idx_homo, idx_virt
     598             :       REAL(KIND=dp)                                      :: alpha
     599          18 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigvec_entries, oscill_str
     600          18 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: dipole_exc
     601             : 
     602          18 :       CALL timeset(routineN, handle)
     603             : 
     604             :       !Prepare variables for printing
     605          18 :       IF (mp2_env%ri_g0w0%bse_spin_config == 0) THEN
     606          18 :          multiplet = "Singlet"
     607          18 :          alpha = 2.0_dp
     608             :       ELSE
     609           0 :          multiplet = "Triplet"
     610           0 :          alpha = 0.0_dp
     611             :       END IF
     612          18 :       IF (.NOT. PRESENT(flag_TDA)) THEN
     613           0 :          flag_TDA = .FALSE.
     614             :       END IF
     615          18 :       IF (flag_TDA) THEN
     616          12 :          info_approximation = " -TDA- "
     617             :       ELSE
     618           6 :          info_approximation = "-ABBA-"
     619             :       END IF
     620             : 
     621             :       !Get information about eigenvector
     622             : 
     623          18 :       IF (unit_nr > 0) THEN
     624           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     625           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     626           9 :          IF (flag_TDA) THEN
     627           6 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
     628           6 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '*   Bethe Salpeter equation (BSE) with Tamm Dancoff approximation (TDA)  *'
     629           6 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
     630           6 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     631           6 :             WRITE (unit_nr, '(T2,A4,T7,A48,A23)') 'BSE|', 'The excitations are calculated by diagonalizing ', &
     632          12 :                'the BSE within the TDA:'
     633           6 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     634           6 :             WRITE (unit_nr, '(T2,A4,T29,A16)') 'BSE|', 'A X^n = Ω^n X^n'
     635           6 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     636           6 :             WRITE (unit_nr, '(T2,A4,T7,A23)') 'BSE|', 'i.e. in index notation:'
     637           6 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     638           6 :             WRITE (unit_nr, '(T2,A4,T7,A41)') 'BSE|', 'sum_jb ( A_ia,jb   X_jb^n ) = Ω^n X_ia^n'
     639           6 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     640           6 :             WRITE (unit_nr, '(T2,A4,T7,A30)') 'BSE|', 'prelim Ref.: Eq. (36) with B=0'
     641           6 :             WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
     642             :          ELSE
     643           3 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
     644           3 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '*      Full ("ABBA") Bethe Salpeter equation (BSE) (i.e. without TDA)    *'
     645           3 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
     646           3 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     647           3 :             WRITE (unit_nr, '(T2,A4,T7,A48,A24)') 'BSE|', 'The excitations are calculated by diagonalizing ', &
     648           6 :                'the BSE without the TDA:'
     649           3 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     650           3 :             WRITE (unit_nr, '(T2,A4,T22,A30)') 'BSE|', '|A B| |X^n|       |1  0| |X^n|'
     651           3 :             WRITE (unit_nr, '(T2,A4,T22,A31)') 'BSE|', '|B A| |Y^n| = Ω^n |0 -1| |Y^n|'
     652           3 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     653           3 :             WRITE (unit_nr, '(T2,A4,T7,A23)') 'BSE|', 'i.e. in index notation:'
     654           3 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     655           3 :             WRITE (unit_nr, '(T2,A4,T7,A62)') 'BSE|', '  sum_jb ( A_ia,jb   X_jb^n + B_ia,jb   Y_jb^n ) = Ω^n X_ia^n'
     656           3 :             WRITE (unit_nr, '(T2,A4,T7,A62)') 'BSE|', '- sum_jb ( B_ia,jb   X_jb^n + A_ia,jb   Y_jb^n ) = Ω^n Y_ia^n'
     657             :          END IF
     658           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     659           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     660           9 :          WRITE (unit_nr, '(T2,A4,T7,A4,T18,A42,T70,A1,I4,A1,I4,A1)') 'BSE|', 'i,j:', &
     661          18 :             'occupied molecular orbitals, i.e. state in', '[', homo_irred - homo + 1, ',', homo_irred, ']'
     662           9 :          WRITE (unit_nr, '(T2,A4,T7,A4,T18,A44,T70,A1,I4,A1,I4,A1)') 'BSE|', 'a,b:', &
     663          18 :             'unoccupied molecular orbitals, i.e. state in', '[', homo_irred + 1, ',', homo_irred + virtual, ']'
     664           9 :          WRITE (unit_nr, '(T2,A4,T7,A2,T18,A16)') 'BSE|', 'n:', 'Excitation index'
     665           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     666           9 :          WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', 'A_ia,jb = (ε_a-ε_i) δ_ij δ_ab + α * v_ia,jb - W_ij,ab'
     667           9 :          IF (.NOT. flag_TDA) THEN
     668           3 :             WRITE (unit_nr, '(T2,A4,T7,A32)') 'BSE|', 'B_ia,jb = α * v_ia,jb - W_ib,aj'
     669           3 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     670           3 :             WRITE (unit_nr, '(T2,A4,T7,A35)') 'BSE|', 'prelim Ref.: Eqs. (24-27),(30),(35)'
     671           3 :             WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
     672             :          END IF
     673           9 :          IF (.NOT. flag_TDA) THEN
     674           3 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     675           3 :             WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', 'The BSE is solved for Ω^n and X_ia^n as a hermitian problem, e.g. Eq.(42)'
     676           3 :             WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
     677             :             ! WRITE (unit_nr, '(T2,A4,T7,A69)') 'BSE|', 'C_ia,jb = sum_kc,ld ((A-B)^0.5)_ia,kc (A+B)_kc,ld ((A-B)^0.5)_ld,jb'
     678             :             ! WRITE (unit_nr, '(T2,A4)') 'BSE|'
     679             :             ! WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', '(X+Y)_ia,n = sum_jb,m  ((A-B)^0.5)ia,jb Z_jb,m (Ω_m)^-0.5'
     680             :             ! WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', '(X-Y)_ia,n = sum_jb,m  ((A-B)^-0.5)ia,jb Z_jb,m (Ω_m)^0.5'
     681             :          END IF
     682           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     683           9 :          WRITE (unit_nr, '(T2,A4,T7,A7,T19,A23)') 'BSE|', 'ε_...:', 'GW quasiparticle energy'
     684           9 :          WRITE (unit_nr, '(T2,A4,T7,A7,T19,A15)') 'BSE|', 'δ_...:', 'Kronecker delta'
     685           9 :          WRITE (unit_nr, '(T2,A4,T7,A3,T19,A21)') 'BSE|', 'α:', 'spin-dependent factor (Singlet/Triplet)'
     686           9 :          WRITE (unit_nr, '(T2,A4,T7,A6,T18,A34)') 'BSE|', 'v_...:', 'Electron-hole exchange interaction'
     687           9 :          WRITE (unit_nr, '(T2,A4,T7,A6,T18,A27)') 'BSE|', 'W_...:', 'Screened direct interaction'
     688           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     689           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     690           9 :          WRITE (unit_nr, '(T2,A4,T7,A47,A7,A9,F3.1)') 'BSE|', &
     691          18 :             'The spin-dependent factor is for the requested ', multiplet, " is α = ", alpha
     692           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     693           9 :          IF (flag_TDA) THEN
     694           6 :             WRITE (unit_nr, '(T2,A4,T7,A56)') 'BSE|', 'Excitation energies from solving the BSE within the TDA:'
     695             :          ELSE
     696           3 :             WRITE (unit_nr, '(T2,A4,T7,A57)') 'BSE|', 'Excitation energies from solving the BSE without the TDA:'
     697             :          END IF
     698           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     699           9 :          WRITE (unit_nr, '(T2,A4,T11,A12,T26,A11,T44,A8,T55,A27)') 'BSE|', &
     700          18 :             'Excitation n', "Spin Config", 'TDA/ABBA', 'Excitation energy Ω^n (eV)'
     701             :       END IF
     702             :       !prints actual energies values
     703          18 :       IF (unit_nr > 0) THEN
     704         234 :          DO i_exc = 1, MIN(homo*virtual, mp2_env%ri_g0w0%num_print_exc)
     705             :             WRITE (unit_nr, '(T2,A4,T7,I16,T30,A7,T46,A6,T59,F22.4)') &
     706         234 :                'BSE|', i_exc, multiplet, info_approximation, Exc_ens(i_exc)*evolt
     707             :          END DO
     708             :       END IF
     709             :       !prints single particle transitions
     710          18 :       IF (unit_nr > 0) THEN
     711           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     712             : 
     713             :          WRITE (unit_nr, '(T2,A4,T7,A70)') &
     714           9 :             'BSE|', "Excitations are built up by the following single-particle transitions,"
     715             :          WRITE (unit_nr, '(T2,A4,T7,A42,F5.2,A2)') &
     716           9 :             'BSE|', "neglecting contributions where |X_ia^n| < ", mp2_env%ri_g0w0%eps_x, " :"
     717             : 
     718           9 :          WRITE (unit_nr, '(T2,A4,T15,A27,I5,A13,I5,A3)') 'BSE|', '-- Quick reminder: HOMO i =', &
     719          18 :             homo_irred, ' and LUMO a =', homo_irred + 1, " --"
     720           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     721             :          WRITE (unit_nr, '(T2,A4,T7,A12,T25,A1,T27,A2,T34,A1,T54,A8,T71,A10)') &
     722           9 :             "BSE|", "Excitation n", "i", "=>", "a", 'TDA/ABBA', "|X_ia^n|"
     723             :       END IF
     724         468 :       DO i_exc = 1, MIN(homo*virtual, mp2_env%ri_g0w0%num_print_exc)
     725             :          !Iterate through eigenvector and print values above threshold
     726             :          CALL filter_eigvec_contrib(fm_eigvec_X, idx_homo, idx_virt, eigvec_entries, &
     727         450 :                                     i_exc, virtual, num_entries, mp2_env)
     728         450 :          IF (unit_nr > 0) THEN
     729         225 :             WRITE (unit_nr, '(T2,A4)') 'BSE|'
     730         756 :             DO k = 1, num_entries
     731             :                WRITE (unit_nr, '(T2,A4,T14,I5,T21,I5,T27,A2,T30,I5,T56,A6,T65,F16.4)') &
     732         531 :                   "BSE|", i_exc, homo_irred - homo + idx_homo(k), "=>", &
     733        1287 :                   homo_irred + idx_virt(k), info_approximation, ABS(eigvec_entries(k))
     734             :             END DO
     735             :          END IF
     736             : 
     737         450 :          DEALLOCATE (idx_homo)
     738         450 :          DEALLOCATE (idx_virt)
     739         468 :          DEALLOCATE (eigvec_entries)
     740             :       END DO
     741             :       ! Compute BSE dipoles and oscillator strengths
     742             :       CALL get_oscillator_strengths(fm_eigvec_X, Exc_ens, &
     743             :                                     dipole_exc, oscill_str, &
     744             :                                     mp2_env, qs_env, mo_coeff, &
     745             :                                     homo, virtual, unit_nr, &
     746          18 :                                     fm_eigvec_Y)
     747          18 :       IF (unit_nr > 0) THEN
     748           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     749             :          WRITE (unit_nr, '(T2,A4,T7,A63)') &
     750           9 :             'BSE|', "Dipoles d_r^n and oscillator strength f^n of excitation level n"
     751             :          WRITE (unit_nr, '(T2,A4,T7,A17)') &
     752           9 :             'BSE|', "are obtained from"
     753           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     754           9 :          IF (flag_TDA) THEN
     755             :             WRITE (unit_nr, '(T2,A4,T12,A51)') &
     756           6 :                'BSE|', "d_r^n = sqrt(2) sum_ia < ψ_i | µ | ψ_a >  X_ia^n"
     757             :          ELSE
     758             :             WRITE (unit_nr, '(T2,A4,T12,A63)') &
     759           3 :                'BSE|', "d_r^n = sqrt(2) sum_ia < ψ_i | µ | ψ_a > ( X_ia^n + Y_ia^n )"
     760             :          END IF
     761           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     762             :          WRITE (unit_nr, '(T2,A4,T20,A44)') &
     763           9 :             'BSE|', "f^n = 2/3 * Ω^n sum_r∈(x,y,z) ( d_r^n )^2"
     764           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     765             :          WRITE (unit_nr, '(T2,A4,T7,A19)') &
     766           9 :             'BSE|', "where we introduced"
     767           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     768             :          WRITE (unit_nr, '(T2,A4,T7,A5,T15,A28)') &
     769           9 :             'BSE|', "ψ_i:", "occupied molecular orbitals,"
     770             :          WRITE (unit_nr, '(T2,A4,T7,A5,T15,A28)') &
     771           9 :             'BSE|', "ψ_a:", "empty molecular orbitals and"
     772             :          WRITE (unit_nr, '(T2,A4,T7,A3,T15,A16)') &
     773           9 :             'BSE|', "µ:", "dipole operator."
     774           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     775             :          WRITE (unit_nr, '(T2,A4,T7,A28)') &
     776           9 :             'BSE|', "prelim Ref.: Eqs. (23), (24)"
     777             :          WRITE (unit_nr, '(T2,A4,T7,A71)') &
     778           9 :             'BSE|', "in J. Chem. Phys. 152, 044105 (2020); https://doi.org/10.1063/1.5123290"
     779           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     780           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     781           9 :          WRITE (unit_nr, '(T2,A4,T8,A12,T22,A8,T35,A8,T45,A8,T55,A8,T65,A16)') 'BSE|', &
     782          18 :             'Excitation n', "TDA/ABBA", "Dipole X", "Dipole Y", "Dipole Z", 'Osc. strength'
     783         234 :          DO i_exc = 1, MIN(homo*virtual, mp2_env%ri_g0w0%num_print_exc)
     784             :             WRITE (unit_nr, '(T2,A4,T8,I12,T24,A6,T35,F8.3,T45,F8.3,T55,F8.3,T65,F16.3)') &
     785         225 :                'BSE|', i_exc, info_approximation, dipole_exc(1, 1, i_exc), dipole_exc(2, 1, i_exc), &
     786         459 :                dipole_exc(3, 1, i_exc), oscill_str(i_exc)
     787             :          END DO
     788           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     789             :       END IF
     790             : 
     791             :       ! Compute and print the absorption spectrum to external file
     792          18 :       IF (mp2_env%ri_g0w0%bse_print_spectrum) THEN
     793             :          CALL compute_absorption_spectrum(oscill_str, Exc_ens, &
     794           0 :                                           info_approximation, unit_nr, mp2_env)
     795             :       END IF
     796          18 :       DEALLOCATE (oscill_str, dipole_exc)
     797          18 :       IF (unit_nr > 0) THEN
     798           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     799           9 :          WRITE (unit_nr, '(T2,A4)') 'BSE|'
     800             :       END IF
     801             : 
     802          18 :       CALL timestop(handle)
     803             : 
     804          18 :    END SUBROUTINE success_message
     805             : 
     806             : END MODULE bse_full_diag

Generated by: LCOV version 1.15