LCOV - code coverage report
Current view: top level - src - mp2_grids.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:3130539) Lines: 501 558 89.8 %
Date: 2025-05-14 06:57:18 Functions: 16 17 94.1 %

          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 frequency and time grids (integration points and weights)
      10             : !>        for correlation methods
      11             : !> \par History
      12             : !>      05.2019 Refactored from rpa_ri_gpw [Frederick Stein]
      13             : ! **************************************************************************************************
      14             : MODULE mp2_grids
      15             :    USE cp_fm_types,                     ONLY: cp_fm_get_info,&
      16             :                                               cp_fm_type
      17             :    USE input_section_types,             ONLY: section_vals_type,&
      18             :                                               section_vals_val_set
      19             :    USE kinds,                           ONLY: dp
      20             :    USE kpoint_types,                    ONLY: get_kpoint_info,&
      21             :                                               kpoint_env_type,&
      22             :                                               kpoint_type
      23             :    USE machine,                         ONLY: m_flush
      24             :    USE mathconstants,                   ONLY: pi
      25             :    USE message_passing,                 ONLY: mp_para_env_release,&
      26             :                                               mp_para_env_type
      27             :    USE minimax_exp,                     ONLY: get_exp_minimax_coeff
      28             :    USE minimax_exp_gw,                  ONLY: get_exp_minimax_coeff_gw
      29             :    USE minimax_rpa,                     ONLY: get_rpa_minimax_coeff,&
      30             :                                               get_rpa_minimax_coeff_larger_grid
      31             :    USE qs_environment_types,            ONLY: get_qs_env,&
      32             :                                               qs_environment_type
      33             :    USE qs_mo_types,                     ONLY: get_mo_set,&
      34             :                                               mo_set_type
      35             : #include "./base/base_uses.f90"
      36             : 
      37             :    IMPLICIT NONE
      38             : 
      39             :    PRIVATE
      40             : 
      41             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'mp2_grids'
      42             : 
      43             :    PUBLIC :: get_minimax_grid, get_clenshaw_grid, test_least_square_ft, get_l_sq_wghts_cos_tf_t_to_w, &
      44             :              get_l_sq_wghts_cos_tf_w_to_t, get_l_sq_wghts_sin_tf_t_to_w, init_greenx_grids
      45             : 
      46             : CONTAINS
      47             : 
      48             : ! **************************************************************************************************
      49             : !> \brief ...
      50             : !> \param para_env ...
      51             : !> \param unit_nr ...
      52             : !> \param homo ...
      53             : !> \param Eigenval ...
      54             : !> \param num_integ_points ...
      55             : !> \param do_im_time ...
      56             : !> \param do_ri_sos_laplace_mp2 ...
      57             : !> \param do_print ...
      58             : !> \param tau_tj ...
      59             : !> \param tau_wj ...
      60             : !> \param qs_env ...
      61             : !> \param do_gw_im_time ...
      62             : !> \param do_kpoints_cubic_RPA ...
      63             : !> \param e_fermi ...
      64             : !> \param tj ...
      65             : !> \param wj ...
      66             : !> \param weights_cos_tf_t_to_w ...
      67             : !> \param weights_cos_tf_w_to_t ...
      68             : !> \param weights_sin_tf_t_to_w ...
      69             : !> \param regularization ...
      70             : ! **************************************************************************************************
      71         126 :    SUBROUTINE get_minimax_grid(para_env, unit_nr, homo, Eigenval, num_integ_points, &
      72             :                                do_im_time, do_ri_sos_laplace_mp2, do_print, tau_tj, tau_wj, qs_env, do_gw_im_time, &
      73             :                                do_kpoints_cubic_RPA, e_fermi, tj, wj, weights_cos_tf_t_to_w, &
      74             :                                weights_cos_tf_w_to_t, weights_sin_tf_t_to_w, regularization)
      75             : 
      76             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
      77             :       INTEGER, INTENT(IN)                                :: unit_nr
      78             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
      79             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
      80             :       INTEGER, INTENT(IN)                                :: num_integ_points
      81             :       LOGICAL, INTENT(IN)                                :: do_im_time, do_ri_sos_laplace_mp2, &
      82             :                                                             do_print
      83             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
      84             :          INTENT(OUT)                                     :: tau_tj, tau_wj
      85             :       TYPE(qs_environment_type), POINTER                 :: qs_env
      86             :       LOGICAL, INTENT(IN)                                :: do_gw_im_time, do_kpoints_cubic_RPA
      87             :       REAL(KIND=dp), INTENT(OUT)                         :: e_fermi
      88             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
      89             :          INTENT(INOUT)                                   :: tj, wj
      90             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
      91             :          INTENT(OUT)                                     :: weights_cos_tf_t_to_w, &
      92             :                                                             weights_cos_tf_w_to_t, &
      93             :                                                             weights_sin_tf_t_to_w
      94             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: regularization
      95             : 
      96             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_minimax_grid'
      97             :       INTEGER, PARAMETER                                 :: num_points_per_magnitude = 200
      98             : 
      99             :       INTEGER                                            :: handle, ierr, ispin, jquad, nspins
     100             :       LOGICAL                                            :: my_do_kpoints, my_open_shell
     101             :       REAL(KIND=dp)                                      :: Emax, Emin, max_error_min, my_E_Range, &
     102             :                                                             my_regularization, scaling
     103         126 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: x_tw
     104             :       TYPE(section_vals_type), POINTER                   :: input
     105             : 
     106         126 :       CALL timeset(routineN, handle)
     107             : 
     108             :       ! Test for spin unrestricted
     109         126 :       nspins = SIZE(homo)
     110         126 :       my_open_shell = (nspins == 2)
     111             : 
     112             :       ! Test whether all necessary variables are available
     113         126 :       my_do_kpoints = .FALSE.
     114         126 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
     115          68 :          my_do_kpoints = do_kpoints_cubic_RPA
     116             :       END IF
     117             : 
     118         126 :       my_regularization = 0.0_dp
     119         126 :       IF (PRESENT(regularization)) THEN
     120         126 :          my_regularization = regularization
     121             :       END IF
     122             : 
     123         126 :       IF (my_do_kpoints) THEN
     124           0 :          CALL gap_and_max_eig_diff_kpoints(qs_env, para_env, Emin, Emax, e_fermi)
     125           0 :          my_E_Range = Emax/Emin
     126             :       ELSE
     127         126 :          IF (qs_env%mp2_env%E_range <= 1.0_dp .OR. qs_env%mp2_env%E_gap <= 0.0_dp) THEN
     128           0 :             Emin = HUGE(dp)
     129           0 :             Emax = 0.0_dp
     130           0 :             DO ispin = 1, nspins
     131           0 :                IF (homo(ispin) > 0) THEN
     132           0 :                   Emin = MIN(Emin, Eigenval(homo(ispin) + 1, 1, ispin) - Eigenval(homo(ispin), 1, ispin))
     133           0 :                   Emax = MAX(Emax, MAXVAL(Eigenval(:, :, ispin)) - MINVAL(Eigenval(:, :, ispin)))
     134             :                END IF
     135             :             END DO
     136           0 :             my_E_Range = Emax/Emin
     137           0 :             qs_env%mp2_env%e_range = my_e_range
     138           0 :             qs_env%mp2_env%e_gap = Emin
     139             : 
     140           0 :             CALL get_qs_env(qs_env, input=input)
     141           0 :             CALL section_vals_val_set(input, "DFT%XC%WF_CORRELATION%E_RANGE", r_val=my_e_range)
     142           0 :             CALL section_vals_val_set(input, "DFT%XC%WF_CORRELATION%E_GAP", r_val=emin)
     143             :          ELSE
     144         126 :             my_E_range = qs_env%mp2_env%E_range
     145         126 :             Emin = qs_env%mp2_env%E_gap
     146         126 :             Emax = Emin*my_E_range
     147             :          END IF
     148             :       END IF
     149             : 
     150         126 :       IF (num_integ_points > 20 .AND. my_E_Range < 100.0_dp) THEN
     151           0 :          IF (unit_nr > 0) &
     152             :             CALL cp_warn(__LOCATION__, &
     153             :                          "You requested a large minimax grid (> 20 points) for a small minimax range R (R < 100). "// &
     154             :                          "That may lead to numerical "// &
     155             :                          "instabilities when computing minimax grid weights. You can prevent small ranges by choosing "// &
     156           0 :                          "a larger basis set with higher angular momenta or alternatively using all-electron calculations.")
     157             :       END IF
     158             : 
     159         126 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
     160         204 :          ALLOCATE (x_tw(2*num_integ_points))
     161         584 :          x_tw = 0.0_dp
     162          68 :          ierr = 0
     163          68 :          IF (num_integ_points .LE. 20) THEN
     164          68 :             CALL get_rpa_minimax_coeff(num_integ_points, my_E_Range, x_tw, ierr)
     165             :          ELSE
     166           0 :             CALL get_rpa_minimax_coeff_larger_grid(num_integ_points, my_E_Range, x_tw)
     167             :          END IF
     168             : 
     169         204 :          ALLOCATE (tj(num_integ_points))
     170         326 :          tj = 0.0_dp
     171             : 
     172         204 :          ALLOCATE (wj(num_integ_points))
     173         326 :          wj = 0.0_dp
     174             : 
     175         326 :          DO jquad = 1, num_integ_points
     176         258 :             tj(jquad) = x_tw(jquad)
     177         326 :             wj(jquad) = x_tw(jquad + num_integ_points)
     178             :          END DO
     179             : 
     180             :          ! for the smaller grids, the factor of 4 is included in get_rpa_minimax_coeff for wj
     181          68 :          IF (num_integ_points >= 26) THEN
     182           0 :             wj(:) = wj(:)*4.0_dp
     183             :          END IF
     184             : 
     185          68 :          DEALLOCATE (x_tw)
     186             : 
     187          68 :          IF (unit_nr > 0 .AND. do_print) THEN
     188             :             WRITE (UNIT=unit_nr, FMT="(T3,A,T75,i6)") &
     189          33 :                "MINIMAX_INFO| Number of integration points:", num_integ_points
     190             :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
     191          33 :                "MINIMAX_INFO| Gap for the minimax approximation:", Emin
     192             :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
     193          33 :                "MINIMAX_INFO| Range for the minimax approximation:", my_E_Range
     194          33 :             WRITE (UNIT=unit_nr, FMT="(T3,A,T54,A,T72,A)") "MINIMAX_INFO| Minimax parameters:", "Weights", "Abscissas"
     195         157 :             DO jquad = 1, num_integ_points
     196         157 :                WRITE (UNIT=unit_nr, FMT="(T41,F20.10,F20.10)") wj(jquad), tj(jquad)
     197             :             END DO
     198          33 :             CALL m_flush(unit_nr)
     199             :          END IF
     200             : 
     201             :          ! scale the minimax parameters
     202         326 :          tj(:) = tj(:)*Emin
     203         326 :          wj(:) = wj(:)*Emin
     204             :       ELSE
     205             :          ! When we perform SOS-MP2, we need an additional factor of 2 for the energies (compare with mp2_laplace.F)
     206             :          ! We do not need weights etc. for the cosine transform
     207             :          ! We do not scale Emax because it is not needed for SOS-MP2
     208          58 :          Emin = Emin*2.0_dp
     209             :       END IF
     210             : 
     211             :       ! set up the minimax time grid
     212         126 :       IF (do_im_time .OR. do_ri_sos_laplace_mp2) THEN
     213             : 
     214         300 :          ALLOCATE (x_tw(2*num_integ_points))
     215         836 :          x_tw = 0.0_dp
     216             : 
     217         100 :          IF (num_integ_points .LE. 20) THEN
     218         100 :             CALL get_exp_minimax_coeff(num_integ_points, my_E_Range, x_tw)
     219             :          ELSE
     220           0 :             CALL get_exp_minimax_coeff_gw(num_integ_points, my_E_Range, x_tw)
     221             :          END IF
     222             : 
     223             :          ! For RPA we include already a factor of two (see later steps)
     224         100 :          scaling = 2.0_dp
     225         100 :          IF (do_ri_sos_laplace_mp2) scaling = 1.0_dp
     226             : 
     227         300 :          ALLOCATE (tau_tj(num_integ_points))
     228         468 :          tau_tj = 0.0_dp
     229             : 
     230         300 :          ALLOCATE (tau_wj(num_integ_points))
     231         468 :          tau_wj = 0.0_dp
     232             : 
     233         468 :          DO jquad = 1, num_integ_points
     234         368 :             tau_tj(jquad) = x_tw(jquad)/scaling
     235         468 :             tau_wj(jquad) = x_tw(jquad + num_integ_points)/scaling
     236             :          END DO
     237             : 
     238         100 :          DEALLOCATE (x_tw)
     239             : 
     240         100 :          IF (unit_nr > 0 .AND. do_print) THEN
     241             :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
     242          49 :                "MINIMAX_INFO| Range for the minimax approximation:", my_E_Range
     243             :             ! For testing the gap
     244             :             WRITE (UNIT=unit_nr, FMT="(T3,A,T66,F15.4)") &
     245          49 :                "MINIMAX_INFO| Gap:", Emin
     246             :             WRITE (UNIT=unit_nr, FMT="(T3,A,T54,A,T72,A)") &
     247          49 :                "MINIMAX_INFO| Minimax parameters of the time grid:", "Weights", "Abscissas"
     248         228 :             DO jquad = 1, num_integ_points
     249         228 :                WRITE (UNIT=unit_nr, FMT="(T41,F20.10,F20.10)") tau_wj(jquad), tau_tj(jquad)
     250             :             END DO
     251          49 :             CALL m_flush(unit_nr)
     252             :          END IF
     253             : 
     254             :          ! scale grid from [1,R] to [Emin,Emax]
     255         468 :          tau_tj(:) = tau_tj(:)/Emin
     256         468 :          tau_wj(:) = tau_wj(:)/Emin
     257             : 
     258         100 :          IF (.NOT. do_ri_sos_laplace_mp2) THEN
     259         168 :             ALLOCATE (weights_cos_tf_t_to_w(num_integ_points, num_integ_points))
     260         678 :             weights_cos_tf_t_to_w = 0.0_dp
     261             : 
     262             :             CALL get_l_sq_wghts_cos_tf_t_to_w(num_integ_points, tau_tj, weights_cos_tf_t_to_w, tj, &
     263             :                                               Emin, Emax, max_error_min, num_points_per_magnitude, &
     264          42 :                                               my_regularization)
     265             : 
     266             :             ! get the weights for the cosine transform W^c(iw) -> W^c(it)
     267         168 :             ALLOCATE (weights_cos_tf_w_to_t(num_integ_points, num_integ_points))
     268         678 :             weights_cos_tf_w_to_t = 0.0_dp
     269             : 
     270             :             CALL get_l_sq_wghts_cos_tf_w_to_t(num_integ_points, tau_tj, weights_cos_tf_w_to_t, tj, &
     271             :                                               Emin, Emax, max_error_min, num_points_per_magnitude, &
     272          42 :                                               my_regularization)
     273             : 
     274          42 :             IF (do_gw_im_time) THEN
     275             : 
     276             :                ! get the weights for the sine transform Sigma^sin(it) -> Sigma^sin(iw) (PRB 94, 165109 (2016), Eq. 71)
     277          40 :                ALLOCATE (weights_sin_tf_t_to_w(num_integ_points, num_integ_points))
     278         310 :                weights_sin_tf_t_to_w = 0.0_dp
     279             : 
     280             :                CALL get_l_sq_wghts_sin_tf_t_to_w(num_integ_points, tau_tj, weights_sin_tf_t_to_w, tj, &
     281             :                                                  Emin, Emax, max_error_min, num_points_per_magnitude, &
     282          10 :                                                  my_regularization)
     283             : 
     284          10 :                IF (unit_nr > 0) THEN
     285             :                   WRITE (UNIT=unit_nr, FMT="(T3,A,T66,ES15.2)") &
     286           5 :                      "MINIMAX_INFO| Maximum deviation of the imag. time fit:", max_error_min
     287             :                END IF
     288             :             END IF
     289             : 
     290             :          END IF
     291             : 
     292             :       END IF
     293             : 
     294         126 :       CALL timestop(handle)
     295             : 
     296         126 :    END SUBROUTINE get_minimax_grid
     297             : 
     298             : ! **************************************************************************************************
     299             : !> \brief ...
     300             : !> \param para_env ...
     301             : !> \param para_env_RPA ...
     302             : !> \param unit_nr ...
     303             : !> \param homo ...
     304             : !> \param virtual ...
     305             : !> \param Eigenval ...
     306             : !> \param num_integ_points ...
     307             : !> \param num_integ_group ...
     308             : !> \param color_rpa_group ...
     309             : !> \param fm_mat_S ...
     310             : !> \param my_do_gw ...
     311             : !> \param ext_scaling ...
     312             : !> \param a_scaling ...
     313             : !> \param tj ...
     314             : !> \param wj ...
     315             : ! **************************************************************************************************
     316          94 :    SUBROUTINE get_clenshaw_grid(para_env, para_env_RPA, unit_nr, homo, virtual, Eigenval, num_integ_points, &
     317          94 :                                 num_integ_group, color_rpa_group, fm_mat_S, my_do_gw, &
     318             :                                 ext_scaling, a_scaling, tj, wj)
     319             : 
     320             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_RPA
     321             :       INTEGER, INTENT(IN)                                :: unit_nr
     322             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
     323             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
     324             :       INTEGER, INTENT(IN)                                :: num_integ_points, num_integ_group, &
     325             :                                                             color_rpa_group
     326             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S
     327             :       LOGICAL, INTENT(IN)                                :: my_do_gw
     328             :       REAL(KIND=dp), INTENT(IN)                          :: ext_scaling
     329             :       REAL(KIND=dp), INTENT(OUT)                         :: a_scaling
     330             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     331             :          INTENT(OUT)                                     :: tj, wj
     332             : 
     333             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'get_clenshaw_grid'
     334             : 
     335             :       INTEGER                                            :: handle, jquad, nspins
     336             :       LOGICAL                                            :: my_open_shell
     337             : 
     338          94 :       CALL timeset(routineN, handle)
     339             : 
     340          94 :       nspins = SIZE(homo)
     341          94 :       my_open_shell = (nspins == 2)
     342             : 
     343             :       ! Now, start to prepare the different grid
     344         282 :       ALLOCATE (tj(num_integ_points))
     345        3684 :       tj = 0.0_dp
     346             : 
     347         188 :       ALLOCATE (wj(num_integ_points))
     348        3684 :       wj = 0.0_dp
     349             : 
     350        3590 :       DO jquad = 1, num_integ_points - 1
     351        3496 :          tj(jquad) = jquad*pi/(2.0_dp*num_integ_points)
     352        3590 :          wj(jquad) = pi/(num_integ_points*SIN(tj(jquad))**2)
     353             :       END DO
     354          94 :       tj(num_integ_points) = pi/2.0_dp
     355          94 :       wj(num_integ_points) = pi/(2.0_dp*num_integ_points*SIN(tj(num_integ_points))**2)
     356             : 
     357          94 :       IF (my_do_gw .AND. ext_scaling > 0.0_dp) THEN
     358          58 :          a_scaling = ext_scaling
     359             :       ELSE
     360             :          CALL calc_scaling_factor(a_scaling, para_env, para_env_RPA, homo, virtual, Eigenval, &
     361             :                                   num_integ_points, num_integ_group, color_rpa_group, &
     362          36 :                                   tj, wj, fm_mat_S)
     363             :       END IF
     364             : 
     365          94 :       IF (unit_nr > 0) WRITE (unit_nr, '(T3,A,T56,F25.5)') 'INTEG_INFO| Scaling parameter:', a_scaling
     366             : 
     367        3684 :       wj(:) = wj(:)*a_scaling
     368             : 
     369          94 :       CALL timestop(handle)
     370             : 
     371          94 :    END SUBROUTINE get_clenshaw_grid
     372             : 
     373             : ! **************************************************************************************************
     374             : !> \brief ...
     375             : !> \param a_scaling_ext ...
     376             : !> \param para_env ...
     377             : !> \param para_env_RPA ...
     378             : !> \param homo ...
     379             : !> \param virtual ...
     380             : !> \param Eigenval ...
     381             : !> \param num_integ_points ...
     382             : !> \param num_integ_group ...
     383             : !> \param color_rpa_group ...
     384             : !> \param tj_ext ...
     385             : !> \param wj_ext ...
     386             : !> \param fm_mat_S ...
     387             : ! **************************************************************************************************
     388          36 :    SUBROUTINE calc_scaling_factor(a_scaling_ext, para_env, para_env_RPA, homo, virtual, Eigenval, &
     389             :                                   num_integ_points, num_integ_group, color_rpa_group, &
     390          36 :                                   tj_ext, wj_ext, fm_mat_S)
     391             :       REAL(KIND=dp), INTENT(OUT)                         :: a_scaling_ext
     392             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_RPA
     393             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo, virtual
     394             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
     395             :       INTEGER, INTENT(IN)                                :: num_integ_points, num_integ_group, &
     396             :                                                             color_rpa_group
     397             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     398             :          INTENT(IN)                                      :: tj_ext, wj_ext
     399             :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: fm_mat_S
     400             : 
     401             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_scaling_factor'
     402             : 
     403             :       INTEGER                                            :: handle, icycle, jquad, ncol_local, &
     404             :                                                             ncol_local_beta, nspins
     405             :       LOGICAL                                            :: my_open_shell
     406             :       REAL(KIND=dp) :: a_high, a_low, a_scaling, conv_param, eps, first_deriv, left_term, &
     407             :          right_term, right_term_ref, right_term_ref_beta, step
     408          36 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: cottj, D_ia, D_ia_beta, iaia_RI, &
     409          36 :                                                             iaia_RI_beta, M_ia, M_ia_beta
     410             :       TYPE(mp_para_env_type), POINTER                    :: para_env_col, para_env_col_beta
     411             : 
     412          36 :       CALL timeset(routineN, handle)
     413             : 
     414          36 :       nspins = SIZE(homo)
     415          36 :       my_open_shell = (nspins == 2)
     416             : 
     417          36 :       eps = 1.0E-10_dp
     418             : 
     419         108 :       ALLOCATE (cottj(num_integ_points))
     420             : 
     421             :       ! calculate the cotangent of the abscissa tj
     422         406 :       DO jquad = 1, num_integ_points
     423         406 :          cottj(jquad) = 1.0_dp/TAN(tj_ext(jquad))
     424             :       END DO
     425             : 
     426             :       CALL calc_ia_ia_integrals(para_env_RPA, homo(1), virtual(1), ncol_local, right_term_ref, Eigenval(:, 1, 1), &
     427          36 :                                 D_ia, iaia_RI, M_ia, fm_mat_S(1), para_env_col)
     428             : 
     429             :       ! In the open shell case do point 1-2-3 for the beta spin
     430          36 :       IF (my_open_shell) THEN
     431             :          CALL calc_ia_ia_integrals(para_env_RPA, homo(2), virtual(2), ncol_local_beta, right_term_ref_beta, Eigenval(:, 1, 2), &
     432           6 :                                    D_ia_beta, iaia_RI_beta, M_ia_beta, fm_mat_S(2), para_env_col_beta)
     433             : 
     434           6 :          right_term_ref = right_term_ref + right_term_ref_beta
     435             :       END IF
     436             : 
     437             :       ! bcast the result
     438          36 :       IF (para_env%mepos == 0) THEN
     439          18 :          CALL para_env%bcast(right_term_ref, 0)
     440             :       ELSE
     441          18 :          right_term_ref = 0.0_dp
     442          18 :          CALL para_env%bcast(right_term_ref, 0)
     443             :       END IF
     444             : 
     445             :       ! 5) start iteration for solving the non-linear equation by bisection
     446             :       ! find limit, here step=0.5 seems a good compromise
     447          36 :       conv_param = 100.0_dp*EPSILON(right_term_ref)
     448          36 :       step = 0.5_dp
     449          36 :       a_low = 0.0_dp
     450          36 :       a_high = step
     451          36 :       right_term = -right_term_ref
     452          98 :       DO icycle = 1, num_integ_points*2
     453          90 :          a_scaling = a_high
     454             : 
     455             :          CALL calculate_objfunc(a_scaling, left_term, first_deriv, num_integ_points, my_open_shell, &
     456             :                                 M_ia, cottj, wj_ext, D_ia, D_ia_beta, M_ia_beta, &
     457             :                                 ncol_local, ncol_local_beta, num_integ_group, color_rpa_group, &
     458          90 :                                 para_env, para_env_col, para_env_col_beta)
     459          90 :          left_term = left_term/4.0_dp/pi*a_scaling
     460             : 
     461          90 :          IF (ABS(left_term) > ABS(right_term) .OR. ABS(left_term + right_term) <= conv_param) EXIT
     462          62 :          a_low = a_high
     463          98 :          a_high = a_high + step
     464             : 
     465             :       END DO
     466             : 
     467          36 :       IF (ABS(left_term + right_term) >= conv_param) THEN
     468          32 :          IF (a_scaling >= 2*num_integ_points*step) THEN
     469          10 :             a_scaling = 1.0_dp
     470             :          ELSE
     471             : 
     472         340 :             DO icycle = 1, num_integ_points*2
     473         336 :                a_scaling = (a_low + a_high)/2.0_dp
     474             : 
     475             :                CALL calculate_objfunc(a_scaling, left_term, first_deriv, num_integ_points, my_open_shell, &
     476             :                                       M_ia, cottj, wj_ext, D_ia, D_ia_beta, M_ia_beta, &
     477             :                                       ncol_local, ncol_local_beta, num_integ_group, color_rpa_group, &
     478         336 :                                       para_env, para_env_col, para_env_col_beta)
     479         336 :                left_term = left_term/4.0_dp/pi*a_scaling
     480             : 
     481         336 :                IF (ABS(left_term) > ABS(right_term)) THEN
     482             :                   a_high = a_scaling
     483             :                ELSE
     484         186 :                   a_low = a_scaling
     485             :                END IF
     486             : 
     487         340 :                IF (ABS(a_high - a_low) < 1.0e-5_dp) EXIT
     488             : 
     489             :             END DO
     490             : 
     491             :          END IF
     492             :       END IF
     493             : 
     494          36 :       a_scaling_ext = a_scaling
     495          36 :       CALL para_env%bcast(a_scaling_ext, 0)
     496             : 
     497          36 :       DEALLOCATE (cottj)
     498          36 :       DEALLOCATE (iaia_RI)
     499          36 :       DEALLOCATE (D_ia)
     500          36 :       DEALLOCATE (M_ia)
     501          36 :       CALL mp_para_env_release(para_env_col)
     502             : 
     503          36 :       IF (my_open_shell) THEN
     504           6 :          DEALLOCATE (iaia_RI_beta)
     505           6 :          DEALLOCATE (D_ia_beta)
     506           6 :          DEALLOCATE (M_ia_beta)
     507           6 :          CALL mp_para_env_release(para_env_col_beta)
     508             :       END IF
     509             : 
     510          36 :       CALL timestop(handle)
     511             : 
     512          72 :    END SUBROUTINE calc_scaling_factor
     513             : 
     514             : ! **************************************************************************************************
     515             : !> \brief ...
     516             : !> \param para_env_RPA ...
     517             : !> \param homo ...
     518             : !> \param virtual ...
     519             : !> \param ncol_local ...
     520             : !> \param right_term_ref ...
     521             : !> \param Eigenval ...
     522             : !> \param D_ia ...
     523             : !> \param iaia_RI ...
     524             : !> \param M_ia ...
     525             : !> \param fm_mat_S ...
     526             : !> \param para_env_col ...
     527             : ! **************************************************************************************************
     528          42 :    SUBROUTINE calc_ia_ia_integrals(para_env_RPA, homo, virtual, ncol_local, right_term_ref, Eigenval, &
     529             :                                    D_ia, iaia_RI, M_ia, fm_mat_S, para_env_col)
     530             : 
     531             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env_RPA
     532             :       INTEGER, INTENT(IN)                                :: homo, virtual
     533             :       INTEGER, INTENT(OUT)                               :: ncol_local
     534             :       REAL(KIND=dp), INTENT(OUT)                         :: right_term_ref
     535             :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: Eigenval
     536             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     537             :          INTENT(OUT)                                     :: D_ia, iaia_RI, M_ia
     538             :       TYPE(cp_fm_type), INTENT(IN)                       :: fm_mat_S
     539             :       TYPE(mp_para_env_type), POINTER                    :: para_env_col
     540             : 
     541             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_ia_ia_integrals'
     542             : 
     543             :       INTEGER                                            :: avirt, color_col, color_row, handle, &
     544             :                                                             i_global, iiB, iocc, nrow_local
     545          42 :       INTEGER, DIMENSION(:), POINTER                     :: col_indices, row_indices
     546             :       REAL(KIND=dp)                                      :: eigen_diff
     547             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: iaia_RI_dp
     548             :       TYPE(mp_para_env_type), POINTER                    :: para_env_row
     549             : 
     550          42 :       CALL timeset(routineN, handle)
     551             : 
     552             :       ! calculate the (ia|ia) RI integrals
     553             :       ! ----------------------------------
     554             :       ! 1) get info fm_mat_S
     555             :       CALL cp_fm_get_info(matrix=fm_mat_S, &
     556             :                           nrow_local=nrow_local, &
     557             :                           ncol_local=ncol_local, &
     558             :                           row_indices=row_indices, &
     559          42 :                           col_indices=col_indices)
     560             : 
     561             :       ! allocate the local buffer of iaia_RI integrals (dp kind)
     562         124 :       ALLOCATE (iaia_RI_dp(ncol_local))
     563        2722 :       iaia_RI_dp = 0.0_dp
     564             : 
     565             :       ! 2) perform the local multiplication SUM_K (ia|K)*(ia|K)
     566        2722 :       DO iiB = 1, ncol_local
     567      186900 :          iaia_RI_dp(iiB) = iaia_RI_dp(iiB) + DOT_PRODUCT(fm_mat_S%local_data(:, iiB), fm_mat_S%local_data(:, iiB))
     568             :       END DO
     569             : 
     570             :       ! 3) sum the result with the processes of the RPA_group having the same columns
     571             :       !          _______ia______               _
     572             :       !         |   |   |   |   |             | |
     573             :       !     --> | 1 | 5 | 9 | 13|   SUM -->   | |
     574             :       !         |___|__ |___|___|             |_|
     575             :       !         |   |   |   |   |             | |
     576             :       !     --> | 2 | 6 | 10| 14|   SUM -->   | |
     577             :       !       K |___|___|___|___|             |_|   (ia|ia)_RI
     578             :       !         |   |   |   |   |             | |
     579             :       !     --> | 3 | 7 | 11| 15|   SUM -->   | |
     580             :       !         |___|___|___|___|             |_|
     581             :       !         |   |   |   |   |             | |
     582             :       !     --> | 4 | 8 | 12| 16|   SUM -->   | |
     583             :       !         |___|___|___|___|             |_|
     584             :       !
     585             : 
     586          42 :       color_col = fm_mat_S%matrix_struct%context%mepos(2)
     587          42 :       ALLOCATE (para_env_col)
     588          42 :       CALL para_env_col%from_split(para_env_RPA, color_col)
     589             : 
     590          42 :       CALL para_env_col%sum(iaia_RI_dp)
     591             : 
     592             :       ! convert the iaia_RI_dp into double-double precision
     593         124 :       ALLOCATE (iaia_RI(ncol_local))
     594        2722 :       DO iiB = 1, ncol_local
     595        2722 :          iaia_RI(iiB) = iaia_RI_dp(iiB)
     596             :       END DO
     597          42 :       DEALLOCATE (iaia_RI_dp)
     598             : 
     599             :       ! 4) calculate the right hand term, D_ia is the matrix containing the
     600             :       ! orbital energy differences, M_ia is the diagonal of the full RPA 'excitation'
     601             :       ! matrix
     602         124 :       ALLOCATE (D_ia(ncol_local))
     603             : 
     604          82 :       ALLOCATE (M_ia(ncol_local))
     605             : 
     606        2722 :       DO iiB = 1, ncol_local
     607        2680 :          i_global = col_indices(iiB)
     608             : 
     609        2680 :          iocc = MAX(1, i_global - 1)/virtual + 1
     610        2680 :          avirt = i_global - (iocc - 1)*virtual
     611        2680 :          eigen_diff = Eigenval(avirt + homo) - Eigenval(iocc)
     612             : 
     613        2722 :          D_ia(iiB) = eigen_diff
     614             :       END DO
     615             : 
     616        2722 :       DO iiB = 1, ncol_local
     617        2722 :          M_ia(iiB) = D_ia(iiB)*D_ia(iiB) + 2.0_dp*D_ia(iiB)*iaia_RI(iiB)
     618             :       END DO
     619             : 
     620          42 :       right_term_ref = 0.0_dp
     621        2722 :       DO iiB = 1, ncol_local
     622        2722 :          right_term_ref = right_term_ref + (SQRT(M_ia(iiB)) - D_ia(iiB) - iaia_RI(iiB))
     623             :       END DO
     624          42 :       right_term_ref = right_term_ref/2.0_dp
     625             : 
     626             :       ! sum the result with the processes of the RPA_group having the same row
     627          42 :       color_row = fm_mat_S%matrix_struct%context%mepos(1)
     628          42 :       ALLOCATE (para_env_row)
     629          42 :       CALL para_env_row%from_split(para_env_RPA, color_row)
     630             : 
     631             :       ! allocate communication array for rows
     632          42 :       CALL para_env_row%sum(right_term_ref)
     633             : 
     634          42 :       CALL mp_para_env_release(para_env_row)
     635             : 
     636          42 :       CALL timestop(handle)
     637             : 
     638          42 :    END SUBROUTINE calc_ia_ia_integrals
     639             : 
     640             : ! **************************************************************************************************
     641             : !> \brief ...
     642             : !> \param a_scaling ...
     643             : !> \param left_term ...
     644             : !> \param first_deriv ...
     645             : !> \param num_integ_points ...
     646             : !> \param my_open_shell ...
     647             : !> \param M_ia ...
     648             : !> \param cottj ...
     649             : !> \param wj ...
     650             : !> \param D_ia ...
     651             : !> \param D_ia_beta ...
     652             : !> \param M_ia_beta ...
     653             : !> \param ncol_local ...
     654             : !> \param ncol_local_beta ...
     655             : !> \param num_integ_group ...
     656             : !> \param color_rpa_group ...
     657             : !> \param para_env ...
     658             : !> \param para_env_col ...
     659             : !> \param para_env_col_beta ...
     660             : ! **************************************************************************************************
     661         426 :    SUBROUTINE calculate_objfunc(a_scaling, left_term, first_deriv, num_integ_points, my_open_shell, &
     662             :                                 M_ia, cottj, wj, D_ia, D_ia_beta, M_ia_beta, &
     663             :                                 ncol_local, ncol_local_beta, num_integ_group, color_rpa_group, &
     664             :                                 para_env, para_env_col, para_env_col_beta)
     665             :       REAL(KIND=dp), INTENT(IN)                          :: a_scaling
     666             :       REAL(KIND=dp), INTENT(INOUT)                       :: left_term, first_deriv
     667             :       INTEGER, INTENT(IN)                                :: num_integ_points
     668             :       LOGICAL, INTENT(IN)                                :: my_open_shell
     669             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     670             :          INTENT(IN)                                      :: M_ia, cottj, wj, D_ia, D_ia_beta, &
     671             :                                                             M_ia_beta
     672             :       INTEGER, INTENT(IN)                                :: ncol_local, ncol_local_beta, &
     673             :                                                             num_integ_group, color_rpa_group
     674             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env, para_env_col
     675             :       TYPE(mp_para_env_type), POINTER                    :: para_env_col_beta
     676             : 
     677             :       INTEGER                                            :: iiB, jquad
     678             :       REAL(KIND=dp)                                      :: first_deriv_beta, left_term_beta, omega
     679             : 
     680         426 :       left_term = 0.0_dp
     681         426 :       first_deriv = 0.0_dp
     682         426 :       left_term_beta = 0.0_dp
     683         426 :       first_deriv_beta = 0.0_dp
     684        4370 :       DO jquad = 1, num_integ_points
     685             :          ! parallelize over integration points
     686        3944 :          IF (MODULO(jquad, num_integ_group) /= color_rpa_group) CYCLE
     687        2172 :          omega = a_scaling*cottj(jquad)
     688             : 
     689      161964 :          DO iiB = 1, ncol_local
     690             :             ! parallelize over ia elements in the para_env_row group
     691      159792 :             IF (MODULO(iiB, para_env_col%num_pe) /= para_env_col%mepos) CYCLE
     692             :             ! calculate left_term
     693             :             left_term = left_term + wj(jquad)* &
     694             :                         (LOG(1.0_dp + (M_ia(iiB) - D_ia(iiB)**2)/(omega**2 + D_ia(iiB)**2)) - &
     695      144592 :                          (M_ia(iiB) - D_ia(iiB)**2)/(omega**2 + D_ia(iiB)**2))
     696             :             first_deriv = first_deriv + wj(jquad)*cottj(jquad)**2* &
     697      161964 :                           ((-M_ia(iiB) + D_ia(iiB)**2)**2/((omega**2 + D_ia(iiB)**2)**2*(omega**2 + M_ia(iiB))))
     698             :          END DO
     699             : 
     700        2598 :          IF (my_open_shell) THEN
     701       14170 :             DO iiB = 1, ncol_local_beta
     702             :                ! parallelize over ia elements in the para_env_row group
     703       13860 :                IF (MODULO(iiB, para_env_col_beta%num_pe) /= para_env_col_beta%mepos) CYCLE
     704             :                ! calculate left_term
     705             :                left_term_beta = left_term_beta + wj(jquad)* &
     706             :                                 (LOG(1.0_dp + (M_ia_beta(iiB) - D_ia_beta(iiB)**2)/(omega**2 + D_ia_beta(iiB)**2)) - &
     707       13860 :                                  (M_ia_beta(iiB) - D_ia_beta(iiB)**2)/(omega**2 + D_ia_beta(iiB)**2))
     708             :                first_deriv_beta = &
     709             :                   first_deriv_beta + wj(jquad)*cottj(jquad)**2* &
     710       14170 :                   ((-M_ia_beta(iiB) + D_ia_beta(iiB)**2)**2/((omega**2 + D_ia_beta(iiB)**2)**2*(omega**2 + M_ia_beta(iiB))))
     711             :             END DO
     712             :          END IF
     713             : 
     714             :       END DO
     715             : 
     716             :       ! sum the contribution from all proc, starting form the row group
     717         426 :       CALL para_env%sum(left_term)
     718         426 :       CALL para_env%sum(first_deriv)
     719             : 
     720         426 :       IF (my_open_shell) THEN
     721          68 :          CALL para_env%sum(left_term_beta)
     722          68 :          CALL para_env%sum(first_deriv_beta)
     723             : 
     724          68 :          left_term = left_term + left_term_beta
     725          68 :          first_deriv = first_deriv + first_deriv_beta
     726             :       END IF
     727             : 
     728         426 :    END SUBROUTINE calculate_objfunc
     729             : 
     730             : ! **************************************************************************************************
     731             : !> \brief Calculate integration weights for the tau grid (in dependency of the omega node)
     732             : !> \param num_integ_points ...
     733             : !> \param tau_tj ...
     734             : !> \param weights_cos_tf_t_to_w ...
     735             : !> \param omega_tj ...
     736             : !> \param E_min ...
     737             : !> \param E_max ...
     738             : !> \param max_error ...
     739             : !> \param num_points_per_magnitude ...
     740             : !> \param regularization ...
     741             : ! **************************************************************************************************
     742          70 :    SUBROUTINE get_l_sq_wghts_cos_tf_t_to_w(num_integ_points, tau_tj, weights_cos_tf_t_to_w, omega_tj, &
     743             :                                            E_min, E_max, max_error, num_points_per_magnitude, &
     744             :                                            regularization)
     745             : 
     746             :       INTEGER, INTENT(IN)                                :: num_integ_points
     747             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     748             :          INTENT(IN)                                      :: tau_tj
     749             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     750             :          INTENT(INOUT)                                   :: weights_cos_tf_t_to_w
     751             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     752             :          INTENT(IN)                                      :: omega_tj
     753             :       REAL(KIND=dp), INTENT(IN)                          :: E_min, E_max
     754             :       REAL(KIND=dp), INTENT(INOUT)                       :: max_error
     755             :       INTEGER, INTENT(IN)                                :: num_points_per_magnitude
     756             :       REAL(KIND=dp), INTENT(IN)                          :: regularization
     757             : 
     758             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_l_sq_wghts_cos_tf_t_to_w'
     759             : 
     760             :       INTEGER                                            :: handle, iii, info, jjj, jquad, lwork, &
     761             :                                                             num_x_nodes
     762          70 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: iwork
     763             :       REAL(KIND=dp)                                      :: multiplicator, omega
     764          70 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: sing_values, tau_wj_work, vec_UTy, work, &
     765             :                                                             x_values, y_values
     766          70 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: mat_A, mat_SinvVSinvSigma, &
     767          70 :                                                             mat_SinvVSinvT, mat_U
     768             : 
     769          70 :       CALL timeset(routineN, handle)
     770             : 
     771             :       ! take num_points_per_magnitude points per 10-interval
     772          70 :       num_x_nodes = (INT(LOG10(E_max/E_min)) + 1)*num_points_per_magnitude
     773             : 
     774             :       ! take at least as many x points as integration points to have clear
     775             :       ! input for the singular value decomposition
     776          70 :       num_x_nodes = MAX(num_x_nodes, num_integ_points)
     777             : 
     778         210 :       ALLOCATE (x_values(num_x_nodes))
     779       24070 :       x_values = 0.0_dp
     780         140 :       ALLOCATE (y_values(num_x_nodes))
     781       24070 :       y_values = 0.0_dp
     782         280 :       ALLOCATE (mat_A(num_x_nodes, num_integ_points))
     783      150976 :       mat_A = 0.0_dp
     784         210 :       ALLOCATE (tau_wj_work(num_integ_points))
     785         576 :       tau_wj_work = 0.0_dp
     786         140 :       ALLOCATE (sing_values(num_integ_points))
     787         576 :       sing_values = 0.0_dp
     788         280 :       ALLOCATE (mat_U(num_x_nodes, num_x_nodes))
     789     9144070 :       mat_U = 0.0_dp
     790         210 :       ALLOCATE (mat_SinvVSinvT(num_x_nodes, num_integ_points))
     791             : 
     792      150976 :       mat_SinvVSinvT = 0.0_dp
     793             :       ! double the value nessary for 'A' to achieve good performance
     794          70 :       lwork = 8*num_integ_points*num_integ_points + 12*num_integ_points + 2*num_x_nodes
     795         210 :       ALLOCATE (work(lwork))
     796      105230 :       work = 0.0_dp
     797         210 :       ALLOCATE (iwork(8*num_integ_points))
     798        4118 :       iwork = 0
     799         210 :       ALLOCATE (mat_SinvVSinvSigma(num_integ_points, num_x_nodes))
     800      174470 :       mat_SinvVSinvSigma = 0.0_dp
     801         140 :       ALLOCATE (vec_UTy(num_x_nodes))
     802       24070 :       vec_UTy = 0.0_dp
     803             : 
     804          70 :       max_error = 0.0_dp
     805             : 
     806             :       ! loop over all omega frequency points
     807         576 :       DO jquad = 1, num_integ_points
     808             : 
     809             :          ! set the x-values logarithmically in the interval [Emin,Emax]
     810         506 :          multiplicator = (E_max/E_min)**(1.0_dp/(REAL(num_x_nodes, KIND=dp) - 1.0_dp))
     811      150906 :          DO iii = 1, num_x_nodes
     812      150906 :             x_values(iii) = E_min*multiplicator**(iii - 1)
     813             :          END DO
     814             : 
     815         506 :          omega = omega_tj(jquad)
     816             : 
     817             :          ! y=2x/(x^2+omega_k^2)
     818      150906 :          DO iii = 1, num_x_nodes
     819      150906 :             y_values(iii) = 2.0_dp*x_values(iii)/((x_values(iii))**2 + omega**2)
     820             :          END DO
     821             : 
     822             :          ! calculate mat_A
     823        6892 :          DO jjj = 1, num_integ_points
     824     1590892 :             DO iii = 1, num_x_nodes
     825     1590386 :                mat_A(iii, jjj) = COS(omega*tau_tj(jjj))*EXP(-x_values(iii)*tau_tj(jjj))
     826             :             END DO
     827             :          END DO
     828             : 
     829             :          ! Singular value decomposition of mat_A
     830             :          CALL DGESDD('A', num_x_nodes, num_integ_points, mat_A, num_x_nodes, sing_values, mat_U, num_x_nodes, &
     831         506 :                      mat_SinvVSinvT, num_x_nodes, work, lwork, iwork, info)
     832             : 
     833         506 :          CPASSERT(info == 0)
     834             : 
     835             :          ! integration weights = V Sigma U^T y
     836             :          ! 1) V*Sigma
     837        6892 :          DO jjj = 1, num_integ_points
     838      114582 :             DO iii = 1, num_integ_points
     839             : !               mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)/sing_values(jjj)
     840             :                mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)*sing_values(jjj) &
     841      114076 :                                               /(regularization**2 + sing_values(jjj)**2)
     842             :             END DO
     843             :          END DO
     844             : 
     845             :          ! 2) U^T y
     846             :          CALL DGEMM('T', 'N', num_x_nodes, 1, num_x_nodes, 1.0_dp, mat_U, num_x_nodes, y_values, num_x_nodes, &
     847         506 :                     0.0_dp, vec_UTy, num_x_nodes)
     848             : 
     849             :          ! 3) (V*Sigma) * (U^T y)
     850             :          CALL DGEMM('N', 'N', num_integ_points, 1, num_x_nodes, 1.0_dp, mat_SinvVSinvSigma, num_integ_points, vec_UTy, &
     851         506 :                     num_x_nodes, 0.0_dp, tau_wj_work, num_integ_points)
     852             : 
     853        6892 :          weights_cos_tf_t_to_w(jquad, :) = tau_wj_work(:)
     854             : 
     855             :          CALL calc_max_error_fit_tau_grid_with_cosine(max_error, omega, tau_tj, tau_wj_work, x_values, &
     856         576 :                                                       y_values, num_integ_points, num_x_nodes)
     857             : 
     858             :       END DO ! jquad
     859             : 
     860           0 :       DEALLOCATE (x_values, y_values, mat_A, tau_wj_work, sing_values, mat_U, mat_SinvVSinvT, &
     861          70 :                   work, iwork, mat_SinvVSinvSigma, vec_UTy)
     862             : 
     863          70 :       CALL timestop(handle)
     864             : 
     865          70 :    END SUBROUTINE get_l_sq_wghts_cos_tf_t_to_w
     866             : 
     867             : ! **************************************************************************************************
     868             : !> \brief Calculate integration weights for the tau grid (in dependency of the omega node)
     869             : !> \param num_integ_points ...
     870             : !> \param tau_tj ...
     871             : !> \param weights_sin_tf_t_to_w ...
     872             : !> \param omega_tj ...
     873             : !> \param E_min ...
     874             : !> \param E_max ...
     875             : !> \param max_error ...
     876             : !> \param num_points_per_magnitude ...
     877             : !> \param regularization ...
     878             : ! **************************************************************************************************
     879          38 :    SUBROUTINE get_l_sq_wghts_sin_tf_t_to_w(num_integ_points, tau_tj, weights_sin_tf_t_to_w, omega_tj, &
     880             :                                            E_min, E_max, max_error, num_points_per_magnitude, regularization)
     881             : 
     882             :       INTEGER, INTENT(IN)                                :: num_integ_points
     883             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     884             :          INTENT(IN)                                      :: tau_tj
     885             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
     886             :          INTENT(INOUT)                                   :: weights_sin_tf_t_to_w
     887             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
     888             :          INTENT(IN)                                      :: omega_tj
     889             :       REAL(KIND=dp), INTENT(IN)                          :: E_min, E_max
     890             :       REAL(KIND=dp), INTENT(OUT)                         :: max_error
     891             :       INTEGER, INTENT(IN)                                :: num_points_per_magnitude
     892             :       REAL(KIND=dp), INTENT(IN)                          :: regularization
     893             : 
     894             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_l_sq_wghts_sin_tf_t_to_w'
     895             : 
     896             :       INTEGER                                            :: handle, iii, info, jjj, jquad, lwork, &
     897             :                                                             num_x_nodes
     898          38 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: iwork
     899             :       REAL(KIND=dp)                                      :: chi2_min_jquad, multiplicator, omega
     900          38 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: sing_values, tau_wj_work, vec_UTy, work, &
     901          38 :                                                             work_array, x_values, y_values
     902          38 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: mat_A, mat_SinvVSinvSigma, &
     903          38 :                                                             mat_SinvVSinvT, mat_U
     904             : 
     905          38 :       CALL timeset(routineN, handle)
     906             : 
     907             :       ! take num_points_per_magnitude points per 10-interval
     908          38 :       num_x_nodes = (INT(LOG10(E_max/E_min)) + 1)*num_points_per_magnitude
     909             : 
     910             :       ! take at least as many x points as integration points to have clear
     911             :       ! input for the singular value decomposition
     912          38 :       num_x_nodes = MAX(num_x_nodes, num_integ_points)
     913             : 
     914         114 :       ALLOCATE (x_values(num_x_nodes))
     915       12838 :       x_values = 0.0_dp
     916          76 :       ALLOCATE (y_values(num_x_nodes))
     917       12838 :       y_values = 0.0_dp
     918         152 :       ALLOCATE (mat_A(num_x_nodes, num_integ_points))
     919      119656 :       mat_A = 0.0_dp
     920         114 :       ALLOCATE (tau_wj_work(num_integ_points))
     921         456 :       tau_wj_work = 0.0_dp
     922         114 :       ALLOCATE (work_array(2*num_integ_points))
     923         874 :       work_array = 0.0_dp
     924          76 :       ALLOCATE (sing_values(num_integ_points))
     925         456 :       sing_values = 0.0_dp
     926         152 :       ALLOCATE (mat_U(num_x_nodes, num_x_nodes))
     927     4972838 :       mat_U = 0.0_dp
     928         114 :       ALLOCATE (mat_SinvVSinvT(num_x_nodes, num_integ_points))
     929             : 
     930      119656 :       mat_SinvVSinvT = 0.0_dp
     931             :       ! double the value nessary for 'A' to achieve good performance
     932          38 :       lwork = 8*num_integ_points*num_integ_points + 12*num_integ_points + 2*num_x_nodes
     933         114 :       ALLOCATE (work(lwork))
     934       79758 :       work = 0.0_dp
     935         114 :       ALLOCATE (iwork(8*num_integ_points))
     936        3382 :       iwork = 0
     937         114 :       ALLOCATE (mat_SinvVSinvSigma(num_integ_points, num_x_nodes))
     938      132038 :       mat_SinvVSinvSigma = 0.0_dp
     939          76 :       ALLOCATE (vec_UTy(num_x_nodes))
     940       12838 :       vec_UTy = 0.0_dp
     941             : 
     942          38 :       max_error = 0.0_dp
     943             : 
     944             :       ! loop over all omega frequency points
     945         456 :       DO jquad = 1, num_integ_points
     946             : 
     947         418 :          chi2_min_jquad = 100.0_dp
     948             : 
     949             :          ! set the x-values logarithmically in the interval [Emin,Emax]
     950         418 :          multiplicator = (E_max/E_min)**(1.0_dp/(REAL(num_x_nodes, KIND=dp) - 1.0_dp))
     951      119618 :          DO iii = 1, num_x_nodes
     952      119618 :             x_values(iii) = E_min*multiplicator**(iii - 1)
     953             :          END DO
     954             : 
     955         418 :          omega = omega_tj(jquad)
     956             : 
     957             :          ! y=2x/(x^2+omega_k^2)
     958      119618 :          DO iii = 1, num_x_nodes
     959             : !            y_values(iii) = 2.0_dp*x_values(iii)/((x_values(iii))**2+omega**2)
     960      119618 :             y_values(iii) = 2.0_dp*omega/((x_values(iii))**2 + omega**2)
     961             :          END DO
     962             : 
     963             :          ! calculate mat_A
     964        6556 :          DO jjj = 1, num_integ_points
     965     1501756 :             DO iii = 1, num_x_nodes
     966     1501338 :                mat_A(iii, jjj) = SIN(omega*tau_tj(jjj))*EXP(-x_values(iii)*tau_tj(jjj))
     967             :             END DO
     968             :          END DO
     969             : 
     970             :          ! Singular value decomposition of mat_A
     971             :          CALL DGESDD('A', num_x_nodes, num_integ_points, mat_A, num_x_nodes, sing_values, mat_U, num_x_nodes, &
     972         418 :                      mat_SinvVSinvT, num_x_nodes, work, lwork, iwork, info)
     973             : 
     974         418 :          CPASSERT(info == 0)
     975             : 
     976             :          ! integration weights = V Sigma U^T y
     977             :          ! 1) V*Sigma
     978        6556 :          DO jjj = 1, num_integ_points
     979      113534 :             DO iii = 1, num_integ_points
     980             : !               mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)/sing_values(jjj)
     981             :                mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)*sing_values(jjj) &
     982      113116 :                                               /(regularization**2 + sing_values(jjj)**2)
     983             :             END DO
     984             :          END DO
     985             : 
     986             :          ! 2) U^T y
     987             :          CALL DGEMM('T', 'N', num_x_nodes, 1, num_x_nodes, 1.0_dp, mat_U, num_x_nodes, y_values, num_x_nodes, &
     988         418 :                     0.0_dp, vec_UTy, num_x_nodes)
     989             : 
     990             :          ! 3) (V*Sigma) * (U^T y)
     991             :          CALL DGEMM('N', 'N', num_integ_points, 1, num_x_nodes, 1.0_dp, mat_SinvVSinvSigma, num_integ_points, vec_UTy, &
     992         418 :                     num_x_nodes, 0.0_dp, tau_wj_work, num_integ_points)
     993             : 
     994        6556 :          weights_sin_tf_t_to_w(jquad, :) = tau_wj_work(:)
     995             : 
     996             :          CALL calc_max_error_fit_tau_grid_with_sine(max_error, omega, tau_tj, tau_wj_work, x_values, &
     997         456 :                                                     y_values, num_integ_points, num_x_nodes)
     998             : 
     999             :       END DO ! jquad
    1000             : 
    1001           0 :       DEALLOCATE (x_values, y_values, mat_A, tau_wj_work, work_array, sing_values, mat_U, mat_SinvVSinvT, &
    1002          38 :                   work, iwork, mat_SinvVSinvSigma, vec_UTy)
    1003             : 
    1004          38 :       CALL timestop(handle)
    1005             : 
    1006          38 :    END SUBROUTINE get_l_sq_wghts_sin_tf_t_to_w
    1007             : 
    1008             : ! **************************************************************************************************
    1009             : !> \brief ...
    1010             : !> \param max_error ...
    1011             : !> \param omega ...
    1012             : !> \param tau_tj ...
    1013             : !> \param tau_wj_work ...
    1014             : !> \param x_values ...
    1015             : !> \param y_values ...
    1016             : !> \param num_integ_points ...
    1017             : !> \param num_x_nodes ...
    1018             : ! **************************************************************************************************
    1019         506 :    PURE SUBROUTINE calc_max_error_fit_tau_grid_with_cosine(max_error, omega, tau_tj, tau_wj_work, x_values, &
    1020             :                                                            y_values, num_integ_points, num_x_nodes)
    1021             : 
    1022             :       REAL(KIND=dp), INTENT(INOUT)                       :: max_error, omega
    1023             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1024             :          INTENT(IN)                                      :: tau_tj, tau_wj_work, x_values, y_values
    1025             :       INTEGER, INTENT(IN)                                :: num_integ_points, num_x_nodes
    1026             : 
    1027             :       INTEGER                                            :: kkk
    1028             :       REAL(KIND=dp)                                      :: func_val, func_val_temp, max_error_tmp
    1029             : 
    1030         506 :       max_error_tmp = 0.0_dp
    1031             : 
    1032      150906 :       DO kkk = 1, num_x_nodes
    1033             : 
    1034             :          func_val = 0.0_dp
    1035             : 
    1036      150400 :          CALL eval_fit_func_tau_grid_cosine(func_val, x_values(kkk), num_integ_points, tau_tj, tau_wj_work, omega)
    1037             : 
    1038      150906 :          IF (ABS(y_values(kkk) - func_val) > max_error_tmp) THEN
    1039        2486 :             max_error_tmp = ABS(y_values(kkk) - func_val)
    1040        2486 :             func_val_temp = func_val
    1041             :          END IF
    1042             : 
    1043             :       END DO
    1044             : 
    1045         506 :       IF (max_error_tmp > max_error) THEN
    1046             : 
    1047         124 :          max_error = max_error_tmp
    1048             : 
    1049             :       END IF
    1050             : 
    1051         506 :    END SUBROUTINE calc_max_error_fit_tau_grid_with_cosine
    1052             : 
    1053             : ! **************************************************************************************************
    1054             : !> \brief Evaluate fit function when calculating tau grid for cosine transform
    1055             : !> \param func_val ...
    1056             : !> \param x_value ...
    1057             : !> \param num_integ_points ...
    1058             : !> \param tau_tj ...
    1059             : !> \param tau_wj_work ...
    1060             : !> \param omega ...
    1061             : ! **************************************************************************************************
    1062      150400 :    PURE SUBROUTINE eval_fit_func_tau_grid_cosine(func_val, x_value, num_integ_points, tau_tj, tau_wj_work, omega)
    1063             : 
    1064             :       REAL(KIND=dp), INTENT(OUT)                         :: func_val
    1065             :       REAL(KIND=dp), INTENT(IN)                          :: x_value
    1066             :       INTEGER, INTENT(IN)                                :: num_integ_points
    1067             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1068             :          INTENT(IN)                                      :: tau_tj, tau_wj_work
    1069             :       REAL(KIND=dp), INTENT(IN)                          :: omega
    1070             : 
    1071             :       INTEGER                                            :: iii
    1072             : 
    1073      150400 :       func_val = 0.0_dp
    1074             : 
    1075     1734400 :       DO iii = 1, num_integ_points
    1076             : 
    1077             :          ! calculate value of the fit function
    1078     1734400 :          func_val = func_val + tau_wj_work(iii)*COS(omega*tau_tj(iii))*EXP(-x_value*tau_tj(iii))
    1079             : 
    1080             :       END DO
    1081             : 
    1082      150400 :    END SUBROUTINE eval_fit_func_tau_grid_cosine
    1083             : 
    1084             : ! **************************************************************************************************
    1085             : !> \brief Evaluate fit function when calculating tau grid for sine transform
    1086             : !> \param func_val ...
    1087             : !> \param x_value ...
    1088             : !> \param num_integ_points ...
    1089             : !> \param tau_tj ...
    1090             : !> \param tau_wj_work ...
    1091             : !> \param omega ...
    1092             : ! **************************************************************************************************
    1093      119200 :    PURE SUBROUTINE eval_fit_func_tau_grid_sine(func_val, x_value, num_integ_points, tau_tj, tau_wj_work, omega)
    1094             : 
    1095             :       REAL(KIND=dp), INTENT(INOUT)                       :: func_val
    1096             :       REAL(KIND=dp), INTENT(IN)                          :: x_value
    1097             :       INTEGER, INTENT(in)                                :: num_integ_points
    1098             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1099             :          INTENT(IN)                                      :: tau_tj, tau_wj_work
    1100             :       REAL(KIND=dp), INTENT(IN)                          :: omega
    1101             : 
    1102             :       INTEGER                                            :: iii
    1103             : 
    1104      119200 :       func_val = 0.0_dp
    1105             : 
    1106     1614400 :       DO iii = 1, num_integ_points
    1107             : 
    1108             :          ! calculate value of the fit function
    1109     1614400 :          func_val = func_val + tau_wj_work(iii)*SIN(omega*tau_tj(iii))*EXP(-x_value*tau_tj(iii))
    1110             : 
    1111             :       END DO
    1112             : 
    1113      119200 :    END SUBROUTINE eval_fit_func_tau_grid_sine
    1114             : 
    1115             : ! **************************************************************************************************
    1116             : !> \brief ...
    1117             : !> \param max_error ...
    1118             : !> \param omega ...
    1119             : !> \param tau_tj ...
    1120             : !> \param tau_wj_work ...
    1121             : !> \param x_values ...
    1122             : !> \param y_values ...
    1123             : !> \param num_integ_points ...
    1124             : !> \param num_x_nodes ...
    1125             : ! **************************************************************************************************
    1126         418 :    PURE SUBROUTINE calc_max_error_fit_tau_grid_with_sine(max_error, omega, tau_tj, tau_wj_work, x_values, &
    1127             :                                                          y_values, num_integ_points, num_x_nodes)
    1128             : 
    1129             :       REAL(KIND=dp), INTENT(INOUT)                       :: max_error, omega
    1130             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1131             :          INTENT(IN)                                      :: tau_tj, tau_wj_work, x_values, y_values
    1132             :       INTEGER, INTENT(IN)                                :: num_integ_points, num_x_nodes
    1133             : 
    1134             :       INTEGER                                            :: kkk
    1135             :       REAL(KIND=dp)                                      :: func_val, func_val_temp, max_error_tmp
    1136             : 
    1137         418 :       max_error_tmp = 0.0_dp
    1138             : 
    1139      119618 :       DO kkk = 1, num_x_nodes
    1140             : 
    1141      119200 :          func_val = 0.0_dp
    1142             : 
    1143      119200 :          CALL eval_fit_func_tau_grid_sine(func_val, x_values(kkk), num_integ_points, tau_tj, tau_wj_work, omega)
    1144             : 
    1145      119618 :          IF (ABS(y_values(kkk) - func_val) > max_error_tmp) THEN
    1146        2410 :             max_error_tmp = ABS(y_values(kkk) - func_val)
    1147        2410 :             func_val_temp = func_val
    1148             :          END IF
    1149             : 
    1150             :       END DO
    1151             : 
    1152         418 :       IF (max_error_tmp > max_error) THEN
    1153             : 
    1154          42 :          max_error = max_error_tmp
    1155             : 
    1156             :       END IF
    1157             : 
    1158         418 :    END SUBROUTINE calc_max_error_fit_tau_grid_with_sine
    1159             : 
    1160             : ! **************************************************************************************************
    1161             : !> \brief test the singular value decomposition for the computation of integration weights for the
    1162             : !>         Fourier transform between time and frequency grid in cubic-scaling RPA
    1163             : !> \param nR ...
    1164             : !> \param iw ...
    1165             : ! **************************************************************************************************
    1166           0 :    SUBROUTINE test_least_square_ft(nR, iw)
    1167             :       INTEGER, INTENT(IN)                                :: nR, iw
    1168             : 
    1169             :       INTEGER                                            :: ierr, iR, jquad, num_integ_points
    1170             :       REAL(KIND=dp)                                      :: max_error, multiplicator, Rc, Rc_max
    1171           0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: tau_tj, tau_wj, tj, wj, x_tw
    1172           0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: weights_cos_tf_t_to_w
    1173             : 
    1174           0 :       Rc_max = 1.0E+7
    1175             : 
    1176           0 :       multiplicator = Rc_max**(1.0_dp/(REAL(nR, KIND=dp) - 1.0_dp))
    1177             : 
    1178           0 :       DO num_integ_points = 1, 20
    1179             : 
    1180           0 :          ALLOCATE (x_tw(2*num_integ_points))
    1181           0 :          x_tw = 0.0_dp
    1182           0 :          ALLOCATE (tau_tj(num_integ_points))
    1183           0 :          tau_tj = 0.0_dp
    1184           0 :          ALLOCATE (weights_cos_tf_t_to_w(num_integ_points, num_integ_points))
    1185           0 :          weights_cos_tf_t_to_w = 0.0_dp
    1186           0 :          ALLOCATE (tau_wj(num_integ_points))
    1187           0 :          tau_wj = 0.0_dp
    1188           0 :          ALLOCATE (tj(num_integ_points))
    1189           0 :          tj = 0.0_dp
    1190           0 :          ALLOCATE (wj(num_integ_points))
    1191           0 :          wj = 0.0_dp
    1192             : 
    1193           0 :          DO iR = 0, nR - 1
    1194             : 
    1195           0 :             Rc = 2.0_dp*multiplicator**iR
    1196             : 
    1197           0 :             ierr = 0
    1198           0 :             CALL get_rpa_minimax_coeff(num_integ_points, Rc, x_tw, ierr, print_warning=.FALSE.)
    1199             : 
    1200           0 :             DO jquad = 1, num_integ_points
    1201           0 :                tj(jquad) = x_tw(jquad)
    1202           0 :                wj(jquad) = x_tw(jquad + num_integ_points)
    1203             :             END DO
    1204             : 
    1205           0 :             x_tw = 0.0_dp
    1206             : 
    1207           0 :             CALL get_exp_minimax_coeff(num_integ_points, Rc, x_tw)
    1208             : 
    1209           0 :             DO jquad = 1, num_integ_points
    1210           0 :                tau_tj(jquad) = x_tw(jquad)/2.0_dp
    1211           0 :                tau_wj(jquad) = x_tw(jquad + num_integ_points)/2.0_dp
    1212             :             END DO
    1213             : 
    1214             :             CALL get_l_sq_wghts_cos_tf_t_to_w(num_integ_points, tau_tj, &
    1215             :                                               weights_cos_tf_t_to_w, tj, &
    1216           0 :                                               1.0_dp, Rc, max_error, 200, 0.0_dp)
    1217             : 
    1218           0 :             IF (iw > 0) THEN
    1219           0 :                WRITE (iw, '(T2, I3, F12.1, ES12.3)') num_integ_points, Rc, max_error
    1220             :             END IF
    1221             : 
    1222             :          END DO
    1223             : 
    1224           0 :          DEALLOCATE (x_tw, tau_tj, weights_cos_tf_t_to_w, tau_wj, wj, tj)
    1225             : 
    1226             :       END DO
    1227             : 
    1228           0 :    END SUBROUTINE test_least_square_ft
    1229             : 
    1230             : ! **************************************************************************************************
    1231             : !> \brief ...
    1232             : !> \param num_integ_points ...
    1233             : !> \param tau_tj ...
    1234             : !> \param weights_cos_tf_w_to_t ...
    1235             : !> \param omega_tj ...
    1236             : !> \param E_min ...
    1237             : !> \param E_max ...
    1238             : !> \param max_error ...
    1239             : !> \param num_points_per_magnitude ...
    1240             : !> \param regularization ...
    1241             : ! **************************************************************************************************
    1242          70 :    SUBROUTINE get_l_sq_wghts_cos_tf_w_to_t(num_integ_points, tau_tj, weights_cos_tf_w_to_t, omega_tj, &
    1243             :                                            E_min, E_max, max_error, num_points_per_magnitude, regularization)
    1244             : 
    1245             :       INTEGER, INTENT(IN)                                :: num_integ_points
    1246             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1247             :          INTENT(IN)                                      :: tau_tj
    1248             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
    1249             :          INTENT(INOUT)                                   :: weights_cos_tf_w_to_t
    1250             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1251             :          INTENT(IN)                                      :: omega_tj
    1252             :       REAL(KIND=dp), INTENT(IN)                          :: E_min, E_max
    1253             :       REAL(KIND=dp), INTENT(INOUT)                       :: max_error
    1254             :       INTEGER, INTENT(IN)                                :: num_points_per_magnitude
    1255             :       REAL(KIND=dp), INTENT(IN)                          :: regularization
    1256             : 
    1257             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'get_l_sq_wghts_cos_tf_w_to_t'
    1258             : 
    1259             :       INTEGER                                            :: handle, iii, info, jjj, jquad, lwork, &
    1260             :                                                             num_x_nodes
    1261          70 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: iwork
    1262             :       REAL(KIND=dp)                                      :: chi2_min_jquad, multiplicator, omega, &
    1263             :                                                             tau, x_value
    1264          70 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: omega_wj_work, sing_values, vec_UTy, &
    1265          70 :                                                             work, work_array, x_values, y_values
    1266          70 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: mat_A, mat_SinvVSinvSigma, &
    1267          70 :                                                             mat_SinvVSinvT, mat_U
    1268             : 
    1269          70 :       CALL timeset(routineN, handle)
    1270             : 
    1271             :       ! take num_points_per_magnitude points per 10-interval
    1272          70 :       num_x_nodes = (INT(LOG10(E_max/E_min)) + 1)*num_points_per_magnitude
    1273             : 
    1274             :       ! take at least as many x points as integration points to have clear
    1275             :       ! input for the singular value decomposition
    1276          70 :       num_x_nodes = MAX(num_x_nodes, num_integ_points)
    1277             : 
    1278         210 :       ALLOCATE (x_values(num_x_nodes))
    1279       24070 :       x_values = 0.0_dp
    1280         140 :       ALLOCATE (y_values(num_x_nodes))
    1281       24070 :       y_values = 0.0_dp
    1282         280 :       ALLOCATE (mat_A(num_x_nodes, num_integ_points))
    1283      150976 :       mat_A = 0.0_dp
    1284         210 :       ALLOCATE (omega_wj_work(num_integ_points))
    1285         576 :       omega_wj_work = 0.0_dp
    1286         210 :       ALLOCATE (work_array(2*num_integ_points))
    1287        1082 :       work_array = 0.0_dp
    1288         140 :       ALLOCATE (sing_values(num_integ_points))
    1289         576 :       sing_values = 0.0_dp
    1290         280 :       ALLOCATE (mat_U(num_x_nodes, num_x_nodes))
    1291     9144070 :       mat_U = 0.0_dp
    1292         210 :       ALLOCATE (mat_SinvVSinvT(num_x_nodes, num_integ_points))
    1293             : 
    1294      150976 :       mat_SinvVSinvT = 0.0_dp
    1295             :       ! double the value nessary for 'A' to achieve good performance
    1296          70 :       lwork = 8*num_integ_points*num_integ_points + 12*num_integ_points + 2*num_x_nodes
    1297         210 :       ALLOCATE (work(lwork))
    1298      105230 :       work = 0.0_dp
    1299         210 :       ALLOCATE (iwork(8*num_integ_points))
    1300        4118 :       iwork = 0
    1301         210 :       ALLOCATE (mat_SinvVSinvSigma(num_integ_points, num_x_nodes))
    1302      174470 :       mat_SinvVSinvSigma = 0.0_dp
    1303         140 :       ALLOCATE (vec_UTy(num_x_nodes))
    1304       24070 :       vec_UTy = 0.0_dp
    1305             : 
    1306             :       ! set the x-values logarithmically in the interval [Emin,Emax]
    1307          70 :       multiplicator = (E_max/E_min)**(1.0_dp/(REAL(num_x_nodes, KIND=dp) - 1.0_dp))
    1308       24070 :       DO iii = 1, num_x_nodes
    1309       24070 :          x_values(iii) = E_min*multiplicator**(iii - 1)
    1310             :       END DO
    1311             : 
    1312          70 :       max_error = 0.0_dp
    1313             : 
    1314             :       ! loop over all tau time points
    1315         576 :       DO jquad = 1, num_integ_points
    1316             : 
    1317         506 :          chi2_min_jquad = 100.0_dp
    1318             : 
    1319         506 :          tau = tau_tj(jquad)
    1320             : 
    1321             :          ! y=exp(-x*|tau_k|)
    1322      150906 :          DO iii = 1, num_x_nodes
    1323      150906 :             y_values(iii) = EXP(-x_values(iii)*tau)
    1324             :          END DO
    1325             : 
    1326             :          ! calculate mat_A
    1327        6892 :          DO jjj = 1, num_integ_points
    1328     1590892 :             DO iii = 1, num_x_nodes
    1329     1584000 :                omega = omega_tj(jjj)
    1330     1584000 :                x_value = x_values(iii)
    1331     1590386 :                mat_A(iii, jjj) = COS(tau*omega)*2.0_dp*x_value/(x_value**2 + omega**2)
    1332             :             END DO
    1333             :          END DO
    1334             : 
    1335             :          ! Singular value decomposition of mat_A
    1336             :          CALL DGESDD('A', num_x_nodes, num_integ_points, mat_A, num_x_nodes, sing_values, mat_U, num_x_nodes, &
    1337         506 :                      mat_SinvVSinvT, num_x_nodes, work, lwork, iwork, info)
    1338             : 
    1339         506 :          CPASSERT(info == 0)
    1340             : 
    1341             :          ! integration weights = V Sigma U^T y
    1342             :          ! 1) V*Sigma
    1343        6892 :          DO jjj = 1, num_integ_points
    1344      114582 :             DO iii = 1, num_integ_points
    1345             : !               mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)/sing_values(jjj)
    1346             :                mat_SinvVSinvSigma(iii, jjj) = mat_SinvVSinvT(jjj, iii)*sing_values(jjj) &
    1347      114076 :                                               /(regularization**2 + sing_values(jjj)**2)
    1348             :             END DO
    1349             :          END DO
    1350             : 
    1351             :          ! 2) U^T y
    1352             :          CALL DGEMM('T', 'N', num_x_nodes, 1, num_x_nodes, 1.0_dp, mat_U, num_x_nodes, y_values, num_x_nodes, &
    1353         506 :                     0.0_dp, vec_UTy, num_x_nodes)
    1354             : 
    1355             :          ! 3) (V*Sigma) * (U^T y)
    1356             :          CALL DGEMM('N', 'N', num_integ_points, 1, num_x_nodes, 1.0_dp, mat_SinvVSinvSigma, num_integ_points, vec_UTy, &
    1357         506 :                     num_x_nodes, 0.0_dp, omega_wj_work, num_integ_points)
    1358             : 
    1359        6892 :          weights_cos_tf_w_to_t(jquad, :) = omega_wj_work(:)
    1360             : 
    1361             :          CALL calc_max_error_fit_omega_grid_with_cosine(max_error, tau, omega_tj, omega_wj_work, x_values, &
    1362         576 :                                                         y_values, num_integ_points, num_x_nodes)
    1363             : 
    1364             :       END DO ! jquad
    1365             : 
    1366           0 :       DEALLOCATE (x_values, y_values, mat_A, omega_wj_work, work_array, sing_values, mat_U, mat_SinvVSinvT, &
    1367          70 :                   work, iwork, mat_SinvVSinvSigma, vec_UTy)
    1368             : 
    1369          70 :       CALL timestop(handle)
    1370             : 
    1371          70 :    END SUBROUTINE get_l_sq_wghts_cos_tf_w_to_t
    1372             : 
    1373             : ! **************************************************************************************************
    1374             : !> \brief ...
    1375             : !> \param max_error ...
    1376             : !> \param tau ...
    1377             : !> \param omega_tj ...
    1378             : !> \param omega_wj_work ...
    1379             : !> \param x_values ...
    1380             : !> \param y_values ...
    1381             : !> \param num_integ_points ...
    1382             : !> \param num_x_nodes ...
    1383             : ! **************************************************************************************************
    1384         506 :    SUBROUTINE calc_max_error_fit_omega_grid_with_cosine(max_error, tau, omega_tj, omega_wj_work, x_values, &
    1385             :                                                         y_values, num_integ_points, num_x_nodes)
    1386             : 
    1387             :       REAL(KIND=dp), INTENT(INOUT)                       :: max_error
    1388             :       REAL(KIND=dp), INTENT(IN)                          :: tau
    1389             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1390             :          INTENT(IN)                                      :: omega_tj, omega_wj_work, x_values, &
    1391             :                                                             y_values
    1392             :       INTEGER, INTENT(IN)                                :: num_integ_points, num_x_nodes
    1393             : 
    1394             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calc_max_error_fit_omega_grid_with_cosine'
    1395             : 
    1396             :       INTEGER                                            :: handle, kkk
    1397             :       REAL(KIND=dp)                                      :: func_val, func_val_temp, max_error_tmp
    1398             : 
    1399         506 :       CALL timeset(routineN, handle)
    1400             : 
    1401         506 :       max_error_tmp = 0.0_dp
    1402             : 
    1403      150906 :       DO kkk = 1, num_x_nodes
    1404             : 
    1405             :          func_val = 0.0_dp
    1406             : 
    1407      150400 :          CALL eval_fit_func_omega_grid_cosine(func_val, x_values(kkk), num_integ_points, omega_tj, omega_wj_work, tau)
    1408             : 
    1409      150906 :          IF (ABS(y_values(kkk) - func_val) > max_error_tmp) THEN
    1410        4228 :             max_error_tmp = ABS(y_values(kkk) - func_val)
    1411        4228 :             func_val_temp = func_val
    1412             :          END IF
    1413             : 
    1414             :       END DO
    1415             : 
    1416         506 :       IF (max_error_tmp > max_error) THEN
    1417             : 
    1418         140 :          max_error = max_error_tmp
    1419             : 
    1420             :       END IF
    1421             : 
    1422         506 :       CALL timestop(handle)
    1423             : 
    1424         506 :    END SUBROUTINE calc_max_error_fit_omega_grid_with_cosine
    1425             : 
    1426             : ! **************************************************************************************************
    1427             : !> \brief ...
    1428             : !> \param func_val ...
    1429             : !> \param x_value ...
    1430             : !> \param num_integ_points ...
    1431             : !> \param omega_tj ...
    1432             : !> \param omega_wj_work ...
    1433             : !> \param tau ...
    1434             : ! **************************************************************************************************
    1435      150400 :    PURE SUBROUTINE eval_fit_func_omega_grid_cosine(func_val, x_value, num_integ_points, omega_tj, omega_wj_work, tau)
    1436             :       REAL(KIND=dp), INTENT(OUT)                         :: func_val
    1437             :       REAL(KIND=dp), INTENT(IN)                          :: x_value
    1438             :       INTEGER, INTENT(IN)                                :: num_integ_points
    1439             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
    1440             :          INTENT(IN)                                      :: omega_tj, omega_wj_work
    1441             :       REAL(KIND=dp), INTENT(IN)                          :: tau
    1442             : 
    1443             :       INTEGER                                            :: iii
    1444             :       REAL(KIND=dp)                                      :: omega
    1445             : 
    1446      150400 :       func_val = 0.0_dp
    1447             : 
    1448     1734400 :       DO iii = 1, num_integ_points
    1449             : 
    1450             :          ! calculate value of the fit function
    1451     1584000 :          omega = omega_tj(iii)
    1452     1734400 :          func_val = func_val + omega_wj_work(iii)*COS(tau*omega)*2.0_dp*x_value/(x_value**2 + omega**2)
    1453             : 
    1454             :       END DO
    1455             : 
    1456      150400 :    END SUBROUTINE eval_fit_func_omega_grid_cosine
    1457             : 
    1458             : ! **************************************************************************************************
    1459             : !> \brief ...
    1460             : !> \param qs_env ...
    1461             : !> \param para_env ...
    1462             : !> \param gap ...
    1463             : !> \param max_eig_diff ...
    1464             : !> \param e_fermi ...
    1465             : ! **************************************************************************************************
    1466           8 :    SUBROUTINE gap_and_max_eig_diff_kpoints(qs_env, para_env, gap, max_eig_diff, e_fermi)
    1467             : 
    1468             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1469             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    1470             :       REAL(KIND=dp), INTENT(OUT)                         :: gap, max_eig_diff, e_fermi
    1471             : 
    1472             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'gap_and_max_eig_diff_kpoints'
    1473             : 
    1474             :       INTEGER                                            :: handle, homo, ikpgr, ispin, kplocal, &
    1475             :                                                             nmo, nspin
    1476             :       INTEGER, DIMENSION(2)                              :: kp_range
    1477             :       REAL(KIND=dp)                                      :: e_homo, e_homo_temp, e_lumo, e_lumo_temp
    1478             :       REAL(KIND=dp), DIMENSION(3)                        :: tmp
    1479           4 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: eigenvalues
    1480             :       TYPE(kpoint_env_type), POINTER                     :: kp
    1481             :       TYPE(kpoint_type), POINTER                         :: kpoint
    1482             :       TYPE(mo_set_type), POINTER                         :: mo_set
    1483             : 
    1484           4 :       CALL timeset(routineN, handle)
    1485             : 
    1486             :       CALL get_qs_env(qs_env, &
    1487           4 :                       kpoints=kpoint)
    1488             : 
    1489           4 :       mo_set => kpoint%kp_env(1)%kpoint_env%mos(1, 1)
    1490           4 :       CALL get_mo_set(mo_set, nmo=nmo)
    1491             : 
    1492           4 :       CALL get_kpoint_info(kpoint, kp_range=kp_range)
    1493           4 :       kplocal = kp_range(2) - kp_range(1) + 1
    1494             : 
    1495           4 :       gap = 1000.0_dp
    1496           4 :       max_eig_diff = 0.0_dp
    1497           4 :       e_homo = -1000.0_dp
    1498           4 :       e_lumo = 1000.0_dp
    1499             : 
    1500          12 :       DO ikpgr = 1, kplocal
    1501           8 :          kp => kpoint%kp_env(ikpgr)%kpoint_env
    1502           8 :          nspin = SIZE(kp%mos, 2)
    1503          20 :          DO ispin = 1, nspin
    1504           8 :             mo_set => kp%mos(1, ispin)
    1505           8 :             CALL get_mo_set(mo_set, eigenvalues=eigenvalues, homo=homo)
    1506           8 :             e_homo_temp = eigenvalues(homo)
    1507           8 :             e_lumo_temp = eigenvalues(homo + 1)
    1508             : 
    1509           8 :             IF (e_homo_temp > e_homo) e_homo = e_homo_temp
    1510           8 :             IF (e_lumo_temp < e_lumo) e_lumo = e_lumo_temp
    1511          24 :             IF (eigenvalues(nmo) - eigenvalues(1) > max_eig_diff) max_eig_diff = eigenvalues(nmo) - eigenvalues(1)
    1512             : 
    1513             :          END DO
    1514             :       END DO
    1515             : 
    1516             :       ! Collect all three numbers in an array
    1517             :       ! Reverse sign of lumo to reduce number of MPI calls
    1518           4 :       tmp(1) = e_homo
    1519           4 :       tmp(2) = -e_lumo
    1520           4 :       tmp(3) = max_eig_diff
    1521           4 :       CALL para_env%max(tmp)
    1522             : 
    1523           4 :       gap = -tmp(2) - tmp(1)
    1524           4 :       e_fermi = (tmp(1) - tmp(2))*0.5_dp
    1525           4 :       max_eig_diff = tmp(3)
    1526             : 
    1527           4 :       CALL timestop(handle)
    1528             : 
    1529           4 :    END SUBROUTINE
    1530             : 
    1531             : ! **************************************************************************************************
    1532             : !> \brief returns minimal and maximal energy values for the E_range for the minimax grid selection
    1533             : !> \param qs_env ...
    1534             : !> \param para_env ...
    1535             : !> \param homo index of the homo level for the respective spin channel
    1536             : !> \param Eigenval eigenvalues
    1537             : !> \param do_ri_sos_laplace_mp2 flag for SOS-MP2
    1538             : !> \param do_kpoints_cubic_RPA flag for cubic-scaling RPA with k-points
    1539             : !> \param Emin minimal eigenvalue difference (gap of the system)
    1540             : !> \param Emax maximal eigenvalue difference
    1541             : !> \param e_fermi Fermi level
    1542             : ! **************************************************************************************************
    1543         200 :    SUBROUTINE init_greenx_grids(qs_env, para_env, homo, Eigenval, do_ri_sos_laplace_mp2, &
    1544             :                                 do_kpoints_cubic_RPA, Emin, Emax, e_fermi)
    1545             : 
    1546             :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1547             :       TYPE(mp_para_env_type), INTENT(IN)                 :: para_env
    1548             :       INTEGER, DIMENSION(:), INTENT(IN)                  :: homo
    1549             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: Eigenval
    1550             :       LOGICAL, INTENT(IN)                                :: do_ri_sos_laplace_mp2, &
    1551             :                                                             do_kpoints_cubic_RPA
    1552             :       REAL(KIND=dp), INTENT(OUT)                         :: Emin, Emax, e_fermi
    1553             : 
    1554             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'init_greenx_grids'
    1555             : 
    1556             :       INTEGER                                            :: handle, ispin, nspins
    1557             :       LOGICAL                                            :: my_do_kpoints, my_open_shell
    1558             :       REAL(KIND=dp)                                      :: my_E_Range
    1559             :       TYPE(section_vals_type), POINTER                   :: input
    1560             : 
    1561         200 :       CALL timeset(routineN, handle)
    1562             :       ! Test for spin unrestricted
    1563         200 :       nspins = SIZE(homo)
    1564         200 :       my_open_shell = (nspins == 2)
    1565             : 
    1566             :       ! Test whether all necessary variables are available
    1567         200 :       my_do_kpoints = .FALSE.
    1568         200 :       IF (.NOT. do_ri_sos_laplace_mp2) THEN
    1569         142 :          my_do_kpoints = do_kpoints_cubic_RPA
    1570             :       END IF
    1571             : 
    1572         142 :       IF (my_do_kpoints) THEN
    1573           4 :          CALL gap_and_max_eig_diff_kpoints(qs_env, para_env, Emin, Emax, e_fermi)
    1574             :          my_E_Range = Emax/Emin
    1575             :       ELSE
    1576         196 :          IF (qs_env%mp2_env%E_range <= 1.0_dp .OR. qs_env%mp2_env%E_gap <= 0.0_dp) THEN
    1577         150 :             Emin = HUGE(dp)
    1578         150 :             Emax = 0.0_dp
    1579         336 :             DO ispin = 1, nspins
    1580         336 :                IF (homo(ispin) > 0) THEN
    1581         182 :                   Emin = MIN(Emin, Eigenval(homo(ispin) + 1, 1, ispin) - Eigenval(homo(ispin), 1, ispin))
    1582       14640 :                   Emax = MAX(Emax, MAXVAL(Eigenval(:, :, ispin)) - MINVAL(Eigenval(:, :, ispin)))
    1583             :                END IF
    1584             :             END DO
    1585         150 :             my_E_Range = Emax/Emin
    1586         150 :             qs_env%mp2_env%e_range = my_e_range
    1587         150 :             qs_env%mp2_env%e_gap = Emin
    1588             : 
    1589         150 :             CALL get_qs_env(qs_env, input=input)
    1590         150 :             CALL section_vals_val_set(input, "DFT%XC%WF_CORRELATION%E_RANGE", r_val=my_e_range)
    1591         150 :             CALL section_vals_val_set(input, "DFT%XC%WF_CORRELATION%E_GAP", r_val=emin)
    1592             :          ELSE
    1593             :             my_E_range = qs_env%mp2_env%E_range
    1594          46 :             Emin = qs_env%mp2_env%E_gap
    1595          46 :             Emax = Emin*my_E_range
    1596             :          END IF
    1597             :       END IF
    1598             : 
    1599             :       ! When we perform SOS-MP2, we need an additional factor of 2 for the energies (compare with mp2_laplace.F)
    1600             :       ! We do not need weights etc. for the cosine transform
    1601             :       ! We do not scale Emax because it is not needed for SOS-MP2
    1602         200 :       IF (do_ri_sos_laplace_mp2) THEN
    1603          58 :          Emin = Emin*2.0_dp
    1604             :       END IF
    1605             : 
    1606         200 :       CALL timestop(handle)
    1607         200 :    END SUBROUTINE
    1608             : 
    1609             : END MODULE mp2_grids

Generated by: LCOV version 1.15