LCOV - code coverage report
Current view: top level - src - mp2_ri_gpw.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:123285f) Lines: 97.7 % 1079 1054
Test Date: 2026-11-04 00:58:17 Functions: 100.0 % 14 14

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Routines to calculate RI-GPW-MP2 energy using pw
      10              : !> \par History
      11              : !>      06.2012 created [Mauro Del Ben]
      12              : !>      03.2019 Refactored from mp2_ri_gpw [Frederick Stein]
      13              : ! **************************************************************************************************
      14              : MODULE mp2_ri_gpw
      15              :    USE cp_log_handling,                 ONLY: cp_to_string
      16              :    USE dgemm_counter_types,             ONLY: dgemm_counter_init,&
      17              :                                               dgemm_counter_start,&
      18              :                                               dgemm_counter_stop,&
      19              :                                               dgemm_counter_type,&
      20              :                                               dgemm_counter_write
      21              :    USE group_dist_types,                ONLY: get_group_dist,&
      22              :                                               group_dist_d1_type,&
      23              :                                               maxsize,&
      24              :                                               release_group_dist
      25              :    USE kinds,                           ONLY: dp,&
      26              :                                               int_8
      27              :    USE libint_2c_3c,                    ONLY: compare_potential_types
      28              :    USE local_gemm_api,                  ONLY: LOCAL_GEMM_PU_GPU
      29              :    USE machine,                         ONLY: m_flush,&
      30              :                                               m_memory,&
      31              :                                               m_walltime
      32              :    USE message_passing,                 ONLY: mp_comm_type,&
      33              :                                               mp_para_env_type
      34              :    USE mp2_ri_grad_util,                ONLY: complete_gamma
      35              :    USE mp2_types,                       ONLY: mp2_type,&
      36              :                                               three_dim_real_array
      37              : 
      38              : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
      39              : #include "./base/base_uses.f90"
      40              : 
      41              :    IMPLICIT NONE
      42              : 
      43              :    PRIVATE
      44              : 
      45              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mp2_ri_gpw'
      46              : 
      47              :    PUBLIC :: mp2_ri_gpw_compute_en
      48              : 
      49              : CONTAINS
      50              : 
      51              : ! **************************************************************************************************
      52              : !> \brief ...
      53              : !> \param Emp2_Cou ...
      54              : !> \param Emp2_EX ...
      55              : !> \param Emp2_S ...
      56              : !> \param Emp2_T ...
      57              : !> \param BIb_C ...
      58              : !> \param mp2_env ...
      59              : !> \param para_env ...
      60              : !> \param para_env_sub ...
      61              : !> \param color_sub ...
      62              : !> \param gd_array ...
      63              : !> \param gd_B_virtual ...
      64              : !> \param Eigenval ...
      65              : !> \param nmo ...
      66              : !> \param homo ...
      67              : !> \param dimen_RI ...
      68              : !> \param unit_nr ...
      69              : !> \param calc_forces ...
      70              : !> \param calc_ex ...
      71              : ! **************************************************************************************************
      72         1062 :    SUBROUTINE mp2_ri_gpw_compute_en(Emp2_Cou, Emp2_EX, Emp2_S, Emp2_T, BIb_C, mp2_env, para_env, para_env_sub, color_sub, &
      73          354 :                                     gd_array, gd_B_virtual, &
      74          354 :                                     Eigenval, nmo, homo, dimen_RI, unit_nr, calc_forces, calc_ex)
      75              :       REAL(KIND=dp), INTENT(INOUT)                       :: Emp2_Cou, Emp2_EX, Emp2_S, Emp2_T
      76              :       TYPE(three_dim_real_array), DIMENSION(:), &
      77              :          INTENT(INOUT)                                   :: BIb_C
      78              :       TYPE(mp2_type)                                     :: mp2_env
      79              :       TYPE(mp_para_env_type), INTENT(IN), POINTER        :: para_env, para_env_sub
      80              :       INTEGER, INTENT(IN)                                :: color_sub
      81              :       TYPE(group_dist_d1_type), INTENT(INOUT)            :: gd_array
      82              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
      83              :       INTEGER, INTENT(IN)                                :: nmo
      84              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: Eigenval
      85              :       TYPE(group_dist_d1_type), DIMENSION(SIZE(homo)), &
      86              :          INTENT(INOUT)                                   :: gd_B_virtual
      87              :       INTEGER, INTENT(IN)                                :: dimen_RI, unit_nr
      88              :       LOGICAL, INTENT(IN)                                :: calc_forces, calc_ex
      89              : 
      90              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_gpw_compute_en'
      91              : 
      92              :       INTEGER :: a, a_global, b, b_global, block_size, decil, end_point, handle, handle2, handle3, &
      93              :          iiB, ij_counter, ij_counter_send, ij_index, integ_group_size, ispin, jjB, jspin, &
      94              :          max_ij_pairs, my_block_size, my_group_L_end, my_group_L_size, my_group_L_size_orig, &
      95              :          my_group_L_start, my_i, my_ij_pairs, my_j, my_new_group_L_size, ngroup, nspins, &
      96              :          num_integ_group, proc_receive, proc_send, proc_shift, rec_B_size, rec_B_virtual_end, &
      97              :          rec_B_virtual_start, rec_L_size, send_B_size, send_B_virtual_end, send_B_virtual_start, &
      98              :          send_i, send_ij_index, send_j, start_point, tag, total_ij_pairs
      99          354 :       INTEGER, ALLOCATABLE, DIMENSION(:) :: integ_group_pos2color_sub, my_B_size, &
     100          354 :          my_B_virtual_end, my_B_virtual_start, num_ij_pairs, sizes_array_orig, virtual
     101          354 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: ij_map
     102          354 :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :)           :: ranges_info_array
     103              :       LOGICAL                                            :: my_alpha_beta_case, my_beta_beta_case, &
     104              :                                                             my_open_shell_SS
     105              :       REAL(KIND=dp)                                      :: amp_fac, my_Emp2_Cou, my_Emp2_EX, &
     106              :                                                             sym_fac, t_new, t_start
     107          354 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), TARGET   :: buffer_1D
     108              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     109          354 :          TARGET                                          :: local_ab, local_ba, t_ab
     110              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     111          354 :          TARGET                                          :: local_i_aL, local_j_aL, Y_i_aP, Y_j_aP
     112              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
     113          354 :          POINTER                                         :: external_ab, external_i_aL
     114              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
     115          354 :          POINTER                                         :: BI_C_rec
     116              :       TYPE(dgemm_counter_type)                           :: dgemm_counter
     117              :       TYPE(mp_comm_type)                                 :: comm_exchange, comm_rep
     118              :       TYPE(three_dim_real_array), ALLOCATABLE, &
     119          354 :          DIMENSION(:)                                    :: B_ia_Q
     120              : 
     121          354 :       CALL timeset(routineN, handle)
     122              : 
     123          354 :       nspins = SIZE(homo)
     124              : 
     125         1062 :       ALLOCATE (virtual(nspins))
     126          796 :       virtual(:) = nmo - homo(:)
     127              : 
     128         1416 :       ALLOCATE (my_B_size(nspins), my_B_virtual_start(nspins), my_B_virtual_end(nspins))
     129          796 :       DO ispin = 1, nspins
     130              :          CALL get_group_dist(gd_B_virtual(ispin), para_env_sub%mepos, &
     131          796 :                              my_B_virtual_start(ispin), my_B_virtual_end(ispin), my_B_size(ispin))
     132              :       END DO
     133              : 
     134          354 :       CALL get_group_dist(gd_array, color_sub, my_group_L_start, my_group_L_end, my_group_L_size)
     135              : 
     136          354 :       CALL dgemm_counter_init(dgemm_counter, unit_nr, mp2_env%ri_mp2%print_dgemm_info)
     137              : 
     138              :       ! local_gemm_ctx has a very footprint the first time this routine is
     139              :       ! called.
     140          354 :       CALL mp2_env%local_gemm_ctx%create(LOCAL_GEMM_PU_GPU)
     141          354 :       CALL mp2_env%local_gemm_ctx%set_op_threshold_gpu(128*128*128*2)
     142              : 
     143              :       CALL mp2_ri_get_integ_group_size( &
     144              :          mp2_env, para_env, para_env_sub, gd_array, gd_B_virtual, &
     145              :          homo, dimen_RI, unit_nr, &
     146              :          integ_group_size, ngroup, &
     147          354 :          num_integ_group, virtual, calc_forces)
     148              : 
     149              :       ! now create a group that contains all the proc that have the same virtual starting point
     150              :       ! in the integ group
     151              :       CALL mp2_ri_create_group( &
     152              :          para_env, para_env_sub, color_sub, &
     153              :          gd_array%sizes, calc_forces, &
     154              :          integ_group_size, my_group_L_end, &
     155              :          my_group_L_size, my_group_L_size_orig, my_group_L_start, my_new_group_L_size, &
     156              :          integ_group_pos2color_sub, sizes_array_orig, &
     157          354 :          ranges_info_array, comm_exchange, comm_rep, num_integ_group)
     158              : 
     159              :       ! We cannot fix the tag because of the recv routine
     160          354 :       tag = 42
     161              : 
     162          796 :       DO jspin = 1, nspins
     163              : 
     164              :          CALL replicate_iaK_2intgroup(BIb_C(jspin)%array, comm_exchange, comm_rep, &
     165              :                                       homo(jspin), gd_array%sizes, my_B_size(jspin), &
     166          442 :                                       my_group_L_size, ranges_info_array)
     167              : 
     168         1326 :          DO ispin = 1, jspin
     169              : 
     170          530 :             IF (unit_nr > 0) THEN
     171          265 :                IF (nspins == 1) THEN
     172          133 :                   WRITE (unit_nr, *) "Start loop run"
     173          132 :                ELSE IF (ispin == 1 .AND. jspin == 1) THEN
     174           44 :                   WRITE (unit_nr, *) "Start loop run alpha-alpha"
     175           88 :                ELSE IF (ispin == 1 .AND. jspin == 2) THEN
     176           44 :                   WRITE (unit_nr, *) "Start loop run alpha-beta"
     177           44 :                ELSE IF (ispin == 2 .AND. jspin == 2) THEN
     178           44 :                   WRITE (unit_nr, *) "Start loop run beta-beta"
     179              :                END IF
     180          265 :                CALL m_flush(unit_nr)
     181              :             END IF
     182              : 
     183          530 :             my_open_shell_SS = (nspins == 2) .AND. (ispin == jspin)
     184              : 
     185              :             ! t_ab = amp_fac*(:,a|:,b)-(:,b|:,a)
     186              :             ! If we calculate the gradient we need to distinguish
     187              :             ! between alpha-alpha and beta-beta cases for UMP2
     188              : 
     189          530 :             my_beta_beta_case = .FALSE.
     190          530 :             my_alpha_beta_case = .FALSE.
     191          530 :             IF (ispin /= jspin) THEN
     192           88 :                my_alpha_beta_case = .TRUE.
     193          442 :             ELSE IF (my_open_shell_SS) THEN
     194          176 :                IF (ispin == 2) my_beta_beta_case = .TRUE.
     195              :             END IF
     196              : 
     197          530 :             amp_fac = mp2_env%scale_S + mp2_env%scale_T
     198          530 :             IF (my_alpha_beta_case .OR. my_open_shell_SS) amp_fac = mp2_env%scale_T
     199              : 
     200              :             CALL mp2_ri_allocate_no_blk(local_ab, t_ab, mp2_env, homo, virtual, my_B_size, &
     201          530 :                                         my_group_L_size, calc_forces, ispin, jspin, local_ba)
     202              : 
     203              :             CALL mp2_ri_get_block_size( &
     204              :                mp2_env, para_env, para_env_sub, gd_array, gd_B_virtual(ispin:jspin), &
     205              :                homo(ispin:jspin), virtual(ispin:jspin), dimen_RI, unit_nr, block_size, &
     206          530 :                ngroup, num_integ_group, my_open_shell_ss, calc_forces, buffer_1D)
     207              : 
     208              :             ! *****************************************************************
     209              :             ! **********  REPLICATION-BLOCKED COMMUNICATION SCHEME  ***********
     210              :             ! *****************************************************************
     211              :             ! introduce block size, the number of occupied orbitals has to be a
     212              :             ! multiple of the block size
     213              : 
     214              :             ! Calculate the maximum number of ij pairs that have to be computed
     215              :             ! among groups
     216              :             CALL mp2_ri_communication(my_alpha_beta_case, total_ij_pairs, homo(ispin), homo(jspin), &
     217          530 :                                       block_size, ngroup, ij_map, color_sub, my_ij_pairs, my_open_shell_SS, unit_nr)
     218              : 
     219         1590 :             ALLOCATE (num_ij_pairs(0:comm_exchange%num_pe - 1))
     220          530 :             CALL comm_exchange%allgather(my_ij_pairs, num_ij_pairs)
     221              : 
     222         1170 :             max_ij_pairs = MAXVAL(num_ij_pairs)
     223              : 
     224              :             ! start real stuff
     225              :             CALL mp2_ri_allocate_blk(dimen_RI, my_B_size, block_size, local_i_aL, &
     226          530 :                                      local_j_aL, calc_forces, Y_i_aP, Y_j_aP, ispin, jspin)
     227              : 
     228          530 :             CALL timeset(routineN//"_RI_loop", handle2)
     229          530 :             my_Emp2_Cou = 0.0_dp
     230          530 :             my_Emp2_EX = 0.0_dp
     231          530 :             t_start = m_walltime()
     232         2572 :             DO ij_index = 1, max_ij_pairs
     233              : 
     234              :                ! Prediction is unreliable if we are in the first step of the loop
     235         2042 :                IF (unit_nr > 0 .AND. ij_index > 1) THEN
     236          742 :                   decil = ij_index*10/max_ij_pairs
     237          742 :                   IF (decil /= (ij_index - 1)*10/max_ij_pairs) THEN
     238          701 :                      t_new = m_walltime()
     239          701 :                      t_new = (t_new - t_start)/60.0_dp*(max_ij_pairs - ij_index + 1)/(ij_index - 1)
     240              :                      WRITE (unit_nr, FMT="(T3,A)") "Percentage of finished loop: "// &
     241          701 :                         cp_to_string(decil*10)//". Minutes left: "//cp_to_string(t_new)
     242          701 :                      CALL m_flush(unit_nr)
     243              :                   END IF
     244              :                END IF
     245              : 
     246         2042 :                IF (calc_forces) THEN
     247         1617 :                   Y_i_aP = 0.0_dp
     248         1617 :                   Y_j_aP = 0.0_dp
     249              :                END IF
     250              : 
     251         2042 :                IF (ij_index <= my_ij_pairs) THEN
     252              :                   ! We have work to do
     253         1993 :                   ij_counter = (ij_index - MIN(1, color_sub))*ngroup + color_sub
     254         1993 :                   my_i = ij_map(1, ij_counter)
     255         1993 :                   my_j = ij_map(2, ij_counter)
     256         1993 :                   my_block_size = ij_map(3, ij_counter)
     257              : 
     258         1993 :                   local_i_aL = 0.0_dp
     259              :                   CALL fill_local_i_aL(local_i_aL(:, :, 1:my_block_size), ranges_info_array(:, :, comm_exchange%mepos), &
     260         1993 :                                        BIb_C(ispin)%array(:, :, my_i:my_i + my_block_size - 1))
     261              : 
     262         1993 :                   local_j_aL = 0.0_dp
     263              :                   CALL fill_local_i_aL(local_j_aL(:, :, 1:my_block_size), ranges_info_array(:, :, comm_exchange%mepos), &
     264         1993 :                                        BIb_C(jspin)%array(:, :, my_j:my_j + my_block_size - 1))
     265              : 
     266              :                   ! collect data from other proc
     267         1993 :                   CALL timeset(routineN//"_comm", handle3)
     268         2102 :                   DO proc_shift = 1, comm_exchange%num_pe - 1
     269          109 :                      proc_send = MODULO(comm_exchange%mepos + proc_shift, comm_exchange%num_pe)
     270          109 :                      proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
     271              : 
     272          109 :                      send_ij_index = num_ij_pairs(proc_send)
     273              : 
     274          109 :                      CALL get_group_dist(gd_array, proc_receive, sizes=rec_L_size)
     275              : 
     276         2102 :                      IF (ij_index <= send_ij_index) THEN
     277              :                         ij_counter_send = (ij_index - MIN(1, integ_group_pos2color_sub(proc_send)))*ngroup + &
     278           60 :                                           integ_group_pos2color_sub(proc_send)
     279           60 :                         send_i = ij_map(1, ij_counter_send)
     280           60 :                         send_j = ij_map(2, ij_counter_send)
     281              : 
     282              :                         ! occupied i
     283              :                         BI_C_rec(1:rec_L_size, 1:my_B_size(ispin), 1:my_block_size) => &
     284           60 :                            buffer_1D(1:rec_L_size*my_B_size(ispin)*my_block_size)
     285           60 :                         BI_C_rec = 0.0_dp
     286              :                         CALL comm_exchange%sendrecv(BIb_C(ispin)%array(:, :, send_i:send_i + my_block_size - 1), &
     287           60 :                                                     proc_send, BI_C_rec, proc_receive, tag)
     288              : 
     289              :                         CALL fill_local_i_aL(local_i_aL(:, :, 1:my_block_size), ranges_info_array(:, :, proc_receive), &
     290           60 :                                              BI_C_rec(:, 1:my_B_size(ispin), :))
     291              : 
     292              :                         ! occupied j
     293              :                         BI_C_rec(1:rec_L_size, 1:my_B_size(jspin), 1:my_block_size) => &
     294           60 :                            buffer_1D(1:INT(rec_L_size, int_8)*my_B_size(jspin)*my_block_size)
     295           60 :                         BI_C_rec = 0.0_dp
     296              :                         CALL comm_exchange%sendrecv(BIb_C(jspin)%array(:, :, send_j:send_j + my_block_size - 1), &
     297           60 :                                                     proc_send, BI_C_rec, proc_receive, tag)
     298              : 
     299              :                         CALL fill_local_i_aL(local_j_aL(:, :, 1:my_block_size), ranges_info_array(:, :, proc_receive), &
     300           60 :                                              BI_C_rec(:, 1:my_B_size(jspin), :))
     301              : 
     302              :                      ELSE
     303              :                         ! we send nothing while we know that we have to receive something
     304              : 
     305              :                         ! occupied i
     306              :                         BI_C_rec(1:rec_L_size, 1:my_B_size(ispin), 1:my_block_size) => &
     307           49 :                            buffer_1D(1:INT(rec_L_size, int_8)*my_B_size(ispin)*my_block_size)
     308           49 :                         BI_C_rec = 0.0_dp
     309           49 :                         CALL comm_exchange%recv(BI_C_rec, proc_receive, tag)
     310              : 
     311              :                         CALL fill_local_i_aL(local_i_aL(:, :, 1:my_block_size), ranges_info_array(:, :, proc_receive), &
     312           49 :                                              BI_C_rec(:, 1:my_B_size(ispin), 1:my_block_size))
     313              : 
     314              :                         ! occupied j
     315              :                         BI_C_rec(1:rec_L_size, 1:my_B_size(jspin), 1:my_block_size) => &
     316           49 :                            buffer_1D(1:INT(rec_L_size, int_8)*my_B_size(jspin)*my_block_size)
     317           49 :                         BI_C_rec = 0.0_dp
     318           49 :                         CALL comm_exchange%recv(BI_C_rec, proc_receive, tag)
     319              : 
     320              :                         CALL fill_local_i_aL(local_j_aL(:, :, 1:my_block_size), ranges_info_array(:, :, proc_receive), &
     321           49 :                                              BI_C_rec(:, 1:my_B_size(jspin), 1:my_block_size))
     322              : 
     323              :                      END IF
     324              : 
     325              :                   END DO
     326              : 
     327         1993 :                   CALL timestop(handle3)
     328              : 
     329              :                   ! loop over the block elements
     330         3990 :                   DO iiB = 1, my_block_size
     331         5995 :                      DO jjB = 1, my_block_size
     332         2005 :                         CALL timeset(routineN//"_expansion", handle3)
     333         4002 :                         ASSOCIATE (my_local_i_aL => local_i_aL(:, :, iiB), my_local_j_aL => local_j_aL(:, :, jjB))
     334              : 
     335              :                            ! calculate the integrals (ia|jb) strating from my local data ...
     336         2005 :                            local_ab = 0.0_dp
     337          574 :                            IF ((my_alpha_beta_case) .AND. (calc_forces)) THEN
     338          502 :                               local_ba = 0.0_dp
     339              :                            END IF
     340         2005 :                            CALL dgemm_counter_start(dgemm_counter)
     341              :                            CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(ispin), my_B_size(jspin), dimen_RI, 1.0_dp, &
     342              :                                                             my_local_i_aL, dimen_RI, my_local_j_aL, dimen_RI, &
     343              :                                                            0.0_dp, local_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :), &
     344        64287 :                                                             my_B_size(ispin))
     345              :                            ! Additional integrals only for alpha_beta case and forces
     346         2005 :                            IF (my_alpha_beta_case .AND. calc_forces) THEN
     347              :                               local_ba(my_B_virtual_start(jspin):my_B_virtual_end(jspin), :) = &
     348       133101 :                                  TRANSPOSE(local_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :))
     349              :                            END IF
     350              :                            ! ... and from the other of my subgroup
     351         2279 :                            DO proc_shift = 1, para_env_sub%num_pe - 1
     352          274 :                               proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
     353          274 :                               proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
     354              : 
     355              :                               CALL get_group_dist(gd_B_virtual(ispin), proc_receive, rec_B_virtual_start, &
     356          274 :                                                   rec_B_virtual_end, rec_B_size)
     357              : 
     358          274 :                               external_i_aL(1:dimen_RI, 1:rec_B_size) => buffer_1D(1:INT(dimen_RI, int_8)*rec_B_size)
     359          274 :                               external_i_aL = 0.0_dp
     360              : 
     361              :                               CALL para_env_sub%sendrecv(my_local_i_aL, proc_send, &
     362          274 :                                                          external_i_aL, proc_receive, tag)
     363              : 
     364              :                               CALL mp2_env%local_gemm_ctx%gemm( &
     365              :                                  'T', 'N', rec_B_size, my_B_size(jspin), dimen_RI, 1.0_dp, &
     366              :                                  external_i_aL, dimen_RI, my_local_j_aL, dimen_RI, &
     367        62318 :                                  0.0_dp, local_ab(rec_B_virtual_start:rec_B_virtual_end, 1:my_B_size(jspin)), rec_B_size)
     368              : 
     369              :                               ! Additional integrals only for alpha_beta case and forces
     370         2553 :                               IF (my_alpha_beta_case .AND. calc_forces) THEN
     371              : 
     372              :                                  CALL get_group_dist(gd_B_virtual(jspin), proc_receive, rec_B_virtual_start, &
     373           70 :                                                      rec_B_virtual_end, rec_B_size)
     374              : 
     375           70 :                                  external_i_aL(1:dimen_RI, 1:rec_B_size) => buffer_1D(1:INT(dimen_RI, int_8)*rec_B_size)
     376           70 :                                  external_i_aL = 0.0_dp
     377              : 
     378              :                                  CALL para_env_sub%sendrecv(my_local_j_aL, proc_send, &
     379           70 :                                                             external_i_aL, proc_receive, tag)
     380              : 
     381              :                                  CALL mp2_env%local_gemm_ctx%gemm('T', 'N', rec_B_size, my_B_size(ispin), dimen_RI, 1.0_dp, &
     382              :                                                                   external_i_aL, dimen_RI, my_local_i_aL, dimen_RI, &
     383        15330 :                                             0.0_dp, local_ba(rec_B_virtual_start:rec_B_virtual_end, 1:my_B_size(ispin)), rec_B_size)
     384              :                               END IF
     385              :                            END DO
     386         2005 :                            IF (my_alpha_beta_case .AND. calc_forces) THEN
     387              :                               ! Is just an approximation, but the call does not allow it,
     388              :                               ! it ought to be (virtual_i*B_size_j+virtual_j*B_size_i)*dimen_RI
     389          502 :                               CALL dgemm_counter_stop(dgemm_counter, virtual(ispin), my_B_size(ispin) + my_B_size(jspin), dimen_RI)
     390              :                            ELSE
     391         1503 :                               CALL dgemm_counter_stop(dgemm_counter, virtual(ispin), my_B_size(jspin), dimen_RI)
     392              :                            END IF
     393         2005 :                            CALL timestop(handle3)
     394              : 
     395              :                            !sample peak memory
     396         2005 :                            CALL m_memory()
     397              : 
     398         2005 :                            CALL timeset(routineN//"_ener", handle3)
     399              :                            ! calculate coulomb only MP2
     400         2005 :                            sym_fac = 2.0_dp
     401         2005 :                            IF (my_i == my_j) sym_fac = 1.0_dp
     402         2005 :                            IF (my_alpha_beta_case) sym_fac = 0.5_dp
     403        30928 :                            DO b = 1, my_B_size(jspin)
     404        28923 :                               b_global = b + my_B_virtual_start(jspin) - 1
     405       585679 :                               DO a = 1, virtual(ispin)
     406              :                                  my_Emp2_Cou = my_Emp2_Cou - sym_fac*2.0_dp*local_ab(a, b)**2/ &
     407              :                                                (Eigenval(homo(ispin) + a, ispin) + Eigenval(homo(jspin) + b_global, jspin) - &
     408       583674 :                                                 Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, jspin))
     409              :                               END DO
     410              :                            END DO
     411              : 
     412         2005 :                            IF (calc_ex) THEN
     413              :                               ! contract integrals with orbital energies for exchange MP2 energy
     414              :                               ! starting with local ...
     415         2005 :                               IF (calc_forces .AND. (.NOT. my_alpha_beta_case)) t_ab = 0.0_dp
     416        30328 :                               DO b = 1, my_B_size(ispin)
     417        28323 :                                  b_global = b + my_B_virtual_start(ispin) - 1
     418       548367 :                                  DO a = 1, my_B_size(ispin)
     419       518039 :                                     a_global = a + my_B_virtual_start(ispin) - 1
     420              :                                     my_Emp2_Ex = my_Emp2_Ex + sym_fac*local_ab(a_global, b)*local_ab(b_global, a)/ &
     421              :                                               (Eigenval(homo(ispin) + a_global, ispin) + Eigenval(homo(ispin) + b_global, ispin) - &
     422       518039 :                                                   Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, ispin))
     423       546362 :                                     IF (calc_forces .AND. (.NOT. my_alpha_beta_case)) THEN
     424              :                                      t_ab(a_global, b) = -(amp_fac*local_ab(a_global, b) - mp2_env%scale_T*local_ab(b_global, a))/ &
     425              :                                                            (Eigenval(homo(ispin) + a_global, ispin) + &
     426              :                                                             Eigenval(homo(ispin) + b_global, ispin) - &
     427       302030 :                                                             Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, ispin))
     428              :                                     END IF
     429              :                                  END DO
     430              :                               END DO
     431              :                               ! ... and then with external data
     432         2279 :                               DO proc_shift = 1, para_env_sub%num_pe - 1
     433          274 :                                  proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
     434          274 :                                  proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
     435              : 
     436              :                                  CALL get_group_dist(gd_B_virtual(ispin), proc_receive, &
     437          274 :                                                      rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
     438              :                                  CALL get_group_dist(gd_B_virtual(ispin), proc_send, &
     439          274 :                                                      send_B_virtual_start, send_B_virtual_end, send_B_size)
     440              : 
     441              :                                  external_ab(1:my_B_size(ispin), 1:rec_B_size) => &
     442          274 :                                     buffer_1D(1:INT(rec_B_size, int_8)*my_B_size(ispin))
     443          274 :                                  external_ab = 0.0_dp
     444              : 
     445              :                       CALL para_env_sub%sendrecv(local_ab(send_B_virtual_start:send_B_virtual_end, 1:my_B_size(ispin)), proc_send, &
     446        60536 :                                                             external_ab(1:my_B_size(ispin), 1:rec_B_size), proc_receive, tag)
     447              : 
     448         5284 :                                  DO b = 1, my_B_size(ispin)
     449         2731 :                                     b_global = b + my_B_virtual_start(ispin) - 1
     450        30405 :                                     DO a = 1, rec_B_size
     451        27400 :                                        a_global = a + rec_B_virtual_start - 1
     452              :                                        my_Emp2_Ex = my_Emp2_Ex + sym_fac*local_ab(a_global, b)*external_ab(b, a)/ &
     453              :                                               (Eigenval(homo(ispin) + a_global, ispin) + Eigenval(homo(ispin) + b_global, ispin) - &
     454        27400 :                                                      Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, ispin))
     455        30131 :                                        IF (calc_forces .AND. (.NOT. my_alpha_beta_case)) THEN
     456              :                                          t_ab(a_global, b) = -(amp_fac*local_ab(a_global, b) - mp2_env%scale_T*external_ab(b, a))/ &
     457              :                                                               (Eigenval(homo(ispin) + a_global, ispin) + &
     458              :                                                                Eigenval(homo(ispin) + b_global, ispin) - &
     459         9580 :                                                                Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, ispin))
     460              :                                        END IF
     461              :                                     END DO
     462              :                                  END DO
     463              :                               END DO
     464              :                            END IF
     465         2005 :                            CALL timestop(handle3)
     466              : 
     467         4010 :                            IF (calc_forces) THEN
     468              :                               ! update P_ab, Gamma_P_ia
     469              :                               CALL mp2_update_P_gamma(mp2_env, para_env_sub, gd_B_virtual, &
     470              :                                                       Eigenval, homo, dimen_RI, iiB, jjB, my_B_size, &
     471              :                                                       my_B_virtual_end, my_B_virtual_start, my_i, my_j, virtual, &
     472              :                                                       local_ab, t_ab, my_local_i_aL, my_local_j_aL, &
     473              :                                                       my_open_shell_ss, Y_i_aP(:, :, iiB), Y_j_aP(:, :, jjB), local_ba, &
     474         1620 :                                                       ispin, jspin, dgemm_counter, buffer_1D)
     475              : 
     476              :                            END IF
     477              : 
     478              :                         END ASSOCIATE
     479              : 
     480              :                      END DO ! jjB
     481              :                   END DO ! iiB
     482              : 
     483              :                ELSE
     484              :                   ! We need it later in case of gradients
     485           49 :                   my_block_size = 1
     486              : 
     487           49 :                   CALL timeset(routineN//"_comm", handle3)
     488              :                   ! No work to do and we know that we have to receive nothing, but send something
     489              :                   ! send data to other proc
     490           98 :                   DO proc_shift = 1, comm_exchange%num_pe - 1
     491           49 :                      proc_send = MODULO(comm_exchange%mepos + proc_shift, comm_exchange%num_pe)
     492           49 :                      proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
     493              : 
     494           49 :                      send_ij_index = num_ij_pairs(proc_send)
     495              : 
     496           98 :                      IF (ij_index <= send_ij_index) THEN
     497              :                         ! something to send
     498              :                         ij_counter_send = (ij_index - MIN(1, integ_group_pos2color_sub(proc_send)))*ngroup + &
     499           49 :                                           integ_group_pos2color_sub(proc_send)
     500           49 :                         send_i = ij_map(1, ij_counter_send)
     501           49 :                         send_j = ij_map(2, ij_counter_send)
     502              : 
     503              :                         ! occupied i
     504              :                         CALL comm_exchange%send(BIb_C(ispin)%array(:, :, send_i:send_i + my_block_size - 1), &
     505           49 :                                                 proc_send, tag)
     506              :                         ! occupied j
     507              :                         CALL comm_exchange%send(BIb_C(jspin)%array(:, :, send_j:send_j + my_block_size - 1), &
     508           49 :                                                 proc_send, tag)
     509              :                      END IF
     510              :                   END DO
     511           49 :                   CALL timestop(handle3)
     512              :                END IF
     513              : 
     514              :                ! redistribute gamma
     515         2572 :                IF (calc_forces) THEN
     516              :                   CALL mp2_redistribute_gamma(mp2_env%ri_grad%Gamma_P_ia(ispin)%array, ij_index, my_B_size(ispin), &
     517              :                                               my_block_size, my_group_L_size, my_i, my_ij_pairs, ngroup, &
     518              :                                               num_integ_group, integ_group_pos2color_sub, num_ij_pairs, &
     519              :                                               ij_map, ranges_info_array, Y_i_aP(:, :, 1:my_block_size), comm_exchange, &
     520         1617 :                                               gd_array%sizes, 1, buffer_1D)
     521              :                   CALL mp2_redistribute_gamma(mp2_env%ri_grad%Gamma_P_ia(jspin)%array, ij_index, my_B_size(jspin), &
     522              :                                               my_block_size, my_group_L_size, my_j, my_ij_pairs, ngroup, &
     523              :                                               num_integ_group, integ_group_pos2color_sub, num_ij_pairs, &
     524              :                                               ij_map, ranges_info_array, Y_j_aP(:, :, 1:my_block_size), comm_exchange, &
     525         1617 :                                               gd_array%sizes, 2, buffer_1D)
     526              :                END IF
     527              : 
     528              :             END DO
     529          530 :             CALL timestop(handle2)
     530              : 
     531          530 :             DEALLOCATE (local_i_aL)
     532          530 :             DEALLOCATE (local_j_aL)
     533          530 :             DEALLOCATE (ij_map)
     534          530 :             DEALLOCATE (num_ij_pairs)
     535          530 :             DEALLOCATE (local_ab)
     536              : 
     537          530 :             IF (calc_forces) THEN
     538          384 :                DEALLOCATE (Y_i_aP)
     539          384 :                DEALLOCATE (Y_j_aP)
     540          384 :                IF (ALLOCATED(t_ab)) THEN
     541          306 :                   DEALLOCATE (t_ab)
     542              :                END IF
     543          384 :                DEALLOCATE (local_ba)
     544              : 
     545              :                ! here we check if there are almost degenerate ij
     546              :                ! pairs and we update P_ij with these contribution.
     547              :                ! If all pairs are degenerate with each other this step will scale O(N^6),
     548              :                ! if the number of degenerate pairs scales linearly with the system size
     549              :                ! this step will scale O(N^5).
     550              :                ! Start counting the number of almost degenerate ij pairs according
     551              :                ! to eps_canonical
     552              :                CALL quasi_degenerate_P_ij( &
     553              :                   mp2_env, Eigenval(:, ispin:jspin), homo(ispin:jspin), virtual(ispin:jspin), my_open_shell_ss, &
     554              :                   my_beta_beta_case, Bib_C(ispin:jspin), unit_nr, dimen_RI, &
     555              :                   my_B_size(ispin:jspin), ngroup, my_group_L_size, &
     556              :                   color_sub, ranges_info_array, comm_exchange, para_env_sub, para_env, &
     557              :                   my_B_virtual_start(ispin:jspin), my_B_virtual_end(ispin:jspin), gd_array%sizes, gd_B_virtual(ispin:jspin), &
     558          384 :                   integ_group_pos2color_sub, dgemm_counter, buffer_1D)
     559              : 
     560              :             END IF
     561              : 
     562          530 :             DEALLOCATE (buffer_1D)
     563              : 
     564              :             ! Dereplicate BIb_C and Gamma_P_ia to save memory
     565              :             ! These matrices will not be needed in that fashion anymore
     566              :             ! B_ia_Q will needed later
     567          530 :             IF (calc_forces .AND. jspin == nspins) THEN
     568         1068 :                IF (.NOT. ALLOCATED(B_ia_Q)) ALLOCATE (B_ia_Q(nspins))
     569         1530 :                ALLOCATE (B_ia_Q(ispin)%array(homo(ispin), my_B_size(ispin), my_group_L_size_orig))
     570       907278 :                B_ia_Q(ispin)%array = 0.0_dp
     571         1408 :                DO jjB = 1, homo(ispin)
     572        17332 :                   DO iiB = 1, my_B_size(ispin)
     573              :                      B_ia_Q(ispin)%array(jjB, iiB, 1:my_group_L_size_orig) = &
     574       724326 :                         BIb_C(ispin)%array(1:my_group_L_size_orig, iiB, jjB)
     575              :                   END DO
     576              :                END DO
     577          306 :                DEALLOCATE (BIb_C(ispin)%array)
     578              : 
     579              :                ! sum Gamma and dereplicate
     580         1530 :                ALLOCATE (BIb_C(ispin)%array(my_B_size(ispin), homo(ispin), my_group_L_size_orig))
     581          582 :                DO proc_shift = 1, comm_rep%num_pe - 1
     582              :                   ! invert order
     583          276 :                   proc_send = MODULO(comm_rep%mepos - proc_shift, comm_rep%num_pe)
     584          276 :                   proc_receive = MODULO(comm_rep%mepos + proc_shift, comm_rep%num_pe)
     585              : 
     586          276 :                   start_point = ranges_info_array(3, proc_shift, comm_exchange%mepos)
     587          276 :                   end_point = ranges_info_array(4, proc_shift, comm_exchange%mepos)
     588              : 
     589              :                   CALL comm_rep%sendrecv(mp2_env%ri_grad%Gamma_P_ia(ispin)%array(:, :, start_point:end_point), &
     590          276 :                                          proc_send, BIb_C(ispin)%array, proc_receive, tag)
     591              : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
     592          582 : !$OMP          SHARED(mp2_env,BIb_C,ispin,homo,my_B_size,my_group_L_size_orig)
     593              :                   mp2_env%ri_grad%Gamma_P_ia(ispin)%array(:, :, 1:my_group_L_size_orig) = &
     594              :                      mp2_env%ri_grad%Gamma_P_ia(ispin)%array(:, :, 1:my_group_L_size_orig) &
     595              :                      + BIb_C(ispin)%array(:, :, :)
     596              : !$OMP END PARALLEL WORKSHARE
     597              :                END DO
     598              : 
     599       770352 :                BIb_C(ispin)%array(:, :, :) = mp2_env%ri_grad%Gamma_P_ia(ispin)%array(:, :, 1:my_group_L_size_orig)
     600          306 :                DEALLOCATE (mp2_env%ri_grad%Gamma_P_ia(ispin)%array)
     601          306 :                CALL MOVE_ALLOC(BIb_C(ispin)%array, mp2_env%ri_grad%Gamma_P_ia(ispin)%array)
     602          224 :             ELSE IF (jspin == nspins) THEN
     603          136 :                DEALLOCATE (BIb_C(ispin)%array)
     604              :             END IF
     605              : 
     606          530 :             CALL para_env%sum(my_Emp2_Cou)
     607          530 :             CALL para_env%sum(my_Emp2_Ex)
     608              : 
     609         1502 :             IF (my_open_shell_SS .OR. my_alpha_beta_case) THEN
     610          264 :                IF (my_alpha_beta_case) THEN
     611           88 :                   Emp2_S = Emp2_S + my_Emp2_Cou
     612           88 :                   Emp2_Cou = Emp2_Cou + my_Emp2_Cou
     613              :                ELSE
     614          176 :                   my_Emp2_Cou = my_Emp2_Cou*0.25_dp
     615          176 :                   my_Emp2_EX = my_Emp2_EX*0.5_dp
     616          176 :                   Emp2_T = Emp2_T + my_Emp2_Cou + my_Emp2_EX
     617          176 :                   Emp2_Cou = Emp2_Cou + my_Emp2_Cou
     618          176 :                   Emp2_EX = Emp2_EX + my_Emp2_EX
     619              :                END IF
     620              :             ELSE
     621          266 :                Emp2_Cou = Emp2_Cou + my_Emp2_Cou
     622          266 :                Emp2_EX = Emp2_EX + my_Emp2_EX
     623              :             END IF
     624              :          END DO
     625              : 
     626              :       END DO
     627              : 
     628          354 :       DEALLOCATE (integ_group_pos2color_sub)
     629          354 :       DEALLOCATE (ranges_info_array)
     630              : 
     631          354 :       CALL comm_exchange%free()
     632          354 :       CALL comm_rep%free()
     633              : 
     634          354 :       IF (calc_forces) THEN
     635              :          ! recover original information (before replication)
     636          228 :          DEALLOCATE (gd_array%sizes)
     637          228 :          iiB = SIZE(sizes_array_orig)
     638          684 :          ALLOCATE (gd_array%sizes(0:iiB - 1))
     639          678 :          gd_array%sizes(:) = sizes_array_orig
     640          228 :          DEALLOCATE (sizes_array_orig)
     641              : 
     642              :          ! Remove replication from BIb_C and reorder the matrix
     643          228 :          my_group_L_size = my_group_L_size_orig
     644              : 
     645              :          ! B_ia_Q(ispin)%array will be deallocated inside of complete_gamma
     646          534 :          DO ispin = 1, nspins
     647              :             CALL complete_gamma(mp2_env, B_ia_Q(ispin)%array, dimen_RI, homo(ispin), virtual(ispin), &
     648              :                                 para_env, para_env_sub, my_group_L_size, my_group_L_start, my_group_L_end, &
     649          534 :                                 my_B_size(ispin), my_B_virtual_start(ispin), gd_B_virtual(ispin), ispin)
     650              :          END DO
     651          534 :          DEALLOCATE (B_ia_Q)
     652              : 
     653        45074 :          IF (nspins == 1) mp2_env%ri_grad%P_ab(1)%array(:, :) = mp2_env%ri_grad%P_ab(1)%array(:, :)*2.0_dp
     654              :          BLOCK
     655              :             TYPE(mp_comm_type) :: comm
     656          228 :             CALL comm%from_split(para_env, para_env_sub%mepos)
     657          534 :             DO ispin = 1, nspins
     658              :                ! P_ab is only replicated over all subgroups
     659          306 :                CALL comm%sum(mp2_env%ri_grad%P_ab(ispin)%array)
     660              :                ! P_ij is replicated over all processes
     661          534 :                CALL para_env%sum(mp2_env%ri_grad%P_ij(ispin)%array)
     662              :             END DO
     663          456 :             CALL comm%free()
     664              :          END BLOCK
     665              :       END IF
     666              : 
     667          354 :       CALL release_group_dist(gd_array)
     668          796 :       DO ispin = 1, nspins
     669          442 :          IF (ALLOCATED(BIb_C(ispin)%array)) DEALLOCATE (BIb_C(ispin)%array)
     670          796 :          CALL release_group_dist(gd_B_virtual(ispin))
     671              :       END DO
     672              : 
     673              :       ! We do not need this matrix later, so deallocate it here to safe memory
     674          354 :       IF (calc_forces) DEALLOCATE (mp2_env%ri_grad%PQ_half)
     675          354 :       IF (calc_forces .AND. .NOT. compare_potential_types(mp2_env%ri_metric, mp2_env%potential_parameter)) THEN
     676            8 :          DEALLOCATE (mp2_env%ri_grad%operator_half)
     677              :       END IF
     678              : 
     679          354 :       CALL dgemm_counter_write(dgemm_counter, para_env)
     680              : 
     681              :       ! release memory allocated by local_gemm when run on GPU. local_gemm_ctx is null on cpu only runs
     682          354 :       CALL mp2_env%local_gemm_ctx%destroy()
     683          354 :       CALL timestop(handle)
     684              : 
     685         1062 :    END SUBROUTINE mp2_ri_gpw_compute_en
     686              : 
     687              : ! **************************************************************************************************
     688              : !> \brief ...
     689              : !> \param local_i_aL ...
     690              : !> \param ranges_info_array ...
     691              : !> \param BIb_C_rec ...
     692              : ! **************************************************************************************************
     693         4360 :    SUBROUTINE fill_local_i_aL(local_i_aL, ranges_info_array, BIb_C_rec)
     694              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: local_i_aL
     695              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: ranges_info_array
     696              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: BIb_C_rec
     697              : 
     698              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'fill_local_i_aL'
     699              : 
     700              :       INTEGER                                            :: end_point, handle, irep, Lend_pos, &
     701              :                                                             Lstart_pos, start_point
     702              : 
     703         4360 :       CALL timeset(routineN, handle)
     704              : 
     705        12100 :       DO irep = 1, SIZE(ranges_info_array, 2)
     706         7740 :          Lstart_pos = ranges_info_array(1, irep)
     707         7740 :          Lend_pos = ranges_info_array(2, irep)
     708         7740 :          start_point = ranges_info_array(3, irep)
     709         7740 :          end_point = ranges_info_array(4, irep)
     710              : 
     711              : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
     712        12100 : !$OMP          SHARED(BIb_C_rec,local_i_aL,Lstart_pos,Lend_pos,start_point,end_point)
     713              :          local_i_aL(Lstart_pos:Lend_pos, :, :) = BIb_C_rec(start_point:end_point, :, :)
     714              : !$OMP END PARALLEL WORKSHARE
     715              :       END DO
     716              : 
     717         4360 :       CALL timestop(handle)
     718              : 
     719         4360 :    END SUBROUTINE fill_local_i_aL
     720              : 
     721              : ! **************************************************************************************************
     722              : !> \brief ...
     723              : !> \param local_i_aL ...
     724              : !> \param ranges_info_array ...
     725              : !> \param BIb_C_rec ...
     726              : ! **************************************************************************************************
     727          266 :    SUBROUTINE fill_local_i_aL_2D(local_i_aL, ranges_info_array, BIb_C_rec)
     728              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: local_i_aL
     729              :       INTEGER, DIMENSION(:, :), INTENT(IN)               :: ranges_info_array
     730              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: BIb_C_rec
     731              : 
     732              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'fill_local_i_aL_2D'
     733              : 
     734              :       INTEGER                                            :: end_point, handle, irep, Lend_pos, &
     735              :                                                             Lstart_pos, start_point
     736              : 
     737          266 :       CALL timeset(routineN, handle)
     738              : 
     739          766 :       DO irep = 1, SIZE(ranges_info_array, 2)
     740          500 :          Lstart_pos = ranges_info_array(1, irep)
     741          500 :          Lend_pos = ranges_info_array(2, irep)
     742          500 :          start_point = ranges_info_array(3, irep)
     743          500 :          end_point = ranges_info_array(4, irep)
     744              : 
     745              : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
     746          766 : !$OMP          SHARED(BIb_C_rec,local_i_aL,Lstart_pos,Lend_pos,start_point,end_point)
     747              :          local_i_aL(Lstart_pos:Lend_pos, :) = BIb_C_rec(start_point:end_point, :)
     748              : !$OMP END PARALLEL WORKSHARE
     749              :       END DO
     750              : 
     751          266 :       CALL timestop(handle)
     752              : 
     753          266 :    END SUBROUTINE fill_local_i_aL_2D
     754              : 
     755              : ! **************************************************************************************************
     756              : !> \brief ...
     757              : !> \param BIb_C ...
     758              : !> \param comm_exchange ...
     759              : !> \param comm_rep ...
     760              : !> \param homo ...
     761              : !> \param sizes_array ...
     762              : !> \param my_B_size ...
     763              : !> \param my_group_L_size ...
     764              : !> \param ranges_info_array ...
     765              : ! **************************************************************************************************
     766          442 :    SUBROUTINE replicate_iaK_2intgroup(BIb_C, comm_exchange, comm_rep, homo, sizes_array, my_B_size, &
     767          442 :                                       my_group_L_size, ranges_info_array)
     768              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     769              :          INTENT(INOUT)                                   :: BIb_C
     770              :       TYPE(mp_comm_type), INTENT(IN)                     :: comm_exchange, comm_rep
     771              :       INTEGER, INTENT(IN)                                :: homo
     772              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: sizes_array
     773              :       INTEGER, INTENT(IN)                                :: my_B_size, my_group_L_size
     774              :       INTEGER, DIMENSION(:, 0:, 0:), INTENT(IN)          :: ranges_info_array
     775              : 
     776              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'replicate_iaK_2intgroup'
     777              : 
     778              :       INTEGER                                            :: end_point, handle, max_L_size, &
     779              :                                                             proc_receive, proc_shift, start_point
     780              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: BIb_C_copy
     781          442 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :, :)  :: BIb_C_gather
     782              : 
     783          442 :       CALL timeset(routineN, handle)
     784              : 
     785              :       ! replication scheme using mpi_allgather
     786              :       ! get the max L size of the
     787          988 :       max_L_size = MAXVAL(sizes_array)
     788              : 
     789         2210 :       ALLOCATE (BIb_C_copy(max_L_size, my_B_size, homo))
     790          442 :       BIb_C_copy = 0.0_dp
     791       898474 :       BIb_C_copy(1:SIZE(BIb_C, 1), 1:my_B_size, 1:homo) = BIb_C
     792              : 
     793          442 :       DEALLOCATE (BIb_C)
     794              : 
     795         2652 :       ALLOCATE (BIb_C_gather(max_L_size, my_B_size, homo, 0:comm_rep%num_pe - 1))
     796          442 :       BIb_C_gather = 0.0_dp
     797              : 
     798          442 :       CALL comm_rep%allgather(BIb_C_copy, BIb_C_gather)
     799              : 
     800          442 :       DEALLOCATE (BIb_C_copy)
     801              : 
     802         2210 :       ALLOCATE (BIb_C(my_group_L_size, my_B_size, homo))
     803          442 :       BIb_C = 0.0_dp
     804              : 
     805              :       ! reorder data
     806         1204 :       DO proc_shift = 0, comm_rep%num_pe - 1
     807          762 :          proc_receive = MODULO(comm_rep%mepos - proc_shift, comm_rep%num_pe)
     808              : 
     809          762 :          start_point = ranges_info_array(3, proc_shift, comm_exchange%mepos)
     810          762 :          end_point = ranges_info_array(4, proc_shift, comm_exchange%mepos)
     811              : 
     812              :          BIb_C(start_point:end_point, 1:my_B_size, 1:homo) = &
     813      1674771 :             BIb_C_gather(1:end_point - start_point + 1, 1:my_B_size, 1:homo, proc_receive)
     814              : 
     815              :       END DO
     816              : 
     817          442 :       DEALLOCATE (BIb_C_gather)
     818              : 
     819          442 :       CALL timestop(handle)
     820              : 
     821          442 :    END SUBROUTINE replicate_iaK_2intgroup
     822              : 
     823              : ! **************************************************************************************************
     824              : !> \brief ...
     825              : !> \param local_ab ...
     826              : !> \param t_ab ...
     827              : !> \param mp2_env ...
     828              : !> \param homo ...
     829              : !> \param virtual ...
     830              : !> \param my_B_size ...
     831              : !> \param my_group_L_size ...
     832              : !> \param calc_forces ...
     833              : !> \param ispin ...
     834              : !> \param jspin ...
     835              : !> \param local_ba ...
     836              : ! **************************************************************************************************
     837          530 :    SUBROUTINE mp2_ri_allocate_no_blk(local_ab, t_ab, mp2_env, homo, virtual, my_B_size, &
     838              :                                      my_group_L_size, calc_forces, ispin, jspin, local_ba)
     839              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     840              :          INTENT(OUT)                                     :: local_ab, t_ab
     841              :       TYPE(mp2_type)                                     :: mp2_env
     842              :       INTEGER, INTENT(IN)                                :: homo(2), virtual(2), my_B_size(2), &
     843              :                                                             my_group_L_size
     844              :       LOGICAL, INTENT(IN)                                :: calc_forces
     845              :       INTEGER, INTENT(IN)                                :: ispin, jspin
     846              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     847              :          INTENT(OUT)                                     :: local_ba
     848              : 
     849              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_allocate_no_blk'
     850              : 
     851              :       INTEGER                                            :: handle
     852              : 
     853          530 :       CALL timeset(routineN, handle)
     854              : 
     855         2120 :       ALLOCATE (local_ab(virtual(ispin), my_B_size(jspin)))
     856          530 :       local_ab = 0.0_dp
     857              : 
     858          530 :       IF (calc_forces) THEN
     859          384 :          IF (.NOT. ALLOCATED(mp2_env%ri_grad%P_ij(jspin)%array)) THEN
     860         1224 :             ALLOCATE (mp2_env%ri_grad%P_ij(jspin)%array(homo(ispin), homo(ispin)))
     861         6278 :             mp2_env%ri_grad%P_ij(jspin)%array = 0.0_dp
     862              :          END IF
     863          384 :          IF (.NOT. ALLOCATED(mp2_env%ri_grad%P_ab(jspin)%array)) THEN
     864         1224 :             ALLOCATE (mp2_env%ri_grad%P_ab(jspin)%array(my_B_size(jspin), virtual(jspin)))
     865        85070 :             mp2_env%ri_grad%P_ab(jspin)%array = 0.0_dp
     866              :          END IF
     867          384 :          IF (.NOT. ALLOCATED(mp2_env%ri_grad%Gamma_P_ia(jspin)%array)) THEN
     868         1530 :             ALLOCATE (mp2_env%ri_grad%Gamma_P_ia(jspin)%array(my_B_size(jspin), homo(jspin), my_group_L_size))
     869      1475502 :             mp2_env%ri_grad%Gamma_P_ia(jspin)%array = 0.0_dp
     870              :          END IF
     871              : 
     872          384 :          IF (ispin == jspin) THEN
     873              :             ! For non-alpha-beta case we need amplitudes
     874          918 :             ALLOCATE (t_ab(virtual(ispin), my_B_size(jspin)))
     875              : 
     876              :             ! That is just a dummy. In that way, we can pass it as array to other routines w/o requirement for allocatable array
     877          306 :             ALLOCATE (local_ba(1, 1))
     878              :          ELSE
     879              :             ! We need more integrals
     880          312 :             ALLOCATE (local_ba(virtual(jspin), my_B_size(ispin)))
     881              :          END IF
     882              :       END IF
     883              :       !
     884              : 
     885          530 :       CALL timestop(handle)
     886              : 
     887          530 :    END SUBROUTINE mp2_ri_allocate_no_blk
     888              : 
     889              : ! **************************************************************************************************
     890              : !> \brief ...
     891              : !> \param dimen_RI ...
     892              : !> \param my_B_size ...
     893              : !> \param block_size ...
     894              : !> \param local_i_aL ...
     895              : !> \param local_j_aL ...
     896              : !> \param calc_forces ...
     897              : !> \param Y_i_aP ...
     898              : !> \param Y_j_aP ...
     899              : !> \param ispin ...
     900              : !> \param jspin ...
     901              : ! **************************************************************************************************
     902          530 :    SUBROUTINE mp2_ri_allocate_blk(dimen_RI, my_B_size, block_size, &
     903              :                                   local_i_aL, local_j_aL, calc_forces, &
     904              :                                   Y_i_aP, Y_j_aP, ispin, jspin)
     905              :       INTEGER, INTENT(IN)                                :: dimen_RI, my_B_size(2), block_size
     906              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     907              :          INTENT(OUT)                                     :: local_i_aL, local_j_aL
     908              :       LOGICAL, INTENT(IN)                                :: calc_forces
     909              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
     910              :          INTENT(OUT)                                     :: Y_i_aP, Y_j_aP
     911              :       INTEGER, INTENT(IN)                                :: ispin, jspin
     912              : 
     913              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_allocate_blk'
     914              : 
     915              :       INTEGER                                            :: handle
     916              : 
     917          530 :       CALL timeset(routineN, handle)
     918              : 
     919         2650 :       ALLOCATE (local_i_aL(dimen_RI, my_B_size(ispin), block_size))
     920          530 :       local_i_aL = 0.0_dp
     921         2650 :       ALLOCATE (local_j_aL(dimen_RI, my_B_size(jspin), block_size))
     922          530 :       local_j_aL = 0.0_dp
     923              : 
     924          530 :       IF (calc_forces) THEN
     925         1536 :          ALLOCATE (Y_i_aP(my_B_size(ispin), dimen_RI, block_size))
     926          384 :          Y_i_aP = 0.0_dp
     927              :          ! For  closed-shell, alpha-alpha and beta-beta my_B_size_beta=my_b_size
     928              :          ! Not for alpha-beta case: Y_j_aP_beta is sent and received as Y_j_aP
     929         1536 :          ALLOCATE (Y_j_aP(my_B_size(jspin), dimen_RI, block_size))
     930          384 :          Y_j_aP = 0.0_dp
     931              :       END IF
     932              :       !
     933              : 
     934          530 :       CALL timestop(handle)
     935              : 
     936          530 :    END SUBROUTINE mp2_ri_allocate_blk
     937              : 
     938              : ! **************************************************************************************************
     939              : !> \brief ...
     940              : !> \param my_alpha_beta_case ...
     941              : !> \param total_ij_pairs ...
     942              : !> \param homo ...
     943              : !> \param homo_beta ...
     944              : !> \param block_size ...
     945              : !> \param ngroup ...
     946              : !> \param ij_map ...
     947              : !> \param color_sub ...
     948              : !> \param my_ij_pairs ...
     949              : !> \param my_open_shell_SS ...
     950              : !> \param unit_nr ...
     951              : ! **************************************************************************************************
     952          530 :    SUBROUTINE mp2_ri_communication(my_alpha_beta_case, total_ij_pairs, homo, homo_beta, &
     953              :                                    block_size, ngroup, ij_map, color_sub, my_ij_pairs, my_open_shell_SS, unit_nr)
     954              :       LOGICAL, INTENT(IN)                                :: my_alpha_beta_case
     955              :       INTEGER, INTENT(OUT)                               :: total_ij_pairs
     956              :       INTEGER, INTENT(IN)                                :: homo, homo_beta, block_size, ngroup
     957              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: ij_map
     958              :       INTEGER, INTENT(IN)                                :: color_sub
     959              :       INTEGER, INTENT(OUT)                               :: my_ij_pairs
     960              :       LOGICAL, INTENT(IN)                                :: my_open_shell_SS
     961              :       INTEGER, INTENT(IN)                                :: unit_nr
     962              : 
     963              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_communication'
     964              : 
     965              :       INTEGER :: assigned_blocks, first_I_block, first_J_block, handle, iiB, ij_block_counter, &
     966              :          ij_counter, jjB, last_i_block, last_J_block, num_block_per_group, num_IJ_blocks, &
     967              :          num_IJ_blocks_beta, total_ij_block, total_ij_pairs_blocks
     968          530 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :)              :: ij_marker
     969              : 
     970              : ! Calculate the maximum number of ij pairs that have to be computed
     971              : ! among groups
     972              : 
     973          530 :       CALL timeset(routineN, handle)
     974              : 
     975          530 :       IF (.NOT. my_open_shell_ss .AND. .NOT. my_alpha_beta_case) THEN
     976          266 :          total_ij_pairs = homo*(1 + homo)/2
     977          266 :          num_IJ_blocks = homo/block_size - 1
     978              : 
     979          266 :          first_I_block = 1
     980          266 :          last_i_block = block_size*(num_IJ_blocks - 1)
     981              : 
     982          266 :          first_J_block = block_size + 1
     983          266 :          last_J_block = block_size*(num_IJ_blocks + 1)
     984              : 
     985          266 :          ij_block_counter = 0
     986          602 :          DO iiB = first_I_block, last_i_block, block_size
     987          602 :             DO jjB = iiB + block_size, last_J_block, block_size
     988          840 :                ij_block_counter = ij_block_counter + 1
     989              :             END DO
     990              :          END DO
     991              : 
     992          266 :          total_ij_block = ij_block_counter
     993          266 :          num_block_per_group = total_ij_block/ngroup
     994          266 :          assigned_blocks = num_block_per_group*ngroup
     995              : 
     996          266 :          total_ij_pairs_blocks = assigned_blocks + (total_ij_pairs - assigned_blocks*(block_size**2))
     997              : 
     998         1064 :          ALLOCATE (ij_marker(homo, homo))
     999         4018 :          ij_marker = .TRUE.
    1000          798 :          ALLOCATE (ij_map(3, total_ij_pairs_blocks))
    1001          266 :          ij_map = 0
    1002          266 :          ij_counter = 0
    1003          266 :          my_ij_pairs = 0
    1004          602 :          DO iiB = first_I_block, last_i_block, block_size
    1005         1278 :             DO jjB = iiB + block_size, last_J_block, block_size
    1006          840 :                IF (ij_counter + 1 > assigned_blocks) EXIT
    1007          676 :                ij_counter = ij_counter + 1
    1008         2028 :                ij_marker(iiB:iiB + block_size - 1, jjB:jjB + block_size - 1) = .FALSE.
    1009          676 :                ij_map(1, ij_counter) = iiB
    1010          676 :                ij_map(2, ij_counter) = jjB
    1011          676 :                ij_map(3, ij_counter) = block_size
    1012         1012 :                IF (MOD(ij_counter, ngroup) == color_sub) my_ij_pairs = my_ij_pairs + 1
    1013              :             END DO
    1014              :          END DO
    1015         1070 :          DO iiB = 1, homo
    1016         2946 :             DO jjB = iiB, homo
    1017         2680 :                IF (ij_marker(iiB, jjB)) THEN
    1018         1200 :                   ij_counter = ij_counter + 1
    1019         1200 :                   ij_map(1, ij_counter) = iiB
    1020         1200 :                   ij_map(2, ij_counter) = jjB
    1021         1200 :                   ij_map(3, ij_counter) = 1
    1022         1200 :                   IF (MOD(ij_counter, ngroup) == color_sub) my_ij_pairs = my_ij_pairs + 1
    1023              :                END IF
    1024              :             END DO
    1025              :          END DO
    1026          266 :          DEALLOCATE (ij_marker)
    1027              : 
    1028          264 :       ELSE IF (.NOT. my_alpha_beta_case) THEN
    1029              :          ! THese are the cases alpha/alpha and beta/beta
    1030              :          ! We do not have to consider the diagonal elements
    1031          176 :          total_ij_pairs = homo*(homo - 1)/2
    1032          176 :          num_IJ_blocks = (homo - 1)/block_size - 1
    1033              : 
    1034          176 :          first_I_block = 1
    1035          176 :          last_i_block = block_size*(num_IJ_blocks - 1)
    1036              : 
    1037              :          ! We shift the blocks to prevent the calculation of the diagonal elements which always give zero
    1038          176 :          first_J_block = block_size + 2
    1039          176 :          last_J_block = block_size*(num_IJ_blocks + 1) + 1
    1040              : 
    1041          176 :          ij_block_counter = 0
    1042          262 :          DO iiB = first_I_block, last_i_block, block_size
    1043          262 :             DO jjB = iiB + block_size + 1, last_J_block, block_size
    1044          200 :                ij_block_counter = ij_block_counter + 1
    1045              :             END DO
    1046              :          END DO
    1047              : 
    1048          176 :          total_ij_block = ij_block_counter
    1049          176 :          num_block_per_group = total_ij_block/ngroup
    1050          176 :          assigned_blocks = num_block_per_group*ngroup
    1051              : 
    1052          176 :          total_ij_pairs_blocks = assigned_blocks + (total_ij_pairs - assigned_blocks*(block_size**2))
    1053              : 
    1054          704 :          ALLOCATE (ij_marker(homo, homo))
    1055         2984 :          ij_marker = .TRUE.
    1056          528 :          ALLOCATE (ij_map(3, total_ij_pairs_blocks))
    1057          176 :          ij_map = 0
    1058          176 :          ij_counter = 0
    1059          176 :          my_ij_pairs = 0
    1060          262 :          DO iiB = first_I_block, last_i_block, block_size
    1061          458 :             DO jjB = iiB + block_size + 1, last_J_block, block_size
    1062          200 :                IF (ij_counter + 1 > assigned_blocks) EXIT
    1063          196 :                ij_counter = ij_counter + 1
    1064          604 :                ij_marker(iiB:iiB + block_size - 1, jjB:jjB + block_size - 1) = .FALSE.
    1065          196 :                ij_map(1, ij_counter) = iiB
    1066          196 :                ij_map(2, ij_counter) = jjB
    1067          196 :                ij_map(3, ij_counter) = block_size
    1068          282 :                IF (MOD(ij_counter, ngroup) == color_sub) my_ij_pairs = my_ij_pairs + 1
    1069              :             END DO
    1070              :          END DO
    1071          774 :          DO iiB = 1, homo
    1072         1580 :             DO jjB = iiB + 1, homo
    1073         1404 :                IF (ij_marker(iiB, jjB)) THEN
    1074          598 :                   ij_counter = ij_counter + 1
    1075          598 :                   ij_map(1, ij_counter) = iiB
    1076          598 :                   ij_map(2, ij_counter) = jjB
    1077          598 :                   ij_map(3, ij_counter) = 1
    1078          598 :                   IF (MOD(ij_counter, ngroup) == color_sub) my_ij_pairs = my_ij_pairs + 1
    1079              :                END IF
    1080              :             END DO
    1081              :          END DO
    1082          176 :          DEALLOCATE (ij_marker)
    1083              : 
    1084              :       ELSE
    1085           88 :          total_ij_pairs = homo*homo_beta
    1086           88 :          num_IJ_blocks = homo/block_size
    1087           88 :          num_IJ_blocks_beta = homo_beta/block_size
    1088              : 
    1089           88 :          first_I_block = 1
    1090           88 :          last_i_block = block_size*(num_IJ_blocks - 1)
    1091              : 
    1092           88 :          first_J_block = 1
    1093           88 :          last_J_block = block_size*(num_IJ_blocks_beta - 1)
    1094              : 
    1095           88 :          ij_block_counter = 0
    1096          246 :          DO iiB = first_I_block, last_i_block, block_size
    1097          246 :             DO jjB = first_J_block, last_J_block, block_size
    1098          284 :                ij_block_counter = ij_block_counter + 1
    1099              :             END DO
    1100              :          END DO
    1101              : 
    1102           88 :          total_ij_block = ij_block_counter
    1103           88 :          num_block_per_group = total_ij_block/ngroup
    1104           88 :          assigned_blocks = num_block_per_group*ngroup
    1105              : 
    1106           88 :          total_ij_pairs_blocks = assigned_blocks + (total_ij_pairs - assigned_blocks*(block_size**2))
    1107              : 
    1108          352 :          ALLOCATE (ij_marker(homo, homo_beta))
    1109         1396 :          ij_marker = .TRUE.
    1110          264 :          ALLOCATE (ij_map(3, total_ij_pairs_blocks))
    1111           88 :          ij_map = 0
    1112           88 :          ij_counter = 0
    1113           88 :          my_ij_pairs = 0
    1114          246 :          DO iiB = first_I_block, last_i_block, block_size
    1115          486 :             DO jjB = first_J_block, last_J_block, block_size
    1116          244 :                IF (ij_counter + 1 > assigned_blocks) EXIT
    1117          240 :                ij_counter = ij_counter + 1
    1118          720 :                ij_marker(iiB:iiB + block_size - 1, jjB:jjB + block_size - 1) = .FALSE.
    1119          240 :                ij_map(1, ij_counter) = iiB
    1120          240 :                ij_map(2, ij_counter) = jjB
    1121          240 :                ij_map(3, ij_counter) = block_size
    1122          398 :                IF (MOD(ij_counter, ngroup) == color_sub) my_ij_pairs = my_ij_pairs + 1
    1123              :             END DO
    1124              :          END DO
    1125          432 :          DO iiB = 1, homo
    1126         1486 :             DO jjB = 1, homo_beta
    1127         1398 :                IF (ij_marker(iiB, jjB)) THEN
    1128          814 :                   ij_counter = ij_counter + 1
    1129          814 :                   ij_map(1, ij_counter) = iiB
    1130          814 :                   ij_map(2, ij_counter) = jjB
    1131          814 :                   ij_map(3, ij_counter) = 1
    1132          814 :                   IF (MOD(ij_counter, ngroup) == color_sub) my_ij_pairs = my_ij_pairs + 1
    1133              :                END IF
    1134              :             END DO
    1135              :          END DO
    1136           88 :          DEALLOCATE (ij_marker)
    1137              :       END IF
    1138              : 
    1139          530 :       IF (unit_nr > 0) THEN
    1140          265 :          IF (block_size == 1) THEN
    1141              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.1)") &
    1142          236 :                "RI_INFO| Percentage of ij pairs communicated with block size 1:", 100.0_dp
    1143              :          ELSE
    1144              :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.1)") &
    1145           29 :                "RI_INFO| Percentage of ij pairs communicated with block size 1:", &
    1146           58 :                100.0_dp*REAL((total_ij_pairs - assigned_blocks*(block_size**2)), KIND=dp)/REAL(total_ij_pairs, KIND=dp)
    1147              :          END IF
    1148          265 :          CALL m_flush(unit_nr)
    1149              :       END IF
    1150              : 
    1151          530 :       CALL timestop(handle)
    1152              : 
    1153          530 :    END SUBROUTINE mp2_ri_communication
    1154              : 
    1155              : ! **************************************************************************************************
    1156              : !> \brief ...
    1157              : !> \param para_env ...
    1158              : !> \param para_env_sub ...
    1159              : !> \param color_sub ...
    1160              : !> \param sizes_array ...
    1161              : !> \param calc_forces ...
    1162              : !> \param integ_group_size ...
    1163              : !> \param my_group_L_end ...
    1164              : !> \param my_group_L_size ...
    1165              : !> \param my_group_L_size_orig ...
    1166              : !> \param my_group_L_start ...
    1167              : !> \param my_new_group_L_size ...
    1168              : !> \param integ_group_pos2color_sub ...
    1169              : !> \param sizes_array_orig ...
    1170              : !> \param ranges_info_array ...
    1171              : !> \param comm_exchange ...
    1172              : !> \param comm_rep ...
    1173              : !> \param num_integ_group ...
    1174              : ! **************************************************************************************************
    1175          354 :    SUBROUTINE mp2_ri_create_group(para_env, para_env_sub, color_sub, &
    1176              :                                   sizes_array, calc_forces, &
    1177              :                                   integ_group_size, my_group_L_end, &
    1178              :                                   my_group_L_size, my_group_L_size_orig, my_group_L_start, my_new_group_L_size, &
    1179              :                                   integ_group_pos2color_sub, &
    1180              :                                   sizes_array_orig, ranges_info_array, comm_exchange, comm_rep, num_integ_group)
    1181              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_sub
    1182              :       INTEGER, INTENT(IN)                                :: color_sub
    1183              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(INOUT)  :: sizes_array
    1184              :       LOGICAL, INTENT(IN)                                :: calc_forces
    1185              :       INTEGER, INTENT(IN)                                :: integ_group_size, my_group_L_end
    1186              :       INTEGER, INTENT(INOUT)                             :: my_group_L_size
    1187              :       INTEGER, INTENT(OUT)                               :: my_group_L_size_orig
    1188              :       INTEGER, INTENT(IN)                                :: my_group_L_start
    1189              :       INTEGER, INTENT(INOUT)                             :: my_new_group_L_size
    1190              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT)    :: integ_group_pos2color_sub, &
    1191              :                                                             sizes_array_orig
    1192              :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
    1193              :          INTENT(OUT)                                     :: ranges_info_array
    1194              :       TYPE(mp_comm_type), INTENT(OUT)                    :: comm_exchange, comm_rep
    1195              :       INTEGER, INTENT(IN)                                :: num_integ_group
    1196              : 
    1197              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_create_group'
    1198              : 
    1199              :       INTEGER                                            :: handle, iiB, proc_receive, proc_shift, &
    1200              :                                                             sub_sub_color
    1201          354 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: new_sizes_array, rep_ends_array, &
    1202              :                                                             rep_sizes_array, rep_starts_array
    1203              :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: my_info
    1204              : 
    1205          354 :       CALL timeset(routineN, handle)
    1206              :       !
    1207          354 :       sub_sub_color = para_env_sub%mepos*num_integ_group + color_sub/integ_group_size
    1208          354 :       CALL comm_exchange%from_split(para_env, sub_sub_color)
    1209              : 
    1210              :       ! create the replication group
    1211          354 :       sub_sub_color = para_env_sub%mepos*comm_exchange%num_pe + comm_exchange%mepos
    1212          354 :       CALL comm_rep%from_split(para_env, sub_sub_color)
    1213              : 
    1214              :       ! create the new limits for K according to the size
    1215              :       ! of the integral group
    1216              : 
    1217              :       ! info array for replication
    1218         1062 :       ALLOCATE (rep_ends_array(0:comm_rep%num_pe - 1))
    1219          708 :       ALLOCATE (rep_starts_array(0:comm_rep%num_pe - 1))
    1220          708 :       ALLOCATE (rep_sizes_array(0:comm_rep%num_pe - 1))
    1221              : 
    1222          354 :       CALL comm_rep%allgather(my_group_L_size, rep_sizes_array)
    1223          354 :       CALL comm_rep%allgather(my_group_L_start, rep_starts_array)
    1224          354 :       CALL comm_rep%allgather(my_group_L_end, rep_ends_array)
    1225              : 
    1226              :       ! calculate my_new_group_L_size according to sizes_array
    1227          354 :       my_new_group_L_size = my_group_L_size
    1228              : 
    1229              :       ! Info of this process
    1230         1062 :       ALLOCATE (my_info(4, 0:comm_rep%num_pe - 1))
    1231          354 :       my_info(1, 0) = my_group_L_start
    1232          354 :       my_info(2, 0) = my_group_L_end
    1233          354 :       my_info(3, 0) = 1
    1234          354 :       my_info(4, 0) = my_group_L_size
    1235              : 
    1236          596 :       DO proc_shift = 1, comm_rep%num_pe - 1
    1237          242 :          proc_receive = MODULO(comm_rep%mepos - proc_shift, comm_rep%num_pe)
    1238              : 
    1239          242 :          my_new_group_L_size = my_new_group_L_size + rep_sizes_array(proc_receive)
    1240              : 
    1241          242 :          my_info(1, proc_shift) = rep_starts_array(proc_receive)
    1242          242 :          my_info(2, proc_shift) = rep_ends_array(proc_receive)
    1243          242 :          my_info(3, proc_shift) = my_info(4, proc_shift - 1) + 1
    1244          596 :          my_info(4, proc_shift) = my_new_group_L_size
    1245              : 
    1246              :       END DO
    1247              : 
    1248         1062 :       ALLOCATE (new_sizes_array(0:comm_exchange%num_pe - 1))
    1249         1416 :       ALLOCATE (ranges_info_array(4, 0:comm_rep%num_pe - 1, 0:comm_exchange%num_pe - 1))
    1250          354 :       CALL comm_exchange%allgather(my_new_group_L_size, new_sizes_array)
    1251          354 :       CALL comm_exchange%allgather(my_info, ranges_info_array)
    1252              : 
    1253          354 :       DEALLOCATE (rep_sizes_array)
    1254          354 :       DEALLOCATE (rep_starts_array)
    1255          354 :       DEALLOCATE (rep_ends_array)
    1256              : 
    1257         1062 :       ALLOCATE (integ_group_pos2color_sub(0:comm_exchange%num_pe - 1))
    1258          354 :       CALL comm_exchange%allgather(color_sub, integ_group_pos2color_sub)
    1259              : 
    1260          354 :       IF (calc_forces) THEN
    1261          228 :          iiB = SIZE(sizes_array)
    1262          684 :          ALLOCATE (sizes_array_orig(0:iiB - 1))
    1263          678 :          sizes_array_orig(:) = sizes_array
    1264              :       END IF
    1265              : 
    1266          354 :       my_group_L_size_orig = my_group_L_size
    1267          354 :       my_group_L_size = my_new_group_L_size
    1268          354 :       DEALLOCATE (sizes_array)
    1269              : 
    1270         1062 :       ALLOCATE (sizes_array(0:integ_group_size - 1))
    1271          806 :       sizes_array(:) = new_sizes_array
    1272              : 
    1273          354 :       DEALLOCATE (new_sizes_array)
    1274              :       !
    1275          354 :       CALL timestop(handle)
    1276              : 
    1277          708 :    END SUBROUTINE mp2_ri_create_group
    1278              : 
    1279              : ! **************************************************************************************************
    1280              : !> \brief ...
    1281              : !> \param mp2_env ...
    1282              : !> \param para_env ...
    1283              : !> \param para_env_sub ...
    1284              : !> \param gd_array ...
    1285              : !> \param gd_B_virtual ...
    1286              : !> \param homo ...
    1287              : !> \param dimen_RI ...
    1288              : !> \param unit_nr ...
    1289              : !> \param integ_group_size ...
    1290              : !> \param ngroup ...
    1291              : !> \param num_integ_group ...
    1292              : !> \param virtual ...
    1293              : !> \param calc_forces ...
    1294              : ! **************************************************************************************************
    1295         1416 :    SUBROUTINE mp2_ri_get_integ_group_size(mp2_env, para_env, para_env_sub, gd_array, gd_B_virtual, &
    1296          354 :                                           homo, dimen_RI, unit_nr, &
    1297              :                                           integ_group_size, &
    1298              :                                           ngroup, num_integ_group, &
    1299          354 :                                           virtual, calc_forces)
    1300              :       TYPE(mp2_type)                                     :: mp2_env
    1301              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_sub
    1302              :       TYPE(group_dist_d1_type), INTENT(IN)               :: gd_array
    1303              :       TYPE(group_dist_d1_type), DIMENSION(:), INTENT(IN) :: gd_B_virtual
    1304              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
    1305              :       INTEGER, INTENT(IN)                                :: dimen_RI, unit_nr
    1306              :       INTEGER, INTENT(OUT)                               :: integ_group_size, ngroup, num_integ_group
    1307              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: virtual
    1308              :       LOGICAL, INTENT(IN)                                :: calc_forces
    1309              : 
    1310              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_get_integ_group_size'
    1311              : 
    1312              :       INTEGER                                            :: block_size, handle, iiB, &
    1313              :                                                             max_repl_group_size, &
    1314              :                                                             min_integ_group_size
    1315              :       INTEGER(KIND=int_8)                                :: mem
    1316              :       LOGICAL                                            :: calc_group_size
    1317              :       REAL(KIND=dp)                                      :: factor, mem_base, mem_min, mem_per_blk, &
    1318              :                                                             mem_per_repl, mem_per_repl_blk, &
    1319              :                                                             mem_real
    1320              : 
    1321          354 :       CALL timeset(routineN, handle)
    1322              : 
    1323          354 :       ngroup = para_env%num_pe/para_env_sub%num_pe
    1324              : 
    1325          354 :       calc_group_size = mp2_env%ri_mp2%number_integration_groups <= 0
    1326          354 :       IF (.NOT. calc_group_size) THEN
    1327           10 :          IF (MOD(ngroup, mp2_env%ri_mp2%number_integration_groups) /= 0) calc_group_size = .TRUE.
    1328              :       END IF
    1329              : 
    1330          354 :       IF (calc_group_size) THEN
    1331          344 :          CALL m_memory(mem)
    1332          344 :          mem_real = (mem + 1024*1024 - 1)/(1024*1024)
    1333          344 :          CALL para_env%min(mem_real)
    1334          344 :          mem_real = MIN(mem_real, mp2_env%mp2_memory)
    1335              : 
    1336          344 :          mem_base = 0.0_dp
    1337          344 :          mem_per_blk = 0.0_dp
    1338          344 :          mem_per_repl = 0.0_dp
    1339          344 :          mem_per_repl_blk = 0.0_dp
    1340              : 
    1341              :          ! BIB_C_copy
    1342              :          mem_per_repl = mem_per_repl + MAXVAL(MAX(REAL(homo, KIND=dp)*maxsize(gd_array), REAL(dimen_RI, KIND=dp))* &
    1343          770 :                                               maxsize(gd_B_virtual))*8.0_dp/(1024**2)
    1344              :          ! BIB_C
    1345          770 :          mem_per_repl = mem_per_repl + SUM(REAL(homo, KIND=dp)*maxsize(gd_B_virtual))*maxsize(gd_array)*8.0_dp/(1024**2)
    1346              :          ! BIB_C_rec
    1347          770 :          mem_per_repl_blk = mem_per_repl_blk + REAL(MAXVAL(maxsize(gd_B_virtual)), KIND=dp)*maxsize(gd_array)*8.0_dp/(1024**2)
    1348              :          ! local_i_aL+local_j_aL
    1349          770 :          mem_per_blk = mem_per_blk + 2.0_dp*MAXVAL(maxsize(gd_B_virtual))*REAL(dimen_RI, KIND=dp)*8.0_dp/(1024**2)
    1350              :          ! local_ab
    1351          770 :          mem_base = mem_base + MAXVAL(REAL(virtual, KIND=dp)*maxsize(gd_B_virtual))*8.0_dp/(1024**2)
    1352              :          ! external_ab/external_i_aL
    1353         1196 :          mem_base = mem_base + REAL(MAX(dimen_RI, MAXVAL(virtual)), KIND=dp)*MAXVAL(maxsize(gd_B_virtual))*8.0_dp/(1024**2)
    1354              : 
    1355          344 :          IF (calc_forces) THEN
    1356              :             ! Gamma_P_ia
    1357              :             mem_per_repl = mem_per_repl + SUM(REAL(homo, KIND=dp)*maxsize(gd_array)* &
    1358          514 :                                               maxsize(gd_B_virtual))*8.0_dp/(1024**2)
    1359              :             ! Y_i_aP+Y_j_aP
    1360          514 :             mem_per_blk = mem_per_blk + 2.0_dp*MAXVAL(maxsize(gd_B_virtual))*dimen_RI*8.0_dp/(1024**2)
    1361              :             ! local_ba/t_ab
    1362          808 :             mem_base = mem_base + REAL(MAXVAL(maxsize(gd_B_virtual)), KIND=dp)*MAX(dimen_RI, MAXVAL(virtual))*8.0_dp/(1024**2)
    1363              :             ! P_ij
    1364          514 :             mem_base = mem_base + SUM(REAL(homo, KIND=dp)*homo)*8.0_dp/(1024**2)
    1365              :             ! P_ab
    1366          514 :             mem_base = mem_base + SUM(REAL(virtual, KIND=dp)*maxsize(gd_B_virtual))*8.0_dp/(1024**2)
    1367              :             ! send_ab/send_i_aL
    1368          808 :             mem_base = mem_base + REAL(MAX(dimen_RI, MAXVAL(virtual)), KIND=dp)*MAXVAL(maxsize(gd_B_virtual))*8.0_dp/(1024**2)
    1369              :          END IF
    1370              : 
    1371              :          ! This a first guess based on the assumption of optimal block sizes
    1372          770 :          block_size = MAX(1, MIN(FLOOR(SQRT(REAL(MINVAL(homo), KIND=dp))), FLOOR(MINVAL(homo)/SQRT(2.0_dp*ngroup))))
    1373          344 :          IF (mp2_env%ri_mp2%block_size > 0) block_size = mp2_env%ri_mp2%block_size
    1374              : 
    1375          344 :          mem_min = mem_base + mem_per_repl + (mem_per_blk + mem_per_repl_blk)*block_size
    1376              : 
    1377          516 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T68,F9.2,A4)') 'RI_INFO| Minimum available memory per MPI process:', &
    1378          344 :             mem_real, ' MiB'
    1379          516 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T68,F9.2,A4)') 'RI_INFO| Minimum required memory per MPI process:', &
    1380          344 :             mem_min, ' MiB'
    1381              : 
    1382              :          ! We use the following communication model
    1383              :          ! Comm(replication)+Comm(collection of data for ij pair)+Comm(contraction)
    1384              :          ! One can show that the costs of the contraction step are independent of the block size and the replication group size
    1385              :          ! With gradients, the other two steps are carried out twice (Y_i_aP -> Gamma_i_aP, and dereplication)
    1386              :          ! NL ... number of RI basis functions
    1387              :          ! NR ... replication group size
    1388              :          ! NG ... number of sub groups
    1389              :          ! NB ... Block size
    1390              :          ! o  ... number of occupied orbitals
    1391              :          ! Then, we have the communication costs (in multiples of the original BIb_C matrix)
    1392              :          ! (NR/NG)+(1-(NR/NG))*(o/NB+NB-2)/NG = (NR/NG)*(1-(o/NB+NB-2)/NG)+(o/NB+NB-2)/NG
    1393              :          ! and with gradients
    1394              :          ! 2*(NR/NG)+2*(1-(NR/NG))*(o/NB+NB-2)/NG = (NR/NG)*(1-(o/NB+NB-2)/NG)+(o/NB+NB-2)/NG
    1395              :          ! We are looking for the minimum of the communication volume,
    1396              :          ! thus, if the prefactor of (NR/NG) is smaller than zero, use the largest possible replication group size.
    1397              :          ! If the factor is larger than zero, set the replication group size to 1.
    1398              :          ! (For small systems and a large number of subgroups)
    1399              :          ! Replication group size = 1 implies that the integration group size equals the number of subgroups
    1400              : 
    1401          344 :          integ_group_size = ngroup
    1402              : 
    1403              :          ! Multiply everything by homo*virtual to consider differences between spin channels in case of open-shell calculations
    1404              :          factor = REAL(SUM(homo*virtual), KIND=dp) &
    1405         1622 :                   - SUM((REAL(MAXVAL(homo), KIND=dp)/block_size + block_size - 2.0_dp)*homo*virtual)/ngroup
    1406          672 :          IF (SIZE(homo) == 2) factor = factor - 2.0_dp*PRODUCT(homo)/block_size/ngroup*SUM(homo*virtual)
    1407              : 
    1408          688 :          IF (factor <= 0.0_dp) THEN
    1409              :             ! Remove the fixed memory and divide by the memory per replication group size
    1410              :             max_repl_group_size = MIN(MAX(FLOOR((mem_real - mem_base - mem_per_blk*block_size)/ &
    1411          256 :                                                 (mem_per_repl + mem_per_repl_blk*block_size)), 1), ngroup)
    1412              :             ! Convert to an integration group size
    1413          256 :             min_integ_group_size = ngroup/max_repl_group_size
    1414              : 
    1415              :             ! Ensure that the integration group size is a divisor of the number of sub groups
    1416          256 :             DO iiB = MAX(MIN(min_integ_group_size, ngroup), 1), ngroup
    1417              :                ! check that the ngroup is a multiple of  integ_group_size
    1418          256 :                IF (MOD(ngroup, iiB) == 0) THEN
    1419          256 :                   integ_group_size = iiB
    1420          256 :                   EXIT
    1421              :                END IF
    1422            0 :                integ_group_size = integ_group_size + 1
    1423              :             END DO
    1424              :          END IF
    1425              :       ELSE ! We take the user provided group size
    1426           10 :          integ_group_size = ngroup/mp2_env%ri_mp2%number_integration_groups
    1427              :       END IF
    1428              : 
    1429          354 :       IF (unit_nr > 0) THEN
    1430              :          WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
    1431          177 :             "RI_INFO| Group size for integral replication:", integ_group_size*para_env_sub%num_pe
    1432          177 :          CALL m_flush(unit_nr)
    1433              :       END IF
    1434              : 
    1435          354 :       num_integ_group = ngroup/integ_group_size
    1436              : 
    1437          354 :       CALL timestop(handle)
    1438              : 
    1439          354 :    END SUBROUTINE mp2_ri_get_integ_group_size
    1440              : 
    1441              : ! **************************************************************************************************
    1442              : !> \brief ...
    1443              : !> \param mp2_env ...
    1444              : !> \param para_env ...
    1445              : !> \param para_env_sub ...
    1446              : !> \param gd_array ...
    1447              : !> \param gd_B_virtual ...
    1448              : !> \param homo ...
    1449              : !> \param virtual ...
    1450              : !> \param dimen_RI ...
    1451              : !> \param unit_nr ...
    1452              : !> \param block_size ...
    1453              : !> \param ngroup ...
    1454              : !> \param num_integ_group ...
    1455              : !> \param my_open_shell_ss ...
    1456              : !> \param calc_forces ...
    1457              : !> \param buffer_1D ...
    1458              : ! **************************************************************************************************
    1459          530 :    SUBROUTINE mp2_ri_get_block_size(mp2_env, para_env, para_env_sub, gd_array, gd_B_virtual, &
    1460          530 :                                     homo, virtual, dimen_RI, unit_nr, &
    1461              :                                     block_size, ngroup, num_integ_group, &
    1462              :                                     my_open_shell_ss, calc_forces, buffer_1D)
    1463              :       TYPE(mp2_type)                                     :: mp2_env
    1464              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_sub
    1465              :       TYPE(group_dist_d1_type), INTENT(IN)               :: gd_array
    1466              :       TYPE(group_dist_d1_type), DIMENSION(:), INTENT(IN) :: gd_B_virtual
    1467              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
    1468              :       INTEGER, INTENT(IN)                                :: dimen_RI, unit_nr
    1469              :       INTEGER, INTENT(OUT)                               :: block_size, ngroup
    1470              :       INTEGER, INTENT(IN)                                :: num_integ_group
    1471              :       LOGICAL, INTENT(IN)                                :: my_open_shell_ss, calc_forces
    1472              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1473              :          INTENT(OUT)                                     :: buffer_1D
    1474              : 
    1475              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_ri_get_block_size'
    1476              : 
    1477              :       INTEGER                                            :: best_block_size, handle, num_IJ_blocks
    1478              :       INTEGER(KIND=int_8)                                :: buffer_size, mem
    1479              :       REAL(KIND=dp)                                      :: mem_base, mem_per_blk, mem_per_repl_blk, &
    1480              :                                                             mem_real
    1481              : 
    1482          530 :       CALL timeset(routineN, handle)
    1483              : 
    1484          530 :       ngroup = para_env%num_pe/para_env_sub%num_pe
    1485              : 
    1486          530 :       CALL m_memory(mem)
    1487          530 :       mem_real = (mem + 1024*1024 - 1)/(1024*1024)
    1488          530 :       CALL para_env%min(mem_real)
    1489              : 
    1490          530 :       mem_base = 0.0_dp
    1491          530 :       mem_per_blk = 0.0_dp
    1492          530 :       mem_per_repl_blk = 0.0_dp
    1493              : 
    1494              :       ! external_ab
    1495         1766 :       mem_base = mem_base + MAXVAL(maxsize(gd_B_virtual))*MAX(dimen_RI, MAXVAL(virtual))*8.0_dp/(1024**2)
    1496              :       ! BIB_C_rec
    1497         1148 :       mem_per_repl_blk = mem_per_repl_blk + REAL(MAXVAL(maxsize(gd_B_virtual)), KIND=dp)*maxsize(gd_array)*8.0_dp/(1024**2)
    1498              :       ! local_i_aL+local_j_aL
    1499         1148 :       mem_per_blk = mem_per_blk + 2.0_dp*MAXVAL(maxsize(gd_B_virtual))*REAL(dimen_RI, KIND=dp)*8.0_dp/(1024**2)
    1500              :       ! Copy to keep arrays contiguous
    1501         1766 :       mem_base = mem_base + MAXVAL(maxsize(gd_B_virtual))*MAX(dimen_RI, MAXVAL(virtual))*8.0_dp/(1024**2)
    1502              : 
    1503          530 :       IF (calc_forces) THEN
    1504              :          ! Y_i_aP+Y_j_aP+BIb_C_send
    1505          846 :          mem_per_blk = mem_per_blk + 3.0_dp*MAXVAL(maxsize(gd_B_virtual))*dimen_RI*8.0_dp/(1024**2)
    1506              :          ! send_ab
    1507         1308 :          mem_base = mem_base + MAXVAL(maxsize(gd_B_virtual))*MAX(dimen_RI, MAXVAL(virtual))*8.0_dp/(1024**2)
    1508              :       END IF
    1509              : 
    1510          530 :       best_block_size = 1
    1511              : 
    1512              :       ! Here we split the memory half for the communication, half for replication
    1513          530 :       IF (mp2_env%ri_mp2%block_size > 0) THEN
    1514              :          best_block_size = mp2_env%ri_mp2%block_size
    1515              :       ELSE
    1516          294 :          best_block_size = MAX(FLOOR((mem_real - mem_base)/(mem_per_blk + mem_per_repl_blk*ngroup/num_integ_group)), 1)
    1517              : 
    1518      3226924 :          DO
    1519      3227218 :             IF (SIZE(homo) == 1) THEN
    1520      2595468 :             IF (.NOT. my_open_shell_ss) THEN
    1521      1190934 :                num_IJ_blocks = (homo(1)/best_block_size)
    1522      1190934 :                num_IJ_blocks = (num_IJ_blocks*num_IJ_blocks - num_IJ_blocks)/2
    1523              :             ELSE
    1524      1404534 :                num_IJ_blocks = ((homo(1) - 1)/best_block_size)
    1525      1404534 :                num_IJ_blocks = (num_IJ_blocks*num_IJ_blocks - num_IJ_blocks)/2
    1526              :             END IF
    1527              :             ELSE
    1528      1895250 :             num_ij_blocks = PRODUCT(homo/best_block_size)
    1529              :             END IF
    1530              :             ! Enforce at least one large block for each subgroup
    1531      3227218 :             IF ((num_IJ_blocks >= ngroup .AND. num_IJ_blocks > 0) .OR. best_block_size == 1) THEN
    1532              :                EXIT
    1533              :             ELSE
    1534      3226924 :                best_block_size = best_block_size - 1
    1535              :             END IF
    1536              :          END DO
    1537              : 
    1538          294 :          IF (SIZE(homo) == 1) THEN
    1539          232 :          IF (my_open_shell_ss) THEN
    1540              :             ! check that best_block_size is not bigger than sqrt(homo-1)
    1541              :             ! Diagonal elements do not have to be considered
    1542          124 :             best_block_size = MIN(FLOOR(SQRT(REAL(homo(1) - 1, KIND=dp))), best_block_size)
    1543              :          ELSE
    1544              :             ! check that best_block_size is not bigger than sqrt(homo)
    1545          108 :             best_block_size = MIN(FLOOR(SQRT(REAL(homo(1), KIND=dp))), best_block_size)
    1546              :          END IF
    1547              :          END IF
    1548              :       END IF
    1549          530 :       block_size = MAX(1, best_block_size)
    1550              : 
    1551          530 :       IF (unit_nr > 0) THEN
    1552              :          WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
    1553          265 :             "RI_INFO| Block size:", block_size
    1554          265 :          CALL m_flush(unit_nr)
    1555              :       END IF
    1556              : 
    1557              :       ! Determine recv buffer size (BI_C_recv, external_i_aL, external_ab)
    1558              :       buffer_size = MAX(INT(maxsize(gd_array), KIND=int_8)*block_size, INT(MAX(dimen_RI, MAXVAL(virtual)), KIND=int_8)) &
    1559         1766 :                     *MAXVAL(maxsize(gd_B_virtual))
    1560              :       ! The send buffer has the same size as the recv buffer
    1561          530 :       IF (calc_forces) buffer_size = buffer_size*2
    1562         1590 :       ALLOCATE (buffer_1D(buffer_size))
    1563              : 
    1564          530 :       CALL timestop(handle)
    1565              : 
    1566          530 :    END SUBROUTINE mp2_ri_get_block_size
    1567              : 
    1568              : ! **************************************************************************************************
    1569              : !> \brief ...
    1570              : !> \param mp2_env ...
    1571              : !> \param para_env_sub ...
    1572              : !> \param gd_B_virtual ...
    1573              : !> \param Eigenval ...
    1574              : !> \param homo ...
    1575              : !> \param dimen_RI ...
    1576              : !> \param iiB ...
    1577              : !> \param jjB ...
    1578              : !> \param my_B_size ...
    1579              : !> \param my_B_virtual_end ...
    1580              : !> \param my_B_virtual_start ...
    1581              : !> \param my_i ...
    1582              : !> \param my_j ...
    1583              : !> \param virtual ...
    1584              : !> \param local_ab ...
    1585              : !> \param t_ab ...
    1586              : !> \param my_local_i_aL ...
    1587              : !> \param my_local_j_aL ...
    1588              : !> \param open_ss ...
    1589              : !> \param Y_i_aP ...
    1590              : !> \param Y_j_aP ...
    1591              : !> \param local_ba ...
    1592              : !> \param ispin ...
    1593              : !> \param jspin ...
    1594              : !> \param dgemm_counter ...
    1595              : !> \param buffer_1D ...
    1596              : ! **************************************************************************************************
    1597         6480 :    SUBROUTINE mp2_update_P_gamma(mp2_env, para_env_sub, gd_B_virtual, &
    1598         3240 :                                  Eigenval, homo, dimen_RI, iiB, jjB, my_B_size, &
    1599         3240 :                                  my_B_virtual_end, my_B_virtual_start, my_i, my_j, virtual, local_ab, &
    1600         3240 :                                  t_ab, my_local_i_aL, my_local_j_aL, open_ss, Y_i_aP, Y_j_aP, &
    1601         1620 :                                  local_ba, ispin, jspin, dgemm_counter, buffer_1D)
    1602              :       TYPE(mp2_type)                                     :: mp2_env
    1603              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env_sub
    1604              :       TYPE(group_dist_d1_type), DIMENSION(:), INTENT(IN) :: gd_B_virtual
    1605              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: Eigenval
    1606              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
    1607              :       INTEGER, INTENT(IN)                                :: dimen_RI, iiB, jjB
    1608              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: my_B_size, my_B_virtual_end, &
    1609              :                                                             my_B_virtual_start
    1610              :       INTEGER, INTENT(IN)                                :: my_i, my_j
    1611              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: virtual
    1612              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1613              :          INTENT(INOUT), TARGET                           :: local_ab
    1614              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1615              :          INTENT(IN), TARGET                              :: t_ab, my_local_i_aL, my_local_j_aL
    1616              :       LOGICAL, INTENT(IN)                                :: open_ss
    1617              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1618              :          INTENT(INOUT), TARGET                           :: Y_i_aP, Y_j_aP, local_ba
    1619              :       INTEGER, INTENT(IN)                                :: ispin, jspin
    1620              :       TYPE(dgemm_counter_type), INTENT(INOUT)            :: dgemm_counter
    1621              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:), TARGET    :: buffer_1D
    1622              : 
    1623              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_update_P_gamma'
    1624              : 
    1625              :       INTEGER :: a, b, b_global, handle, proc_receive, proc_send, proc_shift, rec_B_size, &
    1626              :          rec_B_virtual_end, rec_B_virtual_start, send_B_size, send_B_virtual_end, &
    1627              :          send_B_virtual_start
    1628              :       INTEGER(KIND=int_8)                                :: offset
    1629              :       LOGICAL                                            :: alpha_beta
    1630              :       REAL(KIND=dp)                                      :: factor, P_ij_diag
    1631              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
    1632         1620 :          POINTER                                         :: external_ab, send_ab
    1633              : 
    1634         1620 :       CALL timeset(routineN//"_Pia", handle)
    1635              : 
    1636         1620 :       alpha_beta = .NOT. (ispin == jspin)
    1637         1620 :       IF (open_ss) THEN
    1638              :          factor = 1.0_dp
    1639              :       ELSE
    1640         1231 :          factor = 2.0_dp
    1641              :       END IF
    1642              :       ! divide the (ia|jb) integrals by Delta_ij^ab
    1643        25159 :       DO b = 1, my_B_size(jspin)
    1644        23539 :          b_global = b + my_B_virtual_start(jspin) - 1
    1645       469848 :          DO a = 1, virtual(ispin)
    1646              :             local_ab(a, b) = -local_ab(a, b)/ &
    1647              :                              (Eigenval(homo(ispin) + a, ispin) + Eigenval(homo(jspin) + b_global, jspin) - &
    1648       468228 :                               Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, jspin))
    1649              :          END DO
    1650              :       END DO
    1651         1620 :       IF (.NOT. (alpha_beta)) THEN
    1652       329242 :          P_ij_diag = -SUM(local_ab*t_ab)*factor
    1653              :       ELSE
    1654              :          ! update diagonal part of P_ij
    1655       140606 :          P_ij_diag = -SUM(local_ab*local_ab)*mp2_env%scale_S
    1656              :          ! More integrals needed only for alpha-beta case: local_ba
    1657         6987 :          DO b = 1, my_B_size(ispin)
    1658         6485 :             b_global = b + my_B_virtual_start(ispin) - 1
    1659       140066 :             DO a = 1, virtual(jspin)
    1660              :                local_ba(a, b) = -local_ba(a, b)/ &
    1661              :                                 (Eigenval(homo(jspin) + a, jspin) + Eigenval(homo(ispin) + b_global, ispin) - &
    1662       139564 :                                  Eigenval(my_i + iiB - 1, ispin) - Eigenval(my_j + jjB - 1, jspin))
    1663              :             END DO
    1664              :          END DO
    1665              :       END IF
    1666              : 
    1667              :       ! P_ab and add diagonal part of P_ij
    1668              : 
    1669         1620 :       CALL dgemm_counter_start(dgemm_counter)
    1670         1620 :       IF (.NOT. (alpha_beta)) THEN
    1671              :          CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(ispin), my_B_size(ispin), virtual(ispin), 1.0_dp, &
    1672              :                                           t_ab, virtual(ispin), local_ab, virtual(ispin), &
    1673              :                                           1.0_dp, mp2_env%ri_grad%P_ab(ispin)%array(:, &
    1674         1118 :                                                                my_B_virtual_start(ispin):my_B_virtual_end(ispin)), my_B_size(ispin))
    1675              :          mp2_env%ri_grad%P_ij(ispin)%array(my_i + iiB - 1, my_i + iiB - 1) = &
    1676         1118 :             mp2_env%ri_grad%P_ij(ispin)%array(my_i + iiB - 1, my_i + iiB - 1) + P_ij_diag
    1677              :       ELSE
    1678              :          CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(ispin), my_B_size(ispin), virtual(jspin), mp2_env%scale_S, &
    1679              :                                           local_ba, virtual(jspin), local_ba, virtual(jspin), 1.0_dp, &
    1680          502 :                           mp2_env%ri_grad%P_ab(ispin)%array(:, my_B_virtual_start(ispin):my_B_virtual_end(ispin)), my_B_size(ispin))
    1681              : 
    1682              :          mp2_env%ri_grad%P_ij(ispin)%array(my_i + iiB - 1, my_i + iiB - 1) = &
    1683          502 :             mp2_env%ri_grad%P_ij(ispin)%array(my_i + iiB - 1, my_i + iiB - 1) + P_ij_diag
    1684              : 
    1685              :          CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(jspin), my_B_size(jspin), virtual(ispin), mp2_env%scale_S, &
    1686              :                                           local_ab, virtual(ispin), local_ab, virtual(ispin), 1.0_dp, &
    1687          502 :                           mp2_env%ri_grad%P_ab(jspin)%array(:, my_B_virtual_start(jspin):my_B_virtual_end(jspin)), my_B_size(jspin))
    1688              : 
    1689              :          mp2_env%ri_grad%P_ij(jspin)%array(my_j + jjB - 1, my_j + jjB - 1) = &
    1690          502 :             mp2_env%ri_grad%P_ij(jspin)%array(my_j + jjB - 1, my_j + jjB - 1) + P_ij_diag
    1691              :       END IF
    1692              :       ! The summation is over unique pairs. In alpha-beta case, all pairs are unique: subroutine is called for
    1693              :       ! both i^alpha,j^beta and i^beta,j^alpha. Formally, my_i can be equal to my_j, but they are different
    1694              :       ! due to spin in alpha-beta case.
    1695         1620 :       IF ((my_i /= my_j) .AND. (.NOT. alpha_beta)) THEN
    1696              : 
    1697              :          CALL mp2_env%local_gemm_ctx%gemm('N', 'T', my_B_size(ispin), virtual(ispin), my_B_size(ispin), 1.0_dp, &
    1698              :                                           t_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :), my_B_size(ispin), &
    1699              :                                           local_ab, virtual(ispin), &
    1700         9843 :                                           1.0_dp, mp2_env%ri_grad%P_ab(ispin)%array, my_B_size(ispin))
    1701              : 
    1702              :          mp2_env%ri_grad%P_ij(ispin)%array(my_j + jjB - 1, my_j + jjB - 1) = &
    1703          823 :             mp2_env%ri_grad%P_ij(ispin)%array(my_j + jjB - 1, my_j + jjB - 1) + P_ij_diag
    1704              :       END IF
    1705         1792 :       DO proc_shift = 1, para_env_sub%num_pe - 1
    1706          172 :          proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    1707          172 :          proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    1708              : 
    1709          172 :          CALL get_group_dist(gd_B_virtual(jspin), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    1710          172 :          CALL get_group_dist(gd_B_virtual(jspin), proc_send, send_B_virtual_start, send_B_virtual_end, send_B_size)
    1711              : 
    1712          172 :          external_ab(1:virtual(ispin), 1:rec_B_size) => buffer_1D(1:INT(virtual(ispin), int_8)*rec_B_size)
    1713          172 :          external_ab = 0.0_dp
    1714              : 
    1715              :          CALL para_env_sub%sendrecv(local_ab, proc_send, &
    1716          172 :                                     external_ab, proc_receive)
    1717              : 
    1718          172 :          IF (.NOT. (alpha_beta)) THEN
    1719              :             CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(ispin), rec_B_size, virtual(ispin), 1.0_dp, &
    1720              :                                              t_ab, virtual(ispin), external_ab, virtual(ispin), &
    1721          102 :                               1.0_dp, mp2_env%ri_grad%P_ab(ispin)%array(:, rec_B_virtual_start:rec_B_virtual_end), my_B_size(ispin))
    1722              :          ELSE
    1723              :             CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(jspin), rec_B_size, virtual(ispin), mp2_env%scale_S, &
    1724              :                                              local_ab, virtual(ispin), external_ab, virtual(ispin), &
    1725              :                                              1.0_dp, mp2_env%ri_grad%P_ab(jspin)%array(:, rec_B_virtual_start:rec_B_virtual_end), &
    1726           70 :                                              my_B_size(jspin))
    1727              : 
    1728              :             ! For alpha-beta part of alpha-density we need a new parallel code
    1729              :             ! And new external_ab (of a different size)
    1730           70 :             CALL get_group_dist(gd_B_virtual(ispin), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    1731           70 :             CALL get_group_dist(gd_B_virtual(ispin), proc_send, send_B_virtual_start, send_B_virtual_end, send_B_size)
    1732           70 :             external_ab(1:virtual(jspin), 1:rec_B_size) => buffer_1D(1:INT(virtual(jspin), int_8)*rec_B_size)
    1733           70 :             external_ab = 0.0_dp
    1734              :             CALL para_env_sub%sendrecv(local_ba, proc_send, &
    1735           70 :                                        external_ab, proc_receive)
    1736              :             CALL mp2_env%local_gemm_ctx%gemm('T', 'N', my_B_size(ispin), rec_B_size, virtual(jspin), mp2_env%scale_S, &
    1737              :                                              local_ba, virtual(jspin), external_ab, virtual(jspin), &
    1738           70 :                               1.0_dp, mp2_env%ri_grad%P_ab(ispin)%array(:, rec_B_virtual_start:rec_B_virtual_end), my_B_size(ispin))
    1739              :          END IF
    1740              : 
    1741         1964 :          IF ((my_i /= my_j) .AND. (.NOT. alpha_beta)) THEN
    1742              :             external_ab(1:my_B_size(ispin), 1:virtual(ispin)) => &
    1743           86 :                buffer_1D(1:INT(virtual(ispin), int_8)*my_B_size(ispin))
    1744           86 :             external_ab = 0.0_dp
    1745              : 
    1746           86 :             offset = INT(virtual(ispin), int_8)*my_B_size(ispin)
    1747              : 
    1748           86 :             send_ab(1:send_B_size, 1:virtual(ispin)) => buffer_1D(offset + 1:offset + INT(send_B_size, int_8)*virtual(ispin))
    1749           86 :             send_ab = 0.0_dp
    1750              : 
    1751              :             CALL mp2_env%local_gemm_ctx%gemm('N', 'T', send_B_size, virtual(ispin), my_B_size(ispin), 1.0_dp, &
    1752              :                                              t_ab(send_B_virtual_start:send_B_virtual_end, :), send_B_size, &
    1753         9063 :                                              local_ab, virtual(ispin), 0.0_dp, send_ab, send_B_size)
    1754              :             CALL para_env_sub%sendrecv(send_ab, proc_send, &
    1755           86 :                                        external_ab, proc_receive)
    1756              : 
    1757        18083 :             mp2_env%ri_grad%P_ab(ispin)%array(:, :) = mp2_env%ri_grad%P_ab(ispin)%array + external_ab
    1758              :          END IF
    1759              : 
    1760              :       END DO
    1761         1620 :       IF (.NOT. alpha_beta) THEN
    1762         1118 :          IF (my_i /= my_j) THEN
    1763          823 :             CALL dgemm_counter_stop(dgemm_counter, 2*my_B_size(ispin), virtual(ispin), virtual(ispin))
    1764              :          ELSE
    1765          295 :             CALL dgemm_counter_stop(dgemm_counter, my_B_size(ispin), virtual(ispin), virtual(ispin))
    1766              :          END IF
    1767              :       ELSE
    1768         1506 :          CALL dgemm_counter_stop(dgemm_counter, SUM(my_B_size), virtual(ispin), virtual(jspin))
    1769              :       END IF
    1770         1620 :       CALL timestop(handle)
    1771              : 
    1772              :       ! Now, Gamma_P_ia (made of Y_ia_P)
    1773              : 
    1774         1620 :       CALL timeset(routineN//"_Gamma", handle)
    1775         1620 :       CALL dgemm_counter_start(dgemm_counter)
    1776         1620 :       IF (.NOT. alpha_beta) THEN
    1777              :          ! Alpha-alpha, beta-beta and closed shell
    1778              :          CALL mp2_env%local_gemm_ctx%gemm('N', 'T', my_B_size(ispin), dimen_RI, my_B_size(ispin), 1.0_dp, &
    1779              :                                           t_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :), my_B_size(ispin), &
    1780        11738 :                                           my_local_j_aL, dimen_RI, 1.0_dp, Y_i_aP, my_B_size(ispin))
    1781              :       ELSE ! Alpha-beta
    1782              :          CALL mp2_env%local_gemm_ctx%gemm('N', 'T', my_B_size(ispin), dimen_RI, my_B_size(jspin), mp2_env%scale_S, &
    1783              :                                           local_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :), my_B_size(ispin), &
    1784         8237 :                                           my_local_j_aL, dimen_RI, 1.0_dp, Y_i_aP, my_B_size(ispin))
    1785              :          CALL mp2_env%local_gemm_ctx%gemm('T', 'T', my_B_size(jspin), dimen_RI, my_B_size(ispin), mp2_env%scale_S, &
    1786              :                                           local_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :), my_B_size(ispin), &
    1787         8237 :                                           my_local_i_aL, dimen_RI, 1.0_dp, Y_j_aP, my_B_size(jspin))
    1788              :       END IF
    1789              : 
    1790         1620 :       IF (para_env_sub%num_pe > 1) THEN
    1791          172 :          external_ab(1:my_B_size(ispin), 1:dimen_RI) => buffer_1D(1:INT(my_B_size(ispin), int_8)*dimen_RI)
    1792          172 :          external_ab = 0.0_dp
    1793              : 
    1794          172 :          offset = INT(my_B_size(ispin), int_8)*dimen_RI
    1795              :       END IF
    1796              :       !
    1797         1792 :       DO proc_shift = 1, para_env_sub%num_pe - 1
    1798          172 :          proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    1799          172 :          proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    1800              : 
    1801          172 :          CALL get_group_dist(gd_B_virtual(ispin), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    1802          172 :          CALL get_group_dist(gd_B_virtual(ispin), proc_send, send_B_virtual_start, send_B_virtual_end, send_B_size)
    1803              : 
    1804          172 :          send_ab(1:send_B_size, 1:dimen_RI) => buffer_1D(offset + 1:offset + INT(dimen_RI, int_8)*send_B_size)
    1805          172 :          send_ab = 0.0_dp
    1806         1792 :          IF (.NOT. alpha_beta) THEN
    1807              :             CALL mp2_env%local_gemm_ctx%gemm('N', 'T', send_B_size, dimen_RI, my_B_size(ispin), 1.0_dp, &
    1808              :                                              t_ab(send_B_virtual_start:send_B_virtual_end, :), send_B_size, &
    1809        10671 :                                              my_local_j_aL, dimen_RI, 0.0_dp, send_ab, send_B_size)
    1810          102 :             CALL para_env_sub%sendrecv(send_ab, proc_send, external_ab, proc_receive)
    1811              : 
    1812       217544 :             Y_i_aP(:, :) = Y_i_aP + external_ab
    1813              : 
    1814              :          ELSE ! Alpha-beta case
    1815              :             ! Alpha-alpha part
    1816              :             CALL mp2_env%local_gemm_ctx%gemm('N', 'T', send_B_size, dimen_RI, my_B_size(jspin), mp2_env%scale_S, &
    1817              :                                              local_ab(send_B_virtual_start:send_B_virtual_end, :), send_B_size, &
    1818         7770 :                                              my_local_j_aL, dimen_RI, 0.0_dp, send_ab, send_B_size)
    1819           70 :             CALL para_env_sub%sendrecv(send_ab, proc_send, external_ab, proc_receive)
    1820       161840 :             Y_i_aP(:, :) = Y_i_aP + external_ab
    1821              :          END IF
    1822              :       END DO
    1823              : 
    1824         1620 :       IF (alpha_beta) THEN
    1825              :          ! For beta-beta part (in alpha-beta case) we need a new parallel code
    1826          502 :          IF (para_env_sub%num_pe > 1) THEN
    1827           70 :             external_ab(1:my_B_size(jspin), 1:dimen_RI) => buffer_1D(1:INT(my_B_size(jspin), int_8)*dimen_RI)
    1828           70 :             external_ab = 0.0_dp
    1829              : 
    1830           70 :             offset = INT(my_B_size(jspin), int_8)*dimen_RI
    1831              :          END IF
    1832          572 :          DO proc_shift = 1, para_env_sub%num_pe - 1
    1833           70 :             proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    1834           70 :             proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    1835              : 
    1836           70 :             CALL get_group_dist(gd_B_virtual(jspin), proc_send, send_B_virtual_start, send_B_virtual_end, send_B_size)
    1837           70 :             send_ab(1:send_B_size, 1:dimen_RI) => buffer_1D(offset + 1:offset + INT(dimen_RI, int_8)*send_B_size)
    1838           70 :             send_ab = 0.0_dp
    1839              :             CALL mp2_env%local_gemm_ctx%gemm('N', 'T', send_B_size, dimen_RI, my_B_size(ispin), mp2_env%scale_S, &
    1840              :                                              local_ba(send_B_virtual_start:send_B_virtual_end, :), send_B_size, &
    1841         7700 :                                              my_local_i_aL, dimen_RI, 0.0_dp, send_ab, send_B_size)
    1842           70 :             CALL para_env_sub%sendrecv(send_ab, proc_send, external_ab, proc_receive)
    1843       177812 :             Y_j_aP(:, :) = Y_j_aP + external_ab
    1844              : 
    1845              :          END DO
    1846              : 
    1847              :          ! Here, we just use approximate bounds. For large systems virtual(ispin) is approx virtual(jspin), same for B_size
    1848          502 :          CALL dgemm_counter_stop(dgemm_counter, 3*virtual(ispin), dimen_RI, my_B_size(jspin))
    1849              :       ELSE
    1850         1118 :          CALL dgemm_counter_stop(dgemm_counter, virtual(ispin), dimen_RI, my_B_size(ispin))
    1851              :       END IF
    1852              : 
    1853         1620 :       IF ((my_i /= my_j) .AND. (.NOT. alpha_beta)) THEN
    1854              :          ! Alpha-alpha, beta-beta and closed shell
    1855          823 :          CALL dgemm_counter_start(dgemm_counter)
    1856              :          CALL mp2_env%local_gemm_ctx%gemm('T', 'T', my_B_size(ispin), dimen_RI, my_B_size(ispin), 1.0_dp, &
    1857              :                                           t_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), :), my_B_size(ispin), &
    1858         9843 :                                           my_local_i_aL, dimen_RI, 1.0_dp, Y_j_aP, my_B_size(ispin))
    1859          909 :          DO proc_shift = 1, para_env_sub%num_pe - 1
    1860           86 :             proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    1861           86 :             proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    1862              : 
    1863           86 :             CALL get_group_dist(gd_B_virtual(ispin), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    1864              : 
    1865           86 :             external_ab(1:dimen_RI, 1:rec_B_size) => buffer_1D(1:INT(dimen_RI, int_8)*rec_B_size)
    1866           86 :             external_ab = 0.0_dp
    1867              : 
    1868              :             CALL para_env_sub%sendrecv(my_local_i_aL, proc_send, &
    1869           86 :                                        external_ab, proc_receive)
    1870              : 
    1871              :             ! Alpha-alpha, beta-beta and closed shell
    1872              :             CALL mp2_env%local_gemm_ctx%gemm('T', 'T', my_B_size(ispin), dimen_RI, rec_B_size, 1.0_dp, &
    1873              :                                              t_ab(rec_B_virtual_start:rec_B_virtual_end, :), rec_B_size, &
    1874         9972 :                                              external_ab, dimen_RI, 1.0_dp, Y_j_aP, my_B_size(ispin))
    1875              :          END DO
    1876              : 
    1877          823 :          CALL dgemm_counter_stop(dgemm_counter, my_B_size(ispin), dimen_RI, virtual(ispin))
    1878              :       END IF
    1879              : 
    1880         1620 :       CALL timestop(handle)
    1881         1620 :    END SUBROUTINE mp2_update_P_gamma
    1882              : 
    1883              : ! **************************************************************************************************
    1884              : !> \brief ...
    1885              : !> \param Gamma_P_ia ...
    1886              : !> \param ij_index ...
    1887              : !> \param my_B_size ...
    1888              : !> \param my_block_size ...
    1889              : !> \param my_group_L_size ...
    1890              : !> \param my_i ...
    1891              : !> \param my_ij_pairs ...
    1892              : !> \param ngroup ...
    1893              : !> \param num_integ_group ...
    1894              : !> \param integ_group_pos2color_sub ...
    1895              : !> \param num_ij_pairs ...
    1896              : !> \param ij_map ...
    1897              : !> \param ranges_info_array ...
    1898              : !> \param Y_i_aP ...
    1899              : !> \param comm_exchange ...
    1900              : !> \param sizes_array ...
    1901              : !> \param spin ...
    1902              : !> \param buffer_1D ...
    1903              : ! **************************************************************************************************
    1904         3234 :    SUBROUTINE mp2_redistribute_gamma(Gamma_P_ia, ij_index, my_B_size, &
    1905              :                                      my_block_size, my_group_L_size, my_i, my_ij_pairs, ngroup, &
    1906              :                                      num_integ_group, integ_group_pos2color_sub, num_ij_pairs, &
    1907         3234 :                                      ij_map, ranges_info_array, Y_i_aP, comm_exchange, &
    1908         3234 :                                      sizes_array, spin, buffer_1D)
    1909              : 
    1910              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: Gamma_P_ia
    1911              :       INTEGER, INTENT(IN)                                :: ij_index, my_B_size, my_block_size, &
    1912              :                                                             my_group_L_size, my_i, my_ij_pairs, &
    1913              :                                                             ngroup, num_integ_group
    1914              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(IN)     :: integ_group_pos2color_sub, num_ij_pairs
    1915              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(IN)  :: ij_map
    1916              :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
    1917              :          INTENT(IN)                                      :: ranges_info_array
    1918              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Y_i_aP
    1919              :       TYPE(mp_comm_type), INTENT(IN)                     :: comm_exchange
    1920              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(IN)     :: sizes_array
    1921              :       INTEGER, INTENT(IN)                                :: spin
    1922              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:), TARGET    :: buffer_1D
    1923              : 
    1924              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'mp2_redistribute_gamma'
    1925              : 
    1926              :       INTEGER :: end_point, handle, handle2, iiB, ij_counter_rec, irep, kkk, lll, Lstart_pos, &
    1927              :          proc_receive, proc_send, proc_shift, rec_i, rec_ij_index, send_L_size, start_point, tag
    1928              :       INTEGER(KIND=int_8)                                :: offset
    1929              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :, :), &
    1930         3234 :          POINTER                                         :: BI_C_rec, BI_C_send
    1931              : 
    1932              : ! In alpha-beta case Y_i_aP_beta is sent as Y_j_aP
    1933              : 
    1934         3234 :       CALL timeset(routineN//"_comm2", handle)
    1935              : 
    1936         3234 :       tag = 43
    1937              : 
    1938         3234 :       IF (ij_index <= my_ij_pairs) THEN
    1939              :          ! somethig to send
    1940              :          ! start with myself
    1941         3216 :          CALL timeset(routineN//"_comm2_w", handle2)
    1942         9230 :          DO irep = 0, num_integ_group - 1
    1943         6014 :             Lstart_pos = ranges_info_array(1, irep, comm_exchange%mepos)
    1944         6014 :             start_point = ranges_info_array(3, irep, comm_exchange%mepos)
    1945         6014 :             end_point = ranges_info_array(4, irep, comm_exchange%mepos)
    1946              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1947              : !$OMP             PRIVATE(kkk,lll,iiB) &
    1948              : !$OMP             SHARED(start_point,end_point,Lstart_pos,my_block_size,&
    1949         9230 : !$OMP                    Gamma_P_ia,my_i,my_B_size,Y_i_aP)
    1950              :             DO kkk = start_point, end_point
    1951              :                lll = kkk - start_point + Lstart_pos
    1952              :                DO iiB = 1, my_block_size
    1953              :                   Gamma_P_ia(1:my_B_size, my_i + iiB - 1, kkk) = &
    1954              :                      Gamma_P_ia(1:my_B_size, my_i + iiB - 1, kkk) + &
    1955              :                      Y_i_aP(1:my_B_size, lll, iiB)
    1956              :                END DO
    1957              :             END DO
    1958              : !$OMP END PARALLEL DO
    1959              :          END DO
    1960         3216 :          CALL timestop(handle2)
    1961              : 
    1962              :          ! Y_i_aP(my_B_size,dimen_RI,block_size)
    1963              : 
    1964         3314 :          DO proc_shift = 1, comm_exchange%num_pe - 1
    1965           98 :             proc_send = MODULO(comm_exchange%mepos + proc_shift, comm_exchange%num_pe)
    1966           98 :             proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
    1967              : 
    1968           98 :             send_L_size = sizes_array(proc_send)
    1969              :             BI_C_send(1:my_B_size, 1:my_block_size, 1:send_L_size) => &
    1970           98 :                buffer_1D(1:INT(my_B_size, int_8)*my_block_size*send_L_size)
    1971              : 
    1972           98 :             offset = INT(my_B_size, int_8)*my_block_size*send_L_size
    1973              : 
    1974           98 :             CALL timeset(routineN//"_comm2_w", handle2)
    1975           98 :             BI_C_send = 0.0_dp
    1976          196 :             DO irep = 0, num_integ_group - 1
    1977           98 :                Lstart_pos = ranges_info_array(1, irep, proc_send)
    1978           98 :                start_point = ranges_info_array(3, irep, proc_send)
    1979           98 :                end_point = ranges_info_array(4, irep, proc_send)
    1980              : !$OMP PARALLEL DO DEFAULT(NONE) &
    1981              : !$OMP             PRIVATE(kkk,lll,iiB) &
    1982              : !$OMP             SHARED(start_point,end_point,Lstart_pos,my_block_size,&
    1983          196 : !$OMP                    BI_C_send,my_B_size,Y_i_aP)
    1984              :                DO kkk = start_point, end_point
    1985              :                   lll = kkk - start_point + Lstart_pos
    1986              :                   DO iiB = 1, my_block_size
    1987              :                      BI_C_send(1:my_B_size, iiB, kkk) = Y_i_aP(1:my_B_size, lll, iiB)
    1988              :                   END DO
    1989              :                END DO
    1990              : !$OMP END PARALLEL DO
    1991              :             END DO
    1992           98 :             CALL timestop(handle2)
    1993              : 
    1994           98 :             rec_ij_index = num_ij_pairs(proc_receive)
    1995              : 
    1996         3412 :             IF (ij_index <= rec_ij_index) THEN
    1997              :                ! we know that proc_receive has something to send for us, let's see what
    1998              :                ij_counter_rec = &
    1999           80 :                   (ij_index - MIN(1, integ_group_pos2color_sub(proc_receive)))*ngroup + integ_group_pos2color_sub(proc_receive)
    2000              : 
    2001           80 :                rec_i = ij_map(spin, ij_counter_rec)
    2002              : 
    2003              :                BI_C_rec(1:my_B_size, 1:my_block_size, 1:my_group_L_size) => &
    2004           80 :                   buffer_1D(offset + 1:offset + INT(my_B_size, int_8)*my_block_size*my_group_L_size)
    2005           80 :                BI_C_rec = 0.0_dp
    2006              : 
    2007              :                CALL comm_exchange%sendrecv(BI_C_send, proc_send, &
    2008           80 :                                            BI_C_rec, proc_receive, tag)
    2009              : 
    2010           80 :                CALL timeset(routineN//"_comm2_w", handle2)
    2011          160 :                DO irep = 0, num_integ_group - 1
    2012           80 :                   start_point = ranges_info_array(3, irep, comm_exchange%mepos)
    2013           80 :                   end_point = ranges_info_array(4, irep, comm_exchange%mepos)
    2014              : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
    2015              : !$OMP                    SHARED(start_point,end_point,my_block_size,&
    2016          160 : !$OMP                           Gamma_P_ia,rec_i,iiB,my_B_size,BI_C_rec)
    2017              :                   Gamma_P_ia(:, rec_i:rec_i + my_block_size - 1, start_point:end_point) = &
    2018              :                      Gamma_P_ia(:, rec_i:rec_i + my_block_size - 1, start_point:end_point) + &
    2019              :                      BI_C_rec(1:my_B_size, :, start_point:end_point)
    2020              : !$OMP END PARALLEL WORKSHARE
    2021              :                END DO
    2022           80 :                CALL timestop(handle2)
    2023              : 
    2024              :             ELSE
    2025              :                ! we have something to send but nothing to receive
    2026           18 :                CALL comm_exchange%send(BI_C_send, proc_send, tag)
    2027              : 
    2028              :             END IF
    2029              : 
    2030              :          END DO
    2031              : 
    2032              :       ELSE
    2033              :          ! noting to send check if we have to receive
    2034           36 :          DO proc_shift = 1, comm_exchange%num_pe - 1
    2035           18 :             proc_send = MODULO(comm_exchange%mepos + proc_shift, comm_exchange%num_pe)
    2036           18 :             proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
    2037           18 :             rec_ij_index = num_ij_pairs(proc_receive)
    2038              : 
    2039           36 :             IF (ij_index <= rec_ij_index) THEN
    2040              :                ! we know that proc_receive has something to send for us, let's see what
    2041              :                ij_counter_rec = &
    2042           18 :                   (ij_index - MIN(1, integ_group_pos2color_sub(proc_receive)))*ngroup + integ_group_pos2color_sub(proc_receive)
    2043              : 
    2044           18 :                rec_i = ij_map(spin, ij_counter_rec)
    2045              : 
    2046              :                BI_C_rec(1:my_B_size, 1:my_block_size, 1:my_group_L_size) => &
    2047           18 :                   buffer_1D(1:INT(my_B_size, int_8)*my_block_size*my_group_L_size)
    2048              : 
    2049           18 :                BI_C_rec = 0.0_dp
    2050              : 
    2051           18 :                CALL comm_exchange%recv(BI_C_rec, proc_receive, tag)
    2052              : 
    2053           18 :                CALL timeset(routineN//"_comm2_w", handle2)
    2054           36 :                DO irep = 0, num_integ_group - 1
    2055           18 :                   start_point = ranges_info_array(3, irep, comm_exchange%mepos)
    2056           18 :                   end_point = ranges_info_array(4, irep, comm_exchange%mepos)
    2057              : #if !defined(__INTEL_LLVM_COMPILER) || (20250000 <= __INTEL_LLVM_COMPILER)
    2058              : !$OMP PARALLEL WORKSHARE DEFAULT(NONE) &
    2059              : !$OMP                    SHARED(start_point,end_point,my_block_size,&
    2060           36 : !$OMP                           Gamma_P_ia,rec_i,my_B_size,BI_C_rec)
    2061              : #endif
    2062              :                   Gamma_P_ia(:, rec_i:rec_i + my_block_size - 1, start_point:end_point) = &
    2063              :                      Gamma_P_ia(:, rec_i:rec_i + my_block_size - 1, start_point:end_point) + &
    2064              :                      BI_C_rec(1:my_B_size, :, start_point:end_point)
    2065              : #if !defined(__INTEL_LLVM_COMPILER) || (20250000 <= __INTEL_LLVM_COMPILER)
    2066              : !$OMP END PARALLEL WORKSHARE
    2067              : #endif
    2068              :                END DO
    2069           18 :                CALL timestop(handle2)
    2070              : 
    2071              :             END IF
    2072              :          END DO
    2073              : 
    2074              :       END IF
    2075         3234 :       CALL timestop(handle)
    2076              : 
    2077         3234 :    END SUBROUTINE mp2_redistribute_gamma
    2078              : 
    2079              : ! **************************************************************************************************
    2080              : !> \brief ...
    2081              : !> \param mp2_env ...
    2082              : !> \param Eigenval ...
    2083              : !> \param homo ...
    2084              : !> \param virtual ...
    2085              : !> \param open_shell ...
    2086              : !> \param beta_beta ...
    2087              : !> \param Bib_C ...
    2088              : !> \param unit_nr ...
    2089              : !> \param dimen_RI ...
    2090              : !> \param my_B_size ...
    2091              : !> \param ngroup ...
    2092              : !> \param my_group_L_size ...
    2093              : !> \param color_sub ...
    2094              : !> \param ranges_info_array ...
    2095              : !> \param comm_exchange ...
    2096              : !> \param para_env_sub ...
    2097              : !> \param para_env ...
    2098              : !> \param my_B_virtual_start ...
    2099              : !> \param my_B_virtual_end ...
    2100              : !> \param sizes_array ...
    2101              : !> \param gd_B_virtual ...
    2102              : !> \param integ_group_pos2color_sub ...
    2103              : !> \param dgemm_counter ...
    2104              : !> \param buffer_1D ...
    2105              : ! **************************************************************************************************
    2106          384 :    SUBROUTINE quasi_degenerate_P_ij(mp2_env, Eigenval, homo, virtual, open_shell, &
    2107          384 :                                     beta_beta, Bib_C, unit_nr, dimen_RI, &
    2108          384 :                                     my_B_size, ngroup, my_group_L_size, &
    2109              :                                     color_sub, ranges_info_array, comm_exchange, para_env_sub, para_env, &
    2110          384 :                                     my_B_virtual_start, my_B_virtual_end, sizes_array, gd_B_virtual, &
    2111          384 :                                     integ_group_pos2color_sub, dgemm_counter, buffer_1D)
    2112              :       TYPE(mp2_type)                                     :: mp2_env
    2113              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: Eigenval
    2114              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
    2115              :       LOGICAL, INTENT(IN)                                :: open_shell, beta_beta
    2116              :       TYPE(three_dim_real_array), DIMENSION(:), &
    2117              :          INTENT(IN)                                      :: BIb_C
    2118              :       INTEGER, INTENT(IN)                                :: unit_nr, dimen_RI
    2119              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: my_B_size
    2120              :       INTEGER, INTENT(IN)                                :: ngroup, my_group_L_size, color_sub
    2121              :       INTEGER, ALLOCATABLE, DIMENSION(:, :, :), &
    2122              :          INTENT(IN)                                      :: ranges_info_array
    2123              :       TYPE(mp_comm_type), INTENT(IN)                     :: comm_exchange
    2124              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env_sub, para_env
    2125              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: my_B_virtual_start, my_B_virtual_end
    2126              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(IN)     :: sizes_array
    2127              :       TYPE(group_dist_d1_type), DIMENSION(:), INTENT(IN) :: gd_B_virtual
    2128              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(IN)     :: integ_group_pos2color_sub
    2129              :       TYPE(dgemm_counter_type), INTENT(INOUT)            :: dgemm_counter
    2130              :       REAL(KIND=dp), CONTIGUOUS, DIMENSION(:), TARGET    :: buffer_1D
    2131              : 
    2132              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'quasi_degenerate_P_ij'
    2133              : 
    2134              :       INTEGER :: a, a_global, b, b_global, block_size, decil, handle, handle2, ijk_counter, &
    2135              :          ijk_counter_send, ijk_index, ispin, kkB, kspin, max_block_size, max_ijk, my_i, my_ijk, &
    2136              :          my_j, my_k, my_last_k(2), my_virtual, nspins, proc_receive, proc_send, proc_shift, &
    2137              :          rec_B_size, rec_B_virtual_end, rec_B_virtual_start, rec_L_size, send_B_size, &
    2138              :          send_B_virtual_end, send_B_virtual_start, send_i, send_ijk_index, send_j, send_k, &
    2139              :          size_B_i, size_B_k, tag, tag2
    2140          384 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: num_ijk
    2141          384 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: ijk_map, send_last_k
    2142              :       LOGICAL                                            :: alpha_beta, do_recv_i, do_recv_j, &
    2143              :                                                             do_recv_k, do_send_i, do_send_j, &
    2144              :                                                             do_send_k
    2145              :       REAL(KIND=dp)                                      :: amp_fac, P_ij_elem, t_new, t_start
    2146              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
    2147          384 :          TARGET                                          :: local_ab, local_aL_i, local_aL_j, t_ab
    2148          384 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: local_aL_k
    2149          384 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: BI_C_rec, external_ab, external_aL
    2150          384 :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: BI_C_rec_3D
    2151              : 
    2152          384 :       CALL timeset(routineN//"_ij_sing", handle)
    2153              : 
    2154          384 :       tag = 44
    2155          384 :       tag2 = 45
    2156              : 
    2157          384 :       nspins = SIZE(BIb_C)
    2158          384 :       alpha_beta = (nspins == 2)
    2159              : 
    2160              :       ! Set amplitude factor
    2161          384 :       amp_fac = mp2_env%scale_S + mp2_env%scale_T
    2162          384 :       IF (open_shell) amp_fac = mp2_env%scale_T
    2163              : 
    2164          794 :       ALLOCATE (send_last_k(2, comm_exchange%num_pe - 1))
    2165              : 
    2166              :       ! Loop(s) over orbital triplets
    2167          846 :       DO ispin = 1, nspins
    2168          462 :          size_B_i = my_B_size(ispin)
    2169          462 :          IF (ispin == 1 .AND. alpha_beta) THEN
    2170              :             kspin = 2
    2171              :          ELSE
    2172          384 :             kspin = 1
    2173              :          END IF
    2174          462 :          size_B_k = my_B_size(kspin)
    2175              : 
    2176              :          ! Find the number of quasi-degenerate orbitals and orbital triplets
    2177              : 
    2178              :          CALL Find_quasi_degenerate_ij(my_ijk, homo(ispin), homo(kspin), Eigenval(:, ispin), mp2_env, ijk_map, unit_nr, ngroup, &
    2179              :                                        .NOT. beta_beta .AND. ispin /= 2, comm_exchange, num_ijk, max_ijk, color_sub, &
    2180          618 :                                        SIZE(buffer_1D), my_group_L_size, size_B_k, para_env, virtual(ispin), size_B_i)
    2181              : 
    2182          462 :          my_virtual = virtual(ispin)
    2183          462 :          IF (SIZE(ijk_map, 2) > 0) THEN
    2184           98 :             max_block_size = ijk_map(4, 1)
    2185              :          ELSE
    2186              :             max_block_size = 1
    2187              :          END IF
    2188              : 
    2189         1848 :          ALLOCATE (local_aL_i(dimen_RI, size_B_i))
    2190         1386 :          ALLOCATE (local_aL_j(dimen_RI, size_B_i))
    2191         2310 :          ALLOCATE (local_aL_k(dimen_RI, size_B_k, max_block_size))
    2192         1848 :          ALLOCATE (t_ab(my_virtual, size_B_k))
    2193              : 
    2194         1386 :          my_last_k = -1
    2195          552 :          send_last_k = -1
    2196              : 
    2197          462 :          t_start = m_walltime()
    2198          618 :          DO ijk_index = 1, max_ijk
    2199              : 
    2200              :             ! Prediction is unreliable if we are in the first step of the loop
    2201          156 :             IF (unit_nr > 0 .AND. ijk_index > 1) THEN
    2202           18 :                decil = ijk_index*10/max_ijk
    2203           18 :                IF (decil /= (ijk_index - 1)*10/max_ijk) THEN
    2204           18 :                   t_new = m_walltime()
    2205           18 :                   t_new = (t_new - t_start)/60.0_dp*(max_ijk - ijk_index + 1)/(ijk_index - 1)
    2206              :                   WRITE (unit_nr, FMT="(T3,A)") "Percentage of finished loop: "// &
    2207           18 :                      cp_to_string(decil*10)//". Minutes left: "//cp_to_string(t_new)
    2208           18 :                   CALL m_flush(unit_nr)
    2209              :                END IF
    2210              :             END IF
    2211              : 
    2212          618 :             IF (ijk_index <= my_ijk) THEN
    2213              :                ! work to be done
    2214          154 :                ijk_counter = (ijk_index - MIN(1, color_sub))*ngroup + color_sub
    2215          154 :                my_i = ijk_map(1, ijk_counter)
    2216          154 :                my_j = ijk_map(2, ijk_counter)
    2217          154 :                my_k = ijk_map(3, ijk_counter)
    2218          154 :                block_size = ijk_map(4, ijk_counter)
    2219              : 
    2220          154 :                do_recv_i = (ispin /= kspin) .OR. my_i < my_k .OR. my_i > my_k + block_size - 1
    2221          154 :                do_recv_j = (ispin /= kspin) .OR. my_j < my_k .OR. my_j > my_k + block_size - 1
    2222          154 :                do_recv_k = my_k /= my_last_k(1) .OR. my_k + block_size - 1 /= my_last_k(2)
    2223          154 :                my_last_k(1) = my_k
    2224          154 :                my_last_k(2) = my_k + block_size - 1
    2225              : 
    2226          154 :                local_aL_i = 0.0_dp
    2227          154 :                IF (do_recv_i) THEN
    2228              :                   CALL fill_local_i_aL_2D(local_al_i, ranges_info_array(:, :, comm_exchange%mepos), &
    2229          125 :                                           BIb_C(ispin)%array(:, :, my_i))
    2230              :                END IF
    2231              : 
    2232          154 :                local_aL_j = 0.0_dp
    2233          154 :                IF (do_recv_j) THEN
    2234              :                   CALL fill_local_i_aL_2D(local_al_j, ranges_info_array(:, :, comm_exchange%mepos), &
    2235          125 :                                           BIb_C(ispin)%array(:, :, my_j))
    2236              :                END IF
    2237              : 
    2238          154 :                IF (do_recv_k) THEN
    2239          146 :                   local_aL_k = 0.0_dp
    2240              :                   CALL fill_local_i_aL(local_aL_k(:, :, 1:block_size), ranges_info_array(:, :, comm_exchange%mepos), &
    2241          146 :                                        BIb_C(kspin)%array(:, :, my_k:my_k + block_size - 1))
    2242              :                END IF
    2243              : 
    2244          154 :                CALL timeset(routineN//"_comm", handle2)
    2245          164 :                DO proc_shift = 1, comm_exchange%num_pe - 1
    2246           10 :                   proc_send = MODULO(comm_exchange%mepos + proc_shift, comm_exchange%num_pe)
    2247           10 :                   proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
    2248              : 
    2249           10 :                   send_ijk_index = num_ijk(proc_send)
    2250              : 
    2251           10 :                   rec_L_size = sizes_array(proc_receive)
    2252           10 :                   BI_C_rec(1:rec_L_size, 1:size_B_i) => buffer_1D(1:INT(rec_L_size, KIND=int_8)*size_B_i)
    2253              : 
    2254           10 :                   do_send_i = .FALSE.
    2255           10 :                   do_send_j = .FALSE.
    2256           10 :                   do_send_k = .FALSE.
    2257           10 :                   IF (ijk_index <= send_ijk_index) THEN
    2258              :                      ! something to send
    2259              :                      ijk_counter_send = (ijk_index - MIN(1, integ_group_pos2color_sub(proc_send)))* &
    2260            8 :                                         ngroup + integ_group_pos2color_sub(proc_send)
    2261            8 :                      send_i = ijk_map(1, ijk_counter_send)
    2262            8 :                      send_j = ijk_map(2, ijk_counter_send)
    2263            8 :                      send_k = ijk_map(3, ijk_counter_send)
    2264              : 
    2265            8 :                      do_send_i = (ispin /= kspin) .OR. send_i < send_k .OR. send_i > send_k + block_size - 1
    2266            8 :                      do_send_j = (ispin /= kspin) .OR. send_j < send_k .OR. send_j > send_k + block_size - 1
    2267            8 :                      do_send_k = send_k /= send_last_k(1, proc_shift) .OR. send_k + block_size - 1 /= send_last_k(2, proc_shift)
    2268            8 :                      send_last_k(1, proc_shift) = send_k
    2269            8 :                      send_last_k(2, proc_shift) = send_k + block_size - 1
    2270              :                   END IF
    2271              : 
    2272              :                   ! occupied i
    2273          722 :                   BI_C_rec = 0.0_dp
    2274           10 :                   IF (do_send_i) THEN
    2275            6 :                   IF (do_recv_i) THEN
    2276              :                      CALL comm_exchange%sendrecv(BIb_C(ispin)%array(:, :, send_i), proc_send, &
    2277          288 :                                                  BI_C_rec, proc_receive, tag)
    2278              :                   ELSE
    2279            2 :                      CALL comm_exchange%send(BIb_C(ispin)%array(:, :, send_i), proc_send, tag)
    2280              :                   END IF
    2281            4 :                   ELSE IF (do_recv_i) THEN
    2282          580 :                   CALL comm_exchange%recv(BI_C_rec, proc_receive, tag)
    2283              :                   END IF
    2284           10 :                   IF (do_recv_i) THEN
    2285            8 :                      CALL fill_local_i_aL_2D(local_al_i, ranges_info_array(:, :, proc_receive), BI_C_rec)
    2286              :                   END IF
    2287              : 
    2288              :                   ! occupied j
    2289          722 :                   BI_C_rec = 0.0_dp
    2290           10 :                   IF (do_send_j) THEN
    2291            8 :                   IF (do_recv_j) THEN
    2292              :                      CALL comm_exchange%sendrecv(BIb_C(ispin)%array(:, :, send_j), proc_send, &
    2293          576 :                                                  BI_C_rec, proc_receive, tag)
    2294              :                   ELSE
    2295            0 :                      CALL comm_exchange%send(BIb_C(ispin)%array(:, :, send_j), proc_send, tag)
    2296              :                   END IF
    2297            2 :                   ELSE IF (do_recv_j) THEN
    2298            0 :                   CALL comm_exchange%recv(BI_C_rec, proc_receive, tag)
    2299              :                   END IF
    2300            8 :                   IF (do_recv_j) THEN
    2301            8 :                      CALL fill_local_i_aL_2D(local_al_j, ranges_info_array(:, :, proc_receive), BI_C_rec)
    2302              :                   END IF
    2303              : 
    2304              :                   ! occupied k
    2305              :                   BI_C_rec_3D(1:rec_L_size, 1:size_B_k, 1:block_size) => &
    2306           10 :                      buffer_1D(1:INT(rec_L_size, KIND=int_8)*size_B_k*block_size)
    2307           10 :                   IF (do_send_k) THEN
    2308            8 :                   IF (do_recv_k) THEN
    2309              :                      CALL comm_exchange%sendrecv(BIb_C(kspin)%array(:, :, send_k:send_k + block_size - 1), proc_send, &
    2310          726 :                                                  BI_C_rec_3D, proc_receive, tag)
    2311              :                   ELSE
    2312            0 :                      CALL comm_exchange%send(BI_C_rec, proc_receive, tag)
    2313              :                   END IF
    2314            2 :                   ELSE IF (do_recv_k) THEN
    2315          294 :                   CALL comm_exchange%recv(BI_C_rec_3D, proc_receive, tag)
    2316              :                   END IF
    2317          164 :                   IF (do_recv_k) THEN
    2318           10 :                      CALL fill_local_i_aL(local_al_k(:, :, 1:block_size), ranges_info_array(:, :, proc_receive), BI_C_rec_3D)
    2319              :                   END IF
    2320              :                END DO
    2321              : 
    2322        20868 :                IF (.NOT. do_recv_i) local_aL_i(:, :) = local_aL_k(:, :, my_i - my_k + 1)
    2323        20868 :                IF (.NOT. do_recv_j) local_aL_j(:, :) = local_aL_k(:, :, my_j - my_k + 1)
    2324          154 :                CALL timestop(handle2)
    2325              : 
    2326              :                ! expand integrals
    2327          376 :                DO kkB = 1, block_size
    2328          222 :                   CALL timeset(routineN//"_exp_ik", handle2)
    2329          222 :                   CALL dgemm_counter_start(dgemm_counter)
    2330          888 :                   ALLOCATE (local_ab(my_virtual, size_B_k))
    2331          222 :                   local_ab = 0.0_dp
    2332              :                   CALL mp2_env%local_gemm_ctx%gemm('T', 'N', size_B_i, size_B_k, dimen_RI, 1.0_dp, &
    2333              :                                                    local_aL_i, dimen_RI, local_aL_k(:, :, kkB), dimen_RI, &
    2334          222 :                                           0.0_dp, local_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), 1:size_B_k), size_B_i)
    2335          222 :                   DO proc_shift = 1, para_env_sub%num_pe - 1
    2336            0 :                      proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    2337            0 :                      proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    2338              : 
    2339            0 :                      CALL get_group_dist(gd_B_virtual(ispin), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    2340              : 
    2341            0 :                      external_aL(1:dimen_RI, 1:rec_B_size) => buffer_1D(1:INT(dimen_RI, KIND=int_8)*rec_B_size)
    2342              : 
    2343              :                      CALL comm_exchange%sendrecv(local_aL_i, proc_send, &
    2344            0 :                                                  external_aL, proc_receive, tag)
    2345              : 
    2346              :                      CALL mp2_env%local_gemm_ctx%gemm('T', 'N', rec_B_size, size_B_k, dimen_RI, 1.0_dp, &
    2347              :                                                       external_aL, dimen_RI, local_aL_k(:, :, kkB), dimen_RI, &
    2348          222 :                                                     0.0_dp, local_ab(rec_B_virtual_start:rec_B_virtual_end, 1:size_B_k), rec_B_size)
    2349              :                   END DO
    2350          222 :                   CALL dgemm_counter_stop(dgemm_counter, my_virtual, size_B_k, dimen_RI)
    2351          222 :                   CALL timestop(handle2)
    2352              : 
    2353              :                   ! Amplitudes
    2354          222 :                   CALL timeset(routineN//"_tab", handle2)
    2355          222 :                   t_ab = 0.0_dp
    2356              :                   ! Alpha-alpha, beta-beta and closed shell
    2357          222 :                   IF (.NOT. alpha_beta) THEN
    2358         1156 :                      DO b = 1, size_B_k
    2359         1038 :                         b_global = b + my_B_virtual_start(1) - 1
    2360        17250 :                         DO a = 1, my_B_size(1)
    2361        16094 :                            a_global = a + my_B_virtual_start(1) - 1
    2362              :                            t_ab(a_global, b) = (amp_fac*local_ab(a_global, b) - mp2_env%scale_T*local_ab(b_global, a))/ &
    2363              :                                                (Eigenval(my_i, 1) + Eigenval(my_k + kkB - 1, 1) &
    2364        17132 :                                                 - Eigenval(homo(1) + a_global, 1) - Eigenval(homo(1) + b_global, 1))
    2365              :                         END DO
    2366              :                      END DO
    2367              :                   ELSE
    2368         1030 :                      DO b = 1, size_B_k
    2369          926 :                         b_global = b + my_B_virtual_start(kspin) - 1
    2370        15388 :                         DO a = 1, my_B_size(ispin)
    2371        14358 :                            a_global = a + my_B_virtual_start(ispin) - 1
    2372              :                            t_ab(a_global, b) = mp2_env%scale_S*local_ab(a_global, b)/ &
    2373              :                                                (Eigenval(my_i, ispin) + Eigenval(my_k + kkB - 1, kspin) &
    2374        15284 :                                                 - Eigenval(homo(ispin) + a_global, ispin) - Eigenval(homo(kspin) + b_global, kspin))
    2375              :                         END DO
    2376              :                      END DO
    2377              :                   END IF
    2378              : 
    2379          222 :                   IF (.NOT. alpha_beta) THEN
    2380          118 :                      DO proc_shift = 1, para_env_sub%num_pe - 1
    2381            0 :                         proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    2382            0 :                         proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    2383            0 :                         CALL get_group_dist(gd_B_virtual(1), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    2384            0 :                         CALL get_group_dist(gd_B_virtual(1), proc_send, send_B_virtual_start, send_B_virtual_end, send_B_size)
    2385              : 
    2386            0 :                         external_ab(1:size_B_i, 1:rec_B_size) => buffer_1D(1:INT(size_B_i, KIND=int_8)*rec_B_size)
    2387              :                         CALL para_env_sub%sendrecv(local_ab(send_B_virtual_start:send_B_virtual_end, 1:size_B_k), proc_send, &
    2388            0 :                                                    external_ab(1:size_B_i, 1:rec_B_size), proc_receive, tag)
    2389              : 
    2390          118 :                         DO b = 1, my_B_size(1)
    2391            0 :                            b_global = b + my_B_virtual_start(1) - 1
    2392            0 :                            DO a = 1, rec_B_size
    2393            0 :                               a_global = a + rec_B_virtual_start - 1
    2394              :                               t_ab(a_global, b) = (amp_fac*local_ab(a_global, b) - mp2_env%scale_T*external_ab(b, a))/ &
    2395              :                                                   (Eigenval(my_i, 1) + Eigenval(my_k + kkB - 1, 1) &
    2396            0 :                                                    - Eigenval(homo(1) + a_global, 1) - Eigenval(homo(1) + b_global, 1))
    2397              :                            END DO
    2398              :                         END DO
    2399              :                      END DO
    2400              :                   END IF
    2401          222 :                   CALL timestop(handle2)
    2402              : 
    2403              :                   ! Expand the second set of integrals
    2404          222 :                   CALL timeset(routineN//"_exp_jk", handle2)
    2405          222 :                   local_ab = 0.0_dp
    2406          222 :                   CALL dgemm_counter_start(dgemm_counter)
    2407              :                   CALL mp2_env%local_gemm_ctx%gemm('T', 'N', size_B_i, size_B_k, dimen_RI, 1.0_dp, &
    2408              :                                                    local_aL_j, dimen_RI, local_aL_k(:, :, kkB), dimen_RI, &
    2409          222 :                                           0.0_dp, local_ab(my_B_virtual_start(ispin):my_B_virtual_end(ispin), 1:size_B_k), size_B_i)
    2410          222 :                   DO proc_shift = 1, para_env_sub%num_pe - 1
    2411            0 :                      proc_send = MODULO(para_env_sub%mepos + proc_shift, para_env_sub%num_pe)
    2412            0 :                      proc_receive = MODULO(para_env_sub%mepos - proc_shift, para_env_sub%num_pe)
    2413              : 
    2414            0 :                      CALL get_group_dist(gd_B_virtual(ispin), proc_receive, rec_B_virtual_start, rec_B_virtual_end, rec_B_size)
    2415              : 
    2416            0 :                      external_aL(1:dimen_RI, 1:rec_B_size) => buffer_1D(1:INT(dimen_RI, KIND=int_8)*rec_B_size)
    2417              : 
    2418              :                      CALL comm_exchange%sendrecv(local_aL_j, proc_send, &
    2419            0 :                                                  external_aL, proc_receive, tag)
    2420              :                      CALL mp2_env%local_gemm_ctx%gemm('T', 'N', rec_B_size, size_B_k, dimen_RI, 1.0_dp, &
    2421              :                                                       external_aL, dimen_RI, local_aL_k(:, :, kkB), dimen_RI, &
    2422          222 :                                                     0.0_dp, local_ab(rec_B_virtual_start:rec_B_virtual_end, 1:size_B_k), rec_B_size)
    2423              :                   END DO
    2424          222 :                   CALL dgemm_counter_stop(dgemm_counter, my_virtual, size_B_k, dimen_RI)
    2425          222 :                   CALL timestop(handle2)
    2426              : 
    2427          222 :                   CALL timeset(routineN//"_Pij", handle2)
    2428         2186 :                   DO b = 1, size_B_k
    2429         1964 :                      b_global = b + my_B_virtual_start(kspin) - 1
    2430        32638 :                      DO a = 1, my_B_size(ispin)
    2431        30452 :                         a_global = a + my_B_virtual_start(ispin) - 1
    2432              :                         local_ab(a_global, b) = &
    2433              :                            local_ab(a_global, b)/(Eigenval(my_j, ispin) + Eigenval(my_k + kkB - 1, kspin) &
    2434        32416 :                                                 - Eigenval(homo(ispin) + a_global, ispin) - Eigenval(homo(kspin) + b_global, kspin))
    2435              :                      END DO
    2436              :                   END DO
    2437              :                   !
    2438        32638 :                   P_ij_elem = SUM(local_ab*t_ab)
    2439          222 :                   DEALLOCATE (local_ab)
    2440          222 :                   IF ((.NOT. open_shell) .AND. (.NOT. alpha_beta)) THEN
    2441            4 :                      P_ij_elem = P_ij_elem*2.0_dp
    2442              :                   END IF
    2443          222 :                   IF (beta_beta) THEN
    2444           34 :                      mp2_env%ri_grad%P_ij(2)%array(my_i, my_j) = mp2_env%ri_grad%P_ij(2)%array(my_i, my_j) - P_ij_elem
    2445           34 :                      mp2_env%ri_grad%P_ij(2)%array(my_j, my_i) = mp2_env%ri_grad%P_ij(2)%array(my_j, my_i) - P_ij_elem
    2446              :                   ELSE
    2447          188 :                      mp2_env%ri_grad%P_ij(ispin)%array(my_i, my_j) = mp2_env%ri_grad%P_ij(ispin)%array(my_i, my_j) - P_ij_elem
    2448          188 :                      mp2_env%ri_grad%P_ij(ispin)%array(my_j, my_i) = mp2_env%ri_grad%P_ij(ispin)%array(my_j, my_i) - P_ij_elem
    2449              :                   END IF
    2450         1264 :                   CALL timestop(handle2)
    2451              :                END DO
    2452              :             ELSE
    2453            2 :                CALL timeset(routineN//"_comm", handle2)
    2454              :                ! no work to be done, possible messeges to be exchanged
    2455            4 :                DO proc_shift = 1, comm_exchange%num_pe - 1
    2456            2 :                   proc_send = MODULO(comm_exchange%mepos + proc_shift, comm_exchange%num_pe)
    2457            2 :                   proc_receive = MODULO(comm_exchange%mepos - proc_shift, comm_exchange%num_pe)
    2458              : 
    2459            2 :                   send_ijk_index = num_ijk(proc_send)
    2460              : 
    2461            4 :                   IF (ijk_index <= send_ijk_index) THEN
    2462              :                      ! somethig to send
    2463              :                      ijk_counter_send = (ijk_index - MIN(1, integ_group_pos2color_sub(proc_send)))*ngroup + &
    2464            2 :                                         integ_group_pos2color_sub(proc_send)
    2465            2 :                      send_i = ijk_map(1, ijk_counter_send)
    2466            2 :                      send_j = ijk_map(2, ijk_counter_send)
    2467            2 :                      send_k = ijk_map(3, ijk_counter_send)
    2468            2 :                      block_size = ijk_map(4, ijk_counter_send)
    2469              : 
    2470            2 :                      do_send_i = (ispin /= kspin) .OR. send_i < send_k .OR. send_i > send_k + block_size - 1
    2471            2 :                      do_send_j = (ispin /= kspin) .OR. send_j < send_k .OR. send_j > send_k + block_size - 1
    2472              :                      ! occupied i
    2473            2 :                      IF (do_send_i) THEN
    2474            2 :                         CALL comm_exchange%send(BIb_C(ispin)%array(:, :, send_i), proc_send, tag)
    2475              :                      END IF
    2476              :                      ! occupied j
    2477            2 :                      IF (do_send_j) THEN
    2478            0 :                         CALL comm_exchange%send(BIb_C(ispin)%array(:, :, send_j), proc_send, tag)
    2479              :                      END IF
    2480              :                      ! occupied k
    2481            2 :                      CALL comm_exchange%send(BIb_C(kspin)%array(:, :, send_k:send_k + block_size - 1), proc_send, tag)
    2482              :                   END IF
    2483              : 
    2484              :                END DO ! proc loop
    2485            2 :                CALL timestop(handle2)
    2486              :             END IF
    2487              :          END DO ! ijk_index loop
    2488          462 :          DEALLOCATE (local_aL_i)
    2489          462 :          DEALLOCATE (local_aL_j)
    2490          462 :          DEALLOCATE (local_aL_k)
    2491          462 :          DEALLOCATE (t_ab)
    2492          846 :          DEALLOCATE (ijk_map)
    2493              :       END DO ! over number of loops (ispin)
    2494          384 :       CALL timestop(handle)
    2495              : 
    2496          768 :    END SUBROUTINE Quasi_degenerate_P_ij
    2497              : 
    2498              : ! **************************************************************************************************
    2499              : !> \brief ...
    2500              : !> \param my_ijk ...
    2501              : !> \param homo ...
    2502              : !> \param homo_beta ...
    2503              : !> \param Eigenval ...
    2504              : !> \param mp2_env ...
    2505              : !> \param ijk_map ...
    2506              : !> \param unit_nr ...
    2507              : !> \param ngroup ...
    2508              : !> \param do_print_alpha ...
    2509              : !> \param comm_exchange ...
    2510              : !> \param num_ijk ...
    2511              : !> \param max_ijk ...
    2512              : !> \param color_sub ...
    2513              : !> \param buffer_size ...
    2514              : !> \param my_group_L_size ...
    2515              : !> \param B_size_k ...
    2516              : !> \param para_env ...
    2517              : !> \param virtual ...
    2518              : !> \param B_size_i ...
    2519              : ! **************************************************************************************************
    2520          462 :    SUBROUTINE Find_quasi_degenerate_ij(my_ijk, homo, homo_beta, Eigenval, mp2_env, ijk_map, unit_nr, ngroup, &
    2521              :                                        do_print_alpha, comm_exchange, num_ijk, max_ijk, color_sub, &
    2522              :                                        buffer_size, my_group_L_size, B_size_k, para_env, virtual, B_size_i)
    2523              : 
    2524              :       INTEGER, INTENT(OUT)                               :: my_ijk
    2525              :       INTEGER, INTENT(IN)                                :: homo, homo_beta
    2526              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: Eigenval
    2527              :       TYPE(mp2_type), INTENT(IN)                         :: mp2_env
    2528              :       INTEGER, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: ijk_map
    2529              :       INTEGER, INTENT(IN)                                :: unit_nr, ngroup
    2530              :       LOGICAL, INTENT(IN)                                :: do_print_alpha
    2531              :       TYPE(mp_comm_type), INTENT(IN)                     :: comm_exchange
    2532              :       INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT)    :: num_ijk
    2533              :       INTEGER, INTENT(OUT)                               :: max_ijk
    2534              :       INTEGER, INTENT(IN)                                :: color_sub, buffer_size, my_group_L_size, &
    2535              :                                                             B_size_k
    2536              :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    2537              :       INTEGER, INTENT(IN)                                :: virtual, B_size_i
    2538              : 
    2539              :       INTEGER :: block_size, communication_steps, communication_volume, iib, ij_counter, &
    2540              :          ijk_counter, jjb, kkb, max_block_size, max_num_k_blocks, min_communication_volume, &
    2541              :          my_steps, num_k_blocks, num_sing_ij, total_ijk
    2542              :       INTEGER(KIND=int_8)                                :: mem
    2543          462 :       LOGICAL, ALLOCATABLE, DIMENSION(:, :)              :: ijk_marker
    2544              : 
    2545         1386 :       ALLOCATE (num_ijk(0:comm_exchange%num_pe - 1))
    2546              : 
    2547          462 :       num_sing_ij = 0
    2548         2092 :       DO iiB = 1, homo
    2549              :          ! diagonal elements already updated
    2550         4368 :          DO jjB = iiB + 1, homo
    2551         3906 :             IF (ABS(Eigenval(jjB) - Eigenval(iiB)) < mp2_env%ri_grad%eps_canonical) THEN
    2552          114 :                num_sing_ij = num_sing_ij + 1
    2553              :             END IF
    2554              :          END DO
    2555              :       END DO
    2556              : 
    2557          462 :       IF (unit_nr > 0) THEN
    2558          231 :       IF (do_print_alpha) THEN
    2559              :          WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
    2560          153 :             "MO_INFO| Number of ij pairs below EPS_CANONICAL:", num_sing_ij
    2561              :       ELSE
    2562              :          WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
    2563           78 :             "MO_INFO| Number of ij pairs (spin beta) below EPS_CANONICAL:", num_sing_ij
    2564              :       END IF
    2565              :       END IF
    2566              : 
    2567              :       ! Determine the block size, first guess: use available buffer
    2568          462 :       max_block_size = buffer_size/(my_group_L_size*B_size_k)
    2569              : 
    2570              :       ! Second limit: memory
    2571          462 :       CALL m_memory(mem)
    2572              :       ! Convert to number of doubles
    2573          462 :       mem = mem/8
    2574              :       ! Remove local_ab (2x) and local_aL_i (2x)
    2575          462 :       mem = mem - 2_int_8*(virtual*B_size_k + B_size_i*my_group_L_size)
    2576          462 :       max_block_size = MIN(max_block_size, MAX(1, INT(mem/(my_group_L_size*B_size_k), KIND(max_block_size))))
    2577              : 
    2578              :       ! Exchange the limit
    2579          462 :       CALL para_env%min(max_block_size)
    2580              : 
    2581              :       ! Find now the block size which minimizes the communication volume and then the number of communication steps
    2582          462 :       block_size = 1
    2583          462 :       min_communication_volume = 3*homo_beta*num_sing_ij
    2584          462 :       communication_steps = 3*homo_beta*num_sing_ij
    2585         1174 :       DO iiB = max_block_size, 2, -1
    2586          712 :          max_num_k_blocks = homo_beta/iiB*num_sing_ij
    2587          712 :          num_k_blocks = max_num_k_blocks - MOD(max_num_k_blocks, ngroup)
    2588          712 :          communication_volume = num_k_blocks*(2 + iiB) + 3*(homo_beta*num_sing_ij - iiB*num_k_blocks)
    2589          712 :          my_steps = num_k_blocks + homo_beta*num_sing_ij - iiB*num_k_blocks
    2590         1174 :          IF (communication_volume < min_communication_volume) THEN
    2591           52 :             block_size = iiB
    2592           52 :             min_communication_volume = communication_volume
    2593           52 :             communication_steps = my_steps
    2594          660 :          ELSE IF (communication_volume == min_communication_volume .AND. my_steps < communication_steps) THEN
    2595           58 :             block_size = iiB
    2596           58 :             communication_steps = my_steps
    2597              :          END IF
    2598              :       END DO
    2599              : 
    2600          462 :       IF (unit_nr > 0) THEN
    2601              :          WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
    2602          231 :             "MO_INFO| Block size:", block_size
    2603          231 :          CALL m_flush(unit_nr)
    2604              :       END IF
    2605              : 
    2606              :       ! Calculate number of large blocks
    2607          462 :       max_num_k_blocks = homo_beta/block_size*num_sing_ij
    2608          462 :       num_k_blocks = max_num_k_blocks - MOD(max_num_k_blocks, ngroup)
    2609              : 
    2610          462 :       total_ijk = num_k_blocks + homo_beta*num_sing_ij - num_k_blocks*block_size
    2611         1022 :       ALLOCATE (ijk_map(4, total_ijk))
    2612          462 :       ijk_map = 0
    2613         1484 :       ALLOCATE (ijk_marker(homo_beta, num_sing_ij))
    2614         1020 :       ijk_marker = .TRUE.
    2615              : 
    2616          462 :       my_ijk = 0
    2617          462 :       ijk_counter = 0
    2618          462 :       ij_counter = 0
    2619         2092 :       DO iiB = 1, homo
    2620              :          ! diagonal elements already updated
    2621         4368 :          DO jjB = iiB + 1, homo
    2622         2276 :             IF (ABS(Eigenval(jjB) - Eigenval(iiB)) >= mp2_env%ri_grad%eps_canonical) CYCLE
    2623          114 :             ij_counter = ij_counter + 1
    2624         1880 :             DO kkB = 1, homo_beta - MOD(homo_beta, block_size), block_size
    2625          172 :                IF (ijk_counter + 1 > num_k_blocks) EXIT
    2626          136 :                ijk_counter = ijk_counter + 1
    2627          408 :                ijk_marker(kkB:kkB + block_size - 1, ij_counter) = .FALSE.
    2628          136 :                ijk_map(1, ijk_counter) = iiB
    2629          136 :                ijk_map(2, ijk_counter) = jjB
    2630          136 :                ijk_map(3, ijk_counter) = kkB
    2631          136 :                ijk_map(4, ijk_counter) = block_size
    2632         2412 :                IF (MOD(ijk_counter, ngroup) == color_sub) my_ijk = my_ijk + 1
    2633              :             END DO
    2634              :          END DO
    2635              :       END DO
    2636              :       ij_counter = 0
    2637         2092 :       DO iiB = 1, homo
    2638              :          ! diagonal elements already updated
    2639         4368 :          DO jjB = iiB + 1, homo
    2640         2276 :             IF (ABS(Eigenval(jjB) - Eigenval(iiB)) >= mp2_env%ri_grad%eps_canonical) CYCLE
    2641          114 :             ij_counter = ij_counter + 1
    2642         2188 :             DO kkB = 1, homo_beta
    2643         2720 :                IF (ijk_marker(kkB, ij_counter)) THEN
    2644          172 :                   ijk_counter = ijk_counter + 1
    2645          172 :                   ijk_map(1, ijk_counter) = iiB
    2646          172 :                   ijk_map(2, ijk_counter) = jjB
    2647          172 :                   ijk_map(3, ijk_counter) = kkB
    2648          172 :                   ijk_map(4, ijk_counter) = 1
    2649          172 :                   IF (MOD(ijk_counter, ngroup) == color_sub) my_ijk = my_ijk + 1
    2650              :                END IF
    2651              :             END DO
    2652              :          END DO
    2653              :       END DO
    2654              : 
    2655          462 :       DEALLOCATE (ijk_marker)
    2656              : 
    2657          462 :       CALL comm_exchange%allgather(my_ijk, num_ijk)
    2658          954 :       max_ijk = MAXVAL(num_ijk)
    2659              : 
    2660          462 :    END SUBROUTINE Find_quasi_degenerate_ij
    2661              : 
    2662              : END MODULE mp2_ri_gpw
        

Generated by: LCOV version 2.0-1