LCOV - code coverage report
Current view: top level - src - rpa_exchange.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:b310db4) Lines: 97.6 % 381 372
Test Date: 2026-10-23 01:10:43 Functions: 60.0 % 15 9

            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 Auxiliary routines needed for RPA-exchange
      10              : !>        given blacs_env to another
      11              : !> \par History
      12              : !>      09.2016 created [Vladimir Rybkin]
      13              : !>      03.2019 Renamed [Frederick Stein]
      14              : !>      03.2019 Moved Functions from rpa_ri_gpw.F [Frederick Stein]
      15              : !>      04.2024 Added open-shell calculations, SOSEX [Frederick Stein]
      16              : !> \author Vladimir Rybkin
      17              : ! **************************************************************************************************
      18              : MODULE rpa_exchange
      19              :    USE atomic_kind_types,               ONLY: atomic_kind_type
      20              :    USE cell_types,                      ONLY: cell_type
      21              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      22              :    USE cp_control_types,                ONLY: dft_control_type
      23              :    USE cp_dbcsr_api,                    ONLY: &
      24              :         dbcsr_copy, dbcsr_create, dbcsr_get_info, dbcsr_init_p, dbcsr_multiply, dbcsr_p_type, &
      25              :         dbcsr_release, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
      26              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_trace
      27              :    USE cp_dbcsr_operations,             ONLY: dbcsr_allocate_matrix_set
      28              :    USE cp_dbcsr_redistribution,         ONLY: cp_array_to_dbcsr_slices
      29              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale
      30              :    USE cp_fm_diag,                      ONLY: choose_eigv_solver
      31              :    USE cp_fm_redistribution,            ONLY: cp_fm_to_array
      32              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      33              :                                               cp_fm_struct_p_type,&
      34              :                                               cp_fm_struct_release
      35              :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      36              :                                               cp_fm_get_info,&
      37              :                                               cp_fm_release,&
      38              :                                               cp_fm_set_all,&
      39              :                                               cp_fm_to_fm,&
      40              :                                               cp_fm_to_fm_submat_general,&
      41              :                                               cp_fm_type
      42              :    USE group_dist_types,                ONLY: create_group_dist,&
      43              :                                               get_group_dist,&
      44              :                                               group_dist_d1_type,&
      45              :                                               group_dist_proc,&
      46              :                                               maxsize,&
      47              :                                               release_group_dist
      48              :    USE hfx_admm_utils,                  ONLY: tddft_hfx_matrix
      49              :    USE hfx_types,                       ONLY: hfx_create,&
      50              :                                               hfx_release,&
      51              :                                               hfx_type
      52              :    USE input_constants,                 ONLY: rpa_exchange_axk,&
      53              :                                               rpa_exchange_none,&
      54              :                                               rpa_exchange_sosex
      55              :    USE input_section_types,             ONLY: section_vals_get_subs_vals,&
      56              :                                               section_vals_type
      57              :    USE kinds,                           ONLY: dp,&
      58              :                                               int_8
      59              :    USE local_gemm_api,                  ONLY: LOCAL_GEMM_PU_GPU
      60              :    USE mathconstants,                   ONLY: sqrthalf
      61              :    USE message_passing,                 ONLY: mp_para_env_type,&
      62              :                                               mp_proc_null
      63              :    USE mp2_types,                       ONLY: mp2_type
      64              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      65              :    USE particle_types,                  ONLY: particle_type
      66              :    USE qs_environment_types,            ONLY: get_qs_env,&
      67              :                                               qs_environment_type
      68              :    USE qs_kind_types,                   ONLY: qs_kind_type
      69              :    USE qs_subsys_types,                 ONLY: qs_subsys_get,&
      70              :                                               qs_subsys_type
      71              :    USE rpa_util,                        ONLY: calc_fm_mat_S_rpa,&
      72              :                                               remove_scaling_factor_rpa
      73              :    USE scf_control_types,               ONLY: scf_control_type
      74              : #include "./base/base_uses.f90"
      75              : 
      76              :    IMPLICIT NONE
      77              : 
      78              :    PRIVATE
      79              : 
      80              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'rpa_exchange'
      81              : 
      82              :    PUBLIC :: rpa_exchange_work_type, rpa_exchange_needed_mem
      83              : 
      84              :    TYPE rpa_exchange_env_type
      85              :       PRIVATE
      86              :       TYPE(qs_environment_type), POINTER             :: qs_env => NULL()
      87              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER      :: mat_hfx => NULL()
      88              :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER      :: dbcsr_Gamma_munu_P => NULL()
      89              :       TYPE(dbcsr_type), ALLOCATABLE, DIMENSION(:)    :: dbcsr_Gamma_inu_P
      90              :       ! Workaround GCC 8
      91              :       TYPE(dbcsr_type), DIMENSION(:), POINTER :: mo_coeff_o => NULL()
      92              :       TYPE(dbcsr_type), DIMENSION(:), POINTER :: mo_coeff_v => NULL()
      93              :       TYPE(dbcsr_type)                               :: work_ao
      94              :       TYPE(hfx_type), DIMENSION(:, :), POINTER       :: x_data => NULL()
      95              :       TYPE(mp_para_env_type), POINTER                :: para_env => NULL()
      96              :       TYPE(section_vals_type), POINTER               :: hfx_sections => NULL()
      97              :       LOGICAL :: my_recalc_hfx_integrals = .FALSE.
      98              :       REAL(KIND=dp) :: eps_filter = 0.0_dp
      99              :       TYPE(cp_fm_struct_p_type), DIMENSION(:), ALLOCATABLE :: struct_Gamma
     100              :    CONTAINS
     101              :       PROCEDURE, PASS(exchange_env), NON_OVERRIDABLE :: create => hfx_create_subgroup
     102              :       !PROCEDURE, PASS(exchange_env), NON_OVERRIDABLE :: integrate => integrate_exchange
     103              :       PROCEDURE, PASS(exchange_env), NON_OVERRIDABLE :: release => hfx_release_subgroup
     104              :    END TYPE rpa_exchange_env_type
     105              : 
     106              :    TYPE dbcsr_matrix_p_set
     107              :       TYPE(dbcsr_type), ALLOCATABLE, DIMENSION(:) :: matrix_set
     108              :    END TYPE dbcsr_matrix_p_set
     109              : 
     110              :    TYPE rpa_exchange_work_type
     111              :       PRIVATE
     112              :       INTEGER :: exchange_correction = rpa_exchange_none
     113              :       TYPE(rpa_exchange_env_type) :: exchange_env
     114              :       INTEGER, DIMENSION(:), ALLOCATABLE :: homo, virtual, dimen_ia
     115              :       TYPE(group_dist_d1_type) :: aux_func_dist = group_dist_d1_type()
     116              :       INTEGER, DIMENSION(:), ALLOCATABLE :: aux2send
     117              :       INTEGER :: dimen_RI = 0
     118              :       INTEGER :: block_size = 0
     119              :       INTEGER :: color_sub = 0
     120              :       INTEGER :: ngroup = 0
     121              :       TYPE(cp_fm_type) :: fm_mat_Q_tmp = cp_fm_type()
     122              :       TYPE(cp_fm_type) :: fm_mat_R_half_gemm = cp_fm_type()
     123              :       TYPE(cp_fm_type) :: fm_mat_U = cp_fm_type()
     124              :       TYPE(mp_para_env_type), POINTER :: para_env_sub => NULL()
     125              :    CONTAINS
     126              :       PROCEDURE, PUBLIC, PASS(exchange_work), NON_OVERRIDABLE :: create => rpa_exchange_work_create
     127              :       PROCEDURE, PUBLIC, PASS(exchange_work), NON_OVERRIDABLE :: compute => rpa_exchange_work_compute
     128              :       PROCEDURE, PUBLIC, PASS(exchange_work), NON_OVERRIDABLE :: release => rpa_exchange_work_release
     129              :       PROCEDURE, PRIVATE, PASS(exchange_work), NON_OVERRIDABLE :: redistribute_into_subgroups
     130              :       PROCEDURE, PRIVATE, PASS(exchange_work), NON_OVERRIDABLE :: compute_fm => rpa_exchange_work_compute_fm
     131              :       PROCEDURE, PRIVATE, PASS(exchange_work), NON_OVERRIDABLE :: compute_hfx => rpa_exchange_work_compute_hfx
     132              :    END TYPE rpa_exchange_work_type
     133              : 
     134              : CONTAINS
     135              : 
     136              : ! **************************************************************************************************
     137              : !> \brief ...
     138              : !> \param mp2_env ...
     139              : !> \param homo ...
     140              : !> \param virtual ...
     141              : !> \param dimen_RI ...
     142              : !> \param para_env ...
     143              : !> \param mem_per_rank ...
     144              : !> \param mem_per_repl ...
     145              : ! **************************************************************************************************
     146          140 :    SUBROUTINE rpa_exchange_needed_mem(mp2_env, homo, virtual, dimen_RI, para_env, mem_per_rank, mem_per_repl)
     147              :       TYPE(mp2_type), INTENT(IN)                         :: mp2_env
     148              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
     149              :       INTEGER, INTENT(IN)                                :: dimen_RI
     150              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
     151              :       REAL(KIND=dp), INTENT(INOUT)                       :: mem_per_rank, mem_per_repl
     152              : 
     153              :       INTEGER                                            :: block_size
     154              : 
     155              :       ! We need the block size and if it is unknown, an upper bound
     156          140 :       block_size = mp2_env%ri_rpa%exchange_block_size
     157          140 :       IF (block_size <= 0) block_size = MAX(1, (dimen_RI + para_env%num_pe - 1)/para_env%num_pe)
     158              : 
     159              :       ! storage of product matrix (upper bound only as it depends on the square of the potential still unknown block size)
     160          310 :       mem_per_rank = mem_per_rank + REAL(MAXVAL(homo), KIND=dp)**2*block_size**2*8.0_dp/(1024_dp**2)
     161              : 
     162              :       ! work arrays R (2x) and U, copies of Gamma (2x), communication buffer (as expensive as Gamma)
     163              :       mem_per_repl = mem_per_repl + 3.0_dp*dimen_RI*dimen_RI*8.0_dp/(1024_dp**2) &
     164          310 :                      + 3.0_dp*MAXVAL(homo*virtual)*dimen_RI*8.0_dp/(1024_dp**2)
     165          140 :    END SUBROUTINE rpa_exchange_needed_mem
     166              : 
     167              : ! **************************************************************************************************
     168              : !> \brief ...
     169              : !> \param exchange_work ...
     170              : !> \param qs_env ...
     171              : !> \param para_env_sub ...
     172              : !> \param mat_munu ...
     173              : !> \param dimen_RI ...
     174              : !> \param fm_mat_S ...
     175              : !> \param fm_mat_Q ...
     176              : !> \param fm_mat_Q_gemm ...
     177              : !> \param homo ...
     178              : !> \param virtual ...
     179              : ! **************************************************************************************************
     180          170 :    SUBROUTINE rpa_exchange_work_create(exchange_work, qs_env, para_env_sub, mat_munu, dimen_RI, &
     181          170 :                                        fm_mat_S, fm_mat_Q, fm_mat_Q_gemm, homo, virtual)
     182              :       CLASS(rpa_exchange_work_type), INTENT(INOUT) :: exchange_work
     183              :       TYPE(qs_environment_type), POINTER :: qs_env
     184              :       TYPE(mp_para_env_type), POINTER, INTENT(IN) :: para_env_sub
     185              :       TYPE(dbcsr_p_type), INTENT(IN) :: mat_munu
     186              :       INTEGER, INTENT(IN) :: dimen_RI
     187              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: fm_mat_S
     188              :       TYPE(cp_fm_type), INTENT(IN) :: fm_mat_Q, fm_mat_Q_gemm
     189              :       INTEGER, DIMENSION(SIZE(fm_mat_S)), INTENT(IN) :: homo, virtual
     190              : 
     191              :       INTEGER :: nspins, aux_global, aux_local, my_process_row, proc, ispin
     192          170 :       INTEGER, DIMENSION(:), POINTER :: row_indices, aux_distribution_fm
     193              :       TYPE(cp_blacs_env_type), POINTER :: context
     194              : 
     195          170 :       exchange_work%exchange_correction = qs_env%mp2_env%ri_rpa%exchange_correction
     196              : 
     197          170 :       IF (exchange_work%exchange_correction == rpa_exchange_none) RETURN
     198              : 
     199              :       ASSOCIATE (para_env => fm_mat_S(1)%matrix_struct%para_env)
     200           12 :          exchange_work%para_env_sub => para_env_sub
     201           12 :          exchange_work%ngroup = para_env%num_pe/para_env_sub%num_pe
     202           12 :          exchange_work%color_sub = para_env%mepos/para_env_sub%num_pe
     203              :       END ASSOCIATE
     204              : 
     205           12 :       CALL cp_fm_get_info(fm_mat_S(1), row_indices=row_indices, nrow_locals=aux_distribution_fm, context=context)
     206           12 :       CALL context%get(my_process_row=my_process_row)
     207              : 
     208           12 :       CALL create_group_dist(exchange_work%aux_func_dist, exchange_work%ngroup, dimen_RI)
     209           36 :       ALLOCATE (exchange_work%aux2send(0:exchange_work%ngroup - 1))
     210           36 :       exchange_work%aux2send = 0
     211          499 :       DO aux_local = 1, aux_distribution_fm(my_process_row)
     212          487 :          aux_global = row_indices(aux_local)
     213          487 :          proc = group_dist_proc(exchange_work%aux_func_dist, aux_global)
     214          499 :          exchange_work%aux2send(proc) = exchange_work%aux2send(proc) + 1
     215              :       END DO
     216              : 
     217           12 :       nspins = SIZE(fm_mat_S)
     218              : 
     219           60 :       ALLOCATE (exchange_work%homo(nspins), exchange_work%virtual(nspins), exchange_work%dimen_ia(nspins))
     220           26 :       exchange_work%homo(:) = homo
     221           26 :       exchange_work%virtual(:) = virtual
     222           26 :       exchange_work%dimen_ia(:) = homo*virtual
     223           12 :       exchange_work%dimen_RI = dimen_RI
     224              : 
     225           12 :       exchange_work%block_size = qs_env%mp2_env%ri_rpa%exchange_block_size
     226           12 :       IF (exchange_work%block_size <= 0) exchange_work%block_size = dimen_RI
     227              : 
     228           12 :       CALL cp_fm_create(exchange_work%fm_mat_U, fm_mat_Q%matrix_struct, name="fm_mat_U")
     229           12 :       CALL cp_fm_create(exchange_work%fm_mat_Q_tmp, fm_mat_Q%matrix_struct, name="fm_mat_Q_tmp")
     230           12 :       CALL cp_fm_create(exchange_work%fm_mat_R_half_gemm, fm_mat_Q_gemm%matrix_struct)
     231              : 
     232           12 :       IF (qs_env%mp2_env%ri_rpa%use_hfx_implementation) THEN
     233            2 :          CALL exchange_work%exchange_env%create(qs_env, mat_munu%matrix, para_env_sub, fm_mat_S)
     234              :       END IF
     235              : 
     236           12 :       IF (ASSOCIATED(qs_env%mp2_env%ri_rpa%mo_coeff_o)) THEN
     237           22 :          DO ispin = 1, SIZE(qs_env%mp2_env%ri_rpa%mo_coeff_o)
     238           22 :             CALL dbcsr_release(qs_env%mp2_env%ri_rpa%mo_coeff_o(ispin))
     239              :          END DO
     240           10 :          DEALLOCATE (qs_env%mp2_env%ri_rpa%mo_coeff_o)
     241              :       END IF
     242              : 
     243           12 :       IF (ASSOCIATED(qs_env%mp2_env%ri_rpa%mo_coeff_v)) THEN
     244           22 :          DO ispin = 1, SIZE(qs_env%mp2_env%ri_rpa%mo_coeff_v)
     245           22 :             CALL dbcsr_release(qs_env%mp2_env%ri_rpa%mo_coeff_v(ispin))
     246              :          END DO
     247           10 :          DEALLOCATE (qs_env%mp2_env%ri_rpa%mo_coeff_v)
     248              :       END IF
     249          170 :    END SUBROUTINE rpa_exchange_work_create
     250              : 
     251              : ! **************************************************************************************************
     252              : !> \brief ... Initializes x_data on a subgroup
     253              : !> \param exchange_env ...
     254              : !> \param qs_env ...
     255              : !> \param mat_munu ...
     256              : !> \param para_env_sub ...
     257              : !> \param fm_mat_S ...
     258              : !> \author Vladimir Rybkin
     259              : ! **************************************************************************************************
     260            2 :    SUBROUTINE hfx_create_subgroup(exchange_env, qs_env, mat_munu, para_env_sub, fm_mat_S)
     261              :       CLASS(rpa_exchange_env_type), INTENT(INOUT) :: exchange_env
     262              :       TYPE(dbcsr_type), INTENT(IN) :: mat_munu
     263              :       TYPE(qs_environment_type), POINTER   :: qs_env
     264              :       TYPE(mp_para_env_type), POINTER, INTENT(IN)            :: para_env_sub
     265              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: fm_mat_S
     266              : 
     267              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'hfx_create_subgroup'
     268              : 
     269              :       INTEGER                                            :: handle, nelectron_total, ispin, &
     270              :                                                             number_of_aos, nspins, dimen_RI, dimen_ia
     271            2 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     272              :       TYPE(cell_type), POINTER                           :: my_cell
     273              :       TYPE(dft_control_type), POINTER                    :: dft_control
     274            2 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     275            2 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     276              :       TYPE(qs_subsys_type), POINTER                      :: subsys
     277              :       TYPE(scf_control_type), POINTER                    :: scf_control
     278              :       TYPE(section_vals_type), POINTER                   :: input
     279              : 
     280            2 :       CALL timeset(routineN, handle)
     281              : 
     282            2 :       exchange_env%mo_coeff_o => qs_env%mp2_env%ri_rpa%mo_coeff_o
     283            2 :       exchange_env%mo_coeff_v => qs_env%mp2_env%ri_rpa%mo_coeff_v
     284            2 :       NULLIFY (qs_env%mp2_env%ri_rpa%mo_coeff_o, qs_env%mp2_env%ri_rpa%mo_coeff_v)
     285              : 
     286            2 :       nspins = SIZE(exchange_env%mo_coeff_o)
     287              : 
     288            2 :       exchange_env%qs_env => qs_env
     289            2 :       exchange_env%para_env => para_env_sub
     290            2 :       exchange_env%eps_filter = qs_env%mp2_env%mp2_gpw%eps_filter
     291              : 
     292            2 :       NULLIFY (my_cell, atomic_kind_set, particle_set, dft_control, qs_kind_set, scf_control)
     293              : 
     294              :       CALL get_qs_env(qs_env, &
     295              :                       subsys=subsys, &
     296              :                       input=input, &
     297              :                       scf_control=scf_control, &
     298            2 :                       nelectron_total=nelectron_total)
     299              : 
     300              :       CALL qs_subsys_get(subsys, &
     301              :                          cell=my_cell, &
     302              :                          atomic_kind_set=atomic_kind_set, &
     303              :                          qs_kind_set=qs_kind_set, &
     304            2 :                          particle_set=particle_set)
     305              : 
     306            2 :       exchange_env%hfx_sections => section_vals_get_subs_vals(input, "DFT%XC%WF_CORRELATION%RI_RPA%HF")
     307            2 :       CALL get_qs_env(qs_env, dft_control=dft_control)
     308              : 
     309              :       ! Retrieve particle_set and atomic_kind_set
     310              :       CALL hfx_create(exchange_env%x_data, para_env_sub, exchange_env%hfx_sections, atomic_kind_set, &
     311              :                       qs_kind_set, particle_set, dft_control, my_cell, orb_basis='ORB', &
     312            2 :                       nelectron_total=nelectron_total)
     313              : 
     314            2 :       exchange_env%my_recalc_hfx_integrals = .TRUE.
     315              : 
     316            2 :       CALL dbcsr_allocate_matrix_set(exchange_env%mat_hfx, nspins)
     317            4 :       DO ispin = 1, nspins
     318            2 :          ALLOCATE (exchange_env%mat_hfx(ispin)%matrix)
     319            2 :          CALL dbcsr_init_p(exchange_env%mat_hfx(ispin)%matrix)
     320              :          CALL dbcsr_create(exchange_env%mat_hfx(ispin)%matrix, template=mat_munu, &
     321            2 :                            matrix_type=dbcsr_type_no_symmetry)
     322            4 :          CALL dbcsr_copy(exchange_env%mat_hfx(ispin)%matrix, mat_munu)
     323              :       END DO
     324              : 
     325            2 :       CALL dbcsr_get_info(mat_munu, nfullcols_total=number_of_aos)
     326              : 
     327              :       CALL dbcsr_create(exchange_env%work_ao, template=mat_munu, &
     328            2 :                         matrix_type=dbcsr_type_no_symmetry)
     329              : 
     330            8 :       ALLOCATE (exchange_env%dbcsr_Gamma_inu_P(nspins))
     331            2 :       CALL dbcsr_allocate_matrix_set(exchange_env%dbcsr_Gamma_munu_P, nspins)
     332            4 :       DO ispin = 1, nspins
     333            2 :          ALLOCATE (exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix)
     334              :          CALL dbcsr_create(exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix, template=mat_munu, &
     335            2 :                            matrix_type=dbcsr_type_no_symmetry)
     336            2 :          CALL dbcsr_copy(exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix, mat_munu)
     337            2 :          CALL dbcsr_set(exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix, 0.0_dp)
     338              : 
     339            2 :          CALL dbcsr_create(exchange_env%dbcsr_Gamma_inu_P(ispin), template=exchange_env%mo_coeff_o(ispin))
     340            2 :          CALL dbcsr_copy(exchange_env%dbcsr_Gamma_inu_P(ispin), exchange_env%mo_coeff_o(ispin))
     341            4 :          CALL dbcsr_set(exchange_env%dbcsr_Gamma_inu_P(ispin), 0.0_dp)
     342              :       END DO
     343              : 
     344            8 :       ALLOCATE (exchange_env%struct_Gamma(nspins))
     345            4 :       DO ispin = 1, nspins
     346            2 :          CALL cp_fm_get_info(fm_mat_S(ispin), nrow_global=dimen_RI, ncol_global=dimen_ia)
     347              :          CALL cp_fm_struct_create(exchange_env%struct_Gamma(ispin)%struct, template_fmstruct=fm_mat_S(ispin)%matrix_struct, &
     348            4 :                                   nrow_global=dimen_ia, ncol_global=dimen_RI)
     349              :       END DO
     350              : 
     351            2 :       CALL timestop(handle)
     352              : 
     353            4 :    END SUBROUTINE hfx_create_subgroup
     354              : 
     355              : ! **************************************************************************************************
     356              : !> \brief ...
     357              : !> \param exchange_work ...
     358              : ! **************************************************************************************************
     359          170 :    SUBROUTINE rpa_exchange_work_release(exchange_work)
     360              :       CLASS(rpa_exchange_work_type), INTENT(INOUT) :: exchange_work
     361              : 
     362          170 :       IF (ALLOCATED(exchange_work%homo)) DEALLOCATE (exchange_work%homo)
     363          170 :       IF (ALLOCATED(exchange_work%virtual)) DEALLOCATE (exchange_work%virtual)
     364          170 :       IF (ALLOCATED(exchange_work%dimen_ia)) DEALLOCATE (exchange_work%dimen_ia)
     365          170 :       NULLIFY (exchange_work%para_env_sub)
     366          170 :       CALL release_group_dist(exchange_work%aux_func_dist)
     367          170 :       IF (ALLOCATED(exchange_work%aux2send)) DEALLOCATE (exchange_work%aux2send)
     368          170 :       CALL cp_fm_release(exchange_work%fm_mat_Q_tmp)
     369          170 :       CALL cp_fm_release(exchange_work%fm_mat_U)
     370          170 :       CALL cp_fm_release(exchange_work%fm_mat_R_half_gemm)
     371              : 
     372          170 :       CALL exchange_work%exchange_env%release()
     373          170 :    END SUBROUTINE rpa_exchange_work_release
     374              : 
     375              : ! **************************************************************************************************
     376              : !> \brief ...
     377              : !> \param exchange_env ...
     378              : ! **************************************************************************************************
     379          170 :    SUBROUTINE hfx_release_subgroup(exchange_env)
     380              :       CLASS(rpa_exchange_env_type), INTENT(INOUT) :: exchange_env
     381              : 
     382              :       INTEGER :: ispin
     383              : 
     384          170 :       NULLIFY (exchange_env%para_env, exchange_env%hfx_sections)
     385              : 
     386          170 :       IF (ASSOCIATED(exchange_env%x_data)) THEN
     387            2 :          CALL hfx_release(exchange_env%x_data)
     388            2 :          NULLIFY (exchange_env%x_data)
     389              :       END IF
     390              : 
     391          170 :       CALL dbcsr_release(exchange_env%work_ao)
     392              : 
     393          170 :       IF (ASSOCIATED(exchange_env%dbcsr_Gamma_munu_P)) THEN
     394            4 :          DO ispin = 1, SIZE(exchange_env%mat_hfx, 1)
     395            2 :             CALL dbcsr_release(exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix)
     396            2 :             CALL dbcsr_release(exchange_env%mat_hfx(ispin)%matrix)
     397            2 :             CALL dbcsr_release(exchange_env%dbcsr_Gamma_inu_P(ispin))
     398            2 :             CALL dbcsr_release(exchange_env%mo_coeff_o(ispin))
     399            2 :             CALL dbcsr_release(exchange_env%mo_coeff_v(ispin))
     400            2 :             DEALLOCATE (exchange_env%mat_hfx(ispin)%matrix)
     401            4 :             DEALLOCATE (exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix)
     402              :          END DO
     403            2 :          DEALLOCATE (exchange_env%mat_hfx, exchange_env%dbcsr_Gamma_munu_P)
     404            2 :          DEALLOCATE (exchange_env%dbcsr_Gamma_inu_P, exchange_env%mo_coeff_o, exchange_env%mo_coeff_v)
     405            2 :          NULLIFY (exchange_env%mat_hfx, exchange_env%dbcsr_Gamma_munu_P)
     406              :       END IF
     407          170 :       IF (ALLOCATED(exchange_env%struct_Gamma)) THEN
     408            4 :       DO ispin = 1, SIZE(exchange_env%struct_Gamma)
     409            4 :          CALL cp_fm_struct_release(exchange_env%struct_Gamma(ispin)%struct)
     410              :       END DO
     411            2 :       DEALLOCATE (exchange_env%struct_Gamma)
     412              :       END IF
     413          170 :    END SUBROUTINE hfx_release_subgroup
     414              : 
     415              : ! **************************************************************************************************
     416              : !> \brief Main driver for RPA-exchange energies
     417              : !> \param exchange_work ...
     418              : !> \param fm_mat_Q ...
     419              : !> \param eig ...
     420              : !> \param fm_mat_S ...
     421              : !> \param omega ...
     422              : !> \param e_exchange_corr exchange energy correction for a quadrature point
     423              : !> \param mp2_env ...
     424              : !> \author Vladimir Rybkin, 07/2016
     425              : ! **************************************************************************************************
     426           12 :    SUBROUTINE rpa_exchange_work_compute(exchange_work, fm_mat_Q, eig, fm_mat_S, omega, &
     427              :                                         e_exchange_corr, mp2_env)
     428              :       CLASS(rpa_exchange_work_type), INTENT(INOUT) :: exchange_work
     429              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_Q
     430              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: eig
     431              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)         :: fm_mat_S
     432              :       REAL(KIND=dp), INTENT(IN)                          :: omega
     433              :       REAL(KIND=dp), INTENT(INOUT)                       :: e_exchange_corr
     434              :       TYPE(mp2_type), INTENT(INOUT) :: mp2_env
     435              : 
     436              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rpa_exchange_work_compute'
     437              :       REAL(KIND=dp), PARAMETER                           :: thresh = 0.0000001_dp
     438              : 
     439              :       INTEGER :: handle, nspins, dimen_RI, iiB
     440           12 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: eigenval
     441              : 
     442           12 :       IF (exchange_work%exchange_correction == rpa_exchange_none) RETURN
     443              : 
     444           12 :       CALL timeset(routineN, handle)
     445              : 
     446           12 :       CALL cp_fm_get_info(fm_mat_Q, ncol_global=dimen_RI)
     447              : 
     448           12 :       nspins = SIZE(fm_mat_S)
     449              : 
     450              :       ! Eigenvalues
     451           36 :       ALLOCATE (eigenval(dimen_RI))
     452           12 :       eigenval = 0.0_dp
     453              : 
     454           12 :       CALL cp_fm_set_all(matrix=exchange_work%fm_mat_Q_tmp, alpha=0.0_dp)
     455           12 :       CALL cp_fm_set_all(matrix=exchange_work%fm_mat_U, alpha=0.0_dp)
     456              : 
     457              :       ! Copy Q to Q_tmp
     458           12 :       CALL cp_fm_to_fm(fm_mat_Q, exchange_work%fm_mat_Q_tmp)
     459              :       ! Diagonalize Q
     460           12 :       CALL choose_eigv_solver(exchange_work%fm_mat_Q_tmp, exchange_work%fm_mat_U, eigenval)
     461              : 
     462              :       ! Calculate diagonal matrix for R_half
     463              : 
     464              :       ! Manipulate eigenvalues to get diagonal matrix
     465           12 :       IF (exchange_work%exchange_correction == rpa_exchange_axk) THEN
     466          818 :          DO iib = 1, dimen_RI
     467          818 :             IF (ABS(eigenval(iib)) >= thresh) THEN
     468              :                eigenval(iib) = &
     469              :                   SQRT((1.0_dp/(eigenval(iib)**2))*LOG(1.0_dp + eigenval(iib)) &
     470          718 :                        - 1.0_dp/(eigenval(iib)*(eigenval(iib) + 1.0_dp)))
     471              :             ELSE
     472           90 :                eigenval(iib) = sqrthalf
     473              :             END IF
     474              :          END DO
     475            2 :       ELSE IF (exchange_work%exchange_correction == rpa_exchange_sosex) THEN
     476          168 :          DO iib = 1, dimen_RI
     477          168 :             IF (ABS(eigenval(iib)) >= thresh) THEN
     478              :                eigenval(iib) = &
     479              :                   SQRT(-(1.0_dp/(eigenval(iib)**2))*LOG(1.0_dp + eigenval(iib)) &
     480          144 :                        + 1.0_dp/eigenval(iib))
     481              :             ELSE
     482           22 :                eigenval(iib) = sqrthalf
     483              :             END IF
     484              :          END DO
     485              :       ELSE
     486            0 :          CPABORT("Unknown RPA exchange correction")
     487              :       END IF
     488              : 
     489              :       ! fm_mat_U now contains some sqrt of the required matrix-valued function
     490           12 :       CALL cp_fm_column_scale(exchange_work%fm_mat_U, eigenval)
     491              : 
     492              :       ! Release memory
     493           12 :       DEALLOCATE (eigenval)
     494              : 
     495              :       ! Redistribute fm_mat_U for "rectangular" multiplication: ia*P P*P
     496           12 :       CALL cp_fm_set_all(matrix=exchange_work%fm_mat_R_half_gemm, alpha=0.0_dp)
     497              : 
     498              :       CALL cp_fm_to_fm_submat_general(exchange_work%fm_mat_U, exchange_work%fm_mat_R_half_gemm, dimen_RI, &
     499           12 :                                       dimen_RI, 1, 1, 1, 1, exchange_work%fm_mat_U%matrix_struct%context)
     500              : 
     501           12 :       IF (mp2_env%ri_rpa%use_hfx_implementation) THEN
     502            2 :          CALL exchange_work%compute_hfx(fm_mat_S, eig, omega, e_exchange_corr)
     503              :       ELSE
     504           10 :          CALL exchange_work%compute_fm(fm_mat_S, eig, omega, e_exchange_corr, mp2_env)
     505              :       END IF
     506              : 
     507           12 :       CALL timestop(handle)
     508              : 
     509           12 :    END SUBROUTINE rpa_exchange_work_compute
     510              : 
     511              : ! **************************************************************************************************
     512              : !> \brief Main driver for RPA-exchange energies
     513              : !> \param exchange_work ...
     514              : !> \param fm_mat_S ...
     515              : !> \param eig ...
     516              : !> \param omega ...
     517              : !> \param e_exchange_corr exchange energy correction for a quadrature point
     518              : !> \param mp2_env ...
     519              : !> \author Frederick Stein, May-June 2024
     520              : ! **************************************************************************************************
     521           10 :    SUBROUTINE rpa_exchange_work_compute_fm(exchange_work, fm_mat_S, eig, omega, &
     522              :                                            e_exchange_corr, mp2_env)
     523              :       CLASS(rpa_exchange_work_type), INTENT(INOUT) :: exchange_work
     524              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S
     525              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: eig
     526              :       REAL(KIND=dp), INTENT(IN)                          :: omega
     527              :       REAL(KIND=dp), INTENT(INOUT)                       :: e_exchange_corr
     528              :       TYPE(mp2_type), INTENT(INOUT) :: mp2_env
     529              : 
     530              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'rpa_exchange_work_compute_fm'
     531              : 
     532              :       INTEGER :: handle, ispin, nspins, P, Q, L_size_Gamma, hom, virt, i, &
     533              :                  send_proc, recv_proc, recv_size, max_aux_size, proc_shift, dimen_ia, &
     534              :                  block_size, P_start, P_end, P_size, Q_start, Q_size, Q_end, handle2, my_aux_size, my_virt
     535           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), TARGET :: mat_Gamma_3_3D
     536           10 :       REAL(KIND=dp), POINTER, DIMENSION(:), CONTIGUOUS :: mat_Gamma_3_1D
     537           10 :       REAL(KIND=dp), POINTER, DIMENSION(:, :), CONTIGUOUS :: mat_Gamma_3_2D
     538           10 :       REAL(KIND=dp), ALLOCATABLE, TARGET, DIMENSION(:) :: recv_buffer_1D
     539           10 :       REAL(KIND=dp), POINTER, DIMENSION(:, :), CONTIGUOUS :: recv_buffer_2D
     540           10 :       REAL(KIND=dp), POINTER, DIMENSION(:, :, :), CONTIGUOUS :: recv_buffer_3D
     541           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: mat_B_iaP
     542           10 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), TARGET :: product_matrix_1D
     543           10 :       REAL(KIND=dp), POINTER, DIMENSION(:, :), CONTIGUOUS :: product_matrix_2D
     544           10 :       REAL(KIND=dp), POINTER, DIMENSION(:, :, :, :), CONTIGUOUS :: product_matrix_4D
     545              :       TYPE(cp_fm_type)        :: fm_mat_Gamma_3
     546              :       TYPE(mp_para_env_type), POINTER :: para_env
     547           10 :       TYPE(group_dist_d1_type)                           :: virt_dist
     548              : 
     549           10 :       CALL timeset(routineN, handle)
     550              : 
     551           10 :       nspins = SIZE(fm_mat_S)
     552              : 
     553           10 :       CALL get_group_dist(exchange_work%aux_func_dist, exchange_work%color_sub, sizes=my_aux_size)
     554              : 
     555           10 :       e_exchange_corr = 0.0_dp
     556           10 :       max_aux_size = maxsize(exchange_work%aux_func_dist)
     557              : 
     558              :       ! local_gemm_ctx has a very large footprint the first time this routine is
     559              :       ! called.
     560           10 :       CALL mp2_env%local_gemm_ctx%create(LOCAL_GEMM_PU_GPU)
     561           10 :       CALL mp2_env%local_gemm_ctx%set_op_threshold_gpu(128*128*128*2)
     562              : 
     563           22 :       DO ispin = 1, nspins
     564           12 :          hom = exchange_work%homo(ispin)
     565           12 :          virt = exchange_work%virtual(ispin)
     566           12 :          dimen_ia = hom*virt
     567           12 :          IF (hom < 1 .OR. virt < 1) CYCLE
     568              : 
     569           12 :          CALL cp_fm_get_info(fm_mat_S(ispin), para_env=para_env)
     570              : 
     571           12 :          CALL cp_fm_create(fm_mat_Gamma_3, fm_mat_S(ispin)%matrix_struct)
     572           12 :          CALL cp_fm_set_all(matrix=fm_mat_Gamma_3, alpha=0.0_dp)
     573              : 
     574              :          ! Update G with a new value of Omega: in practice, it is G*S
     575              : 
     576              :          ! Scale fm_work_iaP
     577              :          CALL calc_fm_mat_S_rpa(fm_mat_S(ispin), .TRUE., virt, eig(:, ispin), &
     578           12 :                                 hom, omega, 0.0_dp)
     579              : 
     580              :          ! Calculate Gamma_3: Gamma_3 = G*S*R^(1/2) = G*S*R^(1/2)
     581              :          CALL parallel_gemm(transa="T", transb="N", m=exchange_work%dimen_RI, n=dimen_ia, k=exchange_work%dimen_RI, alpha=1.0_dp, &
     582              :                             matrix_a=exchange_work%fm_mat_R_half_gemm, matrix_b=fm_mat_S(ispin), beta=0.0_dp, &
     583           12 :                             matrix_c=fm_mat_Gamma_3)
     584              : 
     585           12 :          CALL create_group_dist(virt_dist, exchange_work%para_env_sub%num_pe, virt)
     586              : 
     587              :          ! Remove extra factor from S after the multiplication (to return to the original matrix)
     588           12 :          CALL remove_scaling_factor_rpa(fm_mat_S(ispin), virt, eig(:, ispin), hom, omega)
     589              : 
     590           12 :          CALL exchange_work%redistribute_into_subgroups(fm_mat_Gamma_3, mat_Gamma_3_3D, ispin, virt_dist)
     591           12 :          CALL cp_fm_release(fm_mat_Gamma_3)
     592              : 
     593              :          ! We need only the pure matrix
     594           12 :          CALL remove_scaling_factor_rpa(fm_mat_S(ispin), virt, eig(:, ispin), hom, omega)
     595              : 
     596              :          ! Reorder matrix from (P, i*a) -> (a, i, P) with P being distributed within subgroups
     597           12 :          CALL exchange_work%redistribute_into_subgroups(fm_mat_S(ispin), mat_B_iaP, ispin, virt_dist)
     598              : 
     599              :          ! Return to the original tensor
     600           12 :          CALL calc_fm_mat_S_rpa(fm_mat_S(ispin), .TRUE., virt, eig(:, ispin), hom, omega, 0.0_dp)
     601              : 
     602           12 :          L_size_Gamma = SIZE(mat_Gamma_3_3D, 3)
     603           12 :          my_virt = SIZE(mat_Gamma_3_3D, 1)
     604           12 :          block_size = exchange_work%block_size
     605              : 
     606           12 :          mat_Gamma_3_1D(1:INT(my_virt, KIND=int_8)*hom*my_aux_size) => mat_Gamma_3_3D(:, :, 1:my_aux_size)
     607           12 :          mat_Gamma_3_2D(1:my_virt, 1:hom*my_aux_size) => mat_Gamma_3_1D(1:INT(my_virt, KIND=int_8)*hom*my_aux_size)
     608              : 
     609            0 :          ALLOCATE (product_matrix_1D(INT(hom*MIN(block_size, L_size_gamma), KIND=int_8)* &
     610           36 :                                      INT(hom*MIN(block_size, max_aux_size), KIND=int_8)))
     611           36 :          ALLOCATE (recv_buffer_1D(INT(virt, KIND=int_8)*hom*max_aux_size))
     612           12 :          recv_buffer_2D(1:my_virt, 1:hom*max_aux_size) => recv_buffer_1D(1:INT(virt, KIND=int_8)*hom*max_aux_size)
     613           12 :          recv_buffer_3D(1:my_virt, 1:hom, 1:max_aux_size) => recv_buffer_1D(1:INT(virt, KIND=int_8)*hom*max_aux_size)
     614           36 :          DO proc_shift = 0, para_env%num_pe - 1, exchange_work%para_env_sub%num_pe
     615           24 :             send_proc = MODULO(para_env%mepos + proc_shift, para_env%num_pe)
     616           24 :             recv_proc = MODULO(para_env%mepos - proc_shift, para_env%num_pe)
     617              : 
     618           24 :             CALL get_group_dist(exchange_work%aux_func_dist, recv_proc/exchange_work%para_env_sub%num_pe, sizes=recv_size)
     619              : 
     620           24 :             IF (recv_size == 0) recv_proc = mp_proc_null
     621              : 
     622           24 :             CALL para_env%sendrecv(mat_B_iaP, send_proc, recv_buffer_3D(:, :, 1:recv_size), recv_proc)
     623              : 
     624           24 :             IF (recv_size == 0) CYCLE
     625              : 
     626         1038 :             DO P_start = 1, L_size_Gamma, block_size
     627         1002 :                P_end = MIN(L_size_Gamma, P_start + block_size - 1)
     628         1002 :                P_size = P_end - P_start + 1
     629        43875 :                DO Q_start = 1, recv_size, block_size
     630        42849 :                   Q_end = MIN(recv_size, Q_start + block_size - 1)
     631        42849 :                   Q_size = Q_end - Q_start + 1
     632              : 
     633              :                   ! Reassign product_matrix pointers to enforce contiguity of target array
     634              :                   product_matrix_2D(1:hom*P_size, 1:hom*Q_size) => &
     635        42849 :                      product_matrix_1D(1:INT(hom*P_size, KIND=int_8)*INT(hom*Q_size, KIND=int_8))
     636              :                   product_matrix_4D(1:hom, 1:P_size, 1:hom, 1:Q_size) => &
     637        42849 :                      product_matrix_1D(1:INT(hom*P_size, KIND=int_8)*INT(hom*Q_size, KIND=int_8))
     638              : 
     639        42849 :                   CALL timeset(routineN//"_gemm", handle2)
     640              :                   CALL mp2_env%local_gemm_ctx%gemm("T", "N", hom*P_size, hom*Q_size, my_virt, 1.0_dp, &
     641              :                                                    mat_Gamma_3_2D(:, hom*(P_start - 1) + 1:hom*P_end), my_virt, &
     642              :                                                    recv_buffer_2D(:, hom*(Q_start - 1) + 1:hom*Q_end), my_virt, &
     643        42849 :                                                    0.0_dp, product_matrix_2D, hom*P_size)
     644        42849 :                   CALL timestop(handle2)
     645              : 
     646        42849 :                   CALL timeset(routineN//"_energy", handle2)
     647              : !$OMP PARALLEL DO DEFAULT(NONE) SHARED(P_size, Q_size, hom, product_matrix_4D) &
     648        42849 : !$OMP             COLLAPSE(3) REDUCTION(+: e_exchange_corr) PRIVATE(P, Q, i)
     649              :                   DO P = 1, P_size
     650              :                   DO Q = 1, Q_size
     651              :                   DO i = 1, hom
     652              :                      e_exchange_corr = e_exchange_corr + DOT_PRODUCT(product_matrix_4D(i, P, :, Q), product_matrix_4D(:, P, i, Q))
     653              :                   END DO
     654              :                   END DO
     655              :                   END DO
     656        86700 :                   CALL timestop(handle2)
     657              :                END DO
     658              :             END DO
     659              :          END DO
     660              : 
     661           12 :          CALL release_group_dist(virt_dist)
     662           12 :          IF (ALLOCATED(mat_B_iaP)) DEALLOCATE (mat_B_iaP)
     663           12 :          IF (ALLOCATED(mat_Gamma_3_3D)) DEALLOCATE (mat_Gamma_3_3D)
     664           12 :          IF (ALLOCATED(product_matrix_1D)) DEALLOCATE (product_matrix_1D)
     665           34 :          IF (ALLOCATED(recv_buffer_1D)) DEALLOCATE (recv_buffer_1D)
     666              :       END DO
     667              : 
     668           10 :       CALL mp2_env%local_gemm_ctx%destroy()
     669              : 
     670           10 :       IF (nspins == 2) e_exchange_corr = e_exchange_corr*2.0_dp
     671           10 :       IF (nspins == 1) e_exchange_corr = e_exchange_corr*4.0_dp
     672              : 
     673           10 :       CALL timestop(handle)
     674              : 
     675           20 :    END SUBROUTINE rpa_exchange_work_compute_fm
     676              : 
     677              : ! **************************************************************************************************
     678              : !> \brief Contract RPA-exchange density matrix with HF exchange integrals and evaluate the correction
     679              : !> \param exchange_work ...
     680              : !> \param fm_mat_S ...
     681              : !> \param eig ...
     682              : !> \param omega ...
     683              : !> \param e_exchange_corr ...
     684              : !> \author Vladimir Rybkin, 08/2016
     685              : ! **************************************************************************************************
     686            2 :    SUBROUTINE rpa_exchange_work_compute_hfx(exchange_work, fm_mat_S, eig, omega, e_exchange_corr)
     687              :       CLASS(rpa_exchange_work_type), INTENT(INOUT) :: exchange_work
     688              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT) :: fm_mat_S
     689              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: eig
     690              :       REAL(KIND=dp), INTENT(IN)                          :: omega
     691              :       REAL(KIND=dp), INTENT(OUT) :: e_exchange_corr
     692              : 
     693              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'rpa_exchange_work_compute_hfx'
     694              : 
     695              :       INTEGER                                            :: handle, ispin, my_aux_start, my_aux_end, &
     696              :                                                             my_aux_size, nspins, L_counter, dimen_ia, hom, virt
     697              :       REAL(KIND=dp)                                      :: e_exchange_P
     698            2 :       TYPE(dbcsr_matrix_p_set), DIMENSION(:), ALLOCATABLE          :: dbcsr_Gamma_3
     699              :       TYPE(cp_fm_type) :: fm_mat_Gamma_3
     700              :       TYPE(mp_para_env_type), POINTER :: para_env
     701              : 
     702            2 :       CALL timeset(routineN, handle)
     703              : 
     704            2 :       e_exchange_corr = 0.0_dp
     705              : 
     706            2 :       nspins = SIZE(fm_mat_S)
     707              : 
     708            2 :       CALL get_group_dist(exchange_work%aux_func_dist, exchange_work%color_sub, my_aux_start, my_aux_end, my_aux_size)
     709              : 
     710            8 :       ALLOCATE (dbcsr_Gamma_3(nspins))
     711            4 :       DO ispin = 1, nspins
     712            2 :          hom = exchange_work%homo(ispin)
     713            2 :          virt = exchange_work%virtual(ispin)
     714            2 :          dimen_ia = hom*virt
     715            2 :          IF (hom < 1 .OR. virt < 1) CYCLE
     716              : 
     717            2 :          CALL cp_fm_get_info(fm_mat_S(ispin), para_env=para_env)
     718              : 
     719            2 :          CALL cp_fm_create(fm_mat_Gamma_3, exchange_work%exchange_env%struct_Gamma(ispin)%struct)
     720            2 :          CALL cp_fm_set_all(matrix=fm_mat_Gamma_3, alpha=0.0_dp)
     721              : 
     722              :          ! Update G with a new value of Omega: in practice, it is G*S
     723              : 
     724              :          ! Scale fm_work_iaP
     725              :          CALL calc_fm_mat_S_rpa(fm_mat_S(ispin), .TRUE., virt, eig(:, ispin), &
     726            2 :                                 hom, omega, 0.0_dp)
     727              : 
     728              :          ! Calculate Gamma_3: Gamma_3 = G*S*R^(1/2) = G*S*R^(1/2)
     729              :          CALL parallel_gemm(transa="T", transb="N", m=dimen_ia, n=exchange_work%dimen_RI, &
     730              :                             k=exchange_work%dimen_RI, alpha=1.0_dp, &
     731              :                             matrix_a=fm_mat_S(ispin), matrix_b=exchange_work%fm_mat_R_half_gemm, beta=0.0_dp, &
     732            2 :                             matrix_c=fm_mat_Gamma_3)
     733              : 
     734              :          ! Remove extra factor from S after the multiplication (to return to the original matrix)
     735            2 :          CALL remove_scaling_factor_rpa(fm_mat_S(ispin), virt, eig(:, ispin), hom, omega)
     736              : 
     737              :          ! Copy Gamma_ia_P^3 to dbcsr matrix set
     738            4 :          BLOCK
     739              :             INTEGER :: first_row, last_row, nlocal
     740            2 :             REAL(KIND=dp), ALLOCATABLE :: slices(:, :)
     741            2 :             TYPE(group_dist_d1_type) :: row_distribution
     742              : 
     743            2 :             CALL create_group_dist(row_distribution, exchange_work%para_env_sub%num_pe, dimen_ia)
     744            2 :             CALL get_group_dist(row_distribution, exchange_work%para_env_sub%mepos, first_row, last_row, nlocal)
     745            2 :             CALL cp_fm_to_array(slices, first_row, last_row, my_aux_start, my_aux_end, fm_mat_Gamma_3)
     746           89 :             ALLOCATE (dbcsr_Gamma_3(ispin)%matrix_set(my_aux_size))
     747              :             CALL cp_array_to_dbcsr_slices(slices, hom, virt, exchange_work%para_env_sub, first_row, last_row, &
     748              :                                           exchange_work%exchange_env%mo_coeff_o(ispin), &
     749            2 :                                           matrices=dbcsr_Gamma_3(ispin)%matrix_set)
     750           10 :             CALL release_group_dist(row_distribution)
     751              :          END BLOCK
     752              :       END DO
     753              : 
     754           85 :       DO L_counter = 1, my_aux_size
     755          166 :          DO ispin = 1, nspins
     756              :             ! Do dbcsr multiplication: transform the virtual index
     757              :             CALL dbcsr_multiply("N", "T", 1.0_dp, exchange_work%exchange_env%mo_coeff_v(ispin), &
     758              :                                 dbcsr_Gamma_3(ispin)%matrix_set(L_counter), &
     759              :                                 0.0_dp, exchange_work%exchange_env%dbcsr_Gamma_inu_P(ispin), &
     760           83 :                                 filter_eps=exchange_work%exchange_env%eps_filter)
     761              : 
     762           83 :             CALL dbcsr_release(dbcsr_Gamma_3(ispin)%matrix_set(L_counter))
     763              : 
     764              :             ! Do dbcsr multiplication: transform the occupied index
     765              :             CALL dbcsr_multiply("N", "T", 0.5_dp, exchange_work%exchange_env%dbcsr_Gamma_inu_P(ispin), &
     766              :                                 exchange_work%exchange_env%mo_coeff_o(ispin), &
     767              :                                 0.0_dp, exchange_work%exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix, &
     768           83 :                                 filter_eps=exchange_work%exchange_env%eps_filter)
     769              :             CALL dbcsr_multiply("N", "T", 0.5_dp, exchange_work%exchange_env%mo_coeff_o(ispin), &
     770              :                                 exchange_work%exchange_env%dbcsr_Gamma_inu_P(ispin), &
     771              :                                 1.0_dp, exchange_work%exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix, &
     772           83 :                                 filter_eps=exchange_work%exchange_env%eps_filter)
     773              : 
     774          166 :             CALL dbcsr_set(exchange_work%exchange_env%mat_hfx(ispin)%matrix, 0.0_dp)
     775              :          END DO
     776              : 
     777              :          CALL tddft_hfx_matrix(exchange_work%exchange_env%mat_hfx, exchange_work%exchange_env%dbcsr_Gamma_munu_P, &
     778              :                                exchange_work%exchange_env%qs_env, .FALSE., &
     779              :                                exchange_work%exchange_env%my_recalc_hfx_integrals, &
     780              :                                exchange_work%exchange_env%hfx_sections, exchange_work%exchange_env%x_data, &
     781           83 :                                exchange_work%exchange_env%para_env)
     782              : 
     783           83 :          exchange_work%exchange_env%my_recalc_hfx_integrals = .FALSE.
     784          168 :          DO ispin = 1, nspins
     785              :             CALL dbcsr_multiply("N", "T", 1.0_dp, exchange_work%exchange_env%mat_hfx(ispin)%matrix, &
     786              :                                 exchange_work%exchange_env%dbcsr_Gamma_munu_P(ispin)%matrix, &
     787           83 :                                 0.0_dp, exchange_work%exchange_env%work_ao, filter_eps=exchange_work%exchange_env%eps_filter)
     788           83 :             CALL dbcsr_trace(exchange_work%exchange_env%work_ao, e_exchange_P)
     789          166 :             e_exchange_corr = e_exchange_corr - e_exchange_P
     790              :          END DO
     791              :       END DO
     792              : 
     793              :       IF (nspins == 2) e_exchange_corr = e_exchange_corr
     794            2 :       IF (nspins == 1) e_exchange_corr = e_exchange_corr*4.0_dp
     795              : 
     796            2 :       CALL timestop(handle)
     797              : 
     798            6 :    END SUBROUTINE rpa_exchange_work_compute_hfx
     799              : 
     800              : ! **************************************************************************************************
     801              : !> \brief ...
     802              : !> \param exchange_work ...
     803              : !> \param fm_mat ...
     804              : !> \param mat ...
     805              : !> \param ispin ...
     806              : !> \param virt_dist ...
     807              : ! **************************************************************************************************
     808           24 :    SUBROUTINE redistribute_into_subgroups(exchange_work, fm_mat, mat, ispin, virt_dist)
     809              :       CLASS(rpa_exchange_work_type), INTENT(IN) :: exchange_work
     810              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat
     811              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     812              :          INTENT(OUT)                                     :: mat
     813              :       INTEGER, INTENT(IN)                                :: ispin
     814              :       TYPE(group_dist_d1_type), INTENT(IN)               :: virt_dist
     815              : 
     816              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'redistribute_into_subgroups'
     817              : 
     818              :       INTEGER :: aux_counter, aux_global, aux_local, aux_proc, avirt, dimen_RI, handle, handle2, &
     819              :                  ia_global, ia_local, iocc, max_number_recv, max_number_send, my_aux_end, my_aux_size, &
     820              :                  my_aux_start, my_process_column, my_process_row, my_virt_end, my_virt_size, &
     821              :                  my_virt_start, proc, proc_shift, recv_proc, send_proc, virt_counter, virt_proc, group_size
     822           24 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: data2send, recv_col_indices, &
     823           24 :                                             recv_row_indices, send_aux_indices, send_virt_indices, virt2send
     824              :       INTEGER, DIMENSION(2)                              :: recv_shape
     825           24 :       INTEGER, DIMENSION(:), POINTER                     :: aux_distribution_fm, col_indices, &
     826           24 :                                                             ia_distribution_fm, row_indices
     827           24 :       INTEGER, DIMENSION(:, :), POINTER                  :: mpi2blacs
     828           24 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), TARGET   :: recv_buffer, send_buffer
     829              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     830           24 :          POINTER                                         :: recv_ptr, send_ptr
     831              :       TYPE(cp_blacs_env_type), POINTER                   :: context
     832              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     833              : 
     834           24 :       CALL timeset(routineN, handle)
     835              : 
     836              :       CALL cp_fm_get_info(matrix=fm_mat, &
     837              :                           nrow_locals=aux_distribution_fm, &
     838              :                           col_indices=col_indices, &
     839              :                           row_indices=row_indices, &
     840              :                           ncol_locals=ia_distribution_fm, &
     841              :                           context=context, &
     842              :                           nrow_global=dimen_RI, &
     843           24 :                           para_env=para_env)
     844              : 
     845           24 :       IF (exchange_work%homo(ispin) <= 0 .OR. exchange_work%virtual(ispin) <= 0) THEN
     846            0 :          CALL get_group_dist(virt_dist, exchange_work%para_env_sub%mepos, my_virt_start, my_virt_end, my_virt_size)
     847            0 :          ALLOCATE (mat(exchange_work%homo(ispin), my_virt_size, dimen_RI))
     848            0 :          CALL timestop(handle)
     849            0 :          RETURN
     850              :       END IF
     851              : 
     852           24 :       group_size = exchange_work%para_env_sub%num_pe
     853              : 
     854           24 :       CALL timeset(routineN//"_prep", handle2)
     855           24 :       CALL get_group_dist(exchange_work%aux_func_dist, exchange_work%color_sub, my_aux_start, my_aux_end, my_aux_size)
     856           24 :       CALL get_group_dist(virt_dist, exchange_work%para_env_sub%mepos, my_virt_start, my_virt_end, my_virt_size)
     857           24 :       CALL context%get(my_process_column=my_process_column, my_process_row=my_process_row, mpi2blacs=mpi2blacs)
     858              : 
     859              :       ! Determine the number of columns to send
     860          120 :       ALLOCATE (send_aux_indices(MAXVAL(exchange_work%aux2send)))
     861           72 :       ALLOCATE (virt2send(0:group_size - 1))
     862           24 :       virt2send = 0
     863         1924 :       DO ia_local = 1, ia_distribution_fm(my_process_column)
     864         1900 :          ia_global = col_indices(ia_local)
     865         1900 :          avirt = MOD(ia_global - 1, exchange_work%virtual(ispin)) + 1
     866         1900 :          proc = group_dist_proc(virt_dist, avirt)
     867         1924 :          virt2send(proc) = virt2send(proc) + 1
     868              :       END DO
     869              : 
     870           72 :       ALLOCATE (data2send(0:para_env%num_pe - 1))
     871           72 :       DO aux_proc = 0, exchange_work%ngroup - 1
     872          120 :       DO virt_proc = 0, group_size - 1
     873           96 :          data2send(aux_proc*group_size + virt_proc) = exchange_work%aux2send(aux_proc)*virt2send(virt_proc)
     874              :       END DO
     875              :       END DO
     876              : 
     877           96 :       ALLOCATE (send_virt_indices(MAXVAL(virt2send)))
     878           72 :       max_number_send = MAXVAL(data2send)
     879              : 
     880           72 :       ALLOCATE (send_buffer(INT(max_number_send, KIND=int_8)*exchange_work%homo(ispin)))
     881           24 :       max_number_recv = max_number_send
     882           24 :       CALL para_env%max(max_number_recv)
     883           72 :       ALLOCATE (recv_buffer(max_number_recv))
     884              : 
     885          120 :       ALLOCATE (mat(my_virt_size, exchange_work%homo(ispin), my_aux_size))
     886              : 
     887           24 :       CALL timestop(handle2)
     888              : 
     889           24 :       CALL timeset(routineN//"_own", handle2)
     890              :       ! Start with own data
     891         1026 :       DO aux_local = 1, aux_distribution_fm(my_process_row)
     892         1002 :          aux_global = row_indices(aux_local)
     893         1002 :          IF (aux_global < my_aux_start .OR. aux_global > my_aux_end) CYCLE
     894        40848 :          DO ia_local = 1, ia_distribution_fm(my_process_column)
     895        40318 :             ia_global = fm_mat%matrix_struct%col_indices(ia_local)
     896              : 
     897        40318 :             iocc = (ia_global - 1)/exchange_work%virtual(ispin) + 1
     898        40318 :             avirt = MOD(ia_global - 1, exchange_work%virtual(ispin)) + 1
     899              : 
     900        40318 :             IF (my_virt_start > avirt .OR. my_virt_end < avirt) CYCLE
     901              : 
     902        41320 :             mat(avirt - my_virt_start + 1, iocc, aux_global - my_aux_start + 1) = fm_mat%local_data(aux_local, ia_local)
     903              :          END DO
     904              :       END DO
     905           24 :       CALL timestop(handle2)
     906              : 
     907           48 :       DO proc_shift = 1, para_env%num_pe - 1
     908           24 :          send_proc = MODULO(para_env%mepos + proc_shift, para_env%num_pe)
     909           24 :          recv_proc = MODULO(para_env%mepos - proc_shift, para_env%num_pe)
     910              : 
     911           24 :          CALL timeset(routineN//"_pack_buffer", handle2)
     912              :          send_ptr(1:virt2send(MOD(send_proc, group_size)), &
     913              :                   1:exchange_work%aux2send(send_proc/group_size)) => &
     914              :             send_buffer(1:INT(virt2send(MOD(send_proc, group_size)), KIND=int_8)* &
     915           24 :                         exchange_work%aux2send(send_proc/group_size))
     916              : ! Pack send buffer
     917           24 :          aux_counter = 0
     918         1026 :          DO aux_local = 1, aux_distribution_fm(my_process_row)
     919         1002 :             aux_global = row_indices(aux_local)
     920         1002 :             proc = group_dist_proc(exchange_work%aux_func_dist, aux_global)
     921         1002 :             IF (proc /= send_proc/group_size) CYCLE
     922          496 :             aux_counter = aux_counter + 1
     923          496 :             virt_counter = 0
     924        40016 :             DO ia_local = 1, ia_distribution_fm(my_process_column)
     925        39520 :                ia_global = col_indices(ia_local)
     926        39520 :                avirt = MOD(ia_global - 1, exchange_work%virtual(ispin)) + 1
     927              : 
     928        39520 :                proc = group_dist_proc(virt_dist, avirt)
     929        39520 :                IF (proc /= MOD(send_proc, group_size)) CYCLE
     930        39520 :                virt_counter = virt_counter + 1
     931        39520 :                send_ptr(virt_counter, aux_counter) = fm_mat%local_data(aux_local, ia_local)
     932        40016 :                send_virt_indices(virt_counter) = ia_global
     933              :             END DO
     934         1026 :             send_aux_indices(aux_counter) = aux_global
     935              :          END DO
     936           24 :          CALL timestop(handle2)
     937              : 
     938           24 :          CALL timeset(routineN//"_ex_size", handle2)
     939           24 :          recv_shape = [1, 1]
     940           72 :          CALL para_env%sendrecv(SHAPE(send_ptr), send_proc, recv_shape, recv_proc)
     941           24 :          CALL timestop(handle2)
     942              : 
     943           72 :          IF (SIZE(send_ptr) == 0) send_proc = mp_proc_null
     944           72 :          IF (PRODUCT(recv_shape) == 0) recv_proc = mp_proc_null
     945              : 
     946           24 :          CALL timeset(routineN//"_ex_idx", handle2)
     947          120 :          ALLOCATE (recv_row_indices(recv_shape(1)), recv_col_indices(recv_shape(2)))
     948           24 :          CALL para_env%sendrecv(send_virt_indices(1:virt_counter), send_proc, recv_row_indices, recv_proc)
     949           24 :          CALL para_env%sendrecv(send_aux_indices(1:aux_counter), send_proc, recv_col_indices, recv_proc)
     950           24 :          CALL timestop(handle2)
     951              : 
     952              :          ! Prepare pointer to recv buffer (consider transposition while packing the send buffer)
     953           24 :          recv_ptr(1:recv_shape(1), 1:MAX(1, recv_shape(2))) => recv_buffer(1:recv_shape(1)*MAX(1, recv_shape(2)))
     954              : 
     955           24 :          CALL timeset(routineN//"_sendrecv", handle2)
     956              : ! Perform communication
     957           24 :          CALL para_env%sendrecv(send_ptr, send_proc, recv_ptr, recv_proc)
     958           24 :          CALL timestop(handle2)
     959              : 
     960           24 :          IF (recv_proc == mp_proc_null) THEN
     961            0 :             DEALLOCATE (recv_row_indices, recv_col_indices)
     962            0 :             CYCLE
     963              :          END IF
     964              : 
     965           24 :          CALL timeset(routineN//"_unpack", handle2)
     966              : ! Unpack receive buffer
     967          520 :          DO aux_local = 1, SIZE(recv_col_indices)
     968          496 :             aux_global = recv_col_indices(aux_local)
     969              : 
     970        40040 :             DO ia_local = 1, SIZE(recv_row_indices)
     971        39520 :                ia_global = recv_row_indices(ia_local)
     972              : 
     973        39520 :                iocc = (ia_global - 1)/exchange_work%virtual(ispin) + 1
     974        39520 :                avirt = MOD(ia_global - 1, exchange_work%virtual(ispin)) + 1
     975              : 
     976        40016 :                mat(avirt - my_virt_start + 1, iocc, aux_global - my_aux_start + 1) = recv_ptr(ia_local, aux_local)
     977              :             END DO
     978              :          END DO
     979           24 :          CALL timestop(handle2)
     980              : 
     981           24 :          IF (ALLOCATED(recv_row_indices)) DEALLOCATE (recv_row_indices)
     982          168 :          IF (ALLOCATED(recv_col_indices)) DEALLOCATE (recv_col_indices)
     983              :       END DO
     984              : 
     985           24 :       DEALLOCATE (send_aux_indices, send_virt_indices)
     986              : 
     987           24 :       CALL timestop(handle)
     988              : 
     989           96 :    END SUBROUTINE redistribute_into_subgroups
     990              : 
     991            0 : END MODULE rpa_exchange
        

Generated by: LCOV version 2.0-1