LCOV - code coverage report
Current view: top level - src - qs_dispersion_d2.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:9ccafda) Lines: 91.2 % 91 83
Test Date: 2026-10-15 00:55:44 Functions: 100.0 % 2 2

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \brief Calculation of D2 dispersion with Grimme or Chai-Head-Gordon damping
      10              : !> \author JGH
      11              : ! **************************************************************************************************
      12              : MODULE qs_dispersion_d2
      13              : 
      14              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      15              :                                               get_atomic_kind,&
      16              :                                               get_atomic_kind_set
      17              :    USE atprop_types,                    ONLY: atprop_array_init,&
      18              :                                               atprop_type
      19              :    USE cell_types,                      ONLY: cell_type
      20              :    USE input_constants,                 ONLY: vdw_pairpot_dftd2chg
      21              :    USE kinds,                           ONLY: dp
      22              :    USE physcon,                         ONLY: bohr,&
      23              :                                               kjmol
      24              :    USE qs_dispersion_types,             ONLY: qs_atom_dispersion_type,&
      25              :                                               qs_dispersion_type
      26              :    USE qs_environment_types,            ONLY: get_qs_env,&
      27              :                                               qs_environment_type
      28              :    USE qs_force_types,                  ONLY: qs_force_type
      29              :    USE qs_kind_types,                   ONLY: get_qs_kind,&
      30              :                                               qs_kind_type
      31              :    USE qs_neighbor_list_types,          ONLY: get_iterator_info,&
      32              :                                               neighbor_list_iterate,&
      33              :                                               neighbor_list_iterator_create,&
      34              :                                               neighbor_list_iterator_p_type,&
      35              :                                               neighbor_list_iterator_release,&
      36              :                                               neighbor_list_set_p_type
      37              :    USE virial_methods,                  ONLY: virial_pair_force
      38              :    USE virial_types,                    ONLY: virial_type
      39              : #include "./base/base_uses.f90"
      40              : 
      41              :    IMPLICIT NONE
      42              : 
      43              :    PRIVATE
      44              : 
      45              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dispersion_d2'
      46              : 
      47              :    PUBLIC :: calculate_dispersion_d2_pairpot, dftd2_param
      48              : 
      49              : ! **************************************************************************************************
      50              : 
      51              : CONTAINS
      52              : 
      53              : ! **************************************************************************************************
      54              : !> \brief ...
      55              : !> \param qs_env ...
      56              : !> \param dispersion_env ...
      57              : !> \param evdw ...
      58              : !> \param calculate_forces ...
      59              : !> \param atevdw ...
      60              : ! **************************************************************************************************
      61           74 :    SUBROUTINE calculate_dispersion_d2_pairpot(qs_env, dispersion_env, evdw, calculate_forces, atevdw)
      62              : 
      63              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      64              :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
      65              :       REAL(KIND=dp), INTENT(OUT)                         :: evdw
      66              :       LOGICAL, INTENT(IN)                                :: calculate_forces
      67              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: atevdw
      68              : 
      69              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_dispersion_d2_pairpot'
      70              : 
      71              :       INTEGER                                            :: atom_a, atom_b, handle, iatom, ikind, &
      72              :                                                             jatom, jkind, mepos, natom, nkind, &
      73              :                                                             num_pe, za, zb
      74           74 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_of_kind, atomnumber, kind_of
      75              :       LOGICAL                                            :: atenergy, atex, chg_damping, floating_a, &
      76              :                                                             ghost_a, use_virial
      77           74 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: dodisp, floating, ghost
      78              :       REAL(KIND=dp)                                      :: c6, dd, devdw, dfdmp, dr, er, fac, fdmp, &
      79              :                                                             rcc, rcut, s6, xp
      80           74 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: c6d2, radd2
      81              :       REAL(KIND=dp), DIMENSION(3)                        :: fdij, rij
      82              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: pv_virial_thread
      83           74 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: atener
      84           74 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
      85              :       TYPE(atprop_type), POINTER                         :: atprop
      86              :       TYPE(cell_type), POINTER                           :: cell
      87              :       TYPE(neighbor_list_iterator_p_type), &
      88           74 :          DIMENSION(:), POINTER                           :: nl_iterator
      89              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
      90           74 :          POINTER                                         :: sab_vdw
      91              :       TYPE(qs_atom_dispersion_type), POINTER             :: disp_a
      92           74 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
      93           74 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
      94              :       TYPE(virial_type), POINTER                         :: virial
      95              : 
      96           74 :       CALL timeset(routineN, handle)
      97              : 
      98           74 :       evdw = 0._dp
      99              : 
     100           74 :       NULLIFY (atomic_kind_set, qs_kind_set, sab_vdw)
     101              : 
     102              :       CALL get_qs_env(qs_env=qs_env, nkind=nkind, natom=natom, atomic_kind_set=atomic_kind_set, &
     103           74 :                       qs_kind_set=qs_kind_set, cell=cell, virial=virial, atprop=atprop)
     104              : 
     105              :       ! atomic energy and stress arrays
     106           74 :       atenergy = atprop%energy
     107           74 :       IF (atenergy) THEN
     108            0 :          CALL atprop_array_init(atprop%atevdw, natom)
     109            0 :          atener => atprop%atevdw
     110              :       END IF
     111              :       ! external atomic energy
     112           74 :       atex = .FALSE.
     113           74 :       IF (PRESENT(atevdw)) THEN
     114            0 :          atex = .TRUE.
     115              :       END IF
     116              : 
     117           74 :       NULLIFY (force)
     118           74 :       CALL get_qs_env(qs_env=qs_env, force=force)
     119           74 :       CALL get_atomic_kind_set(atomic_kind_set, atom_of_kind=atom_of_kind, kind_of=kind_of)
     120           74 :       use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
     121           74 :       pv_virial_thread(:, :) = 0._dp
     122              : 
     123          666 :       ALLOCATE (dodisp(nkind), ghost(nkind), floating(nkind), atomnumber(nkind), c6d2(nkind), radd2(nkind))
     124          236 :       DO ikind = 1, nkind
     125          162 :          CALL get_atomic_kind(atomic_kind_set(ikind), z=za)
     126          162 :          CALL get_qs_kind(qs_kind_set(ikind), dispersion=disp_a, ghost=ghost_a, floating=floating_a)
     127          162 :          dodisp(ikind) = disp_a%defined
     128          162 :          ghost(ikind) = ghost_a
     129          162 :          floating(ikind) = floating_a
     130          162 :          atomnumber(ikind) = za
     131          162 :          c6d2(ikind) = disp_a%c6
     132          398 :          radd2(ikind) = disp_a%vdw_radii
     133              :       END DO
     134              : 
     135           74 :       rcut = 2._dp*dispersion_env%rc_disp
     136           74 :       s6 = dispersion_env%scaling
     137           74 :       dd = dispersion_env%exp_pre
     138           74 :       chg_damping = dispersion_env%pp_type == vdw_pairpot_dftd2chg
     139              : 
     140           74 :       sab_vdw => dispersion_env%sab_vdw
     141           74 :       num_pe = 1
     142           74 :       CALL neighbor_list_iterator_create(nl_iterator, sab_vdw, nthread=num_pe)
     143              : 
     144           74 :       mepos = 0
     145        33110 :       DO WHILE (neighbor_list_iterate(nl_iterator, mepos=mepos) == 0)
     146        33036 :          CALL get_iterator_info(nl_iterator, mepos=mepos, ikind=ikind, jkind=jkind, iatom=iatom, jatom=jatom, r=rij)
     147              : 
     148        33036 :          IF (ghost(ikind) .OR. ghost(jkind) .OR. floating(ikind) .OR. floating(jkind)) CYCLE
     149              : 
     150        32538 :          IF (.NOT. (dodisp(ikind) .AND. dodisp(jkind))) CYCLE
     151              : 
     152              :          za = atomnumber(ikind)
     153              :          zb = atomnumber(jkind)
     154              :          ! vdW potential
     155       130152 :          dr = SQRT(SUM(rij(:)**2))
     156        32612 :          IF (dr <= rcut) THEN
     157        32538 :             fac = 1._dp
     158        32538 :             IF (iatom == jatom) fac = 0.5_dp
     159        32538 :             IF (dr > 0.001_dp) THEN
     160        32315 :                c6 = SQRT(c6d2(ikind)*c6d2(jkind))
     161        32315 :                rcc = radd2(ikind) + radd2(jkind)
     162        32315 :                IF (chg_damping) THEN
     163              :                   ! Chai-Head-Gordon damping, using the same radii as Grimme D2.
     164            3 :                   er = 6._dp*(rcc/dr)**12
     165              :                ELSE
     166        32312 :                   er = EXP(-dd*(dr/rcc - 1._dp))
     167              :                END IF
     168        32315 :                fdmp = 1._dp/(1._dp + er)
     169        32315 :                xp = s6*c6/dr**6
     170        32315 :                evdw = evdw - xp*fdmp*fac
     171        32315 :                IF (calculate_forces) THEN
     172        31435 :                   IF (chg_damping) THEN
     173            3 :                      dfdmp = 12._dp/dr*er*fdmp*fdmp
     174              :                   ELSE
     175        31432 :                      dfdmp = dd/rcc*er*fdmp*fdmp
     176              :                   END IF
     177        31435 :                   devdw = -xp*(-6._dp*fdmp/dr + dfdmp)
     178       125740 :                   fdij(:) = devdw*rij(:)/dr*fac
     179        31435 :                   atom_a = atom_of_kind(iatom)
     180        31435 :                   atom_b = atom_of_kind(jatom)
     181       125740 :                   force(ikind)%dispersion(:, atom_a) = force(ikind)%dispersion(:, atom_a) - fdij(:)
     182       125740 :                   force(jkind)%dispersion(:, atom_b) = force(jkind)%dispersion(:, atom_b) + fdij(:)
     183        31435 :                   IF (use_virial) THEN
     184         9842 :                      CALL virial_pair_force(pv_virial_thread, -1._dp, fdij, rij)
     185              :                   END IF
     186              :                END IF
     187        32315 :                IF (atenergy) THEN
     188            0 :                   atener(iatom) = atener(iatom) - 0.5_dp*xp*fdmp*fac
     189            0 :                   atener(jatom) = atener(jatom) - 0.5_dp*xp*fdmp*fac
     190              :                END IF
     191        32315 :                IF (atex) THEN
     192            0 :                   atevdw(iatom) = atevdw(iatom) - 0.5_dp*xp*fdmp*fac
     193            0 :                   atevdw(jatom) = atevdw(jatom) - 0.5_dp*xp*fdmp*fac
     194              :                END IF
     195              :             END IF
     196              :          END IF
     197              : 
     198              :       END DO
     199              : 
     200          962 :       virial%pv_virial = virial%pv_virial + pv_virial_thread
     201              : 
     202           74 :       CALL neighbor_list_iterator_release(nl_iterator)
     203              : 
     204           74 :       DEALLOCATE (dodisp, ghost, floating, atomnumber, radd2, c6d2)
     205              : 
     206           74 :       CALL timestop(handle)
     207              : 
     208          148 :    END SUBROUTINE calculate_dispersion_d2_pairpot
     209              : 
     210              : ! **************************************************************************************************
     211              : !> \brief ...
     212              : !> \param z ...
     213              : !> \param c6 ...
     214              : !> \param r ...
     215              : !> \param found ...
     216              : ! **************************************************************************************************
     217           70 :    SUBROUTINE dftd2_param(z, c6, r, found)
     218              : 
     219              :       INTEGER, INTENT(in)                                :: z
     220              :       REAL(KIND=dp), INTENT(inout)                       :: c6, r
     221              :       LOGICAL, INTENT(inout)                             :: found
     222              : 
     223              :       REAL(KIND=dp), DIMENSION(54), PARAMETER :: c6val = [0.14_dp, 0.08_dp, 1.61_dp, 1.61_dp, &
     224              :          3.13_dp, 1.75_dp, 1.23_dp, 0.70_dp, 0.75_dp, 0.63_dp, 5.71_dp, 5.71_dp, 10.79_dp, 9.23_dp,&
     225              :          7.84_dp, 5.57_dp, 5.07_dp, 4.61_dp, 10.80_dp, 10.80_dp, 10.80_dp, 10.80_dp, 10.80_dp, &
     226              :          10.80_dp, 10.80_dp, 10.80_dp, 10.80_dp, 10.80_dp, 10.80_dp, 10.80_dp, 16.99_dp, 17.10_dp, &
     227              :          16.37_dp, 12.64_dp, 12.47_dp, 12.01_dp, 24.67_dp, 24.67_dp, 24.67_dp, 24.67_dp, 24.67_dp, &
     228              :          24.67_dp, 24.67_dp, 24.67_dp, 24.67_dp, 24.67_dp, 24.67_dp, 24.67_dp, 37.32_dp, 38.71_dp, &
     229              :          38.44_dp, 31.74_dp, 31.50_dp, 29.99_dp]
     230              :       REAL(KIND=dp), DIMENSION(54), PARAMETER :: rval = [1.001_dp, 1.012_dp, 0.825_dp, 1.408_dp, &
     231              :          1.485_dp, 1.452_dp, 1.397_dp, 1.342_dp, 1.287_dp, 1.243_dp, 1.144_dp, 1.364_dp, 1.639_dp, &
     232              :          1.716_dp, 1.705_dp, 1.683_dp, 1.639_dp, 1.595_dp, 1.485_dp, 1.474_dp, 1.562_dp, 1.562_dp, &
     233              :          1.562_dp, 1.562_dp, 1.562_dp, 1.562_dp, 1.562_dp, 1.562_dp, 1.562_dp, 1.562_dp, 1.650_dp, &
     234              :          1.727_dp, 1.760_dp, 1.771_dp, 1.749_dp, 1.727_dp, 1.628_dp, 1.606_dp, 1.639_dp, 1.639_dp, &
     235              :          1.639_dp, 1.639_dp, 1.639_dp, 1.639_dp, 1.639_dp, 1.639_dp, 1.639_dp, 1.639_dp, 1.672_dp, &
     236              :          1.804_dp, 1.881_dp, 1.892_dp, 1.892_dp, 1.881_dp]
     237              : 
     238              : !
     239              : ! GRIMME DISPERSION PARAMETERS
     240              : ! Stefan Grimme, Semiempirical GGA-Type Density Functional Constructed
     241              : !                with a Long-Range Dispersion Correction, J. Comp. Chem. 27: 1787-1799 (2006)
     242              : ! doi:10.1002/jcc.20495
     243              : !
     244              : ! Conversion factor [Jnm^6mol^-1] -> [a.u.] : 17.34527758021901
     245              : ! Conversion factor [A] -> [a.u.] : 1.889726132885643
     246              : !
     247              : ! C6 values in [Jnm^6/mol]
     248              : ! vdW radii [A]
     249              : 
     250           70 :       IF (z > 0 .AND. z <= 54) THEN
     251           70 :          found = .TRUE.
     252           70 :          c6 = c6val(z)*1000._dp*bohr**6/kjmol
     253           70 :          r = rval(z)*bohr
     254              :       ELSE
     255            0 :          found = .FALSE.
     256              :       END IF
     257              : 
     258           70 :    END SUBROUTINE dftd2_param
     259              : 
     260              : ! **************************************************************************************************
     261              : 
     262              : END MODULE qs_dispersion_d2
        

Generated by: LCOV version 2.0-1