LCOV - code coverage report
Current view: top level - src - rpa_util.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 99.3 % 296 294
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 14 14

            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 Utility functions for RPA calculations
      10              : !> \par History
      11              : !>      06.2019 Moved from rpa_ri_gpw.F [Frederick Stein]
      12              : ! **************************************************************************************************
      13              : MODULE rpa_util
      14              : 
      15              :    USE cell_types,                      ONLY: cell_type,&
      16              :                                               get_cell
      17              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      18              :                                               cp_blacs_env_release,&
      19              :                                               cp_blacs_env_type
      20              :    USE cp_cfm_types,                    ONLY: cp_cfm_copy_general,&
      21              :                                               cp_cfm_create,&
      22              :                                               cp_cfm_release,&
      23              :                                               cp_cfm_set_all,&
      24              :                                               cp_cfm_type,&
      25              :                                               cp_fm_to_cfm
      26              :    USE cp_dbcsr_api,                    ONLY: &
      27              :         dbcsr_create, dbcsr_deallocate_matrix, dbcsr_filter, dbcsr_get_info, dbcsr_multiply, &
      28              :         dbcsr_p_type, dbcsr_release, dbcsr_set, dbcsr_type
      29              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      30              :                                               copy_fm_to_dbcsr,&
      31              :                                               dbcsr_allocate_matrix_set,&
      32              :                                               dbcsr_deallocate_matrix_set
      33              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_syrk,&
      34              :                                               cp_fm_transpose
      35              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      36              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      37              :                                               cp_fm_struct_release,&
      38              :                                               cp_fm_struct_type
      39              :    USE cp_fm_types,                     ONLY: &
      40              :         cp_fm_copy_general, cp_fm_create, cp_fm_get_diag, cp_fm_get_info, cp_fm_release, &
      41              :         cp_fm_set_all, cp_fm_to_fm, cp_fm_to_fm_submat_general, cp_fm_type
      42              :    USE dbt_api,                         ONLY: dbt_destroy,&
      43              :                                               dbt_type
      44              :    USE dgemm_counter_types,             ONLY: dgemm_counter_start,&
      45              :                                               dgemm_counter_stop,&
      46              :                                               dgemm_counter_type
      47              :    USE hfx_types,                       ONLY: block_ind_type,&
      48              :                                               dealloc_containers,&
      49              :                                               hfx_compression_type
      50              :    USE input_constants,                 ONLY: wfc_mm_style_gemm,&
      51              :                                               wfc_mm_style_syrk
      52              :    USE kinds,                           ONLY: dp
      53              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      54              :                                               kpoint_release,&
      55              :                                               kpoint_type
      56              :    USE mathconstants,                   ONLY: z_zero
      57              :    USE message_passing,                 ONLY: mp_para_env_release,&
      58              :                                               mp_para_env_type
      59              :    USE mp2_laplace,                     ONLY: calc_fm_mat_S_laplace
      60              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      61              :    USE qs_environment_types,            ONLY: get_qs_env,&
      62              :                                               qs_environment_type
      63              :    USE rpa_gw_kpoints_util,             ONLY: compute_wkp_W
      64              : #include "./base/base_uses.f90"
      65              : 
      66              :    IMPLICIT NONE
      67              : 
      68              :    PRIVATE
      69              : 
      70              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rpa_util'
      71              : 
      72              :    PUBLIC :: compute_Erpa_by_freq_int, alloc_im_time, calc_mat_Q, &
      73              :              dealloc_im_time, contract_P_omega_with_mat_L, calc_fm_mat_S_rpa, remove_scaling_factor_rpa
      74              : 
      75              : CONTAINS
      76              : 
      77              : ! **************************************************************************************************
      78              : !> \brief ...
      79              : !> \param qs_env ...
      80              : !> \param para_env ...
      81              : !> \param dimen_RI ...
      82              : !> \param dimen_RI_red ...
      83              : !> \param num_integ_points ...
      84              : !> \param nspins ...
      85              : !> \param create_cfm_mo_coeff whether to promote the real Gamma-point coefficients to CFM
      86              : !> \param fm_mat_Q ...
      87              : !> \param cfm_mo_coeff ...
      88              : !> \param cfm_matrix_Minv_L_kpoints ...
      89              : !> \param cfm_matrix_L_kpoints ...
      90              : !> \param fm_matrix_Minv_L_gamma ...
      91              : !> \param mat_P_global ...
      92              : !> \param t_3c_O ...
      93              : !> \param matrix_s ...
      94              : !> \param kpoints ...
      95              : !> \param eps_filter_im_time ...
      96              : !> \param cut_memory ...
      97              : !> \param nkp ...
      98              : !> \param num_cells_dm ...
      99              : !> \param num_3c_repl ...
     100              : !> \param size_P ...
     101              : !> \param ikp_local ...
     102              : !> \param index_to_cell_3c ...
     103              : !> \param cell_to_index_3c ...
     104              : !> \param col_blk_size ...
     105              : !> \param do_ic_model ...
     106              : !> \param do_kpoints_cubic_RPA ...
     107              : !> \param do_kpoints_from_Gamma ...
     108              : !> \param do_ri_Sigma_x ...
     109              : !> \param my_open_shell ...
     110              : !> \param has_mat_P_blocks ...
     111              : !> \param wkp_W ...
     112              : !> \param cfm_mat_Q ...
     113              : !> \param cfm_mat_Minv_L_kpoints ...
     114              : !> \param cfm_mat_L_kpoints ...
     115              : !> \param fm_mat_Minv_L_gamma ...
     116              : !> \param cfm_mat_RI_global_work ...
     117              : !> \param fm_mat_work ...
     118              : !> \param mat_dm ...
     119              : !> \param mat_L ...
     120              : !> \param mat_M_P_munu_occ ...
     121              : !> \param mat_M_P_munu_virt ...
     122              : !> \param mat_MinvVMinv ...
     123              : !> \param mat_P_omega ...
     124              : !> \param mat_P_omega_kp ...
     125              : !> \param mat_work ...
     126              : !> \param mo_coeff ...
     127              : ! **************************************************************************************************
     128          288 :    SUBROUTINE alloc_im_time(qs_env, para_env, dimen_RI, dimen_RI_red, num_integ_points, nspins, &
     129              :                             create_cfm_mo_coeff, &
     130              :                             fm_mat_Q, cfm_mo_coeff, &
     131              :                             cfm_matrix_Minv_L_kpoints, cfm_matrix_L_kpoints, fm_matrix_Minv_L_gamma, mat_P_global, &
     132              :                             t_3c_O, matrix_s, kpoints, eps_filter_im_time, &
     133              :                             cut_memory, nkp, num_cells_dm, num_3c_repl, &
     134              :                             size_P, ikp_local, &
     135              :                             index_to_cell_3c, &
     136              :                             cell_to_index_3c, &
     137              :                             col_blk_size, &
     138              :                             do_ic_model, do_kpoints_cubic_RPA, &
     139              :                             do_kpoints_from_Gamma, do_ri_Sigma_x, my_open_shell, &
     140              :                             has_mat_P_blocks, wkp_W, &
     141              :                             cfm_mat_Q, cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints, fm_mat_Minv_L_gamma, &
     142              :                             cfm_mat_RI_global_work, fm_mat_work, mat_dm, mat_L, mat_M_P_munu_occ, mat_M_P_munu_virt, &
     143              :                             mat_MinvVMinv, mat_P_omega, mat_P_omega_kp, &
     144          144 :                             mat_work, mo_coeff)
     145              : 
     146              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     147              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     148              :       INTEGER, INTENT(IN)                                :: dimen_RI, dimen_RI_red, &
     149              :                                                             num_integ_points, nspins
     150              :       LOGICAL, INTENT(IN)                                :: create_cfm_mo_coeff
     151              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_Q
     152              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_mo_coeff, cfm_matrix_Minv_L_kpoints, &
     153              :                                                             cfm_matrix_L_kpoints
     154              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv_L_gamma
     155              :       TYPE(dbcsr_p_type), INTENT(IN)                     :: mat_P_global
     156              :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:, :), &
     157              :          INTENT(INOUT)                                   :: t_3c_O
     158              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     159              :       TYPE(kpoint_type), POINTER                         :: kpoints
     160              :       REAL(KIND=dp), INTENT(IN)                          :: eps_filter_im_time
     161              :       INTEGER, INTENT(IN)                                :: cut_memory
     162              :       INTEGER, INTENT(OUT)                               :: nkp, num_cells_dm, num_3c_repl, size_P, &
     163              :                                                             ikp_local
     164              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: index_to_cell_3c
     165              :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
     166              :          INTENT(OUT)                                     :: cell_to_index_3c
     167              :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size
     168              :       LOGICAL, INTENT(IN)                                :: do_ic_model, do_kpoints_cubic_RPA, &
     169              :                                                             do_kpoints_from_Gamma, do_ri_Sigma_x, &
     170              :                                                             my_open_shell
     171              :       LOGICAL, ALLOCATABLE, DIMENSION(:, :, :, :, :), &
     172              :          INTENT(OUT)                                     :: has_mat_P_blocks
     173              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     174              :          INTENT(OUT)                                     :: wkp_W
     175              :       TYPE(cp_cfm_type), INTENT(OUT)                     :: cfm_mat_Q
     176              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints
     177              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_mat_Minv_L_gamma
     178              :       TYPE(cp_cfm_type), INTENT(OUT)                     :: cfm_mat_RI_global_work
     179              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_mat_work
     180              :       TYPE(dbcsr_p_type), INTENT(OUT)                    :: mat_dm, mat_L, mat_M_P_munu_occ, &
     181              :                                                             mat_M_P_munu_virt, mat_MinvVMinv
     182              :       TYPE(dbcsr_p_type), ALLOCATABLE, &
     183              :          DIMENSION(:, :, :)                              :: mat_P_omega
     184              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_P_omega_kp
     185              :       TYPE(dbcsr_type), POINTER                          :: mat_work
     186              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
     187              : 
     188              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'alloc_im_time'
     189              : 
     190              :       INTEGER                                            :: cell_grid_dm(3), first_ikp_local, &
     191              :                                                             handle, i_dim, i_kp, ispin, jquad, &
     192              :                                                             nspins_P_omega, periodic(3)
     193          144 :       INTEGER, DIMENSION(:), POINTER                     :: row_blk_size
     194          144 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: wkp_V
     195              :       TYPE(cell_type), POINTER                           :: cell
     196              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_sub_kp
     197              : 
     198          144 :       CALL timeset(routineN, handle)
     199              : 
     200          144 :       NULLIFY (mat_L%matrix)
     201              : 
     202          144 :       IF (create_cfm_mo_coeff) THEN
     203          212 :          ALLOCATE (cfm_mo_coeff(nspins))
     204          112 :          DO ispin = 1, SIZE(mo_coeff)
     205          112 :             CALL create_mo_coeff(cfm_mo_coeff(ispin), mo_coeff(ispin))
     206              :          END DO
     207              :       END IF
     208              : 
     209          144 :       num_3c_repl = SIZE(t_3c_O, 2)
     210              : 
     211          144 :       IF (do_kpoints_cubic_RPA) THEN
     212              :          ! we always use an odd number of image cells
     213              :          ! CAUTION: also at another point, cell_grid_dm is defined, these definitions have to be identical
     214           24 :          DO i_dim = 1, 3
     215           24 :             cell_grid_dm(i_dim) = (kpoints%nkp_grid(i_dim)/2)*2 - 1
     216              :          END DO
     217            6 :          num_cells_dm = cell_grid_dm(1)*cell_grid_dm(2)*cell_grid_dm(3)
     218           18 :          ALLOCATE (index_to_cell_3c(3, SIZE(kpoints%index_to_cell, 2)))
     219            6 :          CPASSERT(SIZE(kpoints%index_to_cell, 1) == 3)
     220          126 :          index_to_cell_3c(:, :) = kpoints%index_to_cell(:, :)
     221            0 :          ALLOCATE (cell_to_index_3c(LBOUND(kpoints%cell_to_index, 1):UBOUND(kpoints%cell_to_index, 1), &
     222              :                                     LBOUND(kpoints%cell_to_index, 2):UBOUND(kpoints%cell_to_index, 2), &
     223           30 :                                     LBOUND(kpoints%cell_to_index, 3):UBOUND(kpoints%cell_to_index, 3)))
     224           96 :          cell_to_index_3c(:, :, :) = kpoints%cell_to_index(:, :, :)
     225              : 
     226              :       ELSE
     227          138 :          ALLOCATE (index_to_cell_3c(3, 1))
     228          552 :          index_to_cell_3c(:, 1) = 0
     229          138 :          ALLOCATE (cell_to_index_3c(0:0, 0:0, 0:0))
     230          138 :          cell_to_index_3c(0, 0, 0) = 1
     231          138 :          num_cells_dm = 1
     232              :       END IF
     233              : 
     234          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
     235              : 
     236           22 :          CALL get_sub_para_kp(fm_struct_sub_kp, para_env, dimen_RI, ikp_local, first_ikp_local)
     237              : 
     238           22 :          CALL cp_cfm_create(cfm_mat_Q, fm_struct_sub_kp)
     239           22 :          CALL cp_cfm_set_all(cfm_mat_Q, z_zero)
     240              :       ELSE
     241          122 :          first_ikp_local = 1
     242              :       END IF
     243              : 
     244              :       ! if we do kpoints, mat_P has a kpoint and mat_P_omega has the inted
     245              :       ! mat_P(tau, kpoint)
     246          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
     247              : 
     248           22 :          NULLIFY (cell)
     249           22 :          CALL get_qs_env(qs_env, cell=cell)
     250           22 :          CALL get_cell(cell=cell, periodic=periodic)
     251              : 
     252           22 :          CALL get_kpoint_info(kpoints, nkp=nkp)
     253              :          ! compute k-point weights such that functions 1/k^2, 1/k and const function are
     254              :          ! integrated correctly
     255           22 :          CALL compute_wkp_W(qs_env, wkp_W, wkp_V, kpoints, cell%h_inv, periodic)
     256           22 :          DEALLOCATE (wkp_V)
     257              : 
     258              :       ELSE
     259          122 :          nkp = 1
     260              :       END IF
     261              : 
     262          144 :       IF (do_kpoints_cubic_RPA) THEN
     263            6 :          size_P = MAX(num_cells_dm/2 + 1, nkp)
     264          138 :       ELSE IF (do_kpoints_from_Gamma) THEN
     265           16 :          size_P = MAX(3**(periodic(1) + periodic(2) + periodic(3)), nkp)
     266              :       ELSE
     267          122 :          size_P = 1
     268              :       END IF
     269              : 
     270          144 :       nspins_P_omega = 1
     271          144 :       IF (my_open_shell) nspins_P_omega = 2
     272              : 
     273         5518 :       ALLOCATE (mat_P_omega(num_integ_points, size_P, nspins_P_omega))
     274          320 :       DO ispin = 1, nspins_P_omega
     275          952 :          DO i_kp = 1, size_P
     276         4798 :             DO jquad = 1, num_integ_points
     277         3990 :                NULLIFY (mat_P_omega(jquad, i_kp, ispin)%matrix)
     278         3990 :                ALLOCATE (mat_P_omega(jquad, i_kp, ispin)%matrix)
     279              :                CALL dbcsr_create(matrix=mat_P_omega(jquad, i_kp, ispin)%matrix, &
     280         3990 :                                  template=mat_P_global%matrix)
     281         4622 :                CALL dbcsr_set(mat_P_omega(jquad, i_kp, ispin)%matrix, 0.0_dp)
     282              :             END DO
     283              :          END DO
     284              :       END DO
     285              : 
     286          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
     287           22 :          CALL alloc_mat_P_omega(mat_P_omega_kp, 2, size_P, mat_P_global%matrix)
     288              :       END IF
     289              : 
     290          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
     291           22 :          CALL cp_cfm_create(cfm_mat_RI_global_work, cfm_matrix_Minv_L_kpoints(1)%matrix_struct, set_zero=.TRUE.)
     292              :       END IF
     293              : 
     294         1008 :       ALLOCATE (has_mat_P_blocks(num_cells_dm/2 + 1, cut_memory, cut_memory, num_3c_repl, num_3c_repl))
     295         3352 :       has_mat_P_blocks = .TRUE.
     296              : 
     297          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
     298              :          CALL reorder_cfm_mat_L(cfm_mat_Minv_L_kpoints, cfm_matrix_Minv_L_kpoints, fm_struct_sub_kp, para_env, &
     299           22 :                                 first_ikp_local, ikp_local)
     300              : 
     301              :          CALL reorder_cfm_mat_L(cfm_mat_L_kpoints, cfm_matrix_L_kpoints, fm_struct_sub_kp, para_env, &
     302           22 :                                 first_ikp_local, ikp_local)
     303              : 
     304           22 :          CALL cp_fm_struct_release(fm_struct_sub_kp)
     305              : 
     306              :       ELSE
     307              :          CALL reorder_mat_L(fm_mat_Minv_L_gamma, fm_matrix_Minv_L_gamma, fm_mat_Q%matrix_struct, mat_L, &
     308          122 :                             mat_P_global%matrix, dimen_RI, dimen_RI_red)
     309              :       END IF
     310              : 
     311              :       ! Create Scalapack working matrix for the contraction with the metric
     312          144 :       IF (dimen_RI == dimen_RI_red) THEN
     313          140 :          CALL cp_fm_create(fm_mat_work, fm_mat_Q%matrix_struct, set_zero=.TRUE.)
     314              : 
     315              :       ELSE
     316              :          CALL cp_fm_create(fm_mat_work, fm_mat_Q%matrix_struct, nrow=dimen_RI, ncol=dimen_RI_red, &
     317            4 :                            set_zero=.TRUE.)
     318              : 
     319              :       END IF
     320              : 
     321              :       ! Then its DBCSR counter part
     322          144 :       IF (.NOT. (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma)) THEN
     323          122 :          CALL dbcsr_get_info(mat_L%matrix, col_blk_size=col_blk_size, row_blk_size=row_blk_size)
     324              : 
     325              :          ! Create mat_work having the shape of the transposed of mat_L (compare with contract_P_omega_with_mat_L)
     326              :          NULLIFY (mat_work)
     327          122 :          ALLOCATE (mat_work)
     328          122 :          CALL dbcsr_create(mat_work, template=mat_L%matrix, row_blk_size=col_blk_size, col_blk_size=row_blk_size)
     329              :       END IF
     330              : 
     331          144 :       IF (do_ri_Sigma_x .OR. do_ic_model) THEN
     332              : 
     333              :          NULLIFY (mat_MinvVMinv%matrix)
     334          114 :          ALLOCATE (mat_MinvVMinv%matrix)
     335          114 :          CALL dbcsr_create(mat_MinvVMinv%matrix, template=mat_P_global%matrix)
     336          114 :          CALL dbcsr_set(mat_MinvVMinv%matrix, 0.0_dp)
     337              : 
     338              :          ! for kpoints we compute SinvVSinv later with kpoints
     339          114 :          IF (.NOT. (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma)) THEN
     340              : 
     341              :             !  get the Coulomb matrix for Sigma_x = G*V
     342              :             CALL dbcsr_multiply("T", "N", 1.0_dp, mat_L%matrix, mat_L%matrix, &
     343           96 :                                 0.0_dp, mat_MinvVMinv%matrix, filter_eps=eps_filter_im_time)
     344              : 
     345              :          END IF
     346              : 
     347              :       END IF
     348              : 
     349          144 :       IF (do_ri_Sigma_x) THEN
     350              : 
     351              :          NULLIFY (mat_dm%matrix)
     352          114 :          ALLOCATE (mat_dm%matrix)
     353          114 :          CALL dbcsr_create(mat_dm%matrix, template=matrix_s(1)%matrix)
     354              : 
     355              :       END IF
     356              : 
     357          144 :       CALL timestop(handle)
     358              : 
     359          288 :    END SUBROUTINE alloc_im_time
     360              : 
     361              : ! **************************************************************************************************
     362              : !> \brief ...
     363              : !> \param cfm_mo_coeff ...
     364              : !> \param mo_coeff ...
     365              : ! **************************************************************************************************
     366          124 :    SUBROUTINE create_mo_coeff(cfm_mo_coeff, mo_coeff)
     367              : 
     368              :       TYPE(cp_cfm_type), INTENT(OUT)                     :: cfm_mo_coeff
     369              :       TYPE(cp_fm_type), INTENT(IN)                       :: mo_coeff
     370              : 
     371              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'create_mo_coeff'
     372              : 
     373              :       INTEGER                                            :: handle
     374              : 
     375           62 :       CALL timeset(routineN, handle)
     376              : 
     377           62 :       CALL cp_cfm_create(cfm_mo_coeff, mo_coeff%matrix_struct)
     378           62 :       CALL cp_fm_to_cfm(msourcer=mo_coeff, mtarget=cfm_mo_coeff)
     379              : 
     380           62 :       CALL timestop(handle)
     381              : 
     382           62 :    END SUBROUTINE create_mo_coeff
     383              : 
     384              : ! **************************************************************************************************
     385              : !> \brief Reorders complex k-point matrices to the subgroup distribution.
     386              : !> \param cfm_mat_L ...
     387              : !> \param cfm_matrix_L_kpoints ...
     388              : !> \param fm_struct_sub_kp ...
     389              : !> \param para_env ...
     390              : !> \param first_ikp_local ...
     391              : !> \param ikp_local ...
     392              : ! **************************************************************************************************
     393           44 :    SUBROUTINE reorder_cfm_mat_L(cfm_mat_L, cfm_matrix_L_kpoints, fm_struct_sub_kp, para_env, first_ikp_local, ikp_local)
     394              : 
     395              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_mat_L, cfm_matrix_L_kpoints
     396              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_sub_kp
     397              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     398              :       INTEGER, INTENT(IN)                                :: first_ikp_local, ikp_local
     399              : 
     400              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'reorder_cfm_mat_L'
     401              : 
     402              :       INTEGER                                            :: handle, ikp
     403              : 
     404           44 :       CALL timeset(routineN, handle)
     405              : 
     406          988 :       ALLOCATE (cfm_mat_L(SIZE(cfm_matrix_L_kpoints)))
     407          900 :       DO ikp = 1, SIZE(cfm_matrix_L_kpoints)
     408          856 :          IF (ikp == first_ikp_local .OR. ikp_local == -1) THEN
     409          856 :             CALL cp_cfm_create(cfm_mat_L(ikp), fm_struct_sub_kp, set_zero=.TRUE.)
     410              :          END IF
     411          856 :          CALL cp_cfm_copy_general(cfm_matrix_L_kpoints(ikp), cfm_mat_L(ikp), para_env)
     412          900 :          IF (ASSOCIATED(cfm_matrix_L_kpoints(ikp)%matrix_struct)) CALL cp_cfm_release(cfm_matrix_L_kpoints(ikp))
     413              :       END DO
     414           44 :       DEALLOCATE (cfm_matrix_L_kpoints)
     415              : 
     416           44 :       CALL timestop(handle)
     417              : 
     418           44 :    END SUBROUTINE reorder_cfm_mat_L
     419              : 
     420              : ! **************************************************************************************************
     421              : !> \brief ...
     422              : !> \param mat_P_omega ...
     423              : !> \param num_integ_points ...
     424              : !> \param size_P ...
     425              : !> \param template ...
     426              : ! **************************************************************************************************
     427           22 :    SUBROUTINE alloc_mat_P_omega(mat_P_omega, num_integ_points, size_P, template)
     428              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_P_omega
     429              :       INTEGER, INTENT(IN)                                :: num_integ_points, size_P
     430              :       TYPE(dbcsr_type), POINTER                          :: template
     431              : 
     432              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'alloc_mat_P_omega'
     433              : 
     434              :       INTEGER                                            :: handle, i_kp, jquad
     435              : 
     436           22 :       CALL timeset(routineN, handle)
     437              : 
     438           22 :       NULLIFY (mat_P_omega)
     439           22 :       CALL dbcsr_allocate_matrix_set(mat_P_omega, num_integ_points, size_P)
     440          450 :       DO i_kp = 1, size_P
     441         1306 :          DO jquad = 1, num_integ_points
     442          856 :             ALLOCATE (mat_P_omega(jquad, i_kp)%matrix)
     443              :             CALL dbcsr_create(matrix=mat_P_omega(jquad, i_kp)%matrix, &
     444          856 :                               template=template)
     445         1284 :             CALL dbcsr_set(mat_P_omega(jquad, i_kp)%matrix, 0.0_dp)
     446              :          END DO
     447              :       END DO
     448              : 
     449           22 :       CALL timestop(handle)
     450              : 
     451           22 :    END SUBROUTINE alloc_mat_P_omega
     452              : 
     453              : ! **************************************************************************************************
     454              : !> \brief ...
     455              : !> \param fm_mat_L ...
     456              : !> \param fm_matrix_Minv_L_gamma ...
     457              : !> \param fm_struct_template ...
     458              : !> \param mat_L ...
     459              : !> \param mat_template ...
     460              : !> \param dimen_RI ...
     461              : !> \param dimen_RI_red ...
     462              : ! **************************************************************************************************
     463          366 :    SUBROUTINE reorder_mat_L(fm_mat_L, fm_matrix_Minv_L_gamma, fm_struct_template, mat_L, mat_template, &
     464              :                             dimen_RI, dimen_RI_red)
     465              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_mat_L
     466              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv_L_gamma
     467              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_template
     468              :       TYPE(dbcsr_p_type), INTENT(OUT)                    :: mat_L
     469              :       TYPE(dbcsr_type), INTENT(IN)                       :: mat_template
     470              :       INTEGER, INTENT(IN)                                :: dimen_RI, dimen_RI_red
     471              : 
     472              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'reorder_mat_L'
     473              : 
     474              :       INTEGER                                            :: handle, nblk
     475          122 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, row_blk_size
     476              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     477              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     478              :       TYPE(cp_fm_type)                                   :: fm_mat_L_transposed
     479              : 
     480          122 :       CALL timeset(routineN, handle)
     481              : 
     482              :       ! Get the fm_struct for fm_mat_L
     483          122 :       NULLIFY (fm_struct)
     484          122 :       IF (dimen_RI == dimen_RI_red) THEN
     485          118 :          fm_struct => fm_struct_template
     486              :       ELSE
     487              :          ! The template is assumed to be square such that we need a new fm_struct if dimensions are not equal
     488            4 :          CALL cp_fm_struct_create(fm_struct, nrow_global=dimen_RI_red, ncol_global=dimen_RI, template_fmstruct=fm_struct_template)
     489              :       END IF
     490              : 
     491          122 :       CALL cp_fm_create(fm_mat_L, fm_struct)
     492          122 :       CALL cp_fm_set_all(fm_mat_L, 0.0_dp)
     493              : 
     494              :       ! For the transposed matric we need a different fm_struct
     495          122 :       IF (dimen_RI == dimen_RI_red) THEN
     496          118 :          fm_struct => fm_mat_L%matrix_struct
     497              :       ELSE
     498            4 :          CALL cp_fm_struct_release(fm_struct)
     499              : 
     500              :          ! Create a fm_struct with transposed sizes
     501            4 :          NULLIFY (fm_struct)
     502              :          CALL cp_fm_struct_create(fm_struct, nrow_global=dimen_RI, ncol_global=dimen_RI_red, &
     503            4 :                                   template_fmstruct=fm_mat_L%matrix_struct)
     504              :       END IF
     505              : 
     506          122 :       CALL cp_fm_create(fm_mat_L_transposed, fm_struct)
     507          122 :       CALL cp_fm_set_all(matrix=fm_mat_L_transposed, alpha=0.0_dp)
     508              : 
     509          122 :       IF (dimen_RI /= dimen_RI_red) CALL cp_fm_struct_release(fm_struct)
     510              : 
     511          122 :       CALL cp_fm_get_info(fm_mat_L_transposed, context=blacs_env)
     512              : 
     513          122 :       CALL cp_fm_copy_general(fm_matrix_Minv_L_gamma(1, 1), fm_mat_L_transposed, blacs_env%para_env)
     514          122 :       CALL cp_fm_transpose(fm_mat_L_transposed, fm_mat_L)
     515              : 
     516              :       ! Release old matrix
     517          122 :       CALL cp_fm_release(fm_matrix_Minv_L_gamma)
     518              :       ! Release buffer
     519          122 :       CALL cp_fm_release(fm_mat_L_transposed)
     520              : 
     521              :       NULLIFY (mat_L%matrix)
     522          122 :       ALLOCATE (mat_L%matrix)
     523          122 :       IF (dimen_RI == dimen_RI_red) THEN
     524          118 :          CALL dbcsr_create(mat_L%matrix, template=mat_template)
     525              :       ELSE
     526            4 :          CALL dbcsr_get_info(mat_template, nblkrows_total=nblk, col_blk_size=col_blk_size)
     527              : 
     528            4 :          CALL calculate_equal_blk_size(row_blk_size, dimen_RI_red, nblk)
     529              : 
     530            4 :          CALL dbcsr_create(mat_L%matrix, template=mat_template, row_blk_size=row_blk_size, col_blk_size=col_blk_size)
     531              : 
     532            4 :          DEALLOCATE (row_blk_size)
     533              :       END IF
     534              : 
     535          122 :       CALL copy_fm_to_dbcsr(fm_mat_L, mat_L%matrix)
     536              : 
     537          122 :       CALL timestop(handle)
     538              : 
     539          122 :    END SUBROUTINE reorder_mat_L
     540              : 
     541              : ! **************************************************************************************************
     542              : !> \brief ...
     543              : !> \param blk_size_new ...
     544              : !> \param dimen_RI_red ...
     545              : !> \param nblk ...
     546              : ! **************************************************************************************************
     547            4 :    SUBROUTINE calculate_equal_blk_size(blk_size_new, dimen_RI_red, nblk)
     548              :       INTEGER, DIMENSION(:), POINTER                     :: blk_size_new
     549              :       INTEGER, INTENT(IN)                                :: dimen_RI_red, nblk
     550              : 
     551              :       INTEGER                                            :: col_per_blk, remainder
     552              : 
     553            4 :       NULLIFY (blk_size_new)
     554           12 :       ALLOCATE (blk_size_new(nblk))
     555              : 
     556            4 :       remainder = MOD(dimen_RI_red, nblk)
     557            4 :       col_per_blk = dimen_RI_red/nblk
     558              : 
     559              :       ! Determine a new distribution for the columns (corresponding to the number of columns)
     560           10 :       IF (remainder > 0) blk_size_new(1:remainder) = col_per_blk + 1
     561           10 :       blk_size_new(remainder + 1:nblk) = col_per_blk
     562              : 
     563            4 :    END SUBROUTINE calculate_equal_blk_size
     564              : 
     565              : ! **************************************************************************************************
     566              : !> \brief ...
     567              : !> \param fm_mat_S ...
     568              : !> \param do_ri_sos_laplace_mp2 ...
     569              : !> \param first_cycle ...
     570              : !> \param virtual ...
     571              : !> \param Eigenval ...
     572              : !> \param homo ...
     573              : !> \param omega ...
     574              : !> \param omega_old ...
     575              : !> \param jquad ...
     576              : !> \param mm_style ...
     577              : !> \param dimen_RI ...
     578              : !> \param dimen_ia ...
     579              : !> \param alpha ...
     580              : !> \param fm_mat_Q ...
     581              : !> \param fm_mat_Q_gemm ...
     582              : !> \param do_bse ...
     583              : !> \param fm_mat_Q_static_bse_gemm ...
     584              : !> \param dgemm_counter ...
     585              : !> \param num_integ_points ...
     586              : !> \param count_ev_sc_GW ...
     587              : ! **************************************************************************************************
     588        25038 :    SUBROUTINE calc_mat_Q(fm_mat_S, do_ri_sos_laplace_mp2, first_cycle, virtual, &
     589        12519 :                          Eigenval, homo, omega, omega_old, jquad, mm_style, dimen_RI, dimen_ia, alpha, fm_mat_Q, fm_mat_Q_gemm, &
     590              :                          do_bse, fm_mat_Q_static_bse_gemm, dgemm_counter, &
     591              :                          num_integ_points, count_ev_sc_GW)
     592              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S
     593              :       LOGICAL, INTENT(IN)                                :: do_ri_sos_laplace_mp2, first_cycle
     594              :       INTEGER, INTENT(IN)                                :: virtual
     595              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: Eigenval
     596              :       INTEGER, INTENT(IN)                                :: homo
     597              :       REAL(KIND=dp), INTENT(IN)                          :: omega, omega_old
     598              :       INTEGER, INTENT(IN)                                :: jquad, mm_style, dimen_RI, dimen_ia
     599              :       REAL(KIND=dp), INTENT(IN)                          :: alpha
     600              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_Q, fm_mat_Q_gemm
     601              :       LOGICAL, INTENT(IN)                                :: do_bse
     602              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_Q_static_bse_gemm
     603              :       TYPE(dgemm_counter_type), INTENT(INOUT)            :: dgemm_counter
     604              :       INTEGER, INTENT(IN)                                :: num_integ_points, count_ev_sc_GW
     605              : 
     606              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'calc_mat_Q'
     607              : 
     608              :       INTEGER                                            :: handle
     609              : 
     610        12519 :       CALL timeset(routineN, handle)
     611              : 
     612        12519 :       IF (do_ri_sos_laplace_mp2) THEN
     613              :          ! the first index of tau_tj starts with 0 (see mp2_weights)
     614           88 :          CALL calc_fm_mat_S_laplace(fm_mat_S, homo, virtual, Eigenval, omega - omega_old)
     615              :       ELSE
     616              :          CALL calc_fm_mat_S_rpa(fm_mat_S, first_cycle, virtual, Eigenval, &
     617        12431 :                                 homo, omega, omega_old)
     618              :       END IF
     619              : 
     620              :       CALL contract_S_to_Q(mm_style, dimen_RI, dimen_ia, alpha, fm_mat_S, fm_mat_Q_gemm, &
     621        12519 :                            fm_mat_Q, dgemm_counter)
     622              :       ! fm_mat_Q_static_bse_gemm does not enter W_ijab (A matrix in TDA), but only full ABBA
     623              :       ! (since only B_ij_bar enters W_ijab)
     624              :       ! Changing jquad, since omega=0 is at last idx
     625              :       ! We enforce W0 for BSE in case of evGW
     626        12519 :       IF (do_bse .AND. jquad == num_integ_points .AND. count_ev_sc_GW == 1) THEN
     627           64 :          CALL cp_fm_to_fm(fm_mat_Q_gemm, fm_mat_Q_static_bse_gemm)
     628              :       END IF
     629        12519 :       CALL timestop(handle)
     630              : 
     631        12519 :    END SUBROUTINE calc_mat_Q
     632              : 
     633              : ! **************************************************************************************************
     634              : !> \brief ...
     635              : !> \param fm_mat_S ...
     636              : !> \param virtual ...
     637              : !> \param Eigenval_last ...
     638              : !> \param homo ...
     639              : !> \param omega_old ...
     640              : ! **************************************************************************************************
     641          282 :    SUBROUTINE remove_scaling_factor_rpa(fm_mat_S, virtual, Eigenval_last, homo, omega_old)
     642              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S
     643              :       INTEGER, INTENT(IN)                                :: virtual
     644              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: Eigenval_last
     645              :       INTEGER, INTENT(IN)                                :: homo
     646              :       REAL(KIND=dp), INTENT(IN)                          :: omega_old
     647              : 
     648              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'remove_scaling_factor_rpa'
     649              : 
     650              :       INTEGER                                            :: avirt, handle, i_global, iiB, iocc, &
     651              :                                                             ncol_local
     652          282 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices
     653              :       REAL(KIND=dp)                                      :: eigen_diff
     654              : 
     655          282 :       CALL timeset(routineN, handle)
     656              : 
     657              :       ! get info of fm_mat_S
     658              :       CALL cp_fm_get_info(matrix=fm_mat_S, &
     659              :                           ncol_local=ncol_local, &
     660          282 :                           col_indices=col_indices)
     661              : 
     662              : !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(iiB,iocc,avirt,eigen_diff,i_global) &
     663          282 : !$OMP             SHARED(ncol_local,col_indices,Eigenval_last,fm_mat_S,virtual,homo,omega_old)
     664              :       DO iiB = 1, ncol_local
     665              :          i_global = col_indices(iiB)
     666              : 
     667              :          iocc = MAX(1, i_global - 1)/virtual + 1
     668              :          avirt = i_global - (iocc - 1)*virtual
     669              :          eigen_diff = Eigenval_last(avirt + homo) - Eigenval_last(iocc)
     670              : 
     671              :          fm_mat_S%local_data(:, iiB) = fm_mat_S%local_data(:, iiB)/ &
     672              :                                        SQRT(eigen_diff/(eigen_diff**2 + omega_old**2))
     673              : 
     674              :       END DO
     675              : 
     676          282 :       CALL timestop(handle)
     677              : 
     678          282 :    END SUBROUTINE remove_scaling_factor_rpa
     679              : 
     680              : ! **************************************************************************************************
     681              : !> \brief ...
     682              : !> \param fm_mat_S ...
     683              : !> \param first_cycle ...
     684              : !> \param virtual ...
     685              : !> \param Eigenval ...
     686              : !> \param homo ...
     687              : !> \param omega ...
     688              : !> \param omega_old ...
     689              : ! **************************************************************************************************
     690        12521 :    SUBROUTINE calc_fm_mat_S_rpa(fm_mat_S, first_cycle, virtual, Eigenval, homo, &
     691              :                                 omega, omega_old)
     692              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S
     693              :       LOGICAL, INTENT(IN)                                :: first_cycle
     694              :       INTEGER, INTENT(IN)                                :: virtual
     695              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: Eigenval
     696              :       INTEGER, INTENT(IN)                                :: homo
     697              :       REAL(KIND=dp), INTENT(IN)                          :: omega, omega_old
     698              : 
     699              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'calc_fm_mat_S_rpa'
     700              : 
     701              :       INTEGER                                            :: avirt, handle, i_global, iiB, iocc, &
     702              :                                                             ncol_local
     703        12521 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices
     704              :       REAL(KIND=dp)                                      :: eigen_diff
     705              : 
     706        12521 :       CALL timeset(routineN, handle)
     707              : 
     708              :       ! get info of fm_mat_S
     709              :       CALL cp_fm_get_info(matrix=fm_mat_S, &
     710              :                           ncol_local=ncol_local, &
     711        12521 :                           col_indices=col_indices)
     712              : 
     713              :       ! update G matrix with the new value of omega
     714        12521 :       IF (first_cycle) THEN
     715              :          ! In this case just update the matrix (symmetric form) with
     716              :          ! SQRT((epsi_a-epsi_i)/((epsi_a-epsi_i)**2+omega**2))
     717              :          !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(iiB,iocc,avirt,eigen_diff,i_global) &
     718          418 :          !$OMP             SHARED(ncol_local,col_indices,Eigenval,fm_mat_S,virtual,homo,omega)
     719              :          DO iiB = 1, ncol_local
     720              :             i_global = col_indices(iiB)
     721              : 
     722              :             iocc = MAX(1, i_global - 1)/virtual + 1
     723              :             avirt = i_global - (iocc - 1)*virtual
     724              :             eigen_diff = Eigenval(avirt + homo) - Eigenval(iocc)
     725              : 
     726              :             fm_mat_S%local_data(:, iiB) = fm_mat_S%local_data(:, iiB)* &
     727              :                                           SQRT(eigen_diff/(eigen_diff**2 + omega**2))
     728              : 
     729              :          END DO
     730              :       ELSE
     731              :          ! In this case the update has to remove the old omega component thus
     732              :          ! SQRT(((epsi_a-epsi_i)**2+omega_old**2)/((epsi_a-epsi_i)**2+omega**2))
     733              :          !$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(iiB,iocc,avirt,eigen_diff,i_global) &
     734        12103 :          !$OMP             SHARED(ncol_local,col_indices,Eigenval,fm_mat_S,virtual,homo,omega,omega_old)
     735              :          DO iiB = 1, ncol_local
     736              :             i_global = col_indices(iiB)
     737              : 
     738              :             iocc = MAX(1, i_global - 1)/virtual + 1
     739              :             avirt = i_global - (iocc - 1)*virtual
     740              :             eigen_diff = Eigenval(avirt + homo) - Eigenval(iocc)
     741              : 
     742              :             fm_mat_S%local_data(:, iiB) = fm_mat_S%local_data(:, iiB)* &
     743              :                                           SQRT((eigen_diff**2 + omega_old**2)/(eigen_diff**2 + omega**2))
     744              : 
     745              :          END DO
     746              :       END IF
     747              : 
     748        12521 :       CALL timestop(handle)
     749              : 
     750        12521 :    END SUBROUTINE calc_fm_mat_S_rpa
     751              : 
     752              : ! **************************************************************************************************
     753              : !> \brief ...
     754              : !> \param mm_style ...
     755              : !> \param dimen_RI ...
     756              : !> \param dimen_ia ...
     757              : !> \param alpha ...
     758              : !> \param fm_mat_S ...
     759              : !> \param fm_mat_Q_gemm ...
     760              : !> \param fm_mat_Q ...
     761              : !> \param dgemm_counter ...
     762              : ! **************************************************************************************************
     763        12519 :    SUBROUTINE contract_S_to_Q(mm_style, dimen_RI, dimen_ia, alpha, fm_mat_S, fm_mat_Q_gemm, &
     764              :                               fm_mat_Q, dgemm_counter)
     765              : 
     766              :       INTEGER, INTENT(IN)                                :: mm_style, dimen_RI, dimen_ia
     767              :       REAL(KIND=dp), INTENT(IN)                          :: alpha
     768              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S, fm_mat_Q_gemm, fm_mat_Q
     769              :       TYPE(dgemm_counter_type), INTENT(INOUT)            :: dgemm_counter
     770              : 
     771              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'contract_S_to_Q'
     772              : 
     773              :       INTEGER                                            :: handle
     774              : 
     775        12519 :       CALL timeset(routineN, handle)
     776              : 
     777        12519 :       CALL dgemm_counter_start(dgemm_counter)
     778        25028 :       SELECT CASE (mm_style)
     779              :       CASE (wfc_mm_style_gemm)
     780              :          ! waste-fully computes the full symmetrix matrix, but maybe faster than cp_fm_syrk for optimized cp_fm_gemm !!!
     781              :          CALL parallel_gemm(transa="N", transb="T", m=dimen_RI, n=dimen_RI, k=dimen_ia, alpha=alpha, &
     782              :                             matrix_a=fm_mat_S, matrix_b=fm_mat_S, beta=0.0_dp, &
     783        12509 :                             matrix_c=fm_mat_Q_gemm)
     784              :       CASE (wfc_mm_style_syrk)
     785              :          ! will only compute the upper half of the matrix, which is fine, since we only use it for cholesky later
     786              :          CALL cp_fm_syrk(uplo='U', trans='N', k=dimen_ia, alpha=alpha, matrix_a=fm_mat_S, &
     787           10 :                          ia=1, ja=1, beta=0.0_dp, matrix_c=fm_mat_Q_gemm)
     788              :       CASE DEFAULT
     789        12519 :          CPABORT("Unknown mm_style for contract_S_to_Q")
     790              :       END SELECT
     791        12519 :       CALL dgemm_counter_stop(dgemm_counter, dimen_RI, dimen_RI, dimen_ia)
     792              : 
     793              :       ! copy/redistribute fm_mat_Q_gemm to fm_mat_Q
     794        12519 :       CALL cp_fm_set_all(matrix=fm_mat_Q, alpha=0.0_dp)
     795              :       CALL cp_fm_to_fm_submat_general(fm_mat_Q_gemm, fm_mat_Q, dimen_RI, dimen_RI, 1, 1, 1, 1, &
     796        12519 :                                       fm_mat_Q_gemm%matrix_struct%context)
     797              : 
     798        12519 :       CALL timestop(handle)
     799              : 
     800        12519 :    END SUBROUTINE contract_S_to_Q
     801              : 
     802              : ! **************************************************************************************************
     803              : !> \brief Factorize epsilon in place and accumulate the frequency-weighted RPA energy.
     804              : !> \param dimen_RI dimension of the active RI block
     805              : !> \param diag_Qomega global diagonal elements of Q
     806              : !> \param fm_mat_Q epsilon on entry, its upper Cholesky factor on exit
     807              : !> \param para_env_RPA ...
     808              : !> \param Erpa ...
     809              : !> \param wjquad ...
     810              : ! **************************************************************************************************
     811        12721 :    SUBROUTINE compute_Erpa_by_freq_int(dimen_RI, diag_Qomega, fm_mat_Q, para_env_RPA, Erpa, wjquad)
     812              : 
     813              :       INTEGER, INTENT(IN)                                :: dimen_RI
     814              :       REAL(KIND=dp), DIMENSION(dimen_RI), INTENT(IN)     :: diag_Qomega
     815              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_Q
     816              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env_RPA
     817              :       REAL(KIND=dp), INTENT(INOUT)                       :: Erpa
     818              :       REAL(KIND=dp), INTENT(IN)                          :: wjquad
     819              : 
     820              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_Erpa_by_freq_int'
     821              : 
     822              :       INTEGER                                            :: handle, iiB, info_chol
     823              :       REAL(KIND=dp)                                      :: FComega
     824        12721 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: Q_log
     825              : 
     826        12721 :       CALL timeset(routineN, handle)
     827              : 
     828              :       ! epsilon = U^T U; log(det(epsilon)) = 2*sum(log(U_ii)).
     829        12721 :       CALL cp_fm_cholesky_decompose(matrix=fm_mat_Q, n=dimen_RI, info_out=info_chol)
     830        12721 :       IF (info_chol /= 0) THEN
     831              :          CALL cp_warn(__LOCATION__, &
     832              :                       "The Cholesky decomposition before inverting the RPA matrix / dielectric "// &
     833              :                       "function failed. "// &
     834              :                       "In case of low-scaling RPA/GW, decreasing EPS_FILTER in the &LOW_SCALING "// &
     835              :                       "section might "// &
     836              :                       "increase the overall accuracy making the matrix positive definite. "// &
     837            0 :                       "Code will abort.")
     838              :       END IF
     839              : 
     840        12721 :       CPASSERT(info_chol == 0)
     841              : 
     842        38163 :       ALLOCATE (Q_log(dimen_RI))
     843        12721 :       CALL cp_fm_get_diag(fm_mat_Q, Q_log, n_active=dimen_RI)
     844      1072186 :       Q_log = 2.0_dp*LOG(Q_log)
     845              : 
     846              :       ! the following frequency integration is Eq. (27) in M. Del Ben et al., JCTC 9, 2654 (2013)
     847              :       ! (https://doi.org/10.1021/ct4002202)
     848              :       FComega = 0.0_dp
     849      1072186 :       DO iiB = 1, dimen_RI
     850      1059465 :          IF (MODULO(iiB, para_env_RPA%num_pe) /= para_env_RPA%mepos) CYCLE
     851      1072186 :          FComega = FComega + (Q_log(iiB) - diag_Qomega(iiB))/2.0_dp
     852              :       END DO
     853        12721 :       Erpa = Erpa + FComega*wjquad
     854              : 
     855        12721 :       DEALLOCATE (Q_log)
     856              : 
     857        12721 :       CALL timestop(handle)
     858              : 
     859        12721 :    END SUBROUTINE compute_Erpa_by_freq_int
     860              : 
     861              : ! **************************************************************************************************
     862              : !> \brief ...
     863              : !> \param fm_struct_sub_kp ...
     864              : !> \param para_env ...
     865              : !> \param dimen_RI ...
     866              : !> \param ikp_local ...
     867              : !> \param first_ikp_local ...
     868              : ! **************************************************************************************************
     869           22 :    SUBROUTINE get_sub_para_kp(fm_struct_sub_kp, para_env, dimen_RI, &
     870              :                               ikp_local, first_ikp_local)
     871              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_sub_kp
     872              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     873              :       INTEGER, INTENT(IN)                                :: dimen_RI
     874              :       INTEGER, INTENT(OUT)                               :: ikp_local, first_ikp_local
     875              : 
     876              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'get_sub_para_kp'
     877              : 
     878              :       INTEGER                                            :: color_sub_kp, handle, num_proc_per_kp
     879              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env_sub_kp
     880              :       TYPE(mp_para_env_type), POINTER                    :: para_env_sub_kp
     881              : 
     882           22 :       CALL timeset(routineN, handle)
     883              : 
     884              :       ! we use all processors for every k-point, subgroups for cp_cfm_heevd only seems to work for
     885              :       ! very small subgroups with 1, 2, or 3 MPI ranks. For more MPI-ranks, eigenvalues and
     886              :       ! eigenvectors coming out of cp_cfm_heevd are totally wrong unfortunately.
     887           22 :       num_proc_per_kp = para_env%num_pe
     888              : 
     889              :       ! IF(nkp > para_env%num_pe) THEN
     890              :       !   num_proc_per_kp = para_env%num_pe
     891              :       ! ELSE
     892              :       !   num_proc_per_kp = para_env%num_pe/nkp
     893              :       ! END IF
     894              : 
     895           22 :       color_sub_kp = para_env%mepos/num_proc_per_kp
     896           22 :       ALLOCATE (para_env_sub_kp)
     897           22 :       CALL para_env_sub_kp%from_split(para_env, color_sub_kp)
     898              : 
     899              :       ! grid_2d(1) = 1
     900              :       ! grid_2d(2) = para_env_sub_kp%num_pe
     901              : 
     902           22 :       NULLIFY (blacs_env_sub_kp)
     903              :       ! CALL cp_blacs_env_create(blacs_env=blacs_env_sub_kp, para_env=para_env_sub_kp, grid_2d=grid_2d)
     904           22 :       CALL cp_blacs_env_create(blacs_env=blacs_env_sub_kp, para_env=para_env_sub_kp)
     905              : 
     906           22 :       NULLIFY (fm_struct_sub_kp)
     907              :       CALL cp_fm_struct_create(fm_struct_sub_kp, context=blacs_env_sub_kp, nrow_global=dimen_RI, &
     908           22 :                                ncol_global=dimen_RI, para_env=para_env_sub_kp)
     909              : 
     910           22 :       CALL cp_blacs_env_release(blacs_env_sub_kp)
     911              : 
     912              :       ! IF(nkp > para_env%num_pe) THEN
     913              :       ! every processor has all ikp's
     914           22 :       ikp_local = -1
     915           22 :       first_ikp_local = 1
     916              :       ! ELSE
     917              :       !    ikp_local = 0
     918              :       !    first_ikp_local = 1
     919              :       !    DO ikp = 1, nkp
     920              :       !      IF(MOD(ikp-1, para_env%num_pe/num_proc_per_kp) == color_sub_kp) THEN
     921              :       !        ikp_local = ikp
     922              :       !        first_ikp_local = ikp
     923              :       !      END IF
     924              :       !    END DO
     925              :       ! END IF
     926              : 
     927           22 :       CALL mp_para_env_release(para_env_sub_kp)
     928              : 
     929           22 :       CALL timestop(handle)
     930              : 
     931           22 :    END SUBROUTINE get_sub_para_kp
     932              : 
     933              : ! **************************************************************************************************
     934              : !> \brief ...
     935              : !> \param cfm_mo_coeff ...
     936              : !> \param index_to_cell_3c ...
     937              : !> \param cell_to_index_3c ...
     938              : !> \param do_ic_model ...
     939              : !> \param do_kpoints_cubic_RPA ...
     940              : !> \param do_kpoints_from_Gamma ...
     941              : !> \param do_ri_Sigma_x ...
     942              : !> \param has_mat_P_blocks ...
     943              : !> \param wkp_W ...
     944              : !> \param cfm_mat_Q ...
     945              : !> \param cfm_mat_Minv_L_kpoints ...
     946              : !> \param cfm_mat_L_kpoints ...
     947              : !> \param fm_mat_Minv_L_gamma ...
     948              : !> \param fm_matrix_Minv ...
     949              : !> \param fm_matrix_Minv_Vtrunc_Minv ...
     950              : !> \param cfm_mat_RI_global_work ...
     951              : !> \param fm_mat_work ...
     952              : !> \param mat_dm ...
     953              : !> \param mat_L ...
     954              : !> \param mat_MinvVMinv ...
     955              : !> \param mat_P_omega ...
     956              : !> \param mat_P_omega_kp ...
     957              : !> \param t_3c_M ...
     958              : !> \param t_3c_O ...
     959              : !> \param t_3c_O_compressed ...
     960              : !> \param t_3c_O_ind ...
     961              : !> \param mat_work ...
     962              : !> \param qs_env ...
     963              : ! **************************************************************************************************
     964          144 :    SUBROUTINE dealloc_im_time(cfm_mo_coeff, index_to_cell_3c, &
     965              :                               cell_to_index_3c, do_ic_model, &
     966              :                               do_kpoints_cubic_RPA, do_kpoints_from_Gamma, do_ri_Sigma_x, &
     967              :                               has_mat_P_blocks, &
     968              :                               wkp_W, cfm_mat_Q, cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints, &
     969              :                               fm_mat_Minv_L_gamma, &
     970              :                               fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv, &
     971              :                               cfm_mat_RI_global_work, fm_mat_work, mat_dm, mat_L, &
     972              :                               mat_MinvVMinv, mat_P_omega, mat_P_omega_kp, &
     973              :                               t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, &
     974              :                               mat_work, qs_env)
     975              : 
     976              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:), &
     977              :          INTENT(INOUT)                                   :: cfm_mo_coeff
     978              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), &
     979              :          INTENT(INOUT)                                   :: index_to_cell_3c
     980              :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
     981              :          INTENT(INOUT)                                   :: cell_to_index_3c
     982              :       LOGICAL, INTENT(IN)                                :: do_ic_model, do_kpoints_cubic_RPA, &
     983              :                                                             do_kpoints_from_Gamma, do_ri_Sigma_x
     984              :       LOGICAL, ALLOCATABLE, DIMENSION(:, :, :, :, :), &
     985              :          INTENT(INOUT)                                   :: has_mat_P_blocks
     986              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     987              :          INTENT(INOUT)                                   :: wkp_W
     988              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: cfm_mat_Q
     989              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints
     990              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_mat_Minv_L_gamma
     991              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv, &
     992              :                                                             fm_matrix_Minv_Vtrunc_Minv
     993              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: cfm_mat_RI_global_work
     994              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_mat_work
     995              :       TYPE(dbcsr_p_type), INTENT(INOUT)                  :: mat_dm, mat_L, mat_MinvVMinv
     996              :       TYPE(dbcsr_p_type), ALLOCATABLE, &
     997              :          DIMENSION(:, :, :), INTENT(INOUT)               :: mat_P_omega
     998              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_P_omega_kp
     999              :       TYPE(dbt_type)                                     :: t_3c_M
    1000              :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:, :)       :: t_3c_O
    1001              :       TYPE(hfx_compression_type), ALLOCATABLE, &
    1002              :          DIMENSION(:, :, :), INTENT(INOUT)               :: t_3c_O_compressed
    1003              :       TYPE(block_ind_type), ALLOCATABLE, &
    1004              :          DIMENSION(:, :, :), INTENT(INOUT)               :: t_3c_O_ind
    1005              :       TYPE(dbcsr_type), POINTER                          :: mat_work
    1006              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1007              : 
    1008              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'dealloc_im_time'
    1009              : 
    1010              :       INTEGER                                            :: cut_memory, handle, i_kp, i_mem, i_size, &
    1011              :                                                             ispin, j_size, jquad, unused
    1012              : 
    1013          144 :       CALL timeset(routineN, handle)
    1014              : 
    1015          144 :       IF (ALLOCATED(cfm_mo_coeff)) THEN
    1016          112 :          DO ispin = 1, SIZE(cfm_mo_coeff)
    1017          112 :             CALL cp_cfm_release(cfm_mo_coeff(ispin))
    1018              :          END DO
    1019           50 :          DEALLOCATE (cfm_mo_coeff)
    1020              :       END IF
    1021          144 :       IF (ALLOCATED(cfm_mat_Minv_L_kpoints)) THEN
    1022           18 :          DO i_kp = 1, SIZE(cfm_mat_Minv_L_kpoints)
    1023           18 :             IF (ASSOCIATED(cfm_mat_Minv_L_kpoints(i_kp)%matrix_struct)) THEN
    1024           12 :                CALL cp_cfm_release(cfm_mat_Minv_L_kpoints(i_kp))
    1025              :             END IF
    1026              :          END DO
    1027            6 :          DEALLOCATE (cfm_mat_Minv_L_kpoints)
    1028              :       END IF
    1029          144 :       IF (ALLOCATED(cfm_mat_L_kpoints)) THEN
    1030           18 :          DO i_kp = 1, SIZE(cfm_mat_L_kpoints)
    1031           18 :             IF (ASSOCIATED(cfm_mat_L_kpoints(i_kp)%matrix_struct)) CALL cp_cfm_release(cfm_mat_L_kpoints(i_kp))
    1032              :          END DO
    1033            6 :          DEALLOCATE (cfm_mat_L_kpoints)
    1034              :       END IF
    1035          144 :       CALL cp_fm_release(fm_mat_Minv_L_gamma)
    1036              : 
    1037          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
    1038           22 :          CALL cp_fm_release(fm_matrix_Minv_Vtrunc_Minv)
    1039           22 :          CALL cp_fm_release(fm_matrix_Minv)
    1040              :       END IF
    1041              : 
    1042          144 :       CALL cp_fm_release(fm_mat_work)
    1043              : 
    1044          144 :       IF (.NOT. (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma)) THEN
    1045          122 :          CALL dbcsr_release(mat_work)
    1046          122 :          DEALLOCATE (mat_work)
    1047              :       END IF
    1048              : 
    1049          144 :       IF (ASSOCIATED(mat_L%matrix)) THEN
    1050          122 :          CALL dbcsr_release(mat_L%matrix)
    1051          122 :          DEALLOCATE (mat_L%matrix)
    1052              :       END IF
    1053              : 
    1054          144 :       IF (do_ri_Sigma_x .OR. do_ic_model) THEN
    1055          114 :          CALL dbcsr_release(mat_MinvVMinv%matrix)
    1056          114 :          DEALLOCATE (mat_MinvVMinv%matrix)
    1057              :       END IF
    1058          144 :       IF (do_ri_Sigma_x) THEN
    1059          114 :          CALL dbcsr_release(mat_dm%matrix)
    1060          114 :          DEALLOCATE (mat_dm%matrix)
    1061              :       END IF
    1062              : 
    1063          144 :       DEALLOCATE (index_to_cell_3c, cell_to_index_3c)
    1064              : 
    1065          144 :       IF (ALLOCATED(mat_P_omega)) THEN
    1066          320 :          DO ispin = 1, SIZE(mat_P_omega, 3)
    1067          952 :             DO i_kp = 1, SIZE(mat_P_omega, 2)
    1068         4798 :                DO jquad = 1, SIZE(mat_P_omega, 1)
    1069         4622 :                   CALL dbcsr_deallocate_matrix(mat_P_omega(jquad, i_kp, ispin)%matrix)
    1070              :                END DO
    1071              :             END DO
    1072              :          END DO
    1073          144 :          DEALLOCATE (mat_P_omega)
    1074              :       END IF
    1075              : 
    1076          312 :       DO j_size = 1, SIZE(t_3c_O, 2)
    1077          600 :          DO i_size = 1, SIZE(t_3c_O, 1)
    1078          456 :             CALL dbt_destroy(t_3c_O(i_size, j_size))
    1079              :          END DO
    1080              :       END DO
    1081              : 
    1082          432 :       DEALLOCATE (t_3c_O)
    1083          144 :       CALL dbt_destroy(t_3c_M)
    1084              : 
    1085          144 :       DEALLOCATE (has_mat_P_blocks)
    1086              : 
    1087          144 :       IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
    1088           22 :          CALL cp_cfm_release(cfm_mat_Q)
    1089           22 :          CALL cp_cfm_release(cfm_mat_RI_global_work)
    1090           22 :          CALL dbcsr_deallocate_matrix_set(mat_P_omega_kp)
    1091           22 :          DEALLOCATE (wkp_W)
    1092              :       END IF
    1093              : 
    1094          144 :       cut_memory = SIZE(t_3c_O_compressed, 3)
    1095              : 
    1096          620 :       DEALLOCATE (t_3c_O_ind)
    1097          428 :       DO i_mem = 1, cut_memory
    1098          744 :          DO j_size = 1, SIZE(t_3c_O_compressed, 2)
    1099         1076 :             DO i_size = 1, SIZE(t_3c_O_compressed, 1)
    1100          792 :                CALL dealloc_containers(t_3c_O_compressed(i_size, j_size, i_mem), unused)
    1101              :             END DO
    1102              :          END DO
    1103              :       END DO
    1104          144 :       DEALLOCATE (t_3c_O_compressed)
    1105              : 
    1106          144 :       IF (do_kpoints_from_Gamma) THEN
    1107           16 :          CALL kpoint_release(qs_env%mp2_env%ri_rpa_im_time%kpoints_G)
    1108           16 :          IF (qs_env%mp2_env%ri_g0w0%do_kpoints_Sigma) THEN
    1109           16 :             CALL kpoint_release(qs_env%mp2_env%ri_rpa_im_time%kpoints_Sigma)
    1110           16 :             CALL kpoint_release(qs_env%mp2_env%ri_rpa_im_time%kpoints_Sigma_no_xc)
    1111              :          END IF
    1112              :       END IF
    1113              : 
    1114          144 :       CALL timestop(handle)
    1115              : 
    1116          144 :    END SUBROUTINE dealloc_im_time
    1117              : 
    1118              : ! **************************************************************************************************
    1119              : !> \brief ...
    1120              : !> \param mat_P_omega ...
    1121              : !> \param mat_L ...
    1122              : !> \param mat_work ...
    1123              : !> \param eps_filter_im_time ...
    1124              : !> \param fm_mat_work ...
    1125              : !> \param dimen_RI ...
    1126              : !> \param dimen_RI_red ...
    1127              : !> \param fm_mat_L ...
    1128              : !> \param fm_mat_Q ...
    1129              : ! **************************************************************************************************
    1130         1338 :    SUBROUTINE contract_P_omega_with_mat_L(mat_P_omega, mat_L, mat_work, eps_filter_im_time, fm_mat_work, dimen_RI, &
    1131              :                                           dimen_RI_red, fm_mat_L, fm_mat_Q)
    1132              : 
    1133              :       TYPE(dbcsr_type), INTENT(IN)                       :: mat_P_omega, mat_L
    1134              :       TYPE(dbcsr_type), INTENT(INOUT)                    :: mat_work
    1135              :       REAL(KIND=dp), INTENT(IN)                          :: eps_filter_im_time
    1136              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_mat_work
    1137              :       INTEGER, INTENT(IN)                                :: dimen_RI, dimen_RI_red
    1138              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_L, fm_mat_Q
    1139              : 
    1140              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'contract_P_omega_with_mat_L'
    1141              : 
    1142              :       INTEGER                                            :: handle
    1143              : 
    1144         1338 :       CALL timeset(routineN, handle)
    1145              : 
    1146              :       ! multiplication with RI metric/Coulomb operator
    1147              :       CALL dbcsr_multiply("N", "T", 1.0_dp, mat_P_omega, mat_L, &
    1148         1338 :                           0.0_dp, mat_work, filter_eps=eps_filter_im_time)
    1149              : 
    1150         1338 :       CALL copy_dbcsr_to_fm(mat_work, fm_mat_work)
    1151              : 
    1152              :       CALL parallel_gemm('N', 'N', dimen_RI_red, dimen_RI_red, dimen_RI, 1.0_dp, fm_mat_L, fm_mat_work, &
    1153         1338 :                          0.0_dp, fm_mat_Q)
    1154              : 
    1155              :       ! Reset mat_work to save memory
    1156         1338 :       CALL dbcsr_set(mat_work, 0.0_dp)
    1157         1338 :       CALL dbcsr_filter(mat_work, 1.0_dp)
    1158              : 
    1159         1338 :       CALL timestop(handle)
    1160              : 
    1161         1338 :    END SUBROUTINE contract_P_omega_with_mat_L
    1162              : 
    1163              : END MODULE rpa_util
        

Generated by: LCOV version 2.0-1