LCOV - code coverage report
Current view: top level - src - qs_dispersion_d4.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 70.4 % 587 413
Test Date: 2026-06-05 07:04:50 Functions: 66.7 % 12 8

            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 dispersion using pair potentials
      10              : !> \author Johann Pototschnig
      11              : ! **************************************************************************************************
      12              : MODULE qs_dispersion_d4
      13              :    USE atomic_kind_types, ONLY: atomic_kind_type, &
      14              :                                 get_atomic_kind, &
      15              :                                 get_atomic_kind_set
      16              :    USE distribution_1d_types, ONLY: distribution_1d_type
      17              :    USE eeq_method, ONLY: eeq_charges, eeq_forces
      18              :    USE machine, ONLY: m_flush, &
      19              :                       m_walltime
      20              :    USE cell_types, ONLY: cell_type, &
      21              :                          plane_distance, &
      22              :                          pbc, &
      23              :                          get_cell
      24              :    USE qs_environment_types, ONLY: get_qs_env, &
      25              :                                    qs_environment_type
      26              :    USE qs_force_types, ONLY: qs_force_type
      27              :    USE qs_kind_types, ONLY: get_qs_kind, &
      28              :                             qs_kind_type, &
      29              :                             set_qs_kind
      30              :    USE qs_neighbor_list_types, ONLY: get_iterator_info, &
      31              :                                      neighbor_list_iterate, &
      32              :                                      neighbor_list_iterator_create, &
      33              :                                      neighbor_list_iterator_p_type, &
      34              :                                      neighbor_list_iterator_release, &
      35              :                                      neighbor_list_set_p_type
      36              :    USE virial_methods, ONLY: virial_pair_force
      37              :    USE virial_types, ONLY: virial_type
      38              :    USE kinds, ONLY: dp
      39              :    USE particle_types, ONLY: particle_type
      40              :    USE qs_dispersion_types, ONLY: qs_dispersion_type
      41              :    USE qs_dispersion_utils, ONLY: cellhash
      42              :    USE qs_dispersion_cnum, ONLY: cnumber_init, dcnum_type, cnumber_release
      43              :    USE message_passing, ONLY: mp_para_env_type
      44              : 
      45              : #if defined(__DFTD4)
      46              : !&<
      47              :    USE dftd4,                           ONLY: d4_model, &
      48              :                                               damping_param, &
      49              :                                               get_dispersion, &
      50              :                                               get_rational_damping, &
      51              :                                               new, &
      52              :                                               new_d4_model, &
      53              :                                               realspace_cutoff, &
      54              :                                               structure_type, &
      55              :                                               rational_damping_param, &
      56              :                                               get_coordination_number, &
      57              :                                               get_lattice_points
      58              : #if defined(__DFTD4_V3)
      59              :    USE dftd4_charge,                    ONLY: get_charges
      60              : #else
      61              :    USE multicharge,                     ONLY: get_charges
      62              :    USE mctc_env,                        ONLY: error_type
      63              : #endif
      64              : !&>
      65              : #endif
      66              : #include "./base/base_uses.f90"
      67              : 
      68              :    IMPLICIT NONE
      69              : 
      70              :    PRIVATE
      71              : 
      72              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_dispersion_d4'
      73              : 
      74              :    PUBLIC :: calculate_dispersion_d4_pairpot
      75              : 
      76              : ! **************************************************************************************************
      77              : 
      78              : CONTAINS
      79              : 
      80              : #if defined(__DFTD4)
      81              : ! **************************************************************************************************
      82              : !> \brief Read smooth-cutoff width override from environment.
      83              : !> \param primary primary environment variable name
      84              : !> \param fallback fallback environment variable name
      85              : !> \param cutoff real-space cutoff used to validate the width
      86              : !> \param width smooth-cutoff width to update
      87              : ! **************************************************************************************************
      88         1820 :    SUBROUTINE d4_smooth_width_from_env(primary, fallback, cutoff, width)
      89              :       CHARACTER(LEN=*), INTENT(IN)                       :: primary, fallback
      90              :       REAL(KIND=dp), INTENT(IN)                          :: cutoff
      91              :       REAL(KIND=dp), INTENT(INOUT)                       :: width
      92              : 
      93              :       CHARACTER(LEN=64)                                  :: env
      94              :       INTEGER                                            :: io, stat
      95              :       REAL(KIND=dp)                                      :: env_width
      96              : 
      97         1820 :       CALL GET_ENVIRONMENT_VARIABLE(primary, env, STATUS=stat)
      98         1820 :       IF (stat /= 0 .OR. LEN_TRIM(env) == 0) THEN
      99         1820 :          CALL GET_ENVIRONMENT_VARIABLE(fallback, env, STATUS=stat)
     100              :       END IF
     101         1820 :       IF (stat == 0 .AND. LEN_TRIM(env) > 0) THEN
     102            0 :          READ (env, *, IOSTAT=io) env_width
     103            0 :          IF (io == 0) THEN
     104            0 :             IF (env_width > 0.0_dp .AND. env_width < cutoff) THEN
     105            0 :                width = env_width
     106              :             ELSE
     107            0 :                width = 0.0_dp
     108              :             END IF
     109              :          END IF
     110              :       END IF
     111              : 
     112         1820 :    END SUBROUTINE d4_smooth_width_from_env
     113              : 
     114              : ! **************************************************************************************************
     115              : !> \brief ...
     116              : !> \param qs_env ...
     117              : !> \param dispersion_env ...
     118              : !> \param evdw ...
     119              : !> \param calculate_forces ...
     120              : !> \param iw ...
     121              : !> \param atomic_energy ...
     122              : ! **************************************************************************************************
     123          910 :    SUBROUTINE calculate_dispersion_d4_pairpot(qs_env, dispersion_env, evdw, calculate_forces, iw, &
     124          910 :                                               atomic_energy)
     125              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     126              :       TYPE(qs_dispersion_type), INTENT(IN), POINTER      :: dispersion_env
     127              :       REAL(KIND=dp), INTENT(INOUT)                       :: evdw
     128              :       LOGICAL, INTENT(IN)                                :: calculate_forces
     129              :       INTEGER, INTENT(IN)                                :: iw
     130              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: atomic_energy
     131              : 
     132              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_dispersion_d4_pairpot'
     133              : 
     134              :       INTEGER                                            :: atoma, cnfun, enshift, handle, i, iatom
     135              : #if defined(__DFTD4_V3)
     136              :       INTEGER                                            :: ifull, ikind, mref, natom, &
     137              :                                                             natom_full, nghost
     138              : #else
     139              :       INTEGER                                            :: ifull, ikind, mref, natom, ncoup, &
     140              :                                                             natom_full, nghost
     141              : #endif
     142          910 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_map, atom_map_back, atom_of_kind, &
     143          910 :                                                             atomtype, kind_of, species, t_atomtype
     144              :       INTEGER, DIMENSION(3)                              :: periodic
     145              :       LOGICAL                                            :: debug, grad, ifloating, ighost, &
     146              :                                                             use_virial
     147          910 :       LOGICAL, ALLOCATABLE, DIMENSION(:)                 :: a_ghost, exclude_ghost
     148              :       LOGICAL, DIMENSION(3)                              :: lperiod
     149              :       REAL(KIND=dp)                                      :: ed2, ed3, ev1, ev2, ev3, ev4, pd2, pd3, &
     150              :                                                             ta, tb, tc, td, te, ts
     151          910 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: cn, cn_red, cnd, dEdcn, dEdq, &
     152          910 :                                                             edcn, edq, enerd2, &
     153          910 :                                                             enerd3, energies, energies3, q_red, qd
     154              : #if defined(__DFTD4_V3)
     155              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: ga, gradient, gwdcn, gwdq, &
     156              :                                                             gwvec, t_xyz, tvec, xyz
     157              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: gdeb
     158              : #else
     159          910 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: ga, gradient, t_xyz, tvec, xyz
     160          910 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: gdeb, gwdcn, gwdq, gwvec
     161              : #endif
     162              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: sigma, stress
     163              :       REAL(KIND=dp), DIMENSION(3, 3, 4)                  :: sdeb
     164          910 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     165              :       TYPE(cell_type), POINTER                           :: cell
     166          910 :       TYPE(dcnum_type), ALLOCATABLE, DIMENSION(:)        :: dcnum
     167              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     168          910 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     169          910 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     170          910 :       TYPE(qs_kind_type), DIMENSION(:), POINTER          :: qs_kind_set
     171              :       TYPE(virial_type), POINTER                         :: virial
     172              : 
     173         1820 :       CLASS(damping_param), ALLOCATABLE                  :: param
     174          910 :       TYPE(d4_model)                                     :: disp
     175          910 :       TYPE(structure_type)                               :: mol
     176              :       TYPE(realspace_cutoff)                             :: cutoff
     177              : 
     178              : #if !defined(__DFTD4_V3)
     179          910 :       TYPE(error_type), ALLOCATABLE                      :: error
     180              : #endif
     181              : 
     182          910 :       CALL timeset(routineN, handle)
     183              : 
     184          910 :       debug = dispersion_env%d4_debug
     185              : 
     186              :       CALL get_qs_env(qs_env=qs_env, particle_set=particle_set, atomic_kind_set=atomic_kind_set, &
     187          910 :                       cell=cell, force=force, virial=virial, para_env=para_env)
     188          910 :       CALL get_atomic_kind_set(atomic_kind_set, atom_of_kind=atom_of_kind, kind_of=kind_of)
     189              : 
     190              :       !get information about particles
     191          910 :       natom_full = SIZE(particle_set)
     192          910 :       nghost = 0
     193         5460 :       ALLOCATE (t_xyz(3, natom_full), t_atomtype(natom_full), a_ghost(natom_full))
     194          910 :       CALL get_qs_env(qs_env=qs_env, qs_kind_set=qs_kind_set)
     195         4828 :       DO iatom = 1, natom_full
     196        15672 :          t_xyz(:, iatom) = particle_set(iatom)%r(:)
     197         3918 :          ikind = kind_of(iatom)
     198         3918 :          CALL get_qs_kind(qs_kind_set(ikind), zatom=t_atomtype(iatom), ghost=ighost, floating=ifloating)
     199         3918 :          a_ghost(iatom) = ighost .OR. ifloating
     200         4828 :          IF (a_ghost(iatom)) nghost = nghost + 1
     201              :       END DO
     202              : 
     203          910 :       natom = natom_full - nghost
     204              :       ! Build atom mapping: full index -> reduced index (0 for ghost)
     205         3640 :       ALLOCATE (atom_map(natom_full), atom_map_back(natom))
     206          910 :       atom_map = 0
     207          910 :       iatom = 0
     208         3640 :       ALLOCATE (xyz(3, natom), atomtype(natom))
     209         4828 :       DO i = 1, natom_full
     210         4828 :          IF (.NOT. a_ghost(i)) THEN
     211         3906 :             iatom = iatom + 1
     212         3906 :             atom_map(i) = iatom
     213         3906 :             atom_map_back(iatom) = i
     214        15624 :             xyz(:, iatom) = t_xyz(:, i)
     215         3906 :             atomtype(iatom) = t_atomtype(i)
     216              :          END IF
     217              :       END DO
     218          910 :       DEALLOCATE (a_ghost, t_xyz, t_atomtype)
     219              : 
     220              :       !get information about cell / lattice
     221          910 :       CALL get_cell(cell=cell, periodic=periodic)
     222          910 :       lperiod(1) = periodic(1) == 1
     223          910 :       lperiod(2) = periodic(2) == 1
     224          910 :       lperiod(3) = periodic(3) == 1
     225              :       ! enforce en shift method 1 (original/molecular)
     226              :       ! method 2 from paper on PBC seems not to work
     227          910 :       enshift = 1
     228              :       !IF (ALL(periodic == 0)) enshift = 1
     229              : 
     230              :       !prepare for the call to the dispersion function
     231          910 :       CALL new(mol, atomtype, xyz, lattice=cell%hmat, periodic=lperiod)
     232              : #if defined(__DFTD4_V3)
     233              :       CALL new_d4_model(disp, mol)
     234              : #else
     235          910 :       CALL new_d4_model(error, disp, mol)
     236          910 :       IF (ALLOCATED(error)) THEN
     237            0 :          CPABORT(error%message)
     238              :       END IF
     239              : 
     240              :       ! Number of coupling
     241          910 :       ncoup = disp%ncoup
     242              : #endif
     243              : 
     244              :       ! Build species mapping: full atom index -> D4 species ID (0 for ghost)
     245         1820 :       ALLOCATE (species(natom_full))
     246          910 :       species = 0
     247         4816 :       DO i = 1, natom
     248         4816 :          species(atom_map_back(i)) = mol%id(i)
     249              :       END DO
     250              : 
     251              :       ! Build per-kind exclusion mask for EEQ (ghost/floating kinds excluded)
     252         2730 :       ALLOCATE (exclude_ghost(SIZE(qs_kind_set)))
     253          910 :       exclude_ghost = .FALSE.
     254         3024 :       DO i = 1, SIZE(qs_kind_set)
     255         2114 :          CALL get_qs_kind(qs_kind_set(i), ghost=ighost, floating=ifloating)
     256         5130 :          exclude_ghost(i) = ighost .OR. ifloating
     257              :       END DO
     258              : 
     259          910 :       IF (dispersion_env%ref_functional == "none") THEN
     260          858 :          CALL get_rational_damping("pbe", param, s9=0.0_dp)
     261          858 :          IF (.NOT. ALLOCATED(param)) THEN
     262            0 :             CPABORT("D4: Failed to get rational damping parameters for default functional")
     263              :          END IF
     264              :          SELECT TYPE (param)
     265              :          TYPE is (rational_damping_param)
     266          858 :             param%s6 = dispersion_env%s6
     267          858 :             param%s8 = dispersion_env%s8
     268          858 :             param%a1 = dispersion_env%a1
     269          858 :             param%a2 = dispersion_env%a2
     270          858 :             param%alp = dispersion_env%alp
     271              :          END SELECT
     272              :       ELSE
     273           52 :          CALL get_rational_damping(dispersion_env%ref_functional, param, s9=dispersion_env%s9)
     274           52 :          IF (.NOT. ALLOCATED(param)) THEN
     275            0 :             CPABORT("D4: Unknown reference functional '"//TRIM(dispersion_env%ref_functional)//"'")
     276              :          END IF
     277              :          SELECT TYPE (param)
     278              :          TYPE is (rational_damping_param)
     279           52 :             dispersion_env%s6 = param%s6
     280           52 :             dispersion_env%s8 = param%s8
     281           52 :             dispersion_env%a1 = param%a1
     282           52 :             dispersion_env%a2 = param%a2
     283           52 :             dispersion_env%alp = param%alp
     284              :          END SELECT
     285              :       END IF
     286              : 
     287              :       ! Coordination number cutoff
     288          910 :       cutoff%cn = dispersion_env%rc_cn
     289              :       ! Two-body interaction cutoff
     290          910 :       cutoff%disp2 = dispersion_env%rc_d4*2._dp
     291              :       ! Three-body interaction cutoff
     292          910 :       cutoff%disp3 = dispersion_env%rc_disp*2._dp
     293          910 :       IF (cutoff%disp3 > cutoff%disp2) THEN
     294            0 :          CPABORT("D4: Three-body cutoff should be smaller than two-body cutoff")
     295              :       END IF
     296              : #if defined(__DFTD4_V4_2)
     297              :       ! DFTD4 4.2 introduced explicit smooth-cutoff widths.
     298              :       ! Keep the same narrow two-body smoothing used by the toolchain patch.
     299              :       cutoff%width2 = 0.05_dp
     300              :       cutoff%width3 = 0.0_dp
     301              :       CALL d4_smooth_width_from_env("DFTD4_DISP2_SMOOTH_WIDTH", "TBLITE_D4_DISP2_SMOOTH_WIDTH", &
     302          910 :                                     cutoff%disp2, cutoff%width2)
     303              :       CALL d4_smooth_width_from_env("DFTD4_DISP3_SMOOTH_WIDTH", "TBLITE_D4_DISP3_SMOOTH_WIDTH", &
     304          910 :                                     cutoff%disp3, cutoff%width3)
     305              : #endif
     306              : 
     307          910 :       IF (calculate_forces) THEN
     308           24 :          grad = .TRUE.
     309           24 :          use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
     310              :       ELSE
     311          886 :          grad = .FALSE.
     312          886 :          use_virial = .FALSE.
     313              :       END IF
     314              : 
     315          910 :       IF (dispersion_env%d4_reference_code) THEN
     316              : 
     317              :          !> Wrapper to handle the evaluation of dispersion energy and derivatives
     318            6 :          IF (.NOT. dispersion_env%doabc) THEN
     319            0 :             CPWARN("Using D4_REFERENCE_CODE enforces calculation of C9 term.")
     320              :          END IF
     321            6 :          IF (grad) THEN
     322            4 :             ALLOCATE (gradient(3, natom))
     323            2 :             CALL get_dispersion(mol, disp, param, cutoff, evdw, gradient, stress)
     324            2 :             IF (calculate_forces) THEN
     325            2 :                IF (use_virial) THEN
     326            0 :                   virial%pv_virial = virial%pv_virial - stress/para_env%num_pe
     327              :                END IF
     328           22 :                DO iatom = 1, natom
     329           20 :                   ifull = atom_map_back(iatom)
     330           20 :                   ikind = kind_of(ifull)
     331           20 :                   atoma = atom_of_kind(ifull)
     332              :                   force(ikind)%dispersion(:, atoma) = &
     333           82 :                      force(ikind)%dispersion(:, atoma) + gradient(:, iatom)/para_env%num_pe
     334              :                END DO
     335              :             END IF
     336            2 :             DEALLOCATE (gradient)
     337              :          ELSE
     338            4 :             CALL get_dispersion(mol, disp, param, cutoff, evdw)
     339              :          END IF
     340              :          !dispersion energy is computed by every MPI process
     341            6 :          evdw = evdw/para_env%num_pe
     342            6 :          IF (dispersion_env%ext_charges) dispersion_env%dcharges = 0.0_dp
     343            6 :          IF (PRESENT(atomic_energy)) THEN
     344            0 :             CPWARN("Atomic energies not available for D4 reference code")
     345            0 :             atomic_energy = 0.0_dp
     346              :          END IF
     347              : 
     348              :       ELSE
     349              : 
     350          904 :          IF (iw > 0) THEN
     351            0 :             WRITE (iw, '(/,T2,A)') '!-----------------------------------------------------------------------------!'
     352            0 :             WRITE (iw, FMT="(T32,A)") "DEBUG D4 DISPERSION"
     353            0 :             WRITE (iw, '(T2,A)') '!-----------------------------------------------------------------------------!'
     354            0 :             WRITE (iw, '(A,T71,A10)') " DEBUG D4| Reference functional   ", TRIM(dispersion_env%ref_functional)
     355            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| Scaling parameter (s6) ", dispersion_env%s6
     356            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| Scaling parameter (s8) ", dispersion_env%s8
     357            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| BJ Damping parameter (a1) ", dispersion_env%a1
     358            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| BJ Damping parameter (a2) ", dispersion_env%a2
     359            0 :             WRITE (iw, '(A,T71,E10.4)') " DEBUG D4| Cutoff value coordination numbers ", dispersion_env%eps_cn
     360            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| Cutoff radius coordination numbers ", dispersion_env%rc_cn
     361            0 :             WRITE (iw, '(A,T71,I10)') " DEBUG D4| Coordination number function type ", dispersion_env%cnfun
     362            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| Cutoff radius 2-body terms [bohr]", 2._dp*dispersion_env%rc_d4
     363            0 :             WRITE (iw, '(A,T71,F10.4)') " DEBUG D4| Cutoff radius 3-body terms [bohr]", 2._dp*dispersion_env%rc_disp
     364              :          END IF
     365              : 
     366          904 :          td = 0.0_dp
     367          904 :          IF (debug .AND. iw > 0) THEN
     368            0 :             ts = m_walltime()
     369              :             CALL refd4_debug(param, disp, mol, cutoff, grad, dispersion_env%doabc, &
     370            0 :                              enerd2, enerd3, cnd, qd, Edcn, Edq, gdeb, sdeb)
     371            0 :             te = m_walltime()
     372            0 :             td = te - ts
     373              :          END IF
     374              : 
     375          904 :          tc = 0.0_dp
     376          904 :          ts = m_walltime()
     377              : 
     378         2998 :          mref = MAXVAL(disp%ref)
     379              :          ! Coordination numbers (full-size from qs_env; ghosts excluded internally)
     380          904 :          cnfun = dispersion_env%cnfun
     381          904 :          CALL cnumber_init(qs_env, cn, dcnum, cnfun, grad)
     382              :          ! cn has size natom_full; ghost entries are 0
     383              : 
     384              :          ! Filter CN to reduced space for D4 model
     385         2712 :          ALLOCATE (cn_red(natom))
     386         4750 :          DO i = 1, natom
     387         4750 :             cn_red(i) = cn(atom_map_back(i))
     388              :          END DO
     389          904 :          IF (debug .AND. iw > 0) THEN
     390            0 :             WRITE (iw, '(A,T71,F10.6)') " DEBUG D4| CN differences (max)", MAXVAL(ABS(cn_red - cnd))
     391            0 :             WRITE (iw, '(A,T71,F10.6)') " DEBUG D4| CN differences (ave)", SUM(ABS(cn_red - cnd))/natom
     392              :          END IF
     393              : 
     394              :          ! EEQ charges
     395              :          ! Use CP2K's MPI-parallel EEQ solver with ghost exclusion.
     396              :          ! Ghost kinds get huge hardness + zero coupling -> q_ghost = 0 exactly,
     397              :          ! without influencing real atom charges. Preserves full MPI parallelism.
     398          904 :          IF (dispersion_env%ext_charges) THEN
     399         1716 :             ALLOCATE (q_red(natom))
     400         4320 :             q_red(1:natom) = dispersion_env%charges(1:natom)
     401              :          ELSE
     402              :             ! eeq_charges writes natom_full entries (from qs_env), so allocate full-size
     403          138 :             ALLOCATE (q_red(natom_full))
     404              :             CALL eeq_charges(qs_env, q_red, dispersion_env%eeq_sparam, 2, enshift, &
     405           46 :                              exclude=exclude_ghost, cn_max=8.0_dp)
     406              :             ! Filter to reduced size for D4 model
     407              :             BLOCK
     408           46 :                REAL(KIND=dp), ALLOCATABLE :: q_tmp(:)
     409           92 :                ALLOCATE (q_tmp(natom))
     410          430 :                DO i = 1, natom
     411          430 :                   q_tmp(i) = q_red(atom_map_back(i))
     412              :                END DO
     413           46 :                DEALLOCATE (q_red)
     414           46 :                CALL MOVE_ALLOC(q_tmp, q_red)
     415              :             END BLOCK
     416              :          END IF
     417          904 :          IF (debug .AND. iw > 0) THEN
     418            0 :             WRITE (iw, '(A,T71,F10.6)') " DEBUG D4| Charge differences (max)", MAXVAL(ABS(q_red - qd))
     419            0 :             WRITE (iw, '(A,T71,F10.6)') " DEBUG D4| Charge differences (ave)", SUM(ABS(q_red - qd))/natom
     420              :          END IF
     421              :          ! Weights for C6 calculation (reduced space)
     422              : #if defined(__DFTD4_V3)
     423              :          ALLOCATE (gwvec(mref, natom))
     424              :          IF (grad) ALLOCATE (gwdcn(mref, natom), gwdq(mref, natom))
     425              : #else
     426         4520 :          ALLOCATE (gwvec(mref, natom, ncoup))
     427         1036 :          IF (grad) ALLOCATE (gwdcn(mref, natom, ncoup), gwdq(mref, natom, ncoup))
     428              : #endif
     429          904 :          CALL disp%weight_references(mol, cn_red, q_red, gwvec, gwdcn, gwdq)
     430              : 
     431              :          ! Energies and derivatives (full-size for CP2K infrastructure compatibility)
     432         2712 :          ALLOCATE (energies(natom_full))
     433          904 :          energies(:) = 0.0_dp
     434          904 :          IF (grad) THEN
     435           66 :             ALLOCATE (gradient(3, natom_full), ga(3, natom_full))
     436           66 :             ALLOCATE (dEdcn(natom_full), dEdq(natom_full))
     437           22 :             dEdcn(:) = 0.0_dp; dEdq(:) = 0.0_dp
     438           22 :             ga(:, :) = 0.0_dp
     439           22 :             sigma(:, :) = 0.0_dp
     440              :          END IF
     441              :          CALL dispersion_2b(dispersion_env, cutoff%disp2, disp%r4r2, &
     442              :                             gwvec, gwdcn, gwdq, disp%c6, disp%ref, &
     443              :                             energies, dEdcn, dEdq, grad, ga, sigma, &
     444          904 :                             atom_map, species)
     445          904 :          IF (grad) THEN
     446          566 :             gradient(1:3, 1:natom_full) = ga(1:3, 1:natom_full)
     447           22 :             stress = sigma
     448           22 :             IF (debug) THEN
     449            0 :                CALL para_env%sum(ga)
     450            0 :                CALL para_env%sum(sigma)
     451            0 :                IF (iw > 0) THEN
     452            0 :                   CALL gerror(ga, gdeb(:, :, 1), ev1, ev2, ev3, ev4)
     453            0 :                   WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| RMS error Gradient [2B]", ev1, ev2, " %"
     454            0 :                   WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Gradient [2B]", ev3, ev4, " %"
     455            0 :                   IF (use_virial) THEN
     456            0 :                      CALL serror(sigma, sdeb(:, :, 1), ev1, ev2)
     457            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Stress [2B]", ev1, ev2, " %"
     458              :                   END IF
     459              :                END IF
     460              :             END IF
     461              :          END IF
     462              :          ! no contribution from dispersion_3b as q=0 (but q is changed!)
     463              :          ! so we calculate this here
     464          904 :          IF (grad) THEN
     465           22 :             IF (dispersion_env%ext_charges) THEN
     466           60 :                dispersion_env%dcharges = dEdq
     467              :             ELSE
     468           10 :                CALL para_env%sum(dEdq)
     469              :                ! Reconstruct full-sized charges for eeq_forces
     470              :                BLOCK
     471           10 :                   REAL(KIND=dp), ALLOCATABLE :: q_full(:)
     472           20 :                   ALLOCATE (q_full(natom_full))
     473           10 :                   q_full = 0.0_dp
     474           98 :                   DO i = 1, natom
     475           98 :                      q_full(atom_map_back(i)) = q_red(i)
     476              :                   END DO
     477           10 :                   ga(:, :) = 0.0_dp
     478           10 :                   sigma = 0.0_dp
     479              :                   CALL eeq_forces(qs_env, q_full, dEdq, ga, sigma, dispersion_env%eeq_sparam, &
     480              :                                   2, enshift, response_only=.TRUE., exclude=exclude_ghost, &
     481           10 :                                   cn_max=8.0_dp)
     482           10 :                   DEALLOCATE (q_full)
     483              :                END BLOCK
     484          362 :                gradient(1:3, 1:natom_full) = gradient(1:3, 1:natom_full) + ga(1:3, 1:natom_full)
     485          130 :                stress = stress + sigma
     486           10 :                IF (debug) THEN
     487            0 :                   CALL para_env%sum(ga)
     488            0 :                   CALL para_env%sum(sigma)
     489            0 :                   IF (iw > 0) THEN
     490            0 :                      CALL verror(dEdq, Edq, ev1, ev2)
     491            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Derivative dEdq", ev1, ev2, " %"
     492            0 :                      CALL gerror(ga, gdeb(:, :, 2), ev1, ev2, ev3, ev4)
     493            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| RMS error Gradient [dEdq]", ev1, ev2, " %"
     494            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Gradient [dEdq]", ev3, ev4, " %"
     495            0 :                      IF (use_virial) THEN
     496            0 :                         CALL serror(sigma, sdeb(:, :, 2), ev1, ev2)
     497            0 :                         WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Stress [dEdq]", ev1, ev2, " %"
     498              :                      END IF
     499              :                   END IF
     500              :                END IF
     501              :             END IF
     502              :          END IF
     503              : 
     504          904 :          IF (dispersion_env%doabc) THEN
     505           92 :             ALLOCATE (energies3(natom_full))
     506           46 :             energies3(:) = 0.0_dp
     507           46 :             q_red(:) = 0.0_dp
     508              :             ! i.e. dc6dq = dEdq = 0
     509           46 :             CALL disp%weight_references(mol, cn_red, q_red, gwvec, gwdcn, gwdq)
     510              :             !
     511           46 :             IF (grad) THEN
     512           10 :                gwdq = 0.0_dp
     513           10 :                ga(:, :) = 0.0_dp
     514           10 :                sigma = 0.0_dp
     515              :             END IF
     516           46 :             CALL get_lattice_points(mol%periodic, mol%lattice, cutoff%disp3, tvec)
     517              :             CALL dispersion_3b(qs_env, dispersion_env, tvec, cutoff%disp3, disp%r4r2, &
     518              :                                gwvec, gwdcn, gwdq, disp%c6, disp%ref, &
     519              :                                energies3, dEdcn, dEdq, grad, ga, sigma, &
     520           46 :                                atom_map, species)
     521           46 :             IF (grad) THEN
     522          362 :                gradient(1:3, 1:natom_full) = gradient(1:3, 1:natom_full) + ga(1:3, 1:natom_full)
     523          130 :                stress = stress + sigma
     524           10 :                IF (debug) THEN
     525            0 :                   CALL para_env%sum(ga)
     526            0 :                   CALL para_env%sum(sigma)
     527            0 :                   IF (iw > 0) THEN
     528            0 :                      CALL gerror(ga, gdeb(:, :, 3), ev1, ev2, ev3, ev4)
     529            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| RMS error Gradient [3B]", ev1, ev2, " %"
     530            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Gradient [3B]", ev3, ev4, " %"
     531            0 :                      IF (use_virial) THEN
     532            0 :                         CALL serror(sigma, sdeb(:, :, 3), ev1, ev2)
     533            0 :                         WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Stress [3B]", ev1, ev2, " %"
     534              :                      END IF
     535              :                   END IF
     536              :                END IF
     537              :             END IF
     538              :          END IF
     539              : 
     540          904 :          IF (grad) THEN
     541           22 :             CALL para_env%sum(dEdcn)
     542           22 :             ga(:, :) = 0.0_dp
     543           22 :             sigma = 0.0_dp
     544           22 :             CALL dEdcn_force(qs_env, dEdcn, dcnum, ga, sigma)
     545          566 :             gradient(1:3, 1:natom_full) = gradient(1:3, 1:natom_full) + ga(1:3, 1:natom_full)
     546          286 :             stress = stress + sigma
     547           22 :             IF (debug) THEN
     548            0 :                CALL para_env%sum(ga)
     549            0 :                CALL para_env%sum(sigma)
     550            0 :                IF (iw > 0) THEN
     551            0 :                   CALL verror(dEdcn, Edcn, ev1, ev2)
     552            0 :                   WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Derivative dEdcn", ev1, ev2, " %"
     553            0 :                   CALL gerror(ga, gdeb(:, :, 4), ev1, ev2, ev3, ev4)
     554            0 :                   WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| RMS error Gradient [dEdcn]", ev1, ev2, " %"
     555            0 :                   WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Gradient [dEdcn]", ev3, ev4, " %"
     556            0 :                   IF (use_virial) THEN
     557            0 :                      CALL serror(sigma, sdeb(:, :, 4), ev1, ev2)
     558            0 :                      WRITE (iw, '(A,T51,F14.10,T69,F10.4,A)') " DEBUG D4| MAV error Stress [dEdcn]", ev1, ev2, " %"
     559              :                   END IF
     560              :                END IF
     561              :             END IF
     562              :          END IF
     563          904 :          DEALLOCATE (q_red, cn_red)
     564          904 :          CALL cnumber_release(cn, dcnum, grad)
     565          904 :          te = m_walltime()
     566          904 :          tc = tc + te - ts
     567              : 
     568          904 :          IF (debug) THEN
     569            0 :             ta = SUM(energies)
     570            0 :             CALL para_env%sum(ta)
     571            0 :             IF (iw > 0) THEN
     572            0 :                tb = SUM(enerd2)
     573            0 :                ed2 = ta - tb
     574            0 :                pd2 = ABS(ed2)/ABS(tb)*100.
     575            0 :                WRITE (iw, '(A,T51,F14.8,T69,F10.4,A)') " DEBUG D4| Energy error 2-body", ed2, pd2, " %"
     576              :             END IF
     577            0 :             IF (dispersion_env%doabc) THEN
     578            0 :                ta = SUM(energies3)
     579            0 :                CALL para_env%sum(ta)
     580            0 :                IF (iw > 0) THEN
     581            0 :                   tb = SUM(enerd3)
     582            0 :                   ed3 = ta - tb
     583            0 :                   pd3 = ABS(ed3)/ABS(tb)*100.
     584            0 :                   WRITE (iw, '(A,T51,F14.8,T69,F10.4,A)') " DEBUG D4| Energy error 3-body", ed3, pd3, " %"
     585              :                END IF
     586              :             END IF
     587            0 :             IF (iw > 0) THEN
     588            0 :                WRITE (iw, '(A,T67,F14.4)') " DEBUG D4| Time for reference code [s]", td
     589            0 :                WRITE (iw, '(A,T67,F14.4)') " DEBUG D4| Time for production code [s]", tc
     590              :             END IF
     591              :          END IF
     592              : 
     593          904 :          IF (dispersion_env%doabc) THEN
     594          442 :             energies(:) = energies(:) + energies3(:)
     595              :          END IF
     596         4762 :          evdw = SUM(energies)
     597          904 :          IF (PRESENT(atomic_energy)) THEN
     598            0 :             atomic_energy(1:natom_full) = energies(1:natom_full)
     599              :          END IF
     600              : 
     601          904 :          IF (use_virial .AND. calculate_forces) THEN
     602           78 :             virial%pv_virial = virial%pv_virial - stress
     603              :          END IF
     604          904 :          IF (calculate_forces) THEN
     605          158 :             DO iatom = 1, natom_full
     606          136 :                IF (atom_map(iatom) == 0) CYCLE
     607          136 :                ikind = kind_of(iatom)
     608          136 :                atoma = atom_of_kind(iatom)
     609              :                force(ikind)%dispersion(:, atoma) = &
     610          566 :                   force(ikind)%dispersion(:, atoma) + gradient(:, iatom)
     611              :             END DO
     612              :          END IF
     613              : 
     614          904 :          DEALLOCATE (energies)
     615          904 :          IF (dispersion_env%doabc) DEALLOCATE (energies3)
     616          904 :          IF (grad) THEN
     617           22 :             DEALLOCATE (gradient, ga)
     618              :          END IF
     619              : 
     620              :       END IF
     621              : 
     622          910 :       DEALLOCATE (xyz, atomtype, atom_map, atom_map_back, species, exclude_ghost)
     623              : 
     624          910 :       CALL timestop(handle)
     625              : 
     626         1820 :    END SUBROUTINE calculate_dispersion_d4_pairpot
     627              : 
     628              : ! **************************************************************************************************
     629              : !> \brief ...
     630              : !> \param param ...
     631              : !> \param disp ...
     632              : !> \param mol ...
     633              : !> \param cutoff ...
     634              : !> \param grad ...
     635              : !> \param doabc ...
     636              : !> \param enerd2 ...
     637              : !> \param enerd3 ...
     638              : !> \param cnd ...
     639              : !> \param qd ...
     640              : !> \param dEdcn ...
     641              : !> \param dEdq ...
     642              : !> \param gradient ...
     643              : !> \param stress ...
     644              : ! **************************************************************************************************
     645            0 :    SUBROUTINE refd4_debug(param, disp, mol, cutoff, grad, doabc, &
     646              :                           enerd2, enerd3, cnd, qd, dEdcn, dEdq, gradient, stress)
     647              :       CLASS(damping_param)                               :: param
     648              :       TYPE(d4_model)                                     :: disp
     649              :       TYPE(structure_type)                               :: mol
     650              :       TYPE(realspace_cutoff)                             :: cutoff
     651              : #if !defined(__DFTD4_V3)
     652            0 :       TYPE(error_type), ALLOCATABLE                      :: error
     653              : #endif
     654              :       LOGICAL, INTENT(IN)                                :: grad, doabc
     655              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: enerd2, enerd3, cnd, qd, dEdcn, dEdq
     656              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: gradient
     657              :       REAL(KIND=dp), DIMENSION(3, 3, 4)                  :: stress
     658              : 
     659              : #if defined(__DFTD4_V3)
     660              :       INTEGER                                            :: mref, natom, i
     661              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: q, qq
     662              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: lattr, gwdcn, gwdq, gwvec, &
     663              :                                                             c6, dc6dcn, dc6dq
     664              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: cndr, cndL, qdr, qdL
     665              : #else
     666              :       INTEGER                                            :: mref, natom, i, ncoup
     667            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: q, qq
     668            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: lattr, c6, dc6dcn, dc6dq
     669            0 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: cndr, cndL, qdr, qdL, gwdcn, gwdq, gwvec
     670              : #endif
     671              : 
     672            0 :       mref = MAXVAL(disp%ref)
     673            0 :       natom = mol%nat
     674              : #if !defined(__DFTD4_V3)
     675            0 :       ncoup = disp%ncoup
     676              : #endif
     677              : 
     678              :       ! Coordination numbers
     679            0 :       ALLOCATE (cnd(natom))
     680            0 :       IF (grad) ALLOCATE (cndr(3, natom, natom), cndL(3, 3, natom))
     681            0 :       CALL get_lattice_points(mol%periodic, mol%lattice, cutoff%cn, lattr)
     682              :       CALL get_coordination_number(mol, lattr, cutoff%cn, disp%rcov, disp%en, &
     683            0 :                                    cnd, cndr, cndL)
     684              :       ! EEQ charges
     685            0 :       ALLOCATE (qd(natom))
     686            0 :       IF (grad) ALLOCATE (qdr(3, natom, natom), qdL(3, 3, natom))
     687              : #if defined(__DFTD4_V3)
     688              :       CALL get_charges(mol, qd, qdr, qdL)
     689              : #else
     690            0 :       CALL get_charges(disp%mchrg, mol, error, qd, qdr, qdL)
     691            0 :       IF (ALLOCATED(error)) THEN
     692            0 :          CPABORT(error%message)
     693              :       END IF
     694              : #endif
     695              :       ! C6 interpolation
     696              : #if defined(__DFTD4_V3)
     697              :       ALLOCATE (gwvec(mref, natom))
     698              :       IF (grad) ALLOCATE (gwdcn(mref, natom), gwdq(mref, natom))
     699              : #else
     700            0 :       ALLOCATE (gwvec(mref, natom, ncoup))
     701            0 :       IF (grad) ALLOCATE (gwdcn(mref, natom, ncoup), gwdq(mref, natom, ncoup))
     702              : #endif
     703            0 :       CALL disp%weight_references(mol, cnd, qd, gwvec, gwdcn, gwdq)
     704            0 :       ALLOCATE (c6(natom, natom))
     705            0 :       IF (grad) ALLOCATE (dc6dcn(natom, natom), dc6dq(natom, natom))
     706            0 :       CALL disp%get_atomic_c6(mol, gwvec, gwdcn, gwdq, c6, dc6dcn, dc6dq)
     707            0 :       CALL get_lattice_points(mol%periodic, mol%lattice, cutoff%disp2, lattr)
     708              :       !
     709            0 :       IF (grad) THEN
     710            0 :          ALLOCATE (gradient(3, natom, 4))
     711            0 :          gradient = 0.0_dp
     712            0 :          stress = 0.0_dp
     713              :       END IF
     714              :       !
     715            0 :       ALLOCATE (enerd2(natom))
     716            0 :       enerd2(:) = 0.0_dp
     717            0 :       IF (grad) THEN
     718            0 :          ALLOCATE (dEdcn(natom), dEdq(natom))
     719            0 :          dEdcn(:) = 0.0_dp; dEdq(:) = 0.0_dp
     720              :       END IF
     721              : #if defined(__DFTD4_V4_2)
     722              :       CALL param%get_dispersion2(mol, lattr, cutoff%disp2, cutoff%width2, disp%r4r2, c6, &
     723              :                                  dc6dcn, dc6dq, enerd2, dEdcn, dEdq, gradient(:, :, 1), &
     724            0 :                                  stress(:, :, 1))
     725              : #else
     726              :       CALL param%get_dispersion2(mol, lattr, cutoff%disp2, disp%r4r2, c6, dc6dcn, dc6dq, &
     727              :                                  enerd2, dEdcn, dEdq, gradient(:, :, 1), stress(:, :, 1))
     728              : #endif
     729              :       !
     730            0 :       IF (grad) THEN
     731            0 :          DO i = 1, 3
     732            0 :             gradient(i, :, 2) = MATMUL(qdr(i, :, :), dEdq(:))
     733            0 :             stress(i, :, 2) = MATMUL(qdL(i, :, :), dEdq(:))
     734              :          END DO
     735              :       END IF
     736              :       !
     737            0 :       IF (doabc) THEN
     738            0 :          ALLOCATE (q(natom), qq(natom))
     739            0 :          q(:) = 0.0_dp; qq(:) = 0.0_dp
     740            0 :          ALLOCATE (enerd3(natom))
     741            0 :          enerd3(:) = 0.0_dp
     742            0 :          CALL disp%weight_references(mol, cnd, q, gwvec, gwdcn, gwdq)
     743            0 :          CALL disp%get_atomic_c6(mol, gwvec, gwdcn, gwdq, c6, dc6dcn, dc6dq)
     744            0 :          CALL get_lattice_points(mol%periodic, mol%lattice, cutoff%disp3, lattr)
     745              : #if defined(__DFTD4_V4_2)
     746              :          CALL param%get_dispersion3(mol, lattr, cutoff%disp3, cutoff%width3, disp%r4r2, c6, &
     747              :                                     dc6dcn, dc6dq, enerd3, dEdcn, qq, gradient(:, :, 3), &
     748            0 :                                     stress(:, :, 3))
     749              : #else
     750              :          CALL param%get_dispersion3(mol, lattr, cutoff%disp3, disp%r4r2, c6, dc6dcn, dc6dq, &
     751              :                                     enerd3, dEdcn, qq, gradient(:, :, 3), stress(:, :, 3))
     752              : #endif
     753              :       END IF
     754            0 :       IF (grad) THEN
     755            0 :          DO i = 1, 3
     756            0 :             gradient(i, :, 4) = MATMUL(cndr(i, :, :), dEdcn(:))
     757            0 :             stress(i, :, 4) = MATMUL(cndL(i, :, :), dEdcn(:))
     758              :          END DO
     759              :       END IF
     760              : 
     761            0 :    END SUBROUTINE refd4_debug
     762              : 
     763              : #else
     764              : 
     765              : ! **************************************************************************************************
     766              : !> \brief ...
     767              : !> \param qs_env ...
     768              : !> \param dispersion_env ...
     769              : !> \param evdw ...
     770              : !> \param calculate_forces ...
     771              : !> \param iw ...
     772              : !> \param atomic_energy ...
     773              : ! **************************************************************************************************
     774              :    SUBROUTINE calculate_dispersion_d4_pairpot(qs_env, dispersion_env, evdw, calculate_forces, &
     775              :                                               iw, atomic_energy)
     776              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     777              :       TYPE(qs_dispersion_type), INTENT(IN), POINTER      :: dispersion_env
     778              :       REAL(KIND=dp), INTENT(INOUT)                       :: evdw
     779              :       LOGICAL, INTENT(IN)                                :: calculate_forces
     780              :       INTEGER, INTENT(IN)                                :: iw
     781              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL              :: atomic_energy
     782              : 
     783              :       MARK_USED(qs_env)
     784              :       MARK_USED(dispersion_env)
     785              :       MARK_USED(evdw)
     786              :       MARK_USED(calculate_forces)
     787              :       MARK_USED(iw)
     788              :       MARK_USED(atomic_energy)
     789              : 
     790              :       CPABORT("CP2K build without DFTD4")
     791              : 
     792              :    END SUBROUTINE calculate_dispersion_d4_pairpot
     793              : 
     794              : #endif
     795              : 
     796              : ! **************************************************************************************************
     797              : !> \brief ...
     798              : !> \param dispersion_env ...
     799              : !> \param cutoff ...
     800              : !> \param r4r2 ...
     801              : !> \param gwvec ...
     802              : !> \param gwdcn ...
     803              : !> \param gwdq ...
     804              : !> \param c6ref ...
     805              : !> \param mrefs ...
     806              : !> \param energies ...
     807              : !> \param dEdcn ...
     808              : !> \param dEdq ...
     809              : !> \param calculate_forces ...
     810              : !> \param gradient ...
     811              : !> \param stress ...
     812              : !> \param atom_map ...
     813              : !> \param species ...
     814              : ! **************************************************************************************************
     815         2712 :    SUBROUTINE dispersion_2b(dispersion_env, cutoff, r4r2, &
     816         2668 :                             gwvec, gwdcn, gwdq, c6ref, mrefs, &
     817         1808 :                             energies, dEdcn, dEdq, &
     818         1786 :                             calculate_forces, gradient, stress, &
     819          904 :                             atom_map, species)
     820              :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
     821              :       REAL(KIND=dp), INTENT(IN)                          :: cutoff
     822              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: r4r2
     823              : #if defined(__DFTD4_V3)
     824              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: gwvec, gwdcn, gwdq
     825              : #else
     826              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: gwvec, gwdcn, gwdq
     827              : #endif
     828              :       REAL(KIND=dp), DIMENSION(:, :, :, :), INTENT(IN)   :: c6ref
     829              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mrefs
     830              :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT)         :: energies, dEdcn, dEdq
     831              :       LOGICAL, INTENT(IN)                                :: calculate_forces
     832              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: gradient, stress
     833              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: atom_map, species
     834              : 
     835              :       INTEGER                                            :: ia, iatom, ik, ikind, ja, jatom, jk, &
     836              :                                                             jkind, mepos, num_pe
     837              :       REAL(KINd=dp)                                      :: a1, a2, c6ij, cutoff2, d6, d8, dE, dr2, &
     838              :                                                             edisp, fac, gdisp, r0ij, rrij, s6, s8, &
     839              :                                                             t6, t8
     840              :       REAL(KINd=dp), DIMENSION(2)                        :: dcdcn, dcdq
     841              :       REAL(KINd=dp), DIMENSION(3)                        :: dG, rij
     842              :       REAL(KINd=dp), DIMENSION(3, 3)                     :: dS
     843              :       TYPE(neighbor_list_iterator_p_type), &
     844          904 :          DIMENSION(:), POINTER                           :: nl_iterator
     845              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     846              :          POINTER                                         :: sab_vdw
     847              : 
     848          904 :       a1 = dispersion_env%a1
     849          904 :       a2 = dispersion_env%a2
     850          904 :       s6 = dispersion_env%s6
     851          904 :       s8 = dispersion_env%s8
     852          904 :       cutoff2 = cutoff*cutoff
     853              : 
     854          904 :       sab_vdw => dispersion_env%sab_vdw
     855              : 
     856          904 :       num_pe = 1
     857          904 :       CALL neighbor_list_iterator_create(nl_iterator, sab_vdw, nthread=num_pe)
     858              : 
     859          904 :       mepos = 0
     860       194149 :       DO WHILE (neighbor_list_iterate(nl_iterator, mepos=mepos) == 0)
     861              :          CALL get_iterator_info(nl_iterator, mepos=mepos, ikind=ikind, jkind=jkind, &
     862       193245 :                                 iatom=iatom, jatom=jatom, r=rij)
     863              :          ! Skip ghost/floating atoms
     864       193245 :          ia = atom_map(iatom)
     865       193245 :          ja = atom_map(jatom)
     866       193245 :          IF (ia == 0 .OR. ja == 0) CYCLE
     867              :          ! D4 species indices
     868       193215 :          ik = species(iatom)
     869       193215 :          jk = species(jatom)
     870              :          ! vdW potential
     871       772860 :          dr2 = SUM(rij(:)**2)
     872       194119 :          IF (dr2 <= cutoff2 .AND. dr2 > 0.0000001_dp) THEN
     873       191292 :             rrij = 3._dp*r4r2(ik)*r4r2(jk)
     874       191292 :             r0ij = a1*SQRT(rrij) + a2
     875       191292 :             IF (calculate_forces) THEN
     876              :                CALL get_c6derivs(c6ij, dcdcn, dcdq, ia, ja, ik, jk, &
     877        92013 :                                  gwvec, gwdcn, gwdq, c6ref, mrefs)
     878              :             ELSE
     879        99279 :                CALL get_c6value(c6ij, ia, ja, ik, jk, gwvec, c6ref, mrefs)
     880              :             END IF
     881       191292 :             fac = 1._dp
     882       191292 :             IF (iatom == jatom) fac = 0.5_dp
     883       191292 :             t6 = 1.0_dp/(dr2**3 + r0ij**6)
     884       191292 :             t8 = 1.0_dp/(dr2**4 + r0ij**8)
     885              : 
     886       191292 :             edisp = (s6*t6 + s8*rrij*t8)*fac
     887       191292 :             dE = -c6ij*edisp
     888       191292 :             energies(iatom) = energies(iatom) + dE*0.5_dp
     889       191292 :             energies(jatom) = energies(jatom) + dE*0.5_dp
     890              : 
     891       191292 :             IF (calculate_forces) THEN
     892        92013 :                d6 = -6.0_dp*dr2**2*t6**2
     893        92013 :                d8 = -8.0_dp*dr2**3*t8**2
     894        92013 :                gdisp = (s6*d6 + s8*rrij*d8)*fac
     895       368052 :                dG(:) = -c6ij*gdisp*rij(:)
     896       368052 :                gradient(:, iatom) = gradient(:, iatom) - dG
     897       368052 :                gradient(:, jatom) = gradient(:, jatom) + dG
     898      1196169 :                dS(:, :) = SPREAD(dG, 1, 3)*SPREAD(rij, 2, 3)
     899      1196169 :                stress(:, :) = stress(:, :) + dS(:, :)
     900        92013 :                dEdcn(iatom) = dEdcn(iatom) - dcdcn(1)*edisp
     901        92013 :                dEdq(iatom) = dEdq(iatom) - dcdq(1)*edisp
     902        92013 :                dEdcn(jatom) = dEdcn(jatom) - dcdcn(2)*edisp
     903        92013 :                dEdq(jatom) = dEdq(jatom) - dcdq(2)*edisp
     904              :             END IF
     905              :          END IF
     906              :       END DO
     907              : 
     908          904 :       CALL neighbor_list_iterator_release(nl_iterator)
     909              : 
     910          904 :    END SUBROUTINE dispersion_2b
     911              : 
     912              : ! **************************************************************************************************
     913              : !> \brief ...
     914              : !> \param qs_env ...
     915              : !> \param dispersion_env ...
     916              : !> \param tvec ...
     917              : !> \param cutoff ...
     918              : !> \param r4r2 ...
     919              : !> \param gwvec ...
     920              : !> \param gwdcn ...
     921              : !> \param gwdq ...
     922              : !> \param c6ref ...
     923              : !> \param mrefs ...
     924              : !> \param energies ...
     925              : !> \param dEdcn ...
     926              : !> \param dEdq ...
     927              : !> \param calculate_forces ...
     928              : !> \param gradient ...
     929              : !> \param stress ...
     930              : !> \param atom_map ...
     931              : !> \param species ...
     932              : ! **************************************************************************************************
     933           46 :    SUBROUTINE dispersion_3b(qs_env, dispersion_env, tvec, cutoff, r4r2, &
     934          118 :                             gwvec, gwdcn, gwdq, c6ref, mrefs, &
     935           92 :                             energies, dEdcn, dEdq, &
     936           82 :                             calculate_forces, gradient, stress, &
     937           46 :                             atom_map, species)
     938              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     939              :       TYPE(qs_dispersion_type), POINTER                  :: dispersion_env
     940              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: tvec
     941              :       REAL(KIND=dp), INTENT(IN)                          :: cutoff
     942              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: r4r2
     943              : #if defined(__DFTD4_V3)
     944              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: gwvec, gwdcn, gwdq
     945              : #else
     946              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: gwvec, gwdcn, gwdq
     947              : #endif
     948              :       REAL(KIND=dp), DIMENSION(:, :, :, :), INTENT(IN)   :: c6ref
     949              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mrefs
     950              :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT)         :: energies, dEdcn, dEdq
     951              :       LOGICAL, INTENT(IN)                                :: calculate_forces
     952              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: gradient, stress
     953              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: atom_map, species
     954              : 
     955              :       INTEGER                                            :: ia, iatom, ik, ikind, ja, jatom, jk, &
     956              :                                                             jkind, ka, katom, kk, ktr, mepos, &
     957              :                                                             natom, num_pe
     958           46 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: kind_of
     959              :       INTEGER, DIMENSION(3)                              :: cell_b
     960              :       REAL(KINd=dp)                                      :: a1, a2, alp, ang, c6ij, c6ik, c6jk, c9, &
     961              :                                                             cutoff2, dang, dE, dfdmp, fac, fdmp, &
     962              :                                                             r0, r0ij, r0ik, r0jk, r1, r2, r2ij, &
     963              :                                                             r2ik, r2jk, r3, r5, rr, s6, s8, s9
     964           46 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: rcpbc
     965              :       REAL(KINd=dp), DIMENSION(2)                        :: dc6dcnij, dc6dcnik, dc6dcnjk, dc6dqij, &
     966              :                                                             dc6dqik, dc6dqjk
     967              :       REAL(KINd=dp), DIMENSION(3)                        :: dGij, dGik, dGjk, ra, rb, rb0, rij, vij, &
     968              :                                                             vik, vjk
     969              :       REAL(KINd=dp), DIMENSION(3, 3)                     :: dS
     970           46 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     971              :       TYPE(cell_type), POINTER                           :: cell
     972              :       TYPE(neighbor_list_iterator_p_type), &
     973           46 :          DIMENSION(:), POINTER                           :: nl_iterator
     974              :       TYPE(neighbor_list_set_p_type), DIMENSION(:), &
     975           46 :          POINTER                                         :: sab_vdw
     976           46 :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     977              : 
     978              :       CALL get_qs_env(qs_env=qs_env, natom=natom, cell=cell, &
     979           46 :                       atomic_kind_set=atomic_kind_set, particle_set=particle_set)
     980              : 
     981          138 :       ALLOCATE (rcpbc(3, natom))
     982          442 :       DO iatom = 1, natom
     983          442 :          rcpbc(:, iatom) = pbc(particle_set(iatom)%r(:), cell)
     984              :       END DO
     985           46 :       CALL get_atomic_kind_set(atomic_kind_set, kind_of=kind_of)
     986              : 
     987           46 :       a1 = dispersion_env%a1
     988           46 :       a2 = dispersion_env%a2
     989           46 :       s6 = dispersion_env%s6
     990           46 :       s8 = dispersion_env%s8
     991           46 :       s9 = dispersion_env%s9
     992           46 :       alp = dispersion_env%alp
     993              : 
     994           46 :       cutoff2 = cutoff**2
     995              : 
     996           46 :       sab_vdw => dispersion_env%sab_vdw
     997              : 
     998           46 :       num_pe = 1
     999           46 :       CALL neighbor_list_iterator_create(nl_iterator, sab_vdw, nthread=num_pe)
    1000              : 
    1001           46 :       mepos = 0
    1002       131209 :       DO WHILE (neighbor_list_iterate(nl_iterator, mepos=mepos) == 0)
    1003       131163 :          CALL get_iterator_info(nl_iterator, mepos=mepos, ikind=ikind, jkind=jkind, iatom=iatom, jatom=jatom, r=rij)
    1004              : 
    1005              :          ! Skip ghost/floating atoms
    1006       131163 :          ia = atom_map(iatom)
    1007       131163 :          ja = atom_map(jatom)
    1008       131163 :          IF (ia == 0 .OR. ja == 0) CYCLE
    1009       131133 :          ik = species(iatom)
    1010       131133 :          jk = species(jatom)
    1011              : 
    1012       524532 :          r2ij = SUM(rij(:)**2)
    1013       131133 :          IF (calculate_forces) THEN
    1014              :             CALL get_c6derivs(c6ij, dc6dcnij, dc6dqij, ia, ja, ik, jk, &
    1015        89727 :                               gwvec, gwdcn, gwdq, c6ref, mrefs)
    1016              :          ELSE
    1017        41406 :             CALL get_c6value(c6ij, ia, ja, ik, jk, gwvec, c6ref, mrefs)
    1018              :          END IF
    1019       131133 :          r0ij = a1*SQRT(3._dp*r4r2(jk)*r4r2(ik)) + a2
    1020       131179 :          IF (r2ij <= cutoff2 .AND. r2ij > EPSILON(1._dp)) THEN
    1021        26841 :             CALL get_iterator_info(nl_iterator, cell=cell_b)
    1022       429456 :             rb0(:) = MATMUL(cell%hmat, cell_b)
    1023       107364 :             ra(:) = rcpbc(:, iatom)
    1024       107364 :             rb(:) = rcpbc(:, jatom) + rb0
    1025       107364 :             vij(:) = rb(:) - ra(:)
    1026              : 
    1027       132328 :             DO katom = 1, MIN(iatom, jatom)
    1028       105487 :                ka = atom_map(katom)
    1029       105487 :                IF (ka == 0) CYCLE
    1030       105478 :                kk = species(katom)
    1031       105478 :                IF (calculate_forces) THEN
    1032              :                   CALL get_c6derivs(c6ik, dc6dcnik, dc6dqik, ka, ia, kk, ik, &
    1033        90148 :                                     gwvec, gwdcn, gwdq, c6ref, mrefs)
    1034              :                   CALL get_c6derivs(c6jk, dc6dcnjk, dc6dqjk, ka, ja, kk, jk, &
    1035        90148 :                                     gwvec, gwdcn, gwdq, c6ref, mrefs)
    1036              :                ELSE
    1037        15330 :                   CALL get_c6value(c6ik, ka, ia, kk, ik, gwvec, c6ref, mrefs)
    1038        15330 :                   CALL get_c6value(c6jk, ka, ja, kk, jk, gwvec, c6ref, mrefs)
    1039              :                END IF
    1040       105478 :                c9 = -s9*SQRT(ABS(c6ij*c6ik*c6jk))
    1041       105478 :                r0ik = a1*SQRT(3._dp*r4r2(kk)*r4r2(ik)) + a2
    1042       105478 :                r0jk = a1*SQRT(3._dp*r4r2(kk)*r4r2(jk)) + a2
    1043       105478 :                r0 = r0ij*r0ik*r0jk
    1044       105478 :                fac = triple_scale(iatom, jatom, katom)
    1045    111665690 :                DO ktr = 1, SIZE(tvec, 2)
    1046    446133448 :                   vik(:) = rcpbc(:, katom) + tvec(:, ktr) - rcpbc(:, iatom)
    1047    111533362 :                   r2ik = vik(1)*vik(1) + vik(2)*vik(2) + vik(3)*vik(3)
    1048    111533362 :                   IF (r2ik > cutoff2 .OR. r2ik < EPSILON(1.0_dp)) CYCLE
    1049    123744248 :                   vjk(:) = rcpbc(:, katom) + tvec(:, ktr) - rb(:)
    1050     30936062 :                   r2jk = vjk(1)*vjk(1) + vjk(2)*vjk(2) + vjk(3)*vjk(3)
    1051     30936062 :                   IF (r2jk > cutoff2 .OR. r2jk < EPSILON(1.0_dp)) CYCLE
    1052     14452920 :                   r2 = r2ij*r2ik*r2jk
    1053     14452920 :                   r1 = SQRT(r2)
    1054     14452920 :                   r3 = r2*r1
    1055     14452920 :                   r5 = r3*r2
    1056              : 
    1057     14452920 :                   fdmp = 1.0_dp/(1.0_dp + 6.0_dp*(r0/r1)**(alp/3.0_dp))
    1058              :                   ang = 0.375_dp*(r2ij + r2jk - r2ik)*(r2ij - r2jk + r2ik)* &
    1059     14452920 :                         (-r2ij + r2jk + r2ik)/r5 + 1.0_dp/r3
    1060              : 
    1061     14452920 :                   rr = ang*fdmp
    1062     14452920 :                   dE = rr*c9*fac
    1063     14452920 :                   energies(iatom) = energies(iatom) - dE/3._dp
    1064     14452920 :                   energies(jatom) = energies(jatom) - dE/3._dp
    1065     14452920 :                   energies(katom) = energies(katom) - dE/3._dp
    1066              : 
    1067     14558398 :                   IF (calculate_forces) THEN
    1068              : 
    1069     14258672 :                      dfdmp = -2.0_dp*alp*(r0/r1)**(alp/3.0_dp)*fdmp**2
    1070              : 
    1071              :                      ! d/drij
    1072              :                      dang = -0.375_dp*(r2ij**3 + r2ij**2*(r2jk + r2ik) &
    1073              :                                        + r2ij*(3.0_dp*r2jk**2 + 2.0_dp*r2jk*r2ik &
    1074              :                                                + 3.0_dp*r2ik**2) &
    1075     14258672 :                                        - 5.0_dp*(r2jk - r2ik)**2*(r2jk + r2ik))/r5
    1076     57034688 :                      dGij(:) = c9*(-dang*fdmp + ang*dfdmp)/r2ij*vij
    1077              : 
    1078              :                      ! d/drik
    1079              :                      dang = -0.375_dp*(r2ik**3 + r2ik**2*(r2jk + r2ij) &
    1080              :                                        + r2ik*(3.0_dp*r2jk**2 + 2.0_dp*r2jk*r2ij &
    1081              :                                                + 3.0_dp*r2ij**2) &
    1082     14258672 :                                        - 5.0_dp*(r2jk - r2ij)**2*(r2jk + r2ij))/r5
    1083     57034688 :                      dGik(:) = c9*(-dang*fdmp + ang*dfdmp)/r2ik*vik
    1084              : 
    1085              :                      ! d/drjk
    1086              :                      dang = -0.375_dp*(r2jk**3 + r2jk**2*(r2ik + r2ij) &
    1087              :                                        + r2jk*(3.0_dp*r2ik**2 + 2.0_dp*r2ik*r2ij &
    1088              :                                                + 3.0_dp*r2ij**2) &
    1089     14258672 :                                        - 5.0_dp*(r2ik - r2ij)**2*(r2ik + r2ij))/r5
    1090     57034688 :                      dGjk(:) = c9*(-dang*fdmp + ang*dfdmp)/r2jk*vjk
    1091              : 
    1092     57034688 :                      gradient(:, iatom) = gradient(:, iatom) - dGij - dGik
    1093     57034688 :                      gradient(:, jatom) = gradient(:, jatom) + dGij - dGjk
    1094     57034688 :                      gradient(:, katom) = gradient(:, katom) + dGik + dGjk
    1095              : 
    1096              :                      dS(:, :) = SPREAD(dGij, 1, 3)*SPREAD(vij, 2, 3) &
    1097              :                                 + SPREAD(dGik, 1, 3)*SPREAD(vik, 2, 3) &
    1098    185362736 :                                 + SPREAD(dGjk, 1, 3)*SPREAD(vjk, 2, 3)
    1099              : 
    1100    185362736 :                      stress(:, :) = stress + dS*fac
    1101              : 
    1102              :                      dEdcn(iatom) = dEdcn(iatom) - dE*0.5_dp &
    1103     14258672 :                                     *(dc6dcnij(1)/c6ij + dc6dcnik(2)/c6ik)
    1104              :                      dEdcn(jatom) = dEdcn(jatom) - dE*0.5_dp &
    1105     14258672 :                                     *(dc6dcnij(2)/c6ij + dc6dcnjk(2)/c6jk)
    1106              :                      dEdcn(katom) = dEdcn(katom) - dE*0.5_dp &
    1107     14258672 :                                     *(dc6dcnik(1)/c6ik + dc6dcnjk(1)/c6jk)
    1108              : 
    1109              :                      dEdq(iatom) = dEdq(iatom) - dE*0.5_dp &
    1110     14258672 :                                    *(dc6dqij(1)/c6ij + dc6dqik(2)/c6ik)
    1111              :                      dEdq(jatom) = dEdq(jatom) - dE*0.5_dp &
    1112     14258672 :                                    *(dc6dqij(2)/c6ij + dc6dqjk(2)/c6jk)
    1113              :                      dEdq(katom) = dEdq(katom) - dE*0.5_dp &
    1114     14258672 :                                    *(dc6dqik(1)/c6ik + dc6dqjk(1)/c6jk)
    1115              : 
    1116              :                   END IF
    1117              : 
    1118              :                END DO
    1119              :             END DO
    1120              :          END IF
    1121              :       END DO
    1122              : 
    1123           46 :       CALL neighbor_list_iterator_release(nl_iterator)
    1124              : 
    1125           46 :       DEALLOCATE (rcpbc)
    1126              : 
    1127           92 :    END SUBROUTINE dispersion_3b
    1128              : 
    1129              : ! **************************************************************************************************
    1130              : !> \brief ...
    1131              : !> \param ii ...
    1132              : !> \param jj ...
    1133              : !> \param kk ...
    1134              : !> \return ...
    1135              : ! **************************************************************************************************
    1136       105478 :    FUNCTION triple_scale(ii, jj, kk) RESULT(triple)
    1137              :       INTEGER, INTENT(IN)                                :: ii, jj, kk
    1138              :       REAL(KIND=dp)                                      :: triple
    1139              : 
    1140       105478 :       IF (ii == jj) THEN
    1141        25881 :          IF (ii == kk) THEN
    1142              :             ! ii'i" -> 1/6
    1143              :             triple = 1.0_dp/6.0_dp
    1144              :          ELSE
    1145              :             ! ii'j -> 1/2
    1146        20997 :             triple = 0.5_dp
    1147              :          END IF
    1148              :       ELSE
    1149        79597 :          IF (ii /= kk .AND. jj /= kk) THEN
    1150              :             ! ijk -> 1 (full)
    1151              :             triple = 1.0_dp
    1152              :          ELSE
    1153              :             ! ijj' and iji' -> 1/2
    1154        21957 :             triple = 0.5_dp
    1155              :          END IF
    1156              :       END IF
    1157              : 
    1158       105478 :    END FUNCTION triple_scale
    1159              : 
    1160              : ! **************************************************************************************************
    1161              : !> \brief ...
    1162              : !> \param qs_env ...
    1163              : !> \param dEdcn ...
    1164              : !> \param dcnum ...
    1165              : !> \param gradient ...
    1166              : !> \param stress ...
    1167              : ! **************************************************************************************************
    1168           22 :    SUBROUTINE dEdcn_force(qs_env, dEdcn, dcnum, gradient, stress)
    1169              :       TYPE(qs_environment_type), POINTER                 :: qs_env
    1170              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: dEdcn
    1171              :       TYPE(dcnum_type), DIMENSION(:), INTENT(IN)         :: dcnum
    1172              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: gradient
    1173              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(INOUT)      :: stress
    1174              : 
    1175              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'dEdcn_force'
    1176              : 
    1177              :       INTEGER                                            :: handle, i, ia, iatom, ikind, katom, &
    1178              :                                                             natom, nkind
    1179              :       LOGICAL                                            :: use_virial
    1180              :       REAL(KIND=dp)                                      :: drk
    1181              :       REAL(KIND=dp), DIMENSION(3)                        :: fdik, rik
    1182              :       TYPE(distribution_1d_type), POINTER                :: local_particles
    1183              :       TYPE(virial_type), POINTER                         :: virial
    1184              : 
    1185           22 :       CALL timeset(routineN, handle)
    1186              : 
    1187              :       CALL get_qs_env(qs_env, nkind=nkind, natom=natom, &
    1188              :                       local_particles=local_particles, &
    1189           22 :                       virial=virial)
    1190           22 :       use_virial = virial%pv_availability .AND. (.NOT. virial%pv_numer)
    1191              : 
    1192           76 :       DO ikind = 1, nkind
    1193          144 :          DO ia = 1, local_particles%n_el(ikind)
    1194           68 :             iatom = local_particles%list(ikind)%array(ia)
    1195          222 :             DO i = 1, dcnum(iatom)%neighbors
    1196          100 :                katom = dcnum(iatom)%nlist(i)
    1197          400 :                rik = dcnum(iatom)%rik(:, i)
    1198          400 :                drk = SQRT(SUM(rik(:)**2))
    1199          400 :                fdik(:) = -(dEdcn(iatom) + dEdcn(katom))*dcnum(iatom)%dvals(i)*rik(:)/drk
    1200          400 :                gradient(:, iatom) = gradient(:, iatom) + fdik(:)
    1201          168 :                IF (use_virial) THEN
    1202           22 :                   CALL virial_pair_force(stress, -0.5_dp, fdik, rik)
    1203              :                END IF
    1204              :             END DO
    1205              :          END DO
    1206              :       END DO
    1207              : 
    1208           22 :       CALL timestop(handle)
    1209              : 
    1210           22 :    END SUBROUTINE dEdcn_force
    1211              : 
    1212              : ! **************************************************************************************************
    1213              : !> \brief ...
    1214              : !> \param c6ij ...
    1215              : !> \param ia ...
    1216              : !> \param ja ...
    1217              : !> \param ik ...
    1218              : !> \param jk ...
    1219              : !> \param gwvec ...
    1220              : !> \param c6ref ...
    1221              : !> \param mrefs ...
    1222              : ! **************************************************************************************************
    1223       171345 :    SUBROUTINE get_c6value(c6ij, ia, ja, ik, jk, gwvec, c6ref, mrefs)
    1224              :       REAL(KIND=dp), INTENT(OUT)                         :: c6ij
    1225              :       INTEGER, INTENT(IN)                                :: ia, ja, ik, jk
    1226              : #if defined(__DFTD4_V3)
    1227              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: gwvec
    1228              : #else
    1229              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: gwvec
    1230              : #endif
    1231              :       REAL(KIND=dp), DIMENSION(:, :, :, :), INTENT(IN)   :: c6ref
    1232              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mrefs
    1233              : 
    1234              :       INTEGER                                            :: iref, jref
    1235              :       REAL(KIND=dp)                                      :: refc6
    1236              : 
    1237       171345 :       c6ij = 0.0_dp
    1238       699407 :       DO jref = 1, mrefs(jk)
    1239      2665200 :          DO iref = 1, mrefs(ik)
    1240      1965793 :             refc6 = c6ref(iref, jref, ik, jk)
    1241              : #if defined(__DFTD4_V3)
    1242              :             c6ij = c6ij + gwvec(iref, ia)*gwvec(jref, ja)*refc6
    1243              : #else
    1244      2493855 :             c6ij = c6ij + gwvec(iref, ia, 1)*gwvec(jref, ja, 1)*refc6
    1245              : #endif
    1246              :          END DO
    1247              :       END DO
    1248              : 
    1249       171345 :    END SUBROUTINE get_c6value
    1250              : 
    1251              : ! **************************************************************************************************
    1252              : !> \brief ...
    1253              : !> \param c6ij ...
    1254              : !> \param dc6dcn ...
    1255              : !> \param dc6dq ...
    1256              : !> \param ia ...
    1257              : !> \param ja ...
    1258              : !> \param ik ...
    1259              : !> \param jk ...
    1260              : !> \param gwvec ...
    1261              : !> \param gwdcn ...
    1262              : !> \param gwdq ...
    1263              : !> \param c6ref ...
    1264              : !> \param mrefs ...
    1265              : ! **************************************************************************************************
    1266       362036 :    SUBROUTINE get_c6derivs(c6ij, dc6dcn, dc6dq, ia, ja, ik, jk, &
    1267       362036 :                            gwvec, gwdcn, gwdq, c6ref, mrefs)
    1268              :       REAL(KIND=dp), INTENT(OUT)                         :: c6ij
    1269              :       REAL(KIND=dp), DIMENSION(2), INTENT(OUT)           :: dc6dcn, dc6dq
    1270              :       INTEGER, INTENT(IN)                                :: ia, ja, ik, jk
    1271              : #if defined(__DFTD4_V3)
    1272              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: gwvec, gwdcn, gwdq
    1273              : #else
    1274              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(IN)      :: gwvec, gwdcn, gwdq
    1275              : #endif
    1276              :       REAL(KIND=dp), DIMENSION(:, :, :, :), INTENT(IN)   :: c6ref
    1277              :       INTEGER, DIMENSION(:), INTENT(IN)                  :: mrefs
    1278              : 
    1279              :       INTEGER                                            :: iref, jref
    1280              :       REAL(KIND=dp)                                      :: refc6
    1281              : 
    1282       362036 :       c6ij = 0.0_dp
    1283       362036 :       dc6dcn = 0.0_dp
    1284       362036 :       dc6dq = 0.0_dp
    1285      1326656 :       DO jref = 1, mrefs(jk)
    1286      4990419 :          DO iref = 1, mrefs(ik)
    1287      3663763 :             refc6 = c6ref(iref, jref, ik, jk)
    1288              : #if defined(__DFTD4_V3)
    1289              :             c6ij = c6ij + gwvec(iref, ia)*gwvec(jref, ja)*refc6
    1290              :             dc6dcn(1) = dc6dcn(1) + gwdcn(iref, ia)*gwvec(jref, ja)*refc6
    1291              :             dc6dcn(2) = dc6dcn(2) + gwvec(iref, ia)*gwdcn(jref, ja)*refc6
    1292              :             dc6dq(1) = dc6dq(1) + gwdq(iref, ia)*gwvec(jref, ja)*refc6
    1293              :             dc6dq(2) = dc6dq(2) + gwvec(iref, ia)*gwdq(jref, ja)*refc6
    1294              : #else
    1295      3663763 :             c6ij = c6ij + gwvec(iref, ia, 1)*gwvec(jref, ja, 1)*refc6
    1296      3663763 :             dc6dcn(1) = dc6dcn(1) + gwdcn(iref, ia, 1)*gwvec(jref, ja, 1)*refc6
    1297      3663763 :             dc6dcn(2) = dc6dcn(2) + gwvec(iref, ia, 1)*gwdcn(jref, ja, 1)*refc6
    1298      3663763 :             dc6dq(1) = dc6dq(1) + gwdq(iref, ia, 1)*gwvec(jref, ja, 1)*refc6
    1299      4628383 :             dc6dq(2) = dc6dq(2) + gwvec(iref, ia, 1)*gwdq(jref, ja, 1)*refc6
    1300              : #endif
    1301              :          END DO
    1302              :       END DO
    1303              : 
    1304       362036 :    END SUBROUTINE get_c6derivs
    1305              : 
    1306              : ! **************************************************************************************************
    1307              : !> \brief ...
    1308              : !> \param ga ...
    1309              : !> \param gd ...
    1310              : !> \param ev1 ...
    1311              : !> \param ev2 ...
    1312              : !> \param ev3 ...
    1313              : !> \param ev4 ...
    1314              : ! **************************************************************************************************
    1315            0 :    SUBROUTINE gerror(ga, gd, ev1, ev2, ev3, ev4)
    1316              :       REAL(KIND=dp), DIMENSION(:, :)                     :: ga, gd
    1317              :       REAL(KIND=dp), INTENT(OUT)                         :: ev1, ev2, ev3, ev4
    1318              : 
    1319              :       INTEGER                                            :: na, np(2)
    1320              : 
    1321            0 :       na = SIZE(ga, 2)
    1322            0 :       ev1 = SQRT(SUM((gd - ga)**2)/na)
    1323            0 :       ev2 = ev1/SQRT(SUM(gd**2)/na)*100._dp
    1324            0 :       np = MAXLOC(ABS(gd - ga))
    1325            0 :       ev3 = ABS(gd(np(1), np(2)) - ga(np(1), np(2)))
    1326            0 :       ev4 = ABS(gd(np(1), np(2)))
    1327            0 :       IF (ev4 > 1.E-6) THEN
    1328            0 :          ev4 = ev3/ev4*100._dp
    1329              :       ELSE
    1330            0 :          ev4 = 100.0_dp
    1331              :       END IF
    1332              : 
    1333            0 :    END SUBROUTINE gerror
    1334              : 
    1335              : ! **************************************************************************************************
    1336              : !> \brief ...
    1337              : !> \param sa ...
    1338              : !> \param sd ...
    1339              : !> \param ev1 ...
    1340              : !> \param ev2 ...
    1341              : ! **************************************************************************************************
    1342            0 :    SUBROUTINE serror(sa, sd, ev1, ev2)
    1343              :       REAL(KIND=dp), DIMENSION(3, 3)                     :: sa, sd
    1344              :       REAL(KIND=dp), INTENT(OUT)                         :: ev1, ev2
    1345              : 
    1346              :       INTEGER                                            :: i, j
    1347              :       REAL(KIND=dp)                                      :: rel
    1348              : 
    1349            0 :       ev1 = MAXVAL(ABS(sd - sa))
    1350            0 :       ev2 = 0.0_dp
    1351            0 :       DO i = 1, 3
    1352            0 :          DO j = 1, 3
    1353            0 :             IF (ABS(sd(i, j)) > 1.E-6_dp) THEN
    1354            0 :                rel = ABS(sd(i, j) - sa(i, j))/ABS(sd(i, j))*100._dp
    1355            0 :                ev2 = MAX(ev2, rel)
    1356              :             END IF
    1357              :          END DO
    1358              :       END DO
    1359              : 
    1360            0 :    END SUBROUTINE serror
    1361              : 
    1362              : ! **************************************************************************************************
    1363              : !> \brief ...
    1364              : !> \param va ...
    1365              : !> \param vd ...
    1366              : !> \param ev1 ...
    1367              : !> \param ev2 ...
    1368              : ! **************************************************************************************************
    1369            0 :    SUBROUTINE verror(va, vd, ev1, ev2)
    1370              :       REAL(KIND=dp), DIMENSION(:)                        :: va, vd
    1371              :       REAL(KIND=dp), INTENT(OUT)                         :: ev1, ev2
    1372              : 
    1373              :       INTEGER                                            :: i, na
    1374              :       REAL(KIND=dp)                                      :: rel
    1375              : 
    1376            0 :       na = SIZE(va)
    1377            0 :       ev1 = MAXVAL(ABS(vd - va))
    1378            0 :       ev2 = 0.0_dp
    1379            0 :       DO i = 1, na
    1380            0 :          IF (ABS(vd(i)) > 1.E-8_dp) THEN
    1381            0 :             rel = ABS(vd(i) - va(i))/ABS(vd(i))*100._dp
    1382            0 :             ev2 = MAX(ev2, rel)
    1383              :          END IF
    1384              :       END DO
    1385              : 
    1386            0 :    END SUBROUTINE verror
    1387              : 
    1388          910 : END MODULE qs_dispersion_d4
        

Generated by: LCOV version 2.0-1