LCOV - code coverage report
Current view: top level - src - mp2.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4c33f95) Lines: 313 371 84.4 %
Date: 2025-01-30 06:53:08 Functions: 3 3 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Routines to calculate MP2 energy
      10             : !> \par History
      11             : !>      05.2011 created [Mauro Del Ben]
      12             : !> \author Mauro Del Ben
      13             : ! **************************************************************************************************
      14             : MODULE mp2
      15             :    USE admm_types,                      ONLY: admm_type
      16             :    USE admm_utils,                      ONLY: admm_correct_for_eigenvalues,&
      17             :                                               admm_uncorrect_for_eigenvalues
      18             :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      19             :                                               get_atomic_kind_set
      20             :    USE bibliography,                    ONLY: Bussy2023,&
      21             :                                               DelBen2012,&
      22             :                                               DelBen2015b,&
      23             :                                               Rybkin2016,&
      24             :                                               Stein2022,&
      25             :                                               Stein2024,&
      26             :                                               cite_reference
      27             :    USE cp_blacs_env,                    ONLY: cp_blacs_env_type
      28             :    USE cp_control_types,                ONLY: dft_control_type
      29             :    USE cp_dbcsr_api,                    ONLY: dbcsr_get_info,&
      30             :                                               dbcsr_p_type
      31             :    USE cp_dbcsr_operations,             ONLY: copy_dbcsr_to_fm
      32             :    USE cp_fm_basic_linalg,              ONLY: cp_fm_column_scale,&
      33             :                                               cp_fm_syrk,&
      34             :                                               cp_fm_triangular_invert,&
      35             :                                               cp_fm_uplo_to_full
      36             :    USE cp_fm_cholesky,                  ONLY: cp_fm_cholesky_decompose
      37             :    USE cp_fm_diag,                      ONLY: choose_eigv_solver
      38             :    USE cp_fm_struct,                    ONLY: cp_fm_struct_create,&
      39             :                                               cp_fm_struct_release,&
      40             :                                               cp_fm_struct_type
      41             :    USE cp_fm_types,                     ONLY: cp_fm_create,&
      42             :                                               cp_fm_get_submatrix,&
      43             :                                               cp_fm_release,&
      44             :                                               cp_fm_set_all,&
      45             :                                               cp_fm_to_fm,&
      46             :                                               cp_fm_type
      47             :    USE cp_log_handling,                 ONLY: cp_get_default_logger,&
      48             :                                               cp_logger_type
      49             :    USE cp_output_handling,              ONLY: cp_print_key_finished_output,&
      50             :                                               cp_print_key_unit_nr
      51             :    USE hfx_exx,                         ONLY: calculate_exx
      52             :    USE hfx_types,                       ONLY: &
      53             :         alloc_containers, dealloc_containers, hfx_basis_info_type, hfx_basis_type, &
      54             :         hfx_container_type, hfx_create_basis_types, hfx_init_container, hfx_release_basis_types, &
      55             :         hfx_type
      56             :    USE input_constants,                 ONLY: cholesky_inverse,&
      57             :                                               cholesky_off,&
      58             :                                               do_eri_gpw,&
      59             :                                               do_eri_mme,&
      60             :                                               rpa_exchange_axk,&
      61             :                                               rpa_exchange_none,&
      62             :                                               rpa_exchange_sosex,&
      63             :                                               sigma_none
      64             :    USE input_section_types,             ONLY: section_vals_get,&
      65             :                                               section_vals_get_subs_vals,&
      66             :                                               section_vals_type
      67             :    USE kinds,                           ONLY: dp,&
      68             :                                               int_8
      69             :    USE kpoint_types,                    ONLY: kpoint_type
      70             :    USE machine,                         ONLY: m_flush,&
      71             :                                               m_memory,&
      72             :                                               m_walltime
      73             :    USE message_passing,                 ONLY: mp_para_env_type
      74             :    USE mp2_direct_method,               ONLY: mp2_direct_energy
      75             :    USE mp2_gpw,                         ONLY: mp2_gpw_main
      76             :    USE mp2_optimize_ri_basis,           ONLY: optimize_ri_basis_main
      77             :    USE mp2_types,                       ONLY: mp2_biel_type,&
      78             :                                               mp2_method_direct,&
      79             :                                               mp2_method_gpw,&
      80             :                                               mp2_ri_optimize_basis,&
      81             :                                               mp2_type,&
      82             :                                               ri_mp2_laplace,&
      83             :                                               ri_mp2_method_gpw,&
      84             :                                               ri_rpa_method_gpw
      85             :    USE parallel_gemm_api,               ONLY: parallel_gemm
      86             :    USE particle_types,                  ONLY: particle_type
      87             :    USE qs_energy_types,                 ONLY: qs_energy_type
      88             :    USE qs_environment_types,            ONLY: get_qs_env,&
      89             :                                               qs_environment_type
      90             :    USE qs_kind_types,                   ONLY: qs_kind_type
      91             :    USE qs_mo_types,                     ONLY: allocate_mo_set,&
      92             :                                               deallocate_mo_set,&
      93             :                                               get_mo_set,&
      94             :                                               init_mo_set,&
      95             :                                               mo_set_type
      96             :    USE qs_scf_methods,                  ONLY: eigensolver,&
      97             :                                               eigensolver_symm
      98             :    USE qs_scf_types,                    ONLY: qs_scf_env_type
      99             :    USE rpa_gw_sigma_x,                  ONLY: compute_vec_Sigma_x_minus_vxc_gw
     100             :    USE scf_control_types,               ONLY: scf_control_type
     101             :    USE virial_types,                    ONLY: virial_type
     102             : 
     103             : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num, omp_get_num_threads
     104             : 
     105             : #include "./base/base_uses.f90"
     106             : 
     107             :    IMPLICIT NONE
     108             : 
     109             :    PRIVATE
     110             : 
     111             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mp2'
     112             : 
     113             :    PUBLIC :: mp2_main
     114             : 
     115             : CONTAINS
     116             : 
     117             : ! **************************************************************************************************
     118             : !> \brief the main entry point for MP2 calculations
     119             : !> \param qs_env ...
     120             : !> \param calc_forces ...
     121             : !> \author Mauro Del Ben
     122             : ! **************************************************************************************************
     123         694 :    SUBROUTINE mp2_main(qs_env, calc_forces)
     124             :       TYPE(qs_environment_type), POINTER                 :: qs_env
     125             :       LOGICAL, INTENT(IN)                                :: calc_forces
     126             : 
     127             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'mp2_main'
     128             : 
     129             :       INTEGER :: bin, cholesky_method, dimen, handle, handle2, i, i_thread, iatom, ii, ikind, &
     130             :          irep, ispin, max_nset, my_bin_size, n_rep_hf, n_threads, nao, natom, ndep, &
     131             :          nfullcols_total, nfullrows_total, nkind, nmo, nspins, unit_nr
     132             :       INTEGER(KIND=int_8)                                :: mem
     133         694 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: kind_of, nelec
     134             :       LOGICAL :: calc_ex, do_admm, do_admm_rpa_exx, do_dynamic_load_balancing, do_exx, do_gw, &
     135             :          do_im_time, do_kpoints_cubic_RPA, free_hfx_buffer, reuse_hfx, update_xc_energy
     136             :       REAL(KIND=dp) :: E_admm_from_GW(2), E_ex_from_GW, Emp2, Emp2_AA, Emp2_AA_Cou, Emp2_AA_ex, &
     137             :          Emp2_AB, Emp2_AB_Cou, Emp2_AB_ex, Emp2_BB, Emp2_BB_Cou, Emp2_BB_ex, Emp2_Cou, Emp2_ex, &
     138             :          Emp2_S, Emp2_T, maxocc, mem_real, t1, t2, t3
     139         694 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: evals
     140         694 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Auto
     141         694 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: C
     142         694 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: mo_eigenvalues
     143             :       TYPE(admm_type), POINTER                           :: admm_env
     144         694 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     145             :       TYPE(cp_blacs_env_type), POINTER                   :: blacs_env
     146             :       TYPE(cp_fm_struct_type), POINTER                   :: fm_struct
     147             :       TYPE(cp_fm_type)                                   :: evecs, fm_matrix_ks, fm_matrix_s, &
     148             :                                                             fm_matrix_work
     149             :       TYPE(cp_fm_type), POINTER                          :: fm_matrix_ks_red, fm_matrix_s_red, &
     150             :                                                             fm_work_red, mo_coeff
     151             :       TYPE(cp_logger_type), POINTER                      :: logger
     152         694 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     153         694 :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_ks_transl, matrix_s_kp
     154             :       TYPE(dft_control_type), POINTER                    :: dft_control
     155             :       TYPE(hfx_basis_info_type)                          :: basis_info
     156         694 :       TYPE(hfx_basis_type), DIMENSION(:), POINTER        :: basis_parameter
     157         694 :       TYPE(hfx_container_type), DIMENSION(:), POINTER    :: integral_containers
     158             :       TYPE(hfx_container_type), POINTER                  :: maxval_container
     159             :       TYPE(hfx_type), POINTER                            :: actual_x_data
     160             :       TYPE(kpoint_type), POINTER                         :: kpoints
     161         694 :       TYPE(mo_set_type), ALLOCATABLE, DIMENSION(:)       :: mos_mp2
     162         694 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     163         694 :       TYPE(mp2_biel_type)                                :: mp2_biel
     164             :       TYPE(mp2_type), POINTER                            :: mp2_env
     165             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     166         694 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     167             :       TYPE(qs_energy_type), POINTER                      :: energy
     168         694 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     169             :       TYPE(qs_scf_env_type), POINTER                     :: scf_env
     170             :       TYPE(scf_control_type), POINTER                    :: scf_control
     171             :       TYPE(section_vals_type), POINTER                   :: hfx_sections, input
     172             :       TYPE(virial_type), POINTER                         :: virial
     173             : 
     174             :       ! If SCF has not converged we should abort MP2 calculation
     175         694 :       IF (qs_env%mp2_env%hf_fail) THEN
     176             :          CALL cp_abort(__LOCATION__, "SCF not converged: "// &
     177           0 :                        "not possible to run MP2")
     178             :       END IF
     179             : 
     180         694 :       NULLIFY (virial, dft_control, blacs_env, kpoints, fm_matrix_s_red, fm_matrix_ks_red, fm_work_red)
     181         694 :       CALL timeset(routineN, handle)
     182         694 :       logger => cp_get_default_logger()
     183             : 
     184         694 :       CALL cite_reference(DelBen2012)
     185             : 
     186         694 :       do_kpoints_cubic_RPA = qs_env%mp2_env%ri_rpa_im_time%do_im_time_kpoints
     187             : 
     188             :       ! for cubic RPA and GW, we have kpoints and therefore, we get other matrices later
     189         694 :       IF (do_kpoints_cubic_RPA) THEN
     190             : 
     191             :          CALL get_qs_env(qs_env, &
     192             :                          input=input, &
     193             :                          atomic_kind_set=atomic_kind_set, &
     194             :                          qs_kind_set=qs_kind_set, &
     195             :                          dft_control=dft_control, &
     196             :                          particle_set=particle_set, &
     197             :                          para_env=para_env, &
     198             :                          blacs_env=blacs_env, &
     199             :                          energy=energy, &
     200             :                          kpoints=kpoints, &
     201             :                          scf_env=scf_env, &
     202             :                          scf_control=scf_control, &
     203             :                          matrix_ks_kp=matrix_ks_transl, &
     204             :                          matrix_s_kp=matrix_s_kp, &
     205           4 :                          mp2_env=mp2_env)
     206             : 
     207             :          CALL get_gamma(matrix_s, matrix_ks, mos, &
     208           4 :                         matrix_s_kp, matrix_ks_transl, kpoints)
     209             : 
     210             :       ELSE
     211             : 
     212             :          CALL get_qs_env(qs_env, &
     213             :                          input=input, &
     214             :                          atomic_kind_set=atomic_kind_set, &
     215             :                          qs_kind_set=qs_kind_set, &
     216             :                          dft_control=dft_control, &
     217             :                          particle_set=particle_set, &
     218             :                          para_env=para_env, &
     219             :                          blacs_env=blacs_env, &
     220             :                          energy=energy, &
     221             :                          mos=mos, &
     222             :                          scf_env=scf_env, &
     223             :                          scf_control=scf_control, &
     224             :                          virial=virial, &
     225             :                          matrix_ks=matrix_ks, &
     226             :                          matrix_s=matrix_s, &
     227             :                          mp2_env=mp2_env, &
     228         690 :                          admm_env=admm_env)
     229             : 
     230             :       END IF
     231             : 
     232             :       unit_nr = cp_print_key_unit_nr(logger, input, "DFT%XC%WF_CORRELATION%PRINT", &
     233         694 :                                      extension=".mp2Log")
     234             : 
     235         694 :       IF (unit_nr > 0) THEN
     236         347 :          IF (mp2_env%method .NE. ri_rpa_method_gpw) THEN
     237         223 :             WRITE (unit_nr, *)
     238         223 :             WRITE (unit_nr, *)
     239         223 :             WRITE (unit_nr, '(T2,A)') 'MP2 section'
     240         223 :             WRITE (unit_nr, '(T2,A)') '-----------'
     241         223 :             WRITE (unit_nr, *)
     242             :          ELSE
     243         124 :             WRITE (unit_nr, *)
     244         124 :             WRITE (unit_nr, *)
     245         124 :             WRITE (unit_nr, '(T2,A)') 'RI-RPA section'
     246         124 :             WRITE (unit_nr, '(T2,A)') '--------------'
     247         124 :             WRITE (unit_nr, *)
     248             :          END IF
     249             :       END IF
     250             : 
     251         694 :       IF (calc_forces) THEN
     252         314 :          CALL cite_reference(DelBen2015b)
     253         314 :          CALL cite_reference(Rybkin2016)
     254         314 :          CALL cite_reference(Stein2022)
     255         314 :          CALL cite_reference(Bussy2023)
     256         314 :          CALL cite_reference(Stein2024)
     257             :          !Gradients available for RI-MP2, and low-scaling Laplace MP2/RPA
     258         314 :          IF (.NOT. (mp2_env%method == ri_mp2_method_gpw .OR. &
     259             :                     mp2_env%method == ri_rpa_method_gpw .OR. mp2_env%method == ri_mp2_laplace)) THEN
     260           0 :             CPABORT("No forces/gradients for the selected method.")
     261             :          END IF
     262             :       END IF
     263             : 
     264         694 :       IF (.NOT. do_kpoints_cubic_RPA) THEN
     265         690 :          IF (virial%pv_availability .AND. (.NOT. virial%pv_numer) .AND. mp2_env%eri_method == do_eri_mme) THEN
     266           0 :             CPABORT("analytical stress not implemented with ERI_METHOD = MME")
     267             :          END IF
     268             :       END IF
     269             : 
     270         694 :       IF (mp2_env%do_im_time .AND. mp2_env%eri_method .NE. do_eri_gpw) THEN
     271         122 :          mp2_env%mp2_num_proc = 1
     272             :       END IF
     273             : 
     274         694 :       IF (mp2_env%mp2_num_proc < 1 .OR. mp2_env%mp2_num_proc > para_env%num_pe) THEN
     275           0 :          CPWARN("GROUP_SIZE is reset because of a too small or too large value.")
     276           0 :          mp2_env%mp2_num_proc = MAX(MIN(para_env%num_pe, mp2_env%mp2_num_proc), 1)
     277             :       END IF
     278             : 
     279         694 :       IF (MOD(para_env%num_pe, mp2_env%mp2_num_proc) /= 0) THEN
     280           0 :          CPABORT("GROUP_SIZE must be a divisor of the total number of MPI ranks!")
     281             :       END IF
     282             : 
     283         694 :       IF (.NOT. mp2_env%do_im_time) THEN
     284         560 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T76,I5)') 'Used number of processes per group:', mp2_env%mp2_num_proc
     285         840 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T68,F9.2,A4)') 'Maximum allowed memory usage per MPI process:', &
     286         560 :             mp2_env%mp2_memory, ' MiB'
     287             :       END IF
     288             : 
     289             :       IF ((mp2_env%method .NE. mp2_method_gpw) .AND. &
     290             :           (mp2_env%method .NE. ri_mp2_method_gpw) .AND. &
     291         694 :           (mp2_env%method .NE. ri_rpa_method_gpw) .AND. &
     292             :           (mp2_env%method .NE. ri_mp2_laplace)) THEN
     293          24 :          CALL m_memory(mem)
     294          24 :          mem_real = (mem + 1024*1024 - 1)/(1024*1024)
     295          24 :          CALL para_env%max(mem_real)
     296          24 :          mp2_env%mp2_memory = mp2_env%mp2_memory - mem_real
     297          24 :          IF (mp2_env%mp2_memory < 0.0_dp) mp2_env%mp2_memory = 1.0_dp
     298             : 
     299          36 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T68,F9.2,A4)') 'Available memory per MPI process for MP2:', &
     300          24 :             mp2_env%mp2_memory, ' MiB'
     301             :       END IF
     302             : 
     303         694 :       IF (unit_nr > 0) CALL m_flush(unit_nr)
     304             : 
     305         694 :       nspins = dft_control%nspins
     306         694 :       natom = SIZE(particle_set, 1)
     307             : 
     308         694 :       CALL get_atomic_kind_set(atomic_kind_set, kind_of=kind_of)
     309         694 :       nkind = SIZE(atomic_kind_set, 1)
     310             : 
     311         694 :       do_admm_rpa_exx = mp2_env%ri_rpa%do_admm
     312         694 :       IF (do_admm_rpa_exx .AND. .NOT. dft_control%do_admm) THEN
     313           0 :          CPABORT("Need an ADMM input section for ADMM RI_RPA EXX to work")
     314             :       END IF
     315             :       IF (do_admm_rpa_exx) THEN
     316          18 :          CALL hfx_create_basis_types(basis_parameter, basis_info, qs_kind_set, "AUX_FIT")
     317             :       ELSE
     318         676 :          CALL hfx_create_basis_types(basis_parameter, basis_info, qs_kind_set, "ORB")
     319             :       END IF
     320             : 
     321         694 :       dimen = 0
     322         694 :       max_nset = 0
     323        2718 :       DO iatom = 1, natom
     324        2024 :          ikind = kind_of(iatom)
     325        7824 :          dimen = dimen + SUM(basis_parameter(ikind)%nsgf)
     326        2718 :          max_nset = MAX(max_nset, basis_parameter(ikind)%nset)
     327             :       END DO
     328             : 
     329         694 :       CALL get_mo_set(mo_set=mos(1), nao=nao)
     330             : 
     331             :       ! diagonalize the KS matrix in order to have the full set of MO's
     332             :       ! get S and KS matrices in fm_type (create also a working array)
     333         694 :       NULLIFY (fm_struct)
     334         694 :       CALL dbcsr_get_info(matrix_s(1)%matrix, nfullrows_total=nfullrows_total, nfullcols_total=nfullcols_total)
     335             :       CALL cp_fm_struct_create(fm_struct, context=blacs_env, nrow_global=nfullrows_total, &
     336         694 :                                ncol_global=nfullcols_total, para_env=para_env)
     337         694 :       CALL cp_fm_create(fm_matrix_s, fm_struct, name="fm_matrix_s")
     338         694 :       CALL copy_dbcsr_to_fm(matrix_s(1)%matrix, fm_matrix_s)
     339             : 
     340         694 :       CALL cp_fm_create(fm_matrix_ks, fm_struct, name="fm_matrix_ks")
     341             : 
     342         694 :       CALL cp_fm_create(fm_matrix_work, fm_struct, name="fm_matrix_work")
     343         694 :       CALL cp_fm_set_all(matrix=fm_matrix_work, alpha=0.0_dp)
     344             : 
     345         694 :       CALL cp_fm_struct_release(fm_struct)
     346             : 
     347         694 :       nmo = nao
     348        2082 :       ALLOCATE (nelec(nspins))
     349         694 :       IF (scf_env%cholesky_method == cholesky_off) THEN
     350           0 :          ALLOCATE (evals(nao))
     351           0 :          evals = 0
     352             : 
     353           0 :          CALL cp_fm_create(evecs, fm_matrix_s%matrix_struct)
     354             : 
     355             :          ! Perform an EVD
     356           0 :          CALL choose_eigv_solver(fm_matrix_s, evecs, evals)
     357             : 
     358             :          ! Determine the number of neglectable eigenvalues assuming that the eigenvalues are in ascending order
     359             :          ! (Required by Lapack)
     360           0 :          ndep = 0
     361           0 :          DO ii = 1, nao
     362           0 :             IF (evals(ii) > scf_control%eps_eigval) THEN
     363           0 :                ndep = ii - 1
     364           0 :                EXIT
     365             :             END IF
     366             :          END DO
     367           0 :          nmo = nao - ndep
     368             : 
     369           0 :          CALL get_mo_set(mo_set=mos(1), nelectron=nelec(1))
     370           0 :          IF (MAXVAL(nelec) > nmo) THEN
     371             :             ! Should not happen as the following MO calculation is the same as during the SCF steps
     372           0 :             CPABORT("Not enough MOs found!")
     373             :          END IF
     374             : 
     375             :          ! Set the eigenvalue of the eigenvectors belonging to the linear subspace to zero
     376           0 :          evals(1:ndep) = 0.0_dp
     377             :          ! Determine the eigenvalues of the inverse square root
     378           0 :          evals(ndep + 1:nao) = 1.0_dp/SQRT(evals(ndep + 1:nao))
     379             : 
     380           0 :          IF (ndep > 0) THEN
     381           0 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T76,I5)') 'Number of removed MOs:', ndep
     382           0 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T76,I5)') 'Number of available MOs:', nmo
     383             : 
     384             :             ! Create reduced matrices
     385           0 :             NULLIFY (fm_struct)
     386           0 :             CALL cp_fm_struct_create(fm_struct, template_fmstruct=fm_matrix_s%matrix_struct, ncol_global=nmo)
     387             : 
     388           0 :             ALLOCATE (fm_matrix_s_red, fm_work_red)
     389           0 :             CALL cp_fm_create(fm_matrix_s_red, fm_struct)
     390           0 :             CALL cp_fm_create(fm_work_red, fm_struct)
     391           0 :             CALL cp_fm_struct_release(fm_struct)
     392             : 
     393           0 :             ALLOCATE (fm_matrix_ks_red)
     394             :             CALL cp_fm_struct_create(fm_struct, template_fmstruct=fm_matrix_s%matrix_struct, &
     395           0 :                                      nrow_global=nmo, ncol_global=nmo)
     396           0 :             CALL cp_fm_create(fm_matrix_ks_red, fm_struct)
     397           0 :             CALL cp_fm_struct_release(fm_struct)
     398             : 
     399             :             ! Scale the eigenvalues and copy them to
     400           0 :             CALL cp_fm_to_fm(evecs, fm_matrix_s_red, nmo, ndep + 1)
     401           0 :             CALL cp_fm_column_scale(fm_matrix_s_red, evals(ndep + 1:))
     402             : 
     403             :             ! Obtain ortho from (P)DGEMM, skip the linear dependent columns
     404             :             CALL parallel_gemm("N", "T", nao, nao, nmo, 1.0_dp, fm_matrix_s_red, evecs, &
     405           0 :                                0.0_dp, fm_matrix_s, b_first_col=ndep + 1)
     406             :          ELSE
     407             :             ! Take the square roots of the target values to allow application of SYRK
     408           0 :             evals = SQRT(evals)
     409           0 :             CALL cp_fm_column_scale(evecs, evals)
     410           0 :             CALL cp_fm_syrk("U", "N", nao, 1.0_dp, evecs, 1, 1, 0.0_dp, fm_matrix_s)
     411           0 :             CALL cp_fm_uplo_to_full(fm_matrix_s, fm_matrix_work)
     412             :          END IF
     413             : 
     414           0 :          CALL cp_fm_release(evecs)
     415           0 :          cholesky_method = cholesky_off
     416             :       ELSE
     417             :          ! calculate S^(-1/2) (cholesky decomposition)
     418         694 :          CALL cp_fm_cholesky_decompose(fm_matrix_s)
     419         694 :          CALL cp_fm_triangular_invert(fm_matrix_s)
     420         694 :          cholesky_method = cholesky_inverse
     421             :       END IF
     422             : 
     423        2934 :       ALLOCATE (mos_mp2(nspins))
     424        1546 :       DO ispin = 1, nspins
     425             : 
     426         852 :          CALL get_mo_set(mo_set=mos(ispin), maxocc=maxocc, nelectron=nelec(ispin))
     427             : 
     428             :          CALL allocate_mo_set(mo_set=mos_mp2(ispin), &
     429             :                               nao=nao, &
     430             :                               nmo=nmo, &
     431             :                               nelectron=nelec(ispin), &
     432             :                               n_el_f=REAL(nelec(ispin), dp), &
     433             :                               maxocc=maxocc, &
     434         852 :                               flexible_electron_count=dft_control%relax_multiplicity)
     435             : 
     436         852 :          CALL get_mo_set(mos_mp2(ispin), nao=nao)
     437             :          CALL cp_fm_struct_create(fm_struct, nrow_global=nao, &
     438             :                                   ncol_global=nmo, para_env=para_env, &
     439         852 :                                   context=blacs_env)
     440             : 
     441             :          CALL init_mo_set(mos_mp2(ispin), &
     442             :                           fm_struct=fm_struct, &
     443         852 :                           name="mp2_mos")
     444        3250 :          CALL cp_fm_struct_release(fm_struct)
     445             :       END DO
     446             : 
     447        1546 :       DO ispin = 1, nspins
     448             : 
     449             :          ! If ADMM we should make the ks matrix up-to-date
     450         852 :          IF (dft_control%do_admm) THEN
     451          94 :             CALL admm_correct_for_eigenvalues(ispin, admm_env, matrix_ks(ispin)%matrix)
     452             :          END IF
     453             : 
     454         852 :          CALL copy_dbcsr_to_fm(matrix_ks(ispin)%matrix, fm_matrix_ks)
     455             : 
     456         852 :          IF (dft_control%do_admm) THEN
     457          94 :             CALL admm_uncorrect_for_eigenvalues(ispin, admm_env, matrix_ks(ispin)%matrix)
     458             :          END IF
     459             : 
     460         852 :          IF (cholesky_method == cholesky_inverse) THEN
     461             : 
     462             :             ! diagonalize KS matrix
     463             :             CALL eigensolver(matrix_ks_fm=fm_matrix_ks, &
     464             :                              mo_set=mos_mp2(ispin), &
     465             :                              ortho=fm_matrix_s, &
     466             :                              work=fm_matrix_work, &
     467             :                              cholesky_method=cholesky_method, &
     468             :                              do_level_shift=.FALSE., &
     469             :                              level_shift=0.0_dp, &
     470         852 :                              use_jacobi=.FALSE.)
     471             : 
     472           0 :          ELSE IF (cholesky_method == cholesky_off) THEN
     473             : 
     474           0 :             IF (ASSOCIATED(fm_matrix_s_red)) THEN
     475             :                CALL eigensolver_symm(matrix_ks_fm=fm_matrix_ks, &
     476             :                                      mo_set=mos_mp2(ispin), &
     477             :                                      ortho=fm_matrix_s, &
     478             :                                      work=fm_matrix_work, &
     479             :                                      do_level_shift=.FALSE., &
     480             :                                      level_shift=0.0_dp, &
     481             :                                      use_jacobi=.FALSE., &
     482             :                                      jacobi_threshold=0.0_dp, &
     483             :                                      ortho_red=fm_matrix_s_red, &
     484             :                                      matrix_ks_fm_red=fm_matrix_ks_red, &
     485           0 :                                      work_red=fm_work_red)
     486             :             ELSE
     487             :                CALL eigensolver_symm(matrix_ks_fm=fm_matrix_ks, &
     488             :                                      mo_set=mos_mp2(ispin), &
     489             :                                      ortho=fm_matrix_s, &
     490             :                                      work=fm_matrix_work, &
     491             :                                      do_level_shift=.FALSE., &
     492             :                                      level_shift=0.0_dp, &
     493             :                                      use_jacobi=.FALSE., &
     494           0 :                                      jacobi_threshold=0.0_dp)
     495             :             END IF
     496             :          END IF
     497             : 
     498        1546 :          CALL get_mo_set(mos_mp2(ispin), mo_coeff=mo_coeff)
     499             :       END DO
     500             : 
     501         694 :       CALL cp_fm_release(fm_matrix_s)
     502         694 :       CALL cp_fm_release(fm_matrix_ks)
     503         694 :       CALL cp_fm_release(fm_matrix_work)
     504         694 :       IF (ASSOCIATED(fm_matrix_s_red)) THEN
     505           0 :          CALL cp_fm_release(fm_matrix_s_red)
     506           0 :          DEALLOCATE (fm_matrix_s_red)
     507             :       END IF
     508         694 :       IF (ASSOCIATED(fm_matrix_ks_red)) THEN
     509           0 :          CALL cp_fm_release(fm_matrix_ks_red)
     510           0 :          DEALLOCATE (fm_matrix_ks_red)
     511             :       END IF
     512         694 :       IF (ASSOCIATED(fm_work_red)) THEN
     513           0 :          CALL cp_fm_release(fm_work_red)
     514           0 :          DEALLOCATE (fm_work_red)
     515             :       END IF
     516             : 
     517         694 :       hfx_sections => section_vals_get_subs_vals(input, "DFT%XC%HF")
     518             : 
     519             :       !   build the table of index
     520         694 :       t1 = m_walltime()
     521        2776 :       ALLOCATE (mp2_biel%index_table(natom, max_nset))
     522             : 
     523         694 :       CALL build_index_table(natom, max_nset, mp2_biel%index_table, basis_parameter, kind_of)
     524             : 
     525             :       ! free the hfx_container (for now if forces are required we don't release the HFX stuff)
     526         694 :       free_hfx_buffer = .FALSE.
     527         694 :       IF (ASSOCIATED(qs_env%x_data)) THEN
     528         420 :          free_hfx_buffer = .TRUE.
     529         420 :          IF (calc_forces .AND. (.NOT. mp2_env%ri_grad%free_hfx_buffer)) free_hfx_buffer = .FALSE.
     530         420 :          IF (qs_env%x_data(1, 1)%do_hfx_ri) free_hfx_buffer = .FALSE.
     531         420 :          IF (calc_forces .AND. mp2_env%do_im_time) free_hfx_buffer = .FALSE.
     532         420 :          IF (mp2_env%ri_rpa%reuse_hfx) free_hfx_buffer = .FALSE.
     533             :       END IF
     534             : 
     535         694 :       IF (.NOT. do_kpoints_cubic_RPA) THEN
     536         690 :       IF (virial%pv_numer) THEN
     537             :          ! in the case of numerical stress we don't have to free the HFX integrals
     538          72 :          free_hfx_buffer = .FALSE.
     539          72 :          mp2_env%ri_grad%free_hfx_buffer = free_hfx_buffer
     540             :       END IF
     541             :       END IF
     542             : 
     543             :       ! calculate the matrix sigma_x - vxc for G0W0
     544         694 :       t3 = 0
     545         694 :       IF (mp2_env%ri_rpa%do_ri_g0w0) THEN
     546         116 :          CALL compute_vec_Sigma_x_minus_vxc_gw(qs_env, mp2_env, mos_mp2, E_ex_from_GW, E_admm_from_GW, t3, unit_nr)
     547             :       END IF
     548             : 
     549         694 :       IF (free_hfx_buffer) THEN
     550         220 :          CALL timeset(routineN//"_free_hfx", handle2)
     551         220 :          CALL section_vals_get(hfx_sections, n_repetition=n_rep_hf)
     552         220 :          n_threads = 1
     553         220 : !$       n_threads = omp_get_max_threads()
     554             : 
     555         440 :          DO irep = 1, n_rep_hf
     556         660 :             DO i_thread = 0, n_threads - 1
     557         220 :                actual_x_data => qs_env%x_data(irep, i_thread + 1)
     558             : 
     559         220 :                do_dynamic_load_balancing = .TRUE.
     560         220 :                IF (n_threads == 1 .OR. actual_x_data%memory_parameter%do_disk_storage) do_dynamic_load_balancing = .FALSE.
     561             : 
     562             :                IF (do_dynamic_load_balancing) THEN
     563           0 :                   my_bin_size = SIZE(actual_x_data%distribution_energy)
     564             :                ELSE
     565         220 :                   my_bin_size = 1
     566             :                END IF
     567             : 
     568         440 :                IF (.NOT. actual_x_data%memory_parameter%do_all_on_the_fly) THEN
     569         218 :                   CALL dealloc_containers(actual_x_data%store_ints, actual_x_data%memory_parameter%actual_memory_usage)
     570             :                END IF
     571             :             END DO
     572             :          END DO
     573         220 :          CALL timestop(handle2)
     574             :       END IF
     575             : 
     576         694 :       Emp2 = 0.D+00
     577         694 :       Emp2_Cou = 0.D+00
     578         694 :       Emp2_ex = 0.D+00
     579         694 :       calc_ex = .TRUE.
     580             : 
     581         694 :       t1 = m_walltime()
     582         712 :       SELECT CASE (mp2_env%method)
     583             :       CASE (mp2_method_direct)
     584          18 :          IF (unit_nr > 0) WRITE (unit_nr, *)
     585             : 
     586          72 :          ALLOCATE (Auto(dimen, nspins))
     587          90 :          ALLOCATE (C(dimen, dimen, nspins))
     588             : 
     589          40 :          DO ispin = 1, nspins
     590             :             ! get the alpha coeff and eigenvalues
     591             :             CALL get_mo_set(mo_set=mos_mp2(ispin), &
     592             :                             eigenvalues=mo_eigenvalues, &
     593          22 :                             mo_coeff=mo_coeff)
     594             : 
     595          22 :             CALL cp_fm_get_submatrix(mo_coeff, C(:, :, ispin), 1, 1, dimen, dimen, .FALSE.)
     596        1072 :             Auto(:, ispin) = mo_eigenvalues(:)
     597             :          END DO
     598             : 
     599          18 :          IF (nspins == 2) THEN
     600           4 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A)') 'Unrestricted Canonical Direct Methods:'
     601             :             ! for now, require the mos to be always present
     602             : 
     603             :             ! calculate the alpha-alpha MP2
     604           4 :             Emp2_AA = 0.0_dp
     605           4 :             Emp2_AA_Cou = 0.0_dp
     606           4 :             Emp2_AA_ex = 0.0_dp
     607             :             CALL mp2_direct_energy(dimen, nelec(1), nelec(1), mp2_biel, &
     608             :                                    mp2_env, C(:, :, 1), Auto(:, 1), Emp2_AA, Emp2_AA_Cou, Emp2_AA_ex, &
     609           4 :                                    qs_env, para_env, unit_nr)
     610           4 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Energy Alpha-Alpha = ', Emp2_AA
     611           4 :             IF (unit_nr > 0) WRITE (unit_nr, *)
     612             : 
     613           4 :             Emp2_BB = 0.0_dp
     614           4 :             Emp2_BB_Cou = 0.0_dp
     615           4 :             Emp2_BB_ex = 0.0_dp
     616             :             CALL mp2_direct_energy(dimen, nelec(2), nelec(2), mp2_biel, mp2_env, &
     617             :                                    C(:, :, 2), Auto(:, 2), Emp2_BB, Emp2_BB_Cou, Emp2_BB_ex, &
     618           4 :                                    qs_env, para_env, unit_nr)
     619           4 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Energy Beta-Beta= ', Emp2_BB
     620           4 :             IF (unit_nr > 0) WRITE (unit_nr, *)
     621             : 
     622           4 :             Emp2_AB = 0.0_dp
     623           4 :             Emp2_AB_Cou = 0.0_dp
     624           4 :             Emp2_AB_ex = 0.0_dp
     625             :             CALL mp2_direct_energy(dimen, nelec(1), nelec(2), mp2_biel, mp2_env, C(:, :, 1), &
     626             :                                    Auto(:, 1), Emp2_AB, Emp2_AB_Cou, Emp2_AB_ex, &
     627           4 :                                    qs_env, para_env, unit_nr, C(:, :, 2), Auto(:, 2))
     628           4 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Energy Alpha-Beta= ', Emp2_AB
     629           4 :             IF (unit_nr > 0) WRITE (unit_nr, *)
     630             : 
     631           4 :             Emp2 = Emp2_AA + Emp2_BB + Emp2_AB*2.0_dp !+Emp2_BA
     632           4 :             Emp2_Cou = Emp2_AA_Cou + Emp2_BB_Cou + Emp2_AB_Cou*2.0_dp !+Emp2_BA
     633           4 :             Emp2_ex = Emp2_AA_ex + Emp2_BB_ex + Emp2_AB_ex*2.0_dp !+Emp2_BA
     634             : 
     635           4 :             Emp2_S = Emp2_AB*2.0_dp
     636           4 :             Emp2_T = Emp2_AA + Emp2_BB
     637             : 
     638             :          ELSE
     639             : 
     640          14 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A)') 'Canonical Direct Methods:'
     641             : 
     642             :             CALL mp2_direct_energy(dimen, nelec(1)/2, nelec(1)/2, mp2_biel, mp2_env, &
     643             :                                    C(:, :, 1), Auto(:, 1), Emp2, Emp2_Cou, Emp2_ex, &
     644          14 :                                    qs_env, para_env, unit_nr)
     645             : 
     646             :          END IF
     647             : 
     648          18 :          DEALLOCATE (C, Auto)
     649             : 
     650             :       CASE (mp2_ri_optimize_basis)
     651             :          ! optimize ri basis set or tests for RI-MP2 gradients
     652           6 :          IF (unit_nr > 0) THEN
     653           3 :             WRITE (unit_nr, *)
     654           3 :             WRITE (unit_nr, '(T3,A)') 'Optimization of the auxiliary RI-MP2 basis'
     655           3 :             WRITE (unit_nr, *)
     656             :          END IF
     657             : 
     658          24 :          ALLOCATE (Auto(dimen, nspins))
     659          30 :          ALLOCATE (C(dimen, dimen, nspins))
     660             : 
     661          18 :          DO ispin = 1, nspins
     662             :             ! get the alpha coeff and eigenvalues
     663             :             CALL get_mo_set(mo_set=mos_mp2(ispin), &
     664             :                             eigenvalues=mo_eigenvalues, &
     665          12 :                             mo_coeff=mo_coeff)
     666             : 
     667          12 :             CALL cp_fm_get_submatrix(mo_coeff, C(:, :, ispin), 1, 1, dimen, dimen, .FALSE.)
     668         174 :             Auto(:, ispin) = mo_eigenvalues(:)
     669             :          END DO
     670             : 
     671             :          ! optimize basis
     672           6 :          IF (nspins == 2) THEN
     673             :             CALL optimize_ri_basis_main(Emp2, Emp2_Cou, Emp2_ex, Emp2_S, Emp2_T, dimen, natom, nelec(1), &
     674             :                                         mp2_biel, mp2_env, C(:, :, 1), Auto(:, 1), &
     675             :                                         kind_of, qs_env, para_env, unit_nr, &
     676           6 :                                         nelec(2), C(:, :, 2), Auto(:, 2))
     677             : 
     678             :          ELSE
     679             :             CALL optimize_ri_basis_main(Emp2, Emp2_Cou, Emp2_ex, Emp2_S, Emp2_T, dimen, natom, nelec(1)/2, &
     680             :                                         mp2_biel, mp2_env, C(:, :, 1), Auto(:, 1), &
     681           0 :                                         kind_of, qs_env, para_env, unit_nr)
     682             :          END IF
     683             : 
     684           6 :          DEALLOCATE (Auto, C)
     685             : 
     686             :       CASE (mp2_method_gpw)
     687             :          ! check if calculate the exchange contribution
     688          14 :          IF (mp2_env%scale_T == 0.0_dp .AND. (nspins == 2)) calc_ex = .FALSE.
     689             : 
     690             :          ! go with mp2_gpw
     691             :          CALL mp2_gpw_main(qs_env, mp2_env, Emp2, Emp2_Cou, Emp2_EX, Emp2_S, Emp2_T, &
     692         364 :                            mos_mp2, para_env, unit_nr, calc_forces, calc_ex)
     693             : 
     694             :       CASE (ri_mp2_method_gpw)
     695             :          ! check if calculate the exchange contribution
     696         350 :          IF (mp2_env%scale_T == 0.0_dp .AND. (nspins == 2)) calc_ex = .FALSE.
     697             : 
     698             :          ! go with mp2_gpw
     699             :          CALL mp2_gpw_main(qs_env, mp2_env, Emp2, Emp2_Cou, Emp2_EX, Emp2_S, Emp2_T, &
     700         350 :                            mos_mp2, para_env, unit_nr, calc_forces, calc_ex, do_ri_mp2=.TRUE.)
     701             : 
     702             :       CASE (ri_rpa_method_gpw)
     703             :          ! perform RI-RPA energy calculation (since most part of the calculation
     704             :          ! is actually equal to the RI-MP2-GPW we decided to put RPA in the MP2
     705             :          ! section to avoid code replication)
     706             : 
     707         248 :          calc_ex = .FALSE.
     708             : 
     709             :          ! go with ri_rpa_gpw
     710             :          CALL mp2_gpw_main(qs_env, mp2_env, Emp2, Emp2_Cou, Emp2_EX, Emp2_S, Emp2_T, &
     711         248 :                            mos_mp2, para_env, unit_nr, calc_forces, calc_ex, do_ri_rpa=.TRUE.)
     712             :          ! Scale energy contributions
     713         248 :          Emp2 = Emp2*mp2_env%ri_rpa%scale_rpa
     714         248 :          mp2_env%ri_rpa%ener_exchange = mp2_env%ri_rpa%ener_exchange*mp2_env%ri_rpa%scale_rpa
     715             : 
     716             :       CASE (ri_mp2_laplace)
     717             :          ! perform RI-SOS-Laplace-MP2 energy calculation, most part of the code in common
     718             :          ! with the RI-RPA part
     719             : 
     720             :          ! In SOS-MP2 only the coulomb-like contribution of the MP2 energy is computed
     721          58 :          calc_ex = .FALSE.
     722             : 
     723             :          ! go with sos_laplace_mp2_gpw
     724             :          CALL mp2_gpw_main(qs_env, mp2_env, Emp2, Emp2_Cou, Emp2_EX, Emp2_S, Emp2_T, &
     725          58 :                            mos_mp2, para_env, unit_nr, calc_forces, calc_ex, do_ri_sos_laplace_mp2=.TRUE.)
     726             : 
     727             :       CASE DEFAULT
     728         708 :          CPABORT("")
     729             :       END SELECT
     730             : 
     731         694 :       t2 = m_walltime()
     732         694 :       IF (unit_nr > 0) WRITE (unit_nr, *)
     733         694 :       IF (mp2_env%method .NE. ri_rpa_method_gpw) THEN
     734         446 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.6)') 'Total MP2 Time=', t2 - t1
     735         446 :          IF (mp2_env%method == ri_mp2_laplace) THEN
     736          58 :             Emp2_S = Emp2
     737          58 :             Emp2_T = 0.0_dp
     738          58 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Energy SO component (singlet) = ', Emp2_S
     739          58 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Scaling factor SO                 = ', mp2_env%scale_S
     740             :          ELSE
     741         388 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Coulomb Energy = ', Emp2_Cou/2.0_dp
     742         388 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Exchange Energy = ', Emp2_ex
     743         388 :             IF (nspins == 1) THEN
     744             :                ! valid only in the closed shell case
     745         288 :                Emp2_S = Emp2_Cou/2.0_dp
     746         288 :                IF (calc_ex) THEN
     747         288 :                   Emp2_T = Emp2_ex + Emp2_Cou/2.0_dp
     748             :                ELSE
     749             :                   ! unknown if Emp2_ex is not computed
     750           0 :                   Emp2_T = 0.0_dp
     751             :                END IF
     752             :             END IF
     753         388 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Energy SO component (singlet) = ', Emp2_S
     754         388 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'MP2 Energy SS component (triplet) = ', Emp2_T
     755         388 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Scaling factor SO                 = ', mp2_env%scale_S
     756         388 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Scaling factor SS                 = ', mp2_env%scale_T
     757             :          END IF
     758         446 :          Emp2_S = Emp2_S*mp2_env%scale_S
     759         446 :          Emp2_T = Emp2_T*mp2_env%scale_T
     760         446 :          Emp2 = Emp2_S + Emp2_T
     761         446 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Second order perturbation energy  =   ', Emp2
     762             :       ELSE
     763         248 :          IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.6)') 'Total RI-RPA Time=', t2 - t1
     764             : 
     765         248 :          update_xc_energy = .TRUE.
     766         248 :          IF (mp2_env%ri_rpa%do_ri_g0w0 .AND. .NOT. mp2_env%ri_g0w0%update_xc_energy) update_xc_energy = .FALSE.
     767          90 :          IF (.NOT. update_xc_energy) Emp2 = 0.0_dp
     768             : 
     769         248 :          IF (unit_nr > 0 .AND. update_xc_energy) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'RI-RPA energy  =   ', Emp2
     770         248 :          IF (unit_nr > 0 .AND. mp2_env%ri_rpa%sigma_param /= sigma_none) THEN
     771           5 :             WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Sigma corr. to RI-RPA energy  =   ', &
     772          10 :                mp2_env%ri_rpa%e_sigma_corr
     773             :          END IF
     774         248 :          IF (mp2_env%ri_rpa%exchange_correction == rpa_exchange_axk) THEN
     775          10 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'RI-RPA-AXK energy=', mp2_env%ri_rpa%ener_exchange
     776         238 :          ELSE IF (mp2_env%ri_rpa%exchange_correction == rpa_exchange_sosex) THEN
     777           2 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'RI-RPA-SOSEX energy=', mp2_env%ri_rpa%ener_exchange
     778             :          END IF
     779         248 :          IF (mp2_env%ri_rpa%do_rse) THEN
     780           6 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Diagonal singles correction (dRSE) = ', &
     781           4 :                mp2_env%ri_rpa%rse_corr_diag
     782           6 :             IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Full singles correction (RSE) =', &
     783           4 :                mp2_env%ri_rpa%rse_corr
     784           4 :             IF (dft_control%do_admm) CPABORT("RPA RSE not implemented with RI_RPA%ADMM on")
     785             :          END IF
     786             :       END IF
     787         694 :       IF (unit_nr > 0) WRITE (unit_nr, *)
     788             : 
     789             :       ! we have it !!!!
     790         694 :       IF (mp2_env%ri_rpa%exchange_correction /= rpa_exchange_none) THEN
     791          12 :          Emp2 = Emp2 + mp2_env%ri_rpa%ener_exchange
     792             :       END IF
     793         694 :       IF (mp2_env%ri_rpa%do_rse) THEN
     794           4 :          Emp2 = Emp2 + mp2_env%ri_rpa%rse_corr
     795             :       END IF
     796         694 :       IF (mp2_env%ri_rpa%sigma_param /= sigma_none) THEN
     797             :          !WRITE (unit_nr, '(T3,A,T56,F25.14)') 'Sigma corr. to RI-RPA energy  =   ',&
     798          10 :          Emp2 = Emp2 + mp2_env%ri_rpa%e_sigma_corr
     799             :       END IF
     800         694 :       energy%mp2 = Emp2
     801         694 :       energy%total = energy%total + Emp2
     802             : 
     803        1546 :       DO ispin = 1, nspins
     804        1546 :          CALL deallocate_mo_set(mo_set=mos_mp2(ispin))
     805             :       END DO
     806         694 :       DEALLOCATE (mos_mp2)
     807             : 
     808             :       ! if necessary reallocate hfx buffer
     809         694 :       IF (free_hfx_buffer .AND. (.NOT. calc_forces) .AND. &
     810             :           (mp2_env%ri_g0w0%do_ri_Sigma_x .OR. .NOT. mp2_env%ri_rpa_im_time%do_kpoints_from_Gamma)) THEN
     811         120 :          CALL timeset(routineN//"_alloc_hfx", handle2)
     812         240 :          DO irep = 1, n_rep_hf
     813         360 :             DO i_thread = 0, n_threads - 1
     814         120 :                actual_x_data => qs_env%x_data(irep, i_thread + 1)
     815             : 
     816         120 :                do_dynamic_load_balancing = .TRUE.
     817         120 :                IF (n_threads == 1 .OR. actual_x_data%memory_parameter%do_disk_storage) do_dynamic_load_balancing = .FALSE.
     818             : 
     819             :                IF (do_dynamic_load_balancing) THEN
     820           0 :                   my_bin_size = SIZE(actual_x_data%distribution_energy)
     821             :                ELSE
     822         120 :                   my_bin_size = 1
     823             :                END IF
     824             : 
     825         240 :                IF (.NOT. actual_x_data%memory_parameter%do_all_on_the_fly) THEN
     826         120 :                   CALL alloc_containers(actual_x_data%store_ints, my_bin_size)
     827             : 
     828         240 :                   DO bin = 1, my_bin_size
     829         120 :                      maxval_container => actual_x_data%store_ints%maxval_container(bin)
     830         120 :                      integral_containers => actual_x_data%store_ints%integral_containers(:, bin)
     831         120 :                      CALL hfx_init_container(maxval_container, actual_x_data%memory_parameter%actual_memory_usage, .FALSE.)
     832        7920 :                      DO i = 1, 64
     833        7800 :                         CALL hfx_init_container(integral_containers(i), actual_x_data%memory_parameter%actual_memory_usage, .FALSE.)
     834             :                      END DO
     835             :                   END DO
     836             :                END IF
     837             :             END DO
     838             :          END DO
     839         120 :          CALL timestop(handle2)
     840             :       END IF
     841             : 
     842         694 :       CALL hfx_release_basis_types(basis_parameter)
     843             : 
     844             :       ! if required calculate the EXX contribution from the DFT density
     845         694 :       IF (mp2_env%method == ri_rpa_method_gpw .AND. .NOT. calc_forces) THEN
     846             :          do_exx = .FALSE.
     847         200 :          hfx_sections => section_vals_get_subs_vals(input, "DFT%XC%WF_CORRELATION%RI_RPA%HF")
     848         200 :          CALL section_vals_get(hfx_sections, explicit=do_exx)
     849         200 :          IF (do_exx) THEN
     850         128 :             do_gw = mp2_env%ri_rpa%do_ri_g0w0
     851         128 :             do_admm = mp2_env%ri_rpa%do_admm
     852         128 :             reuse_hfx = qs_env%mp2_env%ri_rpa%reuse_hfx
     853         128 :             do_im_time = qs_env%mp2_env%do_im_time
     854             : 
     855             :             CALL calculate_exx(qs_env=qs_env, &
     856             :                                unit_nr=unit_nr, &
     857             :                                hfx_sections=hfx_sections, &
     858             :                                x_data=qs_env%mp2_env%ri_rpa%x_data, &
     859             :                                do_gw=do_gw, &
     860             :                                do_admm=do_admm, &
     861             :                                calc_forces=.FALSE., &
     862             :                                reuse_hfx=reuse_hfx, &
     863             :                                do_im_time=do_im_time, &
     864             :                                E_ex_from_GW=E_ex_from_GW, &
     865             :                                E_admm_from_GW=E_admm_from_GW, &
     866         128 :                                t3=t3)
     867             : 
     868             :          END IF
     869             :       END IF
     870             : 
     871             :       CALL cp_print_key_finished_output(unit_nr, logger, input, &
     872         694 :                                         "DFT%XC%WF_CORRELATION%PRINT")
     873             : 
     874         694 :       CALL timestop(handle)
     875             : 
     876        3470 :    END SUBROUTINE mp2_main
     877             : 
     878             : ! **************************************************************************************************
     879             : !> \brief ...
     880             : !> \param natom ...
     881             : !> \param max_nset ...
     882             : !> \param index_table ...
     883             : !> \param basis_parameter ...
     884             : !> \param kind_of ...
     885             : ! **************************************************************************************************
     886         694 :    PURE SUBROUTINE build_index_table(natom, max_nset, index_table, basis_parameter, kind_of)
     887             :       INTEGER, INTENT(IN)                                :: natom, max_nset
     888             :       INTEGER, DIMENSION(natom, max_nset), INTENT(OUT)   :: index_table
     889             :       TYPE(hfx_basis_type), DIMENSION(:), POINTER        :: basis_parameter
     890             :       INTEGER, DIMENSION(natom), INTENT(IN)              :: kind_of
     891             : 
     892             :       INTEGER                                            :: counter, iatom, ikind, iset, nset
     893             : 
     894        8752 :       index_table = -HUGE(0)
     895             :       counter = 0
     896        2718 :       DO iatom = 1, natom
     897        2024 :          ikind = kind_of(iatom)
     898        2024 :          nset = basis_parameter(ikind)%nset
     899        8518 :          DO iset = 1, nset
     900        5800 :             index_table(iatom, iset) = counter + 1
     901        7824 :             counter = counter + basis_parameter(ikind)%nsgf(iset)
     902             :          END DO
     903             :       END DO
     904             : 
     905         694 :    END SUBROUTINE build_index_table
     906             : 
     907             : ! **************************************************************************************************
     908             : !> \brief ...
     909             : !> \param matrix_s ...
     910             : !> \param matrix_ks ...
     911             : !> \param mos ...
     912             : !> \param matrix_s_kp ...
     913             : !> \param matrix_ks_transl ...
     914             : !> \param kpoints ...
     915             : ! **************************************************************************************************
     916           4 :    PURE SUBROUTINE get_gamma(matrix_s, matrix_ks, mos, matrix_s_kp, matrix_ks_transl, kpoints)
     917             : 
     918             :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_s, matrix_ks
     919             :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     920             :       TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER       :: matrix_s_kp, matrix_ks_transl
     921             :       TYPE(kpoint_type), POINTER                         :: kpoints
     922             : 
     923             :       INTEGER                                            :: nspins
     924             : 
     925           4 :       nspins = SIZE(matrix_ks_transl, 1)
     926             : 
     927           4 :       matrix_ks(1:nspins) => matrix_ks_transl(1:nspins, 1)
     928           4 :       matrix_s(1:1) => matrix_s_kp(1:1, 1)
     929           4 :       mos(1:nspins) => kpoints%kp_env(1)%kpoint_env%mos(1:nspins, 1)
     930             : 
     931           4 :    END SUBROUTINE get_gamma
     932             : 
     933             : END MODULE mp2
     934             : 

Generated by: LCOV version 1.15