LCOV - code coverage report
Current view: top level - src - rpa_gw_static_cohsex.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 83.4 % 277 231
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 6 6

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Static Coulomb-hole screened-exchange (COHSEX) quasiparticle energies and MOs in the
      10              : !>        O(N^4) (RI_RPA%GW) GW code for molecules
      11              : !>
      12              : !>        Symbols
      13              : !>          μ,ν        atomic orbitals (AOs)
      14              : !>          P,Q        RI auxiliary functions (after the RI-basis reduction, dimen_RI)
      15              : !>          i / a      occupied / virtual Kohn-Sham MOs,  p  any MO,  m,n  MOs in the window of
      16              : !>                     corrected MOs [homo-CORR_MOS_OCC+1, homo+CORR_MOS_VIRT]
      17              : !>          ϵ_n        DFT eigenvalue,  ϵ_F  Fermi level (between HOMO and LUMO)
      18              : !>          B^P_nm     = Σ_Q (P|Q)^(-1/2) (Q|nm)            RI 3-center integrals (fm_mat_S_gw)
      19              : !>
      20              : !>        Static screened Coulomb interaction (RPA, ω = 0), closed shell:
      21              : !>          Q_PQ(0)    = 4 Σ_ia B^P_ia B^Q_ia / (ϵ_a - ϵ_i)
      22              : !>          W^c_PQ(0)  = [1 + Q(0)]^(-1)_PQ - δ_PQ           (-δ_PQ removes the bare Coulomb part)
      23              : !>          W^c_mp,pn  = Σ_PQ B^P_mp W^c_PQ(0) B^Q_pn
      24              : !>
      25              : !>        static COHSEX self-energy = Coulomb hole (COH) + screened exchange (SEX):
      26              : !>          Σ^COH_mn   =  1/2 Σ_p     W^c_mp,pn
      27              : !>          Σ^SEX_mn   = -    Σ_i^occ W^c_mi,in              (+ bare exchange Σ^x_mn)
      28              : !>          Σ^c_mn     =  Σ^COH_mn + Σ^SEX_mn = 1/2 Σ_p sgn(ϵ_p - ϵ_F) W^c_mp,pn
      29              : !>          Σ^x_mn     = -Σ_i^occ Σ_P B^P_mi B^P_in          (RI_SIGMA_X; else from HFX)
      30              : !>
      31              : !>        Quasiparticle Hamiltonian in the window:
      32              : !>          H^QP_mn    = ϵ_n δ_mn + Σ^x_mn - v^xc_mn + α_mn Σ^c_mn
      33              : !>          α_mn       = α_IP = COHSEX_SCALE_OCC (m,n occupied),  α_EA = COHSEX_SCALE_VIRT (m,n virtual),  H^QP_ia = 0
      34              : !>          ϵ_n^DG     = H^QP_nn                              (COHSEX DIAGONAL)
      35              : !>          H^QP U     = U ϵ^CN, occ-occ and virt-virt block separately   (COHSEX QP_UPDATE)
      36              : !>          C^QP_μn    = Σ_m C_μm U_mn                        (COHSEX QP_UPDATE MOs)
      37              : !>        COHSEX DIAGONAL prints ϵ^DG only; COHSEX QP_UPDATE also diagonalizes H^QP, prints ϵ^CN
      38              : !>        and the canonical MOs.
      39              : !>
      40              : !> \par History
      41              : !>      09.2026 created [Ritaj Tyagi]
      42              : ! **************************************************************************************************
      43              : MODULE rpa_gw_static_cohsex
      44              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      45              :    USE bibliography,                    ONLY: Hedin1965,&
      46              :                                               Hybertsen1986,&
      47              :                                               Tyagi2024,&
      48              :                                               Tyagi2026,&
      49              :                                               cite_reference
      50              :    USE cell_types,                      ONLY: cell_type
      51              :    USE cp_control_types,                ONLY: dft_control_type
      52              :    USE cp_dbcsr_api,                    ONLY: dbcsr_release_p,&
      53              :                                               dbcsr_type
      54              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm
      55              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_add_on_diag,&
      56              :                                               cp_fm_column_scale
      57              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose,&
      58              :                                               cp_fm_cholesky_invert
      59              :    USE cp_fm_redistribution,            ONLY: cp_fm_permute
      60              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      61              :                                               cp_fm_struct_release,&
      62              :                                               cp_fm_struct_type
      63              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      64              :                                               cp_fm_get_info,&
      65              :                                               cp_fm_get_submatrix,&
      66              :                                               cp_fm_release,&
      67              :                                               cp_fm_set_submatrix,&
      68              :                                               cp_fm_to_fm,&
      69              :                                               cp_fm_type
      70              :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      71              :                                               cp_logger_type
      72              :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      73              :                                               cp_print_key_should_output,&
      74              :                                               cp_print_key_unit_nr
      75              :    USE cp_realspace_grid_cube,          ONLY: cp_pw_to_cube
      76              :    USE input_constants,                 ONLY: cohsex_qp_update
      77              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      78              :                                               section_vals_type,&
      79              :                                               section_vals_val_get
      80              :    USE kinds,                           ONLY: default_path_length,&
      81              :                                               dp
      82              :    USE mathlib,                         ONLY: diamat_all
      83              :    USE message_passing,                 ONLY: mp_para_env_type
      84              :    USE mp2_types,                       ONLY: mp2_type
      85              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      86              :    USE particle_list_types,             ONLY: particle_list_type
      87              :    USE particle_types,                  ONLY: particle_type
      88              :    USE physcon,                         ONLY: evolt
      89              :    USE pw_env_types,                    ONLY: pw_env_get,&
      90              :                                               pw_env_type
      91              :    USE pw_pool_types,                   ONLY: pw_pool_type
      92              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      93              :                                               pw_r3d_rs_type
      94              :    USE qs_collocate_density,            ONLY: calculate_wavefunction
      95              :    USE qs_environment_types,            ONLY: get_qs_env,&
      96              :                                               qs_environment_type
      97              :    USE qs_kind_types,                   ONLY: qs_kind_type
      98              :    USE qs_mo_io,                        ONLY: write_mo_set_to_output_unit
      99              :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
     100              :                                               deallocate_mo_set,&
     101              :                                               init_mo_set,&
     102              :                                               mo_set_type
     103              :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
     104              :                                               qs_subsys_type
     105              : #include "./base/base_uses.f90"
     106              : 
     107              :    IMPLICIT NONE
     108              : 
     109              :    PRIVATE
     110              : 
     111              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rpa_gw_static_cohsex'
     112              : 
     113              :    PUBLIC :: static_cohsex_qp_energies, rotate_bse_slab, get_static_cohsex_mo_coeff
     114              : 
     115              : CONTAINS
     116              : 
     117              : ! **************************************************************************************************
     118              : !> \brief Compute and print the diagonal (ϵ^DG) static COHSEX quasiparticle energies; with
     119              : !>        COHSEX QP_UPDATE also the canonical (ϵ^CN) energies and the canonical MOs
     120              : !> \param fm_mat_Q on entry the spin-summed 1 + Q_PQ(ω=0); on exit W^c_PQ(0) = [1 + Q(0)]^(-1)_PQ - δ_PQ
     121              : !> \param fm_mat_S_gw per-spin B^P_mp
     122              : !> \param fm_mat_S_gw_work ...
     123              : !> \param dimen_RI ...
     124              : !> \param nmo ...
     125              : !> \param homo ...
     126              : !> \param gw_corr_lev_occ ...
     127              : !> \param gw_corr_lev_virt ...
     128              : !> \param Eigenval ...
     129              : !> \param mo_coeff ...
     130              : !> \param unit_nr ...
     131              : !> \param qs_env ...
     132              : !> \param mp2_env ...
     133              : !> \param eigenval_dg ϵ_n^DG of all MOs (scissor outside the window), nmo x nspins
     134              : !> \param eigenval_cn ϵ_n^CN of all MOs (scissor outside the window), nmo x nspins, QP_UPDATE only
     135              : !> \param u_qp_all U_mn of all MOs (δ_mn outside the window), nmo x nmo x nspins, QP_UPDATE only
     136              : ! **************************************************************************************************
     137           16 :    SUBROUTINE static_cohsex_qp_energies(fm_mat_Q, fm_mat_S_gw, fm_mat_S_gw_work, dimen_RI, nmo, homo, &
     138           16 :                                         gw_corr_lev_occ, gw_corr_lev_virt, Eigenval, mo_coeff, unit_nr, &
     139            8 :                                         qs_env, mp2_env, eigenval_dg, eigenval_cn, u_qp_all)
     140              : 
     141              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_mat_Q
     142              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S_gw, fm_mat_S_gw_work
     143              :       INTEGER, INTENT(IN)                                :: dimen_RI, nmo
     144              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, gw_corr_lev_occ, gw_corr_lev_virt
     145              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: Eigenval
     146              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
     147              :       INTEGER, INTENT(IN)                                :: unit_nr
     148              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     149              :       TYPE(mp2_type)                                     :: mp2_env
     150              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT), &
     151              :          OPTIONAL                                        :: eigenval_dg, eigenval_cn
     152              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT), &
     153              :          OPTIONAL                                        :: u_qp_all
     154              : 
     155              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'static_cohsex_qp_energies'
     156              : 
     157              :       CHARACTER(LEN=10)                                  :: spin_label
     158              :       CHARACTER(LEN=3)                                   :: occ_vir
     159              :       CHARACTER(LEN=40)                                  :: cohsex_label
     160              :       INTEGER                                            :: handle, ispin, m, n, n_mo_win, no, &
     161              :                                                             nspins, nv, p, win_start
     162              :       LOGICAL                                            :: qp_update
     163              :       REAL(KIND=dp)                                      :: shift_occ, shift_virt
     164            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: e_can, e_diag, e_qp, scale_vec
     165            8 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: h_qp, sigma_c, sigma_x, &
     166            8 :                                                             sigma_x_minus_vxc, u_qp, vxc
     167              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_B_re, fm_struct_win
     168              :       TYPE(cp_fm_type)                                   :: fm_B_re, fm_sigma, fm_WB_re, fm_work
     169              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     170              : 
     171            8 :       CALL timeset(routineN, handle)
     172              : 
     173            8 :       nspins = SIZE(fm_mat_S_gw)
     174              :       ! COHSEX QP_UPDATE: diagonalize H^QP (canonical energies and MOs); DIAGONAL: ϵ^DG only
     175            8 :       qp_update = (mp2_env%ri_g0w0%cohsex_flavor == cohsex_qp_update)
     176              : 
     177              :       ! static COHSEX; with QP_UPDATE the quasiparticle update; scaled self-energy if requested
     178            8 :       CALL cite_reference(Hedin1965)
     179            8 :       CALL cite_reference(Hybertsen1986)
     180            8 :       IF (qp_update) CALL cite_reference(Tyagi2024)
     181            8 :       IF (mp2_env%ri_g0w0%cohsex_scale_occ /= 1.0_dp .OR. mp2_env%ri_g0w0%cohsex_scale_virt /= 1.0_dp) THEN
     182            6 :          CALL cite_reference(Tyagi2026)
     183              :       END IF
     184            8 :       CALL cp_fm_get_info(mo_coeff(1), para_env=para_env)
     185              : 
     186              :       ! ==============================================================================
     187              :       ! 1. Static correlation part of the screened Coulomb interaction
     188              :       !      ε_PQ(0)   = δ_PQ + Q_PQ(0)
     189              :       !      W^c_PQ(0) = ε^(-1)_PQ(0) - δ_PQ
     190              :       ! ==============================================================================
     191            8 :       CALL cp_fm_cholesky_decompose(fm_mat_Q, n=dimen_RI)
     192            8 :       CALL cp_fm_create(fm_work, fm_mat_Q%matrix_struct)
     193            8 :       CALL cp_fm_cholesky_invert(fm_mat_Q, n=dimen_RI, work=fm_work)
     194            8 :       CALL cp_fm_release(fm_work)
     195            8 :       CALL cp_fm_add_on_diag(fm_mat_Q, -1.0_dp, n_active=dimen_RI)
     196              : 
     197           16 :       DO ispin = 1, nspins
     198              : 
     199            8 :          no = gw_corr_lev_occ(ispin)
     200            8 :          nv = gw_corr_lev_virt(ispin)
     201            8 :          n_mo_win = no + nv
     202            8 :          win_start = homo(ispin) - no + 1
     203              : 
     204              :          ! ==============================================================================
     205              :          ! 2. Screened 3-center integrals, weighted with the COHSEX occupation factor
     206              :          !      (W^c B)^P_mp = Σ_Q W^c_PQ(0) B^Q_mp  s_p,   s_p = 1/2 sgn(ϵ_p - ϵ_F)
     207              :          !      s_p = -1/2 for p occupied,  s_p = +1/2 for p virtual (COH)
     208              :          ! ==============================================================================
     209              :          CALL parallel_gemm(transa="N", transb="N", m=dimen_RI, n=n_mo_win*nmo, k=dimen_RI, &
     210              :                             alpha=1.0_dp, matrix_a=fm_mat_Q, matrix_b=fm_mat_S_gw(ispin), &
     211            8 :                             beta=0.0_dp, matrix_c=fm_mat_S_gw_work(ispin))
     212           24 :          ALLOCATE (scale_vec(n_mo_win*nmo))
     213          162 :          DO m = 1, n_mo_win
     214         3704 :             DO p = 1, nmo
     215         3696 :                IF (p <= homo(ispin)) THEN
     216          616 :                   scale_vec((m - 1)*nmo + p) = -0.5_dp
     217              :                ELSE
     218         2926 :                   scale_vec((m - 1)*nmo + p) = 0.5_dp
     219              :                END IF
     220              :             END DO
     221              :          END DO
     222            8 :          CALL cp_fm_column_scale(fm_mat_S_gw_work(ispin), scale_vec)
     223            8 :          DEALLOCATE (scale_vec)
     224              : 
     225              :          ! ==============================================================================
     226              :          ! 3. Reorder the compound index for O(N^4) contractions over (p,P)
     227              :          !      B'_(p,P),m      = B^P_mp
     228              :          !      (W^c B)'_(p,P),m = (W^c B)^P_mp
     229              :          !    row index (p-1)*dimen_RI + P, P fast: the occupied p (p <= homo) are the
     230              :          !    first homo*dimen_RI rows. cp_fm_permute maps the input indices
     231              :          !    (P,1 ; m,p) with reordering [4,1,3,2] to (p,P ; m,1).
     232              :          ! ==============================================================================
     233            8 :          NULLIFY (fm_struct_B_re)
     234              :          CALL cp_fm_struct_create(fm_struct_B_re, template_fmstruct=fm_mat_S_gw(ispin)%matrix_struct, &
     235            8 :                                   nrow_global=nmo*dimen_RI, ncol_global=n_mo_win)
     236            8 :          CALL cp_fm_create(fm_B_re, fm_struct_B_re, name="static_cohsex_B_reordered", set_zero=.TRUE.)
     237            8 :          CALL cp_fm_create(fm_WB_re, fm_struct_B_re, name="static_cohsex_WB_reordered", set_zero=.TRUE.)
     238            8 :          CALL cp_fm_struct_release(fm_struct_B_re)
     239            8 :          CALL cp_fm_permute(fm_B_re, fm_mat_S_gw(ispin), 1.0_dp, 1, nmo, dimen_RI, 1, [4, 1, 3, 2])
     240            8 :          CALL cp_fm_permute(fm_WB_re, fm_mat_S_gw_work(ispin), 1.0_dp, 1, nmo, dimen_RI, 1, [4, 1, 3, 2])
     241              : 
     242            8 :          NULLIFY (fm_struct_win)
     243              :          CALL cp_fm_struct_create(fm_struct_win, template_fmstruct=fm_mat_S_gw(ispin)%matrix_struct, &
     244            8 :                                   nrow_global=n_mo_win, ncol_global=n_mo_win)
     245            8 :          CALL cp_fm_create(fm_sigma, fm_struct_win)
     246            8 :          CALL cp_fm_struct_release(fm_struct_win)
     247              : 
     248           48 :          ALLOCATE (sigma_c(n_mo_win, n_mo_win), sigma_x(n_mo_win, n_mo_win))
     249              : 
     250              :          ! ==============================================================================
     251              :          ! 4. Correlation self-energy
     252              :          !      Σ^c_mn = Σ_p s_p Σ_PQ B^P_mp W^c_PQ(0) B^Q_pn
     253              :          !             = Σ_(p,P) (W^c B)'_(p,P),m B'_(p,P),n
     254              :          ! ==============================================================================
     255              :          CALL parallel_gemm(transa="T", transb="N", m=n_mo_win, n=n_mo_win, k=nmo*dimen_RI, &
     256              :                             alpha=1.0_dp, matrix_a=fm_WB_re, matrix_b=fm_B_re, &
     257            8 :                             beta=0.0_dp, matrix_c=fm_sigma)
     258            8 :          CALL cp_fm_get_submatrix(fm_sigma, sigma_c)
     259              : 
     260              :          ! ==============================================================================
     261              :          ! 5. RI exchange self-energy (RI_SIGMA_X)
     262              :          !      Σ^x_mn = -Σ_i^occ Σ_P B^P_mi B^P_in = -Σ_(i,P) B'_(i,P),m B'_(i,P),n
     263              :          ! ==============================================================================
     264            8 :          sigma_x(:, :) = 0.0_dp
     265            8 :          IF (mp2_env%ri_g0w0%do_ri_Sigma_x) THEN
     266              :             CALL parallel_gemm(transa="T", transb="N", m=n_mo_win, n=n_mo_win, k=homo(ispin)*dimen_RI, &
     267              :                                alpha=-1.0_dp, matrix_a=fm_B_re, matrix_b=fm_B_re, &
     268            6 :                                beta=0.0_dp, matrix_c=fm_sigma)
     269            6 :             CALL cp_fm_get_submatrix(fm_sigma, sigma_x)
     270              :          END IF
     271              : 
     272            8 :          CALL cp_fm_release(fm_sigma)
     273            8 :          CALL cp_fm_release(fm_B_re)
     274            8 :          CALL cp_fm_release(fm_WB_re)
     275              : 
     276              :          ! ==============================================================================
     277              :          ! 6. v^xc and Σ^x - v^xc in the MO window
     278              :          !      v^xc_mn         = Σ_μν C_μm v^xc_μν C_νn
     279              :          !      (Σ^x - v^xc)_mn = Σ_μν C_μm (Σ^x - v^xc)_μν C_νn
     280              :          !    The AO matrix (Σ^x - v^xc)_μν holds the HFX exchange Σ^x_μν without
     281              :          !    RI_SIGMA_X and only -v^xc_μν with RI_SIGMA_X, hence in both cases
     282              :          !      Σ^x_mn = Σ^x,RI_mn + (Σ^x - v^xc)_mn + v^xc_mn   (Σ^x,RI = 0 without RI)
     283              :          ! ==============================================================================
     284           48 :          ALLOCATE (vxc(n_mo_win, n_mo_win), sigma_x_minus_vxc(n_mo_win, n_mo_win))
     285              :          CALL ao_to_mo_window(mp2_env%ri_g0w0%matrix_vxc(ispin)%matrix, mo_coeff(ispin), &
     286            8 :                               win_start, n_mo_win, vxc)
     287              :          CALL ao_to_mo_window(mp2_env%ri_g0w0%matrix_sigma_x_minus_vxc(ispin)%matrix, mo_coeff(ispin), &
     288            8 :                               win_start, n_mo_win, sigma_x_minus_vxc)
     289         3464 :          sigma_x(:, :) = sigma_x(:, :) + sigma_x_minus_vxc(:, :) + vxc(:, :)
     290              : 
     291              :          ! ==============================================================================
     292              :          ! 7. static COHSEX quasiparticle Hamiltonian in the window
     293              :          !      H^QP_ij = ϵ_i δ_ij + Σ^x_ij - v^xc_ij + α_IP Σ^c_ij   (occ-occ)
     294              :          !      H^QP_ab = ϵ_a δ_ab + Σ^x_ab - v^xc_ab + α_EA Σ^c_ab   (virt-virt)
     295              :          !      H^QP_ia = 0                                              (occ-virt)
     296              :          !    symmetrized, H^QP = (H^QP + H^QP^T)/2
     297              :          !      ϵ_n^DG  = H^QP_nn                                        (diagonal static COHSEX)
     298              :          ! ==============================================================================
     299           32 :          ALLOCATE (h_qp(n_mo_win, n_mo_win))
     300            8 :          h_qp(:, :) = 0.0_dp
     301              :          h_qp(1:no, 1:no) = sigma_x(1:no, 1:no) - vxc(1:no, 1:no) + &
     302          152 :                             mp2_env%ri_g0w0%cohsex_scale_occ*sigma_c(1:no, 1:no)
     303              :          h_qp(no + 1:, no + 1:) = sigma_x(no + 1:, no + 1:) - vxc(no + 1:, no + 1:) + &
     304         2348 :                                   mp2_env%ri_g0w0%cohsex_scale_virt*sigma_c(no + 1:, no + 1:)
     305         6920 :          h_qp(:, :) = 0.5_dp*(h_qp(:, :) + TRANSPOSE(h_qp(:, :)))
     306          162 :          DO n = 1, n_mo_win
     307          162 :             h_qp(n, n) = h_qp(n, n) + Eigenval(win_start + n - 1, ispin)
     308              :          END DO
     309              : 
     310           24 :          ALLOCATE (e_diag(n_mo_win))
     311          162 :          DO n = 1, n_mo_win
     312          162 :             e_diag(n) = h_qp(n, n)
     313              :          END DO
     314              : 
     315              :          ! ϵ^DG of all MOs for a subsequent BSE, scissor shift of the DFT eigenvalue outside the window
     316            8 :          IF (PRESENT(eigenval_dg)) THEN
     317           48 :             DO n = 1, nmo
     318           48 :                IF (n < win_start) THEN
     319            0 :                   eigenval_dg(n, ispin) = Eigenval(n, ispin) + e_diag(1) - Eigenval(win_start, ispin)
     320           46 :                ELSE IF (n >= win_start + n_mo_win) THEN
     321              :                   eigenval_dg(n, ispin) = Eigenval(n, ispin) + e_diag(n_mo_win) - &
     322            0 :                                           Eigenval(win_start + n_mo_win - 1, ispin)
     323              :                ELSE
     324           46 :                   eigenval_dg(n, ispin) = e_diag(n - win_start + 1)
     325              :                END IF
     326              :             END DO
     327              :          END IF
     328              : 
     329            8 :          IF (qp_update) THEN
     330              :             ! ==============================================================================
     331              :             ! 8. Canonical static COHSEX (QP_UPDATE): diagonalize the occ-occ and virt-virt blocks
     332              :             !      Σ_m H^QP_nm U_mk = U_nk ϵ_k^CN
     333              :             ! ==============================================================================
     334            8 :             ALLOCATE (e_can(n_mo_win))
     335            4 :             e_can(:) = 0.0_dp
     336            4 :             IF (para_env%is_source()) THEN
     337            2 :                IF (no > 0) CALL diamat_all(h_qp(1:no, 1:no), e_can(1:no))
     338            2 :                IF (nv > 0) CALL diamat_all(h_qp(no + 1:, no + 1:), e_can(no + 1:))
     339              :             END IF
     340            4 :             CALL para_env%bcast(h_qp, para_env%source)
     341            4 :             CALL para_env%bcast(e_can, para_env%source)
     342              : 
     343              :             ! ==============================================================================
     344              :             ! 9. Energies and MO transformation for all nmo MOs
     345              :             !      inside the window:   ϵ_n^QP = ϵ_n^CN,  U_mn from step 8
     346              :             !      outside the window:  U_mn = δ_mn and scissor shift of the DFT eigenvalue
     347              :             !        ϵ_n^QP = ϵ_n + (ϵ^CN_first - ϵ_first)   below the window (occupied)
     348              :             !        ϵ_n^QP = ϵ_n + (ϵ^CN_last  - ϵ_last)    above the window (virtual)
     349              :             ! ==============================================================================
     350           24 :             ALLOCATE (e_qp(nmo), u_qp(nmo, nmo))
     351            4 :             shift_occ = e_can(1) - Eigenval(win_start, ispin)
     352            4 :             shift_virt = e_can(n_mo_win) - Eigenval(win_start + n_mo_win - 1, ispin)
     353           96 :             DO n = 1, nmo
     354           96 :                IF (n < win_start) THEN
     355            0 :                   e_qp(n) = Eigenval(n, ispin) + shift_occ
     356           92 :                ELSE IF (n >= win_start + n_mo_win) THEN
     357            0 :                   e_qp(n) = Eigenval(n, ispin) + shift_virt
     358              :                ELSE
     359           92 :                   e_qp(n) = e_can(n - win_start + 1)
     360              :                END IF
     361              :             END DO
     362            4 :             u_qp(:, :) = 0.0_dp
     363           96 :             DO n = 1, nmo
     364           96 :                u_qp(n, n) = 1.0_dp
     365              :             END DO
     366         2212 :             u_qp(win_start:win_start + n_mo_win - 1, win_start:win_start + n_mo_win - 1) = h_qp(:, :)
     367              : 
     368              :             ! for a subsequent BSE: ϵ^CN and U of all MOs
     369           50 :             IF (PRESENT(eigenval_cn)) eigenval_cn(:, ispin) = e_qp(:)
     370         1108 :             IF (PRESENT(u_qp_all)) u_qp_all(:, :, ispin) = u_qp(:, :)
     371              :          END IF
     372              : 
     373              :          ! ==============================================================================
     374              :          ! 10. Print per MO: ϵ_n, Σ^c_nn (unscaled), Σ^x_nn, v^xc_nn, ϵ_n^DG and, with QP_UPDATE,
     375              :          !     ϵ_n^CN; then HOMO, LUMO and gap. ϵ^CN is sorted in each block, i.e.
     376              :          !     ϵ^CN_HOMO = max over the occ block and ϵ^CN_LUMO = min over the virt block
     377              :          ! ==============================================================================
     378            8 :          IF (unit_nr > 0) THEN
     379            4 :             spin_label = ""
     380            4 :             IF (nspins == 2 .AND. ispin == 1) spin_label = "Alpha "
     381            4 :             IF (nspins == 2 .AND. ispin == 2) spin_label = "Beta "
     382            4 :             WRITE (unit_nr, "(/,T3,A)") REPEAT("-", 77)
     383              :             ! "static COHSEX" for closed shell, "Alpha static COHSEX" / "Beta static COHSEX" otherwise
     384            4 :             cohsex_label = TRIM(ADJUSTL(TRIM(spin_label)//" static COHSEX"))
     385            4 :             WRITE (unit_nr, "(T3,A)") TRIM(cohsex_label)//" quasiparticle energies"
     386            4 :             WRITE (unit_nr, "(T3,A,F6.3,A,F6.3)") "COHSEX_SCALE_OCC =", mp2_env%ri_g0w0%cohsex_scale_occ, &
     387            8 :                ",  COHSEX_SCALE_VIRT =", mp2_env%ri_g0w0%cohsex_scale_virt
     388            4 :             WRITE (unit_nr, "(T3,A)") REPEAT("-", 77)
     389            4 :             IF (qp_update) THEN
     390              :                WRITE (unit_nr, "(T3,A)") "DG: diagonal of H^QP,  CN: canonical, eigenvalues of the "// &
     391            2 :                   "occ-occ and virt-virt blocks"
     392            2 :                WRITE (unit_nr, "(/,T3,A,T16,A,T27,A,T38,A,T49,A,T60,A,T71,A)") "MO", "e_n^DFT", "Sigma^c_nn", &
     393            4 :                   "Sigma^x_nn", "v^xc_nn", "e_n^DG", "e_n^CN"
     394            2 :                WRITE (unit_nr, "(T3,A,T16,A,T27,A,T38,A,T49,A,T60,A,T71,A)") "", "(eV)", "(eV)", "(eV)", &
     395            4 :                   "(eV)", "(eV)", "(eV)"
     396              :             ELSE
     397            2 :                WRITE (unit_nr, "(T3,A)") "DG: diagonal of H^QP"
     398            2 :                WRITE (unit_nr, "(/,T3,A,T16,A,T27,A,T38,A,T49,A,T60,A)") "MO", "e_n^DFT", "Sigma^c_nn", &
     399            4 :                   "Sigma^x_nn", "v^xc_nn", "e_n^DG"
     400            2 :                WRITE (unit_nr, "(T3,A,T16,A,T27,A,T38,A,T49,A,T60,A)") "", "(eV)", "(eV)", "(eV)", &
     401            4 :                   "(eV)", "(eV)"
     402              :             END IF
     403           81 :             DO n = 1, n_mo_win
     404           77 :                IF (n <= no) THEN
     405           15 :                   occ_vir = "occ"
     406              :                ELSE
     407           62 :                   occ_vir = "vir"
     408              :                END IF
     409           81 :                IF (qp_update) THEN
     410           46 :                   WRITE (unit_nr, "(T3,I5,A,A3,A,6F11.3)") win_start + n - 1, " (", occ_vir, ")", &
     411           46 :                      Eigenval(win_start + n - 1, ispin)*evolt, sigma_c(n, n)*evolt, sigma_x(n, n)*evolt, &
     412           92 :                      vxc(n, n)*evolt, e_diag(n)*evolt, e_can(n)*evolt
     413              :                ELSE
     414           31 :                   WRITE (unit_nr, "(T3,I5,A,A3,A,5F11.3)") win_start + n - 1, " (", occ_vir, ")", &
     415           31 :                      Eigenval(win_start + n - 1, ispin)*evolt, sigma_c(n, n)*evolt, sigma_x(n, n)*evolt, &
     416           62 :                      vxc(n, n)*evolt, e_diag(n)*evolt
     417              :                END IF
     418              :             END DO
     419            4 :             IF (no > 0 .AND. nv > 0) THEN
     420            4 :                WRITE (unit_nr, "(/,T3,A,T66,F15.3)") TRIM(cohsex_label)//" HOMO, diagonal (eV)", &
     421           23 :                   MAXVAL(e_diag(1:no))*evolt
     422            4 :                WRITE (unit_nr, "(T3,A,T66,F15.3)") TRIM(cohsex_label)//" LUMO, diagonal (eV)", &
     423           70 :                   MINVAL(e_diag(no + 1:))*evolt
     424            4 :                WRITE (unit_nr, "(T3,A,T66,F15.3)") TRIM(cohsex_label)//" HOMO-LUMO gap, diagonal (eV)", &
     425           85 :                   (MINVAL(e_diag(no + 1:)) - MAXVAL(e_diag(1:no)))*evolt
     426            4 :                IF (qp_update) THEN
     427            2 :                   WRITE (unit_nr, "(T3,A,T66,F15.3)") TRIM(cohsex_label)//" HOMO, canonical (eV)", &
     428           12 :                      MAXVAL(e_can(1:no))*evolt
     429            2 :                   WRITE (unit_nr, "(T3,A,T66,F15.3)") TRIM(cohsex_label)//" LUMO, canonical (eV)", &
     430           42 :                      MINVAL(e_can(no + 1:))*evolt
     431            2 :                   WRITE (unit_nr, "(T3,A,T66,F15.3)") TRIM(cohsex_label)//" HOMO-LUMO gap, canonical (eV)", &
     432           50 :                      (MINVAL(e_can(no + 1:)) - MAXVAL(e_can(1:no)))*evolt
     433              :                END IF
     434              :             END IF
     435            4 :             WRITE (unit_nr, "(T3,A)") REPEAT("-", 77)
     436              :          END IF
     437              : 
     438            8 :          IF (qp_update) THEN
     439              :             ! ==============================================================================
     440              :             ! 11. Canonical static COHSEX MOs C^QP = C U via DFT%PRINT%MO and DFT%PRINT%MO_CUBES
     441              :             ! ==============================================================================
     442            4 :             CALL print_static_cohsex_mos(qs_env, mo_coeff(ispin), u_qp, e_qp, homo(ispin), nspins, ispin)
     443            4 :             DEALLOCATE (e_can, e_qp, u_qp)
     444              :          END IF
     445              : 
     446           24 :          DEALLOCATE (sigma_c, sigma_x, sigma_x_minus_vxc, vxc, h_qp, e_diag)
     447              : 
     448              :       END DO
     449              : 
     450           16 :       DO ispin = 1, nspins
     451            8 :          CALL dbcsr_release_p(mp2_env%ri_g0w0%matrix_vxc(ispin)%matrix)
     452           16 :          CALL dbcsr_release_p(mp2_env%ri_g0w0%matrix_sigma_x_minus_vxc(ispin)%matrix)
     453              :       END DO
     454            8 :       DEALLOCATE (mp2_env%ri_g0w0%matrix_vxc, mp2_env%ri_g0w0%matrix_sigma_x_minus_vxc)
     455              : 
     456            8 :       CALL timestop(handle)
     457              : 
     458           16 :    END SUBROUTINE static_cohsex_qp_energies
     459              : 
     460              : ! **************************************************************************************************
     461              : !> \brief MO-window block of an AO matrix
     462              : !>          A_mn = Σ_μν C_μm A_μν C_νn,   m,n = win_start, ..., win_start + n_mo_win - 1
     463              : !> \param matrix_ao ...
     464              : !> \param mo_coeff ...
     465              : !> \param win_start ...
     466              : !> \param n_mo_win ...
     467              : !> \param mat_mo ...
     468              : ! **************************************************************************************************
     469           16 :    SUBROUTINE ao_to_mo_window(matrix_ao, mo_coeff, win_start, n_mo_win, mat_mo)
     470              :       TYPE(dbcsr_type), POINTER                          :: matrix_ao
     471              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
     472              :       INTEGER, INTENT(IN)                                :: win_start, n_mo_win
     473              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT)        :: mat_mo
     474              : 
     475              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'ao_to_mo_window'
     476              : 
     477              :       INTEGER                                            :: handle, nao
     478              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     479              :       TYPE(cp_fm_type)                                   :: fm_ao, fm_ao_mo, fm_mo_mo
     480              : 
     481           16 :       CALL timeset(routineN, handle)
     482              : 
     483           16 :       CALL cp_fm_get_info(mo_coeff, nrow_global=nao)
     484              : 
     485           16 :       NULLIFY (fm_struct)
     486              :       CALL cp_fm_struct_create(fm_struct, template_fmstruct=mo_coeff%matrix_struct, &
     487           16 :                                nrow_global=nao, ncol_global=nao)
     488           16 :       CALL cp_fm_create(fm_ao, fm_struct)
     489           16 :       CALL cp_fm_struct_release(fm_struct)
     490           16 :       CALL copy_dbcsr_to_fm(matrix_ao, fm_ao)
     491              : 
     492              :       ! (A C)_μn = Σ_ν A_μν C_νn,  only the window columns n of C
     493              : 
     494           16 :       NULLIFY (fm_struct)
     495              :       CALL cp_fm_struct_create(fm_struct, template_fmstruct=mo_coeff%matrix_struct, &
     496           16 :                                nrow_global=nao, ncol_global=n_mo_win)
     497           16 :       CALL cp_fm_create(fm_ao_mo, fm_struct)
     498           16 :       CALL cp_fm_struct_release(fm_struct)
     499              :       CALL parallel_gemm(transa="N", transb="N", m=nao, n=n_mo_win, k=nao, alpha=1.0_dp, &
     500              :                          matrix_a=fm_ao, matrix_b=mo_coeff, beta=0.0_dp, matrix_c=fm_ao_mo, &
     501           16 :                          b_first_col=win_start)
     502           16 :       CALL cp_fm_release(fm_ao)
     503              : 
     504              :       ! A_mn = Σ_μ C_μm (A C)_μn
     505           16 :       NULLIFY (fm_struct)
     506              :       CALL cp_fm_struct_create(fm_struct, template_fmstruct=mo_coeff%matrix_struct, &
     507           16 :                                nrow_global=n_mo_win, ncol_global=n_mo_win)
     508           16 :       CALL cp_fm_create(fm_mo_mo, fm_struct)
     509           16 :       CALL cp_fm_struct_release(fm_struct)
     510              :       CALL parallel_gemm(transa="T", transb="N", m=n_mo_win, n=n_mo_win, k=nao, alpha=1.0_dp, &
     511              :                          matrix_a=mo_coeff, matrix_b=fm_ao_mo, beta=0.0_dp, matrix_c=fm_mo_mo, &
     512           16 :                          a_first_col=win_start)
     513           16 :       CALL cp_fm_release(fm_ao_mo)
     514              : 
     515           16 :       CALL cp_fm_get_submatrix(fm_mo_mo, mat_mo)
     516           16 :       CALL cp_fm_release(fm_mo_mo)
     517              : 
     518           16 :       CALL timestop(handle)
     519              : 
     520           16 :    END SUBROUTINE ao_to_mo_window
     521              : 
     522              : ! **************************************************************************************************
     523              : !> \brief Print the canonical static COHSEX MOs with the DFT%PRINT%MO and DFT%PRINT%MO_CUBES
     524              : !> \param qs_env ...
     525              : !> \param mo_coeff ...
     526              : !> \param u_qp ...
     527              : !> \param e_qp ...
     528              : !> \param homo ...
     529              : !> \param nspins ...
     530              : !> \param ispin ...
     531              : ! **************************************************************************************************
     532            4 :    SUBROUTINE print_static_cohsex_mos(qs_env, mo_coeff, u_qp, e_qp, homo, nspins, ispin)
     533              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     534              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
     535              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: u_qp
     536              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: e_qp
     537              :       INTEGER, INTENT(IN)                                :: homo, nspins, ispin
     538              : 
     539              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'print_static_cohsex_mos'
     540              : 
     541              :       CHARACTER(LEN=default_path_length)                 :: fname, title
     542              :       INTEGER                                            :: first_mo, handle, ivector, last_mo, nao, &
     543              :                                                             nelectron, nhomo, nlumo, nmo, unit_nr
     544            4 :       INTEGER, DIMENSION(:), POINTER                     :: stride
     545              :       LOGICAL                                            :: print_coeff, print_cubes, &
     546              :                                                             print_energies, print_mo, print_occ
     547              :       REAL(KIND=dp)                                      :: maxocc
     548            4 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     549              :       TYPE(cell_type), POINTER                           :: cell
     550              :       TYPE(cp_fm_type)                                   :: fm_qp_mo
     551              :       TYPE(cp_logger_type), POINTER                      :: logger
     552              :       TYPE(dft_control_type), POINTER                    :: dft_control
     553              :       TYPE(mo_set_type)                                  :: qp_mo_set
     554              :       TYPE(particle_list_type), POINTER                  :: particles
     555            4 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     556              :       TYPE(pw_c1d_gs_type)                               :: wf_g
     557              :       TYPE(pw_env_type), POINTER                         :: pw_env
     558              :       TYPE(pw_pool_type), POINTER                        :: auxbas_pw_pool
     559              :       TYPE(pw_r3d_rs_type)                               :: wf_r
     560            4 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     561              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     562              :       TYPE(section_vals_type), POINTER                   :: dft_section, input
     563              : 
     564            4 :       CALL timeset(routineN, handle)
     565              : 
     566            4 :       CALL get_qs_env(qs_env, input=input)
     567            4 :       dft_section => section_vals_get_subs_vals(input, "DFT")
     568            4 :       logger => cp_get_default_logger()
     569              : 
     570            4 :       CALL section_vals_val_get(dft_section, "PRINT%MO%ENERGIES", l_val=print_energies)
     571            4 :       CALL section_vals_val_get(dft_section, "PRINT%MO%COEFFICIENTS", l_val=print_coeff)
     572            4 :       CALL section_vals_val_get(dft_section, "PRINT%MO%OCCUPATION_NUMBERS", l_val=print_occ)
     573              :       print_mo = (cp_print_key_should_output(logger%iter_info, dft_section, "PRINT%MO") /= 0) .AND. &
     574            4 :                  (print_energies .OR. print_occ .OR. print_coeff)
     575            4 :       print_cubes = (cp_print_key_should_output(logger%iter_info, dft_section, "PRINT%MO_CUBES") /= 0)
     576              : 
     577            4 :       IF (print_mo .OR. print_cubes) THEN
     578              : 
     579            0 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_global=nmo)
     580              : 
     581              :          ! C^QP_μn = Σ_m C_μm U_mn
     582            0 :          CALL get_static_cohsex_mo_coeff(mo_coeff, u_qp, fm_qp_mo)
     583              : 
     584              :          ! MO energies ϵ_n^QP, occupations f_n (maxocc for n <= homo) and coefficients C^QP_μn
     585            0 :          IF (print_mo) THEN
     586            0 :             IF (nspins == 1) THEN
     587            0 :                maxocc = 2.0_dp
     588              :             ELSE
     589            0 :                maxocc = 1.0_dp
     590              :             END IF
     591            0 :             nelectron = NINT(maxocc*REAL(homo, KIND=dp))
     592              :             CALL allocate_mo_set(qp_mo_set, nao=nao, nmo=nmo, nelectron=nelectron, &
     593              :                                  n_el_f=REAL(nelectron, KIND=dp), maxocc=maxocc, &
     594            0 :                                  flexible_electron_count=0.0_dp)
     595            0 :             CALL init_mo_set(qp_mo_set, fm_struct=fm_qp_mo%matrix_struct, name="static_cohsex")
     596            0 :             qp_mo_set%eigenvalues(:) = e_qp(:)
     597            0 :             CALL cp_fm_to_fm(fm_qp_mo, qp_mo_set%mo_coeff)
     598              : 
     599            0 :             CALL get_qs_env(qs_env, particle_set=particle_set, qs_kind_set=qs_kind_set)
     600            0 :             IF (nspins == 1) THEN
     601              :                CALL write_mo_set_to_output_unit(qp_mo_set, qs_kind_set, particle_set, dft_section, &
     602            0 :                                                 4, 0, final_mos=.TRUE.)
     603            0 :             ELSE IF (ispin == 1) THEN
     604              :                CALL write_mo_set_to_output_unit(qp_mo_set, qs_kind_set, particle_set, dft_section, &
     605            0 :                                                 4, 0, final_mos=.TRUE., spin="ALPHA")
     606              :             ELSE
     607              :                CALL write_mo_set_to_output_unit(qp_mo_set, qs_kind_set, particle_set, dft_section, &
     608            0 :                                                 4, 0, final_mos=.TRUE., spin="BETA")
     609              :             END IF
     610            0 :             CALL deallocate_mo_set(qp_mo_set)
     611              :          END IF
     612              : 
     613              :          ! cube files of ψ_n(r) = Σ_μ C^QP_μn ϕ_μ(r) for n = homo-NHOMO+1, ..., homo+NLUMO
     614            0 :          IF (print_cubes) THEN
     615            0 :             CALL section_vals_val_get(dft_section, "PRINT%MO_CUBES%NHOMO", i_val=nhomo)
     616            0 :             CALL section_vals_val_get(dft_section, "PRINT%MO_CUBES%NLUMO", i_val=nlumo)
     617            0 :             CALL section_vals_val_get(dft_section, "PRINT%MO_CUBES%STRIDE", i_vals=stride)
     618            0 :             IF (nhomo == -1) nhomo = homo
     619            0 :             IF (nlumo == -1) nlumo = nmo - homo
     620            0 :             first_mo = MAX(1, homo - nhomo + 1)
     621            0 :             last_mo = MIN(nmo, homo + nlumo)
     622              : 
     623              :             CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
     624              :                             cell=cell, dft_control=dft_control, particle_set=particle_set, &
     625            0 :                             pw_env=pw_env, subsys=subsys)
     626            0 :             CALL qs_subsys_get(subsys, particles=particles)
     627            0 :             CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool)
     628            0 :             CALL auxbas_pw_pool%create_pw(wf_r)
     629            0 :             CALL auxbas_pw_pool%create_pw(wf_g)
     630              : 
     631            0 :             DO ivector = first_mo, last_mo
     632              :                CALL calculate_wavefunction(fm_qp_mo, ivector, wf_r, wf_g, atomic_kind_set, &
     633            0 :                                            qs_kind_set, cell, dft_control, particle_set, pw_env)
     634            0 :                WRITE (fname, '(A,I5.5,A,I1)') "static_cohsex_WFN_", ivector, "_", ispin
     635              :                unit_nr = cp_print_key_unit_nr(logger, dft_section, "PRINT%MO_CUBES", &
     636              :                                               extension=".cube", middle_name=TRIM(fname), &
     637            0 :                                               file_position="REWIND", log_filename=.FALSE.)
     638            0 :                WRITE (title, *) "static COHSEX WAVEFUNCTION ", ivector, " spin ", ispin, &
     639            0 :                   " i.e. HOMO ", ivector - homo
     640            0 :                CALL cp_pw_to_cube(wf_r, unit_nr, title, particles, stride=stride)
     641            0 :                CALL cp_print_key_finished_output(unit_nr, logger, dft_section, "PRINT%MO_CUBES")
     642              :             END DO
     643              : 
     644            0 :             CALL auxbas_pw_pool%give_back_pw(wf_r)
     645            0 :             CALL auxbas_pw_pool%give_back_pw(wf_g)
     646              :          END IF
     647              : 
     648            0 :          CALL cp_fm_release(fm_qp_mo)
     649              :       END IF
     650              : 
     651            4 :       CALL timestop(handle)
     652              : 
     653            4 :    END SUBROUTINE print_static_cohsex_mos
     654              : 
     655              : ! **************************************************************************************************
     656              : !> \brief Canonical static COHSEX MO coefficients
     657              : !>          C^QP_μn = Σ_m C_μm U_mn
     658              : !> \param mo_coeff ...
     659              : !> \param u_qp ...
     660              : !> \param fm_qp_mo ...
     661              : ! **************************************************************************************************
     662            2 :    SUBROUTINE get_static_cohsex_mo_coeff(mo_coeff, u_qp, fm_qp_mo)
     663              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
     664              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: u_qp
     665              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_qp_mo
     666              : 
     667              :       INTEGER                                            :: nao, nmo
     668              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     669              :       TYPE(cp_fm_type)                                   :: fm_u
     670              : 
     671            2 :       CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_global=nmo)
     672            2 :       NULLIFY (fm_struct)
     673              :       CALL cp_fm_struct_create(fm_struct, template_fmstruct=mo_coeff%matrix_struct, &
     674            2 :                                nrow_global=nmo, ncol_global=nmo)
     675            2 :       CALL cp_fm_create(fm_u, fm_struct)
     676            2 :       CALL cp_fm_struct_release(fm_struct)
     677            2 :       CALL cp_fm_set_submatrix(fm_u, u_qp)
     678            2 :       CALL cp_fm_create(fm_qp_mo, mo_coeff%matrix_struct)
     679              :       CALL parallel_gemm(transa="N", transb="N", m=nao, n=nmo, k=nmo, alpha=1.0_dp, &
     680            2 :                          matrix_a=mo_coeff, matrix_b=fm_u, beta=0.0_dp, matrix_c=fm_qp_mo)
     681            2 :       CALL cp_fm_release(fm_u)
     682              : 
     683            2 :    END SUBROUTINE get_static_cohsex_mo_coeff
     684              : 
     685              : ! **************************************************************************************************
     686              : !> \brief Rotate an RI 3-center slab to the canonical static COHSEX MOs
     687              : !> \param fm_slab ...
     688              : !> \param dimen_RI ...
     689              : !> \param n_outer ...
     690              : !> \param n_inner ...
     691              : !> \param u_outer ...
     692              : !> \param u_inner ...
     693              : ! **************************************************************************************************
     694            6 :    SUBROUTINE rotate_bse_slab(fm_slab, dimen_RI, n_outer, n_inner, u_outer, u_inner)
     695              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_slab
     696              :       INTEGER, INTENT(IN)                                :: dimen_RI, n_outer, n_inner
     697              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: u_outer, u_inner
     698              : 
     699              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rotate_bse_slab'
     700              : 
     701              :       INTEGER                                            :: handle
     702              : 
     703            6 :       CALL timeset(routineN, handle)
     704              : 
     705              :       ! (a) inner index: (P ; o,i) -> (P,o ; i), P fast, reordering [3,1,2,4] and back [3,2,1,4]
     706              :       CALL rotate_one_index(fm_slab, dimen_RI, n_outer, n_inner, u_inner, [3, 1, 2, 4], [3, 2, 1, 4], &
     707            6 :                             n_inner)
     708              :       ! (b) outer index: (P ; o,i) -> (P,i ; o), P fast, reordering [4,1,2,3] and back [3,2,4,1]
     709              :       CALL rotate_one_index(fm_slab, dimen_RI, n_inner, n_outer, u_outer, [4, 1, 2, 3], [3, 2, 4, 1], &
     710            6 :                             n_inner)
     711              : 
     712            6 :       CALL timestop(handle)
     713              : 
     714            6 :    END SUBROUTINE rotate_bse_slab
     715              : 
     716              : ! **************************************************************************************************
     717              : !> \brief rotate one MO index of the compound column index
     718              : !> \param fm_slab ...
     719              : !> \param dimen_RI ...
     720              : !> \param n_spect ...
     721              : !> \param n_rot ...
     722              : !> \param u_rot ...
     723              : !> \param reord_to ...
     724              : !> \param reord_back ...
     725              : !> \param n_inner size ...
     726              : ! **************************************************************************************************
     727           12 :    SUBROUTINE rotate_one_index(fm_slab, dimen_RI, n_spect, n_rot, u_rot, reord_to, reord_back, &
     728              :                                n_inner)
     729              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_slab
     730              :       INTEGER, INTENT(IN)                                :: dimen_RI, n_spect, n_rot
     731              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: u_rot
     732              :       INTEGER, DIMENSION(4)                              :: reord_to, reord_back
     733              :       INTEGER, INTENT(IN)                                :: n_inner
     734              : 
     735              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     736              :       TYPE(cp_fm_type)                                   :: fm_slab_out, fm_t, fm_t_rot, fm_u
     737              : 
     738           12 :       NULLIFY (fm_struct)
     739              :       CALL cp_fm_struct_create(fm_struct, template_fmstruct=fm_slab%matrix_struct, &
     740           12 :                                nrow_global=n_spect*dimen_RI, ncol_global=n_rot)
     741           12 :       CALL cp_fm_create(fm_t, fm_struct, name="static_cohsex_slab_reordered", set_zero=.TRUE.)
     742           12 :       CALL cp_fm_create(fm_t_rot, fm_struct, name="static_cohsex_slab_rotated", set_zero=.TRUE.)
     743           12 :       CALL cp_fm_struct_release(fm_struct)
     744           12 :       CALL cp_fm_permute(fm_t, fm_slab, 1.0_dp, 1, n_inner, dimen_RI, n_rot, reord_to)
     745              : 
     746           12 :       NULLIFY (fm_struct)
     747              :       CALL cp_fm_struct_create(fm_struct, template_fmstruct=fm_slab%matrix_struct, &
     748           12 :                                nrow_global=n_rot, ncol_global=n_rot)
     749           12 :       CALL cp_fm_create(fm_u, fm_struct, name="static_cohsex_U")
     750           12 :       CALL cp_fm_struct_release(fm_struct)
     751           12 :       CALL cp_fm_set_submatrix(fm_u, u_rot)
     752              :       CALL parallel_gemm(transa="N", transb="N", m=n_spect*dimen_RI, n=n_rot, k=n_rot, alpha=1.0_dp, &
     753           12 :                          matrix_a=fm_t, matrix_b=fm_u, beta=0.0_dp, matrix_c=fm_t_rot)
     754           12 :       CALL cp_fm_release(fm_u)
     755           12 :       CALL cp_fm_release(fm_t)
     756              : 
     757           12 :       CALL cp_fm_create(fm_slab_out, fm_slab%matrix_struct, name="static_cohsex_slab_back", set_zero=.TRUE.)
     758           12 :       CALL cp_fm_permute(fm_slab_out, fm_t_rot, 1.0_dp, dimen_RI, n_rot, 1, n_inner, reord_back)
     759           12 :       CALL cp_fm_to_fm(fm_slab_out, fm_slab)
     760           12 :       CALL cp_fm_release(fm_slab_out)
     761           12 :       CALL cp_fm_release(fm_t_rot)
     762              : 
     763           12 :    END SUBROUTINE rotate_one_index
     764              : 
     765              : END MODULE rpa_gw_static_cohsex
        

Generated by: LCOV version 2.0-1