LCOV - code coverage report
Current view: top level - src - mp2_ri_2c.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 94.4 % 576 544
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 18 18

            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 Framework for 2c-integrals for RI
      10              : !> \par History
      11              : !>      06.2012 created [Mauro Del Ben]
      12              : !>      03.2019 separated from mp2_ri_gpw [Frederick Stein]
      13              : ! **************************************************************************************************
      14              : MODULE mp2_ri_2c
      15              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      16              :                                               get_atomic_kind_set
      17              :    USE basis_set_types,                 ONLY: gto_basis_set_p_type,&
      18              :                                               gto_basis_set_type
      19              :    USE cell_types,                      ONLY: cell_type,&
      20              :                                               get_cell,&
      21              :                                               plane_distance
      22              :    USE constants_operator,              ONLY: operator_coulomb
      23              :    USE cp_blacs_env,                    ONLY: cp_blacs_env_create,&
      24              :                                               cp_blacs_env_release,&
      25              :                                               cp_blacs_env_type
      26              :    USE cp_cfm_basic_linalg,             ONLY: cp_cfm_scale_and_add_fm
      27              :    USE cp_cfm_diag,                     ONLY: cp_cfm_power
      28              :    USE cp_cfm_types,                    ONLY: cp_cfm_copy_general,&
      29              :                                               cp_cfm_create,&
      30              :                                               cp_cfm_release,&
      31              :                                               cp_cfm_to_cfm,&
      32              :                                               cp_cfm_to_fm,&
      33              :                                               cp_cfm_type,&
      34              :                                               cp_fm_to_cfm
      35              :    USE cp_control_types,                ONLY: dft_control_type
      36              :    USE cp_dbcsr_api,                    ONLY: &
      37              :         dbcsr_copy, dbcsr_create, dbcsr_deallocate_matrix, dbcsr_desymmetrize, &
      38              :         dbcsr_distribution_release, dbcsr_distribution_type, dbcsr_p_type, dbcsr_release, &
      39              :         dbcsr_set, dbcsr_type, dbcsr_type_antisymmetric, dbcsr_type_no_symmetry, &
      40              :         dbcsr_type_symmetric
      41              :    USE cp_dbcsr_contrib,                ONLY: dbcsr_reserve_all_blocks
      42              :    USE cp_dbcsr_cp2k_link,              ONLY: cp_dbcsr_alloc_block_from_nbl
      43              :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm,&
      44              :                                               cp_dbcsr_dist2d_to_dist,&
      45              :                                               dbcsr_allocate_matrix_set,&
      46              :                                               dbcsr_deallocate_matrix_set
      47              :    USE cp_eri_mme_interface,            ONLY: cp_eri_mme_param
      48              :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      49              :                                               cp_fm_triangular_invert
      50              :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      51              :    USE cp_fm_diag,                      ONLY: choose_eigv_solver,&
      52              :                                               cp_fm_power,&
      53              :                                               cp_fm_syevx
      54              :    USE cp_fm_redistribution,            ONLY: cp_array_columns_to_fm
      55              :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      56              :                                               cp_fm_struct_release,&
      57              :                                               cp_fm_struct_type
      58              :    USE cp_fm_types,                     ONLY: cp_fm_copy_general,&
      59              :                                               cp_fm_create,&
      60              :                                               cp_fm_get_info,&
      61              :                                               cp_fm_release,&
      62              :                                               cp_fm_set_all,&
      63              :                                               cp_fm_to_fm,&
      64              :                                               cp_fm_type
      65              :    USE distribution_2d_types,           ONLY: distribution_2d_type
      66              :    USE group_dist_types,                ONLY: create_group_dist,&
      67              :                                               get_group_dist,&
      68              :                                               group_dist_d1_type,&
      69              :                                               release_group_dist
      70              :    USE input_constants,                 ONLY: do_eri_gpw,&
      71              :                                               do_eri_mme,&
      72              :                                               do_eri_os,&
      73              :                                               do_potential_coulomb,&
      74              :                                               do_potential_id,&
      75              :                                               do_potential_long,&
      76              :                                               do_potential_truncated
      77              :    USE kinds,                           ONLY: dp
      78              :    USE kpoint_coulomb_2c,               ONLY: build_2c_coulomb_matrix_kp
      79              :    USE kpoint_methods,                  ONLY: kpoint_init_cell_index,&
      80              :                                               rskp_transform
      81              :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      82              :                                               kpoint_type
      83              :    USE libint_2c_3c,                    ONLY: compare_potential_types,&
      84              :                                               libint_potential_type
      85              :    USE machine,                         ONLY: m_flush
      86              :    USE mathconstants,                   ONLY: gaussi,&
      87              :                                               z_one,&
      88              :                                               z_zero
      89              :    USE message_passing,                 ONLY: mp_comm_type,&
      90              :                                               mp_para_env_release,&
      91              :                                               mp_para_env_type
      92              :    USE mp2_eri,                         ONLY: mp2_eri_2c_integrate
      93              :    USE mp2_eri_gpw,                     ONLY: mp2_eri_2c_integrate_gpw
      94              :    USE parallel_gemm_api,               ONLY: parallel_gemm
      95              :    USE particle_methods,                ONLY: get_particle_set
      96              :    USE particle_types,                  ONLY: particle_type
      97              :    USE qs_environment_types,            ONLY: get_qs_env,&
      98              :                                               qs_environment_type
      99              :    USE qs_integral_utils,               ONLY: basis_set_list_setup
     100              :    USE qs_interactions,                 ONLY: init_interaction_radii
     101              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
     102              :                                               qs_kind_type
     103              :    USE qs_ks_types,                     ONLY: get_ks_env,&
     104              :                                               set_ks_env
     105              :    USE qs_neighbor_list_types,          ONLY: neighbor_list_set_p_type,&
     106              :                                               release_neighbor_list_sets
     107              :    USE qs_tensors,                      ONLY: build_2c_integrals,&
     108              :                                               build_2c_neighbor_lists
     109              : 
     110              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
     111              : #include "./base/base_uses.f90"
     112              : 
     113              :    IMPLICIT NONE
     114              : 
     115              :    PRIVATE
     116              : 
     117              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mp2_ri_2c'
     118              : 
     119              :    PUBLIC :: get_2c_integrals, trunc_coulomb_for_exchange, RI_2c_integral_mat, RI_2c_integral_mat_kp, &
     120              :              inversion_of_M_and_mult_with_chol_dec_of_V
     121              : 
     122              : CONTAINS
     123              : 
     124              : ! **************************************************************************************************
     125              : !> \brief ...
     126              : !> \param qs_env ...
     127              : !> \param eri_method ...
     128              : !> \param eri_param ...
     129              : !> \param para_env ...
     130              : !> \param para_env_sub ...
     131              : !> \param mp2_memory ...
     132              : !> \param my_Lrows ...
     133              : !> \param my_Vrows ...
     134              : !> \param fm_matrix_PQ ...
     135              : !> \param ngroup ...
     136              : !> \param color_sub ...
     137              : !> \param dimen_RI ...
     138              : !> \param dimen_RI_red reduced RI dimension,  needed if we perform SVD instead of Cholesky
     139              : !> \param kpoints ...
     140              : !> \param my_group_L_size ...
     141              : !> \param my_group_L_start ...
     142              : !> \param my_group_L_end ...
     143              : !> \param gd_array ...
     144              : !> \param calc_PQ_cond_num ...
     145              : !> \param do_svd ...
     146              : !> \param eps_svd ...
     147              : !> \param potential ...
     148              : !> \param ri_metric ...
     149              : !> \param cfm_matrix_L_kpoints ...
     150              : !> \param cfm_matrix_Minv_L_kpoints ...
     151              : !> \param fm_matrix_Minv_L_gamma ...
     152              : !> \param fm_matrix_Minv ...
     153              : !> \param fm_matrix_Minv_Vtrunc_Minv ...
     154              : !> \param do_im_time ...
     155              : !> \param do_kpoints ...
     156              : !> \param mp2_eps_pgf_orb_S ...
     157              : !> \param qs_kind_set ...
     158              : !> \param sab_orb_sub ...
     159              : !> \param calc_forces ...
     160              : !> \param unit_nr ...
     161              : ! **************************************************************************************************
     162          696 :    SUBROUTINE get_2c_integrals(qs_env, eri_method, eri_param, para_env, para_env_sub, mp2_memory, &
     163              :                                my_Lrows, my_Vrows, fm_matrix_PQ, ngroup, color_sub, dimen_RI, dimen_RI_red, &
     164              :                                kpoints, my_group_L_size, my_group_L_start, my_group_L_end, &
     165              :                                gd_array, calc_PQ_cond_num, do_svd, eps_svd, potential, ri_metric, &
     166              :                                cfm_matrix_L_kpoints, cfm_matrix_Minv_L_kpoints, fm_matrix_Minv_L_gamma, &
     167              :                                fm_matrix_Minv, fm_matrix_Minv_Vtrunc_Minv, &
     168              :                                do_im_time, do_kpoints, mp2_eps_pgf_orb_S, qs_kind_set, sab_orb_sub, calc_forces, unit_nr)
     169              : 
     170              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     171              :       INTEGER, INTENT(IN)                                :: eri_method
     172              :       TYPE(cp_eri_mme_param), POINTER                    :: eri_param
     173              :       TYPE(mp_para_env_type), POINTER                    :: para_env, para_env_sub
     174              :       REAL(KIND=dp), INTENT(IN)                          :: mp2_memory
     175              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     176              :          INTENT(OUT)                                     :: my_Lrows, my_Vrows
     177              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_matrix_PQ
     178              :       INTEGER, INTENT(IN)                                :: ngroup, color_sub
     179              :       INTEGER, INTENT(OUT)                               :: dimen_RI, dimen_RI_red
     180              :       TYPE(kpoint_type), POINTER                         :: kpoints
     181              :       INTEGER, INTENT(OUT)                               :: my_group_L_size, my_group_L_start, &
     182              :                                                             my_group_L_end
     183              :       TYPE(group_dist_d1_type), INTENT(OUT)              :: gd_array
     184              :       LOGICAL, INTENT(IN)                                :: calc_PQ_cond_num, do_svd
     185              :       REAL(KIND=dp), INTENT(IN)                          :: eps_svd
     186              :       TYPE(libint_potential_type)                        :: potential, ri_metric
     187              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_matrix_L_kpoints, &
     188              :                                                             cfm_matrix_Minv_L_kpoints
     189              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :), &
     190              :          INTENT(OUT)                                     :: fm_matrix_Minv_L_gamma
     191              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv, &
     192              :                                                             fm_matrix_Minv_Vtrunc_Minv
     193              :       LOGICAL, INTENT(IN)                                :: do_im_time, do_kpoints
     194              :       REAL(KIND=dp), INTENT(IN)                          :: mp2_eps_pgf_orb_S
     195              :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     196              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     197              :          POINTER                                         :: sab_orb_sub
     198              :       LOGICAL, INTENT(IN)                                :: calc_forces
     199              :       INTEGER, INTENT(IN)                                :: unit_nr
     200              : 
     201              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_2c_integrals'
     202              : 
     203              :       INTEGER                                            :: handle, i_size, num_small_eigen
     204              :       REAL(KIND=dp)                                      :: cond_num, eps_pgf_orb_old
     205          696 :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_matrix_M_kpoints
     206              :       TYPE(cp_fm_type)                                   :: fm_matrix_L_work, fm_matrix_M_inv_work, &
     207              :                                                             fm_matrix_V
     208              :       TYPE(dft_control_type), POINTER                    :: dft_control
     209              :       TYPE(libint_potential_type)                        :: trunc_coulomb
     210              :       TYPE(mp_para_env_type), POINTER                    :: para_env_L
     211              : 
     212          696 :       CALL timeset(routineN, handle)
     213              : 
     214              :       ! calculate V and store it in fm_matrix_L_work
     215              :       CALL compute_2c_integrals(qs_env, eri_method, eri_param, para_env, para_env_sub, para_env_L, mp2_memory, &
     216              :                                 fm_matrix_L_work, ngroup, color_sub, dimen_RI, &
     217              :                                 my_group_L_size, my_group_L_start, my_group_L_end, &
     218              :                                 gd_array, calc_PQ_cond_num, cond_num, &
     219          696 :                                 num_small_eigen, potential, sab_orb_sub, do_im_time=do_im_time)
     220              : 
     221          696 :       IF (do_im_time .AND. calc_forces) THEN
     222              :          !need a copy of the (P|Q) integrals
     223           50 :          CALL cp_fm_create(fm_matrix_PQ, fm_matrix_L_work%matrix_struct)
     224           50 :          CALL cp_fm_to_fm(fm_matrix_L_work, fm_matrix_PQ)
     225              :       END IF
     226              : 
     227          696 :       dimen_RI_red = dimen_RI
     228              : 
     229          696 :       IF (compare_potential_types(ri_metric, potential) .AND. .NOT. do_im_time) THEN
     230              :          CALL decomp_mat_L(fm_matrix_L_work, do_svd, eps_svd, num_small_eigen, cond_num, .TRUE., gd_array, ngroup, &
     231          516 :                            dimen_RI, dimen_RI_red, para_env)
     232              :       ELSE
     233              : 
     234              :          ! RI-metric matrix (depending on RI metric: Coulomb, overlap or truncated Coulomb)
     235          180 :          IF (do_im_time) THEN
     236          144 :             CALL get_qs_env(qs_env, dft_control=dft_control)
     237              : 
     238              :             ! re-init the radii to be able to generate pair lists with appropriate screening for overlap matrix
     239          144 :             eps_pgf_orb_old = dft_control%qs_control%eps_pgf_orb
     240          144 :             dft_control%qs_control%eps_pgf_orb = mp2_eps_pgf_orb_S
     241          144 :             CALL init_interaction_radii(dft_control%qs_control, qs_kind_set)
     242              : 
     243          144 :             IF (do_kpoints) THEN
     244              :                CALL RI_2c_integral_mat_kp(qs_env, cfm_matrix_M_kpoints, fm_matrix_L_work%matrix_struct, dimen_RI, &
     245              :                                           ri_metric, kpoints, put_mat_KS_env=.TRUE., &
     246           22 :                                           regularization_RI=qs_env%mp2_env%ri_rpa_im_time%regularization_RI)
     247              :             ELSE
     248              :                CALL RI_2c_integral_mat(qs_env, fm_matrix_Minv_L_gamma, fm_matrix_L_work%matrix_struct, dimen_RI, &
     249              :                                        ri_metric, put_mat_KS_env=.TRUE., &
     250          122 :                                        regularization_RI=qs_env%mp2_env%ri_rpa_im_time%regularization_RI)
     251              :             END IF
     252              : 
     253              :             ! re-init the radii to previous values
     254          144 :             dft_control%qs_control%eps_pgf_orb = eps_pgf_orb_old
     255          144 :             CALL init_interaction_radii(dft_control%qs_control, qs_kind_set)
     256              : 
     257              :             ! GPW overlap matrix
     258              :          ELSE
     259              : 
     260           36 :             CALL mp_para_env_release(para_env_L)
     261           36 :             CALL release_group_dist(gd_array)
     262              : 
     263          108 :             ALLOCATE (fm_matrix_Minv_L_gamma(1, 1))
     264              : 
     265              :             ! Calculate matrix of RI operator (for overlap metric: S), store it in fm_matrix_Minv_L_gamma
     266              :             CALL compute_2c_integrals(qs_env, eri_method, eri_param, para_env, para_env_sub, para_env_L, mp2_memory, &
     267              :                                       fm_matrix_Minv_L_gamma(1, 1), ngroup, color_sub, dimen_RI, &
     268              :                                       my_group_L_size, my_group_L_start, my_group_L_end, &
     269              :                                       gd_array, calc_PQ_cond_num, cond_num, &
     270              :                                       num_small_eigen, ri_metric, sab_orb_sub, &
     271           36 :                                       fm_matrix_L_struct=fm_matrix_L_work%matrix_struct)
     272              : 
     273              :          END IF
     274              : 
     275          180 :          IF (do_kpoints) THEN
     276              : 
     277              :             ! k-dependent 1/r Coulomb matrix V_PQ(k)
     278           22 :             CALL compute_V_by_lattice_sum(qs_env, cfm_matrix_L_kpoints, fm_matrix_L_work%matrix_struct, kpoints)
     279              : 
     280              :             CALL inversion_of_M_and_mult_with_chol_dec_of_V(cfm_matrix_M_kpoints, cfm_matrix_L_kpoints, &
     281              :                                                             cfm_matrix_Minv_L_kpoints, dimen_RI, kpoints, &
     282           22 :                                                             qs_env%mp2_env%ri_rpa_im_time%eps_eigval_S)
     283          450 :             DO i_size = 1, SIZE(cfm_matrix_M_kpoints)
     284          450 :                CALL cp_cfm_release(cfm_matrix_M_kpoints(i_size))
     285              :             END DO
     286           22 :             DEALLOCATE (cfm_matrix_M_kpoints)
     287              : 
     288           22 :             CALL trunc_coulomb_for_exchange(qs_env, trunc_coulomb)
     289              : 
     290              :             ! Gamma-only truncated Coulomb matrix V^tr with cutoff radius = half the unit cell size; for exchange self-energy
     291              :             CALL RI_2c_integral_mat(qs_env, fm_matrix_Minv_Vtrunc_Minv, fm_matrix_L_work%matrix_struct, dimen_RI, trunc_coulomb, &
     292           22 :                                     put_mat_KS_env=.FALSE., regularization_RI=0.0_dp)
     293              : 
     294              :             ! Gamma-only RI-metric matrix; for computing Gamma-only/MIC self-energy
     295              :             CALL RI_2c_integral_mat(qs_env, fm_matrix_Minv, fm_matrix_L_work%matrix_struct, dimen_RI, ri_metric, &
     296           22 :                                     put_mat_KS_env=.FALSE., regularization_RI=0.0_dp)
     297              : 
     298              :             CALL Gamma_only_inversion_of_M_and_mult_with_chol_dec_of_Vtrunc(fm_matrix_Minv_Vtrunc_Minv, &
     299           22 :                                                                             fm_matrix_Minv, qs_env)
     300              :          ELSE
     301          158 :             IF (calc_forces .AND. (.NOT. do_im_time)) THEN
     302              :                ! For the gradients, we make a copy of the inverse root of L
     303           12 :                CALL cp_fm_create(fm_matrix_V, fm_matrix_L_work%matrix_struct)
     304           12 :                CALL cp_fm_to_fm(fm_matrix_L_work, fm_matrix_V)
     305              : 
     306              :                CALL decomp_mat_L(fm_matrix_V, do_svd, eps_svd, num_small_eigen, cond_num, .TRUE., gd_array, ngroup, &
     307           12 :                                  dimen_RI, dimen_RI_red, para_env)
     308              :             END IF
     309              : 
     310              :             CALL decomp_mat_L(fm_matrix_L_work, do_svd, eps_svd, num_small_eigen, cond_num, .FALSE., gd_array, ngroup, &
     311          158 :                               dimen_RI, dimen_RI_red, para_env)
     312              : 
     313              :             CALL decomp_mat_L(fm_matrix_Minv_L_gamma(1, 1), .FALSE., 0.0_dp, num_small_eigen, cond_num, .TRUE., &
     314          158 :                               gd_array, ngroup, dimen_RI, dimen_RI_red, para_env)
     315              : 
     316          158 :             CALL cp_fm_create(fm_matrix_M_inv_work, fm_matrix_Minv_L_gamma(1, 1)%matrix_struct)
     317          158 :             CALL cp_fm_set_all(fm_matrix_M_inv_work, 0.0_dp)
     318              : 
     319              :             CALL parallel_gemm('N', 'T', dimen_RI, dimen_RI, dimen_RI, 1.0_dp, fm_matrix_Minv_L_gamma(1, 1), &
     320          158 :                                fm_matrix_Minv_L_gamma(1, 1), 0.0_dp, fm_matrix_M_inv_work)
     321              : 
     322          158 :             IF (do_svd) THEN
     323              :                ! We have to reset the size of fm_matrix_Minv_L_gamma
     324           34 :                CALL reset_size_matrix(fm_matrix_Minv_L_gamma(1, 1), dimen_RI_red, fm_matrix_L_work%matrix_struct)
     325              : 
     326              :                ! L (=fm_matrix_Minv_L_gamma) = S^(-1)*chol_dec(V)
     327              :                CALL parallel_gemm('T', 'N', dimen_RI, dimen_RI_red, dimen_RI, 1.0_dp, fm_matrix_M_inv_work, &
     328           34 :                                   fm_matrix_L_work, 0.0_dp, fm_matrix_Minv_L_gamma(1, 1))
     329              :             ELSE
     330              :                ! L (=fm_matrix_Minv_L_gamma) = S^(-1)*chol_dec(V)
     331              :                CALL parallel_gemm('T', 'T', dimen_RI, dimen_RI, dimen_RI, 1.0_dp, fm_matrix_M_inv_work, &
     332          124 :                                   fm_matrix_L_work, 0.0_dp, fm_matrix_Minv_L_gamma(1, 1))
     333              :             END IF
     334              : 
     335              :             ! clean the S_inv matrix
     336          158 :             CALL cp_fm_release(fm_matrix_M_inv_work)
     337              : 
     338              :          END IF
     339              : 
     340          180 :          IF (.NOT. do_im_time) THEN
     341           36 :             IF (do_kpoints) THEN
     342            0 :                CALL cp_cfm_to_fm(cfm_matrix_Minv_L_kpoints(1), mtargetr=fm_matrix_L_work)
     343              :             ELSE
     344           36 :                CALL cp_fm_to_fm(fm_matrix_Minv_L_gamma(1, 1), fm_matrix_L_work)
     345           36 :                CALL cp_fm_release(fm_matrix_Minv_L_gamma)
     346              :             END IF
     347              : 
     348              :          END IF
     349              : 
     350              :       END IF
     351              : 
     352              :       ! If the group distribution changed because of an SVD, we get the new values here
     353          696 :       CALL get_group_dist(gd_array, color_sub, my_group_L_start, my_group_L_end, my_group_L_size)
     354              : 
     355          696 :       IF (.NOT. do_im_time) THEN
     356          552 :          IF (unit_nr > 0) THEN
     357          276 :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") "RI_INFO| Cholesky decomposition group size:", para_env_L%num_pe
     358          276 :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") "RI_INFO| Number of groups for auxiliary basis functions", ngroup
     359          276 :             IF (calc_PQ_cond_num .OR. do_svd) THEN
     360              :                WRITE (UNIT=unit_nr, FMT="(T3,A,T67,ES14.5)") &
     361           16 :                   "RI_INFO| Condition number of the (P|Q):", cond_num
     362              :                WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     363           16 :                   "RI_INFO| Number of non-positive Eigenvalues of (P|Q):", num_small_eigen
     364              :             END IF
     365          276 :             CALL m_flush(unit_nr)
     366              :          END IF
     367              : 
     368              :          ! replicate the necessary row of the L^{-1} matrix on each proc
     369          552 :          CALL grep_Lcols(fm_matrix_L_work, my_group_L_start, my_group_L_end, my_group_L_size, my_Lrows)
     370          552 :          IF (calc_forces .AND. .NOT. compare_potential_types(qs_env%mp2_env%ri_metric, &
     371              :                                                              qs_env%mp2_env%potential_parameter)) THEN
     372           12 :             CALL grep_Lcols(fm_matrix_V, my_group_L_start, my_group_L_end, my_group_L_size, my_Vrows)
     373              :          END IF
     374              :       END IF
     375          696 :       CALL cp_fm_release(fm_matrix_L_work)
     376          696 :       IF (calc_forces .AND. .NOT. (do_im_time .OR. compare_potential_types(qs_env%mp2_env%ri_metric, &
     377           12 :                                                                qs_env%mp2_env%potential_parameter))) CALL cp_fm_release(fm_matrix_V)
     378          696 :       CALL mp_para_env_release(para_env_L)
     379              : 
     380          696 :       CALL timestop(handle)
     381              : 
     382         1392 :    END SUBROUTINE get_2c_integrals
     383              : 
     384              : ! **************************************************************************************************
     385              : !> \brief ...
     386              : !> \param fm_matrix_L ...
     387              : !> \param do_svd ...
     388              : !> \param eps_svd ...
     389              : !> \param num_small_eigen ...
     390              : !> \param cond_num ...
     391              : !> \param do_inversion ...
     392              : !> \param gd_array ...
     393              : !> \param ngroup ...
     394              : !> \param dimen_RI ...
     395              : !> \param dimen_RI_red ...
     396              : !> \param para_env ...
     397              : ! **************************************************************************************************
     398          844 :    SUBROUTINE decomp_mat_L(fm_matrix_L, do_svd, eps_svd, num_small_eigen, cond_num, do_inversion, gd_array, ngroup, &
     399              :                            dimen_RI, dimen_RI_red, para_env)
     400              : 
     401              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_matrix_L
     402              :       LOGICAL, INTENT(IN)                                :: do_svd
     403              :       REAL(KIND=dp), INTENT(IN)                          :: eps_svd
     404              :       INTEGER, INTENT(INOUT)                             :: num_small_eigen
     405              :       REAL(KIND=dp), INTENT(INOUT)                       :: cond_num
     406              :       LOGICAL, INTENT(IN)                                :: do_inversion
     407              :       TYPE(group_dist_d1_type), INTENT(INOUT)            :: gd_array
     408              :       INTEGER, INTENT(IN)                                :: ngroup, dimen_RI
     409              :       INTEGER, INTENT(INOUT)                             :: dimen_RI_red
     410              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
     411              : 
     412          844 :       IF (do_svd) THEN
     413           46 :          CALL matrix_root_with_svd(fm_matrix_L, num_small_eigen, cond_num, eps_svd, do_inversion, para_env)
     414              : 
     415           46 :          dimen_RI_red = dimen_RI - num_small_eigen
     416              : 
     417              :          ! We changed the size of fm_matrix_L in matrix_root_with_svd.
     418              :          ! So, we have to get new group sizes
     419           46 :          CALL release_group_dist(gd_array)
     420              : 
     421           46 :          CALL create_group_dist(gd_array, ngroup, dimen_RI_red)
     422              :       ELSE
     423              : 
     424              :          ! calculate Cholesky decomposition L (V=LL^T)
     425          798 :          CALL cholesky_decomp(fm_matrix_L, dimen_RI, do_inversion=do_inversion)
     426              : 
     427          798 :          IF (do_inversion) CALL invert_mat(fm_matrix_L)
     428              :       END IF
     429              : 
     430          844 :    END SUBROUTINE decomp_mat_L
     431              : 
     432              : ! **************************************************************************************************
     433              : !> \brief ...
     434              : !> \param qs_env ...
     435              : !> \param cfm_matrix_L_kpoints ...
     436              : !> \param fm_matrix_L_struct ...
     437              : !> \param kpoints ...
     438              : ! **************************************************************************************************
     439           22 :    SUBROUTINE compute_V_by_lattice_sum(qs_env, cfm_matrix_L_kpoints, fm_matrix_L_struct, kpoints)
     440              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     441              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_matrix_L_kpoints
     442              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_matrix_L_struct
     443              :       TYPE(kpoint_type), POINTER                         :: kpoints
     444              : 
     445              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_V_by_lattice_sum'
     446              : 
     447              :       INTEGER                                            :: handle, i_dim, ikp, nkp, nkp_extra, &
     448              :                                                             nkp_orig
     449              :       INTEGER, DIMENSION(3)                              :: nkp_grid_orig, periodic
     450           22 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     451              :       TYPE(cell_type), POINTER                           :: cell
     452              :       TYPE(cp_fm_type)                                   :: fm_matrix_L_work
     453           22 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_RI_aux_transl, matrix_v_RI_kp
     454           22 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     455           22 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     456              : 
     457           22 :       CALL timeset(routineN, handle)
     458              : 
     459           22 :       NULLIFY (matrix_s_RI_aux_transl, particle_set, cell, qs_kind_set)
     460              : 
     461              :       CALL get_qs_env(qs_env=qs_env, &
     462              :                       matrix_s_RI_aux_kp=matrix_s_RI_aux_transl, &
     463              :                       particle_set=particle_set, &
     464              :                       cell=cell, &
     465              :                       qs_kind_set=qs_kind_set, &
     466           22 :                       atomic_kind_set=atomic_kind_set)
     467              : 
     468              :       ! check that we have a 2n x 2m x 2k mesh to guarantee good convergence
     469           22 :       CALL get_cell(cell=cell, periodic=periodic)
     470           88 :       DO i_dim = 1, 3
     471           88 :          IF (periodic(i_dim) == 1) THEN
     472           38 :             CPASSERT(MODULO(kpoints%nkp_grid(i_dim), 2) == 0)
     473              :          END IF
     474              :       END DO
     475              : 
     476           22 :       nkp = kpoints%nkp
     477              : 
     478          494 :       ALLOCATE (cfm_matrix_L_kpoints(nkp))
     479          450 :       DO ikp = 1, nkp
     480          450 :          CALL cp_cfm_create(cfm_matrix_L_kpoints(ikp), fm_matrix_L_struct)
     481              :       END DO
     482           22 :       CALL cp_fm_create(fm_matrix_L_work, fm_matrix_L_struct)
     483              : 
     484           22 :       CALL allocate_matrix_v_RI_kp(matrix_v_RI_kp, matrix_s_RI_aux_transl, nkp)
     485              : 
     486           22 :       IF (qs_env%mp2_env%ri_rpa_im_time%do_extrapolate_kpoints) THEN
     487              : 
     488           16 :          nkp_orig = qs_env%mp2_env%ri_rpa_im_time%nkp_orig
     489           16 :          nkp_extra = qs_env%mp2_env%ri_rpa_im_time%nkp_extra
     490              : 
     491              :          CALL build_2c_coulomb_matrix_kp(matrix_v_RI_kp, kpoints, basis_type="RI_AUX", &
     492              :                                          cell=cell, particle_set=particle_set, qs_kind_set=qs_kind_set, &
     493              :                                          atomic_kind_set=atomic_kind_set, &
     494              :                                          size_lattice_sum=qs_env%mp2_env%mp2_gpw%size_lattice_sum, &
     495           16 :                                          operator_type=operator_coulomb, ikp_start=1, ikp_end=nkp_orig)
     496              : 
     497           64 :          nkp_grid_orig = kpoints%nkp_grid
     498          128 :          kpoints%nkp_grid(1:3) = qs_env%mp2_env%ri_rpa_im_time%kp_grid_extra(1:3)
     499              : 
     500              :          CALL build_2c_coulomb_matrix_kp(matrix_v_RI_kp, kpoints, basis_type="RI_AUX", &
     501              :                                          cell=cell, particle_set=particle_set, qs_kind_set=qs_kind_set, &
     502              :                                          atomic_kind_set=atomic_kind_set, &
     503              :                                          size_lattice_sum=qs_env%mp2_env%mp2_gpw%size_lattice_sum, &
     504           16 :                                          operator_type=operator_coulomb, ikp_start=nkp_orig + 1, ikp_end=nkp)
     505              : 
     506           64 :          kpoints%nkp_grid = nkp_grid_orig
     507              : 
     508              :       ELSE
     509              : 
     510              :          CALL build_2c_coulomb_matrix_kp(matrix_v_RI_kp, kpoints, basis_type="RI_AUX", &
     511              :                                          cell=cell, particle_set=particle_set, qs_kind_set=qs_kind_set, &
     512              :                                          atomic_kind_set=atomic_kind_set, &
     513              :                                          size_lattice_sum=qs_env%mp2_env%mp2_gpw%size_lattice_sum, &
     514            6 :                                          operator_type=operator_coulomb, ikp_start=1, ikp_end=nkp)
     515              : 
     516              :       END IF
     517              : 
     518          450 :       DO ikp = 1, nkp
     519              :          CALL copy_dbcsr_pair_to_cfm(matrix_v_RI_kp(ikp, 1)%matrix, matrix_v_RI_kp(ikp, 2)%matrix, &
     520          450 :                                      fm_matrix_L_work, cfm_matrix_L_kpoints(ikp))
     521              :       END DO
     522           22 :       CALL cp_fm_release(fm_matrix_L_work)
     523              : 
     524           22 :       CALL dbcsr_deallocate_matrix_set(matrix_v_RI_kp)
     525              : 
     526           22 :       CALL timestop(handle)
     527              : 
     528           44 :    END SUBROUTINE compute_V_by_lattice_sum
     529              : 
     530              : ! **************************************************************************************************
     531              : !> \brief ...
     532              : !> \param matrix_v_RI_kp ...
     533              : !> \param matrix_s_RI_aux_transl ...
     534              : !> \param nkp ...
     535              : ! **************************************************************************************************
     536           22 :    SUBROUTINE allocate_matrix_v_RI_kp(matrix_v_RI_kp, matrix_s_RI_aux_transl, nkp)
     537              : 
     538              :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_v_RI_kp, matrix_s_RI_aux_transl
     539              :       INTEGER                                            :: nkp
     540              : 
     541              :       INTEGER                                            :: ikp
     542              : 
     543           22 :       NULLIFY (matrix_v_RI_kp)
     544           22 :       CALL dbcsr_allocate_matrix_set(matrix_v_RI_kp, nkp, 2)
     545              : 
     546          450 :       DO ikp = 1, nkp
     547              : 
     548          428 :          ALLOCATE (matrix_v_RI_kp(ikp, 1)%matrix)
     549              :          CALL dbcsr_create(matrix_v_RI_kp(ikp, 1)%matrix, template=matrix_s_RI_aux_transl(1, 1)%matrix, &
     550          428 :                            matrix_type=dbcsr_type_no_symmetry)
     551          428 :          CALL dbcsr_reserve_all_blocks(matrix_v_RI_kp(ikp, 1)%matrix)
     552          428 :          CALL dbcsr_set(matrix_v_RI_kp(ikp, 1)%matrix, 0.0_dp)
     553              : 
     554          428 :          ALLOCATE (matrix_v_RI_kp(ikp, 2)%matrix)
     555              :          CALL dbcsr_create(matrix_v_RI_kp(ikp, 2)%matrix, template=matrix_s_RI_aux_transl(1, 1)%matrix, &
     556          428 :                            matrix_type=dbcsr_type_no_symmetry)
     557          428 :          CALL dbcsr_reserve_all_blocks(matrix_v_RI_kp(ikp, 2)%matrix)
     558          450 :          CALL dbcsr_set(matrix_v_RI_kp(ikp, 2)%matrix, 0.0_dp)
     559              : 
     560              :       END DO
     561              : 
     562           22 :    END SUBROUTINE allocate_matrix_v_RI_kp
     563              : 
     564              : ! **************************************************************************************************
     565              : !> \brief ...
     566              : !> \param qs_env ...
     567              : !> \param fm_matrix_Minv_L_gamma real Gamma-point result ...
     568              : !> \param fm_matrix_L_struct matrix distribution used for the result ...
     569              : !> \param dimen_RI ...
     570              : !> \param ri_metric ...
     571              : !> \param put_mat_KS_env ...
     572              : !> \param regularization_RI ...
     573              : ! **************************************************************************************************
     574          452 :    SUBROUTINE RI_2c_integral_mat(qs_env, fm_matrix_Minv_L_gamma, fm_matrix_L_struct, dimen_RI, ri_metric, &
     575              :                                  put_mat_KS_env, regularization_RI)
     576              : 
     577              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     578              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_Minv_L_gamma
     579              :       TYPE(cp_fm_struct_type), INTENT(IN), POINTER       :: fm_matrix_L_struct
     580              :       INTEGER, INTENT(IN)                                :: dimen_RI
     581              :       TYPE(libint_potential_type)                        :: ri_metric
     582              :       LOGICAL, OPTIONAL                                  :: put_mat_KS_env
     583              :       REAL(KIND=dp), OPTIONAL                            :: regularization_RI
     584              : 
     585              :       CALL RI_2c_integral_mat_core(qs_env, fm_matrix_Minv_L_gamma=fm_matrix_Minv_L_gamma, &
     586              :                                    fm_matrix_L_struct=fm_matrix_L_struct, dimen_RI=dimen_RI, ri_metric=ri_metric, &
     587              :                                    do_kpoints=.FALSE., put_mat_KS_env=put_mat_KS_env, &
     588          452 :                                    regularization_RI=regularization_RI)
     589              : 
     590          452 :    END SUBROUTINE RI_2c_integral_mat
     591              : 
     592              : ! **************************************************************************************************
     593              : !> \brief Computes the complex k-point RI metric as native CFM matrices.
     594              : !> \param qs_env ...
     595              : !> \param cfm_matrix_M_kpoints ...
     596              : !> \param fm_matrix_struct ...
     597              : !> \param dimen_RI ...
     598              : !> \param ri_metric ...
     599              : !> \param kpoints ...
     600              : !> \param put_mat_KS_env ...
     601              : !> \param regularization_RI ...
     602              : !> \param ikp_ext ...
     603              : !> \param do_build_cell_index ...
     604              : ! **************************************************************************************************
     605          552 :    SUBROUTINE RI_2c_integral_mat_kp(qs_env, cfm_matrix_M_kpoints, fm_matrix_struct, dimen_RI, ri_metric, &
     606              :                                     kpoints, put_mat_KS_env, regularization_RI, ikp_ext, do_build_cell_index)
     607              : 
     608              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     609              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:)       :: cfm_matrix_M_kpoints
     610              :       TYPE(cp_fm_struct_type), INTENT(IN), POINTER       :: fm_matrix_struct
     611              :       INTEGER, INTENT(IN)                                :: dimen_RI
     612              :       TYPE(libint_potential_type)                        :: ri_metric
     613              :       TYPE(kpoint_type), POINTER                         :: kpoints
     614              :       LOGICAL, OPTIONAL                                  :: put_mat_KS_env
     615              :       REAL(KIND=dp), OPTIONAL                            :: regularization_RI
     616              :       INTEGER, OPTIONAL                                  :: ikp_ext
     617              :       LOGICAL, OPTIONAL                                  :: do_build_cell_index
     618              : 
     619              :       CALL RI_2c_integral_mat_core(qs_env, cfm_matrix_M_kpoints=cfm_matrix_M_kpoints, &
     620              :                                    fm_matrix_L_struct=fm_matrix_struct, dimen_RI=dimen_RI, ri_metric=ri_metric, &
     621              :                                    do_kpoints=.TRUE., kpoints=kpoints, put_mat_KS_env=put_mat_KS_env, &
     622              :                                    regularization_RI=regularization_RI, ikp_ext=ikp_ext, &
     623          552 :                                    do_build_cell_index=do_build_cell_index)
     624              : 
     625          552 :    END SUBROUTINE RI_2c_integral_mat_kp
     626              : 
     627              : ! **************************************************************************************************
     628              : !> \brief Shared DBCSR evaluator with representation-specific matrix output adapters.
     629              : !> \param qs_env ...
     630              : !> \param fm_matrix_Minv_L_gamma ...
     631              : !> \param cfm_matrix_M_kpoints ...
     632              : !> \param fm_matrix_L_struct ...
     633              : !> \param dimen_RI ...
     634              : !> \param ri_metric ...
     635              : !> \param do_kpoints ...
     636              : !> \param kpoints ...
     637              : !> \param put_mat_KS_env ...
     638              : !> \param regularization_RI ...
     639              : !> \param ikp_ext ...
     640              : !> \param do_build_cell_index ...
     641              : ! **************************************************************************************************
     642         1004 :    SUBROUTINE RI_2c_integral_mat_core(qs_env, fm_matrix_Minv_L_gamma, cfm_matrix_M_kpoints, &
     643              :                                       fm_matrix_L_struct, dimen_RI, ri_metric, do_kpoints, kpoints, &
     644              :                                       put_mat_KS_env, regularization_RI, ikp_ext, do_build_cell_index)
     645              : 
     646              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     647              :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :), &
     648              :          INTENT(OUT), OPTIONAL                           :: fm_matrix_Minv_L_gamma
     649              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:), &
     650              :          INTENT(OUT), OPTIONAL                           :: cfm_matrix_M_kpoints
     651              :       TYPE(cp_fm_struct_type), INTENT(IN), POINTER       :: fm_matrix_L_struct
     652              :       INTEGER, INTENT(IN)                                :: dimen_RI
     653              :       TYPE(libint_potential_type)                        :: ri_metric
     654              :       LOGICAL, INTENT(IN)                                :: do_kpoints
     655              :       TYPE(kpoint_type), OPTIONAL, POINTER               :: kpoints
     656              :       LOGICAL, OPTIONAL                                  :: put_mat_KS_env
     657              :       REAL(KIND=dp), OPTIONAL                            :: regularization_RI
     658              :       INTEGER, OPTIONAL                                  :: ikp_ext
     659              :       LOGICAL, OPTIONAL                                  :: do_build_cell_index
     660              : 
     661              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'RI_2c_integral_mat_core'
     662              : 
     663              :       INTEGER                                            :: handle, ikp, ikp_for_xkp, img, natom, &
     664              :                                                             nimg, nkind, nkp
     665         1004 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: sizes_RI
     666         1004 :       INTEGER, DIMENSION(:), POINTER                     :: col_bsize, row_bsize
     667         1004 :       INTEGER, DIMENSION(:, :, :), POINTER               :: cell_to_index
     668              :       LOGICAL                                            :: my_do_build_cell_index, my_put_mat_KS_env
     669              :       REAL(KIND=dp)                                      :: my_regularization_RI
     670         1004 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: xkp
     671              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     672              :       TYPE(cp_cfm_type)                                  :: cfm_matrix_S_global
     673              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     674              :       TYPE(cp_fm_type)                                   :: fm_matrix_S_global
     675         1004 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :)     :: fm_matrix_M_kpoints
     676              :       TYPE(dbcsr_distribution_type)                      :: dbcsr_dist
     677         1004 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_RI_aux_transl
     678         1004 :       TYPE(dbcsr_type), ALLOCATABLE, DIMENSION(:)        :: mat_2c
     679              :       TYPE(dbcsr_type), POINTER                          :: cmatrix, matrix_s_RI_aux_desymm, &
     680              :                                                             rmatrix, tmpmat
     681              :       TYPE(dft_control_type), POINTER                    :: dft_control
     682              :       TYPE(distribution_2d_type), POINTER                :: dist_2d
     683         1004 :       TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER  :: basis_set_RI
     684              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     685              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     686         1004 :          POINTER                                         :: sab_RI
     687         1004 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     688         1004 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     689              : 
     690         1004 :       CALL timeset(routineN, handle)
     691              : 
     692         1004 :       IF (do_kpoints) THEN
     693          552 :          CPASSERT(PRESENT(cfm_matrix_M_kpoints))
     694              :       ELSE
     695          452 :          CPASSERT(PRESENT(fm_matrix_Minv_L_gamma))
     696              :       END IF
     697              : 
     698         1004 :       NULLIFY (sab_RI, matrix_s_RI_aux_transl, dist_2d)
     699              : 
     700         1004 :       IF (PRESENT(regularization_RI)) THEN
     701          836 :          my_regularization_RI = regularization_RI
     702              :       ELSE
     703          168 :          my_regularization_RI = 0.0_dp
     704              :       END IF
     705              : 
     706         1004 :       IF (PRESENT(put_mat_KS_env)) THEN
     707          188 :          my_put_mat_KS_env = put_mat_KS_env
     708              :       ELSE
     709              :          my_put_mat_KS_env = .FALSE.
     710              :       END IF
     711              : 
     712         1004 :       IF (PRESENT(do_build_cell_index)) THEN
     713          530 :          my_do_build_cell_index = do_build_cell_index
     714              :       ELSE
     715              :          my_do_build_cell_index = .FALSE.
     716              :       END IF
     717              : 
     718              :       CALL get_qs_env(qs_env=qs_env, &
     719              :                       para_env=para_env, &
     720              :                       blacs_env=blacs_env, &
     721              :                       nkind=nkind, &
     722              :                       distribution_2d=dist_2d, &
     723              :                       qs_kind_set=qs_kind_set, &
     724              :                       particle_set=particle_set, &
     725              :                       dft_control=dft_control, &
     726         1004 :                       natom=natom)
     727              : 
     728         3012 :       ALLOCATE (sizes_RI(natom))
     729         4762 :       ALLOCATE (basis_set_RI(nkind))
     730              : 
     731         1004 :       CALL basis_set_list_setup(basis_set_RI, 'RI_AUX', qs_kind_set)
     732         1004 :       CALL get_particle_set(particle_set, qs_kind_set, nsgf=sizes_RI, basis=basis_set_RI)
     733              : 
     734              :       CALL build_2c_neighbor_lists(sab_RI, basis_set_RI, basis_set_RI, ri_metric, "RPA_2c_nl_RI", qs_env, &
     735         1004 :                                    sym_ij=.TRUE., dist_2d=dist_2d)
     736              : 
     737         1004 :       CALL cp_dbcsr_dist2d_to_dist(dist_2d, dbcsr_dist)
     738         3012 :       ALLOCATE (row_bsize(SIZE(sizes_RI)))
     739         2008 :       ALLOCATE (col_bsize(SIZE(sizes_RI)))
     740         3536 :       row_bsize(:) = sizes_RI
     741         3536 :       col_bsize(:) = sizes_RI
     742              : 
     743         1004 :       IF (do_kpoints) THEN
     744          552 :          CPASSERT(PRESENT(kpoints))
     745          552 :          IF (my_do_build_cell_index) THEN
     746           82 :             CALL kpoint_init_cell_index(kpoints, sab_RI, para_env, dft_control%nimages)
     747              :          END IF
     748              :          CALL get_kpoint_info(kpoints, nkp=nkp, xkp=xkp, &
     749          552 :                               cell_to_index=cell_to_index)
     750          552 :          nimg = dft_control%nimages
     751              :       ELSE
     752          452 :          nkp = 1
     753          452 :          nimg = 1
     754              :       END IF
     755              : 
     756         9826 :       ALLOCATE (mat_2c(nimg))
     757              :       CALL dbcsr_create(mat_2c(1), "(RI|RI)", dbcsr_dist, dbcsr_type_symmetric, &
     758         1004 :                         row_bsize, col_bsize)
     759         1004 :       DEALLOCATE (row_bsize, col_bsize)
     760              : 
     761         6814 :       DO img = 2, nimg
     762         6814 :          CALL dbcsr_create(mat_2c(img), template=mat_2c(1))
     763              :       END DO
     764              : 
     765              :       CALL build_2c_integrals(mat_2c, 0.0_dp, qs_env, sab_RI, basis_set_RI, basis_set_RI, &
     766              :                               ri_metric, do_kpoints=do_kpoints, ext_kpoints=kpoints, &
     767         1004 :                               regularization_RI=my_regularization_RI)
     768              : 
     769         1004 :       CALL dbcsr_distribution_release(dbcsr_dist)
     770         1004 :       DEALLOCATE (basis_set_RI)
     771              : 
     772         1004 :       IF (my_put_mat_KS_env) THEN
     773          144 :          CALL get_ks_env(qs_env%ks_env, matrix_s_RI_aux_kp=matrix_s_RI_aux_transl)
     774          144 :          IF (ASSOCIATED(matrix_s_RI_aux_transl)) CALL dbcsr_deallocate_matrix_set(matrix_s_RI_aux_transl)
     775              :       END IF
     776         1004 :       CALL dbcsr_allocate_matrix_set(matrix_s_RI_aux_transl, 1, nimg)
     777         7818 :       DO img = 1, nimg
     778         6814 :          ALLOCATE (matrix_s_RI_aux_transl(1, img)%matrix)
     779         6814 :          CALL dbcsr_copy(matrix_s_RI_aux_transl(1, img)%matrix, mat_2c(img))
     780         7818 :          CALL dbcsr_release(mat_2c(img))
     781              :       END DO
     782              : 
     783         1004 :       IF (my_put_mat_KS_env) THEN
     784          144 :          CALL set_ks_env(qs_env%ks_env, matrix_s_RI_aux_kp=matrix_s_RI_aux_transl)
     785              :       END IF
     786              : 
     787         1004 :       IF (PRESENT(ikp_ext)) nkp = 1
     788              : 
     789         1004 :       IF (do_kpoints) THEN
     790         2614 :          ALLOCATE (cfm_matrix_M_kpoints(nkp))
     791         1510 :          DO ikp = 1, nkp
     792         1510 :             CALL cp_cfm_create(cfm_matrix_M_kpoints(ikp), fm_matrix_L_struct)
     793              :          END DO
     794              :       ELSE
     795         1356 :          ALLOCATE (fm_matrix_M_kpoints(1, 1))
     796          452 :          CALL cp_fm_create(fm_matrix_M_kpoints(1, 1), fm_matrix_L_struct)
     797          452 :          CALL cp_fm_set_all(fm_matrix_M_kpoints(1, 1), 0.0_dp)
     798              :       END IF
     799              : 
     800         1004 :       NULLIFY (fm_struct)
     801              :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=dimen_RI, &
     802         1004 :                                ncol_global=dimen_RI, para_env=para_env)
     803              : 
     804         1004 :       CALL cp_fm_create(fm_matrix_S_global, fm_struct)
     805         1004 :       CALL cp_fm_set_all(fm_matrix_S_global, 0.0_dp)
     806         1004 :       IF (do_kpoints) CALL cp_cfm_create(cfm_matrix_S_global, fm_struct, set_zero=.TRUE.)
     807              : 
     808         1004 :       IF (do_kpoints) THEN
     809              : 
     810          552 :          ALLOCATE (rmatrix, cmatrix, tmpmat)
     811              :          CALL dbcsr_create(rmatrix, template=matrix_s_RI_aux_transl(1, 1)%matrix, &
     812          552 :                            matrix_type=dbcsr_type_symmetric)
     813              :          CALL dbcsr_create(cmatrix, template=matrix_s_RI_aux_transl(1, 1)%matrix, &
     814          552 :                            matrix_type=dbcsr_type_antisymmetric)
     815              :          CALL dbcsr_create(tmpmat, template=matrix_s_RI_aux_transl(1, 1)%matrix, &
     816          552 :                            matrix_type=dbcsr_type_no_symmetry)
     817          552 :          CALL cp_dbcsr_alloc_block_from_nbl(rmatrix, sab_RI)
     818          552 :          CALL cp_dbcsr_alloc_block_from_nbl(cmatrix, sab_RI)
     819              : 
     820         1510 :          DO ikp = 1, nkp
     821              : 
     822              :             ! s matrix is not spin dependent, double the work
     823          958 :             CALL dbcsr_set(rmatrix, 0.0_dp)
     824          958 :             CALL dbcsr_set(cmatrix, 0.0_dp)
     825              : 
     826          958 :             IF (PRESENT(ikp_ext)) THEN
     827          530 :                ikp_for_xkp = ikp_ext
     828              :             ELSE
     829              :                ikp_for_xkp = ikp
     830              :             END IF
     831              : 
     832              :             CALL rskp_transform(rmatrix=rmatrix, cmatrix=cmatrix, rsmat=matrix_s_RI_aux_transl, ispin=1, &
     833          958 :                                 xkp=xkp(1:3, ikp_for_xkp), cell_to_index=cell_to_index, sab_nl=sab_RI)
     834              : 
     835          958 :             CALL dbcsr_set(tmpmat, 0.0_dp)
     836          958 :             CALL dbcsr_desymmetrize(rmatrix, tmpmat)
     837              : 
     838          958 :             CALL cp_fm_set_all(fm_matrix_S_global, 0.0_dp)
     839          958 :             CALL copy_dbcsr_to_fm(tmpmat, fm_matrix_S_global)
     840          958 :             CALL cp_fm_to_cfm(msourcer=fm_matrix_S_global, mtarget=cfm_matrix_S_global)
     841              : 
     842          958 :             CALL dbcsr_set(tmpmat, 0.0_dp)
     843          958 :             CALL dbcsr_desymmetrize(cmatrix, tmpmat)
     844              : 
     845          958 :             CALL cp_fm_set_all(fm_matrix_S_global, 0.0_dp)
     846          958 :             CALL copy_dbcsr_to_fm(tmpmat, fm_matrix_S_global)
     847          958 :             CALL cp_cfm_scale_and_add_fm(z_one, cfm_matrix_S_global, gaussi, fm_matrix_S_global)
     848         1510 :             CALL cp_cfm_copy_general(cfm_matrix_S_global, cfm_matrix_M_kpoints(ikp), para_env)
     849              : 
     850              :          END DO
     851              : 
     852          552 :          CALL dbcsr_deallocate_matrix(rmatrix)
     853          552 :          CALL dbcsr_deallocate_matrix(cmatrix)
     854          552 :          CALL dbcsr_deallocate_matrix(tmpmat)
     855              : 
     856              :       ELSE
     857              : 
     858              :          NULLIFY (matrix_s_RI_aux_desymm)
     859          452 :          ALLOCATE (matrix_s_RI_aux_desymm)
     860              :          CALL dbcsr_create(matrix_s_RI_aux_desymm, template=matrix_s_RI_aux_transl(1, 1)%matrix, &
     861          452 :                            name='S_RI non_symm', matrix_type=dbcsr_type_no_symmetry)
     862              : 
     863          452 :          CALL dbcsr_desymmetrize(matrix_s_RI_aux_transl(1, 1)%matrix, matrix_s_RI_aux_desymm)
     864              : 
     865          452 :          CALL copy_dbcsr_to_fm(matrix_s_RI_aux_desymm, fm_matrix_S_global)
     866              : 
     867          452 :          CALL cp_fm_copy_general(fm_matrix_S_global, fm_matrix_M_kpoints(1, 1), para_env)
     868              : 
     869          452 :          CALL dbcsr_deallocate_matrix(matrix_s_RI_aux_desymm)
     870              : 
     871              :       END IF
     872              : 
     873         1004 :       CALL release_neighbor_list_sets(sab_RI)
     874              : 
     875         1004 :       CALL cp_fm_struct_release(fm_struct)
     876              : 
     877         1004 :       CALL cp_fm_release(fm_matrix_S_global)
     878              : 
     879         1004 :       IF (do_kpoints) THEN
     880          552 :          CALL cp_cfm_release(cfm_matrix_S_global)
     881              :       ELSE
     882          452 :          CPASSERT(PRESENT(fm_matrix_Minv_L_gamma))
     883          452 :          CALL MOVE_ALLOC(fm_matrix_M_kpoints, fm_matrix_Minv_L_gamma)
     884              :       END IF
     885              : 
     886         1004 :       IF (.NOT. my_put_mat_KS_env) THEN
     887          860 :          CALL dbcsr_deallocate_matrix_set(matrix_s_RI_aux_transl)
     888              :       END IF
     889              : 
     890         1004 :       CALL timestop(handle)
     891              : 
     892         4016 :    END SUBROUTINE RI_2c_integral_mat_core
     893              : 
     894              : ! **************************************************************************************************
     895              : !> \brief Copies a real/imaginary DBCSR pair into its native complex full-matrix representation.
     896              : !> \param matrix_re ...
     897              : !> \param matrix_im ...
     898              : !> \param fm_work ...
     899              : !> \param cfm_matrix ...
     900              : ! **************************************************************************************************
     901          428 :    SUBROUTINE copy_dbcsr_pair_to_cfm(matrix_re, matrix_im, fm_work, cfm_matrix)
     902              :       TYPE(dbcsr_type), POINTER                          :: matrix_re, matrix_im
     903              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: fm_work
     904              :       TYPE(cp_cfm_type), INTENT(INOUT)                   :: cfm_matrix
     905              : 
     906          428 :       CALL cp_fm_set_all(fm_work, 0.0_dp)
     907          428 :       CALL copy_dbcsr_to_fm(matrix_re, fm_work)
     908          428 :       CALL cp_fm_to_cfm(msourcer=fm_work, mtarget=cfm_matrix)
     909              : 
     910          428 :       CALL cp_fm_set_all(fm_work, 0.0_dp)
     911          428 :       CALL copy_dbcsr_to_fm(matrix_im, fm_work)
     912          428 :       CALL cp_cfm_scale_and_add_fm(z_one, cfm_matrix, gaussi, fm_work)
     913          428 :    END SUBROUTINE copy_dbcsr_pair_to_cfm
     914              : 
     915              : ! **************************************************************************************************
     916              : !> \brief ...
     917              : !> \param qs_env ...
     918              : !> \param eri_method ...
     919              : !> \param eri_param ...
     920              : !> \param para_env ...
     921              : !> \param para_env_sub ...
     922              : !> \param para_env_L ...
     923              : !> \param mp2_memory ...
     924              : !> \param fm_matrix_L ...
     925              : !> \param ngroup ...
     926              : !> \param color_sub ...
     927              : !> \param dimen_RI ...
     928              : !> \param my_group_L_size ...
     929              : !> \param my_group_L_start ...
     930              : !> \param my_group_L_end ...
     931              : !> \param gd_array ...
     932              : !> \param calc_PQ_cond_num ...
     933              : !> \param cond_num ...
     934              : !> \param num_small_eigen ...
     935              : !> \param potential ...
     936              : !> \param sab_orb_sub ...
     937              : !> \param do_im_time ...
     938              : !> \param fm_matrix_L_struct ...
     939              : ! **************************************************************************************************
     940          732 :    SUBROUTINE compute_2c_integrals(qs_env, eri_method, eri_param, para_env, para_env_sub, para_env_L, mp2_memory, &
     941              :                                    fm_matrix_L, ngroup, color_sub, dimen_RI, &
     942              :                                    my_group_L_size, my_group_L_start, my_group_L_end, &
     943              :                                    gd_array, calc_PQ_cond_num, cond_num, num_small_eigen, potential, &
     944              :                                    sab_orb_sub, do_im_time, fm_matrix_L_struct)
     945              : 
     946              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     947              :       INTEGER, INTENT(IN)                                :: eri_method
     948              :       TYPE(cp_eri_mme_param), POINTER                    :: eri_param
     949              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
     950              :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env_sub
     951              :       TYPE(mp_para_env_type), INTENT(OUT), POINTER       :: para_env_L
     952              :       REAL(KIND=dp), INTENT(IN)                          :: mp2_memory
     953              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_matrix_L
     954              :       INTEGER, INTENT(IN)                                :: ngroup, color_sub
     955              :       INTEGER, INTENT(OUT)                               :: dimen_RI, my_group_L_size, &
     956              :                                                             my_group_L_start, my_group_L_end
     957              :       TYPE(group_dist_d1_type), INTENT(OUT)              :: gd_array
     958              :       LOGICAL, INTENT(IN)                                :: calc_PQ_cond_num
     959              :       REAL(KIND=dp), INTENT(OUT)                         :: cond_num
     960              :       INTEGER, INTENT(OUT)                               :: num_small_eigen
     961              :       TYPE(libint_potential_type), INTENT(IN)            :: potential
     962              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     963              :          POINTER                                         :: sab_orb_sub
     964              :       LOGICAL, INTENT(IN), OPTIONAL                      :: do_im_time
     965              :       TYPE(cp_fm_struct_type), OPTIONAL, POINTER         :: fm_matrix_L_struct
     966              : 
     967              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_2c_integrals'
     968              : 
     969              :       INTEGER :: best_group_size, color_L, group_size, handle, handle2, i_global, iatom, iiB, &
     970              :          ikind, iproc, j_global, jjB, natom, ncol_local, nkind, nrow_local, nsgf, potential_type, &
     971              :          proc_receive, proc_receive_static, proc_send_static, proc_shift, rec_L_end, rec_L_size, &
     972              :          rec_L_start, strat_group_size
     973          732 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: kind_of
     974          732 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     975              :       LOGICAL                                            :: my_do_im_time
     976              :       REAL(KIND=dp)                                      :: min_mem_for_QK
     977          732 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: egen_L
     978          732 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: L_external_col, L_local_col
     979          732 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     980              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env_L
     981              :       TYPE(cp_fm_type)                                   :: fm_matrix_L_diag
     982          732 :       TYPE(group_dist_d1_type)                           :: gd_sub_array
     983              :       TYPE(gto_basis_set_type), POINTER                  :: basis_set_a
     984          732 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     985          732 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     986              : 
     987          732 :       CALL timeset(routineN, handle)
     988              : 
     989          732 :       my_do_im_time = .FALSE.
     990          732 :       IF (PRESENT(do_im_time)) THEN
     991          696 :          my_do_im_time = do_im_time
     992              :       END IF
     993              : 
     994              :       ! get stuff
     995              :       CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, qs_kind_set=qs_kind_set, &
     996          732 :                       particle_set=particle_set)
     997              : 
     998          732 :       nkind = SIZE(qs_kind_set)
     999          732 :       natom = SIZE(particle_set)
    1000              : 
    1001          732 :       CALL get_atomic_kind_set(atomic_kind_set, kind_of=kind_of)
    1002              : 
    1003         2072 :       DO ikind = 1, nkind
    1004         1340 :          CALL get_qs_kind(qs_kind=qs_kind_set(ikind), basis_set=basis_set_a, basis_type="RI_AUX")
    1005         2072 :          CPASSERT(ASSOCIATED(basis_set_a))
    1006              :       END DO
    1007              : 
    1008          732 :       dimen_RI = 0
    1009         2872 :       DO iatom = 1, natom
    1010         2140 :          ikind = kind_of(iatom)
    1011         2140 :          CALL get_qs_kind(qs_kind=qs_kind_set(ikind), nsgf=nsgf, basis_type="RI_AUX")
    1012         2872 :          dimen_RI = dimen_RI + nsgf
    1013              :       END DO
    1014              : 
    1015              :       ! check that very small systems are not running on too many processes
    1016          732 :       IF (dimen_RI < ngroup) THEN
    1017              :          CALL cp_abort(__LOCATION__, "Product of block size and number "// &
    1018            0 :                        "of RI functions should not exceed total number of processes")
    1019              :       END IF
    1020              : 
    1021          732 :       CALL create_group_dist(gd_array, ngroup, dimen_RI)
    1022              : 
    1023          732 :       CALL get_group_dist(gd_array, color_sub, my_group_L_start, my_group_L_end, my_group_L_size)
    1024              : 
    1025          732 :       CALL timeset(routineN//"_loop_lm", handle2)
    1026              : 
    1027         2928 :       ALLOCATE (L_local_col(dimen_RI, my_group_L_size))
    1028          732 :       L_local_col = 0.0_dp
    1029              : 
    1030          732 :       potential_type = potential%potential_type
    1031              : 
    1032              :       IF ((eri_method == do_eri_mme .OR. eri_method == do_eri_os) &
    1033          732 :           .AND. potential_type == do_potential_coulomb .OR. &
    1034              :           (eri_method == do_eri_mme .AND. potential_type == do_potential_long)) THEN
    1035              : 
    1036              :          CALL mp2_eri_2c_integrate(eri_param, potential, para_env_sub, qs_env, &
    1037              :                                    basis_type_a="RI_AUX", basis_type_b="RI_AUX", &
    1038              :                                    hab=L_local_col, first_b=my_group_L_start, last_b=my_group_L_end, &
    1039          334 :                                    eri_method=eri_method)
    1040              : 
    1041              :       ELSE IF (eri_method == do_eri_gpw .OR. &
    1042              :                (potential_type == do_potential_long .AND. qs_env%mp2_env%eri_method == do_eri_os) &
    1043          398 :                .OR. (potential_type == do_potential_id .AND. qs_env%mp2_env%eri_method == do_eri_mme)) THEN
    1044              : 
    1045              :          CALL mp2_eri_2c_integrate_gpw(qs_env, para_env_sub, my_group_L_start, my_group_L_end, &
    1046          398 :                                        natom, potential, sab_orb_sub, L_local_col, kind_of)
    1047              : 
    1048              :       ELSE
    1049            0 :          CPABORT("unknown ERI method")
    1050              :       END IF
    1051              : 
    1052          732 :       CALL timestop(handle2)
    1053              : 
    1054              :       ! split the total number of proc in a subgroup of the size of ~1/10 of the
    1055              :       ! total num of proc
    1056          732 :       best_group_size = para_env%num_pe
    1057              : 
    1058          732 :       strat_group_size = MAX(1, para_env%num_pe/10)
    1059              : 
    1060          732 :       min_mem_for_QK = REAL(dimen_RI, KIND=dp)*dimen_RI*3.0_dp*8.0_dp/1024_dp/1024_dp
    1061              : 
    1062          732 :       group_size = strat_group_size - 1
    1063          766 :       DO iproc = strat_group_size, para_env%num_pe
    1064          766 :          group_size = group_size + 1
    1065              :          ! check that group_size is a multiple of sub_group_size and a divisor of
    1066              :          ! the total num of proc
    1067          766 :          IF (MOD(para_env%num_pe, group_size) /= 0 .OR. MOD(group_size, para_env_sub%num_pe) /= 0) CYCLE
    1068              : 
    1069              :          ! check for memory
    1070          732 :          IF (REAL(group_size, KIND=dp)*mp2_memory < min_mem_for_QK) CYCLE
    1071              : 
    1072              :          best_group_size = group_size
    1073           34 :          EXIT
    1074              :       END DO
    1075              : 
    1076          732 :       IF (my_do_im_time) THEN
    1077              :          ! para_env_L is the para_env for im. time to avoid bug
    1078          144 :          best_group_size = para_env%num_pe
    1079              :       END IF
    1080              : 
    1081              :       ! create the L group
    1082          732 :       color_L = para_env%mepos/best_group_size
    1083          732 :       ALLOCATE (para_env_L)
    1084          732 :       CALL para_env_L%from_split(para_env, color_L)
    1085              : 
    1086              :       ! create the blacs_L
    1087          732 :       NULLIFY (blacs_env_L)
    1088          732 :       CALL cp_blacs_env_create(blacs_env=blacs_env_L, para_env=para_env_L)
    1089              : 
    1090              :       ! create the full matrix L defined in the L group
    1091          732 :       CALL create_matrix_L(fm_matrix_L, blacs_env_L, dimen_RI, para_env_L, "fm_matrix_L", fm_matrix_L_struct)
    1092              : 
    1093          732 :       IF (my_do_im_time .AND. para_env%num_pe > 1) THEN
    1094              : 
    1095              :          CALL cp_array_columns_to_fm(fm_matrix_L, L_local_col, para_env, &
    1096              :                                      my_group_L_start, my_group_L_end, &
    1097          144 :                                      dimen_RI)
    1098              : 
    1099              :       ELSE
    1100          588 :          BLOCK
    1101              :             TYPE(mp_comm_type) :: comm_exchange
    1102              : 
    1103          588 :             CALL comm_exchange%from_split(para_env_L, para_env_sub%mepos)
    1104              : 
    1105              :             CALL create_group_dist(gd_sub_array, my_group_L_start, &
    1106          588 :                                    my_group_L_end, my_group_L_size, comm_exchange)
    1107              : 
    1108              :             CALL cp_fm_get_info(matrix=fm_matrix_L, &
    1109              :                                 nrow_local=nrow_local, &
    1110              :                                 ncol_local=ncol_local, &
    1111              :                                 row_indices=row_indices, &
    1112          588 :                                 col_indices=col_indices)
    1113              : 
    1114        45076 :             DO jjB = 1, ncol_local
    1115        44488 :                j_global = col_indices(jjB)
    1116        45076 :                IF (j_global >= my_group_L_start .AND. j_global <= my_group_L_end) THEN
    1117      1872770 :                   DO iiB = 1, nrow_local
    1118      1849406 :                      i_global = row_indices(iiB)
    1119      1872770 :                      fm_matrix_L%local_data(iiB, jjB) = L_local_col(i_global, j_global - my_group_L_start + 1)
    1120              :                   END DO
    1121              :                END IF
    1122              :             END DO
    1123              : 
    1124          588 :             proc_send_static = MODULO(comm_exchange%mepos + 1, comm_exchange%num_pe)
    1125          588 :             proc_receive_static = MODULO(comm_exchange%mepos - 1, comm_exchange%num_pe)
    1126              : 
    1127          588 :             DO proc_shift = 1, comm_exchange%num_pe - 1
    1128            0 :                proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
    1129              : 
    1130            0 :                CALL get_group_dist(gd_sub_array, proc_receive, rec_L_start, rec_L_end, rec_L_size)
    1131              : 
    1132            0 :                ALLOCATE (L_external_col(dimen_RI, rec_L_size))
    1133            0 :                L_external_col = 0.0_dp
    1134              : 
    1135            0 :                CALL comm_exchange%sendrecv(L_local_col, proc_send_static, L_external_col, proc_receive_static)
    1136              : 
    1137            0 :                DO jjB = 1, ncol_local
    1138            0 :                   j_global = col_indices(jjB)
    1139            0 :                   IF (j_global >= rec_L_start .AND. j_global <= rec_L_end) THEN
    1140            0 :                      DO iiB = 1, nrow_local
    1141            0 :                         i_global = row_indices(iiB)
    1142            0 :                         fm_matrix_L%local_data(iiB, jjB) = L_external_col(i_global, j_global - rec_L_start + 1)
    1143              :                      END DO
    1144              :                   END IF
    1145              :                END DO
    1146              : 
    1147          588 :                CALL MOVE_ALLOC(L_external_col, L_local_col)
    1148              :             END DO
    1149              : 
    1150          588 :             CALL release_group_dist(gd_sub_array)
    1151         1176 :             CALL comm_exchange%free()
    1152              :          END BLOCK
    1153              :       END IF
    1154              : 
    1155          732 :       DEALLOCATE (L_local_col)
    1156              : 
    1157              :       ! create the new group for the sum of the local data over all processes
    1158              :       BLOCK
    1159              :          TYPE(mp_comm_type) :: comm_exchange
    1160          732 :          comm_exchange = fm_matrix_L%matrix_struct%context%interconnect(para_env)
    1161          732 :          CALL comm_exchange%sum(fm_matrix_L%local_data)
    1162         1464 :          CALL comm_exchange%free()
    1163              :       END BLOCK
    1164              : 
    1165          732 :       cond_num = 1.0_dp
    1166          732 :       num_small_eigen = 0
    1167          732 :       IF (calc_PQ_cond_num) THEN
    1168              :          ! calculate the condition number of the (P|Q) matrix
    1169              :          ! create a copy of the matrix
    1170              : 
    1171            0 :          CALL create_matrix_L(fm_matrix_L_diag, blacs_env_L, dimen_RI, para_env_L, "fm_matrix_L_diag", fm_matrix_L_struct)
    1172              : 
    1173            0 :          CALL cp_fm_to_fm(source=fm_matrix_L, destination=fm_matrix_L_diag)
    1174              : 
    1175            0 :          ALLOCATE (egen_L(dimen_RI))
    1176              : 
    1177            0 :          egen_L = 0.0_dp
    1178            0 :          CALL cp_fm_syevx(matrix=fm_matrix_L_diag, eigenvalues=egen_L)
    1179              : 
    1180            0 :          num_small_eigen = 0
    1181            0 :          DO iiB = 1, dimen_RI
    1182            0 :             IF (ABS(egen_L(iiB)) < 0.001_dp) num_small_eigen = num_small_eigen + 1
    1183              :          END DO
    1184              : 
    1185            0 :          cond_num = MAXVAL(ABS(egen_L))/MINVAL(ABS(egen_L))
    1186              : 
    1187            0 :          CALL cp_fm_release(fm_matrix_L_diag)
    1188              : 
    1189            0 :          DEALLOCATE (egen_L)
    1190              :       END IF
    1191              : 
    1192              :       ! release blacs_env
    1193          732 :       CALL cp_blacs_env_release(blacs_env_L)
    1194              : 
    1195          732 :       CALL timestop(handle)
    1196              : 
    1197         3660 :    END SUBROUTINE compute_2c_integrals
    1198              : 
    1199              : ! **************************************************************************************************
    1200              : !> \brief ...
    1201              : !> \param matrix ...
    1202              : !> \param num_small_evals ...
    1203              : !> \param cond_num ...
    1204              : !> \param eps_svd ...
    1205              : !> \param do_inversion ...
    1206              : !> \param para_env ...
    1207              : ! **************************************************************************************************
    1208           46 :    SUBROUTINE matrix_root_with_svd(matrix, num_small_evals, cond_num, eps_svd, do_inversion, para_env)
    1209              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: matrix
    1210              :       INTEGER, INTENT(OUT)                               :: num_small_evals
    1211              :       REAL(KIND=dp), INTENT(OUT)                         :: cond_num
    1212              :       REAL(KIND=dp), INTENT(IN)                          :: eps_svd
    1213              :       LOGICAL, INTENT(IN)                                :: do_inversion
    1214              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    1215              : 
    1216              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'matrix_root_with_svd'
    1217              : 
    1218              :       INTEGER                                            :: group_size_L, handle, ii, needed_evals, &
    1219              :                                                             nrow, pos_max(1)
    1220           46 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: num_eval
    1221              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
    1222              :       TYPE(cp_fm_type)                                   :: evecs
    1223              :       TYPE(mp_comm_type)                                 :: comm_exchange
    1224              : 
    1225           46 :       CALL timeset(routineN, handle)
    1226              : 
    1227              :       ! Create arrays carrying eigenvalues and eigenvectors later
    1228           46 :       CALL cp_fm_get_info(matrix=matrix, nrow_global=nrow)
    1229              : 
    1230          138 :       ALLOCATE (evals(nrow))
    1231           46 :       evals = 0
    1232              : 
    1233           46 :       CALL cp_fm_create(evecs, matrix%matrix_struct)
    1234              : 
    1235              :       ! Perform the EVD (=SVD of a positive semidefinite matrix)
    1236           46 :       CALL choose_eigv_solver(matrix, evecs, evals)
    1237              : 
    1238              :       ! Determine the number of neglectable eigenvalues assuming that the eigenvalues are in ascending order
    1239           46 :       num_small_evals = 0
    1240          204 :       DO ii = 1, nrow
    1241          204 :          IF (evals(ii) > eps_svd) THEN
    1242           46 :             num_small_evals = ii - 1
    1243           46 :             EXIT
    1244              :          END IF
    1245              :       END DO
    1246           46 :       needed_evals = nrow - num_small_evals
    1247              : 
    1248              :       ! Get the condition number w.r.t. considered eigenvalues
    1249           46 :       cond_num = evals(nrow)/evals(num_small_evals + 1)
    1250              : 
    1251              :       ! Determine the eigenvalues of the request matrix root or its inverse
    1252          204 :       evals(1:num_small_evals) = 0.0_dp
    1253           46 :       IF (do_inversion) THEN
    1254         1008 :          evals(num_small_evals + 1:nrow) = 1.0_dp/SQRT(evals(num_small_evals + 1:nrow))
    1255              :       ELSE
    1256         2754 :          evals(num_small_evals + 1:nrow) = SQRT(evals(num_small_evals + 1:nrow))
    1257              :       END IF
    1258              : 
    1259           46 :       CALL cp_fm_column_scale(evecs, evals)
    1260              : 
    1261              :       ! As it turns out, the results in the subgroups differ.
    1262              :       ! Thus, we have to equilibrate the results.
    1263              :       ! Step 1: Get a communicator connecting processes with same id within subgroups
    1264              :       ! use that group_size_L is divisible by the total number of processes (see above)
    1265           46 :       group_size_L = para_env%num_pe/matrix%matrix_struct%para_env%num_pe
    1266           46 :       comm_exchange = matrix%matrix_struct%context%interconnect(para_env)
    1267              : 
    1268          138 :       ALLOCATE (num_eval(0:group_size_L - 1))
    1269           46 :       CALL comm_exchange%allgather(num_small_evals, num_eval)
    1270              : 
    1271          122 :       num_small_evals = MINVAL(num_eval)
    1272              : 
    1273          122 :       IF (num_small_evals /= MAXVAL(num_eval)) THEN
    1274              :          ! Step 2: Get position of maximum value
    1275            0 :          pos_max = MAXLOC(num_eval)
    1276            0 :          num_small_evals = num_eval(pos_max(1))
    1277            0 :          needed_evals = nrow - num_small_evals
    1278              : 
    1279              :          ! Step 3: Broadcast your local data to all other processes
    1280            0 :          CALL comm_exchange%bcast(evecs%local_data, pos_max(1))
    1281            0 :          CALL comm_exchange%bcast(cond_num, pos_max(1))
    1282              :       END IF
    1283              : 
    1284           46 :       DEALLOCATE (num_eval)
    1285              : 
    1286           46 :       CALL comm_exchange%free()
    1287              : 
    1288           46 :       CALL reset_size_matrix(matrix, needed_evals, matrix%matrix_struct)
    1289              : 
    1290              :       ! Copy the needed eigenvectors
    1291           46 :       CALL cp_fm_to_fm(evecs, matrix, needed_evals, num_small_evals + 1)
    1292              : 
    1293           46 :       CALL cp_fm_release(evecs)
    1294              : 
    1295           46 :       CALL timestop(handle)
    1296              : 
    1297          138 :    END SUBROUTINE matrix_root_with_svd
    1298              : 
    1299              : ! **************************************************************************************************
    1300              : !> \brief ...
    1301              : !> \param matrix ...
    1302              : !> \param new_size ...
    1303              : !> \param fm_struct_template ...
    1304              : ! **************************************************************************************************
    1305          160 :    SUBROUTINE reset_size_matrix(matrix, new_size, fm_struct_template)
    1306              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: matrix
    1307              :       INTEGER, INTENT(IN)                                :: new_size
    1308              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct_template
    1309              : 
    1310              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'reset_size_matrix'
    1311              : 
    1312              :       INTEGER                                            :: handle
    1313              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1314              : 
    1315           80 :       CALL timeset(routineN, handle)
    1316              : 
    1317              :       ! Choose the block sizes as large as in the template for the later steps
    1318           80 :       NULLIFY (fm_struct)
    1319           80 :       CALL cp_fm_struct_create(fm_struct, ncol_global=new_size, template_fmstruct=fm_struct_template, force_block=.TRUE.)
    1320              : 
    1321           80 :       CALL cp_fm_release(matrix)
    1322              : 
    1323           80 :       CALL cp_fm_create(matrix, fm_struct)
    1324           80 :       CALL cp_fm_set_all(matrix, 0.0_dp)
    1325              : 
    1326           80 :       CALL cp_fm_struct_release(fm_struct)
    1327              : 
    1328           80 :       CALL timestop(handle)
    1329              : 
    1330           80 :    END SUBROUTINE reset_size_matrix
    1331              : 
    1332              : ! **************************************************************************************************
    1333              : !> \brief ...
    1334              : !> \param fm_matrix_L ...
    1335              : !> \param dimen_RI ...
    1336              : !> \param do_inversion ...
    1337              : ! **************************************************************************************************
    1338         1640 :    SUBROUTINE cholesky_decomp(fm_matrix_L, dimen_RI, do_inversion)
    1339              : 
    1340              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_matrix_L
    1341              :       INTEGER, INTENT(IN)                                :: dimen_RI
    1342              :       LOGICAL, INTENT(IN)                                :: do_inversion
    1343              : 
    1344              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'cholesky_decomp'
    1345              : 
    1346              :       INTEGER                                            :: handle, i_global, iiB, info_chol, &
    1347              :                                                             j_global, jjB, ncol_local, nrow_local
    1348          820 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    1349              : 
    1350          820 :       CALL timeset(routineN, handle)
    1351              : 
    1352              :       ! do cholesky decomposition
    1353          820 :       CALL cp_fm_cholesky_decompose(matrix=fm_matrix_L, n=dimen_RI, info_out=info_chol)
    1354          820 :       CPASSERT(info_chol == 0)
    1355              : 
    1356          820 :       IF (.NOT. do_inversion) THEN
    1357              :          ! clean the lower part of the L^{-1} matrix (just to not have surprises afterwards)
    1358              :          CALL cp_fm_get_info(matrix=fm_matrix_L, &
    1359              :                              nrow_local=nrow_local, &
    1360              :                              ncol_local=ncol_local, &
    1361              :                              row_indices=row_indices, &
    1362          124 :                              col_indices=col_indices)
    1363        10752 :          DO jjB = 1, ncol_local
    1364        10628 :             j_global = col_indices(jjB)
    1365       567250 :             DO iiB = 1, nrow_local
    1366       556498 :                i_global = row_indices(iiB)
    1367       567126 :                IF (j_global < i_global) fm_matrix_L%local_data(iiB, jjB) = 0.0_dp
    1368              :             END DO
    1369              :          END DO
    1370              : 
    1371              :       END IF
    1372              : 
    1373          820 :       CALL timestop(handle)
    1374              : 
    1375          820 :    END SUBROUTINE cholesky_decomp
    1376              : 
    1377              : ! **************************************************************************************************
    1378              : !> \brief ...
    1379              : !> \param cfm_matrix_M_kpoints ...
    1380              : !> \param cfm_matrix_L_kpoints ...
    1381              : !> \param cfm_matrix_Minv_L_kpoints ...
    1382              : !> \param dimen_RI ...
    1383              : !> \param kpoints ...
    1384              : !> \param eps_eigval_S ...
    1385              : ! **************************************************************************************************
    1386           22 :    SUBROUTINE inversion_of_M_and_mult_with_chol_dec_of_V(cfm_matrix_M_kpoints, cfm_matrix_L_kpoints, &
    1387              :                                                          cfm_matrix_Minv_L_kpoints, dimen_RI, kpoints, eps_eigval_S)
    1388              : 
    1389              :       TYPE(cp_cfm_type), DIMENSION(:), INTENT(IN)        :: cfm_matrix_M_kpoints
    1390              :       TYPE(cp_cfm_type), DIMENSION(:), INTENT(INOUT)     :: cfm_matrix_L_kpoints
    1391              :       TYPE(cp_cfm_type), ALLOCATABLE, DIMENSION(:), &
    1392              :          INTENT(INOUT)                                   :: cfm_matrix_Minv_L_kpoints
    1393              :       INTEGER, INTENT(IN)                                :: dimen_RI
    1394              :       TYPE(kpoint_type), POINTER                         :: kpoints
    1395              :       REAL(KIND=dp), INTENT(IN)                          :: eps_eigval_S
    1396              : 
    1397              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'inversion_of_M_and_mult_with_chol_dec_of_V'
    1398              : 
    1399              :       INTEGER                                            :: handle, ikp, nkp
    1400              :       TYPE(cp_cfm_type)                                  :: cfm_matrix_M_tmp
    1401              :       TYPE(cp_fm_struct_type), POINTER                   :: matrix_struct
    1402              : 
    1403           22 :       CALL timeset(routineN, handle)
    1404              : 
    1405           22 :       matrix_struct => cfm_matrix_M_kpoints(1)%matrix_struct
    1406              : 
    1407           22 :       CALL cp_cfm_create(cfm_matrix_M_tmp, matrix_struct)
    1408              : 
    1409           22 :       CALL get_kpoint_info(kpoints, nkp=nkp)
    1410          494 :       ALLOCATE (cfm_matrix_Minv_L_kpoints(nkp))
    1411              : 
    1412          450 :       DO ikp = 1, nkp
    1413              : 
    1414          428 :          CALL cp_cfm_to_cfm(cfm_matrix_M_kpoints(ikp), cfm_matrix_M_tmp)
    1415              : 
    1416          428 :          CALL cp_cfm_power(cfm_matrix_M_tmp, threshold=eps_eigval_S, exponent=-1.0_dp)
    1417              : 
    1418              :          ! save L(k) = SQRT(V(k))
    1419          428 :          CALL cp_cfm_power(cfm_matrix_L_kpoints(ikp), threshold=0.0_dp, exponent=0.5_dp)
    1420              : 
    1421              :          ! get K = M^(-1)*L, where L is the Cholesky decomposition of V = L^T*L
    1422          428 :          CALL cp_cfm_create(cfm_matrix_Minv_L_kpoints(ikp), matrix_struct)
    1423              :          CALL parallel_gemm("N", "C", dimen_RI, dimen_RI, dimen_RI, z_one, cfm_matrix_M_tmp, &
    1424              :                             cfm_matrix_L_kpoints(ikp), &
    1425          450 :                             z_zero, cfm_matrix_Minv_L_kpoints(ikp))
    1426              : 
    1427              :       END DO
    1428              : 
    1429           22 :       CALL cp_cfm_release(cfm_matrix_M_tmp)
    1430              : 
    1431           22 :       CALL timestop(handle)
    1432              : 
    1433           22 :    END SUBROUTINE inversion_of_M_and_mult_with_chol_dec_of_V
    1434              : 
    1435              : ! **************************************************************************************************
    1436              : !> \brief ...
    1437              : !> \param fm_matrix_Minv_Vtrunc_Minv ...
    1438              : !> \param fm_matrix_Minv ...
    1439              : !> \param qs_env ...
    1440              : ! **************************************************************************************************
    1441           88 :    SUBROUTINE Gamma_only_inversion_of_M_and_mult_with_chol_dec_of_Vtrunc(fm_matrix_Minv_Vtrunc_Minv, &
    1442           22 :                                                                          fm_matrix_Minv, qs_env)
    1443              : 
    1444              :       TYPE(cp_fm_type), DIMENSION(:, :)                  :: fm_matrix_Minv_Vtrunc_Minv, &
    1445              :                                                             fm_matrix_Minv
    1446              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1447              : 
    1448              :       CHARACTER(LEN=*), PARAMETER :: &
    1449              :          routineN = 'Gamma_only_inversion_of_M_and_mult_with_chol_dec_of_Vtrunc'
    1450              :       REAL(KIND=dp), PARAMETER :: eps_eigval_S_Gamma_thre = 1.0E-18_dp
    1451              : 
    1452              :       INTEGER                                            :: dimen_RI, handle, ndep
    1453              :       REAL(KIND=dp)                                      :: eps_eigval_S_Gamma
    1454              :       TYPE(cp_fm_type)                                   :: fm_matrix_RI_metric_inv_work, fm_work
    1455              : 
    1456           22 :       CALL timeset(routineN, handle)
    1457              : 
    1458           22 :       CALL cp_fm_create(fm_work, fm_matrix_Minv(1, 1)%matrix_struct)
    1459           22 :       CALL cp_fm_set_all(fm_work, 0.0_dp)
    1460              : 
    1461           22 :       CALL cp_fm_create(fm_matrix_RI_metric_inv_work, fm_matrix_Minv(1, 1)%matrix_struct)
    1462           22 :       CALL cp_fm_set_all(fm_matrix_RI_metric_inv_work, 0.0_dp)
    1463              : 
    1464           22 :       CALL cp_fm_get_info(matrix=fm_matrix_Minv(1, 1), nrow_global=dimen_RI)
    1465              : 
    1466           22 :       eps_eigval_S_Gamma = qs_env%mp2_env%ri_rpa_im_time%eps_eigval_S_Gamma
    1467              : 
    1468           22 :       IF (eps_eigval_S_Gamma > eps_eigval_S_Gamma_thre) THEN
    1469              : 
    1470              :          ! remove small eigenvalues
    1471              :          CALL cp_fm_power(fm_matrix_Minv(1, 1), fm_matrix_RI_metric_inv_work, -0.5_dp, &
    1472            0 :                           eps_eigval_S_Gamma, ndep)
    1473              : 
    1474              :       ELSE
    1475              : 
    1476           22 :          CALL cholesky_decomp(fm_matrix_Minv(1, 1), dimen_RI, do_inversion=.TRUE.)
    1477              : 
    1478           22 :          CALL invert_mat(fm_matrix_Minv(1, 1))
    1479              : 
    1480              :       END IF
    1481              : 
    1482              :       CALL parallel_gemm('N', 'T', dimen_RI, dimen_RI, dimen_RI, 1.0_dp, fm_matrix_Minv(1, 1), &
    1483           22 :                          fm_matrix_Minv(1, 1), 0.0_dp, fm_matrix_RI_metric_inv_work)
    1484              : 
    1485           22 :       CALL cp_fm_to_fm(fm_matrix_RI_metric_inv_work, fm_matrix_Minv(1, 1))
    1486              : 
    1487              :       CALL parallel_gemm('N', 'N', dimen_RI, dimen_RI, dimen_RI, 1.0_dp, fm_matrix_RI_metric_inv_work, &
    1488           22 :                          fm_matrix_Minv_Vtrunc_Minv(1, 1), 0.0_dp, fm_work)
    1489              : 
    1490              :       CALL parallel_gemm('N', 'N', dimen_RI, dimen_RI, dimen_RI, 1.0_dp, fm_work, &
    1491           22 :                          fm_matrix_RI_metric_inv_work, 0.0_dp, fm_matrix_Minv_Vtrunc_Minv(1, 1))
    1492              : 
    1493           22 :       CALL cp_fm_release(fm_work)
    1494           22 :       CALL cp_fm_release(fm_matrix_RI_metric_inv_work)
    1495              : 
    1496           22 :       CALL timestop(handle)
    1497              : 
    1498           22 :    END SUBROUTINE Gamma_only_inversion_of_M_and_mult_with_chol_dec_of_Vtrunc
    1499              : 
    1500              : ! **************************************************************************************************
    1501              : !> \brief ...
    1502              : !> \param qs_env ...
    1503              : !> \param trunc_coulomb ...
    1504              : !> \param rel_cutoff_trunc_coulomb_ri_x ...
    1505              : !> \param cell_grid ...
    1506              : !> \param do_BvK_cell ...
    1507              : ! **************************************************************************************************
    1508           54 :    SUBROUTINE trunc_coulomb_for_exchange(qs_env, trunc_coulomb, rel_cutoff_trunc_coulomb_ri_x, &
    1509              :                                          cell_grid, do_BvK_cell)
    1510              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1511              :       TYPE(libint_potential_type), OPTIONAL              :: trunc_coulomb
    1512              :       REAL(KIND=dp), OPTIONAL                            :: rel_cutoff_trunc_coulomb_ri_x
    1513              :       INTEGER, DIMENSION(3), OPTIONAL                    :: cell_grid
    1514              :       LOGICAL, OPTIONAL                                  :: do_BvK_cell
    1515              : 
    1516              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'trunc_coulomb_for_exchange'
    1517              : 
    1518              :       INTEGER                                            :: handle, i_dim
    1519              :       INTEGER, DIMENSION(3)                              :: periodic
    1520              :       LOGICAL                                            :: my_do_BvK_cell
    1521              :       REAL(KIND=dp) :: kp_fac, kp_fac_idim, my_rel_cutoff_trunc_coulomb_ri_x, &
    1522              :          shortest_dist_cell_planes
    1523              :       TYPE(cell_type), POINTER                           :: cell
    1524              :       TYPE(kpoint_type), POINTER                         :: kpoints_scf
    1525              : 
    1526           54 :       CALL timeset(routineN, handle)
    1527              : 
    1528           54 :       NULLIFY (cell)
    1529           54 :       CALL get_qs_env(qs_env, cell=cell, kpoints=kpoints_scf)
    1530           54 :       CALL get_cell(cell=cell, periodic=periodic)
    1531              : 
    1532           54 :       my_do_BvK_cell = .FALSE.
    1533           54 :       IF (PRESENT(do_BvK_cell)) my_do_BvK_cell = do_BvK_cell
    1534           32 :       IF (my_do_BvK_cell) THEN
    1535              :          kp_fac = 1.0E10_dp
    1536           64 :          DO i_dim = 1, 3
    1537              :             ! look for smallest k-point mesh in periodic direction
    1538           64 :             IF (periodic(i_dim) == 1) THEN
    1539           32 :                IF (PRESENT(cell_grid)) THEN
    1540           32 :                   kp_fac_idim = REAL(cell_grid(i_dim), KIND=dp)
    1541              :                ELSE
    1542            0 :                   kp_fac_idim = REAL(kpoints_scf%nkp_grid(i_dim), KIND=dp)
    1543              :                END IF
    1544              :                IF (kp_fac > kp_fac_idim) kp_fac = kp_fac_idim
    1545              :             END IF
    1546              :          END DO
    1547              :       ELSE
    1548              :          kp_fac = 1.0_dp
    1549              :       END IF
    1550              : 
    1551           54 :       shortest_dist_cell_planes = 1.0E4_dp
    1552           54 :       IF (periodic(1) == 1) THEN
    1553           14 :          IF (shortest_dist_cell_planes > plane_distance(1, 0, 0, cell)) THEN
    1554           14 :             shortest_dist_cell_planes = plane_distance(1, 0, 0, cell)
    1555              :          END IF
    1556              :       END IF
    1557           54 :       IF (periodic(2) == 1) THEN
    1558           44 :          IF (shortest_dist_cell_planes > plane_distance(0, 1, 0, cell)) THEN
    1559           34 :             shortest_dist_cell_planes = plane_distance(0, 1, 0, cell)
    1560              :          END IF
    1561              :       END IF
    1562           54 :       IF (periodic(3) == 1) THEN
    1563           46 :          IF (shortest_dist_cell_planes > plane_distance(0, 0, 1, cell)) THEN
    1564            8 :             shortest_dist_cell_planes = plane_distance(0, 0, 1, cell)
    1565              :          END IF
    1566              :       END IF
    1567              : 
    1568           54 :       IF (PRESENT(rel_cutoff_trunc_coulomb_ri_x)) THEN
    1569           32 :          my_rel_cutoff_trunc_coulomb_ri_x = rel_cutoff_trunc_coulomb_ri_x
    1570              :       ELSE
    1571           22 :          my_rel_cutoff_trunc_coulomb_ri_x = qs_env%mp2_env%ri_rpa_im_time%rel_cutoff_trunc_coulomb_ri_x
    1572              :       END IF
    1573              : 
    1574           54 :       IF (PRESENT(trunc_coulomb)) THEN
    1575           54 :          trunc_coulomb%potential_type = do_potential_truncated
    1576              :          trunc_coulomb%cutoff_radius = shortest_dist_cell_planes* &
    1577              :                                        my_rel_cutoff_trunc_coulomb_ri_x* &
    1578           54 :                                        kp_fac
    1579           54 :          trunc_coulomb%filename = "t_c_g.dat"
    1580              :          ! dummy
    1581           54 :          trunc_coulomb%omega = 0.0_dp
    1582              :       END IF
    1583              : 
    1584           54 :       CALL timestop(handle)
    1585              : 
    1586           54 :    END SUBROUTINE trunc_coulomb_for_exchange
    1587              : 
    1588              : ! **************************************************************************************************
    1589              : !> \brief ...
    1590              : !> \param fm_matrix_L ...
    1591              : ! **************************************************************************************************
    1592         1392 :    SUBROUTINE invert_mat(fm_matrix_L)
    1593              : 
    1594              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_matrix_L
    1595              : 
    1596              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'invert_mat'
    1597              : 
    1598              :       INTEGER                                            :: handle, i_global, iiB, j_global, jjB, &
    1599              :                                                             ncol_local, nrow_local
    1600          696 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
    1601              : 
    1602          696 :       CALL timeset(routineN, handle)
    1603              : 
    1604          696 :       CALL cp_fm_triangular_invert(matrix_a=fm_matrix_L, uplo_tr='U')
    1605              : 
    1606              :       ! clear the lower part of the L^{-1} matrix (just to have no surprises afterwards)
    1607              :       CALL cp_fm_get_info(matrix=fm_matrix_L, &
    1608              :                           nrow_local=nrow_local, &
    1609              :                           ncol_local=ncol_local, &
    1610              :                           row_indices=row_indices, &
    1611          696 :                           col_indices=col_indices)
    1612              :       ! assume upper triangular format
    1613        54272 :       DO jjB = 1, ncol_local
    1614        53576 :          j_global = col_indices(jjB)
    1615      3970355 :          DO iiB = 1, nrow_local
    1616      3916083 :             i_global = row_indices(iiB)
    1617      3969659 :             IF (j_global < i_global) fm_matrix_L%local_data(iiB, jjB) = 0.0_dp
    1618              :          END DO
    1619              :       END DO
    1620              : 
    1621          696 :       CALL timestop(handle)
    1622              : 
    1623          696 :    END SUBROUTINE invert_mat
    1624              : 
    1625              : ! **************************************************************************************************
    1626              : !> \brief ...
    1627              : !> \param fm_matrix_L ...
    1628              : !> \param blacs_env_L ...
    1629              : !> \param dimen_RI ...
    1630              : !> \param para_env_L ...
    1631              : !> \param name ...
    1632              : !> \param fm_matrix_L_struct ...
    1633              : ! **************************************************************************************************
    1634          732 :    SUBROUTINE create_matrix_L(fm_matrix_L, blacs_env_L, dimen_RI, para_env_L, name, fm_matrix_L_struct)
    1635              :       TYPE(cp_fm_type), INTENT(OUT)                      :: fm_matrix_L
    1636              :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env_L
    1637              :       INTEGER, INTENT(IN)                                :: dimen_RI
    1638              :       TYPE(mp_para_env_type), POINTER                    :: para_env_L
    1639              :       CHARACTER(LEN=*), INTENT(IN)                       :: name
    1640              :       TYPE(cp_fm_struct_type), OPTIONAL, POINTER         :: fm_matrix_L_struct
    1641              : 
    1642              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'create_matrix_L'
    1643              : 
    1644              :       INTEGER                                            :: handle
    1645              :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
    1646              : 
    1647          732 :       CALL timeset(routineN, handle)
    1648              : 
    1649              :       ! create the full matrix L defined in the L group
    1650          732 :       IF (PRESENT(fm_matrix_L_struct)) THEN
    1651           36 :          CALL cp_fm_create(fm_matrix_L, fm_matrix_L_struct, name=name)
    1652              :       ELSE
    1653          696 :          NULLIFY (fm_struct)
    1654              :          CALL cp_fm_struct_create(fm_struct, context=blacs_env_L, nrow_global=dimen_RI, &
    1655          696 :                                   ncol_global=dimen_RI, para_env=para_env_L)
    1656              : 
    1657          696 :          CALL cp_fm_create(fm_matrix_L, fm_struct, name=name)
    1658              : 
    1659          696 :          CALL cp_fm_struct_release(fm_struct)
    1660              :       END IF
    1661              : 
    1662          732 :       CALL cp_fm_set_all(matrix=fm_matrix_L, alpha=0.0_dp)
    1663              : 
    1664          732 :       CALL timestop(handle)
    1665              : 
    1666          732 :    END SUBROUTINE create_matrix_L
    1667              : 
    1668              : ! **************************************************************************************************
    1669              : !> \brief ...
    1670              : !> \param fm_matrix_L ...
    1671              : !> \param my_group_L_start ...
    1672              : !> \param my_group_L_end ...
    1673              : !> \param my_group_L_size ...
    1674              : !> \param my_Lrows ...
    1675              : ! **************************************************************************************************
    1676          564 :    SUBROUTINE grep_Lcols(fm_matrix_L, &
    1677              :                          my_group_L_start, my_group_L_end, my_group_L_size, my_Lrows)
    1678              :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_matrix_L
    1679              :       INTEGER, INTENT(IN)                                :: my_group_L_start, my_group_L_end, &
    1680              :                                                             my_group_L_size
    1681              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
    1682              :          INTENT(OUT)                                     :: my_Lrows
    1683              : 
    1684              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'grep_Lcols'
    1685              : 
    1686              :       INTEGER :: dimen_RI, handle, handle2, i_global, iiB, j_global, jjB, max_row_col_local, &
    1687              :          ncol_local, ncol_rec, nrow_local, nrow_rec, proc_receive_static, proc_send_static, &
    1688              :          proc_shift
    1689          564 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: local_col_row_info, rec_col_row_info
    1690          564 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, col_indices_rec, &
    1691          564 :                                                             row_indices, row_indices_rec
    1692          564 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: local_L, rec_L
    1693              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1694          564 :          POINTER                                         :: local_L_internal
    1695              :       TYPE(mp_para_env_type), POINTER                    :: para_env
    1696              : 
    1697          564 :       CALL timeset(routineN, handle)
    1698              : 
    1699              :       CALL cp_fm_get_info(matrix=fm_matrix_L, &
    1700              :                           nrow_local=nrow_local, &
    1701              :                           ncol_local=ncol_local, &
    1702              :                           row_indices=row_indices, &
    1703              :                           col_indices=col_indices, &
    1704              :                           nrow_global=dimen_RI, &
    1705              :                           local_data=local_L_internal, &
    1706          564 :                           para_env=para_env)
    1707              : 
    1708         2256 :       ALLOCATE (my_Lrows(dimen_RI, my_group_L_size))
    1709          564 :       my_Lrows = 0.0_dp
    1710              : 
    1711         2256 :       ALLOCATE (local_L(nrow_local, ncol_local))
    1712      3469712 :       local_L(:, :) = local_L_internal(1:nrow_local, 1:ncol_local)
    1713              : 
    1714          564 :       max_row_col_local = MAX(nrow_local, ncol_local)
    1715          564 :       CALL para_env%max(max_row_col_local)
    1716              : 
    1717         2256 :       ALLOCATE (local_col_row_info(0:max_row_col_local, 2))
    1718          564 :       local_col_row_info = 0
    1719              :       ! 0,1 nrows
    1720          564 :       local_col_row_info(0, 1) = nrow_local
    1721        41995 :       local_col_row_info(1:nrow_local, 1) = row_indices(1:nrow_local)
    1722              :       ! 0,2 ncols
    1723          564 :       local_col_row_info(0, 2) = ncol_local
    1724        42888 :       local_col_row_info(1:ncol_local, 2) = col_indices(1:ncol_local)
    1725              : 
    1726         1128 :       ALLOCATE (rec_col_row_info(0:max_row_col_local, 2))
    1727              : 
    1728              :       ! accumulate data on my_Lrows starting from myself
    1729        42888 :       DO jjB = 1, ncol_local
    1730        42324 :          j_global = col_indices(jjB)
    1731        42888 :          IF (j_global >= my_group_L_start .AND. j_global <= my_group_L_end) THEN
    1732      1780088 :             DO iiB = 1, nrow_local
    1733      1757906 :                i_global = row_indices(iiB)
    1734      1780088 :                my_Lrows(i_global, j_global - my_group_L_start + 1) = local_L(iiB, jjB)
    1735              :             END DO
    1736              :          END IF
    1737              :       END DO
    1738              : 
    1739          564 :       proc_send_static = MODULO(para_env%mepos + 1, para_env%num_pe)
    1740          564 :       proc_receive_static = MODULO(para_env%mepos - 1, para_env%num_pe)
    1741              : 
    1742          564 :       CALL timeset(routineN//"_comm", handle2)
    1743              : 
    1744          588 :       DO proc_shift = 1, para_env%num_pe - 1
    1745              :          ! first exchange information on the local data
    1746           24 :          rec_col_row_info = 0
    1747           24 :          CALL para_env%sendrecv(local_col_row_info, proc_send_static, rec_col_row_info, proc_receive_static)
    1748           24 :          nrow_rec = rec_col_row_info(0, 1)
    1749           24 :          ncol_rec = rec_col_row_info(0, 2)
    1750              : 
    1751           72 :          ALLOCATE (row_indices_rec(nrow_rec))
    1752         1061 :          row_indices_rec = rec_col_row_info(1:nrow_rec, 1)
    1753              : 
    1754           72 :          ALLOCATE (col_indices_rec(ncol_rec))
    1755         2064 :          col_indices_rec = rec_col_row_info(1:ncol_rec, 2)
    1756              : 
    1757           96 :          ALLOCATE (rec_L(nrow_rec, ncol_rec))
    1758           24 :          rec_L = 0.0_dp
    1759              : 
    1760              :          ! then send and receive the real data
    1761           24 :          CALL para_env%sendrecv(local_L, proc_send_static, rec_L, proc_receive_static)
    1762              : 
    1763              :          ! accumulate the received data on my_Lrows
    1764         2064 :          DO jjB = 1, ncol_rec
    1765         2040 :             j_global = col_indices_rec(jjB)
    1766         2064 :             IF (j_global >= my_group_L_start .AND. j_global <= my_group_L_end) THEN
    1767        91028 :                DO iiB = 1, nrow_rec
    1768        88988 :                   i_global = row_indices_rec(iiB)
    1769        91028 :                   my_Lrows(i_global, j_global - my_group_L_start + 1) = rec_L(iiB, jjB)
    1770              :                END DO
    1771              :             END IF
    1772              :          END DO
    1773              : 
    1774         4200 :          local_col_row_info(:, :) = rec_col_row_info
    1775           24 :          CALL MOVE_ALLOC(rec_L, local_L)
    1776              : 
    1777           24 :          DEALLOCATE (col_indices_rec)
    1778          588 :          DEALLOCATE (row_indices_rec)
    1779              :       END DO
    1780          564 :       CALL timestop(handle2)
    1781              : 
    1782          564 :       DEALLOCATE (local_col_row_info)
    1783          564 :       DEALLOCATE (rec_col_row_info)
    1784          564 :       DEALLOCATE (local_L)
    1785              : 
    1786          564 :       CALL timestop(handle)
    1787              : 
    1788         1692 :    END SUBROUTINE grep_Lcols
    1789              : 
    1790              : END MODULE mp2_ri_2c
        

Generated by: LCOV version 2.0-1