LCOV - code coverage report
Current view: top level - src - rpa_main.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:e08e82d) Lines: 97.3 % 856 833
Test Date: 2026-10-16 00:55:08 Functions: 100.0 % 11 11

            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 Routines to calculate RI-RPA energy
      10              : !> \par History
      11              : !>      06.2012 created [Mauro Del Ben]
      12              : !>      04.2015 GW routines added [Jan Wilhelm]
      13              : !>      10.2015 Cubic-scaling RPA routines added [Jan Wilhelm]
      14              : !>      10.2018 Cubic-scaling SOS-MP2 added [Frederick Stein]
      15              : !>      03.2019 Refactoring [Frederick Stein]
      16              : ! **************************************************************************************************
      17              : MODULE rpa_main
      18              :    USE bibliography,                    ONLY: &
      19              :         Bates2013, DelBen2013, DelBen2015, Freeman1977, Gruneis2009, Ren2011, Ren2013, &
      20              :         Wilhelm2016a, Wilhelm2016b, Wilhelm2017, Wilhelm2018, cite_reference
      21              :    USE bse_main,                        ONLY: bse_solve,&
      22              :                                               prepare_bse_env_from_ri_rpa_gw
      23              :    USE bse_types,                       ONLY: bse_env_release
      24              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      25              :                                               cp_blacs_env_release,&
      26              :                                               cp_blacs_env_type
      27              :    USE cp_cfm_types,                    ONLY: cp_cfm_type
      28              :    USE cp_dbcsr_api,                    ONLY: dbcsr_add,&
      29              :                                               dbcsr_clear,&
      30              :                                               dbcsr_get_info,&
      31              :                                               dbcsr_p_type,&
      32              :                                               dbcsr_type
      33              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_add_on_diag,&
      34              :                                               cp_fm_scale_and_add
      35              :    USE cp_fm_redistribution,            ONLY: cp_array_to_fm
      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: cp_fm_create,&
      40              :                                               cp_fm_get_diag,&
      41              :                                               cp_fm_get_info,&
      42              :                                               cp_fm_release,&
      43              :                                               cp_fm_set_all,&
      44              :                                               cp_fm_to_fm,&
      45              :                                               cp_fm_type
      46              :    USE dbt_api,                         ONLY: dbt_type
      47              :    USE dgemm_counter_types,             ONLY: dgemm_counter_init,&
      48              :                                               dgemm_counter_type,&
      49              :                                               dgemm_counter_write
      50              :    USE group_dist_types,                ONLY: get_group_dist,&
      51              :                                               group_dist_d1_type,&
      52              :                                               maxsize,&
      53              :                                               release_group_dist
      54              :    USE hfx_types,                       ONLY: block_ind_type,&
      55              :                                               hfx_compression_type
      56              :    USE input_constants,                 ONLY: cohsex_qp_update,&
      57              :                                               rpa_exchange_axk,&
      58              :                                               rpa_exchange_none,&
      59              :                                               rpa_exchange_sosex,&
      60              :                                               sigma_none,&
      61              :                                               wfc_mm_style_gemm
      62              :    USE input_section_types,             ONLY: section_vals_type,&
      63              :                                               section_vals_val_set
      64              :    USE kinds,                           ONLY: dp,&
      65              :                                               int_8
      66              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      67              :                                               kpoint_env_type,&
      68              :                                               kpoint_type
      69              :    USE machine,                         ONLY: m_flush,&
      70              :                                               m_memory
      71              :    USE mathconstants,                   ONLY: pi,&
      72              :                                               z_zero
      73              :    USE message_passing,                 ONLY: mp_comm_type,&
      74              :                                               mp_para_env_release,&
      75              :                                               mp_para_env_type
      76              :    USE minimax_exp,                     ONLY: check_exp_minimax_range
      77              :    USE mp2_laplace,                     ONLY: SOS_MP2_postprocessing
      78              :    USE mp2_types,                       ONLY: mp2_type,&
      79              :                                               three_dim_real_array,&
      80              :                                               two_dim_int_array,&
      81              :                                               two_dim_real_array
      82              :    USE qs_environment_types,            ONLY: get_qs_env,&
      83              :                                               qs_environment_type
      84              :    USE qs_mo_types,                     ONLY: get_mo_set,&
      85              :                                               mo_set_type
      86              :    USE rpa_exchange,                    ONLY: rpa_exchange_needed_mem,&
      87              :                                               rpa_exchange_work_type
      88              :    USE rpa_grad,                        ONLY: rpa_grad_copy_Q,&
      89              :                                               rpa_grad_create,&
      90              :                                               rpa_grad_finalize,&
      91              :                                               rpa_grad_matrix_operations,&
      92              :                                               rpa_grad_needed_mem,&
      93              :                                               rpa_grad_type
      94              :    USE rpa_gw,                          ONLY: allocate_matrices_gw,&
      95              :                                               allocate_matrices_gw_im_time,&
      96              :                                               compute_GW_self_energy,&
      97              :                                               compute_QP_energies,&
      98              :                                               compute_W_cubic_GW,&
      99              :                                               deallocate_matrices_gw,&
     100              :                                               deallocate_matrices_gw_im_time,&
     101              :                                               get_fermi_level_offset
     102              :    USE rpa_gw_ic,                       ONLY: calculate_ic_correction
     103              :    USE rpa_gw_kpoints_util,             ONLY: get_bandstruc_and_k_dependent_MOs,&
     104              :                                               invert_eps_compute_W_and_Erpa_kp
     105              :    USE rpa_gw_static_cohsex,            ONLY: get_static_cohsex_mo_coeff,&
     106              :                                               rotate_bse_slab,&
     107              :                                               static_cohsex_qp_energies
     108              :    USE rpa_im_time,                     ONLY: compute_mat_P_omega
     109              :    USE rpa_im_time_force_methods,       ONLY: calc_laplace_loop_forces,&
     110              :                                               calc_post_loop_forces,&
     111              :                                               calc_rpa_loop_forces,&
     112              :                                               init_im_time_forces,&
     113              :                                               keep_initial_quad
     114              :    USE rpa_im_time_force_types,         ONLY: im_time_force_release,&
     115              :                                               im_time_force_type
     116              :    USE rpa_sigma_functional,            ONLY: finalize_rpa_sigma,&
     117              :                                               rpa_sigma_create,&
     118              :                                               rpa_sigma_matrix_spectral,&
     119              :                                               rpa_sigma_type
     120              :    USE rpa_util,                        ONLY: alloc_im_time,&
     121              :                                               calc_mat_Q,&
     122              :                                               compute_Erpa_by_freq_int,&
     123              :                                               contract_P_omega_with_mat_L,&
     124              :                                               dealloc_im_time,&
     125              :                                               remove_scaling_factor_rpa
     126              :    USE time_frequency_grids,            ONLY: build_clenshaw_grid,&
     127              :                                               build_minimax_time_frequency_grid,&
     128              :                                               time_frequency_grid_release,&
     129              :                                               time_frequency_grid_type
     130              :    USE util,                            ONLY: get_limit
     131              : #include "./base/base_uses.f90"
     132              : 
     133              :    IMPLICIT NONE
     134              : 
     135              :    PRIVATE
     136              : 
     137              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rpa_main'
     138              : 
     139              :    PUBLIC :: rpa_ri_compute_en
     140              : 
     141              : CONTAINS
     142              : 
     143              : ! **************************************************************************************************
     144              : !> \brief ...
     145              : !> \param qs_env ...
     146              : !> \param Erpa ...
     147              : !> \param mp2_env ...
     148              : !> \param BIb_C ...
     149              : !> \param BIb_C_gw ...
     150              : !> \param BIb_C_bse_ij ...
     151              : !> \param BIb_C_bse_ab ...
     152              : !> \param para_env ...
     153              : !> \param para_env_sub ...
     154              : !> \param color_sub ...
     155              : !> \param gd_array ...
     156              : !> \param gd_B_virtual ...
     157              : !> \param gd_B_all ...
     158              : !> \param gd_B_occ_bse ...
     159              : !> \param gd_B_virt_bse ...
     160              : !> \param mo_coeff ...
     161              : !> \param fm_matrix_PQ ...
     162              : !> \param cfm_matrix_L_kpoints ...
     163              : !> \param cfm_matrix_Minv_L_kpoints ...
     164              : !> \param fm_matrix_Minv_L_gamma ...
     165              : !> \param fm_matrix_Minv ...
     166              : !> \param fm_matrix_Minv_Vtrunc_Minv ...
     167              : !> \param kpoints ...
     168              : !> \param Eigenval ...
     169              : !> \param nmo ...
     170              : !> \param homo ...
     171              : !> \param dimen_RI ...
     172              : !> \param dimen_RI_red ...
     173              : !> \param gw_corr_lev_occ ...
     174              : !> \param gw_corr_lev_virt ...
     175              : !> \param bse_lev_virt ...
     176              : !> \param unit_nr ...
     177              : !> \param do_ri_sos_laplace_mp2 ...
     178              : !> \param my_do_gw ...
     179              : !> \param do_im_time ...
     180              : !> \param do_bse ...
     181              : !> \param matrix_s ...
     182              : !> \param mat_munu ...
     183              : !> \param mat_P_global ...
     184              : !> \param t_3c_M ...
     185              : !> \param t_3c_O ...
     186              : !> \param t_3c_O_compressed ...
     187              : !> \param t_3c_O_ind ...
     188              : !> \param starts_array_mc ...
     189              : !> \param ends_array_mc ...
     190              : !> \param starts_array_mc_block ...
     191              : !> \param ends_array_mc_block ...
     192              : !> \param calc_forces ...
     193              : ! **************************************************************************************************
     194          342 :    SUBROUTINE rpa_ri_compute_en(qs_env, Erpa, mp2_env, BIb_C, BIb_C_gw, BIb_C_bse_ij, BIb_C_bse_ab, &
     195              :                                 para_env, para_env_sub, color_sub, &
     196         1026 :                                 gd_array, gd_B_virtual, gd_B_all, gd_B_occ_bse, gd_B_virt_bse, &
     197          342 :                                 mo_coeff, fm_matrix_PQ, cfm_matrix_L_kpoints, cfm_matrix_Minv_L_kpoints, &
     198              :                                 fm_matrix_Minv_L_gamma, &
     199              :                                 fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv, kpoints, &
     200          684 :                                 Eigenval, nmo, homo, dimen_RI, dimen_RI_red, gw_corr_lev_occ, gw_corr_lev_virt, &
     201          342 :                                 bse_lev_virt, &
     202              :                                 unit_nr, do_ri_sos_laplace_mp2, my_do_gw, do_im_time, do_bse, matrix_s, &
     203              :                                 mat_munu, mat_P_global, t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, &
     204              :                                 starts_array_mc, ends_array_mc, &
     205              :                                 starts_array_mc_block, ends_array_mc_block, calc_forces)
     206              : 
     207              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     208              :       REAL(KIND=dp), INTENT(OUT)                         :: Erpa
     209              :       TYPE(mp2_type), INTENT(INOUT)                      :: mp2_env
     210              :       TYPE(three_dim_real_array), DIMENSION(:), &
     211              :          INTENT(INOUT)                                   :: BIb_C, BIb_C_gw, BIb_C_bse_ij, &
     212              :                                                             BIb_C_bse_ab
     213              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_sub
     214              :       INTEGER, INTENT(INOUT)                             :: color_sub
     215              :       TYPE(group_dist_d1_type), INTENT(INOUT)            :: gd_array
     216              :       TYPE(group_dist_d1_type), DIMENSION(:), &
     217              :          INTENT(INOUT)                                   :: gd_B_virtual
     218              :       TYPE(group_dist_d1_type), INTENT(INOUT)            :: gd_B_all
     219              :       TYPE(group_dist_d1_type), DIMENSION(:), &
     220              :          INTENT(INOUT)                                   :: gd_B_occ_bse, gd_B_virt_bse
     221              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
     222              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_matrix_PQ
     223              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_matrix_L_kpoints, &
     224              :                                                             cfm_matrix_Minv_L_kpoints
     225              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv_L_gamma, fm_matrix_Minv, &
     226              :                                                             fm_matrix_Minv_Vtrunc_Minv
     227              :       TYPE(kpoint_type), POINTER                         :: kpoints
     228              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     229              :          INTENT(INOUT)                                   :: Eigenval
     230              :       INTEGER, INTENT(IN)                                :: nmo
     231              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
     232              :       INTEGER, INTENT(IN)                                :: dimen_RI, dimen_RI_red
     233              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: gw_corr_lev_occ, gw_corr_lev_virt, &
     234              :                                                             bse_lev_virt
     235              :       INTEGER, INTENT(IN)                                :: unit_nr
     236              :       LOGICAL, INTENT(IN)                                :: do_ri_sos_laplace_mp2, my_do_gw, &
     237              :                                                             do_im_time, do_bse
     238              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
     239              :       TYPE(dbcsr_p_type), INTENT(IN)                     :: mat_munu
     240              :       TYPE(dbcsr_p_type), INTENT(INOUT)                  :: mat_P_global
     241              :       TYPE(dbt_type)                                     :: t_3c_M
     242              :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:, :)       :: t_3c_O
     243              :       TYPE(hfx_compression_type), ALLOCATABLE, &
     244              :          DIMENSION(:, :, :), INTENT(INOUT)               :: t_3c_O_compressed
     245              :       TYPE(block_ind_type), ALLOCATABLE, &
     246              :          DIMENSION(:, :, :), INTENT(INOUT)               :: t_3c_O_ind
     247              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(IN)     :: starts_array_mc, ends_array_mc, &
     248              :                                                             starts_array_mc_block, &
     249              :                                                             ends_array_mc_block
     250              :       LOGICAL, INTENT(IN)                                :: calc_forces
     251              : 
     252              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rpa_ri_compute_en'
     253              : 
     254              :       INTEGER :: best_integ_group_size, best_num_integ_point, color_rpa_group, dimen_nm_gw, &
     255              :          dimen_virt_square, handle, handle2, handle3, ierr, iiB, input_num_integ_groups, &
     256              :          integ_group_size, ispin, jjB, min_integ_group_size, my_group_L_end, my_group_L_size, &
     257              :          my_group_L_start, my_nm_gw_end, my_nm_gw_size, my_nm_gw_start, ncol_block_mat, ngroup, &
     258              :          nrow_block_mat, nspins, num_integ_group, num_integ_points, pos_integ_group
     259              :       INTEGER(KIND=int_8)                                :: mem
     260          684 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: dimen_homo_square, dimen_ia, my_ab_comb_bse_end, &
     261          342 :          my_ab_comb_bse_size, my_ab_comb_bse_start, my_ia_end, my_ia_size, my_ia_start, &
     262          342 :          my_ij_comb_bse_end, my_ij_comb_bse_size, my_ij_comb_bse_start, virtual
     263              :       LOGICAL                                            :: do_kpoints_from_Gamma, do_minimax_quad, &
     264              :                                                             my_open_shell, skip_integ_group_opt
     265              :       REAL(KIND=dp) :: allowed_memory, avail_mem, E_Range, Emax, Emin, mem_for_iaK, mem_for_QK, &
     266              :          mem_min, mem_per_group, mem_per_rank, mem_per_repl, mem_real
     267          342 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: Eigenval_kp
     268          684 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: fm_mat_Q, fm_mat_Q_gemm, fm_mat_S, &
     269          342 :                                                             fm_mat_S_ab_bse, fm_mat_S_gw, &
     270          342 :                                                             fm_mat_S_ij_bse
     271          684 :       TYPE(cp_fm_type), DIMENSION(1)                     :: fm_mat_R_gw
     272              :       TYPE(mp_para_env_type), POINTER                    :: para_env_RPA
     273              :       TYPE(two_dim_real_array), ALLOCATABLE, &
     274          342 :          DIMENSION(:)                                    :: BIb_C_2D, BIb_C_2D_bse_ab, &
     275          342 :                                                             BIb_C_2D_bse_ij, BIb_C_2D_gw
     276              : 
     277          342 :       CALL timeset(routineN, handle)
     278              : 
     279          342 :       CALL cite_reference(DelBen2013)
     280          342 :       CALL cite_reference(DelBen2015)
     281              : 
     282          342 :       IF (mp2_env%ri_rpa%exchange_correction == rpa_exchange_axk) THEN
     283           10 :          CALL cite_reference(Bates2013)
     284          332 :       ELSE IF (mp2_env%ri_rpa%exchange_correction == rpa_exchange_sosex) THEN
     285            2 :          CALL cite_reference(Freeman1977)
     286            2 :          CALL cite_reference(Gruneis2009)
     287              :       END IF
     288          342 :       IF (mp2_env%ri_rpa%do_rse) THEN
     289            8 :          CALL cite_reference(Ren2011)
     290            8 :          CALL cite_reference(Ren2013)
     291              :       END IF
     292              : 
     293          342 :       IF (my_do_gw) THEN
     294          134 :          CALL cite_reference(Wilhelm2016a)
     295          134 :          CALL cite_reference(Wilhelm2017)
     296          134 :          CALL cite_reference(Wilhelm2018)
     297              :       END IF
     298              : 
     299          342 :       IF (do_im_time) THEN
     300          144 :          CALL cite_reference(Wilhelm2016b)
     301              :       END IF
     302              : 
     303          342 :       nspins = SIZE(homo)
     304          342 :       my_open_shell = (nspins == 2)
     305         2394 :       ALLOCATE (virtual(nspins), dimen_ia(nspins), my_ia_end(nspins), my_ia_start(nspins), my_ia_size(nspins))
     306          758 :       virtual(:) = nmo - homo(:)
     307          758 :       dimen_ia(:) = virtual(:)*homo(:)
     308              : 
     309         1368 :       ALLOCATE (Eigenval_kp(nmo, 1, nspins))
     310        10988 :       Eigenval_kp(:, 1, :) = Eigenval(:, :)
     311              : 
     312          342 :       IF (do_im_time) mp2_env%ri_rpa%minimax_quad = .TRUE.
     313          342 :       do_minimax_quad = mp2_env%ri_rpa%minimax_quad
     314              : 
     315          342 :       IF (do_ri_sos_laplace_mp2) THEN
     316           64 :          num_integ_points = mp2_env%ri_laplace%n_quadrature
     317           64 :          input_num_integ_groups = mp2_env%ri_laplace%num_integ_groups
     318              : 
     319              :          ! check the range for the minimax approximation
     320           64 :          E_Range = mp2_env%e_range
     321           64 :          IF (mp2_env%e_range <= 1.0_dp .OR. mp2_env%e_gap <= 0.0_dp) THEN
     322              :             Emin = HUGE(dp)
     323              :             Emax = 0.0_dp
     324          104 :             DO ispin = 1, nspins
     325          104 :                IF (homo(ispin) > 0) THEN
     326           60 :                   Emin = MIN(Emin, 2.0_dp*(Eigenval(homo(ispin) + 1, ispin) - Eigenval(homo(ispin), ispin)))
     327         3200 :                   Emax = MAX(Emax, 2.0_dp*(MAXVAL(Eigenval(:, ispin)) - MINVAL(Eigenval(:, ispin))))
     328              :                END IF
     329              :             END DO
     330           44 :             E_Range = Emax/Emin
     331              :          END IF
     332           64 :          IF (E_Range < 2.0_dp) E_Range = 2.0_dp
     333              :          ierr = 0
     334           64 :          CALL check_exp_minimax_range(num_integ_points, E_Range, ierr)
     335           64 :          IF (ierr /= 0) THEN
     336              :             jjB = num_integ_points - 1
     337            0 :             DO iiB = 1, jjB
     338            0 :                num_integ_points = num_integ_points - 1
     339              :                ierr = 0
     340            0 :                CALL check_exp_minimax_range(num_integ_points, E_Range, ierr)
     341            0 :                IF (ierr == 0) EXIT
     342              :             END DO
     343              :          END IF
     344           64 :          CPASSERT(num_integ_points >= 1)
     345              :       ELSE
     346          278 :          num_integ_points = mp2_env%ri_rpa%rpa_num_quad_points
     347          278 :          input_num_integ_groups = mp2_env%ri_rpa%rpa_num_integ_groups
     348          278 :          IF (my_do_gw .AND. do_minimax_quad) THEN
     349           46 :             IF (num_integ_points > 34) THEN
     350            0 :                IF (unit_nr > 0) THEN
     351              :                   CALL cp_warn(__LOCATION__, &
     352              :                                "The required number of quadrature point exceeds the maximum possible in the "// &
     353            0 :                                "Minimax quadrature scheme. The number of quadrature point has been reset to 30.")
     354              :                END IF
     355            0 :                num_integ_points = 30
     356              :             END IF
     357              :          ELSE
     358          232 :             IF (do_minimax_quad .AND. num_integ_points > 20) THEN
     359            0 :                IF (unit_nr > 0) THEN
     360              :                   CALL cp_warn(__LOCATION__, &
     361              :                                "The required number of quadrature point exceeds the maximum possible in the "// &
     362            0 :                                "Minimax quadrature scheme. The number of quadrature point has been reset to 20.")
     363              :                END IF
     364            0 :                num_integ_points = 20
     365              :             END IF
     366              :          END IF
     367              :       END IF
     368          342 :       allowed_memory = mp2_env%mp2_memory
     369              : 
     370          342 :       CALL get_group_dist(gd_array, color_sub, my_group_L_start, my_group_L_end, my_group_L_size)
     371              : 
     372          342 :       ngroup = para_env%num_pe/para_env_sub%num_pe
     373              : 
     374              :       ! for imaginary time or periodic GW or BSE, we use all processors for a single frequency/time point
     375          342 :       IF (do_im_time .OR. mp2_env%ri_g0w0%do_periodic .OR. do_bse) THEN
     376              : 
     377          202 :          integ_group_size = ngroup
     378          202 :          best_num_integ_point = num_integ_points
     379              : 
     380              :       ELSE
     381              : 
     382              :          ! Calculate available memory and create integral group according to that
     383              :          ! mem_for_iaK is the memory needed for storing the 3 centre integrals
     384          310 :          mem_for_iaK = REAL(SUM(dimen_ia), KIND=dp)*dimen_RI_red*8.0_dp/(1024_dp**2)
     385          140 :          mem_for_QK = REAL(dimen_RI_red, KIND=dp)*nspins*dimen_RI_red*8.0_dp/(1024_dp**2)
     386              : 
     387          140 :          CALL m_memory(mem)
     388          140 :          mem_real = (mem + 1024*1024 - 1)/(1024*1024)
     389          140 :          CALL para_env%min(mem_real)
     390              : 
     391          140 :          mem_per_rank = 0.0_dp
     392              : 
     393              :          ! B_ia_P
     394              :          mem_per_repl = mem_for_iaK
     395              :          ! Q (regular and for dgemm)
     396          140 :          mem_per_repl = mem_per_repl + 2.0_dp*mem_for_QK
     397              : 
     398          140 :          IF (calc_forces) CALL rpa_grad_needed_mem(homo, virtual, dimen_RI_red, mem_per_rank, mem_per_repl, do_ri_sos_laplace_mp2)
     399          140 :          CALL rpa_exchange_needed_mem(mp2_env, homo, virtual, dimen_RI_red, para_env, mem_per_rank, mem_per_repl)
     400              : 
     401          140 :          mem_min = mem_per_repl/para_env%num_pe + mem_per_rank
     402              : 
     403          140 :          IF (unit_nr > 0) THEN
     404           70 :             WRITE (unit_nr, '(T3,A,T68,F9.2,A4)') 'RI_INFO| Minimum required memory per MPI process:', mem_min, ' MiB'
     405           70 :             WRITE (unit_nr, '(T3,A,T68,F9.2,A4)') 'RI_INFO| Available memory per MPI process:', mem_real, ' MiB'
     406              :          END IF
     407              : 
     408              :          ! Use only the allowed amount of memory
     409          140 :          mem_real = MIN(mem_real, allowed_memory)
     410              :          ! For the memory estimate, we require the amount of required memory per replication group and the available memory
     411          140 :          mem_real = mem_real - mem_per_rank
     412              : 
     413          140 :          mem_per_group = mem_real*para_env_sub%num_pe
     414              : 
     415              :          ! here we try to find the best rpa/laplace group size
     416          140 :          skip_integ_group_opt = .FALSE.
     417              : 
     418              :          ! Check the input number of integration groups
     419          140 :          IF (input_num_integ_groups > 0) THEN
     420            2 :             IF (num_integ_points < input_num_integ_groups) THEN
     421            0 :                IF (MOD(ngroup, input_num_integ_groups) == 0) THEN
     422            0 :                   best_integ_group_size = ngroup/input_num_integ_groups
     423            0 :                   best_num_integ_point = (num_integ_points + input_num_integ_groups - 1)/input_num_integ_groups
     424              :                   skip_integ_group_opt = .TRUE.
     425              :                ELSE
     426            0 :                   IF (unit_nr > 0) WRITE (unit_nr, '(T3,A)') 'Total number of groups not multiple of NUM_INTEG_GROUPS'
     427              :                END IF
     428              :             ELSE
     429            2 :                IF (unit_nr > 0) WRITE (unit_nr, '(T3,A)') 'Too many integration groups for the given number of quadrature points'
     430              :             END IF
     431              :          END IF
     432              : 
     433              :          IF (.NOT. skip_integ_group_opt) THEN
     434          140 :             best_integ_group_size = ngroup
     435          140 :             best_num_integ_point = num_integ_points
     436              : 
     437          140 :             min_integ_group_size = MAX(1, ngroup/num_integ_points)
     438              : 
     439          140 :             integ_group_size = min_integ_group_size - 1
     440          140 :             DO iiB = min_integ_group_size + 1, ngroup
     441          118 :                integ_group_size = integ_group_size + 1
     442              : 
     443              :                ! check that the ngroup is a multiple of integ_group_size
     444          118 :                IF (MOD(ngroup, integ_group_size) /= 0) CYCLE
     445              : 
     446              :                ! check for memory
     447          118 :                avail_mem = integ_group_size*mem_per_group
     448          118 :                IF (avail_mem < mem_per_repl) CYCLE
     449              : 
     450              :                ! check that the integration groups have the same size
     451          118 :                num_integ_group = ngroup/integ_group_size
     452              : 
     453          118 :                best_num_integ_point = (num_integ_points + num_integ_group - 1)/num_integ_group
     454          118 :                best_integ_group_size = integ_group_size
     455              : 
     456          140 :                EXIT
     457              : 
     458              :             END DO
     459              :          END IF
     460              : 
     461              :          integ_group_size = best_integ_group_size
     462              : 
     463              :       END IF
     464              : 
     465          342 :       IF (unit_nr > 0 .AND. .NOT. do_im_time) THEN
     466           99 :          IF (do_ri_sos_laplace_mp2) THEN
     467              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     468           14 :                "RI_INFO| Group size for laplace numerical integration:", integ_group_size*para_env_sub%num_pe
     469              :             WRITE (UNIT=unit_nr, FMT="(T3,A)") &
     470           14 :                "INTEG_INFO| MINIMAX approximation"
     471              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     472           14 :                "INTEG_INFO| Number of integration points:", num_integ_points
     473              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     474           14 :                "INTEG_INFO| Max. number of integration points per Laplace group:", best_num_integ_point
     475              :          ELSE
     476              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     477           85 :                "RI_INFO| Group size for frequency integration:", integ_group_size*para_env_sub%num_pe
     478           85 :             IF (do_minimax_quad) THEN
     479              :                WRITE (UNIT=unit_nr, FMT="(T3,A)") &
     480           21 :                   "INTEG_INFO| MINIMAX quadrature"
     481              :             ELSE
     482              :                WRITE (UNIT=unit_nr, FMT="(T3,A)") &
     483           64 :                   "INTEG_INFO| Clenshaw-Curtius quadrature"
     484              :             END IF
     485              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     486           85 :                "INTEG_INFO| Number of integration points:", num_integ_points
     487              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     488           85 :                "INTEG_INFO| Max. number of integration points per RPA group:", best_num_integ_point
     489              :          END IF
     490           99 :          CALL m_flush(unit_nr)
     491              :       END IF
     492              : 
     493          342 :       num_integ_group = ngroup/integ_group_size
     494              : 
     495          342 :       pos_integ_group = MOD(color_sub, integ_group_size)
     496          342 :       color_rpa_group = color_sub/integ_group_size
     497              : 
     498          342 :       CALL timeset(routineN//"_reorder", handle2)
     499              : 
     500              :       ! not necessary for imaginary time
     501              : 
     502         1442 :       ALLOCATE (BIb_C_2D(nspins))
     503              : 
     504          342 :       IF (.NOT. do_im_time) THEN
     505              : 
     506              :          ! reorder the local data in such a way to help the next stage of matrix creation
     507              :          ! now the data inside the group are divided into a ia x K matrix
     508          438 :          DO ispin = 1, nspins
     509              :             CALL calculate_BIb_C_2D(BIb_C_2D(ispin)%array, BIb_C(ispin)%array, para_env_sub, dimen_ia(ispin), &
     510              :                                     homo(ispin), virtual(ispin), gd_B_virtual(ispin), &
     511          240 :                                     my_ia_size(ispin), my_ia_start(ispin), my_ia_end(ispin), my_group_L_size)
     512              : 
     513          240 :             DEALLOCATE (BIb_C(ispin)%array)
     514          438 :             CALL release_group_dist(gd_B_virtual(ispin))
     515              : 
     516              :          END DO
     517              : 
     518              :          ! in the GW case, BIb_C_2D_gw is an nm x K matrix, with n: number of corr GW levels, m=nmo
     519          198 :          IF (my_do_gw) THEN
     520          280 :             ALLOCATE (BIb_C_2D_gw(nspins))
     521              : 
     522           88 :             CALL timeset(routineN//"_reorder_gw", handle3)
     523              : 
     524           88 :             dimen_nm_gw = nmo*(gw_corr_lev_occ(1) + gw_corr_lev_virt(1))
     525              : 
     526              :             ! The same for open shell
     527          192 :             DO ispin = 1, nspins
     528              :                CALL calculate_BIb_C_2D(BIb_C_2D_gw(ispin)%array, BIb_C_gw(ispin)%array, para_env_sub, dimen_nm_gw, &
     529              :                                        gw_corr_lev_occ(ispin) + gw_corr_lev_virt(ispin), nmo, gd_B_all, &
     530          104 :                                        my_nm_gw_size, my_nm_gw_start, my_nm_gw_end, my_group_L_size)
     531          192 :                DEALLOCATE (BIb_C_gw(ispin)%array)
     532              :             END DO
     533              : 
     534           88 :             CALL release_group_dist(gd_B_all)
     535              : 
     536          176 :             CALL timestop(handle3)
     537              : 
     538              :          END IF
     539              :       END IF
     540              : 
     541          342 :       IF (do_bse) THEN
     542              : 
     543           56 :          CALL timeset(routineN//"_reorder_bse1", handle3)
     544              : 
     545          304 :          ALLOCATE (BIb_C_2D_bse_ij(nspins), BIb_C_2D_bse_ab(nspins))
     546          112 :          ALLOCATE (dimen_homo_square(nspins))
     547          224 :          ALLOCATE (my_ij_comb_bse_size(nspins), my_ij_comb_bse_start(nspins), my_ij_comb_bse_end(nspins))
     548          224 :          ALLOCATE (my_ab_comb_bse_size(nspins), my_ab_comb_bse_start(nspins), my_ab_comb_bse_end(nspins))
     549              : 
     550              :          ! We do not implement an explicit bse_lev_occ different to homo here, because the small number of occupied levels
     551              :          ! does not critically influence the memory
     552          124 :          DO ispin = 1, nspins
     553           68 :             dimen_homo_square(ispin) = homo(ispin)**2
     554              :             CALL calculate_BIb_C_2D(BIb_C_2D_bse_ij(ispin)%array, BIb_C_bse_ij(ispin)%array, para_env_sub, &
     555              :                                     dimen_homo_square(ispin), homo(ispin), homo(ispin), gd_B_occ_bse(ispin), &
     556              :                                     my_ij_comb_bse_size(ispin), my_ij_comb_bse_start(ispin), &
     557           68 :                                     my_ij_comb_bse_end(ispin), my_group_L_size)
     558           68 :             DEALLOCATE (BIb_C_bse_ij(ispin)%array)
     559          124 :             CALL release_group_dist(gd_B_occ_bse(ispin))
     560              :          END DO
     561              : 
     562           56 :          CALL timestop(handle3)
     563              : 
     564           56 :          CALL timeset(routineN//"_reorder_bse2", handle3)
     565              : 
     566              :          ! bse_lev_virt(ispin) (hence dimen_virt_square) and gd_B_virt_bse(ispin) are per-spin
     567          124 :          DO ispin = 1, nspins
     568           68 :             dimen_virt_square = bse_lev_virt(ispin)**2
     569              :             CALL calculate_BIb_C_2D(BIb_C_2D_bse_ab(ispin)%array, BIb_C_bse_ab(ispin)%array, para_env_sub, &
     570              :                                     dimen_virt_square, bse_lev_virt(ispin), bse_lev_virt(ispin), gd_B_virt_bse(ispin), &
     571              :                                     my_ab_comb_bse_size(ispin), my_ab_comb_bse_start(ispin), &
     572           68 :                                     my_ab_comb_bse_end(ispin), my_group_L_size)
     573           68 :             DEALLOCATE (BIb_C_bse_ab(ispin)%array)
     574          124 :             CALL release_group_dist(gd_B_virt_bse(ispin))
     575              :          END DO
     576              : 
     577          168 :          CALL timestop(handle3)
     578              : 
     579              :       END IF
     580              : 
     581          342 :       CALL timestop(handle2)
     582              : 
     583          342 :       IF (num_integ_group > 1) THEN
     584          118 :          ALLOCATE (para_env_RPA)
     585          118 :          CALL para_env_RPA%from_split(para_env, color_rpa_group)
     586              :       ELSE
     587          224 :          para_env_RPA => para_env
     588              :       END IF
     589              : 
     590              :       ! now create the matrices needed for the calculation, Q, S and G
     591              :       ! Q and G will have omega dependence
     592              : 
     593          342 :       IF (do_im_time) THEN
     594          896 :          ALLOCATE (fm_mat_Q(nspins), fm_mat_Q_gemm(1), fm_mat_S(1))
     595              :       ELSE
     596         1710 :          ALLOCATE (fm_mat_Q(nspins), fm_mat_Q_gemm(nspins), fm_mat_S(nspins))
     597              :       END IF
     598              : 
     599              :       CALL create_integ_mat(BIb_C_2D, para_env, dimen_RI_red, dimen_ia, mp2_env%block_size_row, &
     600              :                             mp2_env%block_size_col, unit_nr, my_ia_start, my_ia_end, my_group_L_start, &
     601              :                             my_group_L_end, para_env_RPA, fm_mat_S, nrow_block_mat, ncol_block_mat, &
     602              :                             dimen_ia_for_block_size=dimen_ia(1), do_im_time=do_im_time, &
     603          342 :                             fm_mat_Q_gemm=fm_mat_Q_gemm, fm_mat_Q=fm_mat_Q, qs_env=qs_env)
     604              : 
     605          758 :       DEALLOCATE (BIb_C_2D, my_ia_end, my_ia_size, my_ia_start)
     606              : 
     607              :       ! for GW, we need other matrix fm_mat_S, always allocate the container to prevent crying compilers
     608         1442 :       ALLOCATE (fm_mat_S_gw(nspins))
     609          342 :       IF (my_do_gw .AND. .NOT. do_im_time) THEN
     610              : 
     611              :          CALL create_integ_mat(BIb_C_2D_gw, para_env, dimen_RI_red, [dimen_nm_gw, dimen_nm_gw], &
     612              :                                mp2_env%block_size_row, mp2_env%block_size_col, unit_nr, &
     613              :                                [my_nm_gw_start, my_nm_gw_start], [my_nm_gw_end, my_nm_gw_end], &
     614              :                                my_group_L_start, my_group_L_end, para_env_RPA, fm_mat_S_gw, nrow_block_mat, &
     615              :                                ncol_block_mat, fm_mat_Q(1)%matrix_struct%context, &
     616          616 :                                fm_mat_Q(1)%matrix_struct%context, fm_mat_Q=fm_mat_R_gw)
     617          192 :          DEALLOCATE (BIb_C_2D_gw)
     618              : 
     619              :       END IF
     620              : 
     621              :       ! for Bethe-Salpeter, we need other matrix fm_mat_S (per spin; the ab slab dimension is spin-independent)
     622          342 :       IF (do_bse) THEN
     623          304 :          ALLOCATE (fm_mat_S_ij_bse(nspins), fm_mat_S_ab_bse(nspins))
     624              :          CALL create_integ_mat(BIb_C_2D_bse_ij, para_env, dimen_RI_red, dimen_homo_square, &
     625              :                                mp2_env%block_size_row, mp2_env%block_size_col, unit_nr, my_ij_comb_bse_start, &
     626              :                                my_ij_comb_bse_end, my_group_L_start, my_group_L_end, para_env_RPA, &
     627              :                                fm_mat_S_ij_bse, nrow_block_mat, ncol_block_mat, &
     628           56 :                                fm_mat_Q(1)%matrix_struct%context, fm_mat_Q(1)%matrix_struct%context)
     629              : 
     630              :          CALL create_integ_mat(BIb_C_2D_bse_ab, para_env, dimen_RI_red, &
     631              :                                [(bse_lev_virt(ispin)**2, ispin=1, nspins)], mp2_env%block_size_row, &
     632              :                                mp2_env%block_size_col, unit_nr, my_ab_comb_bse_start, my_ab_comb_bse_end, &
     633              :                                my_group_L_start, my_group_L_end, para_env_RPA, fm_mat_S_ab_bse, &
     634              :                                nrow_block_mat, ncol_block_mat, fm_mat_Q(1)%matrix_struct%context, &
     635          248 :                                fm_mat_Q(1)%matrix_struct%context)
     636              : 
     637              :       END IF
     638              : 
     639          342 :       do_kpoints_from_Gamma = qs_env%mp2_env%ri_rpa_im_time%do_kpoints_from_Gamma
     640          342 :       IF (do_kpoints_from_Gamma) THEN
     641           16 :          CALL get_bandstruc_and_k_dependent_MOs(qs_env, Eigenval_kp)
     642              :       END IF
     643              : 
     644              :       ! Now start the RPA calculation
     645              :       ! cfm_mo_coeff will be deallocated here
     646              :       CALL rpa_num_int(qs_env, Erpa, mp2_env, para_env, para_env_RPA, para_env_sub, unit_nr, &
     647              :                        homo, virtual, dimen_RI, dimen_RI_red, dimen_ia, dimen_nm_gw, &
     648              :                        Eigenval_kp, num_integ_points, num_integ_group, color_rpa_group, &
     649              :                        fm_matrix_PQ, fm_mat_S, fm_mat_Q_gemm, fm_mat_Q, fm_mat_S_gw, fm_mat_R_gw(1), &
     650              :                        fm_mat_S_ij_bse, fm_mat_S_ab_bse, &
     651              :                        my_do_gw, do_bse, gw_corr_lev_occ, gw_corr_lev_virt, &
     652              :                        bse_lev_virt, &
     653              :                        do_minimax_quad, &
     654              :                        do_im_time, mo_coeff, &
     655              :                        cfm_matrix_L_kpoints, cfm_matrix_Minv_L_kpoints, &
     656              :                        fm_matrix_Minv_L_gamma, &
     657              :                        fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv, mat_munu, mat_P_global, &
     658              :                        t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, &
     659              :                        starts_array_mc, ends_array_mc, &
     660              :                        starts_array_mc_block, ends_array_mc_block, &
     661              :                        matrix_s, do_kpoints_from_Gamma, kpoints, gd_array, color_sub, &
     662          342 :                        do_ri_sos_laplace_mp2=do_ri_sos_laplace_mp2, calc_forces=calc_forces)
     663              : 
     664          342 :       CALL release_group_dist(gd_array)
     665              : 
     666          342 :       IF (num_integ_group > 1) CALL mp_para_env_release(para_env_RPA)
     667              : 
     668          342 :       IF (.NOT. do_im_time) THEN
     669          198 :          CALL cp_fm_release(fm_mat_Q_gemm)
     670          198 :          CALL cp_fm_release(fm_mat_S)
     671              :       END IF
     672          342 :       CALL cp_fm_release(fm_mat_Q)
     673              : 
     674          342 :       IF (my_do_gw .AND. .NOT. do_im_time) THEN
     675           88 :          CALL cp_fm_release(fm_mat_S_gw)
     676           88 :          CALL cp_fm_release(fm_mat_R_gw(1))
     677              :       END IF
     678              : 
     679          342 :       IF (do_bse) THEN
     680          124 :          DO ispin = 1, nspins
     681           68 :             CALL cp_fm_release(fm_mat_S_ij_bse(ispin))
     682          124 :             CALL cp_fm_release(fm_mat_S_ab_bse(ispin))
     683              :          END DO
     684           56 :          DEALLOCATE (fm_mat_S_ij_bse, fm_mat_S_ab_bse)
     685              :       END IF
     686              : 
     687          342 :       CALL timestop(handle)
     688              : 
     689         1504 :    END SUBROUTINE rpa_ri_compute_en
     690              : 
     691              : ! **************************************************************************************************
     692              : !> \brief reorder the local data in such a way to help the next stage of matrix creation;
     693              : !>        now the data inside the group are divided into a ia x K matrix (BIb_C_2D);
     694              : !>        Subroutine created to avoid massive double coding
     695              : !> \param BIb_C_2D ...
     696              : !> \param BIb_C ...
     697              : !> \param para_env_sub ...
     698              : !> \param dimen_ia ...
     699              : !> \param homo ...
     700              : !> \param virtual ...
     701              : !> \param gd_B_virtual ...
     702              : !> \param my_ia_size ...
     703              : !> \param my_ia_start ...
     704              : !> \param my_ia_end ...
     705              : !> \param my_group_L_size ...
     706              : !> \author Jan Wilhelm, 03/2015
     707              : ! **************************************************************************************************
     708          480 :    SUBROUTINE calculate_BIb_C_2D(BIb_C_2D, BIb_C, para_env_sub, dimen_ia, homo, virtual, &
     709              :                                  gd_B_virtual, &
     710              :                                  my_ia_size, my_ia_start, my_ia_end, my_group_L_size)
     711              : 
     712              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     713              :          INTENT(OUT)                                     :: BIb_C_2D
     714              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     715              :          INTENT(IN)                                      :: BIb_C
     716              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env_sub
     717              :       INTEGER, INTENT(IN)                                :: dimen_ia, homo, virtual
     718              :       TYPE(group_dist_d1_type), INTENT(INOUT)            :: gd_B_virtual
     719              :       INTEGER                                            :: my_ia_size, my_ia_start, my_ia_end, &
     720              :                                                             my_group_L_size
     721              : 
     722              :       INTEGER, PARAMETER                                 :: occ_chunk = 128
     723              : 
     724              :       INTEGER :: ia_global, iiB, itmp(2), jjB, my_B_size, my_B_virtual_start, occ_high, occ_low, &
     725              :          proc_receive, proc_send, proc_shift, rec_B_size, rec_B_virtual_end, rec_B_virtual_start
     726          480 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), TARGET   :: BIb_C_rec_1D
     727          480 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: BIb_C_rec
     728              : 
     729          480 :       itmp = get_limit(dimen_ia, para_env_sub%num_pe, para_env_sub%mepos)
     730          480 :       my_ia_start = itmp(1)
     731          480 :       my_ia_end = itmp(2)
     732          480 :       my_ia_size = my_ia_end - my_ia_start + 1
     733              : 
     734          480 :       CALL get_group_dist(gd_B_virtual, para_env_sub%mepos, sizes=my_B_size, starts=my_B_virtual_start)
     735              : 
     736              :       ! reorder data
     737         1914 :       ALLOCATE (BIb_C_2D(my_group_L_size, my_ia_size))
     738              : 
     739              : !$OMP     PARALLEL DO DEFAULT(NONE) PRIVATE(jjB,ia_global) &
     740              : !$OMP              SHARED(homo,my_B_size,virtual,my_B_virtual_start,my_ia_start,my_ia_end,BIb_C,BIb_C_2D,&
     741          480 : !$OMP              my_group_L_size)
     742              :       DO iiB = 1, homo
     743              :          DO jjB = 1, my_B_size
     744              :             ia_global = (iiB - 1)*virtual + my_B_virtual_start + jjB - 1
     745              :             IF (ia_global >= my_ia_start .AND. ia_global <= my_ia_end) THEN
     746              :                BIb_C_2D(1:my_group_L_size, ia_global - my_ia_start + 1) = BIb_C(1:my_group_L_size, jjB, iiB)
     747              :             END IF
     748              :          END DO
     749              :       END DO
     750              : 
     751          480 :       IF (para_env_sub%num_pe > 1) THEN
     752           30 :          ALLOCATE (BIb_C_rec_1D(INT(my_group_L_size, int_8)*maxsize(gd_B_virtual)*MIN(homo, occ_chunk)))
     753           20 :          DO proc_shift = 1, para_env_sub%num_pe - 1
     754           10 :             proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
     755           10 :             proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
     756              : 
     757           10 :             CALL get_group_dist(gd_B_virtual, proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
     758              : 
     759              :             ! do this in chunks to avoid high memory overhead
     760           20 :             DO occ_low = 1, homo, occ_chunk
     761           10 :                occ_high = MIN(homo, occ_low + occ_chunk - 1)
     762              :                BIb_C_rec(1:my_group_L_size, 1:rec_B_size, 1:occ_high - occ_low + 1) => &
     763           10 :                   BIb_C_rec_1D(1:INT(my_group_L_size, int_8)*rec_B_size*(occ_high - occ_low + 1))
     764              :                CALL para_env_sub%sendrecv(BIb_C(:, :, occ_low:occ_high), proc_send, &
     765        31970 :                                           BIb_C_rec(:, :, 1:occ_high - occ_low + 1), proc_receive)
     766              : !$OMP          PARALLEL DO DEFAULT(NONE) PRIVATE(jjB,ia_global) &
     767              : !$OMP                   SHARED(occ_low,occ_high,rec_B_size,virtual,rec_B_virtual_start,my_ia_start,my_ia_end,BIb_C_rec,BIb_C_2D,&
     768           10 : !$OMP                          my_group_L_size)
     769              :                DO iiB = occ_low, occ_high
     770              :                   DO jjB = 1, rec_B_size
     771              :                      ia_global = (iiB - 1)*virtual + rec_B_virtual_start + jjB - 1
     772              :                      IF (ia_global >= my_ia_start .AND. ia_global <= my_ia_end) THEN
     773              :                      BIb_C_2D(1:my_group_L_size, ia_global - my_ia_start + 1) = BIb_C_rec(1:my_group_L_size, jjB, iiB - occ_low + 1)
     774              :                      END IF
     775              :                   END DO
     776              :                END DO
     777              :             END DO
     778              : 
     779              :          END DO
     780           10 :          DEALLOCATE (BIb_C_rec_1D)
     781              :       END IF
     782              : 
     783          480 :    END SUBROUTINE calculate_BIb_C_2D
     784              : 
     785              : ! **************************************************************************************************
     786              : !> \brief ...
     787              : !> \param BIb_C_2D ...
     788              : !> \param para_env ...
     789              : !> \param dimen_RI ...
     790              : !> \param dimen_ia ...
     791              : !> \param ext_row_block_size ...
     792              : !> \param ext_col_block_size ...
     793              : !> \param unit_nr ...
     794              : !> \param my_ia_start ...
     795              : !> \param my_ia_end ...
     796              : !> \param my_group_L_start ...
     797              : !> \param my_group_L_end ...
     798              : !> \param para_env_RPA ...
     799              : !> \param fm_mat_S ...
     800              : !> \param nrow_block_mat ...
     801              : !> \param ncol_block_mat ...
     802              : !> \param blacs_env_ext ...
     803              : !> \param blacs_env_ext_S ...
     804              : !> \param dimen_ia_for_block_size ...
     805              : !> \param do_im_time ...
     806              : !> \param fm_mat_Q_gemm ...
     807              : !> \param fm_mat_Q ...
     808              : !> \param qs_env ...
     809              : ! **************************************************************************************************
     810          542 :    SUBROUTINE create_integ_mat(BIb_C_2D, para_env, dimen_RI, dimen_ia, ext_row_block_size, ext_col_block_size, &
     811          542 :                                unit_nr, my_ia_start, my_ia_end, my_group_L_start, my_group_L_end, para_env_RPA, &
     812          542 :                                fm_mat_S, nrow_block_mat, ncol_block_mat, blacs_env_ext, blacs_env_ext_S, &
     813          542 :                                dimen_ia_for_block_size, do_im_time, fm_mat_Q_gemm, fm_mat_Q, qs_env)
     814              : 
     815              :       TYPE(two_dim_real_array), DIMENSION(:), &
     816              :          INTENT(INOUT)                                   :: BIb_C_2D
     817              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
     818              :       INTEGER, INTENT(IN)                                :: dimen_RI
     819              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: dimen_ia
     820              :       INTEGER, INTENT(IN)                                :: ext_row_block_size, ext_col_block_size, &
     821              :                                                             unit_nr
     822              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: my_ia_start, my_ia_end
     823              :       INTEGER, INTENT(IN)                                :: my_group_L_start, my_group_L_end
     824              :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env_RPA
     825              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: fm_mat_S
     826              :       INTEGER, INTENT(INOUT)                             :: nrow_block_mat, ncol_block_mat
     827              :       TYPE(cp_blacs_env_type), OPTIONAL, POINTER         :: blacs_env_ext, blacs_env_ext_S
     828              :       INTEGER, INTENT(IN), OPTIONAL                      :: dimen_ia_for_block_size
     829              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_im_time
     830              :       TYPE(cp_fm_type), DIMENSION(:), OPTIONAL           :: fm_mat_Q_gemm, fm_mat_Q
     831              :       TYPE(qs_environment_type), INTENT(IN), OPTIONAL, &
     832              :          POINTER                                         :: qs_env
     833              : 
     834              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'create_integ_mat'
     835              : 
     836              :       INTEGER                                            :: col_row_proc_ratio, grid_2D(2), handle, &
     837              :                                                             iproc, iproc_col, iproc_row, ispin
     838              :       LOGICAL                                            :: my_blacs_ext, my_blacs_S_ext, &
     839              :                                                             my_do_im_time
     840              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env, blacs_env_Q
     841              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     842              : 
     843          542 :       CALL timeset(routineN, handle)
     844              : 
     845          542 :       CPASSERT(PRESENT(blacs_env_ext) .OR. PRESENT(dimen_ia_for_block_size))
     846              : 
     847          542 :       my_blacs_ext = .FALSE.
     848          542 :       IF (PRESENT(blacs_env_ext)) my_blacs_ext = .TRUE.
     849              : 
     850          542 :       my_blacs_S_ext = .FALSE.
     851          542 :       IF (PRESENT(blacs_env_ext_S)) my_blacs_S_ext = .TRUE.
     852              : 
     853          542 :       my_do_im_time = .FALSE.
     854          542 :       IF (PRESENT(do_im_time)) my_do_im_time = do_im_time
     855              : 
     856          542 :       NULLIFY (blacs_env)
     857              :       ! create the RPA blacs env
     858          542 :       IF (my_blacs_S_ext) THEN
     859          200 :          blacs_env => blacs_env_ext_S
     860              :       ELSE
     861          342 :          IF (para_env_RPA%num_pe > 1) THEN
     862          224 :             col_row_proc_ratio = MAX(1, dimen_ia_for_block_size/dimen_RI)
     863              : 
     864          224 :             iproc_col = MIN(MAX(INT(SQRT(REAL(para_env_RPA%num_pe*col_row_proc_ratio, KIND=dp))), 1), para_env_RPA%num_pe) + 1
     865          224 :             DO iproc = 1, para_env_RPA%num_pe
     866          224 :                iproc_col = iproc_col - 1
     867          224 :                IF (MOD(para_env_RPA%num_pe, iproc_col) == 0) EXIT
     868              :             END DO
     869              : 
     870          224 :             iproc_row = para_env_RPA%num_pe/iproc_col
     871          224 :             grid_2D(1) = iproc_row
     872          224 :             grid_2D(2) = iproc_col
     873              :          ELSE
     874          354 :             grid_2D = 1
     875              :          END IF
     876          342 :          CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=para_env_RPA, grid_2d=grid_2D)
     877              : 
     878          342 :          IF (unit_nr > 0 .AND. .NOT. my_do_im_time) THEN
     879              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     880           99 :                "MATRIX_INFO| Number row processes:", grid_2D(1)
     881              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     882           99 :                "MATRIX_INFO| Number column processes:", grid_2D(2)
     883              :          END IF
     884              : 
     885              :          ! define the block_size for the row
     886          342 :          IF (ext_row_block_size > 0) THEN
     887            0 :             nrow_block_mat = ext_row_block_size
     888              :          ELSE
     889          342 :             nrow_block_mat = MAX(1, dimen_RI/grid_2D(1)/2)
     890              :          END IF
     891              : 
     892              :          ! define the block_size for the column
     893          342 :          IF (ext_col_block_size > 0) THEN
     894            0 :             ncol_block_mat = ext_col_block_size
     895              :          ELSE
     896          342 :             ncol_block_mat = MAX(1, dimen_ia_for_block_size/grid_2D(2)/2)
     897              :          END IF
     898              : 
     899          342 :          IF (unit_nr > 0 .AND. .NOT. my_do_im_time) THEN
     900              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     901           99 :                "MATRIX_INFO| Row block size:", nrow_block_mat
     902              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     903           99 :                "MATRIX_INFO| Column block size:", ncol_block_mat
     904              :          END IF
     905              :       END IF
     906              : 
     907          470 :       IF (.NOT. my_do_im_time) THEN
     908          878 :          DO ispin = 1, SIZE(BIb_C_2D)
     909          480 :             NULLIFY (fm_struct)
     910          480 :             IF (my_blacs_ext) THEN
     911              :                CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=dimen_RI, &
     912          240 :                                         ncol_global=dimen_ia(ispin), para_env=para_env_RPA)
     913              :             ELSE
     914              :                CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=dimen_RI, &
     915              :                                         ncol_global=dimen_ia(ispin), para_env=para_env_RPA, &
     916          240 :                                         nrow_block=nrow_block_mat, ncol_block=ncol_block_mat, force_block=.TRUE.)
     917              : 
     918              :             END IF ! external blacs_env
     919              : 
     920              :             CALL cp_array_to_fm(BIb_C_2D(ispin)%array, fm_struct, my_group_L_start, my_group_L_end, &
     921          480 :                                 my_ia_start(ispin), my_ia_end(ispin), fm_mat_S(ispin))
     922              : 
     923          480 :             CALL cp_fm_struct_release(fm_struct)
     924              : 
     925              :             ! sum the local data across processes belonging to different RPA group.
     926          878 :             IF (para_env_RPA%num_pe /= para_env%num_pe) THEN
     927              :                BLOCK
     928              :                   TYPE(mp_comm_type) :: comm_exchange
     929          180 :                   comm_exchange = fm_mat_S(ispin)%matrix_struct%context%interconnect(para_env)
     930          180 :                   CALL comm_exchange%sum(fm_mat_S(ispin)%local_data)
     931          360 :                   CALL comm_exchange%free()
     932              :                END BLOCK
     933              :             END IF
     934              :          END DO
     935              :       END IF
     936              : 
     937          542 :       IF (PRESENT(fm_mat_Q_gemm) .AND. .NOT. my_do_im_time) THEN
     938              :          ! create the Q matrix dimen_RIxdimen_RI where the result of the mat-mat-mult will be stored
     939          198 :          NULLIFY (fm_struct)
     940              :          CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=dimen_RI, &
     941              :                                   ncol_global=dimen_RI, para_env=para_env_RPA, &
     942          198 :                                   nrow_block=nrow_block_mat, ncol_block=ncol_block_mat, force_block=.TRUE.)
     943          438 :          DO ispin = 1, SIZE(fm_mat_Q_gemm)
     944          438 :             CALL cp_fm_create(fm_mat_Q_gemm(ispin), fm_struct, name="fm_mat_Q_gemm")
     945              :          END DO
     946          198 :          CALL cp_fm_struct_release(fm_struct)
     947              :       END IF
     948              : 
     949          542 :       IF (PRESENT(fm_mat_Q)) THEN
     950          430 :          NULLIFY (blacs_env_Q)
     951          430 :          IF (my_blacs_ext) THEN
     952           88 :             blacs_env_Q => blacs_env_ext
     953          342 :          ELSE IF (para_env_RPA%num_pe == para_env%num_pe .AND. PRESENT(qs_env)) THEN
     954          224 :             CALL get_qs_env(qs_env, blacs_env=blacs_env_Q)
     955              :          ELSE
     956          118 :             CALL cp_blacs_env_create(blacs_env=blacs_env_Q, para_env=para_env_RPA)
     957              :          END IF
     958          430 :          NULLIFY (fm_struct)
     959              :          CALL cp_fm_struct_create(fm_struct, context=blacs_env_Q, nrow_global=dimen_RI, &
     960          430 :                                   ncol_global=dimen_RI, para_env=para_env_RPA)
     961          934 :          DO ispin = 1, SIZE(fm_mat_Q)
     962          934 :             CALL cp_fm_create(fm_mat_Q(ispin), fm_struct, name="fm_mat_Q", set_zero=.TRUE.)
     963              :          END DO
     964              : 
     965          430 :          CALL cp_fm_struct_release(fm_struct)
     966              : 
     967          430 :          IF (.NOT. (my_blacs_ext .OR. (para_env_RPA%num_pe == para_env%num_pe .AND. PRESENT(qs_env)))) THEN
     968          118 :             CALL cp_blacs_env_release(blacs_env_Q)
     969              :          END IF
     970              :       END IF
     971              : 
     972              :       ! release blacs_env
     973          542 :       IF (.NOT. my_blacs_S_ext) THEN
     974          342 :          CALL cp_blacs_env_release(blacs_env)
     975              :       ELSE
     976          200 :          NULLIFY (blacs_env)
     977              :       END IF
     978              : 
     979          542 :       CALL timestop(handle)
     980              : 
     981          542 :    END SUBROUTINE create_integ_mat
     982              : 
     983              : ! **************************************************************************************************
     984              : !> \brief ...
     985              : !> \param qs_env ...
     986              : !> \param Erpa ...
     987              : !> \param mp2_env ...
     988              : !> \param para_env ...
     989              : !> \param para_env_RPA ...
     990              : !> \param para_env_sub ...
     991              : !> \param unit_nr ...
     992              : !> \param homo ...
     993              : !> \param virtual ...
     994              : !> \param dimen_RI ...
     995              : !> \param dimen_RI_red ...
     996              : !> \param dimen_ia ...
     997              : !> \param dimen_nm_gw ...
     998              : !> \param Eigenval ...
     999              : !> \param num_integ_points ...
    1000              : !> \param num_integ_group ...
    1001              : !> \param color_rpa_group ...
    1002              : !> \param fm_matrix_PQ ...
    1003              : !> \param fm_mat_S ...
    1004              : !> \param fm_mat_Q_gemm ...
    1005              : !> \param fm_mat_Q ...
    1006              : !> \param fm_mat_S_gw ...
    1007              : !> \param fm_mat_R_gw ...
    1008              : !> \param fm_mat_S_ij_bse ...
    1009              : !> \param fm_mat_S_ab_bse ...
    1010              : !> \param my_do_gw ...
    1011              : !> \param do_bse ...
    1012              : !> \param gw_corr_lev_occ ...
    1013              : !> \param gw_corr_lev_virt ...
    1014              : !> \param bse_lev_virt ...
    1015              : !> \param do_minimax_quad ...
    1016              : !> \param do_im_time ...
    1017              : !> \param mo_coeff ...
    1018              : !> \param cfm_matrix_L_kpoints ...
    1019              : !> \param cfm_matrix_Minv_L_kpoints ...
    1020              : !> \param fm_matrix_Minv_L_gamma ...
    1021              : !> \param fm_matrix_Minv ...
    1022              : !> \param fm_matrix_Minv_Vtrunc_Minv ...
    1023              : !> \param mat_munu ...
    1024              : !> \param mat_P_global ...
    1025              : !> \param t_3c_M ...
    1026              : !> \param t_3c_O ...
    1027              : !> \param t_3c_O_compressed ...
    1028              : !> \param t_3c_O_ind ...
    1029              : !> \param starts_array_mc ...
    1030              : !> \param ends_array_mc ...
    1031              : !> \param starts_array_mc_block ...
    1032              : !> \param ends_array_mc_block ...
    1033              : !> \param matrix_s ...
    1034              : !> \param do_kpoints_from_Gamma ...
    1035              : !> \param kpoints ...
    1036              : !> \param gd_array ...
    1037              : !> \param color_sub ...
    1038              : !> \param do_ri_sos_laplace_mp2 ...
    1039              : !> \param calc_forces ...
    1040              : ! **************************************************************************************************
    1041          342 :    SUBROUTINE rpa_num_int(qs_env, Erpa, mp2_env, para_env, para_env_RPA, para_env_sub, unit_nr, &
    1042          342 :                           homo, virtual, dimen_RI, dimen_RI_red, dimen_ia, dimen_nm_gw, &
    1043              :                           Eigenval, num_integ_points, num_integ_group, color_rpa_group, &
    1044          684 :                           fm_matrix_PQ, fm_mat_S, fm_mat_Q_gemm, fm_mat_Q, fm_mat_S_gw, fm_mat_R_gw, &
    1045          342 :                           fm_mat_S_ij_bse, fm_mat_S_ab_bse, &
    1046          342 :                           my_do_gw, do_bse, gw_corr_lev_occ, gw_corr_lev_virt, &
    1047          342 :                           bse_lev_virt, &
    1048          342 :                           do_minimax_quad, do_im_time, mo_coeff, &
    1049              :                           cfm_matrix_L_kpoints, cfm_matrix_Minv_L_kpoints, &
    1050              :                           fm_matrix_Minv_L_gamma, &
    1051              :                           fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv, mat_munu, mat_P_global, &
    1052              :                           t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, &
    1053              :                           starts_array_mc, ends_array_mc, &
    1054              :                           starts_array_mc_block, ends_array_mc_block, &
    1055              :                           matrix_s, do_kpoints_from_Gamma, kpoints, gd_array, color_sub, &
    1056              :                           do_ri_sos_laplace_mp2, calc_forces)
    1057              : 
    1058              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1059              :       REAL(KIND=dp), INTENT(OUT)                         :: Erpa
    1060              :       TYPE(mp2_type)                                     :: mp2_env
    1061              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_RPA, para_env_sub
    1062              :       INTEGER, INTENT(IN)                                :: unit_nr
    1063              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
    1064              :       INTEGER, INTENT(IN)                                :: dimen_RI, dimen_RI_red
    1065              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: dimen_ia
    1066              :       INTEGER, INTENT(IN)                                :: dimen_nm_gw
    1067              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
    1068              :          INTENT(INOUT)                                   :: Eigenval
    1069              :       INTEGER, INTENT(IN)                                :: num_integ_points, num_integ_group, &
    1070              :                                                             color_rpa_group
    1071              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_matrix_PQ
    1072              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: fm_mat_S
    1073              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_Q_gemm
    1074              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: fm_mat_Q
    1075              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S_gw
    1076              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_R_gw
    1077              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S_ij_bse, fm_mat_S_ab_bse
    1078              :       LOGICAL, INTENT(IN)                                :: my_do_gw, do_bse
    1079              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: gw_corr_lev_occ, gw_corr_lev_virt, &
    1080              :                                                             bse_lev_virt
    1081              :       LOGICAL, INTENT(IN)                                :: do_minimax_quad, do_im_time
    1082              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: mo_coeff
    1083              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_matrix_L_kpoints, &
    1084              :                                                             cfm_matrix_Minv_L_kpoints
    1085              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv_L_gamma, fm_matrix_Minv, &
    1086              :                                                             fm_matrix_Minv_Vtrunc_Minv
    1087              :       TYPE(dbcsr_p_type), INTENT(IN)                     :: mat_munu
    1088              :       TYPE(dbcsr_p_type), INTENT(INOUT)                  :: mat_P_global
    1089              :       TYPE(dbt_type), INTENT(INOUT)                      :: t_3c_M
    1090              :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:, :), &
    1091              :          INTENT(INOUT)                                   :: t_3c_O
    1092              :       TYPE(hfx_compression_type), ALLOCATABLE, &
    1093              :          DIMENSION(:, :, :), INTENT(INOUT)               :: t_3c_O_compressed
    1094              :       TYPE(block_ind_type), ALLOCATABLE, &
    1095              :          DIMENSION(:, :, :), INTENT(INOUT)               :: t_3c_O_ind
    1096              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(IN)     :: starts_array_mc, ends_array_mc, &
    1097              :                                                             starts_array_mc_block, &
    1098              :                                                             ends_array_mc_block
    1099              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s
    1100              :       LOGICAL                                            :: do_kpoints_from_Gamma
    1101              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1102              :       TYPE(group_dist_d1_type), INTENT(IN)               :: gd_array
    1103              :       INTEGER, INTENT(IN)                                :: color_sub
    1104              :       LOGICAL, INTENT(IN)                                :: do_ri_sos_laplace_mp2, calc_forces
    1105              : 
    1106              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rpa_num_int'
    1107              : 
    1108              :       COMPLEX(KIND=dp), ALLOCATABLE, &
    1109          342 :          DIMENSION(:, :, :, :)                           :: vec_Sigma_c_gw
    1110              :       INTEGER :: count_ev_sc_GW, cut_memory, group_size_P, gw_corr_lev_tot, handle, handle3, i, &
    1111              :          ikp_local, ispin, iter_evGW, iter_sc_GW0, j, jquad, min_bsize, mm_style, nkp, &
    1112              :          nkp_self_energy, nmo, nspins, num_3c_repl, num_cells_dm, num_fit_points, Pspin, Qspin, &
    1113              :          size_P
    1114              :       INTEGER(int_8)                                     :: dbcsr_nflop
    1115          342 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: index_to_cell_3c
    1116          342 :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: cell_to_index_3c
    1117          684 :       INTEGER, DIMENSION(:), POINTER                     :: col_blk_size, prim_blk_sizes, &
    1118          342 :                                                             RI_blk_sizes
    1119              :       LOGICAL :: do_apply_ic_corr_to_gw, do_gw_im_time, do_ic_model, do_kpoints_cubic_RPA, &
    1120              :          do_periodic, do_print, do_ri_Sigma_x, do_static_cohsex, exit_ev_gw, first_cycle, &
    1121              :          first_cycle_periodic_correction, my_open_shell, print_ic_values
    1122          342 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :, :, :, :)     :: has_mat_P_blocks
    1123              :       REAL(KIND=dp) :: alpha, dbcsr_time, e_exchange, e_exchange_corr, eps_filter, &
    1124              :          eps_filter_im_time, ext_scaling, fermi_level_offset, fermi_level_offset_input, &
    1125              :          my_flop_rate, omega, omega_max_fit, omega_old, tau, tau_old
    1126          342 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: delta_corr, diag_Qomega, e_fermi, &
    1127          342 :                                                             vec_omega_fit_gw, wkp_W
    1128          342 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: static_cohsex_eigenval_cn, &
    1129          684 :                                                             static_cohsex_eigenval_dg, vec_W_gw
    1130          342 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: Eigenval_last, Eigenval_scf, &
    1131          684 :                                                             static_cohsex_u, vec_Sigma_x_gw
    1132              :       TYPE(cp_cfm_type)                                  :: cfm_mat_Q, cfm_mat_RI_global_work
    1133          342 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_mat_L_kpoints, &
    1134          342 :                                                             cfm_mat_Minv_L_kpoints, cfm_mo_coeff
    1135              :       TYPE(cp_fm_type)                                   :: fm_mat_Minv_L_gamma, &
    1136              :                                                             fm_mat_Q_static_bse_gemm, fm_mat_work
    1137          342 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: fm_mat_S_gw_work, fm_mat_S_ia_bse, &
    1138          684 :                                                             fm_mat_W, mo_coeff_bse
    1139              :       TYPE(dbcsr_p_type)                                 :: mat_dm, mat_L, mat_M_P_munu_occ, &
    1140              :                                                             mat_M_P_munu_virt, mat_MinvVMinv
    1141              :       TYPE(dbcsr_p_type), ALLOCATABLE, &
    1142          342 :          DIMENSION(:, :, :)                              :: mat_P_omega
    1143          342 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_berry_im_mo_mo, &
    1144          342 :                                                             matrix_berry_re_mo_mo
    1145          342 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: mat_P_omega_kp
    1146              :       TYPE(dbcsr_type), POINTER                          :: mat_W, mat_work
    1147         3078 :       TYPE(dbt_type)                                     :: t_3c_overl_int_ao_mo
    1148          342 :       TYPE(dbt_type), ALLOCATABLE, DIMENSION(:)          :: t_3c_overl_int_gw_AO, &
    1149          342 :                                                             t_3c_overl_int_gw_RI, &
    1150          342 :                                                             t_3c_overl_nnP_ic, &
    1151          342 :                                                             t_3c_overl_nnP_ic_reflected
    1152              :       TYPE(dgemm_counter_type)                           :: dgemm_counter
    1153              :       TYPE(hfx_compression_type), ALLOCATABLE, &
    1154          342 :          DIMENSION(:)                                    :: t_3c_O_mo_compressed
    1155        28728 :       TYPE(im_time_force_type)                           :: force_data
    1156          342 :       TYPE(rpa_exchange_work_type)                       :: exchange_work
    1157         2052 :       TYPE(rpa_grad_type)                                :: rpa_grad
    1158          342 :       TYPE(rpa_sigma_type)                               :: rpa_sigma
    1159          342 :       TYPE(time_frequency_grid_type)                     :: time_frequency_grid
    1160          342 :       TYPE(two_dim_int_array), ALLOCATABLE, DIMENSION(:) :: t_3c_O_mo_ind
    1161              : 
    1162          342 :       CALL timeset(routineN, handle)
    1163              : 
    1164          342 :       nspins = SIZE(homo)
    1165          342 :       nmo = homo(1) + virtual(1)
    1166              : 
    1167          342 :       my_open_shell = (nspins == 2)
    1168              : 
    1169          342 :       do_gw_im_time = my_do_gw .AND. do_im_time
    1170          342 :       do_ri_Sigma_x = mp2_env%ri_g0w0%do_ri_Sigma_x
    1171          342 :       do_ic_model = mp2_env%ri_g0w0%do_ic_model
    1172          342 :       print_ic_values = mp2_env%ri_g0w0%print_ic_values
    1173          342 :       do_periodic = mp2_env%ri_g0w0%do_periodic
    1174          342 :       do_kpoints_cubic_RPA = mp2_env%ri_rpa_im_time%do_im_time_kpoints
    1175          342 :       do_static_cohsex = my_do_gw .AND. mp2_env%ri_g0w0%do_static_cohsex
    1176              : 
    1177              :       ! For SOS-MP2 only gemm is implemented
    1178          342 :       mm_style = wfc_mm_style_gemm
    1179          342 :       IF (.NOT. do_ri_sos_laplace_mp2) mm_style = mp2_env%ri_rpa%mm_style
    1180              : 
    1181          342 :       IF (my_do_gw) THEN
    1182          134 :          ext_scaling = 0.2_dp
    1183          134 :          omega_max_fit = mp2_env%ri_g0w0%omega_max_fit
    1184          134 :          fermi_level_offset_input = mp2_env%ri_g0w0%fermi_level_offset
    1185          134 :          iter_evGW = mp2_env%ri_g0w0%iter_evGW
    1186          134 :          iter_sc_GW0 = mp2_env%ri_g0w0%iter_sc_GW0
    1187          134 :          IF ((.NOT. do_im_time)) THEN
    1188           88 :             IF (iter_sc_GW0 /= 1 .AND. iter_evGW /= 1) CPABORT("Mixed scGW0/evGW not implemented.")
    1189              :             ! in case of scGW0 with the N^4 algorithm, we use the evGW code but use the DFT eigenvalues for W
    1190           88 :             IF (iter_sc_GW0 /= 1) iter_evGW = iter_sc_GW0
    1191              :          END IF
    1192          134 :          IF (do_static_cohsex) THEN
    1193            8 :             IF (do_im_time) CPABORT("COHSEX is only implemented in the O(N^4) GW code.")
    1194            8 :             IF (do_periodic) CPABORT("COHSEX with PERIODIC_CORRECTION is not implemented.")
    1195              :             ! BSE after static COHSEX: W = v + α W^c(0) with one α for both A and B
    1196            8 :             IF (do_bse .AND. mp2_env%ri_g0w0%cohsex_scale_occ /= mp2_env%ri_g0w0%cohsex_scale_virt) THEN
    1197              :                CALL cp_abort(__LOCATION__, "BSE after COHSEX requires COHSEX_SCALE_OCC = COHSEX_SCALE_VIRT "// &
    1198            0 :                              "(the scaling of W^c in the BSE).")
    1199              :             END IF
    1200            8 :             IF (do_ri_sos_laplace_mp2) CPABORT("COHSEX with SOS-MP2 is not implemented.")
    1201              :             ! static COHSEX is one-shot @DFT: Σ^COHSEX is static, no quasiparticle self-consistency
    1202            8 :             iter_evGW = 1
    1203            8 :             iter_sc_GW0 = 1
    1204              :          END IF
    1205              :       ELSE
    1206          208 :          ext_scaling = 0.0_dp
    1207          208 :          iter_evGW = 1
    1208          208 :          iter_sc_GW0 = 1
    1209              :       END IF
    1210              : 
    1211          342 :       IF (do_kpoints_cubic_RPA .AND. do_ri_sos_laplace_mp2) THEN
    1212            0 :          CPABORT("RI-SOS-Laplace-MP2 with k-point-sampling is not implemented.")
    1213              :       END IF
    1214              : 
    1215          342 :       do_apply_ic_corr_to_gw = .FALSE.
    1216          342 :       IF (mp2_env%ri_g0w0%ic_corr_list(1)%array(1) > 0.0_dp) do_apply_ic_corr_to_gw = .TRUE.
    1217              : 
    1218          342 :       IF (do_im_time) THEN
    1219          144 :          CPASSERT(do_minimax_quad .OR. do_ri_sos_laplace_mp2)
    1220              : 
    1221          144 :          group_size_P = mp2_env%ri_rpa_im_time%group_size_P
    1222          144 :          cut_memory = mp2_env%ri_rpa_im_time%cut_memory
    1223          144 :          eps_filter = mp2_env%ri_rpa_im_time%eps_filter
    1224              :          eps_filter_im_time = mp2_env%ri_rpa_im_time%eps_filter* &
    1225          144 :                               mp2_env%ri_rpa_im_time%eps_filter_factor
    1226              : 
    1227          144 :          min_bsize = mp2_env%ri_rpa_im_time%min_bsize
    1228              : 
    1229              :          CALL alloc_im_time(qs_env, para_env, dimen_RI, dimen_RI_red, &
    1230              :                             num_integ_points, nspins, calc_forces, fm_mat_Q(1), cfm_mo_coeff, &
    1231              :                             cfm_matrix_Minv_L_kpoints, cfm_matrix_L_kpoints, fm_matrix_Minv_L_gamma, mat_P_global, &
    1232              :                             t_3c_O, matrix_s, kpoints, eps_filter_im_time, &
    1233              :                             cut_memory, nkp, num_cells_dm, num_3c_repl, &
    1234              :                             size_P, ikp_local, &
    1235              :                             index_to_cell_3c, &
    1236              :                             cell_to_index_3c, &
    1237              :                             col_blk_size, &
    1238              :                             do_ic_model, do_kpoints_cubic_RPA, &
    1239              :                             do_kpoints_from_Gamma, do_ri_Sigma_x, my_open_shell, &
    1240              :                             has_mat_P_blocks, wkp_W, &
    1241              :                             cfm_mat_Q, cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints, fm_mat_Minv_L_gamma, &
    1242              :                             cfm_mat_RI_global_work, fm_mat_work, mat_dm, mat_L, mat_M_P_munu_occ, mat_M_P_munu_virt, &
    1243          144 :                             mat_MinvVMinv, mat_P_omega, mat_P_omega_kp, mat_work, mo_coeff)
    1244              : 
    1245          144 :          IF (calc_forces) CALL init_im_time_forces(force_data, fm_matrix_PQ, t_3c_M, unit_nr, mp2_env, qs_env)
    1246              : 
    1247          144 :          IF (my_do_gw) THEN
    1248              : 
    1249              :             CALL dbcsr_get_info(mat_P_global%matrix, &
    1250           46 :                                 row_blk_size=RI_blk_sizes)
    1251              : 
    1252              :             CALL dbcsr_get_info(matrix_s(1)%matrix, &
    1253           46 :                                 row_blk_size=prim_blk_sizes)
    1254              : 
    1255           46 :             gw_corr_lev_tot = gw_corr_lev_occ(1) + gw_corr_lev_virt(1)
    1256              : 
    1257           46 :             IF (.NOT. do_kpoints_cubic_RPA) THEN
    1258              :                CALL allocate_matrices_gw_im_time(gw_corr_lev_occ, gw_corr_lev_virt, homo, nmo, &
    1259              :                                                  num_integ_points, unit_nr, &
    1260              :                                                  RI_blk_sizes, do_ic_model, &
    1261              :                                                  para_env, fm_mat_W, fm_mat_Q(1), &
    1262              :                                                  mo_coeff, &
    1263              :                                                  t_3c_overl_int_ao_mo, t_3c_O_mo_compressed, t_3c_O_mo_ind, &
    1264              :                                                  t_3c_overl_int_gw_RI, t_3c_overl_int_gw_AO, &
    1265              :                                                  starts_array_mc, ends_array_mc, &
    1266              :                                                  t_3c_overl_nnP_ic, t_3c_overl_nnP_ic_reflected, &
    1267              :                                                  matrix_s, mat_W, t_3c_O, &
    1268              :                                                  t_3c_O_compressed, t_3c_O_ind, &
    1269           46 :                                                  qs_env)
    1270              : 
    1271              :             END IF
    1272              :          END IF
    1273              : 
    1274              :       END IF
    1275          342 :       IF (do_ic_model) THEN
    1276              :          ! image charge model only implemented for cubic scaling GW
    1277            2 :          CPASSERT(do_gw_im_time)
    1278            2 :          CPASSERT(.NOT. do_periodic)
    1279            2 :          IF (cut_memory /= 1) CPABORT("For IC, use MEMORY_CUT 1 in the LOW_SCALING section.")
    1280              :       END IF
    1281              : 
    1282         1026 :       ALLOCATE (e_fermi(nspins))
    1283          342 :       IF (do_minimax_quad .OR. do_ri_sos_laplace_mp2) THEN
    1284          214 :          do_print = .NOT. do_ic_model
    1285              :          CALL get_minimax_grid(para_env, unit_nr, homo, Eigenval, num_integ_points, do_im_time, &
    1286              :                                do_ri_sos_laplace_mp2, do_print, &
    1287          214 :                                qs_env, do_gw_im_time, do_kpoints_cubic_RPA, e_fermi(1), time_frequency_grid)
    1288              : 
    1289              :          !For sos_laplace_mp2 and low-scaling RPA, potentially need to store/retrieve the initial weights
    1290          214 :          IF (qs_env%mp2_env%ri_rpa_im_time%keep_quad) THEN
    1291          214 :             CALL keep_initial_quad(time_frequency_grid, do_ri_sos_laplace_mp2, do_im_time, unit_nr, qs_env)
    1292              :          END IF
    1293              :       ELSE
    1294          128 :          IF (calc_forces) CPABORT("Forces with Clenshaw-Curtis grid not implemented.")
    1295              :          CALL get_clenshaw_grid(para_env, para_env_RPA, unit_nr, homo, virtual, Eigenval, num_integ_points, &
    1296              :                                 num_integ_group, color_rpa_group, fm_mat_S, my_do_gw, &
    1297          128 :                                 ext_scaling, time_frequency_grid)
    1298              :       END IF
    1299              : 
    1300              :       ! This array is needed for RPA
    1301          342 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
    1302          834 :          ALLOCATE (diag_Qomega(dimen_RI_red))
    1303              :       END IF
    1304              : 
    1305          342 :       IF (do_ri_sos_laplace_mp2 .AND. .NOT. do_im_time) THEN
    1306           28 :          alpha = 1.0_dp
    1307          314 :       ELSE IF (my_open_shell .OR. do_ri_sos_laplace_mp2) THEN
    1308           90 :          alpha = 2.0_dp
    1309              :       ELSE
    1310          224 :          alpha = 4.0_dp
    1311              :       END IF
    1312          342 :       IF (my_do_gw) THEN
    1313              :          CALL allocate_matrices_gw(vec_Sigma_c_gw, color_rpa_group, dimen_nm_gw, &
    1314              :                                    gw_corr_lev_occ, gw_corr_lev_virt, homo, &
    1315              :                                    nmo, num_integ_group, unit_nr, &
    1316              :                                    gw_corr_lev_tot, num_fit_points, omega_max_fit, &
    1317              :                                    do_minimax_quad, do_periodic, do_ri_Sigma_x,.NOT. do_im_time, &
    1318              :                                    first_cycle_periodic_correction, &
    1319              :                                    time_frequency_grid, Eigenval, vec_omega_fit_gw, vec_Sigma_x_gw, &
    1320              :                                    delta_corr, Eigenval_last, Eigenval_scf, vec_W_gw, &
    1321              :                                    fm_mat_S_gw, fm_mat_S_gw_work, &
    1322              :                                    para_env, mp2_env, kpoints, nkp, nkp_self_energy, &
    1323          134 :                                    do_kpoints_cubic_RPA, do_kpoints_from_Gamma)
    1324              : 
    1325          134 :          IF (do_bse) THEN
    1326              : 
    1327           56 :             CALL cp_fm_create(fm_mat_Q_static_bse_gemm, fm_mat_Q_gemm(1)%matrix_struct, set_zero=.TRUE.)
    1328              : 
    1329              :          END IF
    1330              : 
    1331              :       END IF
    1332              : 
    1333          342 :       IF (calc_forces .AND. .NOT. do_im_time) CALL rpa_grad_create(rpa_grad, fm_mat_Q(1), &
    1334              :                                                                    fm_mat_S, homo, virtual, mp2_env, Eigenval(:, 1, :), &
    1335           44 :                                                                    unit_nr, do_ri_sos_laplace_mp2)
    1336          342 :       IF (.NOT. do_im_time .AND. .NOT. do_ri_sos_laplace_mp2) THEN
    1337              :          CALL exchange_work%create(qs_env, para_env_sub, mat_munu, dimen_RI_red, &
    1338          170 :                                    fm_mat_S, fm_mat_Q(1), fm_mat_Q_gemm(1), homo, virtual)
    1339              :       END IF
    1340          342 :       Erpa = 0.0_dp
    1341          342 :       IF (mp2_env%ri_rpa%exchange_correction /= rpa_exchange_none) e_exchange = 0.0_dp
    1342          342 :       first_cycle = .TRUE.
    1343          342 :       omega_old = 0.0_dp
    1344          342 :       CALL dgemm_counter_init(dgemm_counter, unit_nr, mp2_env%ri_rpa%print_dgemm_info)
    1345              : 
    1346          794 :       DO count_ev_sc_GW = 1, iter_evGW
    1347          472 :          dbcsr_time = 0.0_dp
    1348          472 :          dbcsr_nflop = 0
    1349              : 
    1350          472 :          IF (do_ic_model) CYCLE
    1351              : 
    1352              :          ! reset some values, important when doing eigenvalue self-consistent GW
    1353          470 :          IF (my_do_gw) THEN
    1354          262 :             Erpa = 0.0_dp
    1355          262 :             vec_Sigma_c_gw = z_zero
    1356          262 :             first_cycle = .TRUE.
    1357              :          END IF
    1358              : 
    1359              :          ! calculate Q_PQ(it)
    1360          470 :          IF (do_im_time) THEN ! not using Imaginary time
    1361              : 
    1362          156 :             IF (.NOT. do_kpoints_cubic_RPA) THEN
    1363          332 :                DO ispin = 1, nspins
    1364          332 :                   e_fermi(ispin) = (Eigenval(homo(ispin), 1, ispin) + Eigenval(homo(ispin) + 1, 1, ispin))*0.5_dp
    1365              :                END DO
    1366              :             END IF
    1367              : 
    1368          156 :             tau = 0.0_dp
    1369          156 :             tau_old = 0.0_dp
    1370              : 
    1371          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(/T3,A,T66,i15)") &
    1372           78 :                "MEMORY_INFO| Memory cut:", cut_memory
    1373          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(T3,A,T66,ES15.2)") &
    1374           78 :                "SPARSITY_INFO| Eps filter for M virt/occ tensors:", eps_filter
    1375          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(T3,A,T66,ES15.2)") &
    1376           78 :                "SPARSITY_INFO| Eps filter for P matrix:", eps_filter_im_time
    1377          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(T3,A,T66,i15)") &
    1378           78 :                "SPARSITY_INFO| Minimum tensor block size:", min_bsize
    1379              : 
    1380              :             ! compute the matrix Q(it) and Fourier transform it directly to mat_P_omega(iw)
    1381              :             CALL compute_mat_P_omega(mat_P_omega(:, :, 1), mo_coeff(1), homo(1), &
    1382              :                                      mat_P_global, matrix_s, 1, &
    1383              :                                      t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, &
    1384              :                                      starts_array_mc, ends_array_mc, &
    1385              :                                      starts_array_mc_block, ends_array_mc_block, &
    1386              :                                      time_frequency_grid, e_fermi(1), eps_filter, alpha, &
    1387              :                                      eps_filter_im_time, Eigenval(:, 1, 1), nmo, &
    1388              :                                      cut_memory, &
    1389              :                                      unit_nr, mp2_env, para_env, &
    1390              :                                      qs_env, do_kpoints_from_Gamma, &
    1391              :                                      index_to_cell_3c, cell_to_index_3c, &
    1392              :                                      has_mat_P_blocks, do_ri_sos_laplace_mp2, &
    1393          156 :                                      dbcsr_time, dbcsr_nflop)
    1394              : 
    1395              :             ! the same for open shell, use the beta-spin MO coefficients
    1396          156 :             IF (my_open_shell) THEN
    1397              :                CALL compute_mat_P_omega(mat_P_omega(:, :, 2), mo_coeff(2), homo(2), &
    1398              :                                         mat_P_global, matrix_s, 2, &
    1399              :                                         t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, &
    1400              :                                         starts_array_mc, ends_array_mc, &
    1401              :                                         starts_array_mc_block, ends_array_mc_block, &
    1402              :                                         time_frequency_grid, e_fermi(2), eps_filter, alpha, &
    1403              :                                         eps_filter_im_time, Eigenval(:, 1, 2), nmo, &
    1404              :                                         cut_memory, &
    1405              :                                         unit_nr, mp2_env, para_env, &
    1406              :                                         qs_env, do_kpoints_from_Gamma, &
    1407              :                                         index_to_cell_3c, cell_to_index_3c, &
    1408              :                                         has_mat_P_blocks, do_ri_sos_laplace_mp2, &
    1409           32 :                                         dbcsr_time, dbcsr_nflop)
    1410              : 
    1411              :                !For RPA, we sum up the P matrices. If no force needed, can clean-up the beta spin one
    1412           32 :                IF (.NOT. do_ri_sos_laplace_mp2) THEN
    1413           90 :                   DO j = 1, SIZE(mat_P_omega, 2)
    1414          598 :                      DO i = 1, SIZE(mat_P_omega, 1)
    1415          508 :                         CALL dbcsr_add(mat_P_omega(i, j, 1)%matrix, mat_P_omega(i, j, 2)%matrix, 1.0_dp, 1.0_dp)
    1416          578 :                         IF (.NOT. calc_forces) CALL dbcsr_clear(mat_P_omega(i, j, 2)%matrix)
    1417              :                      END DO
    1418              :                   END DO
    1419              :                END IF
    1420              :             END IF ! my_open_shell
    1421              : 
    1422              :          END IF ! do im time
    1423              : 
    1424          470 :          IF (mp2_env%ri_rpa%sigma_param /= sigma_none) THEN
    1425           10 :             CALL rpa_sigma_create(rpa_sigma, mp2_env%ri_rpa%sigma_param, fm_mat_Q(1), unit_nr, para_env)
    1426              :          END IF
    1427              : 
    1428              :          ! ==============================================================================
    1429              :          ! static COHSEX: only the static screening at ω = 0, no frequency integration, no
    1430              :          ! analytic continuation and no RPA correlation energy (Erpa stays zero)
    1431              :          !   S^P_ia(0) = B^P_ia sqrt(1/(ϵ_a - ϵ_i))
    1432              :          !   Q_PQ(0)   = 4 Σ_ia S^P_ia S^Q_ia (closed shell), 2 Σ_ia S^P_ia S^Q_ia per spin (open shell)
    1433              :          !   Q_PQ(0)   = Σ_σ Q^σ_PQ(0)                          (spin sum, open shell)
    1434              :          !   ε_PQ(0)   = δ_PQ + Q_PQ(0)
    1435              :          ! then W^c(0), Σ^c, Σ^x, H^QP and the diagonal/canonical static COHSEX energies
    1436              :          ! ==============================================================================
    1437          470 :          IF (do_static_cohsex) THEN
    1438            8 :             omega = 0.0_dp
    1439           16 :             DO ispin = 1, nspins
    1440              :                CALL calc_mat_Q(fm_mat_S(ispin), do_ri_sos_laplace_mp2, first_cycle, virtual(ispin), &
    1441              :                                Eigenval(:, 1, ispin), homo(ispin), omega, omega_old, 1, mm_style, &
    1442              :                                dimen_RI_red, dimen_ia(ispin), alpha, fm_mat_Q(ispin), &
    1443              :                                fm_mat_Q_gemm(ispin), do_bse, fm_mat_Q_static_bse_gemm, dgemm_counter, &
    1444           16 :                                num_integ_points, count_ev_sc_GW)
    1445              :             END DO
    1446            8 :             DO ispin = 2, nspins
    1447            8 :                CALL cp_fm_scale_and_add(alpha=1.0_dp, matrix_a=fm_mat_Q(1), beta=1.0_dp, matrix_b=fm_mat_Q(ispin))
    1448              :             END DO
    1449              :             ! BSE: the static polarizability Q_PQ(0) = Σ_σ Q^σ_PQ(0);
    1450            8 :             IF (do_bse) THEN
    1451            4 :                CALL cp_fm_set_all(fm_mat_Q_static_bse_gemm, 0.0_dp)
    1452            8 :                DO ispin = 1, nspins
    1453            8 :                   CALL cp_fm_scale_and_add(1.0_dp, fm_mat_Q_static_bse_gemm, 1.0_dp, fm_mat_Q_gemm(ispin))
    1454              :                END DO
    1455              :             END IF
    1456            8 :             CALL cp_fm_add_on_diag(fm_mat_Q(1), 1.0_dp, n_active=dimen_RI_red)
    1457            8 :             IF (do_bse) THEN
    1458              :                ! the BSE reads the quasiparticle energies from Eigenval: ϵ^CN (QP_UPDATE, with the
    1459              :                ! canonical MOs, see the BSE block) or ϵ^DG (DIAGONAL, with the KS MOs)
    1460            4 :                IF (mp2_env%ri_g0w0%cohsex_flavor == cohsex_qp_update) THEN
    1461           16 :                   ALLOCATE (static_cohsex_eigenval_cn(nmo, nspins), static_cohsex_u(nmo, nmo, nspins))
    1462              :                   CALL static_cohsex_qp_energies(fm_mat_Q(1), fm_mat_S_gw, fm_mat_S_gw_work, dimen_RI_red, nmo, &
    1463              :                                                  homo, gw_corr_lev_occ, gw_corr_lev_virt, Eigenval(:, 1, :), &
    1464              :                                                  mo_coeff, unit_nr, qs_env, mp2_env, &
    1465            2 :                                                  eigenval_cn=static_cohsex_eigenval_cn, u_qp_all=static_cohsex_u)
    1466           50 :                   Eigenval(:, 1, :) = static_cohsex_eigenval_cn(:, :)
    1467            2 :                   DEALLOCATE (static_cohsex_eigenval_cn)
    1468              :                ELSE
    1469            8 :                   ALLOCATE (static_cohsex_eigenval_dg(nmo, nspins))
    1470              :                   CALL static_cohsex_qp_energies(fm_mat_Q(1), fm_mat_S_gw, fm_mat_S_gw_work, dimen_RI_red, nmo, &
    1471              :                                                  homo, gw_corr_lev_occ, gw_corr_lev_virt, Eigenval(:, 1, :), &
    1472              :                                                  mo_coeff, unit_nr, qs_env, mp2_env, &
    1473            2 :                                                  eigenval_dg=static_cohsex_eigenval_dg)
    1474           50 :                   Eigenval(:, 1, :) = static_cohsex_eigenval_dg(:, :)
    1475            2 :                   DEALLOCATE (static_cohsex_eigenval_dg)
    1476              :                END IF
    1477              :                ! direct terms of the BSE with W = v + α W^c(0), α = COHSEX_SCALE_OCC (= COHSEX_SCALE_VIRT)
    1478            4 :                mp2_env%bse%wc_scaling = mp2_env%ri_g0w0%cohsex_scale_occ
    1479              :             ELSE
    1480              :                CALL static_cohsex_qp_energies(fm_mat_Q(1), fm_mat_S_gw, fm_mat_S_gw_work, dimen_RI_red, nmo, homo, &
    1481              :                                               gw_corr_lev_occ, gw_corr_lev_virt, Eigenval(:, 1, :), mo_coeff, &
    1482            4 :                                               unit_nr, qs_env, mp2_env)
    1483              :             END IF
    1484            8 :             first_cycle = .FALSE.
    1485              :          END IF
    1486              : 
    1487        14302 :          DO jquad = 1, num_integ_points
    1488              :             ! static COHSEX needs no frequency integral
    1489        13840 :             IF (do_static_cohsex) EXIT
    1490        13832 :             IF (MODULO(jquad, num_integ_group) /= color_rpa_group) CYCLE
    1491              : 
    1492        13059 :             CALL timeset(routineN//"_RPA_matrix_operations", handle3)
    1493              : 
    1494        13059 :             IF (do_ri_sos_laplace_mp2) THEN
    1495          206 :                omega = time_frequency_grid%imaginary_time(jquad)
    1496              :             ELSE
    1497        12853 :                omega = time_frequency_grid%frequency(jquad)
    1498              :             END IF ! do_ri_sos_laplace_mp2
    1499              : 
    1500        13059 :             IF (do_im_time) THEN
    1501              :                ! in case we do imag time, we already calculated fm_mat_Q by a Fourier transform from im. time
    1502              : 
    1503         1222 :                IF (.NOT. (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma)) THEN
    1504              : 
    1505         2428 :                   DO ispin = 1, SIZE(mat_P_omega, 3)
    1506              :                      CALL contract_P_omega_with_mat_L(mat_P_omega(jquad, 1, ispin)%matrix, mat_L%matrix, mat_work, &
    1507              :                                                       eps_filter_im_time, fm_mat_work, dimen_RI, dimen_RI_red, &
    1508         2428 :                                                       fm_mat_Minv_L_gamma, fm_mat_Q(ispin))
    1509              :                   END DO
    1510              :                END IF
    1511              : 
    1512              :             ELSE
    1513        11837 :                IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(T3, A, 1X, I3, 1X, A, 1X, I3)") &
    1514         5915 :                   "INTEG_INFO| Started with Integration point", jquad, "of", num_integ_points
    1515              : 
    1516        11837 :                IF (first_cycle .AND. count_ev_sc_gw > 1) THEN
    1517          116 :                   IF (iter_sc_gw0 == 1) THEN
    1518          124 :                      DO ispin = 1, nspins
    1519              :                         CALL remove_scaling_factor_rpa(fm_mat_S(ispin), virtual(ispin), &
    1520          124 :                                                        Eigenval_last(:, 1, ispin), homo(ispin), omega_old)
    1521              :                      END DO
    1522              :                   ELSE
    1523          116 :                      DO ispin = 1, nspins
    1524              :                         CALL remove_scaling_factor_rpa(fm_mat_S(ispin), virtual(ispin), &
    1525          116 :                                                        Eigenval_scf(:, 1, ispin), homo(ispin), omega_old)
    1526              :                      END DO
    1527              :                   END IF
    1528              :                END IF
    1529              : 
    1530        11837 :                IF (iter_sc_GW0 > 1) THEN
    1531        12140 :                DO ispin = 1, nspins
    1532              :                   CALL calc_mat_Q(fm_mat_S(ispin), do_ri_sos_laplace_mp2, first_cycle, virtual(ispin), &
    1533              :                                   Eigenval_scf(:, 1, ispin), homo(ispin), omega, omega_old, jquad, mm_style, &
    1534              :                                   dimen_RI_red, dimen_ia(ispin), alpha, fm_mat_Q(ispin), &
    1535              :                                   fm_mat_Q_gemm(ispin), do_bse, fm_mat_Q_static_bse_gemm, dgemm_counter, &
    1536        12140 :                                   num_integ_points, count_ev_sc_GW)
    1537              :                END DO
    1538              : 
    1539              :                ! For SOS-MP2 we need both matrices separately
    1540         6070 :                IF (.NOT. do_ri_sos_laplace_mp2) THEN
    1541         6070 :                DO ispin = 2, nspins
    1542         6070 :                   CALL cp_fm_scale_and_add(alpha=1.0_dp, matrix_a=fm_mat_Q(1), beta=1.0_dp, matrix_b=fm_mat_Q(ispin))
    1543              :                END DO
    1544              :                END IF
    1545              :                ELSE
    1546        12208 :                DO ispin = 1, nspins
    1547              :                   CALL calc_mat_Q(fm_mat_S(ispin), do_ri_sos_laplace_mp2, first_cycle, virtual(ispin), &
    1548              :                                   Eigenval(:, 1, ispin), homo(ispin), omega, omega_old, jquad, mm_style, &
    1549              :                                   dimen_RI_red, dimen_ia(ispin), alpha, fm_mat_Q(ispin), &
    1550              :                                   fm_mat_Q_gemm(ispin), do_bse, fm_mat_Q_static_bse_gemm, dgemm_counter, &
    1551        12208 :                                   num_integ_points, count_ev_sc_GW)
    1552              :                END DO
    1553              :                ! For open-shell BSE: the static screened-Coulomb polarizability is the
    1554              :                ! sum over both spin channels. calc_mat_Q overwrites fm_mat_Q_static_bse_gemm
    1555              :                ! per spin, so rebuild it here as the explicit spin sum at omega=0.
    1556         5767 :                IF (do_bse .AND. nspins > 1 .AND. jquad == num_integ_points .AND. &
    1557              :                    count_ev_sc_GW == 1) THEN
    1558           12 :                   CALL cp_fm_set_all(fm_mat_Q_static_bse_gemm, 0.0_dp)
    1559           36 :                   DO ispin = 1, nspins
    1560              :                      CALL cp_fm_scale_and_add(1.0_dp, fm_mat_Q_static_bse_gemm, &
    1561           36 :                                               1.0_dp, fm_mat_Q_gemm(ispin))
    1562              :                   END DO
    1563              :                END IF
    1564              : 
    1565              :                ! For SOS-MP2 we need both matrices separately
    1566         5767 :                IF (.NOT. do_ri_sos_laplace_mp2) THEN
    1567         6353 :                DO ispin = 2, nspins
    1568         6353 :                   CALL cp_fm_scale_and_add(alpha=1.0_dp, matrix_a=fm_mat_Q(1), beta=1.0_dp, matrix_b=fm_mat_Q(ispin))
    1569              :                END DO
    1570              :                END IF
    1571              : 
    1572              :                END IF
    1573              : 
    1574              :             END IF ! im time
    1575              : 
    1576              :             ! Calculate RPA exchange energy correction
    1577        13059 :             IF (mp2_env%ri_rpa%exchange_correction /= rpa_exchange_none) THEN
    1578           12 :                e_exchange_corr = 0.0_dp
    1579           12 :                CALL exchange_work%compute(fm_mat_Q(1), Eigenval(:, 1, :), fm_mat_S, omega, e_exchange_corr, mp2_env)
    1580              : 
    1581              :                ! Evaluate the final exchange energy correction
    1582           12 :                e_exchange = e_exchange + e_exchange_corr*time_frequency_grid%frequency_weights(jquad)
    1583              :             END IF
    1584              : 
    1585              :             ! for developing Sigma functional  closed and open shell are taken cared for
    1586        13059 :             IF (mp2_env%ri_rpa%sigma_param /= sigma_none) THEN
    1587           30 :                CALL rpa_sigma_matrix_spectral(rpa_sigma, fm_mat_Q(1), time_frequency_grid%frequency_weights(jquad), para_env_RPA)
    1588              :             END IF
    1589              : 
    1590        13059 :             IF (do_ri_sos_laplace_mp2) THEN
    1591              : 
    1592          206 :                CALL SOS_MP2_postprocessing(fm_mat_Q, Erpa, time_frequency_grid%time_weights_at_zero_frequency(jquad))
    1593              : 
    1594          206 :                IF (calc_forces .AND. .NOT. do_im_time) THEN
    1595              :                   CALL rpa_grad_matrix_operations(mp2_env, rpa_grad, do_ri_sos_laplace_mp2, &
    1596              :                                                   fm_mat_Q, fm_mat_Q_gemm, dgemm_counter, fm_mat_S, omega, homo, virtual, &
    1597              :                                                   Eigenval(:, 1, :), time_frequency_grid%time_weights_at_zero_frequency(jquad), &
    1598           50 :                                                   unit_nr)
    1599              :                END IF
    1600              :             ELSE
    1601        12853 :                IF (calc_forces .AND. .NOT. do_im_time) CALL rpa_grad_copy_Q(fm_mat_Q(1), rpa_grad)
    1602              : 
    1603              :                ! epsilon = I + Q; retain the diagonal of Q for the RPA energy.
    1604        12853 :                CALL cp_fm_get_diag(fm_mat_Q(1), diag_Qomega, n_active=dimen_RI_red)
    1605        12853 :                CALL cp_fm_add_on_diag(fm_mat_Q(1), 1.0_dp, n_active=dimen_RI_red)
    1606              : 
    1607        12853 :                IF (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma) THEN
    1608              :                   CALL invert_eps_compute_W_and_Erpa_kp(dimen_RI, jquad, nkp, count_ev_sc_GW, para_env, &
    1609              :                                                         Erpa, time_frequency_grid, &
    1610              :                                                         wkp_W, do_gw_im_time, do_ri_Sigma_x, do_kpoints_from_Gamma, &
    1611              :                                                         cfm_mat_Q, ikp_local, &
    1612              :                                                         mat_P_omega(:, :, 1), mat_P_omega_kp, qs_env, eps_filter_im_time, unit_nr, &
    1613              :                                                         kpoints, cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints, &
    1614              :                                                         fm_mat_W, cfm_mat_RI_global_work, mat_MinvVMinv, &
    1615          132 :                                                         fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv)
    1616              :                ELSE
    1617              :                   CALL compute_Erpa_by_freq_int(dimen_RI_red, diag_Qomega, fm_mat_Q(1), para_env_RPA, Erpa, &
    1618        12721 :                                                 time_frequency_grid%frequency_weights(jquad))
    1619              :                END IF
    1620              : 
    1621        12853 :                IF (calc_forces .AND. .NOT. do_im_time) THEN
    1622              :                   CALL rpa_grad_matrix_operations(mp2_env, rpa_grad, do_ri_sos_laplace_mp2, &
    1623              :                                                   fm_mat_Q, fm_mat_Q_gemm, dgemm_counter, fm_mat_S, omega, homo, virtual, &
    1624           56 :                                                   Eigenval(:, 1, :), time_frequency_grid%frequency_weights(jquad), unit_nr)
    1625              :                END IF
    1626              :             END IF ! do_ri_sos_laplace_mp2
    1627              : 
    1628              :             ! save omega and reset the first_cycle flag
    1629        13059 :             first_cycle = .FALSE.
    1630        13059 :             omega_old = omega
    1631              : 
    1632        13059 :             CALL timestop(handle3)
    1633              : 
    1634        13059 :             IF (my_do_gw) THEN
    1635              : 
    1636        12188 :                CALL get_fermi_level_offset(fermi_level_offset, fermi_level_offset_input, Eigenval(:, 1, :), homo)
    1637              : 
    1638              :                ! do_im_time = TRUE means low-scaling calculation
    1639        12188 :                IF (do_im_time) THEN
    1640              :                   ! only for molecules
    1641          818 :                   IF (.NOT. (do_kpoints_cubic_RPA .OR. do_kpoints_from_Gamma)) THEN
    1642              :                      CALL compute_W_cubic_GW(fm_mat_W, fm_mat_Q(1), fm_mat_work, dimen_RI, fm_mat_Minv_L_gamma, &
    1643          722 :                                              time_frequency_grid, jquad, omega)
    1644              :                   END IF
    1645              :                ELSE
    1646              :                   CALL compute_GW_self_energy(vec_Sigma_c_gw, dimen_nm_gw, dimen_RI_red, gw_corr_lev_occ, &
    1647              :                                               gw_corr_lev_virt, homo, jquad, nmo, num_fit_points, &
    1648              :                                               do_im_time, do_periodic, first_cycle_periodic_correction, &
    1649              :                                               fermi_level_offset, &
    1650              :                                               omega, Eigenval(:, 1, :), delta_corr, vec_omega_fit_gw, vec_W_gw, &
    1651              :                                               time_frequency_grid, &
    1652              :                                               fm_mat_Q(1), fm_mat_R_gw, fm_mat_S_gw, &
    1653              :                                               fm_mat_S_gw_work, mo_coeff(1), para_env, &
    1654              :                                               para_env_RPA, matrix_berry_im_mo_mo, matrix_berry_re_mo_mo, &
    1655        11370 :                                               kpoints, qs_env, mp2_env)
    1656              :                END IF
    1657              :             END IF
    1658              : 
    1659        13059 :             IF (unit_nr > 0) CALL m_flush(unit_nr)
    1660        27361 :             CALL para_env_RPA%sync() ! sync to see output
    1661              : 
    1662              :          END DO ! jquad
    1663              : 
    1664          470 :          IF (mp2_env%ri_rpa%sigma_param /= sigma_none) THEN
    1665           10 :             CALL finalize_rpa_sigma(rpa_sigma, unit_nr, mp2_env%ri_rpa%e_sigma_corr, para_env, do_minimax_quad)
    1666           10 :             IF (do_minimax_quad) mp2_env%ri_rpa%e_sigma_corr = mp2_env%ri_rpa%e_sigma_corr/2.0_dp
    1667           10 :             CALL para_env%sum(mp2_env%ri_rpa%e_sigma_corr)
    1668              :          END IF
    1669              : 
    1670          470 :          CALL para_env%sum(Erpa)
    1671              : 
    1672          470 :          IF (.NOT. (do_ri_sos_laplace_mp2)) THEN
    1673          406 :             Erpa = Erpa/(pi*2.0_dp)
    1674          406 :             IF (do_minimax_quad) Erpa = Erpa/2.0_dp
    1675              :          END IF
    1676              : 
    1677          470 :          IF (mp2_env%ri_rpa%exchange_correction /= rpa_exchange_none) THEN
    1678           12 :             CALL para_env%sum(E_exchange)
    1679           12 :             E_exchange = E_exchange/(pi*2.0_dp)
    1680           12 :             IF (do_minimax_quad) E_exchange = E_exchange/2.0_dp
    1681           12 :             mp2_env%ri_rpa%ener_exchange = E_exchange
    1682              :          END IF
    1683              : 
    1684          470 :          IF (calc_forces .AND. do_ri_sos_laplace_mp2 .AND. do_im_time) THEN
    1685           22 :             IF (my_open_shell) THEN
    1686            4 :                Pspin = 1
    1687            4 :                Qspin = 2
    1688              :                CALL calc_laplace_loop_forces(force_data, mat_P_omega(:, 1, :), t_3c_M, t_3c_O(1, 1), &
    1689              :                                              t_3c_O_compressed(1, 1, :), t_3c_O_ind(1, 1, :), mo_coeff, homo, &
    1690              :                                              starts_array_mc, ends_array_mc, starts_array_mc_block, &
    1691              :                                              ends_array_mc_block, nmo, Eigenval(:, 1, :), &
    1692              :                                              time_frequency_grid, &
    1693              :                                              cut_memory, Pspin, Qspin, my_open_shell, &
    1694            4 :                                              unit_nr, dbcsr_time, dbcsr_nflop, mp2_env, qs_env)
    1695            4 :                Pspin = 2
    1696            4 :                Qspin = 1
    1697              :                CALL calc_laplace_loop_forces(force_data, mat_P_omega(:, 1, :), t_3c_M, t_3c_O(1, 1), &
    1698              :                                              t_3c_O_compressed(1, 1, :), t_3c_O_ind(1, 1, :), mo_coeff, homo, &
    1699              :                                              starts_array_mc, ends_array_mc, starts_array_mc_block, &
    1700              :                                              ends_array_mc_block, nmo, Eigenval(:, 1, :), &
    1701              :                                              time_frequency_grid, &
    1702              :                                              cut_memory, Pspin, Qspin, my_open_shell, &
    1703            4 :                                              unit_nr, dbcsr_time, dbcsr_nflop, mp2_env, qs_env)
    1704              : 
    1705              :             ELSE
    1706           18 :                Pspin = 1
    1707           18 :                Qspin = 1
    1708              :                CALL calc_laplace_loop_forces(force_data, mat_P_omega(:, 1, :), t_3c_M, t_3c_O(1, 1), &
    1709              :                                              t_3c_O_compressed(1, 1, :), t_3c_O_ind(1, 1, :), mo_coeff, homo, &
    1710              :                                              starts_array_mc, ends_array_mc, starts_array_mc_block, &
    1711              :                                              ends_array_mc_block, nmo, Eigenval(:, 1, :), &
    1712              :                                              time_frequency_grid, &
    1713              :                                              cut_memory, Pspin, Qspin, my_open_shell, &
    1714           18 :                                              unit_nr, dbcsr_time, dbcsr_nflop, mp2_env, qs_env)
    1715              :             END IF
    1716           22 :             CALL calc_post_loop_forces(force_data, unit_nr, qs_env)
    1717              :          END IF !laplace SOS-MP2
    1718              : 
    1719          470 :          IF (calc_forces .AND. do_im_time .AND. .NOT. do_ri_sos_laplace_mp2) THEN
    1720           64 :             DO ispin = 1, nspins
    1721              :                CALL calc_rpa_loop_forces(force_data, mat_P_omega(:, 1, :), t_3c_M, t_3c_O(1, 1), &
    1722              :                                          t_3c_O_compressed(1, 1, :), t_3c_O_ind(1, 1, :), mo_coeff, homo, &
    1723              :                                          starts_array_mc, ends_array_mc, starts_array_mc_block, &
    1724              :                                          ends_array_mc_block, nmo, Eigenval(:, 1, :), &
    1725              :                                          e_fermi(ispin), time_frequency_grid, cut_memory, ispin, my_open_shell, &
    1726              :                                          unit_nr, dbcsr_time, &
    1727           64 :                                          dbcsr_nflop, mp2_env, qs_env)
    1728              :             END DO
    1729           28 :             CALL calc_post_loop_forces(force_data, unit_nr, qs_env)
    1730              :          END IF
    1731              : 
    1732          470 :          IF (do_im_time) THEN
    1733              : 
    1734          156 :             my_flop_rate = REAL(dbcsr_nflop, dp)/(1.0E09_dp*dbcsr_time)
    1735          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(/T3,A,T73,ES8.2)") &
    1736           78 :                "PERFORMANCE| DBCSR total number of flops:", REAL(dbcsr_nflop*para_env%num_pe, dp)
    1737          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.2)") &
    1738           78 :                "PERFORMANCE| DBCSR total execution time:", dbcsr_time
    1739          156 :             IF (unit_nr > 0) WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.2)") &
    1740           78 :                "PERFORMANCE| DBCSR flop rate (Gflops / MPI rank):", my_flop_rate
    1741              : 
    1742              :          ELSE
    1743              : 
    1744          314 :             CALL dgemm_counter_write(dgemm_counter, para_env)
    1745              : 
    1746              :          END IF
    1747              : 
    1748              :          ! GW: for low-scaling calculation: Compute self-energy Sigma(i*tau), Sigma(i*omega)
    1749              :          ! for low-scaling and ordinary-scaling: analytic continuation from Sigma(iw) -> Sigma(w)
    1750              :          !                                       and correction of quasiparticle energies e_n^GW
    1751              :          ! (static COHSEX energies are already computed and printed in static_cohsex_qp_energies)
    1752          812 :          IF (my_do_gw .AND. .NOT. do_static_cohsex) THEN
    1753              : 
    1754              :             CALL compute_QP_energies(vec_Sigma_c_gw, count_ev_sc_GW, gw_corr_lev_occ, &
    1755              :                                      gw_corr_lev_tot, gw_corr_lev_virt, homo, &
    1756              :                                      nmo, num_fit_points, &
    1757              :                                      unit_nr, do_apply_ic_corr_to_gw, do_im_time, &
    1758              :                                      do_periodic, do_ri_Sigma_x, first_cycle_periodic_correction, &
    1759              :                                      e_fermi, eps_filter, fermi_level_offset, &
    1760              :                                      delta_corr, Eigenval, &
    1761              :                                      Eigenval_last, Eigenval_scf, iter_sc_GW0, exit_ev_gw, &
    1762              :                                      time_frequency_grid, vec_omega_fit_gw, vec_Sigma_x_gw, &
    1763              :                                      mp2_env%ri_g0w0%ic_corr_list, &
    1764              :                                      mo_coeff, fm_mat_W, para_env, &
    1765              :                                      para_env_RPA, mat_dm, mat_MinvVMinv, &
    1766              :                                      t_3c_O, t_3c_M, t_3c_overl_int_ao_mo, t_3c_O_compressed, t_3c_O_mo_compressed, &
    1767              :                                      t_3c_O_ind, t_3c_O_mo_ind, &
    1768              :                                      t_3c_overl_int_gw_RI, t_3c_overl_int_gw_AO, &
    1769              :                                      matrix_berry_im_mo_mo, matrix_berry_re_mo_mo, mat_W, matrix_s, &
    1770              :                                      kpoints, mp2_env, qs_env, nkp_self_energy, do_kpoints_cubic_RPA, &
    1771          254 :                                      starts_array_mc, ends_array_mc)
    1772              : 
    1773              :             ! if HOMO-LUMO gap differs by less than mp2_env%ri_g0w0%eps_ev_sc_iter, exit ev sc GW loop
    1774          254 :             IF (exit_ev_gw) EXIT
    1775              : 
    1776              :          END IF ! my_do_gw if
    1777              : 
    1778              :       END DO ! evGW loop
    1779              : 
    1780          342 :       IF (do_ic_model) THEN
    1781              : 
    1782            2 :          IF (my_open_shell) THEN
    1783              : 
    1784              :             CALL calculate_ic_correction(Eigenval(:, 1, 1), mat_MinvVMinv%matrix, &
    1785              :                                          t_3c_overl_nnP_ic(1), t_3c_overl_nnP_ic_reflected(1), &
    1786              :                                          gw_corr_lev_tot, &
    1787              :                                          gw_corr_lev_occ(1), gw_corr_lev_virt(1), homo(1), unit_nr, &
    1788            0 :                                          print_ic_values, para_env, do_alpha=.TRUE.)
    1789              : 
    1790              :             CALL calculate_ic_correction(Eigenval(:, 1, 2), mat_MinvVMinv%matrix, &
    1791              :                                          t_3c_overl_nnP_ic(2), t_3c_overl_nnP_ic_reflected(2), &
    1792              :                                          gw_corr_lev_tot, &
    1793              :                                          gw_corr_lev_occ(2), gw_corr_lev_virt(2), homo(2), unit_nr, &
    1794            0 :                                          print_ic_values, para_env, do_beta=.TRUE.)
    1795              : 
    1796              :          ELSE
    1797              : 
    1798              :             CALL calculate_ic_correction(Eigenval(:, 1, 1), mat_MinvVMinv%matrix, &
    1799              :                                          t_3c_overl_nnP_ic(1), t_3c_overl_nnP_ic_reflected(1), &
    1800              :                                          gw_corr_lev_tot, &
    1801              :                                          gw_corr_lev_occ(1), gw_corr_lev_virt(1), homo(1), unit_nr, &
    1802            2 :                                          print_ic_values, para_env)
    1803              : 
    1804              :          END IF
    1805              : 
    1806              :       END IF
    1807              : 
    1808              :       ! postprocessing after GW for Bethe-Salpeter
    1809          342 :       IF (do_bse) THEN
    1810              :          ! Check used GW flavor; in Case of evGW we use W0 for BSE
    1811              :          ! Use environment variable, since local iter_evGW is overwritten if evGW0 is invoked
    1812           56 :          IF (mp2_env%ri_g0w0%iter_evGW > 1) THEN
    1813            4 :             IF (unit_nr > 0) THEN
    1814              :                CALL cp_warn(__LOCATION__, &
    1815            2 :                             "BSE@evGW applies W0, i.e. screening with DFT energies to the BSE!")
    1816              :             END IF
    1817              :          END IF
    1818              :          ! Create a per-spin copy of fm_mat_S for usage in BSE
    1819          236 :          ALLOCATE (fm_mat_S_ia_bse(nspins))
    1820          124 :          DO ispin = 1, nspins
    1821           68 :             CALL cp_fm_create(fm_mat_S_ia_bse(ispin), fm_mat_S(ispin)%matrix_struct)
    1822           68 :             CALL cp_fm_to_fm(fm_mat_S(ispin), fm_mat_S_ia_bse(ispin))
    1823              :             ! Remove energy/frequency factor from 3c-Integral for BSE
    1824          124 :             IF (iter_sc_gw0 == 1) THEN
    1825              :                CALL remove_scaling_factor_rpa(fm_mat_S_ia_bse(ispin), virtual(ispin), &
    1826           56 :                                               Eigenval_last(:, 1, ispin), homo(ispin), omega)
    1827              :             ELSE
    1828              :                CALL remove_scaling_factor_rpa(fm_mat_S_ia_bse(ispin), virtual(ispin), &
    1829           12 :                                               Eigenval_scf(:, 1, ispin), homo(ispin), omega)
    1830              :             END IF
    1831              :          END DO
    1832              :          ! ==============================================================================
    1833              :          ! BSE with the canonical static COHSEX quasiparticles: the KS-MO slabs are rotated to the
    1834              :          ! canonical MOs C^QP = C U (U block diagonal in occ/virt, δ outside the window)
    1835              :          !   B̃^P_ia = Σ_jb U_ji U_ba B^P_jb,  B̃^P_ij = Σ_kl U_ki U_lj B^P_kl,  B̃^P_ab analogous
    1836              :          ! Q(0), ε^(-1)(0) and the kernel are invariant under these rotations, so the BSE with
    1837              :          ! ϵ^CN and C^QP equals the BSE with the full H^QP in the KS basis.
    1838              :          ! ==============================================================================
    1839           56 :          IF (do_static_cohsex .AND. mp2_env%ri_g0w0%cohsex_flavor == cohsex_qp_update) THEN
    1840            6 :             ALLOCATE (mo_coeff_bse(nspins))
    1841            4 :             DO ispin = 1, nspins
    1842              :                ! the ab slab holds the first bse_lev_virt virtuals: U must not mix beyond them
    1843            2 :                IF (gw_corr_lev_virt(ispin) > bse_lev_virt(ispin)) THEN
    1844            0 :                   CPABORT("Canonical static COHSEX BSE: the corrected virtual MOs exceed the BSE (ab) slab.")
    1845              :                END IF
    1846              :                CALL rotate_bse_slab(fm_mat_S_ia_bse(ispin), dimen_RI_red, homo(ispin), virtual(ispin), &
    1847              :                                     static_cohsex_u(1:homo(ispin), 1:homo(ispin), ispin), &
    1848            2 :                                     static_cohsex_u(homo(ispin) + 1:nmo, homo(ispin) + 1:nmo, ispin))
    1849              :                CALL rotate_bse_slab(fm_mat_S_ij_bse(ispin), dimen_RI_red, homo(ispin), homo(ispin), &
    1850              :                                     static_cohsex_u(1:homo(ispin), 1:homo(ispin), ispin), &
    1851            2 :                                     static_cohsex_u(1:homo(ispin), 1:homo(ispin), ispin))
    1852              :                CALL rotate_bse_slab(fm_mat_S_ab_bse(ispin), dimen_RI_red, bse_lev_virt(ispin), bse_lev_virt(ispin), &
    1853              :                                     static_cohsex_u(homo(ispin) + 1:homo(ispin) + bse_lev_virt(ispin), &
    1854              :                                                     homo(ispin) + 1:homo(ispin) + bse_lev_virt(ispin), ispin), &
    1855              :                                     static_cohsex_u(homo(ispin) + 1:homo(ispin) + bse_lev_virt(ispin), &
    1856            2 :                                                     homo(ispin) + 1:homo(ispin) + bse_lev_virt(ispin), ispin))
    1857              :                ! transition dipoles, NTOs and exciton descriptors with C^QP
    1858            4 :                CALL get_static_cohsex_mo_coeff(mo_coeff(ispin), static_cohsex_u(:, :, ispin), mo_coeff_bse(ispin))
    1859              :             END DO
    1860              :          END IF
    1861           56 :          IF (ALLOCATED(static_cohsex_u)) DEALLOCATE (static_cohsex_u)
    1862              : 
    1863              :          ! the solver keeps [1+Q(0)]^-1 and the window-sized slabs; Q(0) and the full slabs stay the GW's
    1864              :          CALL prepare_bse_env_from_ri_rpa_gw(mp2_env%bse, fm_mat_S_ia_bse, fm_mat_S_ij_bse, fm_mat_S_ab_bse, &
    1865              :                                              fm_mat_Q_static_bse_gemm, Eigenval, Eigenval_scf, &
    1866              :                                              homo, virtual, dimen_RI, dimen_RI_red, mp2_env%ri_g0w0%corr_mos_occ, &
    1867           56 :                                              bse_lev_virt, qs_env, unit_nr)
    1868           56 :          CALL cp_fm_release(fm_mat_Q_static_bse_gemm)
    1869           56 :          IF (ALLOCATED(mo_coeff_bse)) THEN
    1870            2 :             CALL bse_solve(mp2_env%bse, mo_coeff_bse, unit_nr)
    1871            2 :             CALL cp_fm_release(mo_coeff_bse)
    1872              :          ELSE
    1873           54 :             CALL bse_solve(mp2_env%bse, mo_coeff, unit_nr)
    1874              :          END IF
    1875           56 :          CALL bse_env_release(mp2_env%bse)
    1876              :          ! Release per-spin BSE-copy of fm_mat_S
    1877          124 :          DO ispin = 1, nspins
    1878          124 :             CALL cp_fm_release(fm_mat_S_ia_bse(ispin))
    1879              :          END DO
    1880           56 :          DEALLOCATE (fm_mat_S_ia_bse)
    1881              :       END IF
    1882              : 
    1883          342 :       IF (my_do_gw) THEN
    1884              :          CALL deallocate_matrices_gw(fm_mat_S_gw_work, vec_W_gw, vec_Sigma_c_gw, vec_omega_fit_gw, &
    1885              :                                      mp2_env%ri_g0w0%vec_Sigma_x_minus_vxc_gw, &
    1886              :                                      Eigenval_last, Eigenval_scf, do_periodic, matrix_berry_re_mo_mo, matrix_berry_im_mo_mo, &
    1887          134 :                                      kpoints, vec_Sigma_x_gw,.NOT. do_im_time)
    1888              :       END IF
    1889              : 
    1890          342 :       IF (do_im_time) THEN
    1891              : 
    1892              :          CALL dealloc_im_time(cfm_mo_coeff, index_to_cell_3c, &
    1893              :                               cell_to_index_3c, do_ic_model, &
    1894              :                               do_kpoints_cubic_RPA, do_kpoints_from_Gamma, do_ri_Sigma_x, &
    1895              :                               has_mat_P_blocks, &
    1896              :                               wkp_W, cfm_mat_Q, cfm_mat_Minv_L_kpoints, cfm_mat_L_kpoints, &
    1897              :                               fm_mat_Minv_L_gamma, &
    1898              :                               fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv, cfm_mat_RI_global_work, fm_mat_work, &
    1899              :                               mat_dm, mat_L, &
    1900              :                               mat_MinvVMinv, mat_P_omega, mat_P_omega_kp, &
    1901          144 :                               t_3c_M, t_3c_O, t_3c_O_compressed, t_3c_O_ind, mat_work, qs_env)
    1902              : 
    1903          144 :          IF (my_do_gw) THEN
    1904              :             CALL deallocate_matrices_gw_im_time(do_ic_model, do_kpoints_cubic_RPA, fm_mat_W, &
    1905              :                                                 t_3c_overl_int_ao_mo, t_3c_O_mo_compressed, t_3c_O_mo_ind, &
    1906              :                                                 t_3c_overl_int_gw_RI, t_3c_overl_int_gw_AO, &
    1907              :                                                 t_3c_overl_nnP_ic, t_3c_overl_nnP_ic_reflected, &
    1908           46 :                                                 mat_W, qs_env)
    1909              :          END IF
    1910              : 
    1911              :       END IF
    1912              : 
    1913          342 :       IF (.NOT. do_im_time .AND. .NOT. do_ri_sos_laplace_mp2) CALL exchange_work%release()
    1914              : 
    1915          342 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
    1916          278 :          DEALLOCATE (diag_Qomega)
    1917              :       END IF
    1918              : 
    1919          342 :       CALL time_frequency_grid_release(time_frequency_grid)
    1920              : 
    1921          342 :       IF (do_im_time .AND. calc_forces) THEN
    1922           50 :          CALL im_time_force_release(force_data)
    1923              :       END IF
    1924              : 
    1925          342 :       IF (calc_forces .AND. .NOT. do_im_time) CALL rpa_grad_finalize(rpa_grad, mp2_env, para_env_sub, para_env, &
    1926              :                                                                      qs_env, gd_array, color_sub, do_ri_sos_laplace_mp2, &
    1927           44 :                                                                      homo, virtual)
    1928              : 
    1929          342 :       CALL timestop(handle)
    1930              : 
    1931         8330 :    END SUBROUTINE rpa_num_int
    1932              : 
    1933              : ! **************************************************************************************************
    1934              : !> \brief ...
    1935              : !> \param para_env ...
    1936              : !> \param unit_nr ...
    1937              : !> \param homo ...
    1938              : !> \param Eigenval ...
    1939              : !> \param num_integ_points ...
    1940              : !> \param do_im_time ...
    1941              : !> \param do_ri_sos_laplace_mp2 ...
    1942              : !> \param do_print ...
    1943              : !> \param qs_env ...
    1944              : !> \param do_gw_im_time ...
    1945              : !> \param do_kpoints_cubic_RPA ...
    1946              : !> \param e_fermi ...
    1947              : !> \param grid ...
    1948              : ! **************************************************************************************************
    1949          214 :    SUBROUTINE get_minimax_grid(para_env, unit_nr, homo, Eigenval, num_integ_points, &
    1950              :                                do_im_time, do_ri_sos_laplace_mp2, do_print, qs_env, do_gw_im_time, &
    1951              :                                do_kpoints_cubic_RPA, e_fermi, grid)
    1952              : 
    1953              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    1954              :       INTEGER, INTENT(IN)                                :: unit_nr
    1955              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
    1956              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
    1957              :       INTEGER, INTENT(IN)                                :: num_integ_points
    1958              :       LOGICAL, INTENT(IN)                                :: do_im_time, do_ri_sos_laplace_mp2, &
    1959              :                                                             do_print
    1960              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1961              :       LOGICAL, INTENT(IN)                                :: do_gw_im_time, do_kpoints_cubic_RPA
    1962              :       REAL(KIND=dp), INTENT(OUT)                         :: e_fermi
    1963              :       TYPE(time_frequency_grid_type), INTENT(OUT)        :: grid
    1964              : 
    1965              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_minimax_grid'
    1966              :       INTEGER, PARAMETER                                 :: num_points_per_magnitude = 200
    1967              : 
    1968              :       INTEGER                                            :: handle, jquad
    1969              :       LOGICAL                                            :: used_external_backend
    1970              :       REAL(KIND=dp)                                      :: E_Range, Emax, Emin, max_error_min
    1971              : 
    1972          214 :       CALL timeset(routineN, handle)
    1973              : 
    1974              :       CALL determine_energy_range(qs_env, para_env, homo, Eigenval, do_ri_sos_laplace_mp2, &
    1975          214 :                                   do_kpoints_cubic_RPA, Emin, Emax, e_range, e_fermi)
    1976              : 
    1977              :       ! Open-shell uses ONE minimax grid for the combined [min gap, max span] over both spins (the
    1978              :       ! superset covers each channel, so it is accurate; per-spin grids would only be more efficient).
    1979          214 :       IF (SIZE(homo) > 1) THEN
    1980              :          CALL cp_hint(__LOCATION__, &
    1981              :                       "Open-shell RPA/GW uses one minimax grid spanning [min gap, max span] across "// &
    1982              :                       "both spin channels; raise QUADRATURE_POINTS if QP convergence is marginal for "// &
    1983           50 :                       "strongly spin-asymmetric systems.")
    1984              :       END IF
    1985              : 
    1986              :       CALL build_minimax_time_frequency_grid(num_integ_points, Emin, Emax, &
    1987              :                                              qs_env%mp2_env%ri_g0w0%regularization_minimax, &
    1988              :                                              num_points_per_magnitude, grid, &
    1989              :                                              build_frequency=.NOT. do_ri_sos_laplace_mp2, &
    1990              :                                              build_time=do_im_time .OR. do_ri_sos_laplace_mp2, &
    1991              :                                              build_transforms=do_im_time .AND. .NOT. do_ri_sos_laplace_mp2, &
    1992              :                                              build_sine=do_im_time .AND. (.NOT. do_ri_sos_laplace_mp2) .AND. do_gw_im_time, &
    1993              :                                              time_scaling=MERGE(1.0_dp, 2.0_dp, do_ri_sos_laplace_mp2), &
    1994              :                                              time_weight_scaling=MERGE(1.0_dp, 2.0_dp, do_ri_sos_laplace_mp2), &
    1995              :                                              max_fit_error=max_error_min, print_warning=.TRUE., unit_nr=unit_nr, &
    1996          680 :                                              prefer_external_backend=.TRUE., used_external_backend=used_external_backend)
    1997              : 
    1998              :       ! Keep the native diagnostics and warning behavior in this RPA policy wrapper. The external
    1999              :       ! backend reports its diagnostics from the grid builder.
    2000          214 :       IF (used_external_backend) THEN
    2001           78 :          CALL timestop(handle)
    2002           78 :          RETURN
    2003              :       END IF
    2004              : 
    2005          136 :       IF (num_integ_points > 20 .AND. e_range < 100.0_dp) THEN
    2006            0 :          IF (unit_nr > 0) THEN
    2007              :             CALL cp_warn(__LOCATION__, &
    2008              :                          "You requested a large minimax grid (> 20 points) for a small minimax range R (R < 100). "// &
    2009              :                          "That may lead to numerical "// &
    2010              :                          "instabilities when computing minimax grid weights. You can prevent small ranges by choosing "// &
    2011            0 :                          "a larger basis set with higher angular momenta or alternatively using all-electron calculations.")
    2012              :          END IF
    2013              :       END IF
    2014              : 
    2015          136 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
    2016           72 :          IF (unit_nr > 0 .AND. do_print) THEN
    2017              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
    2018           35 :                "MINIMAX_INFO| Number of integration points:", num_integ_points
    2019              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
    2020           35 :                "MINIMAX_INFO| Gap for the minimax approximation:", Emin
    2021              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
    2022           35 :                "MINIMAX_INFO| Range for the minimax approximation:", e_range
    2023           35 :             WRITE (UNIT=unit_nr, FMT="(T3,A,T54,A,T72,A)") "MINIMAX_INFO| Minimax parameters:", "Weights", "Abscissas"
    2024          167 :             DO jquad = 1, num_integ_points
    2025              :                WRITE (UNIT=unit_nr, FMT="(T41,F20.10,F20.10)") &
    2026          167 :                   grid%frequency_weights(jquad)/Emin, grid%frequency(jquad)/Emin
    2027              :             END DO
    2028           35 :             CALL m_flush(unit_nr)
    2029              :          END IF
    2030              :       END IF
    2031              : 
    2032          136 :       IF (do_im_time .OR. do_ri_sos_laplace_mp2) THEN
    2033          106 :          IF (unit_nr > 0 .AND. do_print) THEN
    2034              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
    2035           52 :                "MINIMAX_INFO| Range for the minimax approximation:", e_range
    2036              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
    2037           52 :                "MINIMAX_INFO| Gap:", Emin
    2038              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T54,A,T72,A)") &
    2039           52 :                "MINIMAX_INFO| Minimax parameters of the time grid:", "Weights", "Abscissas"
    2040          246 :             DO jquad = 1, num_integ_points
    2041              :                WRITE (UNIT=unit_nr, FMT="(T41,F20.10,F20.10)") &
    2042          246 :                   grid%time_weights_at_zero_frequency(jquad)*Emin, grid%imaginary_time(jquad)*Emin
    2043              :             END DO
    2044           52 :             CALL m_flush(unit_nr)
    2045              :          END IF
    2046              : 
    2047          106 :          IF (unit_nr > 0 .AND. do_im_time .AND. do_gw_im_time .AND. .NOT. do_ri_sos_laplace_mp2) THEN
    2048              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,ES15.2)") &
    2049            5 :                "MINIMAX_INFO| Maximum deviation among requested minimax transform fits:", max_error_min
    2050              :          END IF
    2051              :       END IF
    2052              : 
    2053          136 :       CALL timestop(handle)
    2054              : 
    2055              :    END SUBROUTINE get_minimax_grid
    2056              : 
    2057              : ! **************************************************************************************************
    2058              : !> \brief Construct a Clenshaw-Curtis grid after determining its RPA scaling.
    2059              : !> \param para_env ...
    2060              : !> \param para_env_RPA ...
    2061              : !> \param unit_nr ...
    2062              : !> \param homo ...
    2063              : !> \param virtual ...
    2064              : !> \param Eigenval ...
    2065              : !> \param num_integ_points ...
    2066              : !> \param num_integ_group ...
    2067              : !> \param color_rpa_group ...
    2068              : !> \param fm_mat_S ...
    2069              : !> \param my_do_gw ...
    2070              : !> \param ext_scaling ...
    2071              : !> \param grid ...
    2072              : ! **************************************************************************************************
    2073          256 :    SUBROUTINE get_clenshaw_grid(para_env, para_env_RPA, unit_nr, homo, virtual, Eigenval, num_integ_points, &
    2074          128 :                                 num_integ_group, color_rpa_group, fm_mat_S, my_do_gw, &
    2075              :                                 ext_scaling, grid)
    2076              : 
    2077              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_RPA
    2078              :       INTEGER, INTENT(IN)                                :: unit_nr
    2079              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
    2080              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
    2081              :       INTEGER, INTENT(IN)                                :: num_integ_points, num_integ_group, &
    2082              :                                                             color_rpa_group
    2083              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S
    2084              :       LOGICAL, INTENT(IN)                                :: my_do_gw
    2085              :       REAL(KIND=dp), INTENT(IN)                          :: ext_scaling
    2086              :       TYPE(time_frequency_grid_type), INTENT(OUT)        :: grid
    2087              : 
    2088              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_clenshaw_grid'
    2089              : 
    2090              :       INTEGER                                            :: handle
    2091              :       REAL(KIND=dp)                                      :: a_scaling
    2092              : 
    2093          128 :       CALL timeset(routineN, handle)
    2094              : 
    2095          128 :       CALL build_clenshaw_grid(num_integ_points, grid)
    2096              : 
    2097          128 :       IF (my_do_gw .AND. ext_scaling > 0.0_dp) THEN
    2098           88 :          a_scaling = ext_scaling
    2099              :       ELSE
    2100              :          CALL calc_scaling_factor(a_scaling, para_env, para_env_RPA, homo, virtual, Eigenval, &
    2101              :                                   num_integ_points, num_integ_group, color_rpa_group, &
    2102           40 :                                   grid%frequency, grid%frequency_weights, fm_mat_S)
    2103              :       END IF
    2104              : 
    2105          128 :       IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.5)') 'INTEG_INFO| Scaling parameter:', a_scaling
    2106              : 
    2107         5678 :       grid%frequency_weights(:) = grid%frequency_weights(:)*a_scaling
    2108         5678 :       grid%frequency(:) = a_scaling/TAN(grid%frequency(:))
    2109              : 
    2110          128 :       CALL timestop(handle)
    2111              : 
    2112          128 :    END SUBROUTINE get_clenshaw_grid
    2113              : 
    2114              : ! **************************************************************************************************
    2115              : !> \brief ...
    2116              : !> \param a_scaling_ext ...
    2117              : !> \param para_env ...
    2118              : !> \param para_env_RPA ...
    2119              : !> \param homo ...
    2120              : !> \param virtual ...
    2121              : !> \param Eigenval ...
    2122              : !> \param num_integ_points ...
    2123              : !> \param num_integ_group ...
    2124              : !> \param color_rpa_group ...
    2125              : !> \param tj_ext ...
    2126              : !> \param wj_ext ...
    2127              : !> \param fm_mat_S ...
    2128              : ! **************************************************************************************************
    2129           40 :    SUBROUTINE calc_scaling_factor(a_scaling_ext, para_env, para_env_RPA, homo, virtual, Eigenval, &
    2130              :                                   num_integ_points, num_integ_group, color_rpa_group, &
    2131           40 :                                   tj_ext, wj_ext, fm_mat_S)
    2132              :       REAL(KIND=dp), INTENT(OUT)                         :: a_scaling_ext
    2133              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_RPA
    2134              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
    2135              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
    2136              :       INTEGER, INTENT(IN)                                :: num_integ_points, num_integ_group, &
    2137              :                                                             color_rpa_group
    2138              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    2139              :          INTENT(IN)                                      :: tj_ext, wj_ext
    2140              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S
    2141              : 
    2142              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_scaling_factor'
    2143              : 
    2144              :       INTEGER                                            :: handle, icycle, jquad, ncol_local, &
    2145              :                                                             ncol_local_beta, nspins
    2146              :       LOGICAL                                            :: my_open_shell
    2147              :       REAL(KIND=dp) :: a_high, a_low, a_scaling, conv_param, eps, first_deriv, left_term, &
    2148              :          right_term, right_term_ref, right_term_ref_beta, step
    2149           40 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: cottj, D_ia, D_ia_beta, iaia_RI, &
    2150           40 :                                                             iaia_RI_beta, M_ia, M_ia_beta
    2151              :       TYPE(mp_para_env_type), POINTER                    :: para_env_col, para_env_col_beta
    2152              : 
    2153           40 :       CALL timeset(routineN, handle)
    2154              : 
    2155           40 :       nspins = SIZE(homo)
    2156           40 :       my_open_shell = (nspins == 2)
    2157              : 
    2158           40 :       eps = 1.0E-10_dp
    2159              : 
    2160          120 :       ALLOCATE (cottj(num_integ_points))
    2161              : 
    2162              :       ! calculate the cotangent of the abscissa tj
    2163          570 :       DO jquad = 1, num_integ_points
    2164          570 :          cottj(jquad) = 1.0_dp/TAN(tj_ext(jquad))
    2165              :       END DO
    2166              : 
    2167              :       CALL calc_ia_ia_integrals(para_env_RPA, homo(1), virtual(1), ncol_local, right_term_ref, Eigenval(:, 1, 1), &
    2168           40 :                                 D_ia, iaia_RI, M_ia, fm_mat_S(1), para_env_col)
    2169              : 
    2170              :       ! In the open shell case do point 1-2-3 for the beta spin
    2171           40 :       IF (my_open_shell) THEN
    2172              :          CALL calc_ia_ia_integrals(para_env_RPA, homo(2), virtual(2), ncol_local_beta, right_term_ref_beta, Eigenval(:, 1, 2), &
    2173            8 :                                    D_ia_beta, iaia_RI_beta, M_ia_beta, fm_mat_S(2), para_env_col_beta)
    2174              : 
    2175            8 :          right_term_ref = right_term_ref + right_term_ref_beta
    2176              :       END IF
    2177              : 
    2178              :       ! bcast the result
    2179           40 :       IF (para_env%mepos == 0) THEN
    2180           20 :          CALL para_env%bcast(right_term_ref, 0)
    2181              :       ELSE
    2182           20 :          right_term_ref = 0.0_dp
    2183           20 :          CALL para_env%bcast(right_term_ref, 0)
    2184              :       END IF
    2185              : 
    2186              :       ! 5) start iteration for solving the non-linear equation by bisection
    2187              :       ! find limit, here step=0.5 seems a good compromise
    2188           40 :       conv_param = 100.0_dp*EPSILON(right_term_ref)
    2189           40 :       step = 0.5_dp
    2190           40 :       a_low = 0.0_dp
    2191           40 :       a_high = step
    2192           40 :       right_term = -right_term_ref
    2193          104 :       DO icycle = 1, num_integ_points*2
    2194           96 :          a_scaling = a_high
    2195              : 
    2196              :          CALL calculate_objfunc(a_scaling, left_term, first_deriv, num_integ_points, my_open_shell, &
    2197              :                                 M_ia, cottj, wj_ext, D_ia, D_ia_beta, M_ia_beta, &
    2198              :                                 ncol_local, ncol_local_beta, num_integ_group, color_rpa_group, &
    2199           96 :                                 para_env, para_env_col, para_env_col_beta)
    2200           96 :          left_term = left_term/4.0_dp/pi*a_scaling
    2201              : 
    2202           96 :          IF (ABS(left_term) > ABS(right_term) .OR. ABS(left_term + right_term) <= conv_param) EXIT
    2203           64 :          a_low = a_high
    2204          104 :          a_high = a_high + step
    2205              : 
    2206              :       END DO
    2207              : 
    2208           40 :       IF (ABS(left_term + right_term) >= conv_param) THEN
    2209           32 :          IF (a_scaling >= 2*num_integ_points*step) THEN
    2210           10 :             a_scaling = 1.0_dp
    2211              :          ELSE
    2212              : 
    2213          340 :             DO icycle = 1, num_integ_points*2
    2214          336 :                a_scaling = (a_low + a_high)/2.0_dp
    2215              : 
    2216              :                CALL calculate_objfunc(a_scaling, left_term, first_deriv, num_integ_points, my_open_shell, &
    2217              :                                       M_ia, cottj, wj_ext, D_ia, D_ia_beta, M_ia_beta, &
    2218              :                                       ncol_local, ncol_local_beta, num_integ_group, color_rpa_group, &
    2219          336 :                                       para_env, para_env_col, para_env_col_beta)
    2220          336 :                left_term = left_term/4.0_dp/pi*a_scaling
    2221              : 
    2222          336 :                IF (ABS(left_term) > ABS(right_term)) THEN
    2223              :                   a_high = a_scaling
    2224              :                ELSE
    2225          186 :                   a_low = a_scaling
    2226              :                END IF
    2227              : 
    2228          340 :                IF (ABS(a_high - a_low) < 1.0e-5_dp) EXIT
    2229              : 
    2230              :             END DO
    2231              : 
    2232              :          END IF
    2233              :       END IF
    2234              : 
    2235           40 :       a_scaling_ext = a_scaling
    2236           40 :       CALL para_env%bcast(a_scaling_ext, 0)
    2237              : 
    2238           40 :       DEALLOCATE (cottj)
    2239           40 :       DEALLOCATE (iaia_RI)
    2240           40 :       DEALLOCATE (D_ia)
    2241           40 :       DEALLOCATE (M_ia)
    2242           40 :       CALL mp_para_env_release(para_env_col)
    2243              : 
    2244           40 :       IF (my_open_shell) THEN
    2245            8 :          DEALLOCATE (iaia_RI_beta)
    2246            8 :          DEALLOCATE (D_ia_beta)
    2247            8 :          DEALLOCATE (M_ia_beta)
    2248            8 :          CALL mp_para_env_release(para_env_col_beta)
    2249              :       END IF
    2250              : 
    2251           40 :       CALL timestop(handle)
    2252              : 
    2253           80 :    END SUBROUTINE calc_scaling_factor
    2254              : 
    2255              : ! **************************************************************************************************
    2256              : !> \brief ...
    2257              : !> \param para_env_RPA ...
    2258              : !> \param homo ...
    2259              : !> \param virtual ...
    2260              : !> \param ncol_local ...
    2261              : !> \param right_term_ref ...
    2262              : !> \param Eigenval ...
    2263              : !> \param D_ia ...
    2264              : !> \param iaia_RI ...
    2265              : !> \param M_ia ...
    2266              : !> \param fm_mat_S ...
    2267              : !> \param para_env_col ...
    2268              : ! **************************************************************************************************
    2269           48 :    SUBROUTINE calc_ia_ia_integrals(para_env_RPA, homo, virtual, ncol_local, right_term_ref, Eigenval, &
    2270              :                                    D_ia, iaia_RI, M_ia, fm_mat_S, para_env_col)
    2271              : 
    2272              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env_RPA
    2273              :       INTEGER, INTENT(IN)                                :: homo, virtual
    2274              :       INTEGER, INTENT(OUT)                               :: ncol_local
    2275              :       REAL(KIND=dp), INTENT(OUT)                         :: right_term_ref
    2276              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: Eigenval
    2277              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    2278              :          INTENT(OUT)                                     :: D_ia, iaia_RI, M_ia
    2279              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S
    2280              :       TYPE(mp_para_env_type), POINTER                    :: para_env_col
    2281              : 
    2282              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_ia_ia_integrals'
    2283              : 
    2284              :       INTEGER                                            :: avirt, color_col, color_row, handle, &
    2285              :                                                             i_global, iiB, iocc, nrow_local
    2286           48 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    2287              :       REAL(KIND=dp)                                      :: eigen_diff
    2288              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: iaia_RI_dp
    2289              :       TYPE(mp_para_env_type), POINTER                    :: para_env_row
    2290              : 
    2291           48 :       CALL timeset(routineN, handle)
    2292              : 
    2293              :       ! calculate the (ia|ia) RI integrals
    2294              :       ! ----------------------------------
    2295              :       ! 1) get info fm_mat_S
    2296              :       CALL cp_fm_get_info(matrix=fm_mat_S, &
    2297              :                           nrow_local=nrow_local, &
    2298              :                           ncol_local=ncol_local, &
    2299              :                           row_indices=row_indices, &
    2300           48 :                           col_indices=col_indices)
    2301              : 
    2302              :       ! allocate the local buffer of iaia_RI integrals (dp kind)
    2303          142 :       ALLOCATE (iaia_RI_dp(ncol_local))
    2304           48 :       iaia_RI_dp = 0.0_dp
    2305              : 
    2306              :       ! 2) perform the local multiplication SUM_K (ia|K)*(ia|K)
    2307         2918 :       DO iiB = 1, ncol_local
    2308       200776 :          iaia_RI_dp(iiB) = iaia_RI_dp(iiB) + DOT_PRODUCT(fm_mat_S%local_data(:, iiB), fm_mat_S%local_data(:, iiB))
    2309              :       END DO
    2310              : 
    2311              :       ! 3) sum the result with the processes of the RPA_group having the same columns
    2312              :       !          _______ia______               _
    2313              :       !         |   |   |   |   |             | |
    2314              :       !     --> | 1 | 5 | 9 | 13|   SUM -->   | |
    2315              :       !         |___|__ |___|___|             |_|
    2316              :       !         |   |   |   |   |             | |
    2317              :       !     --> | 2 | 6 | 10| 14|   SUM -->   | |
    2318              :       !       K |___|___|___|___|             |_|   (ia|ia)_RI
    2319              :       !         |   |   |   |   |             | |
    2320              :       !     --> | 3 | 7 | 11| 15|   SUM -->   | |
    2321              :       !         |___|___|___|___|             |_|
    2322              :       !         |   |   |   |   |             | |
    2323              :       !     --> | 4 | 8 | 12| 16|   SUM -->   | |
    2324              :       !         |___|___|___|___|             |_|
    2325              :       !
    2326              : 
    2327           48 :       color_col = fm_mat_S%matrix_struct%context%mepos(2)
    2328           48 :       ALLOCATE (para_env_col)
    2329           48 :       CALL para_env_col%from_split(para_env_RPA, color_col)
    2330              : 
    2331           48 :       CALL para_env_col%sum(iaia_RI_dp)
    2332              : 
    2333              :       ! convert the iaia_RI_dp into double-double precision
    2334          142 :       ALLOCATE (iaia_RI(ncol_local))
    2335         2918 :       DO iiB = 1, ncol_local
    2336         2918 :          iaia_RI(iiB) = iaia_RI_dp(iiB)
    2337              :       END DO
    2338           48 :       DEALLOCATE (iaia_RI_dp)
    2339              : 
    2340              :       ! 4) calculate the right hand term, D_ia is the matrix containing the
    2341              :       ! orbital energy differences, M_ia is the diagonal of the full RPA 'excitation'
    2342              :       ! matrix
    2343          142 :       ALLOCATE (D_ia(ncol_local))
    2344              : 
    2345           94 :       ALLOCATE (M_ia(ncol_local))
    2346              : 
    2347         2918 :       DO iiB = 1, ncol_local
    2348         2870 :          i_global = col_indices(iiB)
    2349              : 
    2350         2870 :          iocc = MAX(1, i_global - 1)/virtual + 1
    2351         2870 :          avirt = i_global - (iocc - 1)*virtual
    2352         2870 :          eigen_diff = Eigenval(avirt + homo) - Eigenval(iocc)
    2353              : 
    2354         2918 :          D_ia(iiB) = eigen_diff
    2355              :       END DO
    2356              : 
    2357         2918 :       DO iiB = 1, ncol_local
    2358         2918 :          M_ia(iiB) = D_ia(iiB)*D_ia(iiB) + 2.0_dp*D_ia(iiB)*iaia_RI(iiB)
    2359              :       END DO
    2360              : 
    2361           48 :       right_term_ref = 0.0_dp
    2362         2918 :       DO iiB = 1, ncol_local
    2363         2918 :          right_term_ref = right_term_ref + (SQRT(M_ia(iiB)) - D_ia(iiB) - iaia_RI(iiB))
    2364              :       END DO
    2365           48 :       right_term_ref = right_term_ref/2.0_dp
    2366              : 
    2367              :       ! sum the result with the processes of the RPA_group having the same row
    2368           48 :       color_row = fm_mat_S%matrix_struct%context%mepos(1)
    2369           48 :       ALLOCATE (para_env_row)
    2370           48 :       CALL para_env_row%from_split(para_env_RPA, color_row)
    2371              : 
    2372              :       ! allocate communication array for rows
    2373           48 :       CALL para_env_row%sum(right_term_ref)
    2374              : 
    2375           48 :       CALL mp_para_env_release(para_env_row)
    2376              : 
    2377           48 :       CALL timestop(handle)
    2378              : 
    2379           48 :    END SUBROUTINE calc_ia_ia_integrals
    2380              : 
    2381              : ! **************************************************************************************************
    2382              : !> \brief ...
    2383              : !> \param a_scaling ...
    2384              : !> \param left_term ...
    2385              : !> \param first_deriv ...
    2386              : !> \param num_integ_points ...
    2387              : !> \param my_open_shell ...
    2388              : !> \param M_ia ...
    2389              : !> \param cottj ...
    2390              : !> \param wj ...
    2391              : !> \param D_ia ...
    2392              : !> \param D_ia_beta ...
    2393              : !> \param M_ia_beta ...
    2394              : !> \param ncol_local ...
    2395              : !> \param ncol_local_beta ...
    2396              : !> \param num_integ_group ...
    2397              : !> \param color_rpa_group ...
    2398              : !> \param para_env ...
    2399              : !> \param para_env_col ...
    2400              : !> \param para_env_col_beta ...
    2401              : ! **************************************************************************************************
    2402          432 :    SUBROUTINE calculate_objfunc(a_scaling, left_term, first_deriv, num_integ_points, my_open_shell, &
    2403              :                                 M_ia, cottj, wj, D_ia, D_ia_beta, M_ia_beta, &
    2404              :                                 ncol_local, ncol_local_beta, num_integ_group, color_rpa_group, &
    2405              :                                 para_env, para_env_col, para_env_col_beta)
    2406              :       REAL(KIND=dp), INTENT(IN)                          :: a_scaling
    2407              :       REAL(KIND=dp), INTENT(INOUT)                       :: left_term, first_deriv
    2408              :       INTEGER, INTENT(IN)                                :: num_integ_points
    2409              :       LOGICAL, INTENT(IN)                                :: my_open_shell
    2410              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    2411              :          INTENT(IN)                                      :: M_ia, cottj, wj, D_ia, D_ia_beta, &
    2412              :                                                             M_ia_beta
    2413              :       INTEGER, INTENT(IN)                                :: ncol_local, ncol_local_beta, &
    2414              :                                                             num_integ_group, color_rpa_group
    2415              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_col
    2416              :       TYPE(mp_para_env_type), POINTER                    :: para_env_col_beta
    2417              : 
    2418              :       INTEGER                                            :: iiB, jquad
    2419              :       REAL(KIND=dp)                                      :: first_deriv_beta, left_term_beta, omega
    2420              : 
    2421          432 :       left_term = 0.0_dp
    2422          432 :       first_deriv = 0.0_dp
    2423          432 :       left_term_beta = 0.0_dp
    2424          432 :       first_deriv_beta = 0.0_dp
    2425         4616 :       DO jquad = 1, num_integ_points
    2426              :          ! parallelize over integration points
    2427         4184 :          IF (MODULO(jquad, num_integ_group) /= color_rpa_group) CYCLE
    2428         2292 :          omega = a_scaling*cottj(jquad)
    2429              : 
    2430       168644 :          DO iiB = 1, ncol_local
    2431              :             ! parallelize over ia elements in the para_env_row group
    2432       166352 :             IF (MODULO(iiB, para_env_col%num_pe) /= para_env_col%mepos) CYCLE
    2433              :             ! calculate left_term
    2434              :             left_term = left_term + wj(jquad)* &
    2435              :                         (LOG(1.0_dp + (M_ia(iiB) - D_ia(iiB)**2)/(omega**2 + D_ia(iiB)**2)) - &
    2436       151152 :                          (M_ia(iiB) - D_ia(iiB)**2)/(omega**2 + D_ia(iiB)**2))
    2437              :             first_deriv = first_deriv + wj(jquad)*cottj(jquad)**2* &
    2438       168644 :                           ((-M_ia(iiB) + D_ia(iiB)**2)**2/((omega**2 + D_ia(iiB)**2)**2*(omega**2 + M_ia(iiB))))
    2439              :          END DO
    2440              : 
    2441         2724 :          IF (my_open_shell) THEN
    2442        14490 :             DO iiB = 1, ncol_local_beta
    2443              :                ! parallelize over ia elements in the para_env_row group
    2444        14140 :                IF (MODULO(iiB, para_env_col_beta%num_pe) /= para_env_col_beta%mepos) CYCLE
    2445              :                ! calculate left_term
    2446              :                left_term_beta = left_term_beta + wj(jquad)* &
    2447              :                                 (LOG(1.0_dp + (M_ia_beta(iiB) - D_ia_beta(iiB)**2)/(omega**2 + D_ia_beta(iiB)**2)) - &
    2448        14140 :                                  (M_ia_beta(iiB) - D_ia_beta(iiB)**2)/(omega**2 + D_ia_beta(iiB)**2))
    2449              :                first_deriv_beta = &
    2450              :                   first_deriv_beta + wj(jquad)*cottj(jquad)**2* &
    2451        14490 :                   ((-M_ia_beta(iiB) + D_ia_beta(iiB)**2)**2/((omega**2 + D_ia_beta(iiB)**2)**2*(omega**2 + M_ia_beta(iiB))))
    2452              :             END DO
    2453              :          END IF
    2454              : 
    2455              :       END DO
    2456              : 
    2457              :       ! sum the contribution from all proc, starting form the row group
    2458          432 :       CALL para_env%sum(left_term)
    2459          432 :       CALL para_env%sum(first_deriv)
    2460              : 
    2461          432 :       IF (my_open_shell) THEN
    2462           70 :          CALL para_env%sum(left_term_beta)
    2463           70 :          CALL para_env%sum(first_deriv_beta)
    2464              : 
    2465           70 :          left_term = left_term + left_term_beta
    2466           70 :          first_deriv = first_deriv + first_deriv_beta
    2467              :       END IF
    2468              : 
    2469          432 :    END SUBROUTINE calculate_objfunc
    2470              : 
    2471              : ! **************************************************************************************************
    2472              : !> \brief ...
    2473              : !> \param qs_env ...
    2474              : !> \param para_env ...
    2475              : !> \param gap ...
    2476              : !> \param max_eig_diff ...
    2477              : !> \param e_fermi ...
    2478              : ! **************************************************************************************************
    2479           12 :    SUBROUTINE gap_and_max_eig_diff_kpoints(qs_env, para_env, gap, max_eig_diff, e_fermi)
    2480              : 
    2481              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2482              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    2483              :       REAL(KIND=dp), INTENT(OUT)                         :: gap, max_eig_diff, e_fermi
    2484              : 
    2485              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'gap_and_max_eig_diff_kpoints'
    2486              : 
    2487              :       INTEGER                                            :: handle, homo, ikpgr, ispin, kplocal, &
    2488              :                                                             nmo, nspin
    2489              :       INTEGER, DIMENSION(2)                              :: kp_range
    2490              :       REAL(KIND=dp)                                      :: e_homo, e_homo_temp, e_lumo, e_lumo_temp
    2491              :       REAL(KIND=dp), DIMENSION(3)                        :: tmp
    2492            6 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
    2493              :       TYPE(kpoint_env_type), POINTER                     :: kp
    2494              :       TYPE(kpoint_type), POINTER                         :: kpoint
    2495              :       TYPE(mo_set_type), POINTER                         :: mo_set
    2496              : 
    2497            6 :       CALL timeset(routineN, handle)
    2498              : 
    2499              :       CALL get_qs_env(qs_env, &
    2500            6 :                       kpoints=kpoint)
    2501              : 
    2502            6 :       mo_set => kpoint%kp_env(1)%kpoint_env%mos(1)
    2503            6 :       CALL get_mo_set(mo_set, nmo=nmo)
    2504              : 
    2505            6 :       CALL get_kpoint_info(kpoint, kp_range=kp_range)
    2506            6 :       kplocal = kp_range(2) - kp_range(1) + 1
    2507              : 
    2508            6 :       gap = 1000.0_dp
    2509            6 :       max_eig_diff = 0.0_dp
    2510            6 :       e_homo = -1000.0_dp
    2511            6 :       e_lumo = 1000.0_dp
    2512              : 
    2513           18 :       DO ikpgr = 1, kplocal
    2514           12 :          kp => kpoint%kp_env(ikpgr)%kpoint_env
    2515           12 :          nspin = SIZE(kp%mos)
    2516           30 :          DO ispin = 1, nspin
    2517           12 :             mo_set => kp%mos(ispin)
    2518           12 :             CALL get_mo_set(mo_set, eigenvalues=eigenvalues, homo=homo)
    2519           12 :             e_homo_temp = eigenvalues(homo)
    2520           12 :             e_lumo_temp = eigenvalues(homo + 1)
    2521              : 
    2522              :             IF (e_homo_temp > e_homo) e_homo = e_homo_temp
    2523              :             IF (e_lumo_temp < e_lumo) e_lumo = e_lumo_temp
    2524           24 :             IF (eigenvalues(nmo) - eigenvalues(1) > max_eig_diff) max_eig_diff = eigenvalues(nmo) - eigenvalues(1)
    2525              : 
    2526              :          END DO
    2527              :       END DO
    2528              : 
    2529              :       ! Collect all three numbers in an array
    2530              :       ! Reverse sign of lumo to reduce number of MPI calls
    2531            6 :       tmp(1) = e_homo
    2532            6 :       tmp(2) = -e_lumo
    2533            6 :       tmp(3) = max_eig_diff
    2534            6 :       CALL para_env%max(tmp)
    2535              : 
    2536            6 :       gap = -tmp(2) - tmp(1)
    2537            6 :       e_fermi = (tmp(1) - tmp(2))*0.5_dp
    2538            6 :       max_eig_diff = tmp(3)
    2539              : 
    2540            6 :       CALL timestop(handle)
    2541              : 
    2542            6 :    END SUBROUTINE gap_and_max_eig_diff_kpoints
    2543              : 
    2544              : ! **************************************************************************************************
    2545              : !> \brief returns minimal and maximal energy values for the E_range for the minimax grid selection
    2546              : !> \param qs_env ...
    2547              : !> \param para_env ...
    2548              : !> \param homo index of the homo level for the respective spin channel
    2549              : !> \param Eigenval eigenvalues
    2550              : !> \param do_ri_sos_laplace_mp2 flag for SOS-MP2
    2551              : !> \param do_kpoints_cubic_RPA flag for cubic-scaling RPA with k-points
    2552              : !> \param Emin minimal eigenvalue difference (gap of the system)
    2553              : !> \param Emax maximal eigenvalue difference
    2554              : !> \param e_range ...
    2555              : !> \param e_fermi Fermi level
    2556              : ! **************************************************************************************************
    2557          214 :    SUBROUTINE determine_energy_range(qs_env, para_env, homo, Eigenval, do_ri_sos_laplace_mp2, &
    2558              :                                      do_kpoints_cubic_RPA, Emin, Emax, e_range, e_fermi)
    2559              : 
    2560              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    2561              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    2562              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
    2563              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
    2564              :       LOGICAL, INTENT(IN)                                :: do_ri_sos_laplace_mp2, &
    2565              :                                                             do_kpoints_cubic_RPA
    2566              :       REAL(KIND=dp), INTENT(OUT)                         :: Emin, Emax, e_range, e_fermi
    2567              : 
    2568              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'determine_energy_range'
    2569              : 
    2570              :       INTEGER                                            :: handle, ispin, nspins
    2571              :       LOGICAL                                            :: my_do_kpoints
    2572              :       TYPE(section_vals_type), POINTER                   :: input
    2573              : 
    2574          214 :       CALL timeset(routineN, handle)
    2575              :       ! Test for spin unrestricted
    2576          214 :       nspins = SIZE(homo)
    2577              : 
    2578              :       ! Test whether all necessary variables are available
    2579          214 :       my_do_kpoints = .FALSE.
    2580          214 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
    2581          150 :          my_do_kpoints = do_kpoints_cubic_RPA
    2582              :       END IF
    2583              : 
    2584          150 :       IF (my_do_kpoints) THEN
    2585            6 :          CALL gap_and_max_eig_diff_kpoints(qs_env, para_env, Emin, Emax, e_fermi)
    2586            6 :          E_Range = Emax/Emin
    2587              :       ELSE
    2588          208 :          IF (qs_env%mp2_env%E_range <= 1.0_dp .OR. qs_env%mp2_env%E_gap <= 0.0_dp) THEN
    2589          160 :             Emin = HUGE(dp)
    2590          160 :             Emax = 0.0_dp
    2591          360 :             DO ispin = 1, nspins
    2592          360 :                IF (homo(ispin) > 0) THEN
    2593          196 :                   Emin = MIN(Emin, Eigenval(homo(ispin) + 1, 1, ispin) - Eigenval(homo(ispin), 1, ispin))
    2594        15360 :                   Emax = MAX(Emax, MAXVAL(Eigenval(:, :, ispin)) - MINVAL(Eigenval(:, :, ispin)))
    2595              :                END IF
    2596              :             END DO
    2597          160 :             E_Range = Emax/Emin
    2598          160 :             qs_env%mp2_env%e_range = e_range
    2599          160 :             qs_env%mp2_env%e_gap = Emin
    2600              : 
    2601          160 :             CALL get_qs_env(qs_env, input=input)
    2602          160 :             CALL section_vals_val_set(input, "DFT%XC%WF_CORRELATION%E_RANGE", r_val=e_range)
    2603          160 :             CALL section_vals_val_set(input, "DFT%XC%WF_CORRELATION%E_GAP", r_val=emin)
    2604              :          ELSE
    2605           48 :             E_range = qs_env%mp2_env%E_range
    2606           48 :             Emin = qs_env%mp2_env%E_gap
    2607           48 :             Emax = Emin*E_range
    2608              :          END IF
    2609              :       END IF
    2610              : 
    2611              :       ! When we perform SOS-MP2, we need an additional factor of 2 for the energies (compare with mp2_laplace.F)
    2612              :       ! We do not need weights etc. for the cosine transform
    2613              :       ! We do not scale Emax because it is not needed for SOS-MP2
    2614          214 :       IF (do_ri_sos_laplace_mp2) THEN
    2615           64 :          Emin = Emin*2.0_dp
    2616           64 :          Emax = Emax*2.0_dp
    2617              :       END IF
    2618              : 
    2619          214 :       CALL timestop(handle)
    2620          214 :    END SUBROUTINE determine_energy_range
    2621              : 
    2622              : END MODULE rpa_main
        

Generated by: LCOV version 2.0-1