LCOV - code coverage report
Current view: top level - src - cp_ddapc_forces.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 93.4 % 258 241
Test Date: 2026-06-05 07:04:50 Functions: 100.0 % 6 6

            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 Density Derived atomic point charges from a QM calculation
      10              : !>      (see J. Chem. Phys. Vol. 103 pp. 7422-7428)
      11              : !> \par History
      12              : !>      08.2005 created [tlaino]
      13              : !> \author Teodoro Laino
      14              : ! **************************************************************************************************
      15              : MODULE cp_ddapc_forces
      16              : 
      17              :    USE atomic_kind_types,               ONLY: atomic_kind_type,&
      18              :                                               get_atomic_kind_set
      19              :    USE cell_types,                      ONLY: cell_type
      20              :    USE cp_control_types,                ONLY: ddapc_restraint_type
      21              :    USE input_constants,                 ONLY: do_ddapc_constraint,&
      22              :                                               do_ddapc_restraint,&
      23              :                                               weight_type_mass,&
      24              :                                               weight_type_unit
      25              :    USE input_section_types,             ONLY: section_vals_type,&
      26              :                                               section_vals_val_get
      27              :    USE kinds,                           ONLY: dp
      28              :    USE mathconstants,                   ONLY: fourpi,&
      29              :                                               pi,&
      30              :                                               rootpi,&
      31              :                                               twopi
      32              :    USE message_passing,                 ONLY: mp_para_env_type
      33              :    USE particle_types,                  ONLY: particle_type
      34              :    USE pw_spline_utils,                 ONLY: Eval_d_Interp_Spl3_pbc
      35              :    USE pw_types,                        ONLY: pw_r3d_rs_type
      36              :    USE qs_environment_types,            ONLY: get_qs_env,&
      37              :                                               qs_environment_type
      38              :    USE qs_force_types,                  ONLY: qs_force_type
      39              :    USE spherical_harmonics,             ONLY: dlegendre,&
      40              :                                               legendre
      41              : !NB for reducing results of calculations that use dq, which is now spread over nodes
      42              : #include "./base/base_uses.f90"
      43              : 
      44              :    IMPLICIT NONE
      45              :    PRIVATE
      46              : 
      47              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      48              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_ddapc_forces'
      49              :    PUBLIC :: ewald_ddapc_force, &
      50              :              reset_ch_pulay, &
      51              :              evaluate_restraint_functional, &
      52              :              restraint_functional_force, &
      53              :              solvation_ddapc_force
      54              : 
      55              : CONTAINS
      56              : 
      57              : ! **************************************************************************************************
      58              : !> \brief Evaluates the Ewald term E2 and E3 energy term for the decoupling/coupling
      59              : !>      of periodic images
      60              : !> \param qs_env ...
      61              : !> \param coeff ...
      62              : !> \param apply_qmmm_periodic ...
      63              : !> \param factor ...
      64              : !> \param multipole_section ...
      65              : !> \param cell ...
      66              : !> \param particle_set ...
      67              : !> \param radii ...
      68              : !> \param dq ...
      69              : !> \param charges ...
      70              : !> \par History
      71              : !>      08.2005 created [tlaino]
      72              : !> \author Teodoro Laino
      73              : ! **************************************************************************************************
      74          144 :    RECURSIVE SUBROUTINE ewald_ddapc_force(qs_env, coeff, apply_qmmm_periodic, &
      75              :                                           factor, multipole_section, cell, particle_set, radii, dq, charges)
      76              :       TYPE(qs_environment_type), POINTER                 :: qs_env
      77              :       TYPE(pw_r3d_rs_type), INTENT(IN), POINTER          :: coeff
      78              :       LOGICAL, INTENT(IN)                                :: apply_qmmm_periodic
      79              :       REAL(KIND=dp), INTENT(IN)                          :: factor
      80              :       TYPE(section_vals_type), POINTER                   :: multipole_section
      81              :       TYPE(cell_type), POINTER                           :: cell
      82              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
      83              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
      84              :       REAL(KIND=dp), DIMENSION(:, :, :), OPTIONAL, &
      85              :          POINTER                                         :: dq
      86              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: charges
      87              : 
      88              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ewald_ddapc_force'
      89              : 
      90              :       INTEGER                                            :: handle, idim, ip1, ip2, iparticle1, &
      91              :                                                             iparticle2, k1, k2, k3, n_rep, r1, r2, &
      92              :                                                             r3
      93              :       INTEGER, DIMENSION(3)                              :: gmax, image_cell, rmax, rmin
      94              :       LOGICAL                                            :: analyt
      95              :       REAL(KIND=dp)                                      :: alpha, eps, fac, frac_radius, fs, &
      96              :                                                             galpha, gsq, gsqi, ij_fac, q1t, q2t, &
      97              :                                                             r, r2tmp, rcut, rcut2, t1, t2, tol, &
      98              :                                                             tol1
      99              :       REAL(KIND=dp), DIMENSION(3)                        :: drvec, g_index, gvec, ra, rvec, svec
     100          144 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: d_el, M
     101              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     102              : 
     103          144 :       NULLIFY (d_el, M, para_env)
     104          144 :       CALL timeset(routineN, handle)
     105          144 :       CALL get_qs_env(qs_env, para_env=para_env)
     106          144 :       CPASSERT(PRESENT(charges))
     107          144 :       CPASSERT(ASSOCIATED(radii))
     108         1440 :       rcut = MIN(NORM2(cell%hmat(:, 1)), NORM2(cell%hmat(:, 2)), NORM2(cell%hmat(:, 3)))/2.0_dp
     109          144 :       CALL section_vals_val_get(multipole_section, "RCUT", n_rep_val=n_rep)
     110          144 :       IF (n_rep == 1) CALL section_vals_val_get(multipole_section, "RCUT", r_val=rcut)
     111          144 :       CALL section_vals_val_get(multipole_section, "EWALD_PRECISION", r_val=eps)
     112          144 :       CALL section_vals_val_get(multipole_section, "ANALYTICAL_GTERM", l_val=analyt)
     113              :       ! The spline interpolation path is only valid for orthorhombic grids.
     114          144 :       analyt = analyt .OR. .NOT. cell%orthorhombic .OR. .NOT. ASSOCIATED(coeff)
     115          144 :       rcut2 = rcut**2
     116              :       !
     117              :       ! Setting-up parameters for Ewald summation
     118              :       !
     119          144 :       eps = MIN(ABS(eps), 0.5_dp)
     120          144 :       tol = SQRT(ABS(LOG(eps*rcut)))
     121          144 :       alpha = SQRT(ABS(LOG(eps*rcut*tol)))/rcut
     122          144 :       galpha = 1.0_dp/(4.0_dp*alpha*alpha)
     123          144 :       tol1 = SQRT(-LOG(eps*rcut*(2.0_dp*tol*alpha)**2))
     124          144 :       IF (cell%orthorhombic) THEN
     125          552 :          DO idim = 1, 3
     126          552 :             gmax(idim) = NINT(0.25_dp + cell%hmat(idim, idim)*alpha*tol1/pi)
     127              :          END DO
     128              :       ELSE
     129           24 :          DO idim = 1, 3
     130           78 :             gmax(idim) = CEILING(alpha*tol1*NORM2(cell%hmat(:, idim))/pi)
     131              :          END DO
     132              :       END IF
     133              : 
     134          432 :       ALLOCATE (d_el(3, SIZE(particle_set)))
     135         1808 :       d_el = 0.0_dp
     136          144 :       fac = 1.e0_dp/cell%deth
     137              :       !
     138          560 :       DO iparticle1 = 1, SIZE(particle_set)
     139              :          !NB parallelization
     140          416 :          IF (MOD(iparticle1, para_env%num_pe) /= para_env%mepos) CYCLE
     141          224 :          ip1 = (iparticle1 - 1)*SIZE(radii)
     142          896 :          q1t = SUM(charges(ip1 + 1:ip1 + SIZE(radii)))
     143          898 :          DO iparticle2 = 1, iparticle1
     144          530 :             ij_fac = 1.0_dp
     145          530 :             IF (iparticle1 == iparticle2) ij_fac = 0.5_dp
     146              : 
     147          530 :             ip2 = (iparticle2 - 1)*SIZE(radii)
     148         2120 :             q2t = SUM(charges(ip2 + 1:ip2 + SIZE(radii)))
     149              :             !
     150              :             ! Real-Space Contribution
     151              :             !
     152         2120 :             rvec = particle_set(iparticle1)%r - particle_set(iparticle2)%r
     153          530 :             IF (iparticle1 /= iparticle2) THEN
     154          306 :                ra = rvec
     155         1224 :                r2tmp = DOT_PRODUCT(ra, ra)
     156          306 :                IF (r2tmp <= rcut2) THEN
     157          194 :                   r = SQRT(r2tmp)
     158          194 :                   t1 = erfc(alpha*r)/r
     159          776 :                   drvec = ra/r*q1t*q2t*factor
     160          194 :                   t2 = -2.0_dp*alpha*EXP(-alpha*alpha*r*r)/(r*rootpi) - t1/r
     161          776 :                   d_el(1:3, iparticle1) = d_el(1:3, iparticle1) - t2*drvec
     162          776 :                   d_el(1:3, iparticle2) = d_el(1:3, iparticle2) + t2*drvec
     163              :                END IF
     164              :             END IF
     165         6890 :             svec = MATMUL(cell%h_inv, rvec)
     166         2120 :             DO idim = 1, 3
     167         6360 :                frac_radius = rcut*NORM2(cell%h_inv(idim, :))
     168         1590 :                rmin(idim) = FLOOR(-svec(idim) - frac_radius)
     169         2120 :                rmax(idim) = CEILING(-svec(idim) + frac_radius)
     170              :             END DO
     171         2200 :             DO r1 = rmin(1), rmax(1)
     172         7646 :                DO r2 = rmin(2), rmax(2)
     173        25587 :                   DO r3 = rmin(3), rmax(3)
     174        18471 :                      IF ((r1 == 0) .AND. (r2 == 0) .AND. (r3 == 0)) CYCLE
     175        71764 :                      image_cell = [r1, r2, r3]
     176       340879 :                      ra = rvec + MATMUL(cell%hmat, REAL(image_cell, KIND=dp))
     177        71764 :                      r2tmp = DOT_PRODUCT(ra, ra)
     178        23387 :                      IF (r2tmp <= rcut2) THEN
     179         1020 :                         r = SQRT(r2tmp)
     180         1020 :                         t1 = erfc(alpha*r)/r
     181         4080 :                         drvec = ra/r*q1t*q2t*factor*ij_fac
     182         1020 :                         t2 = -2.0_dp*alpha*EXP(-alpha*alpha*r*r)/(r*rootpi) - t1/r
     183         1020 :                         d_el(1, iparticle1) = d_el(1, iparticle1) - t2*drvec(1)
     184         1020 :                         d_el(2, iparticle1) = d_el(2, iparticle1) - t2*drvec(2)
     185         1020 :                         d_el(3, iparticle1) = d_el(3, iparticle1) - t2*drvec(3)
     186         1020 :                         d_el(1, iparticle2) = d_el(1, iparticle2) + t2*drvec(1)
     187         1020 :                         d_el(2, iparticle2) = d_el(2, iparticle2) + t2*drvec(2)
     188         1020 :                         d_el(3, iparticle2) = d_el(3, iparticle2) + t2*drvec(3)
     189              :                      END IF
     190              :                   END DO
     191              :                END DO
     192              :             END DO
     193              :             !
     194              :             ! G-space Contribution
     195              :             !
     196          530 :             IF (analyt) THEN
     197         2869 :                DO k1 = 0, gmax(1)
     198        72444 :                   DO k2 = -gmax(2), gmax(2)
     199      2094321 :                      DO k3 = -gmax(3), gmax(3)
     200      2022107 :                         IF (k1 == 0 .AND. k2 == 0 .AND. k3 == 0) CYCLE
     201      2021877 :                         fs = 2.0_dp; IF (k1 == 0) fs = 1.0_dp
     202      8087508 :                         g_index = [REAL(k1, KIND=dp), REAL(k2, KIND=dp), REAL(k3, KIND=dp)]
     203     10109385 :                         gvec = twopi*MATMUL(TRANSPOSE(cell%h_inv), g_index)
     204      8087508 :                         gsq = DOT_PRODUCT(gvec, gvec)
     205      2021877 :                         gsqi = fs/gsq
     206      2021877 :                         t1 = fac*gsqi*EXP(-galpha*gsq)
     207      8087508 :                         t2 = -SIN(DOT_PRODUCT(gvec, rvec))*t1*q1t*q2t*factor*fourpi
     208      8087508 :                         d_el(1:3, iparticle1) = d_el(1:3, iparticle1) - t2*gvec
     209      8157083 :                         d_el(1:3, iparticle2) = d_el(1:3, iparticle2) + t2*gvec
     210              :                      END DO
     211              :                   END DO
     212              :                END DO
     213              :             ELSE
     214         1200 :                gvec = Eval_d_Interp_Spl3_pbc(rvec, coeff)*q1t*q2t*factor*fourpi
     215         1200 :                d_el(1:3, iparticle1) = d_el(1:3, iparticle1) - gvec
     216         1200 :                d_el(1:3, iparticle2) = d_el(1:3, iparticle2) + gvec
     217              :             END IF
     218          946 :             IF (iparticle1 /= iparticle2) THEN
     219          306 :                ra = rvec
     220         1224 :                r = SQRT(DOT_PRODUCT(ra, ra))
     221          306 :                t2 = -1.0_dp/(r*r)*factor
     222         1224 :                drvec = ra/r*q1t*q2t
     223         1224 :                d_el(1:3, iparticle1) = d_el(1:3, iparticle1) + t2*drvec
     224         1224 :                d_el(1:3, iparticle2) = d_el(1:3, iparticle2) - t2*drvec
     225              :             END IF
     226              :          END DO ! iparticle2
     227              :       END DO ! iparticle1
     228              :       !NB parallelization
     229         3472 :       CALL para_env%sum(d_el)
     230          144 :       M => qs_env%cp_ddapc_env%Md
     231          144 :       IF (apply_qmmm_periodic) M => qs_env%cp_ddapc_env%Mr
     232          144 :       CALL cp_decpl_ddapc_forces(qs_env, M, charges, dq, d_el, particle_set)
     233          144 :       DEALLOCATE (d_el)
     234          144 :       CALL timestop(handle)
     235          432 :    END SUBROUTINE ewald_ddapc_force
     236              : 
     237              : ! **************************************************************************************************
     238              : !> \brief Evaluation of the pulay forces due to the fitted charge density
     239              : !> \param qs_env ...
     240              : !> \param M ...
     241              : !> \param charges ...
     242              : !> \param dq ...
     243              : !> \param d_el ...
     244              : !> \param particle_set ...
     245              : !> \par History
     246              : !>      08.2005 created [tlaino]
     247              : !> \author Teodoro Laino
     248              : ! **************************************************************************************************
     249          158 :    SUBROUTINE cp_decpl_ddapc_forces(qs_env, M, charges, dq, d_el, particle_set)
     250              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     251              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: M
     252              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges
     253              :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: dq
     254              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: d_el
     255              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     256              : 
     257              :       CHARACTER(len=*), PARAMETER :: routineN = 'cp_decpl_ddapc_forces'
     258              : 
     259              :       INTEGER                                            :: handle, i, iatom, ikind, j, k, natom
     260          158 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_of_kind, kind_of
     261          158 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: uv
     262              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: chf
     263          158 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     264              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     265          158 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     266              : 
     267          158 :       NULLIFY (para_env)
     268          158 :       CALL timeset(routineN, handle)
     269          158 :       natom = SIZE(particle_set)
     270              :       CALL get_qs_env(qs_env=qs_env, &
     271              :                       atomic_kind_set=atomic_kind_set, &
     272              :                       para_env=para_env, &
     273          158 :                       force=force)
     274          474 :       ALLOCATE (chf(3, natom))
     275              :       CALL get_atomic_kind_set(atomic_kind_set=atomic_kind_set, &
     276              :                                atom_of_kind=atom_of_kind, &
     277          158 :                                kind_of=kind_of)
     278              : 
     279          474 :       ALLOCATE (uv(SIZE(M, 1)))
     280        47906 :       uv(:) = MATMUL(M, charges)
     281          612 :       DO k = 1, natom
     282         1974 :          DO j = 1, 3
     283        17278 :             chf(j, k) = DOT_PRODUCT(uv, dq(:, k, j))
     284              :          END DO
     285              :       END DO
     286              :       !NB now that get_ddapc returns dq that's spread over nodes, must reduce chf here
     287          158 :       CALL para_env%sum(chf)
     288          612 :       DO iatom = 1, natom
     289          454 :          ikind = kind_of(iatom)
     290          454 :          i = atom_of_kind(iatom)
     291         3790 :          force(ikind)%ch_pulay(1:3, i) = force(ikind)%ch_pulay(1:3, i) + chf(1:3, iatom) + d_el(1:3, iatom)
     292              :       END DO
     293          158 :       DEALLOCATE (chf)
     294          158 :       DEALLOCATE (uv)
     295          158 :       CALL timestop(handle)
     296          316 :    END SUBROUTINE cp_decpl_ddapc_forces
     297              : 
     298              : ! **************************************************************************************************
     299              : !> \brief Evaluation of the pulay forces due to the fitted charge density
     300              : !> \param qs_env ...
     301              : !> \par History
     302              : !>      08.2005 created [tlaino]
     303              : !> \author Teodoro Laino
     304              : ! **************************************************************************************************
     305          128 :    SUBROUTINE reset_ch_pulay(qs_env)
     306              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     307              : 
     308              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'reset_ch_pulay'
     309              : 
     310              :       INTEGER                                            :: handle, ind
     311          128 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     312              : 
     313          128 :       CALL timeset(routineN, handle)
     314              :       CALL get_qs_env(qs_env=qs_env, &
     315          128 :                       force=force)
     316          348 :       DO ind = 1, SIZE(force)
     317         1732 :          force(ind)%ch_pulay = 0.0_dp
     318              :       END DO
     319          128 :       CALL timestop(handle)
     320          128 :    END SUBROUTINE reset_ch_pulay
     321              : 
     322              : ! **************************************************************************************************
     323              : !> \brief computes energy and derivatives given a set of charges
     324              : !> \param ddapc_restraint_control ...
     325              : !> \param n_gauss ...
     326              : !> \param uv derivate of energy wrt the corresponding charge entry
     327              : !> \param charges current value of the charges (one number for each gaussian used)
     328              : !>
     329              : !> \param energy_res energy due to the restraint
     330              : !> \par History
     331              : !>      02.2006 [Joost VandeVondele]
     332              : !>               modified [Teo]
     333              : !> \note
     334              : !>       should be easy to adapt for other specialized cases
     335              : ! **************************************************************************************************
     336          872 :    SUBROUTINE evaluate_restraint_functional(ddapc_restraint_control, n_gauss, uv, &
     337              :                                             charges, energy_res)
     338              :       TYPE(ddapc_restraint_type), INTENT(INOUT)          :: ddapc_restraint_control
     339              :       INTEGER, INTENT(in)                                :: n_gauss
     340              :       REAL(KIND=dp), DIMENSION(:)                        :: uv
     341              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges
     342              :       REAL(KIND=dp), INTENT(INOUT)                       :: energy_res
     343              : 
     344              :       INTEGER                                            :: I, ind
     345              :       REAL(KIND=dp)                                      :: dE, order_p
     346              : 
     347              : ! order parameter (i.e. the sum of the charges of the selected atoms)
     348              : 
     349          872 :       order_p = 0.0_dp
     350         1882 :       DO I = 1, ddapc_restraint_control%natoms
     351         1010 :          ind = (ddapc_restraint_control%atoms(I) - 1)*n_gauss
     352         3532 :          order_p = order_p + ddapc_restraint_control%coeff(I)*SUM(charges(ind + 1:ind + n_gauss))
     353              :       END DO
     354          872 :       ddapc_restraint_control%ddapc_order_p = order_p
     355              : 
     356         1140 :       SELECT CASE (ddapc_restraint_control%functional_form)
     357              :       CASE (do_ddapc_restraint)
     358              :          ! the restraint energy
     359          268 :          energy_res = ddapc_restraint_control%strength*(order_p - ddapc_restraint_control%target)**2.0_dp
     360              : 
     361              :          ! derivative of the energy
     362          268 :          dE = 2.0_dp*ddapc_restraint_control%strength*(order_p - ddapc_restraint_control%target)
     363          536 :          DO I = 1, ddapc_restraint_control%natoms
     364          268 :             ind = (ddapc_restraint_control%atoms(I) - 1)*n_gauss
     365         1340 :             uv(ind + 1:ind + n_gauss) = dE*ddapc_restraint_control%coeff(I)
     366              :          END DO
     367              :       CASE (do_ddapc_constraint)
     368          604 :          energy_res = ddapc_restraint_control%strength*(order_p - ddapc_restraint_control%target)
     369              : 
     370              :          ! derivative of the energy
     371         1346 :          DO I = 1, ddapc_restraint_control%natoms
     372          742 :             ind = (ddapc_restraint_control%atoms(I) - 1)*n_gauss
     373         2192 :             uv(ind + 1:ind + n_gauss) = ddapc_restraint_control%strength*ddapc_restraint_control%coeff(I)
     374              :          END DO
     375              : 
     376              :       CASE DEFAULT
     377          872 :          CPABORT("")
     378              :       END SELECT
     379              : 
     380          872 :    END SUBROUTINE evaluate_restraint_functional
     381              : 
     382              : ! **************************************************************************************************
     383              : !> \brief computes derivatives for DDAPC restraint
     384              : !> \param qs_env ...
     385              : !> \param ddapc_restraint_control ...
     386              : !> \param dq ...
     387              : !> \param charges ...
     388              : !> \param n_gauss ...
     389              : !> \param particle_set ...
     390              : !> \par History
     391              : !>      02.2006 [Joost VandeVondele]
     392              : !>              modified [Teo]
     393              : !> \note
     394              : !>       should be easy to adapt for other specialized cases
     395              : ! **************************************************************************************************
     396           36 :    SUBROUTINE restraint_functional_force(qs_env, ddapc_restraint_control, dq, charges, &
     397              :                                          n_gauss, particle_set)
     398              : 
     399              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     400              :       TYPE(ddapc_restraint_type), INTENT(INOUT)          :: ddapc_restraint_control
     401              :       REAL(KIND=dp), DIMENSION(:, :, :), POINTER         :: dq
     402              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges
     403              :       INTEGER, INTENT(in)                                :: n_gauss
     404              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     405              : 
     406              :       CHARACTER(len=*), PARAMETER :: routineN = 'restraint_functional_force'
     407              : 
     408              :       INTEGER                                            :: handle, i, iatom, ikind, j, k, natom
     409           36 :       INTEGER, ALLOCATABLE, DIMENSION(:)                 :: atom_of_kind, kind_of
     410              :       REAL(kind=dp)                                      :: dum
     411              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: uv
     412              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: chf
     413           36 :       TYPE(atomic_kind_type), DIMENSION(:), POINTER      :: atomic_kind_set
     414              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     415           36 :       TYPE(qs_force_type), DIMENSION(:), POINTER         :: force
     416              : 
     417           36 :       NULLIFY (para_env)
     418           36 :       CALL timeset(routineN, handle)
     419           36 :       natom = SIZE(particle_set)
     420              :       CALL get_qs_env(qs_env=qs_env, &
     421              :                       atomic_kind_set=atomic_kind_set, &
     422              :                       para_env=para_env, &
     423           36 :                       force=force)
     424          108 :       ALLOCATE (chf(3, natom))
     425              :       CALL get_atomic_kind_set(atomic_kind_set=atomic_kind_set, &
     426              :                                atom_of_kind=atom_of_kind, &
     427           36 :                                kind_of=kind_of)
     428              : 
     429          108 :       ALLOCATE (uv(SIZE(dq, 1)))
     430           36 :       uv = 0.0_dp
     431              :       CALL evaluate_restraint_functional(ddapc_restraint_control, n_gauss, uv, &
     432           36 :                                          charges, dum)
     433          118 :       DO k = 1, natom
     434          364 :          DO j = 1, 3
     435         1318 :             chf(j, k) = DOT_PRODUCT(uv, dq(:, k, j))
     436              :          END DO
     437              :       END DO
     438              :       !NB now that get_ddapc returns dq that's spread over nodes, must reduce chf here
     439           36 :       CALL para_env%sum(chf)
     440          118 :       DO iatom = 1, natom
     441           82 :          ikind = kind_of(iatom)
     442           82 :          i = atom_of_kind(iatom)
     443          364 :          force(ikind)%ch_pulay(1:3, i) = force(ikind)%ch_pulay(1:3, i) + chf(1:3, iatom)
     444              :       END DO
     445           36 :       DEALLOCATE (chf)
     446           36 :       DEALLOCATE (uv)
     447           36 :       CALL timestop(handle)
     448              : 
     449           72 :    END SUBROUTINE restraint_functional_force
     450              : 
     451              : ! **************************************************************************************************
     452              : !> \brief Evaluates the electrostatic potential due to a simple solvation model
     453              : !>      Spherical cavity in a dieletric medium
     454              : !> \param qs_env ...
     455              : !> \param solvation_section ...
     456              : !> \param particle_set ...
     457              : !> \param radii ...
     458              : !> \param dq ...
     459              : !> \param charges ...
     460              : !> \par History
     461              : !>      08.2006 created [tlaino]
     462              : !> \author Teodoro Laino
     463              : ! **************************************************************************************************
     464           14 :    SUBROUTINE solvation_ddapc_force(qs_env, solvation_section, particle_set, &
     465              :                                     radii, dq, charges)
     466              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     467              :       TYPE(section_vals_type), POINTER                   :: solvation_section
     468              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     469              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     470              :       REAL(KIND=dp), DIMENSION(:, :, :), OPTIONAL, &
     471              :          POINTER                                         :: dq
     472              :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: charges
     473              : 
     474              :       INTEGER                                            :: i, ip1, ip2, iparticle1, iparticle2, l, &
     475              :                                                             lmax, n_rep1, n_rep2, weight
     476           14 :       INTEGER, DIMENSION(:), POINTER                     :: list
     477              :       LOGICAL                                            :: fixed_center
     478              :       REAL(KIND=dp) :: center(3), dcos1(3), dcos2(3), dpos1(3), dpos2(3), eps_in, eps_out, &
     479              :          factor1(3), factor2(3), lr, mass, mycos, pos1, pos1i, pos2, pos2i, ptcos, q1t, q2t, &
     480              :          r1(3), r1s, r2(3), r2s, Rs, rvec(3)
     481           14 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: pos, R0
     482           14 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: d_el, LocP, M
     483              : 
     484           14 :       fixed_center = .FALSE.
     485           14 :       NULLIFY (d_el, M)
     486           14 :       eps_in = 1.0_dp
     487           14 :       CALL section_vals_val_get(solvation_section, "EPS_OUT", r_val=eps_out)
     488           14 :       CALL section_vals_val_get(solvation_section, "LMAX", i_val=lmax)
     489           14 :       CALL section_vals_val_get(solvation_section, "SPHERE%RADIUS", r_val=Rs)
     490           14 :       CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%XYZ", n_rep_val=n_rep1)
     491           14 :       IF (n_rep1 /= 0) THEN
     492           14 :          CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%XYZ", r_vals=R0)
     493           56 :          center = R0
     494              :       ELSE
     495              :          CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%ATOM_LIST", &
     496            0 :                                    n_rep_val=n_rep2)
     497            0 :          IF (n_rep2 /= 0) THEN
     498            0 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%ATOM_LIST", i_vals=list)
     499            0 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%WEIGHT_TYPE", i_val=weight)
     500            0 :             ALLOCATE (R0(SIZE(list)))
     501              :             SELECT CASE (weight)
     502              :             CASE (weight_type_unit)
     503            0 :                R0 = 0.0_dp
     504            0 :                DO i = 1, SIZE(list)
     505            0 :                   R0 = R0 + particle_set(list(i))%r
     506              :                END DO
     507            0 :                R0 = R0/REAL(SIZE(list), KIND=dp)
     508              :             CASE (weight_type_mass)
     509            0 :                R0 = 0.0_dp
     510            0 :                mass = 0.0_dp
     511            0 :                DO i = 1, SIZE(list)
     512            0 :                   R0 = R0 + particle_set(list(i))%r*particle_set(list(i))%atomic_kind%mass
     513            0 :                   mass = mass + particle_set(list(i))%atomic_kind%mass
     514              :                END DO
     515            0 :                R0 = R0/mass
     516              :             END SELECT
     517            0 :             center = R0
     518            0 :             DEALLOCATE (R0)
     519              :          END IF
     520              :       END IF
     521           14 :       CPASSERT(n_rep1 /= 0 .OR. n_rep2 /= 0)
     522              :       ! Potential calculation
     523           56 :       ALLOCATE (LocP(0:lmax, SIZE(particle_set)))
     524           42 :       ALLOCATE (pos(SIZE(particle_set)))
     525           42 :       ALLOCATE (d_el(3, SIZE(particle_set)))
     526          166 :       d_el = 0.0_dp
     527              :       ! Determining the single atomic contribution to the dielectric dipole
     528           52 :       DO i = 1, SIZE(particle_set)
     529          152 :          rvec = particle_set(i)%r - center
     530          152 :          r2s = DOT_PRODUCT(rvec, rvec)
     531           38 :          r1s = SQRT(r2s)
     532          190 :          LocP(:, i) = 0.0_dp
     533           38 :          IF (r1s /= 0.0_dp) THEN
     534          170 :             DO l = 0, lmax
     535              :                LocP(l, i) = (r1s**l*REAL(l + 1, KIND=dp)*(eps_in - eps_out))/ &
     536          170 :                             (Rs**(2*l + 1)*eps_in*(REAL(l, KIND=dp)*eps_in + REAL(l + 1, KIND=dp)*eps_out))
     537              :             END DO
     538              :          END IF
     539           52 :          pos(i) = r1s
     540              :       END DO
     541              :       ! Computes the full derivatives of the interaction energy
     542           52 :       DO iparticle1 = 1, SIZE(particle_set)
     543           38 :          ip1 = (iparticle1 - 1)*SIZE(radii)
     544          152 :          q1t = SUM(charges(ip1 + 1:ip1 + SIZE(radii)))
     545          126 :          DO iparticle2 = 1, iparticle1
     546           74 :             ip2 = (iparticle2 - 1)*SIZE(radii)
     547          296 :             q2t = SUM(charges(ip2 + 1:ip2 + SIZE(radii)))
     548              :             !
     549          296 :             r1 = particle_set(iparticle1)%r - center
     550          296 :             r2 = particle_set(iparticle2)%r - center
     551           74 :             pos1 = pos(iparticle1)
     552           74 :             pos2 = pos(iparticle2)
     553           74 :             factor1 = 0.0_dp
     554           74 :             factor2 = 0.0_dp
     555           74 :             IF (pos1*pos2 /= 0.0_dp) THEN
     556           62 :                pos1i = 1.0_dp/pos1
     557           62 :                pos2i = 1.0_dp/pos2
     558          248 :                dpos1 = pos1i*r1
     559          248 :                dpos2 = pos2i*r2
     560          248 :                ptcos = DOT_PRODUCT(r1, r2)
     561           62 :                mycos = ptcos/(pos1*pos2)
     562           62 :                IF (ABS(mycos) > 1.0_dp) mycos = SIGN(1.0_dp, mycos)
     563          248 :                dcos1 = (r2*(pos1*pos2) - pos2*dpos1*ptcos)/(pos1*pos2)**2
     564          248 :                dcos2 = (r1*(pos1*pos2) - pos1*dpos2*ptcos)/(pos1*pos2)**2
     565              : 
     566          248 :                DO l = 1, lmax
     567          186 :                   lr = REAL(l, KIND=dp)
     568              :                   factor1 = factor1 + lr*LocP(l, iparticle2)*pos1**(l - 1)*legendre(mycos, l, 0)*dpos1 &
     569          744 :                             + LocP(l, iparticle2)*pos1**l*dlegendre(mycos, l, 0)*dcos1
     570              :                   factor2 = factor2 + lr*LocP(l, iparticle1)*pos2**(l - 1)*legendre(mycos, l, 0)*dpos2 &
     571          806 :                             + LocP(l, iparticle1)*pos2**l*dlegendre(mycos, l, 0)*dcos2
     572              :                END DO
     573              :             END IF
     574          296 :             factor1 = factor1*q1t*q2t
     575          296 :             factor2 = factor2*q1t*q2t
     576          296 :             d_el(1:3, iparticle1) = d_el(1:3, iparticle1) + 0.5_dp*factor1
     577          334 :             d_el(1:3, iparticle2) = d_el(1:3, iparticle2) + 0.5_dp*factor2
     578              :          END DO
     579              :       END DO
     580           14 :       DEALLOCATE (pos)
     581           14 :       DEALLOCATE (LocP)
     582           14 :       M => qs_env%cp_ddapc_env%Ms
     583           14 :       CALL cp_decpl_ddapc_forces(qs_env, M, charges, dq, d_el, particle_set)
     584           14 :       DEALLOCATE (d_el)
     585           14 :    END SUBROUTINE solvation_ddapc_force
     586              : 
     587              : END MODULE cp_ddapc_forces
        

Generated by: LCOV version 2.0-1