LCOV - code coverage report
Current view: top level - src - qs_dispersion_nonloc.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 91.5 % 413 378
Test Date: 2025-12-04 06:27:48 Functions: 92.9 % 14 13

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

Generated by: LCOV version 2.0-1