LCOV - code coverage report
Current view: top level - src - qs_dispersion_nonloc.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 378 413 91.5 %
Date: 2024-12-21 06:28:57 Functions: 13 14 92.9 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Calculation of non local dispersion functionals
      10             : !>  Some routines adapted from:
      11             : !>  Copyright (C) 2001-2009 Quantum ESPRESSO group
      12             : !>  Copyright (C) 2009 Brian Kolb, Timo Thonhauser - Wake Forest University
      13             : !>  This file is distributed under the terms of the
      14             : !>  GNU General Public License. See the file `License'
      15             : !>  in the root directory of the present distribution,
      16             : !>  or http://www.gnu.org/copyleft/gpl.txt .
      17             : !> \author JGH
      18             : ! **************************************************************************************************
      19             : MODULE qs_dispersion_nonloc
      20             :    USE bibliography,                    ONLY: Dion2004,&
      21             :                                               Romanperez2009,&
      22             :                                               Sabatini2013,&
      23             :                                               cite_reference
      24             :    USE cp_files,                        ONLY: close_file,&
      25             :                                               open_file
      26             :    USE input_constants,                 ONLY: vdw_nl_DRSLL,&
      27             :                                               vdw_nl_LMKLL,&
      28             :                                               vdw_nl_RVV10,&
      29             :                                               xc_vdw_fun_nonloc
      30             :    USE kinds,                           ONLY: default_string_length,&
      31             :                                               dp
      32             :    USE mathconstants,                   ONLY: pi,&
      33             :                                               rootpi
      34             :    USE message_passing,                 ONLY: mp_para_env_type
      35             :    USE pw_grid_types,                   ONLY: HALFSPACE,&
      36             :                                               pw_grid_type
      37             :    USE pw_methods,                      ONLY: pw_axpy,&
      38             :                                               pw_derive,&
      39             :                                               pw_transfer
      40             :    USE pw_pool_types,                   ONLY: pw_pool_type
      41             :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      42             :                                               pw_r3d_rs_type
      43             :    USE qs_dispersion_types,             ONLY: qs_dispersion_type
      44             :    USE virial_types,                    ONLY: virial_type
      45             : #include "./base/base_uses.f90"
      46             : 
      47             :    IMPLICIT NONE
      48             : 
      49             :    PRIVATE
      50             : 
      51             :    REAL(KIND=dp), PARAMETER :: epsr = 1.e-12_dp
      52             : 
      53             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dispersion_nonloc'
      54             : 
      55             :    PUBLIC :: qs_dispersion_nonloc_init, calculate_dispersion_nonloc
      56             : 
      57             : ! **************************************************************************************************
      58             : 
      59             : CONTAINS
      60             : 
      61             : ! **************************************************************************************************
      62             : !> \brief ...
      63             : !> \param dispersion_env ...
      64             : !> \param para_env ...
      65             : ! **************************************************************************************************
      66          46 :    SUBROUTINE qs_dispersion_nonloc_init(dispersion_env, para_env)
      67             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
      68             :       TYPE(mp_para_env_type), POINTER                    :: para_env
      69             : 
      70             :       CHARACTER(len=*), PARAMETER :: routineN = 'qs_dispersion_nonloc_init'
      71             : 
      72             :       CHARACTER(LEN=default_string_length)               :: filename
      73             :       INTEGER                                            :: funit, handle, nqs, nr_points, q1_i, &
      74             :                                                             q2_i, vdw_type
      75             : 
      76          46 :       CALL timeset(routineN, handle)
      77             : 
      78          46 :       SELECT CASE (dispersion_env%nl_type)
      79             :       CASE DEFAULT
      80           0 :          CPABORT("Unknown vdW-DF functional")
      81             :       CASE (vdw_nl_DRSLL, vdw_nl_LMKLL)
      82          32 :          CALL cite_reference(Dion2004)
      83             :       CASE (vdw_nl_RVV10)
      84          46 :          CALL cite_reference(Sabatini2013)
      85             :       END SELECT
      86          46 :       CALL cite_reference(RomanPerez2009)
      87             : 
      88          46 :       vdw_type = dispersion_env%type
      89          46 :       SELECT CASE (vdw_type)
      90             :       CASE DEFAULT
      91             :          ! do nothing
      92             :       CASE (xc_vdw_fun_nonloc)
      93             :          ! setup information on non local functionals
      94          46 :          filename = dispersion_env%kernel_file_name
      95          46 :          IF (para_env%is_source()) THEN
      96             :             ! Read the kernel information from file "filename"
      97          23 :             CALL open_file(file_name=filename, unit_number=funit, file_form="FORMATTED")
      98          23 :             READ (funit, *) nqs, nr_points
      99          23 :             READ (funit, *) dispersion_env%r_max
     100             :          END IF
     101          46 :          CALL para_env%bcast(nqs)
     102          46 :          CALL para_env%bcast(nr_points)
     103          46 :          CALL para_env%bcast(dispersion_env%r_max)
     104             :          ALLOCATE (dispersion_env%q_mesh(nqs), dispersion_env%kernel(0:nr_points, nqs, nqs), &
     105         460 :                    dispersion_env%d2phi_dk2(0:nr_points, nqs, nqs))
     106          46 :          dispersion_env%nqs = nqs
     107          46 :          dispersion_env%nr_points = nr_points
     108          46 :          IF (para_env%is_source()) THEN
     109             :             !! Read in the values of the q points used to generate this kernel
     110         483 :             READ (funit, "(1p, 4e23.14)") dispersion_env%q_mesh
     111             :             !! For each pair of q values, read in the function phi_q1_q2(k).
     112             :             !! That is, the fourier transformed kernel function assuming q1 and q2
     113             :             !! for all the values of r used.
     114         483 :             DO q1_i = 1, nqs
     115        5313 :                DO q2_i = 1, q1_i
     116        4830 :                   READ (funit, "(1p, 4e23.14)") dispersion_env%kernel(0:nr_points, q1_i, q2_i)
     117     4956040 :                   dispersion_env%kernel(0:nr_points, q2_i, q1_i) = dispersion_env%kernel(0:nr_points, q1_i, q2_i)
     118             :                END DO
     119             :             END DO
     120             :             !! Again, for each pair of q values (q1 and q2), read in the value
     121             :             !! of the second derivative of the above mentiond Fourier transformed
     122             :             !! kernel function phi_alpha_beta(k).  These are used for spline
     123             :             !! interpolation of the Fourier transformed kernel.
     124         483 :             DO q1_i = 1, nqs
     125        5313 :                DO q2_i = 1, q1_i
     126        4830 :                   READ (funit, "(1p, 4e23.14)") dispersion_env%d2phi_dk2(0:nr_points, q1_i, q2_i)
     127     4956040 :                   dispersion_env%d2phi_dk2(0:nr_points, q2_i, q1_i) = dispersion_env%d2phi_dk2(0:nr_points, q1_i, q2_i)
     128             :                END DO
     129             :             END DO
     130          23 :             CALL close_file(unit_number=funit)
     131             :          END IF
     132        1886 :          CALL para_env%bcast(dispersion_env%q_mesh)
     133    37758686 :          CALL para_env%bcast(dispersion_env%kernel)
     134    37758686 :          CALL para_env%bcast(dispersion_env%d2phi_dk2)
     135             :          ! 2nd derivates for interpolation
     136         184 :          ALLOCATE (dispersion_env%d2y_dx2(nqs, nqs))
     137          46 :          CALL initialize_spline_interpolation(dispersion_env%q_mesh, dispersion_env%d2y_dx2)
     138             :          !
     139          46 :          dispersion_env%q_cut = dispersion_env%q_mesh(nqs)
     140          46 :          dispersion_env%q_min = dispersion_env%q_mesh(1)
     141          92 :          dispersion_env%dk = 2.0_dp*pi/dispersion_env%r_max
     142             : 
     143             :       END SELECT
     144             : 
     145          46 :       CALL timestop(handle)
     146             : 
     147          46 :    END SUBROUTINE qs_dispersion_nonloc_init
     148             : 
     149             : ! **************************************************************************************************
     150             : !> \brief Calculates the non-local vdW functional using the method of Soler
     151             : !>        For spin polarized cases we use E(a,b) = E(a+b), i.e. total density
     152             : !> \param vxc_rho ...
     153             : !> \param rho_r ...
     154             : !> \param rho_g ...
     155             : !> \param edispersion ...
     156             : !> \param dispersion_env ...
     157             : !> \param energy_only ...
     158             : !> \param pw_pool ...
     159             : !> \param xc_pw_pool ...
     160             : !> \param para_env ...
     161             : !> \param virial ...
     162             : ! **************************************************************************************************
     163         388 :    SUBROUTINE calculate_dispersion_nonloc(vxc_rho, rho_r, rho_g, edispersion, &
     164             :                                           dispersion_env, energy_only, pw_pool, xc_pw_pool, para_env, virial)
     165             :       TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER        :: vxc_rho, rho_r
     166             :       TYPE(pw_c1d_gs_type), DIMENSION(:), POINTER        :: rho_g
     167             :       REAL(KIND=dp), INTENT(OUT)                         :: edispersion
     168             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
     169             :       LOGICAL, INTENT(IN)                                :: energy_only
     170             :       TYPE(pw_pool_type), POINTER                        :: pw_pool, xc_pw_pool
     171             :       TYPE(mp_para_env_type), POINTER                    :: para_env
     172             :       TYPE(virial_type), OPTIONAL, POINTER               :: virial
     173             : 
     174             :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_dispersion_nonloc'
     175             :       INTEGER, DIMENSION(3, 3), PARAMETER :: nd = RESHAPE((/1, 0, 0, 0, 1, 0, 0, 0, 1/), (/3, 3/))
     176             : 
     177             :       INTEGER                                            :: handle, i, i_grid, idir, ispin, nl_type, &
     178             :                                                             np, nspin, p, q, r, s
     179             :       INTEGER, DIMENSION(1:3)                            :: hi, lo, n
     180             :       LOGICAL                                            :: use_virial
     181             :       REAL(KIND=dp)                                      :: b_value, beta, const, Ec_nl, sumnp
     182         388 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: dq0_dgradrho, dq0_drho, hpot, potential, &
     183         388 :                                                             q0, rho
     184         388 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: drho, thetas
     185             :       TYPE(pw_c1d_gs_type)                               :: tmp_g, vxc_g
     186         388 :       TYPE(pw_c1d_gs_type), ALLOCATABLE, DIMENSION(:)    :: thetas_g
     187             :       TYPE(pw_grid_type), POINTER                        :: grid
     188             :       TYPE(pw_r3d_rs_type)                               :: tmp_r, vxc_r
     189         388 :       TYPE(pw_r3d_rs_type), ALLOCATABLE, DIMENSION(:, :) :: drho_r
     190             : 
     191         388 :       CALL timeset(routineN, handle)
     192             : 
     193         388 :       CPASSERT(ASSOCIATED(rho_r))
     194         388 :       CPASSERT(ASSOCIATED(rho_g))
     195         388 :       CPASSERT(ASSOCIATED(pw_pool))
     196             : 
     197         388 :       IF (PRESENT(virial)) THEN
     198         382 :          use_virial = virial%pv_calculate .AND. (.NOT. virial%pv_numer)
     199             :       ELSE
     200             :          use_virial = .FALSE.
     201             :       END IF
     202             :       IF (use_virial) THEN
     203         108 :          CPASSERT(.NOT. energy_only)
     204             :       END IF
     205         388 :       IF (.NOT. energy_only) THEN
     206         382 :          CPASSERT(ASSOCIATED(vxc_rho))
     207             :       END IF
     208             : 
     209         388 :       nl_type = dispersion_env%nl_type
     210             : 
     211         388 :       b_value = dispersion_env%b_value
     212         388 :       beta = 0.03125_dp*(3.0_dp/(b_value**2.0_dp))**0.75_dp
     213         388 :       nspin = SIZE(rho_r)
     214             : 
     215         388 :       const = 1.0_dp/(3.0_dp*rootpi*b_value**1.5_dp)/(pi**0.75_dp)
     216             : 
     217             :       ! temporary arrays for FFT
     218         388 :       CALL pw_pool%create_pw(tmp_g)
     219         388 :       CALL pw_pool%create_pw(tmp_r)
     220             : 
     221             :       ! get density derivatives
     222        2796 :       ALLOCATE (drho_r(3, nspin))
     223         796 :       DO ispin = 1, nspin
     224        2020 :          DO idir = 1, 3
     225        1224 :             CALL pw_pool%create_pw(drho_r(idir, ispin))
     226        1224 :             CALL pw_transfer(rho_g(ispin), tmp_g)
     227        1224 :             CALL pw_derive(tmp_g, nd(:, idir))
     228        1632 :             CALL pw_transfer(tmp_g, drho_r(idir, ispin))
     229             :          END DO
     230             :       END DO
     231             : 
     232        1552 :       np = SIZE(tmp_r%array)
     233        1940 :       ALLOCATE (rho(np), drho(np, 3)) !in the following loops, rho and drho _will_ have the same bounds
     234        1552 :       DO i = 1, 3
     235        1164 :          lo(i) = LBOUND(tmp_r%array, i)
     236        1164 :          hi(i) = UBOUND(tmp_r%array, i)
     237        1552 :          n(i) = hi(i) - lo(i) + 1
     238             :       END DO
     239             : !$OMP PARALLEL DO DEFAULT(NONE)              &
     240             : !$OMP             SHARED(n,rho)              &
     241         388 : !$OMP             COLLAPSE(3)
     242             :       DO r = 0, n(3) - 1
     243             :          DO q = 0, n(2) - 1
     244             :             DO p = 0, n(1) - 1
     245             :                rho(r*n(2)*n(1) + q*n(1) + p + 1) = 0.0_dp
     246             :             END DO
     247             :          END DO
     248             :       END DO
     249             : !$OMP END PARALLEL DO
     250        1552 :       DO i = 1, 3
     251             : !$OMP PARALLEL DO DEFAULT(NONE)              &
     252             : !$OMP             SHARED(n,i,drho)           &
     253        1552 : !$OMP             COLLAPSE(3)
     254             :          DO r = 0, n(3) - 1
     255             :             DO q = 0, n(2) - 1
     256             :                DO p = 0, n(1) - 1
     257             :                   drho(r*n(2)*n(1) + q*n(1) + p + 1, i) = 0.0_dp
     258             :                END DO
     259             :             END DO
     260             :          END DO
     261             : !$OMP END PARALLEL DO
     262             :       END DO
     263         796 :       DO ispin = 1, nspin
     264         408 :          CALL pw_transfer(rho_g(ispin), tmp_g)
     265         408 :          CALL pw_transfer(tmp_g, tmp_r)
     266             : !$OMP PARALLEL DO DEFAULT(NONE)            &
     267             : !$OMP             SHARED(n,lo,rho,tmp_r)   &
     268             : !$OMP             PRIVATE(s)               &
     269         408 : !$OMP             COLLAPSE(3)
     270             :          DO r = 0, n(3) - 1
     271             :             DO q = 0, n(2) - 1
     272             :                DO p = 0, n(1) - 1
     273             :                   s = r*n(2)*n(1) + q*n(1) + p + 1
     274             :                   rho(s) = rho(s) + tmp_r%array(p + lo(1), q + lo(2), r + lo(3))
     275             :                END DO
     276             :             END DO
     277             :          END DO
     278             : !$OMP END PARALLEL DO
     279        2020 :          DO i = 1, 3
     280             : !$OMP PARALLEL DO DEFAULT(NONE)                      &
     281             : !$OMP             SHARED(ispin,i,n,lo,drho,drho_r)   &
     282             : !$OMP             PRIVATE(s)                         &
     283        1632 : !$OMP             COLLAPSE(3)
     284             :             DO r = 0, n(3) - 1
     285             :                DO q = 0, n(2) - 1
     286             :                   DO p = 0, n(1) - 1
     287             :                      s = r*n(2)*n(1) + q*n(1) + p + 1
     288             :                      drho(s, i) = drho(s, i) + drho_r(i, ispin)%array(p + lo(1), q + lo(2), r + lo(3))
     289             :                   END DO
     290             :                END DO
     291             :             END DO
     292             : !$OMP END PARALLEL DO
     293             :          END DO
     294             :       END DO
     295             :       !! ---------------------------------------------------------------------------------
     296             :       !! Find the value of q0 for all assigned grid points.  q is defined in equations
     297             :       !! 11 and 12 of DION and q0 is the saturated version of q defined in equation
     298             :       !! 5 of SOLER.  This routine also returns the derivatives of the q0s with respect
     299             :       !! to the charge-density and the gradient of the charge-density.  These are needed
     300             :       !! for the potential calculated below.
     301             :       !! ---------------------------------------------------------------------------------
     302             : 
     303         388 :       IF (energy_only) THEN
     304          12 :          ALLOCATE (q0(np))
     305           0 :          SELECT CASE (nl_type)
     306             :          CASE DEFAULT
     307           0 :             CPABORT("Unknown vdW-DF functional")
     308             :          CASE (vdw_nl_DRSLL, vdw_nl_LMKLL)
     309           0 :             CALL get_q0_on_grid_eo_vdw(rho, drho, q0, dispersion_env)
     310             :          CASE (vdw_nl_RVV10)
     311           6 :             CALL get_q0_on_grid_eo_rvv10(rho, drho, q0, dispersion_env)
     312             :          END SELECT
     313             :       ELSE
     314        1528 :          ALLOCATE (q0(np), dq0_drho(np), dq0_dgradrho(np))
     315           0 :          SELECT CASE (nl_type)
     316             :          CASE DEFAULT
     317           0 :             CPABORT("Unknown vdW-DF functional")
     318             :          CASE (vdw_nl_DRSLL, vdw_nl_LMKLL)
     319         228 :             CALL get_q0_on_grid_vdw(rho, drho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
     320             :          CASE (vdw_nl_RVV10)
     321         382 :             CALL get_q0_on_grid_rvv10(rho, drho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
     322             :          END SELECT
     323             :       END IF
     324             : 
     325             :       !! ---------------------------------------------------------------------------------------------
     326             :       !! Here we allocate and calculate the theta functions appearing in equations 8-12 of SOLER.
     327             :       !! They are defined as rho*P_i(q0(rho, gradient_rho)) for vdW and vdW2 or
     328             :       !! constant*rho^(3/4)*P_i(q0(rho, gradient_rho)) for rVV10 where P_i is a polynomial that
     329             :       !! interpolates a Kronecker delta function at the point q_i (taken from the q_mesh) and q0 is
     330             :       !! the saturated version of q.
     331             :       !! q is defined in equations 11 and 12 of DION and the saturation procedure is defined in equation 5
     332             :       !! of soler.  This is the biggest memory consumer in the method since the thetas array is
     333             :       !! (total # of FFT points)*Nqs complex numbers.  In a parallel run, each processor will hold the
     334             :       !! values of all the theta functions on just the points assigned to it.
     335             :       !! --------------------------------------------------------------------------------------------------
     336             :       !! thetas are stored in reciprocal space as  theta_i(k) because this is the way they are used later
     337             :       !! for the convolution (equation 11 of SOLER).
     338             :       !! --------------------------------------------------------------------------------------------------
     339        1552 :       ALLOCATE (thetas(np, dispersion_env%nqs))
     340             :       !! Interpolate the P_i polynomials defined in equation 3 in SOLER for the particular
     341             :       !! q0 values we have.
     342         388 :       CALL spline_interpolation(dispersion_env%q_mesh, dispersion_env%d2y_dx2, q0, thetas)
     343             : 
     344             :       !! Form the thetas where theta is defined as rho*p_i(q0) for vdW and vdW2 or
     345             :       !! constant*rho^(3/4)*p_i(q0) for rVV10
     346             :       !! ------------------------------------------------------------------------------------
     347           0 :       SELECT CASE (nl_type)
     348             :       CASE DEFAULT
     349           0 :          CPABORT("Unknown vdW-DF functional")
     350             :       CASE (vdw_nl_DRSLL, vdw_nl_LMKLL)
     351             : !$OMP PARALLEL DO DEFAULT( NONE )                          &
     352         228 : !$OMP             SHARED( dispersion_env, thetas, rho)
     353             :          DO i = 1, dispersion_env%nqs
     354             :             thetas(:, i) = thetas(:, i)*rho(:)
     355             :          END DO
     356             : !$OMP END PARALLEL DO
     357             :       CASE (vdw_nl_RVV10)
     358             : !$OMP PARALLEL DO DEFAULT( NONE )                                  &
     359             : !$OMP             SHARED( np, rho, dispersion_env, thetas, const ) &
     360             : !$OMP             PRIVATE( i )                                     &
     361         388 : !$OMP             SCHEDULE(DYNAMIC)    ! use dynamic to allow for possibility of cases having   (rho(i_grid) .LE. epsr)
     362             :          DO i_grid = 1, np
     363             :             IF (rho(i_grid) > epsr) THEN
     364             :                DO i = 1, dispersion_env%nqs
     365             :                   thetas(i_grid, i) = thetas(i_grid, i)*const*rho(i_grid)**(0.75_dp)
     366             :                END DO
     367             :             ELSE
     368             :                thetas(i_grid, :) = 0.0_dp
     369             :             END IF
     370             :          END DO
     371             : !$OMP END PARALLEL DO
     372             :       END SELECT
     373             :       !! ------------------------------------------------------------------------------------
     374             :       !! Get thetas in reciprocal space.
     375        1552 :       DO i = 1, 3
     376        1164 :          lo(i) = LBOUND(tmp_r%array, i)
     377        1164 :          hi(i) = UBOUND(tmp_r%array, i)
     378        1552 :          n(i) = hi(i) - lo(i) + 1
     379             :       END DO
     380        8924 :       ALLOCATE (thetas_g(dispersion_env%nqs))
     381        8148 :       DO i = 1, dispersion_env%nqs
     382             : !$OMP PARALLEL DO DEFAULT(NONE)                   &
     383             : !$OMP             SHARED(i,n,lo,thetas,tmp_r)     &
     384        7760 : !$OMP             COLLAPSE(3)
     385             :          DO r = 0, n(3) - 1
     386             :             DO q = 0, n(2) - 1
     387             :                DO p = 0, n(1) - 1
     388             :                   tmp_r%array(p + lo(1), q + lo(2), r + lo(3)) = thetas(r*n(2)*n(1) + q*n(1) + p + 1, i)
     389             :                END DO
     390             :             END DO
     391             :          END DO
     392             : !$OMP END PARALLEL DO
     393        7760 :          CALL pw_pool%create_pw(thetas_g(i))
     394        8148 :          CALL pw_transfer(tmp_r, thetas_g(i))
     395             :       END DO
     396         388 :       grid => thetas_g(1)%pw_grid
     397             :       !! ---------------------------------------------------------------------------------------------
     398             :       !! Carry out the integration in equation 8 of SOLER.  This also turns the thetas array into the
     399             :       !! precursor to the u_i(k) array which is inverse fourier transformed to get the u_i(r) functions
     400             :       !! of SOLER equation 11.  Add the energy we find to the output variable etxc.
     401             :       !! --------------------------------------------------------------------------------------------------
     402         388 :       sumnp = np
     403         388 :       CALL para_env%sum(sumnp)
     404         388 :       IF (use_virial) THEN
     405             :          ! calculates kernel contribution to stress
     406         108 :          CALL vdW_energy(thetas_g, dispersion_env, Ec_nl, energy_only, virial)
     407          40 :          SELECT CASE (nl_type)
     408             :          CASE (vdw_nl_RVV10)
     409      276588 :             Ec_nl = 0.5_dp*Ec_nl + beta*SUM(rho(:))*grid%vol/sumnp
     410             :          END SELECT
     411             :          ! calculates energy contribution to stress
     412             :          ! potential contribution to stress is calculated together with other potentials (Hxc)
     413         432 :          DO idir = 1, 3
     414         432 :             virial%pv_xc(idir, idir) = virial%pv_xc(idir, idir) + Ec_nl
     415             :          END DO
     416             :       ELSE
     417         280 :          CALL vdW_energy(thetas_g, dispersion_env, Ec_nl, energy_only)
     418         120 :          SELECT CASE (nl_type)
     419             :          CASE (vdw_nl_RVV10)
     420      565368 :             Ec_nl = 0.5_dp*Ec_nl + beta*SUM(rho(:))*grid%vol/sumnp
     421             :          END SELECT
     422             :       END IF
     423         388 :       CALL para_env%sum(Ec_nl)
     424         388 :       IF (nl_type == vdw_nl_RVV10) Ec_nl = Ec_nl*dispersion_env%scale_rvv10
     425         388 :       edispersion = Ec_nl
     426             : 
     427         388 :       IF (energy_only) THEN
     428           6 :          DEALLOCATE (q0)
     429             :       ELSE
     430             :          !! ----------------------------------------------------------------------------
     431             :          !! Inverse Fourier transform the u_i(k) to get the u_i(r) of SOLER equation 11.
     432             :          !!-----------------------------------------------------------------------------
     433        1528 :          DO i = 1, 3
     434        1146 :             lo(i) = LBOUND(tmp_r%array, i)
     435        1146 :             hi(i) = UBOUND(tmp_r%array, i)
     436        1528 :             n(i) = hi(i) - lo(i) + 1
     437             :          END DO
     438        8022 :          DO i = 1, dispersion_env%nqs
     439        7640 :             CALL pw_transfer(thetas_g(i), tmp_r)
     440             : !$OMP PARALLEL DO DEFAULT(NONE)                        &
     441             : !$OMP             SHARED(i,n,lo,thetas,tmp_r)          &
     442        8022 : !$OMP             COLLAPSE(3)
     443             :             DO r = 0, n(3) - 1
     444             :                DO q = 0, n(2) - 1
     445             :                   DO p = 0, n(1) - 1
     446             :                      thetas(r*n(2)*n(1) + q*n(1) + p + 1, i) = tmp_r%array(p + lo(1), q + lo(2), r + lo(3))
     447             :                   END DO
     448             :                END DO
     449             :             END DO
     450             : !$OMP END PARALLEL DO
     451             :          END DO
     452             :          !! -------------------------------------------------------------------------
     453             :          !! Here we allocate the array to hold the potential. This is calculated via
     454             :          !! equation 10 of SOLER, using the u_i(r) calculated from equations 11 and
     455             :          !! 12 of SOLER.  Each processor allocates the array to be the size of the
     456             :          !! full grid  because, as can be seen in SOLER equation 9, processors need
     457             :          !! to access grid points outside their allocated regions.
     458             :          !! -------------------------------------------------------------------------
     459        1146 :          ALLOCATE (potential(np), hpot(np))
     460         382 :          IF (use_virial) THEN
     461             :             ! calculates gradient contribution to stress
     462         108 :             grid => tmp_g%pw_grid
     463             :             CALL get_potential(q0, dq0_drho, dq0_dgradrho, rho, thetas, potential, hpot, &
     464         108 :                                dispersion_env, drho, grid%dvol, virial)
     465             :          ELSE
     466             :             CALL get_potential(q0, dq0_drho, dq0_dgradrho, rho, thetas, potential, hpot, &
     467         274 :                                dispersion_env)
     468             :          END IF
     469         154 :          SELECT CASE (nl_type)
     470             :          CASE (vdw_nl_RVV10)
     471      743418 :             potential(:) = (0.5_dp*potential(:) + beta)*dispersion_env%scale_rvv10
     472      743800 :             hpot(:) = 0.5_dp*dispersion_env%scale_rvv10*hpot(:)
     473             :          END SELECT
     474         382 :          CALL pw_pool%create_pw(vxc_r)
     475        1528 :          DO i = 1, 3
     476        1146 :             lo(i) = LBOUND(vxc_r%array, i)
     477        1146 :             hi(i) = UBOUND(vxc_r%array, i)
     478        1528 :             n(i) = hi(i) - lo(i) + 1
     479             :          END DO
     480             : !$OMP PARALLEL DO DEFAULT(NONE)                         &
     481             : !$OMP             SHARED(i,n,lo,potential,vxc_r)        &
     482         382 : !$OMP             COLLAPSE(3)
     483             :          DO r = 0, n(3) - 1
     484             :             DO q = 0, n(2) - 1
     485             :                DO p = 0, n(1) - 1
     486             :                   vxc_r%array(p + lo(1), q + lo(2), r + lo(3)) = potential(r*n(2)*n(1) + q*n(1) + p + 1)
     487             :                END DO
     488             :             END DO
     489             :          END DO
     490             : !$OMP END PARALLEL DO
     491        1528 :          DO i = 1, 3
     492        1146 :             lo(i) = LBOUND(tmp_r%array, i)
     493        1146 :             hi(i) = UBOUND(tmp_r%array, i)
     494        1528 :             n(i) = hi(i) - lo(i) + 1
     495             :          END DO
     496        1528 :          DO idir = 1, 3
     497             : !$OMP PARALLEL DO DEFAULT(NONE)                     &
     498             : !$OMP             SHARED(n,lo,tmp_r)                &
     499        1146 : !$OMP             COLLAPSE(3)
     500             :             DO r = 0, n(3) - 1
     501             :                DO q = 0, n(2) - 1
     502             :                   DO p = 0, n(1) - 1
     503             :                      tmp_r%array(p + lo(1), q + lo(2), r + lo(3)) = 0.0_dp
     504             :                   END DO
     505             :                END DO
     506             :             END DO
     507             : !$OMP END PARALLEL DO
     508        2352 :             DO ispin = 1, nspin
     509             : !$OMP PARALLEL DO DEFAULT(NONE)                              &
     510             : !$OMP             SHARED(n,lo,tmp_r,hpot,drho_r,idir,ispin)  &
     511        2352 : !$OMP             COLLAPSE(3)
     512             :                DO r = 0, n(3) - 1
     513             :                   DO q = 0, n(2) - 1
     514             :                      DO p = 0, n(1) - 1
     515             :                         tmp_r%array(p + lo(1), q + lo(2), r + lo(3)) = tmp_r%array(p + lo(1), q + lo(2), r + lo(3)) &
     516             :                                                                        + hpot(r*n(2)*n(1) + q*n(1) + p + 1) &
     517             :                                                                        *drho_r(idir, ispin)%array(p + lo(1), q + lo(2), r + lo(3))
     518             :                      END DO
     519             :                   END DO
     520             :                END DO
     521             : !$OMP END PARALLEL DO
     522             :             END DO
     523        1146 :             CALL pw_transfer(tmp_r, tmp_g)
     524        1146 :             CALL pw_derive(tmp_g, nd(:, idir))
     525        1146 :             CALL pw_transfer(tmp_g, tmp_r)
     526        1528 :             CALL pw_axpy(tmp_r, vxc_r, -1._dp)
     527             :          END DO
     528         382 :          CALL pw_transfer(vxc_r, tmp_g)
     529         382 :          CALL pw_pool%give_back_pw(vxc_r)
     530         382 :          CALL xc_pw_pool%create_pw(vxc_r)
     531         382 :          CALL xc_pw_pool%create_pw(vxc_g)
     532         382 :          CALL pw_transfer(tmp_g, vxc_g)
     533         382 :          CALL pw_transfer(vxc_g, vxc_r)
     534         784 :          DO ispin = 1, nspin
     535         784 :             CALL pw_axpy(vxc_r, vxc_rho(ispin), 1._dp)
     536             :          END DO
     537         382 :          CALL xc_pw_pool%give_back_pw(vxc_r)
     538         382 :          CALL xc_pw_pool%give_back_pw(vxc_g)
     539         382 :          DEALLOCATE (q0, dq0_drho, dq0_dgradrho)
     540             :       END IF
     541             : 
     542         388 :       DEALLOCATE (thetas)
     543             : 
     544        8148 :       DO i = 1, dispersion_env%nqs
     545        8148 :          CALL pw_pool%give_back_pw(thetas_g(i))
     546             :       END DO
     547         796 :       DO ispin = 1, nspin
     548        2020 :          DO idir = 1, 3
     549        1632 :             CALL pw_pool%give_back_pw(drho_r(idir, ispin))
     550             :          END DO
     551             :       END DO
     552         388 :       CALL pw_pool%give_back_pw(tmp_r)
     553         388 :       CALL pw_pool%give_back_pw(tmp_g)
     554             : 
     555         388 :       DEALLOCATE (rho, drho, drho_r, thetas_g)
     556             : 
     557         388 :       CALL timestop(handle)
     558             : 
     559         776 :    END SUBROUTINE calculate_dispersion_nonloc
     560             : 
     561             : ! **************************************************************************************************
     562             : !> \brief This routine carries out the integration of equation 8 of SOLER.  It returns the non-local
     563             : !> exchange-correlation energy and the u_alpha(k) arrays used to find the u_alpha(r) arrays via
     564             : !> equations 11 and 12 in SOLER.
     565             : !> energy contribution to stress is added in qs_force
     566             : !> \param thetas_g ...
     567             : !> \param dispersion_env ...
     568             : !> \param vdW_xc_energy ...
     569             : !> \param energy_only ...
     570             : !> \param virial ...
     571             : !> \par History
     572             : !>    OpenMP added: Aug 2016  MTucker
     573             : ! **************************************************************************************************
     574         388 :    SUBROUTINE vdW_energy(thetas_g, dispersion_env, vdW_xc_energy, energy_only, virial)
     575             :       TYPE(pw_c1d_gs_type), DIMENSION(:), INTENT(IN)     :: thetas_g
     576             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
     577             :       REAL(KIND=dp), INTENT(OUT)                         :: vdW_xc_energy
     578             :       LOGICAL, INTENT(IN)                                :: energy_only
     579             :       TYPE(virial_type), OPTIONAL, POINTER               :: virial
     580             : 
     581             :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'vdW_energy'
     582             : 
     583             :       COMPLEX(KIND=dp)                                   :: uu
     584         388 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:)        :: theta
     585         388 :       COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :)     :: u_vdw(:, :)
     586             :       INTEGER                                            :: handle, ig, iq, l, m, nl_type, nqs, &
     587             :                                                             q1_i, q2_i
     588             :       LOGICAL                                            :: use_virial
     589             :       REAL(KIND=dp)                                      :: g, g2, g2_last, g_multiplier, gm
     590         388 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: dkernel_of_dk, kernel_of_k
     591             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: virial_thread
     592             :       TYPE(pw_grid_type), POINTER                        :: grid
     593             : 
     594         388 :       CALL timeset(routineN, handle)
     595         388 :       nqs = dispersion_env%nqs
     596             : 
     597         388 :       use_virial = PRESENT(virial)
     598         388 :       virial_thread(:, :) = 0.0_dp ! always initialize to avoid floating point exceptions in OMP REDUCTION
     599             : 
     600         388 :       vdW_xc_energy = 0._dp
     601         388 :       grid => thetas_g(1)%pw_grid
     602             : 
     603         388 :       IF (grid%grid_span == HALFSPACE) THEN
     604             :          g_multiplier = 2._dp
     605             :       ELSE
     606         388 :          g_multiplier = 1._dp
     607             :       END IF
     608             : 
     609         388 :       nl_type = dispersion_env%nl_type
     610             : 
     611         388 :       IF (.NOT. energy_only) THEN
     612        1528 :          ALLOCATE (u_vdW(grid%ngpts_cut_local, nqs))
     613    86161402 :          u_vdW(:, :) = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
     614             :       END IF
     615             : 
     616             : !$OMP PARALLEL DEFAULT( NONE )                                             &
     617             : !$OMP           SHARED( nqs, energy_only, grid, dispersion_env             &
     618             : !$OMP                 , use_virial, thetas_g, g_multiplier, nl_type        &
     619             : !$OMP                 , u_vdW                                              &
     620             : !$OMP                 )                                                    &
     621             : !$OMP          PRIVATE( g2_last, kernel_of_k, dkernel_of_dk, theta         &
     622             : !$OMP                 , g2, g, iq                                          &
     623             : !$OMP                 , q2_i, uu, q1_i, gm, l, m                           &
     624             : !$OMP                 )                                                    &
     625             : !$OMP        REDUCTION( +: vdW_xc_energy, virial_thread                    &
     626         388 : !$OMP                 )
     627             : 
     628             :       g2_last = HUGE(0._dp)
     629             : 
     630             :       ALLOCATE (kernel_of_k(nqs, nqs), dkernel_of_dk(nqs, nqs))
     631             :       ALLOCATE (theta(nqs))
     632             : 
     633             : !$OMP DO
     634             :       DO ig = 1, grid%ngpts_cut_local
     635             :          g2 = grid%gsq(ig)
     636             :          IF (ABS(g2 - g2_last) > 1.e-10) THEN
     637             :             g2_last = g2
     638             :             g = SQRT(g2)
     639             :             CALL interpolate_kernel(g, kernel_of_k, dispersion_env)
     640             :             IF (use_virial) CALL interpolate_dkernel_dk(g, dkernel_of_dk, dispersion_env)
     641             :          END IF
     642             :          DO iq = 1, nqs
     643             :             theta(iq) = thetas_g(iq)%array(ig)
     644             :          END DO
     645             :          DO q2_i = 1, nqs
     646             :             uu = CMPLX(0.0_dp, 0.0_dp, KIND=dp)
     647             :             DO q1_i = 1, nqs
     648             :                uu = uu + kernel_of_k(q2_i, q1_i)*theta(q1_i)
     649             :             END DO
     650             :             IF (ig < grid%first_gne0) THEN
     651             :                vdW_xc_energy = vdW_xc_energy + REAL(uu*CONJG(theta(q2_i)), KIND=dp)
     652             :             ELSE
     653             :                vdW_xc_energy = vdW_xc_energy + g_multiplier*REAL(uu*CONJG(theta(q2_i)), KIND=dp)
     654             :             END IF
     655             :             IF (.NOT. energy_only) u_vdW(ig, q2_i) = uu
     656             : 
     657             :             IF (use_virial .AND. ig >= grid%first_gne0) THEN
     658             :                DO q1_i = 1, nqs
     659             :                   gm = 0.5_dp*g_multiplier*grid%vol*dkernel_of_dk(q1_i, q2_i)*REAL(theta(q1_i)*CONJG(theta(q2_i)), KIND=dp)
     660             :                   IF (nl_type == vdw_nl_RVV10) THEN
     661             :                      gm = 0.5_dp*gm
     662             :                   END IF
     663             :                   DO l = 1, 3
     664             :                      DO m = 1, l
     665             :                         virial_thread(l, m) = virial_thread(l, m) - gm*(grid%g(l, ig)*grid%g(m, ig))/g
     666             :                      END DO
     667             :                   END DO
     668             :                END DO
     669             :             END IF
     670             : 
     671             :          END DO
     672             :       END DO
     673             : !$OMP END DO
     674             : 
     675             :       DEALLOCATE (theta)
     676             :       DEALLOCATE (kernel_of_k, dkernel_of_dk)
     677             : 
     678             :       IF (.NOT. energy_only) THEN
     679             : !$OMP DO
     680             :          DO ig = 1, grid%ngpts_cut_local
     681             :             DO iq = 1, nqs
     682             :                thetas_g(iq)%array(ig) = u_vdW(ig, iq)
     683             :             END DO
     684             :          END DO
     685             : !$OMP END DO
     686             :       END IF
     687             : 
     688             : !$OMP END PARALLEL
     689             : 
     690         388 :       IF (.NOT. energy_only) THEN
     691         382 :          DEALLOCATE (u_vdW)
     692             :       END IF
     693             : 
     694         388 :       vdW_xc_energy = vdW_xc_energy*grid%vol*0.5_dp
     695             : 
     696         388 :       IF (use_virial) THEN
     697         432 :          DO l = 1, 3
     698         648 :             DO m = 1, (l - 1)
     699         324 :                virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
     700         648 :                virial%pv_xc(m, l) = virial%pv_xc(l, m)
     701             :             END DO
     702         324 :             m = l
     703         432 :             virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
     704             :          END DO
     705             :       END IF
     706             : 
     707         388 :       CALL timestop(handle)
     708             : 
     709         388 :    END SUBROUTINE vdW_energy
     710             : 
     711             : ! **************************************************************************************************
     712             : !> \brief This routine finds the non-local correlation contribution to the potential
     713             : !> (i.e. the derivative of the non-local piece of the energy with respect to
     714             : !> density) given in SOLER equation 10.  The u_alpha(k) functions were found
     715             : !> while calculating the energy. They are passed in as the matrix u_vdW.
     716             : !> Most of the required derivatives were calculated in the "get_q0_on_grid"
     717             : !> routine, but the derivative of the interpolation polynomials, P_alpha(q),
     718             : !> (SOLER equation 3) with respect to q is interpolated here, along with the
     719             : !> polynomials themselves.
     720             : !> \param q0 ...
     721             : !> \param dq0_drho ...
     722             : !> \param dq0_dgradrho ...
     723             : !> \param total_rho ...
     724             : !> \param u_vdW ...
     725             : !> \param potential ...
     726             : !> \param h_prefactor ...
     727             : !> \param dispersion_env ...
     728             : !> \param drho ...
     729             : !> \param dvol ...
     730             : !> \param virial ...
     731             : !> \par History
     732             : !> OpenMP added: Aug 2016  MTucker
     733             : ! **************************************************************************************************
     734         382 :    SUBROUTINE get_potential(q0, dq0_drho, dq0_dgradrho, total_rho, u_vdW, potential, h_prefactor, &
     735         382 :                             dispersion_env, drho, dvol, virial)
     736             : 
     737             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: q0, dq0_drho, dq0_dgradrho, total_rho
     738             :       REAL(dp), DIMENSION(:, :), INTENT(in)              :: u_vdW
     739             :       REAL(dp), DIMENSION(:), INTENT(out)                :: potential, h_prefactor
     740             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
     741             :       REAL(dp), DIMENSION(:, :), INTENT(in), OPTIONAL    :: drho
     742             :       REAL(dp), INTENT(IN), OPTIONAL                     :: dvol
     743             :       TYPE(virial_type), OPTIONAL, POINTER               :: virial
     744             : 
     745             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'get_potential'
     746             : 
     747             :       INTEGER                                            :: handle, i_grid, l, m, nl_type, nqs, P_i, &
     748             :                                                             q, q_hi, q_low
     749             :       LOGICAL                                            :: use_virial
     750             :       REAL(dp)                                           :: a, b, b_value, c, const, d, dP_dq0, dq, &
     751             :                                                             dq_6, e, f, P, prefactor, tmp_1_2, &
     752             :                                                             tmp_1_4, tmp_3_4
     753         382 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: y
     754             :       REAL(dp), DIMENSION(3, 3)                          :: virial_thread
     755         382 :       REAL(dp), DIMENSION(:), POINTER                    :: q_mesh
     756         382 :       REAL(dp), DIMENSION(:, :), POINTER                 :: d2y_dx2
     757             : 
     758         382 :       CALL timeset(routineN, handle)
     759             : 
     760         382 :       use_virial = PRESENT(virial)
     761         382 :       CPASSERT(.NOT. use_virial .OR. PRESENT(drho))
     762         382 :       CPASSERT(.NOT. use_virial .OR. PRESENT(dvol))
     763             : 
     764         382 :       virial_thread(:, :) = 0.0_dp ! always initialize to avoid floating point exceptions in OMP REDUCTION
     765         382 :       b_value = dispersion_env%b_value
     766         382 :       const = 1.0_dp/(3.0_dp*b_value**(3.0_dp/2.0_dp)*pi**(5.0_dp/4.0_dp))
     767     4308051 :       potential = 0.0_dp
     768     4308051 :       h_prefactor = 0.0_dp
     769             : 
     770         382 :       d2y_dx2 => dispersion_env%d2y_dx2
     771         382 :       q_mesh => dispersion_env%q_mesh
     772         382 :       nqs = dispersion_env%nqs
     773         382 :       nl_type = dispersion_env%nl_type
     774             : 
     775             : !$OMP PARALLEL DEFAULT( NONE )                                         &
     776             : !$OMP           SHARED( nqs, u_vdW, q_mesh, q0, d2y_dx2, nl_type       &
     777             : !$OMP                 , potential, h_prefactor                         &
     778             : !$OMP                 , dq0_drho, dq0_dgradrho, total_rho, const       &
     779             : !$OMP                 , use_virial, drho, dvol, virial                 &
     780             : !$OMP                 )                                                &
     781             : !$OMP          PRIVATE( y                                              &
     782             : !$OMP                 , q_low, q_hi, q, dq, dq_6, A, b, c, d, e, f     &
     783             : !$OMP                 , P_i, dP_dq0, P, prefactor, l, m                &
     784             : !$OMP                 , tmp_1_2, tmp_1_4, tmp_3_4                      &
     785             : !$OMP                 )                                                &
     786             : !$OMP        REDUCTION(+: virial_thread                                &
     787         382 : !$OMP                 )
     788             : 
     789             :       ALLOCATE (y(nqs))
     790             : 
     791             : !$OMP DO
     792             :       DO i_grid = 1, SIZE(u_vdW, 1)
     793             :          q_low = 1
     794             :          q_hi = nqs
     795             :          ! Figure out which bin our value of q0 is in in the q_mesh
     796             :          DO WHILE ((q_hi - q_low) > 1)
     797             :             q = INT((q_hi + q_low)/2)
     798             :             IF (q_mesh(q) > q0(i_grid)) THEN
     799             :                q_hi = q
     800             :             ELSE
     801             :                q_low = q
     802             :             END IF
     803             :          END DO
     804             :          IF (q_hi == q_low) CPABORT("get_potential:  qhi == qlow")
     805             : 
     806             :          dq = q_mesh(q_hi) - q_mesh(q_low)
     807             :          dq_6 = dq/6.0_dp
     808             : 
     809             :          a = (q_mesh(q_hi) - q0(i_grid))/dq
     810             :          b = (q0(i_grid) - q_mesh(q_low))/dq
     811             :          c = (a**3 - a)*dq*dq_6
     812             :          d = (b**3 - b)*dq*dq_6
     813             :          e = (3.0_dp*a**2 - 1.0_dp)*dq_6
     814             :          f = (3.0_dp*b**2 - 1.0_dp)*dq_6
     815             : 
     816             :          DO P_i = 1, nqs
     817             :             y = 0.0_dp
     818             :             y(P_i) = 1.0_dp
     819             :             dP_dq0 = (y(q_hi) - y(q_low))/dq - e*d2y_dx2(P_i, q_low) + f*d2y_dx2(P_i, q_hi)
     820             :             P = a*y(q_low) + b*y(q_hi) + c*d2y_dx2(P_i, q_low) + d*d2y_dx2(P_i, q_hi)
     821             :             !! The first term in equation 13 of SOLER
     822             :             SELECT CASE (nl_type)
     823             :             CASE DEFAULT
     824             :                CPABORT("Unknown vdW-DF functional")
     825             :             CASE (vdw_nl_DRSLL, vdw_nl_LMKLL)
     826             :                potential(i_grid) = potential(i_grid) + u_vdW(i_grid, P_i)*(P + dP_dq0*dq0_drho(i_grid))
     827             :                prefactor = u_vdW(i_grid, P_i)*dP_dq0*dq0_dgradrho(i_grid)
     828             :             CASE (vdw_nl_RVV10)
     829             :                IF (total_rho(i_grid) > epsr) THEN
     830             :                   tmp_1_2 = SQRT(total_rho(i_grid))
     831             :                   tmp_1_4 = SQRT(tmp_1_2) ! == total_rho(i_grid)**(1.0_dp/4.0_dp)
     832             :                   tmp_3_4 = tmp_1_4*tmp_1_4*tmp_1_4 ! == total_rho(i_grid)**(3.0_dp/4.0_dp)
     833             :                   potential(i_grid) = potential(i_grid) &
     834             :                                       + u_vdW(i_grid, P_i)*(const*0.75_dp/tmp_1_4*P &
     835             :                                                             + const*tmp_3_4*dP_dq0*dq0_drho(i_grid))
     836             :                   prefactor = u_vdW(i_grid, P_i)*const*tmp_3_4*dP_dq0*dq0_dgradrho(i_grid)
     837             :                ELSE
     838             :                   prefactor = 0.0_dp
     839             :                END IF
     840             :             END SELECT
     841             :             IF (q0(i_grid) .NE. q_mesh(nqs)) THEN
     842             :                h_prefactor(i_grid) = h_prefactor(i_grid) + prefactor
     843             :             END IF
     844             : 
     845             :             IF (use_virial .AND. ABS(prefactor) > 0.0_dp) THEN
     846             :                SELECT CASE (nl_type)
     847             :                CASE DEFAULT
     848             :                   ! do nothing
     849             :                CASE (vdw_nl_RVV10)
     850             :                   prefactor = 0.5_dp*prefactor
     851             :                END SELECT
     852             :                prefactor = prefactor*dvol
     853             :                DO l = 1, 3
     854             :                   DO m = 1, l
     855             :                      virial_thread(l, m) = virial_thread(l, m) - prefactor*drho(i_grid, l)*drho(i_grid, m)
     856             :                   END DO
     857             :                END DO
     858             :             END IF
     859             : 
     860             :          END DO ! P_i = 1, nqs
     861             :       END DO ! i_grid = 1, SIZE(u_vdW, 1)
     862             : !$OMP END DO
     863             : 
     864             :       DEALLOCATE (y)
     865             : !$OMP END PARALLEL
     866             : 
     867         382 :       IF (use_virial) THEN
     868         432 :          DO l = 1, 3
     869         648 :             DO m = 1, (l - 1)
     870         324 :                virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
     871         648 :                virial%pv_xc(m, l) = virial%pv_xc(l, m)
     872             :             END DO
     873         324 :             m = l
     874         432 :             virial%pv_xc(l, m) = virial%pv_xc(l, m) + virial_thread(l, m)
     875             :          END DO
     876             :       END IF
     877             : 
     878         382 :       CALL timestop(handle)
     879         764 :    END SUBROUTINE get_potential
     880             : 
     881             : ! **************************************************************************************************
     882             : !> \brief calculates exponent = sum(from i=1 to hi, ((alpha)**i)/i) ) without <<< calling power >>>
     883             : !> \param hi = upper index for sum
     884             : !> \param alpha ...
     885             : !> \param exponent = output value
     886             : !> \par History
     887             : !>     Created:  MTucker, Aug 2016
     888             : ! **************************************************************************************************
     889       72326 :    ELEMENTAL SUBROUTINE calculate_exponent(hi, alpha, exponent)
     890             :       INTEGER, INTENT(in)                                :: hi
     891             :       REAL(dp), INTENT(in)                               :: alpha
     892             :       REAL(dp), INTENT(out)                              :: exponent
     893             : 
     894             :       INTEGER                                            :: i
     895             :       REAL(dp)                                           :: multiplier
     896             : 
     897       72326 :       multiplier = alpha
     898       72326 :       exponent = alpha
     899             : 
     900      867912 :       DO i = 2, hi
     901      795586 :          multiplier = multiplier*alpha
     902      867912 :          exponent = exponent + (multiplier/i)
     903             :       END DO
     904       72326 :    END SUBROUTINE calculate_exponent
     905             : 
     906             : ! **************************************************************************************************
     907             : !> \brief calculate exponent = sum(from i=1 to hi, ((alpha)**i)/i) )  without calling power
     908             : !>        also calculates derivative using similar series
     909             : !> \param hi = upper index for sum
     910             : !> \param alpha ...
     911             : !> \param exponent = output value
     912             : !> \param derivative ...
     913             : !> \par History
     914             : !>     Created:  MTucker, Aug 2016
     915             : ! **************************************************************************************************
     916     4145733 :    ELEMENTAL SUBROUTINE calculate_exponent_derivative(hi, alpha, exponent, derivative)
     917             :       INTEGER, INTENT(in)                                :: hi
     918             :       REAL(dp), INTENT(in)                               :: alpha
     919             :       REAL(dp), INTENT(out)                              :: exponent, derivative
     920             : 
     921             :       INTEGER                                            :: i
     922             :       REAL(dp)                                           :: multiplier
     923             : 
     924     4145733 :       derivative = 0.0d0
     925     4145733 :       multiplier = 1.0d0
     926     4145733 :       exponent = 0.0d0
     927             : 
     928    53894529 :       DO i = 1, hi
     929    49748796 :          derivative = derivative + multiplier
     930    49748796 :          multiplier = multiplier*alpha
     931    53894529 :          exponent = exponent + (multiplier/i)
     932             :       END DO
     933     4145733 :    END SUBROUTINE calculate_exponent_derivative
     934             : 
     935             :    !! This routine first calculates the q value defined in (DION equations 11 and 12), then
     936             :    !! saturates it according to (SOLER equation 5).
     937             : ! **************************************************************************************************
     938             : !> \brief This routine first calculates the q value defined in (DION equations 11 and 12), then
     939             : !> saturates it according to (SOLER equation 5).
     940             : !> \param total_rho ...
     941             : !> \param gradient_rho ...
     942             : !> \param q0 ...
     943             : !> \param dq0_drho ...
     944             : !> \param dq0_dgradrho ...
     945             : !> \param dispersion_env ...
     946             : ! **************************************************************************************************
     947         228 :    SUBROUTINE get_q0_on_grid_vdw(total_rho, gradient_rho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
     948             :       !!
     949             :       !! more specifically it calculates the following
     950             :       !!
     951             :       !!     q0(ir) = q0 as defined above
     952             :       !!     dq0_drho(ir) = total_rho * d q0 /d rho
     953             :       !!     dq0_dgradrho = total_rho / |gradient_rho| * d q0 / d |gradient_rho|
     954             :       !!
     955             :       REAL(dp), INTENT(IN)                               :: total_rho(:), gradient_rho(:, :)
     956             :       REAL(dp), INTENT(OUT)                              :: q0(:), dq0_drho(:), dq0_dgradrho(:)
     957             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
     958             : 
     959             :       INTEGER, PARAMETER                                 :: m_cut = 12
     960             :       REAL(dp), PARAMETER :: LDA_A = 0.031091_dp, LDA_a1 = 0.2137_dp, LDA_b1 = 7.5957_dp, &
     961             :          LDA_b2 = 3.5876_dp, LDA_b3 = 1.6382_dp, LDA_b4 = 0.49294_dp
     962             : 
     963             :       INTEGER                                            :: i_grid
     964             :       REAL(dp)                                           :: dq0_dq, exponent, gradient_correction, &
     965             :                                                             kF, LDA_1, LDA_2, q, q__q_cut, q_cut, &
     966             :                                                             q_min, r_s, sqrt_r_s, Z_ab
     967             : 
     968         228 :       q_cut = dispersion_env%q_cut
     969         228 :       q_min = dispersion_env%q_min
     970         228 :       SELECT CASE (dispersion_env%nl_type)
     971             :       CASE DEFAULT
     972           0 :          CPABORT("Unknown vdW-DF functional")
     973             :       CASE (vdw_nl_DRSLL)
     974          48 :          Z_ab = -0.8491_dp
     975             :       CASE (vdw_nl_LMKLL)
     976         228 :          Z_ab = -1.887_dp
     977             :       END SELECT
     978             : 
     979             :       ! initialize q0-related arrays ...
     980     3564633 :       q0(:) = q_cut
     981     3564633 :       dq0_drho(:) = 0.0_dp
     982     3564633 :       dq0_dgradrho(:) = 0.0_dp
     983             : 
     984     3564633 :       DO i_grid = 1, SIZE(total_rho)
     985             : 
     986             :          !! This prevents numerical problems.  If the charge density is negative (an
     987             :          !! unphysical situation), we simply treat it as very small.  In that case,
     988             :          !! q0 will be very large and will be saturated.  For a saturated q0 the derivative
     989             :          !! dq0_dq will be 0 so we set q0 = q_cut and dq0_drho = dq0_dgradrho = 0 and go on
     990             :          !! to the next point.
     991             :          !! ------------------------------------------------------------------------------------
     992     3564405 :          IF (total_rho(i_grid) < epsr) CYCLE
     993             :          !! ------------------------------------------------------------------------------------
     994             :          !! Calculate some intermediate values needed to find q
     995             :          !! ------------------------------------------------------------------------------------
     996     3492040 :          kF = (3.0_dp*pi*pi*total_rho(i_grid))**(1.0_dp/3.0_dp)
     997     3492040 :          r_s = (3.0_dp/(4.0_dp*pi*total_rho(i_grid)))**(1.0_dp/3.0_dp)
     998     3492040 :          sqrt_r_s = SQRT(r_s)
     999             : 
    1000             :          gradient_correction = -Z_ab/(36.0_dp*kF*total_rho(i_grid)**2) &
    1001     3492040 :                                *(gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2)
    1002             : 
    1003     3492040 :          LDA_1 = 8.0_dp*pi/3.0_dp*(LDA_A*(1.0_dp + LDA_a1*r_s))
    1004     3492040 :          LDA_2 = 2.0_dp*LDA_A*(LDA_b1*sqrt_r_s + LDA_b2*r_s + LDA_b3*r_s*sqrt_r_s + LDA_b4*r_s*r_s)
    1005             :          !! ---------------------------------------------------------------
    1006             :          !! This is the q value defined in equations 11 and 12 of DION
    1007             :          !! ---------------------------------------------------------------
    1008     3492040 :          q = kF + LDA_1*LOG(1.0_dp + 1.0_dp/LDA_2) + gradient_correction
    1009             :          !! ---------------------------------------------------------------
    1010             :          !! Here, we calculate q0 by saturating q according to equation 5 of SOLER.  Also, we find
    1011             :          !! the derivative dq0_dq needed for the derivatives dq0_drho and dq0_dgradrh0 discussed below.
    1012             :          !! ---------------------------------------------------------------------------------------
    1013     3492040 :          q__q_cut = q/q_cut
    1014     3492040 :          CALL calculate_exponent_derivative(m_cut, q__q_cut, exponent, dq0_dq)
    1015     3492040 :          q0(i_grid) = q_cut*(1.0_dp - EXP(-exponent))
    1016     3492040 :          dq0_dq = dq0_dq*EXP(-exponent)
    1017             :          !! ---------------------------------------------------------------------------------------
    1018             :          !! This is to handle a case with q0 too small.  We simply set it to the smallest q value in
    1019             :          !! out q_mesh.  Hopefully this doesn't get used often (ever)
    1020             :          !! ---------------------------------------------------------------------------------------
    1021     3492040 :          IF (q0(i_grid) < q_min) THEN
    1022           0 :             q0(i_grid) = q_min
    1023             :          END IF
    1024             :          !! ---------------------------------------------------------------------------------------
    1025             :          !! Here we find derivatives.  These are actually the density times the derivative of q0 with respect
    1026             :          !! to rho and gradient_rho.  The density factor comes in since we are really differentiating
    1027             :          !! theta = (rho)*P(q0) with respect to density (or its gradient) which will be
    1028             :          !! dtheta_drho = P(q0) + dP_dq0 * [rho * dq0_dq * dq_drho]   and
    1029             :          !! dtheta_dgradient_rho =  dP_dq0  * [rho * dq0_dq * dq_dgradient_rho]
    1030             :          !! The parts in square brackets are what is calculated here.  The dP_dq0 term will be interpolated
    1031             :          !! later.  There should actually be a factor of the magnitude of the gradient in the gradient_rho derivative
    1032             :          !! but that cancels out when we differentiate the magnitude of the gradient with respect to a particular
    1033             :          !! component.
    1034             :          !! ------------------------------------------------------------------------------------------------
    1035             : 
    1036             :          dq0_drho(i_grid) = dq0_dq*(kF/3.0_dp - 7.0_dp/3.0_dp*gradient_correction &
    1037             :                                     - 8.0_dp*pi/9.0_dp*LDA_A*LDA_a1*r_s*LOG(1.0_dp + 1.0_dp/LDA_2) &
    1038             :                                     + LDA_1/(LDA_2*(1.0_dp + LDA_2)) &
    1039             :                                     *(2.0_dp*LDA_A*(LDA_b1/6.0_dp*sqrt_r_s + LDA_b2/3.0_dp*r_s + LDA_b3/2.0_dp*r_s*sqrt_r_s &
    1040     3492040 :                                                     + 2.0_dp*LDA_b4/3.0_dp*r_s**2)))
    1041             : 
    1042     3564633 :          dq0_dgradrho(i_grid) = total_rho(i_grid)*dq0_dq*2.0_dp*(-Z_ab)/(36.0_dp*kF*total_rho(i_grid)**2)
    1043             : 
    1044             :       END DO
    1045             : 
    1046         228 :    END SUBROUTINE get_q0_on_grid_vdw
    1047             : 
    1048             : ! **************************************************************************************************
    1049             : !> \brief ...
    1050             : !> \param total_rho ...
    1051             : !> \param gradient_rho ...
    1052             : !> \param q0 ...
    1053             : !> \param dq0_drho ...
    1054             : !> \param dq0_dgradrho ...
    1055             : !> \param dispersion_env ...
    1056             : ! **************************************************************************************************
    1057         154 :    PURE SUBROUTINE get_q0_on_grid_rvv10(total_rho, gradient_rho, q0, dq0_drho, dq0_dgradrho, dispersion_env)
    1058             :       !!
    1059             :       !! more specifically it calculates the following
    1060             :       !!
    1061             :       !!     q0(ir) = q0 as defined above
    1062             :       !!     dq0_drho(ir) = total_rho * d q0 /d rho
    1063             :       !!     dq0_dgradrho = total_rho / |gradient_rho| * d q0 / d |gradient_rho|
    1064             :       !!
    1065             :       REAL(dp), INTENT(IN)                               :: total_rho(:), gradient_rho(:, :)
    1066             :       REAL(dp), INTENT(OUT)                              :: q0(:), dq0_drho(:), dq0_dgradrho(:)
    1067             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
    1068             : 
    1069             :       INTEGER, PARAMETER                                 :: m_cut = 12
    1070             : 
    1071             :       INTEGER                                            :: i_grid
    1072             :       REAL(dp)                                           :: b_value, C_value, dk_dn, dq0_dq, dw0_dn, &
    1073             :                                                             exponent, gmod2, k, mod_grad, q, &
    1074             :                                                             q__q_cut, q_cut, q_min, w0, wg2, wp2
    1075             : 
    1076         154 :       q_cut = dispersion_env%q_cut
    1077         154 :       q_min = dispersion_env%q_min
    1078         154 :       b_value = dispersion_env%b_value
    1079         154 :       C_value = dispersion_env%c_value
    1080             : 
    1081             :       ! initialize q0-related arrays ...
    1082      743418 :       q0(:) = q_cut
    1083      743418 :       dq0_drho(:) = 0.0_dp
    1084      743418 :       dq0_dgradrho(:) = 0.0_dp
    1085             : 
    1086      743418 :       DO i_grid = 1, SIZE(total_rho)
    1087             : 
    1088      743264 :          gmod2 = gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2
    1089             : 
    1090             :          !if (total_rho(i_grid) > epsr .and. gmod2 > epsr) cycle
    1091      743418 :          IF (total_rho(i_grid) > epsr) THEN
    1092             : 
    1093             :             !! Calculate some intermediate values needed to find q
    1094             :             !! ------------------------------------------------------------------------------------
    1095      653693 :             mod_grad = SQRT(gmod2)
    1096             : 
    1097      653693 :             wp2 = 16.0_dp*pi*total_rho(i_grid)
    1098      653693 :             wg2 = 4_dp*C_value*(mod_grad/total_rho(i_grid))**4
    1099             : 
    1100      653693 :             k = b_value*3.0_dp*pi*((total_rho(i_grid)/(9.0_dp*pi))**(1.0_dp/6.0_dp))
    1101      653693 :             w0 = SQRT(wg2 + wp2/3.0_dp)
    1102             : 
    1103      653693 :             q = w0/k
    1104             : 
    1105             :             !! Here, we calculate q0 by saturating q according
    1106             :             !! ---------------------------------------------------------------------------------------
    1107      653693 :             q__q_cut = q/q_cut
    1108      653693 :             CALL calculate_exponent_derivative(m_cut, q__q_cut, exponent, dq0_dq)
    1109      653693 :             q0(i_grid) = q_cut*(1.0_dp - EXP(-exponent))
    1110      653693 :             dq0_dq = dq0_dq*EXP(-exponent)
    1111             : 
    1112             :             !! ---------------------------------------------------------------------------------------
    1113      653693 :             IF (q0(i_grid) < q_min) THEN
    1114           3 :                q0(i_grid) = q_min
    1115             :             END IF
    1116             : 
    1117             :             !!---------------------------------Final values---------------------------------
    1118      653693 :             dw0_dn = 1.0_dp/(2.0_dp*w0)*(16.0_dp/3.0_dp*pi - 4.0_dp*wg2/total_rho(i_grid))
    1119      653693 :             dk_dn = k/(6.0_dp*total_rho(i_grid))
    1120             : 
    1121      653693 :             dq0_drho(i_grid) = dq0_dq*1.0_dp/(k**2.0)*(dw0_dn*k - dk_dn*w0)
    1122      653693 :             dq0_dgradrho(i_grid) = dq0_dq*1.0_dp/(2.0_dp*k*w0)*4.0_dp*wg2/gmod2
    1123             :          END IF
    1124             : 
    1125             :       END DO
    1126             : 
    1127         154 :    END SUBROUTINE get_q0_on_grid_rvv10
    1128             : 
    1129             : ! **************************************************************************************************
    1130             : !> \brief ...
    1131             : !> \param total_rho ...
    1132             : !> \param gradient_rho ...
    1133             : !> \param q0 ...
    1134             : !> \param dispersion_env ...
    1135             : ! **************************************************************************************************
    1136           0 :    SUBROUTINE get_q0_on_grid_eo_vdw(total_rho, gradient_rho, q0, dispersion_env)
    1137             : 
    1138             :       REAL(dp), INTENT(IN)                               :: total_rho(:), gradient_rho(:, :)
    1139             :       REAL(dp), INTENT(OUT)                              :: q0(:)
    1140             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
    1141             : 
    1142             :       INTEGER, PARAMETER                                 :: m_cut = 12
    1143             :       REAL(dp), PARAMETER :: LDA_A = 0.031091_dp, LDA_a1 = 0.2137_dp, LDA_b1 = 7.5957_dp, &
    1144             :          LDA_b2 = 3.5876_dp, LDA_b3 = 1.6382_dp, LDA_b4 = 0.49294_dp
    1145             : 
    1146             :       INTEGER                                            :: i_grid
    1147             :       REAL(dp)                                           :: exponent, gradient_correction, kF, &
    1148             :                                                             LDA_1, LDA_2, q, q__q_cut, q_cut, &
    1149             :                                                             q_min, r_s, sqrt_r_s, Z_ab
    1150             : 
    1151           0 :       q_cut = dispersion_env%q_cut
    1152           0 :       q_min = dispersion_env%q_min
    1153           0 :       SELECT CASE (dispersion_env%nl_type)
    1154             :       CASE DEFAULT
    1155           0 :          CPABORT("Unknown vdW-DF functional")
    1156             :       CASE (vdw_nl_DRSLL)
    1157           0 :          Z_ab = -0.8491_dp
    1158             :       CASE (vdw_nl_LMKLL)
    1159           0 :          Z_ab = -1.887_dp
    1160             :       END SELECT
    1161             : 
    1162             :       ! initialize q0-related arrays ...
    1163           0 :       q0(:) = q_cut
    1164           0 :       DO i_grid = 1, SIZE(total_rho)
    1165             :          !! This prevents numerical problems.  If the charge density is negative (an
    1166             :          !! unphysical situation), we simply treat it as very small.  In that case,
    1167             :          !! q0 will be very large and will be saturated.  For a saturated q0 the derivative
    1168             :          !! dq0_dq will be 0 so we set q0 = q_cut and dq0_drho = dq0_dgradrho = 0 and go on
    1169             :          !! to the next point.
    1170             :          !! ------------------------------------------------------------------------------------
    1171           0 :          IF (total_rho(i_grid) < epsr) CYCLE
    1172             :          !! ------------------------------------------------------------------------------------
    1173             :          !! Calculate some intermediate values needed to find q
    1174             :          !! ------------------------------------------------------------------------------------
    1175           0 :          kF = (3.0_dp*pi*pi*total_rho(i_grid))**(1.0_dp/3.0_dp)
    1176           0 :          r_s = (3.0_dp/(4.0_dp*pi*total_rho(i_grid)))**(1.0_dp/3.0_dp)
    1177           0 :          sqrt_r_s = SQRT(r_s)
    1178             : 
    1179             :          gradient_correction = -Z_ab/(36.0_dp*kF*total_rho(i_grid)**2) &
    1180           0 :                                *(gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2)
    1181             : 
    1182           0 :          LDA_1 = 8.0_dp*pi/3.0_dp*(LDA_A*(1.0_dp + LDA_a1*r_s))
    1183           0 :          LDA_2 = 2.0_dp*LDA_A*(LDA_b1*sqrt_r_s + LDA_b2*r_s + LDA_b3*r_s*sqrt_r_s + LDA_b4*r_s*r_s)
    1184             :          !! ------------------------------------------------------------------------------------
    1185             :          !! This is the q value defined in equations 11 and 12 of DION
    1186             :          !! ---------------------------------------------------------------
    1187           0 :          q = kF + LDA_1*LOG(1.0_dp + 1.0_dp/LDA_2) + gradient_correction
    1188             : 
    1189             :          !! ---------------------------------------------------------------
    1190             :          !! Here, we calculate q0 by saturating q according to equation 5 of SOLER.  Also, we find
    1191             :          !! the derivative dq0_dq needed for the derivatives dq0_drho and dq0_dgradrh0 discussed below.
    1192             :          !! ---------------------------------------------------------------------------------------
    1193           0 :          q__q_cut = q/q_cut
    1194           0 :          CALL calculate_exponent(m_cut, q__q_cut, exponent)
    1195           0 :          q0(i_grid) = q_cut*(1.0_dp - EXP(-exponent))
    1196             : 
    1197             :          !! ---------------------------------------------------------------------------------------
    1198             :          !! This is to handle a case with q0 too small.  We simply set it to the smallest q value in
    1199             :          !! out q_mesh.  Hopefully this doesn't get used often (ever)
    1200             :          !! ---------------------------------------------------------------------------------------
    1201           0 :          IF (q0(i_grid) < q_min) THEN
    1202           0 :             q0(i_grid) = q_min
    1203             :          END IF
    1204             :       END DO
    1205             : 
    1206           0 :    END SUBROUTINE get_q0_on_grid_eo_vdw
    1207             : 
    1208             : ! **************************************************************************************************
    1209             : !> \brief ...
    1210             : !> \param total_rho ...
    1211             : !> \param gradient_rho ...
    1212             : !> \param q0 ...
    1213             : !> \param dispersion_env ...
    1214             : ! **************************************************************************************************
    1215           6 :    PURE SUBROUTINE get_q0_on_grid_eo_rvv10(total_rho, gradient_rho, q0, dispersion_env)
    1216             : 
    1217             :       REAL(dp), INTENT(IN)                               :: total_rho(:), gradient_rho(:, :)
    1218             :       REAL(dp), INTENT(OUT)                              :: q0(:)
    1219             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
    1220             : 
    1221             :       INTEGER, PARAMETER                                 :: m_cut = 12
    1222             : 
    1223             :       INTEGER                                            :: i_grid
    1224             :       REAL(dp)                                           :: b_value, C_value, exponent, gmod2, k, q, &
    1225             :                                                             q__q_cut, q_cut, q_min, w0, wg2, wp2
    1226             : 
    1227           6 :       q_cut = dispersion_env%q_cut
    1228           6 :       q_min = dispersion_env%q_min
    1229           6 :       b_value = dispersion_env%b_value
    1230           6 :       C_value = dispersion_env%c_value
    1231             : 
    1232             :       ! initialize q0-related arrays ...
    1233       98310 :       q0(:) = q_cut
    1234             : 
    1235       98310 :       DO i_grid = 1, SIZE(total_rho)
    1236             : 
    1237       98304 :          gmod2 = gradient_rho(i_grid, 1)**2 + gradient_rho(i_grid, 2)**2 + gradient_rho(i_grid, 3)**2
    1238             : 
    1239             :          !if (total_rho(i_grid) > epsr .and. gmod2 > epsr) cycle
    1240       98310 :          IF (total_rho(i_grid) > epsr) THEN
    1241             : 
    1242             :             !! Calculate some intermediate values needed to find q
    1243             :             !! ------------------------------------------------------------------------------------
    1244       72326 :             wp2 = 16.0_dp*pi*total_rho(i_grid)
    1245       72326 :             wg2 = 4_dp*C_value*(gmod2*gmod2)/(total_rho(i_grid)**4)
    1246             : 
    1247       72326 :             k = b_value*3.0_dp*pi*((total_rho(i_grid)/(9.0_dp*pi))**(1.0_dp/6.0_dp))
    1248       72326 :             w0 = SQRT(wg2 + wp2/3.0_dp)
    1249             : 
    1250       72326 :             q = w0/k
    1251             : 
    1252             :             !! Here, we calculate q0 by saturating q according
    1253             :             !! ---------------------------------------------------------------------------------------
    1254       72326 :             q__q_cut = q/q_cut
    1255       72326 :             CALL calculate_exponent(m_cut, q__q_cut, exponent)
    1256       72326 :             q0(i_grid) = q_cut*(1.0_dp - EXP(-exponent))
    1257             : 
    1258       72326 :             IF (q0(i_grid) < q_min) THEN
    1259           1 :                q0(i_grid) = q_min
    1260             :             END IF
    1261             : 
    1262             :          END IF
    1263             : 
    1264             :       END DO
    1265             : 
    1266           6 :    END SUBROUTINE get_q0_on_grid_eo_rvv10
    1267             : 
    1268             : ! **************************************************************************************************
    1269             : !> \brief This routine is modeled after an algorithm from "Numerical Recipes in C" by Cambridge University
    1270             : !> press, page 97.  It was adapted for Fortran, of course and for the problem at hand, in that it finds
    1271             : !> the bin a particular x value is in and then loops over all the P_i functions so we only have to find
    1272             : !> the bin once.
    1273             : !> \param x ...
    1274             : !> \param d2y_dx2 ...
    1275             : !> \param evaluation_points ...
    1276             : !> \param values ...
    1277             : !> \par History
    1278             : !>     OpenMP added: Aug 2016  MTucker
    1279             : ! **************************************************************************************************
    1280         388 :    SUBROUTINE spline_interpolation(x, d2y_dx2, evaluation_points, values)
    1281             :       REAL(dp), INTENT(in)                               :: x(:), d2y_dx2(:, :), evaluation_points(:)
    1282             :       REAL(dp), INTENT(out)                              :: values(:, :)
    1283             : 
    1284             :       INTEGER                                            :: i_grid, index, lower_bound, &
    1285             :                                                             Ngrid_points, Nx, P_i, upper_bound
    1286             :       REAL(dp)                                           :: a, b, c, const, d, dx
    1287         388 :       REAL(dp), ALLOCATABLE                              :: y(:)
    1288             : 
    1289         388 :       Nx = SIZE(x)
    1290         388 :       Ngrid_points = SIZE(evaluation_points)
    1291             : 
    1292             : !$OMP PARALLEL DEFAULT( NONE )                                         &
    1293             : !$OMP           SHARED( x, d2y_dx2, evaluation_points, values          &
    1294             : !$OMP                 , Nx, Ngrid_points                               &
    1295             : !$OMP                 )                                                &
    1296             : !$OMP          PRIVATE( y, lower_bound, upper_bound, index             &
    1297             : !$OMP                 , dx, const, A, b, c, d, P_i                     &
    1298         388 : !$OMP                 )
    1299             : 
    1300             :       ALLOCATE (y(Nx))
    1301             : 
    1302             : !$OMP DO
    1303             :       DO i_grid = 1, Ngrid_points
    1304             :          lower_bound = 1
    1305             :          upper_bound = Nx
    1306             :          DO WHILE ((upper_bound - lower_bound) > 1)
    1307             :             index = (upper_bound + lower_bound)/2
    1308             :             IF (evaluation_points(i_grid) > x(index)) THEN
    1309             :                lower_bound = index
    1310             :             ELSE
    1311             :                upper_bound = index
    1312             :             END IF
    1313             :          END DO
    1314             : 
    1315             :          dx = x(upper_bound) - x(lower_bound)
    1316             :          const = dx*dx/6.0_dp
    1317             : 
    1318             :          a = (x(upper_bound) - evaluation_points(i_grid))/dx
    1319             :          b = (evaluation_points(i_grid) - x(lower_bound))/dx
    1320             :          c = (a**3 - a)*const
    1321             :          d = (b**3 - b)*const
    1322             : 
    1323             :          DO P_i = 1, Nx
    1324             :             y = 0
    1325             :             y(P_i) = 1
    1326             :             values(i_grid, P_i) = a*y(lower_bound) + b*y(upper_bound) &
    1327             :                                   + (c*d2y_dx2(P_i, lower_bound) + d*d2y_dx2(P_i, upper_bound))
    1328             :          END DO
    1329             :       END DO
    1330             : !$OMP END DO
    1331             : 
    1332             :       DEALLOCATE (y)
    1333             : !$OMP END PARALLEL
    1334         388 :    END SUBROUTINE spline_interpolation
    1335             : 
    1336             : ! **************************************************************************************************
    1337             : !> \brief This routine is modeled after an algorithm from "Numerical Recipes in C" by Cambridge
    1338             : !> University Press, pages 96-97.  It was adapted for Fortran and for the problem at hand.
    1339             : !> \param x ...
    1340             : !> \param d2y_dx2 ...
    1341             : !> \par History
    1342             : !>     OpenMP added: Aug 2016  MTucker
    1343             : ! **************************************************************************************************
    1344          46 :    SUBROUTINE initialize_spline_interpolation(x, d2y_dx2)
    1345             : 
    1346             :       REAL(dp), INTENT(in)                               :: x(:)
    1347             :       REAL(dp), INTENT(inout)                            :: d2y_dx2(:, :)
    1348             : 
    1349             :       INTEGER                                            :: index, Nx, P_i
    1350             :       REAL(dp)                                           :: temp1, temp2
    1351          46 :       REAL(dp), ALLOCATABLE                              :: temp_array(:), y(:)
    1352             : 
    1353          46 :       Nx = SIZE(x)
    1354             : 
    1355             : !$OMP PARALLEL DEFAULT( NONE )                  &
    1356             : !$OMP           SHARED( x, d2y_dx2, Nx )        &
    1357             : !$OMP          PRIVATE( temp_array, y           &
    1358             : !$OMP                 , index, temp1, temp2     &
    1359          46 : !$OMP                 )
    1360             : 
    1361             :       ALLOCATE (temp_array(Nx), y(Nx))
    1362             : 
    1363             : !$OMP DO
    1364             :       DO P_i = 1, Nx
    1365             :          !! In the Soler method, the polynomials that are interpolated are Kronecker delta functions
    1366             :          !! at a particular q point.  So, we set all y values to 0 except the one corresponding to
    1367             :          !! the particular function P_i.
    1368             :          !! ----------------------------------------------------------------------------------------
    1369             :          y = 0.0_dp
    1370             :          y(P_i) = 1.0_dp
    1371             :          !! ----------------------------------------------------------------------------------------
    1372             : 
    1373             :          d2y_dx2(P_i, 1) = 0.0_dp
    1374             :          temp_array(1) = 0.0_dp
    1375             :          DO index = 2, Nx - 1
    1376             :             temp1 = (x(index) - x(index - 1))/(x(index + 1) - x(index - 1))
    1377             :             temp2 = temp1*d2y_dx2(P_i, index - 1) + 2.0_dp
    1378             :             d2y_dx2(P_i, index) = (temp1 - 1.0_dp)/temp2
    1379             :             temp_array(index) = (y(index + 1) - y(index))/(x(index + 1) - x(index)) &
    1380             :                                 - (y(index) - y(index - 1))/(x(index) - x(index - 1))
    1381             :             temp_array(index) = (6.0_dp*temp_array(index)/(x(index + 1) - x(index - 1)) &
    1382             :                                  - temp1*temp_array(index - 1))/temp2
    1383             :          END DO
    1384             :          d2y_dx2(P_i, Nx) = 0.0_dp
    1385             :          DO index = Nx - 1, 1, -1
    1386             :             d2y_dx2(P_i, index) = d2y_dx2(P_i, index)*d2y_dx2(P_i, index + 1) + temp_array(index)
    1387             :          END DO
    1388             :       END DO
    1389             : !$OMP END DO
    1390             : 
    1391             :       DEALLOCATE (temp_array, y)
    1392             : !$OMP END PARALLEL
    1393             : 
    1394          46 :    END SUBROUTINE initialize_spline_interpolation
    1395             : 
    1396             :    ! **************************************************************************************************
    1397             :    !! This routine is modeled after an algorithm from "Numerical Recipes in C" by Cambridge
    1398             :    !! University Press, page 97.  Adapted for Fortran and the problem at hand.  This function is used to
    1399             :    !! find the Phi_alpha_beta needed for equations 8 and 11 of SOLER.
    1400             : ! **************************************************************************************************
    1401             : !> \brief ...
    1402             : !> \param k ...
    1403             : !> \param kernel_of_k ...
    1404             : !> \param dispersion_env ...
    1405             : !> \par History
    1406             : !>     Optimised when adding OpenMP to vdw_energy (which calls this routine): Aug 2016 MTucker
    1407             : ! **************************************************************************************************
    1408      386581 :    SUBROUTINE interpolate_kernel(k, kernel_of_k, dispersion_env)
    1409             :       REAL(dp), INTENT(in)                               :: k
    1410             :       REAL(dp), INTENT(out)                              :: kernel_of_k(:, :)
    1411             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
    1412             : 
    1413             :       INTEGER                                            :: k_i, Nr_points, q1_i, q2_i
    1414             :       REAL(dp)                                           :: A, B, C, const, D, dk, r_max
    1415      386581 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: d2phi_dk2, kernel
    1416             : 
    1417      386581 :       Nr_points = dispersion_env%nr_points
    1418      386581 :       r_max = dispersion_env%r_max
    1419      386581 :       dk = dispersion_env%dk
    1420      386581 :       kernel => dispersion_env%kernel
    1421      386581 :       d2phi_dk2 => dispersion_env%d2phi_dk2
    1422             : 
    1423             :       !! Check to make sure that the kernel table we have is capable of dealing with this
    1424             :       !! value of k.  If k is larger than Nr_points*2*pi/r_max then we can't perform the
    1425             :       !! interpolation.  In that case, a kernel file should be generated with a larger number
    1426             :       !! of radial points.
    1427             :       !! -------------------------------------------------------------------------------------
    1428           0 :       CPASSERT(k < Nr_points*dk)
    1429             :       !! -------------------------------------------------------------------------------------
    1430   162750601 :       kernel_of_k = 0.0_dp
    1431             :       !! This integer division figures out which bin k is in since the kernel
    1432             :       !! is set on a uniform grid.
    1433      386581 :       k_i = INT(k/dk)
    1434             : 
    1435             :       !! Test to see if we are trying to interpolate a k that is one of the actual
    1436             :       !! function points we have.  The value is just the value of the function in that
    1437             :       !! case.
    1438             :       !! ----------------------------------------------------------------------------------------
    1439      386581 :       IF (MOD(k, dk) == 0) THEN
    1440        4074 :          DO q1_i = 1, dispersion_env%Nqs
    1441       44814 :             DO q2_i = 1, q1_i
    1442       40740 :                kernel_of_k(q1_i, q2_i) = kernel(k_i, q1_i, q2_i)
    1443       44620 :                kernel_of_k(q2_i, q1_i) = kernel(k_i, q2_i, q1_i)
    1444             :             END DO
    1445             :          END DO
    1446      386581 :          RETURN
    1447             :       END IF
    1448             :       !! ----------------------------------------------------------------------------------------
    1449             :       !! If we are not on a function point then we carry out the interpolation
    1450             :       !! ----------------------------------------------------------------------------------------
    1451      386387 :       const = dk*dk/6.0_dp
    1452      386387 :       A = (dk*(k_i + 1.0_dp) - k)/dk
    1453      386387 :       B = (k - dk*k_i)/dk
    1454      386387 :       C = (A**3 - A)*const
    1455      386387 :       D = (B**3 - B)*const
    1456     8114127 :       DO q1_i = 1, dispersion_env%Nqs
    1457    89255397 :          DO q2_i = 1, q1_i
    1458             :             kernel_of_k(q1_i, q2_i) = A*kernel(k_i, q1_i, q2_i) + B*kernel(k_i + 1, q1_i, q2_i) &
    1459    81141270 :                                       + (C*d2phi_dk2(k_i, q1_i, q2_i) + D*d2phi_dk2(k_i + 1, q1_i, q2_i))
    1460    88869010 :             kernel_of_k(q2_i, q1_i) = kernel_of_k(q1_i, q2_i)
    1461             :          END DO
    1462             :       END DO
    1463             : 
    1464      386581 :    END SUBROUTINE interpolate_kernel
    1465             : 
    1466             : ! **************************************************************************************************
    1467             : !> \brief ...
    1468             : !> \param k ...
    1469             : !> \param dkernel_of_dk ...
    1470             : !> \param dispersion_env ...
    1471             : !> \par History
    1472             : !>     Optimised when adding OpenMP to vdw_energy (which calls this routine): Aug 2016 MTucker
    1473             : ! **************************************************************************************************
    1474      297276 :    SUBROUTINE interpolate_dkernel_dk(k, dkernel_of_dk, dispersion_env)
    1475             :       REAL(dp), INTENT(in)                               :: k
    1476             :       REAL(dp), INTENT(out)                              :: dkernel_of_dk(:, :)
    1477             :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
    1478             : 
    1479             :       INTEGER                                            :: k_i, Nr_points, q1_i, q2_i
    1480             :       REAL(dp)                                           :: A, B, dAdk, dBdk, dCdk, dDdk, dk, dk_6
    1481      297276 :       REAL(dp), DIMENSION(:, :, :), POINTER              :: d2phi_dk2, kernel
    1482             : 
    1483      297276 :       Nr_points = dispersion_env%nr_points
    1484      297276 :       dk = dispersion_env%dk
    1485      297276 :       kernel => dispersion_env%kernel
    1486      297276 :       d2phi_dk2 => dispersion_env%d2phi_dk2
    1487      297276 :       dk_6 = dk/6.0_dp
    1488             : 
    1489           0 :       CPASSERT(k < Nr_points*dk)
    1490             : 
    1491   125153196 :       dkernel_of_dk = 0.0_dp
    1492      297276 :       k_i = INT(k/dk)
    1493             : 
    1494      297276 :       A = (dk*(k_i + 1.0_dp) - k)/dk
    1495      297276 :       B = (k - dk*k_i)/dk
    1496      297276 :       dAdk = -1.0_dp/dk
    1497      297276 :       dBdk = 1.0_dp/dk
    1498      297276 :       dCdk = -(3*A**2 - 1.0_dp)*dk_6
    1499      297276 :       dDdk = (3*B**2 - 1.0_dp)*dk_6
    1500     6242796 :       DO q1_i = 1, dispersion_env%Nqs
    1501    68670756 :          DO q2_i = 1, q1_i
    1502             :             dkernel_of_dk(q1_i, q2_i) = dAdk*kernel(k_i, q1_i, q2_i) + dBdk*kernel(k_i + 1, q1_i, q2_i) &
    1503    62427960 :                                         + dCdk*d2phi_dk2(k_i, q1_i, q2_i) + dDdk*d2phi_dk2(k_i + 1, q1_i, q2_i)
    1504    68373480 :             dkernel_of_dk(q2_i, q1_i) = dkernel_of_dk(q1_i, q2_i)
    1505             :          END DO
    1506             :       END DO
    1507             : 
    1508      297276 :    END SUBROUTINE interpolate_dkernel_dk
    1509             : 
    1510             : ! **************************************************************************************************
    1511             : 
    1512             : END MODULE qs_dispersion_nonloc

Generated by: LCOV version 1.15