LCOV - code coverage report
Current view: top level - src - spme.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:b195825) Lines: 396 398 99.5 %
Date: 2024-04-20 06:29:22 Functions: 6 6 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Calculate the electrostatic energy by the Smooth Particle Ewald method
      10             : !> \par History
      11             : !>      JGH (03-May-2001) : first correctly working version
      12             : !> \author JGH (21-Mar-2001)
      13             : ! **************************************************************************************************
      14             : MODULE spme
      15             : 
      16             :    USE atomic_kind_types,               ONLY: get_atomic_kind
      17             :    USE atprop_types,                    ONLY: atprop_type
      18             :    USE bibliography,                    ONLY: Essmann1995,&
      19             :                                               cite_reference
      20             :    USE cell_types,                      ONLY: cell_type
      21             :    USE dgs,                             ONLY: dg_sum_patch,&
      22             :                                               dg_sum_patch_force_1d,&
      23             :                                               dg_sum_patch_force_3d
      24             :    USE ewald_environment_types,         ONLY: ewald_env_get,&
      25             :                                               ewald_environment_type
      26             :    USE ewald_pw_types,                  ONLY: ewald_pw_get,&
      27             :                                               ewald_pw_type
      28             :    USE kinds,                           ONLY: dp
      29             :    USE mathconstants,                   ONLY: fourpi
      30             :    USE message_passing,                 ONLY: mp_comm_type
      31             :    USE particle_types,                  ONLY: particle_type
      32             :    USE pme_tools,                       ONLY: get_center,&
      33             :                                               set_list
      34             :    USE pw_grid_types,                   ONLY: pw_grid_type
      35             :    USE pw_grids,                        ONLY: get_pw_grid_info
      36             :    USE pw_methods,                      ONLY: pw_copy,&
      37             :                                               pw_derive,&
      38             :                                               pw_integral_a2b,&
      39             :                                               pw_multiply_with,&
      40             :                                               pw_transfer
      41             :    USE pw_poisson_methods,              ONLY: pw_poisson_rebuild,&
      42             :                                               pw_poisson_solve
      43             :    USE pw_poisson_types,                ONLY: greens_fn_type,&
      44             :                                               pw_poisson_type
      45             :    USE pw_pool_types,                   ONLY: pw_pool_type
      46             :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      47             :                                               pw_r3d_rs_type
      48             :    USE realspace_grid_types,            ONLY: realspace_grid_desc_type,&
      49             :                                               realspace_grid_type,&
      50             :                                               rs_grid_create,&
      51             :                                               rs_grid_release,&
      52             :                                               rs_grid_set_box,&
      53             :                                               rs_grid_zero,&
      54             :                                               transfer_pw2rs,&
      55             :                                               transfer_rs2pw
      56             :    USE shell_potential_types,           ONLY: shell_kind_type
      57             : #include "./base/base_uses.f90"
      58             : 
      59             :    IMPLICIT NONE
      60             : 
      61             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'spme'
      62             : 
      63             :    PRIVATE
      64             :    PUBLIC :: spme_evaluate, spme_potential, spme_forces, get_patch
      65             : 
      66             :    INTERFACE get_patch
      67             :       MODULE PROCEDURE get_patch_a, get_patch_b
      68             :    END INTERFACE
      69             : 
      70             : CONTAINS
      71             : 
      72             : ! **************************************************************************************************
      73             : !> \brief ...
      74             : !> \param ewald_env ...
      75             : !> \param ewald_pw ...
      76             : !> \param box ...
      77             : !> \param particle_set ...
      78             : !> \param fg_coulomb ...
      79             : !> \param vg_coulomb ...
      80             : !> \param pv_g ...
      81             : !> \param shell_particle_set ...
      82             : !> \param core_particle_set ...
      83             : !> \param fgshell_coulomb ...
      84             : !> \param fgcore_coulomb ...
      85             : !> \param use_virial ...
      86             : !> \param charges ...
      87             : !> \param atprop ...
      88             : !> \par History
      89             : !>      JGH (03-May-2001) : SPME with charge definition
      90             : !> \author JGH (21-Mar-2001)
      91             : ! **************************************************************************************************
      92       29484 :    SUBROUTINE spme_evaluate(ewald_env, ewald_pw, box, particle_set, &
      93       29484 :                             fg_coulomb, vg_coulomb, pv_g, shell_particle_set, core_particle_set, &
      94       29484 :                             fgshell_coulomb, fgcore_coulomb, use_virial, charges, atprop)
      95             : 
      96             :       TYPE(ewald_environment_type), POINTER              :: ewald_env
      97             :       TYPE(ewald_pw_type), POINTER                       :: ewald_pw
      98             :       TYPE(cell_type), POINTER                           :: box
      99             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: particle_set
     100             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT)        :: fg_coulomb
     101             :       REAL(KIND=dp), INTENT(OUT)                         :: vg_coulomb
     102             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT)        :: pv_g
     103             :       TYPE(particle_type), DIMENSION(:), OPTIONAL, &
     104             :          POINTER                                         :: shell_particle_set, core_particle_set
     105             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(OUT), &
     106             :          OPTIONAL                                        :: fgshell_coulomb, fgcore_coulomb
     107             :       LOGICAL, INTENT(IN)                                :: use_virial
     108             :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: charges
     109             :       TYPE(atprop_type), POINTER                         :: atprop
     110             : 
     111             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'spme_evaluate'
     112             : 
     113             :       INTEGER                                            :: handle, i, ig, ipart, j, n, ncore, &
     114             :                                                             npart, nshell, o_spline, p1, p1_shell
     115       58968 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: center, core_center, shell_center
     116             :       INTEGER, DIMENSION(3)                              :: nd, npts
     117             :       LOGICAL                                            :: do_shell
     118             :       REAL(KIND=dp)                                      :: alpha, dvols, fat1, ffa, ffb
     119       29484 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: core_delta, delta, shell_delta
     120             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: rhos
     121             :       REAL(KIND=dp), DIMENSION(3)                        :: fat
     122             :       REAL(KIND=dp), DIMENSION(3, 3)                     :: f_stress, h_stress
     123             :       TYPE(greens_fn_type), POINTER                      :: green
     124             :       TYPE(mp_comm_type)                                 :: group
     125      117936 :       TYPE(pw_c1d_gs_type), DIMENSION(3)                 :: dphi_g
     126             :       TYPE(pw_c1d_gs_type), POINTER                      :: phi_g, rhob_g
     127             :       TYPE(pw_grid_type), POINTER                        :: grid_spme
     128             :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     129             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     130             :       TYPE(pw_r3d_rs_type), POINTER                      :: rhob_r
     131             :       TYPE(realspace_grid_desc_type), POINTER            :: rs_desc
     132     1061424 :       TYPE(realspace_grid_type), DIMENSION(3)            :: drpot
     133             :       TYPE(realspace_grid_type), POINTER                 :: rden, rpot
     134             : 
     135       29484 :       NULLIFY (grid_spme, green, poisson_env, phi_g, rhob_g, rhob_r, pw_pool, rden, rpot)
     136       29484 :       CALL timeset(routineN, handle)
     137       29484 :       CALL cite_reference(Essmann1995)
     138             : 
     139             :       !-------------- INITIALISATION ---------------------
     140             :       CALL ewald_env_get(ewald_env, alpha=alpha, o_spline=o_spline, &
     141       29484 :                          group=group)
     142             :       CALL ewald_pw_get(ewald_pw, pw_big_pool=pw_pool, rs_desc=rs_desc, &
     143       29484 :                         poisson_env=poisson_env)
     144       29484 :       CALL pw_poisson_rebuild(poisson_env)
     145       29484 :       green => poisson_env%green_fft
     146       29484 :       grid_spme => pw_pool%pw_grid
     147             : 
     148       29484 :       npart = SIZE(particle_set)
     149             : 
     150       29484 :       CALL get_pw_grid_info(grid_spme, npts=npts, dvol=dvols)
     151             : 
     152       29484 :       n = o_spline
     153      147420 :       ALLOCATE (rhos(n, n, n))
     154      619164 :       ALLOCATE (rden)
     155       29484 :       CALL rs_grid_create(rden, rs_desc)
     156       29484 :       CALL rs_grid_set_box(grid_spme, rs=rden)
     157       29484 :       CALL rs_grid_zero(rden)
     158             : 
     159      147420 :       ALLOCATE (center(3, npart), delta(3, npart))
     160       29484 :       CALL get_center(particle_set, box, center, delta, npts, n)
     161             : 
     162       29484 :       IF (PRESENT(shell_particle_set) .AND. (PRESENT(core_particle_set))) THEN
     163        9438 :          CPASSERT(ASSOCIATED(shell_particle_set))
     164        9438 :          CPASSERT(ASSOCIATED(core_particle_set))
     165        9438 :          nshell = SIZE(shell_particle_set)
     166        9438 :          ncore = SIZE(core_particle_set)
     167        9438 :          CPASSERT(nshell == ncore)
     168       47190 :          ALLOCATE (shell_center(3, nshell), shell_delta(3, nshell))
     169        9438 :          CALL get_center(shell_particle_set, box, shell_center, shell_delta, npts, n)
     170       47190 :          ALLOCATE (core_center(3, nshell), core_delta(3, nshell))
     171        9438 :          CALL get_center(core_particle_set, box, core_center, core_delta, npts, n)
     172             :       END IF
     173             : 
     174             :       !-------------- DENSITY CALCULATION ----------------
     175       29484 :       ipart = 0
     176             :       ! Particles
     177             :       DO
     178     3601342 :          CALL set_list(particle_set, npart, center, p1, rden, ipart)
     179     3601342 :          IF (p1 == 0) EXIT
     180             : 
     181     3571858 :          do_shell = (particle_set(p1)%shell_index /= 0)
     182     3571858 :          IF (do_shell) CYCLE
     183             :          ! calculate function on small boxes
     184             :          CALL get_patch(particle_set, delta, green, p1, rhos, is_core=.FALSE., &
     185     3173285 :                         is_shell=.FALSE., unit_charge=.FALSE., charges=charges)
     186             : 
     187             :          ! add boxes to real space grid (big box)
     188     3601342 :          CALL dg_sum_patch(rden, rhos, center(:, p1))
     189             :       END DO
     190             :       ! Shell-Model
     191       29484 :       IF (PRESENT(shell_particle_set) .AND. PRESENT(core_particle_set)) THEN
     192        9438 :          ipart = 0
     193      425315 :          DO
     194             :             ! calculate function on small boxes
     195             :             CALL set_list(shell_particle_set, nshell, shell_center, p1_shell, &
     196      425315 :                           rden, ipart)
     197      425315 :             IF (p1_shell == 0) EXIT
     198             :             CALL get_patch(shell_particle_set, shell_delta, green, p1_shell, rhos, &
     199      415877 :                            is_core=.FALSE., is_shell=.TRUE., unit_charge=.FALSE.)
     200             : 
     201             :             ! add boxes to real space grid (big box)
     202      425315 :             CALL dg_sum_patch(rden, rhos, shell_center(:, p1_shell))
     203             :          END DO
     204        9438 :          ipart = 0
     205      425315 :          DO
     206             :             ! calculate function on small boxes
     207             :             CALL set_list(core_particle_set, nshell, core_center, p1_shell, &
     208      425315 :                           rden, ipart)
     209      425315 :             IF (p1_shell == 0) EXIT
     210             :             CALL get_patch(core_particle_set, core_delta, green, p1_shell, rhos, &
     211      415877 :                            is_core=.TRUE., is_shell=.FALSE., unit_charge=.FALSE.)
     212             : 
     213             :             ! add boxes to real space grid (big box)
     214      425315 :             CALL dg_sum_patch(rden, rhos, core_center(:, p1_shell))
     215             :          END DO
     216             :       END IF
     217             :       !----------- END OF DENSITY CALCULATION -------------
     218             : 
     219       29484 :       NULLIFY (rhob_r)
     220       29484 :       ALLOCATE (rhob_r)
     221       29484 :       CALL pw_pool%create_pw(rhob_r)
     222       29484 :       CALL transfer_rs2pw(rden, rhob_r)
     223             :       ! transform density to G space and add charge function
     224       29484 :       NULLIFY (rhob_g)
     225       29484 :       ALLOCATE (rhob_g)
     226       29484 :       CALL pw_pool%create_pw(rhob_g)
     227       29484 :       CALL pw_transfer(rhob_r, rhob_g)
     228             :       ! update charge function
     229       29484 :       CALL pw_multiply_with(rhob_g, green%p3m_charge)
     230             : 
     231             :       !-------------- ELECTROSTATIC CALCULATION -----------
     232             :       ! allocate intermediate arrays
     233      117936 :       DO i = 1, 3
     234      117936 :          CALL pw_pool%create_pw(dphi_g(i))
     235             :       END DO
     236       29484 :       NULLIFY (phi_g)
     237       29484 :       ALLOCATE (phi_g)
     238       29484 :       CALL pw_pool%create_pw(phi_g)
     239             :       CALL pw_poisson_solve(poisson_env, rhob_g, vg_coulomb, phi_g, dphi_g, &
     240       29484 :                             h_stress)
     241             :       !---------- END OF ELECTROSTATIC CALCULATION --------
     242             : 
     243             :       ! Atomic Energy and Stress
     244       29484 :       IF (atprop%energy .OR. atprop%stress) THEN
     245        4872 :          ALLOCATE (rpot)
     246         232 :          CALL rs_grid_create(rpot, rs_desc)
     247         232 :          CALL rs_grid_set_box(grid_spme, rs=rpot)
     248         232 :          CALL pw_multiply_with(phi_g, green%p3m_charge)
     249         232 :          CALL pw_transfer(phi_g, rhob_r)
     250         232 :          CALL transfer_pw2rs(rpot, rhob_r)
     251         232 :          ipart = 0
     252             :          DO
     253        2335 :             CALL set_list(particle_set, npart, center, p1, rden, ipart)
     254        2335 :             IF (p1 == 0) EXIT
     255        2103 :             do_shell = (particle_set(p1)%shell_index /= 0)
     256        2103 :             IF (do_shell) CYCLE
     257             :             ! calculate function on small boxes
     258             :             CALL get_patch(particle_set, delta, green, p1, rhos, is_core=.FALSE., &
     259        1743 :                            is_shell=.FALSE., unit_charge=.FALSE., charges=charges)
     260             :             ! integrate box and potential
     261        1023 :             CALL dg_sum_patch_force_1d(rpot, rhos, center(:, p1), fat1)
     262        1023 :             IF (atprop%energy) THEN
     263        1023 :                atprop%atener(p1) = atprop%atener(p1) + 0.5_dp*fat1*dvols
     264             :             END IF
     265        1255 :             IF (atprop%stress) THEN
     266         303 :                atprop%atstress(1, 1, p1) = atprop%atstress(1, 1, p1) + 0.5_dp*fat1*dvols
     267         303 :                atprop%atstress(2, 2, p1) = atprop%atstress(2, 2, p1) + 0.5_dp*fat1*dvols
     268         303 :                atprop%atstress(3, 3, p1) = atprop%atstress(3, 3, p1) + 0.5_dp*fat1*dvols
     269             :             END IF
     270             :          END DO
     271             :          ! Core-shell model
     272         232 :          IF (PRESENT(shell_particle_set) .AND. PRESENT(core_particle_set)) THEN
     273          30 :             ipart = 0
     274        1110 :             DO
     275        1110 :                CALL set_list(shell_particle_set, nshell, shell_center, p1_shell, rden, ipart)
     276        1110 :                IF (p1_shell == 0) EXIT
     277             :                CALL get_patch(shell_particle_set, shell_delta, green, p1_shell, rhos, &
     278        1080 :                               is_core=.FALSE., is_shell=.TRUE., unit_charge=.FALSE.)
     279        1080 :                CALL dg_sum_patch_force_1d(rpot, rhos, shell_center(:, p1_shell), fat1)
     280        1080 :                p1 = shell_particle_set(p1_shell)%atom_index
     281        1110 :                IF (atprop%energy) THEN
     282        1080 :                   atprop%atener(p1) = atprop%atener(p1) + 0.5_dp*fat1*dvols
     283             :                END IF
     284             :             END DO
     285          30 :             ipart = 0
     286        1110 :             DO
     287        1110 :                CALL set_list(core_particle_set, nshell, core_center, p1_shell, rden, ipart)
     288        1110 :                IF (p1_shell == 0) EXIT
     289             :                CALL get_patch(core_particle_set, core_delta, green, p1_shell, rhos, &
     290        1080 :                               is_core=.TRUE., is_shell=.FALSE., unit_charge=.FALSE.)
     291        1080 :                CALL dg_sum_patch_force_1d(rpot, rhos, core_center(:, p1_shell), fat1)
     292        1080 :                p1 = core_particle_set(p1_shell)%atom_index
     293        1110 :                IF (atprop%energy) THEN
     294        1080 :                   atprop%atener(p1) = atprop%atener(p1) + 0.5_dp*fat1*dvols
     295             :                END IF
     296             :             END DO
     297             :          END IF
     298         232 :          IF (atprop%stress) THEN
     299         202 :             ffa = (0.5_dp/alpha)**2
     300         202 :             ffb = 1.0_dp/fourpi
     301         808 :             DO i = 1, 3
     302      833250 :                DO ig = grid_spme%first_gne0, grid_spme%ngpts_cut_local
     303      832644 :                   phi_g%array(ig) = ffb*dphi_g(i)%array(ig)*(ffa*grid_spme%gsq(ig) + 1.0_dp)
     304      833250 :                   phi_g%array(ig) = phi_g%array(ig)*poisson_env%green_fft%influence_fn%array(ig)
     305             :                END DO
     306         606 :                IF (grid_spme%have_g0) phi_g%array(1) = 0.0_dp
     307        2020 :                DO j = 1, i
     308        1212 :                   nd = 0
     309        1212 :                   nd(j) = 1
     310        1212 :                   CALL pw_copy(phi_g, rhob_g)
     311        1212 :                   CALL pw_derive(rhob_g, nd)
     312        1212 :                   CALL pw_multiply_with(rhob_g, green%p3m_charge)
     313        1212 :                   CALL pw_transfer(rhob_g, rhob_r)
     314        1212 :                   CALL transfer_pw2rs(rpot, rhob_r)
     315             : 
     316        1212 :                   ipart = 0
     317         606 :                   DO
     318        3030 :                      CALL set_list(particle_set, npart, center, p1, rden, ipart)
     319        3030 :                      IF (p1 == 0) EXIT
     320             :                      ! calculate function on small boxes
     321             :                      CALL get_patch(particle_set, delta, green, p1, rhos, &
     322        1818 :                                     is_core=.FALSE., is_shell=.FALSE., unit_charge=.FALSE., charges=charges)
     323             :                      ! integrate box and potential
     324        1818 :                      CALL dg_sum_patch_force_1d(rpot, rhos, center(:, p1), fat1)
     325        1818 :                      atprop%atstress(i, j, p1) = atprop%atstress(i, j, p1) + fat1*dvols
     326        1818 :                      IF (i /= j) atprop%atstress(j, i, p1) = atprop%atstress(j, i, p1) + fat1*dvols
     327             :                   END DO
     328             : 
     329             :                END DO
     330             :             END DO
     331             :          END IF
     332         232 :          CALL rs_grid_release(rpot)
     333         232 :          DEALLOCATE (rpot)
     334             :       END IF
     335             : 
     336       29484 :       CALL pw_pool%give_back_pw(phi_g)
     337       29484 :       CALL pw_pool%give_back_pw(rhob_g)
     338       29484 :       DEALLOCATE (phi_g, rhob_g)
     339             : 
     340             :       !------------- STRESS TENSOR CALCULATION ------------
     341       29484 :       IF (use_virial) THEN
     342       53744 :          DO i = 1, 3
     343      134360 :             DO j = i, 3
     344       80616 :                f_stress(i, j) = pw_integral_a2b(dphi_g(i), dphi_g(j))
     345      120924 :                f_stress(j, i) = f_stress(i, j)
     346             :             END DO
     347             :          END DO
     348       13436 :          ffa = (1.0_dp/fourpi)*(0.5_dp/alpha)**2
     349      174668 :          f_stress = -ffa*f_stress
     350      174668 :          pv_g = h_stress + f_stress
     351             :       END IF
     352             :       !--------END OF STRESS TENSOR CALCULATION -----------
     353             :       ! move derivative of potential to real space grid and
     354             :       ! multiply by charge function in g-space
     355      117936 :       DO i = 1, 3
     356       88452 :          CALL rs_grid_create(drpot(i), rs_desc)
     357       88452 :          CALL rs_grid_set_box(grid_spme, rs=drpot(i))
     358       88452 :          CALL pw_multiply_with(dphi_g(i), green%p3m_charge)
     359       88452 :          CALL pw_transfer(dphi_g(i), rhob_r)
     360       88452 :          CALL pw_pool%give_back_pw(dphi_g(i))
     361      117936 :          CALL transfer_pw2rs(drpot(i), rhob_r)
     362             :       END DO
     363             : 
     364       29484 :       CALL pw_pool%give_back_pw(rhob_r)
     365       29484 :       DEALLOCATE (rhob_r)
     366             :       !----------------- FORCE CALCULATION ----------------
     367             :       ! initialize the forces
     368    25716268 :       fg_coulomb = 0.0_dp
     369             :       ! Particles
     370       29484 :       ipart = 0
     371             :       DO
     372     3601342 :          CALL set_list(particle_set, npart, center, p1, rden, ipart)
     373     3601342 :          IF (p1 == 0) EXIT
     374             : 
     375     3571858 :          do_shell = (particle_set(p1)%shell_index /= 0)
     376     3571858 :          IF (do_shell) CYCLE
     377             :          ! calculate function on small boxes
     378             :          CALL get_patch(particle_set, delta, green, p1, rhos, is_core=.FALSE., &
     379     3173285 :                         is_shell=.FALSE., unit_charge=.FALSE., charges=charges)
     380             : 
     381             :          ! add boxes to real space grid (big box)
     382     3155981 :          CALL dg_sum_patch_force_3d(drpot, rhos, center(:, p1), fat)
     383     3155981 :          fg_coulomb(1, p1) = fg_coulomb(1, p1) - fat(1)*dvols
     384     3155981 :          fg_coulomb(2, p1) = fg_coulomb(2, p1) - fat(2)*dvols
     385     3571858 :          fg_coulomb(3, p1) = fg_coulomb(3, p1) - fat(3)*dvols
     386             :       END DO
     387             :       ! Shell-Model
     388       29484 :       IF (PRESENT(shell_particle_set) .AND. (PRESENT(core_particle_set))) THEN
     389        9438 :          IF (PRESENT(fgshell_coulomb)) THEN
     390        9438 :             ipart = 0
     391     3058294 :             fgshell_coulomb = 0.0_dp
     392      425315 :             DO
     393             :                ! calculate function on small boxes
     394             :                CALL set_list(shell_particle_set, nshell, shell_center, p1_shell, &
     395      425315 :                              rden, ipart)
     396      425315 :                IF (p1_shell == 0) EXIT
     397             : 
     398             :                CALL get_patch(shell_particle_set, shell_delta, green, &
     399      415877 :                               p1_shell, rhos, is_core=.FALSE., is_shell=.TRUE., unit_charge=.FALSE.)
     400             : 
     401             :                ! add boxes to real space grid (big box)
     402      415877 :                CALL dg_sum_patch_force_3d(drpot, rhos, shell_center(:, p1_shell), fat)
     403      415877 :                fgshell_coulomb(1, p1_shell) = fgshell_coulomb(1, p1_shell) - fat(1)*dvols
     404      415877 :                fgshell_coulomb(2, p1_shell) = fgshell_coulomb(2, p1_shell) - fat(2)*dvols
     405      415877 :                fgshell_coulomb(3, p1_shell) = fgshell_coulomb(3, p1_shell) - fat(3)*dvols
     406             : 
     407             :             END DO
     408             :          END IF
     409        9438 :          IF (PRESENT(fgcore_coulomb)) THEN
     410        9438 :             ipart = 0
     411     3058294 :             fgcore_coulomb = 0.0_dp
     412      425315 :             DO
     413             :                ! calculate function on small boxes
     414             :                CALL set_list(core_particle_set, nshell, core_center, p1_shell, &
     415      425315 :                              rden, ipart)
     416      425315 :                IF (p1_shell == 0) EXIT
     417             : 
     418             :                CALL get_patch(core_particle_set, core_delta, green, &
     419      415877 :                               p1_shell, rhos, is_core=.TRUE., is_shell=.FALSE., unit_charge=.FALSE.)
     420             : 
     421             :                ! add boxes to real space grid (big box)
     422      415877 :                CALL dg_sum_patch_force_3d(drpot, rhos, core_center(:, p1_shell), fat)
     423      415877 :                fgcore_coulomb(1, p1_shell) = fgcore_coulomb(1, p1_shell) - fat(1)*dvols
     424      415877 :                fgcore_coulomb(2, p1_shell) = fgcore_coulomb(2, p1_shell) - fat(2)*dvols
     425      415877 :                fgcore_coulomb(3, p1_shell) = fgcore_coulomb(3, p1_shell) - fat(3)*dvols
     426             :             END DO
     427             :          END IF
     428             : 
     429             :       END IF
     430             :       !--------------END OF FORCE CALCULATION -------------
     431             : 
     432             :       !------------------CLEANING UP ----------------------
     433       29484 :       CALL rs_grid_release(rden)
     434       29484 :       DEALLOCATE (rden)
     435      117936 :       DO i = 1, 3
     436      117936 :          CALL rs_grid_release(drpot(i))
     437             :       END DO
     438             : 
     439       29484 :       DEALLOCATE (rhos)
     440       29484 :       DEALLOCATE (center, delta)
     441       29484 :       IF (ALLOCATED(shell_center)) THEN
     442        9438 :          DEALLOCATE (shell_center, shell_delta)
     443             :       END IF
     444       29484 :       IF (ALLOCATED(core_center)) THEN
     445        9438 :          DEALLOCATE (core_center, core_delta)
     446             :       END IF
     447       29484 :       CALL timestop(handle)
     448             : 
     449      117936 :    END SUBROUTINE spme_evaluate
     450             : 
     451             : ! **************************************************************************************************
     452             : !> \brief Calculate the electrostatic potential from particles A (charge A) at
     453             : !>        positions of particles B
     454             : !> \param ewald_env ...
     455             : !> \param ewald_pw ...
     456             : !> \param box ...
     457             : !> \param particle_set_a ...
     458             : !> \param charges_a ...
     459             : !> \param particle_set_b ...
     460             : !> \param potential ...
     461             : !> \par History
     462             : !>      JGH (23-Oct-2014) : adapted from SPME evaluate
     463             : !> \author JGH (23-Oct-2014)
     464             : ! **************************************************************************************************
     465        1368 :    SUBROUTINE spme_potential(ewald_env, ewald_pw, box, particle_set_a, charges_a, &
     466        1368 :                              particle_set_b, potential)
     467             : 
     468             :       TYPE(ewald_environment_type), POINTER              :: ewald_env
     469             :       TYPE(ewald_pw_type), POINTER                       :: ewald_pw
     470             :       TYPE(cell_type), POINTER                           :: box
     471             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: particle_set_a
     472             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges_a
     473             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: particle_set_b
     474             :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT)         :: potential
     475             : 
     476             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'spme_potential'
     477             : 
     478             :       INTEGER                                            :: handle, ipart, n, npart_a, npart_b, &
     479             :                                                             o_spline, p1
     480             :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: center
     481             :       INTEGER, DIMENSION(3)                              :: npts
     482             :       REAL(KIND=dp)                                      :: alpha, dvols, fat1
     483             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: delta
     484             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: rhos
     485             :       TYPE(greens_fn_type), POINTER                      :: green
     486             :       TYPE(mp_comm_type)                                 :: group
     487             :       TYPE(pw_c1d_gs_type), POINTER                      :: phi_g, rhob_g
     488             :       TYPE(pw_grid_type), POINTER                        :: grid_spme
     489             :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     490             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     491             :       TYPE(pw_r3d_rs_type), POINTER                      :: rhob_r
     492             :       TYPE(realspace_grid_desc_type), POINTER            :: rs_desc
     493             :       TYPE(realspace_grid_type), POINTER                 :: rden, rpot
     494             : 
     495        1368 :       NULLIFY (grid_spme, green, poisson_env, phi_g, rhob_g, rhob_r, pw_pool, &
     496        1368 :                rden, rpot)
     497        1368 :       CALL timeset(routineN, handle)
     498        1368 :       CALL cite_reference(Essmann1995)
     499             : 
     500             :       !-------------- INITIALISATION ---------------------
     501        1368 :       CALL ewald_env_get(ewald_env, alpha=alpha, o_spline=o_spline, group=group)
     502        1368 :       CALL ewald_pw_get(ewald_pw, pw_big_pool=pw_pool, rs_desc=rs_desc, poisson_env=poisson_env)
     503        1368 :       CALL pw_poisson_rebuild(poisson_env)
     504        1368 :       green => poisson_env%green_fft
     505        1368 :       grid_spme => pw_pool%pw_grid
     506             : 
     507        1368 :       npart_a = SIZE(particle_set_a)
     508        1368 :       npart_b = SIZE(particle_set_b)
     509             : 
     510        1368 :       CALL get_pw_grid_info(grid_spme, npts=npts, dvol=dvols)
     511             : 
     512        1368 :       n = o_spline
     513        6840 :       ALLOCATE (rhos(n, n, n))
     514       28728 :       ALLOCATE (rden)
     515        1368 :       CALL rs_grid_create(rden, rs_desc)
     516        1368 :       CALL rs_grid_set_box(grid_spme, rs=rden)
     517        1368 :       CALL rs_grid_zero(rden)
     518             : 
     519        6840 :       ALLOCATE (center(3, npart_a), delta(3, npart_a))
     520        1368 :       CALL get_center(particle_set_a, box, center, delta, npts, n)
     521             : 
     522             :       !-------------- DENSITY CALCULATION ----------------
     523        1368 :       ipart = 0
     524             :       ! Particles
     525        2052 :       DO
     526        3420 :          CALL set_list(particle_set_a, npart_a, center, p1, rden, ipart)
     527        3420 :          IF (p1 == 0) EXIT
     528             : 
     529             :          ! calculate function on small boxes
     530        2052 :          CALL get_patch(particle_set_a, delta, green, p1, rhos, charges_a)
     531             : 
     532             :          ! add boxes to real space grid (big box)
     533        3420 :          CALL dg_sum_patch(rden, rhos, center(:, p1))
     534             :       END DO
     535        1368 :       DEALLOCATE (center, delta)
     536             :       !----------- END OF DENSITY CALCULATION -------------
     537             : 
     538        1368 :       NULLIFY (rhob_r)
     539        1368 :       ALLOCATE (rhob_r)
     540        1368 :       CALL pw_pool%create_pw(rhob_r)
     541        1368 :       CALL transfer_rs2pw(rden, rhob_r)
     542             :       ! transform density to G space and add charge function
     543        1368 :       NULLIFY (rhob_g)
     544        1368 :       ALLOCATE (rhob_g)
     545        1368 :       CALL pw_pool%create_pw(rhob_g)
     546        1368 :       CALL pw_transfer(rhob_r, rhob_g)
     547             :       ! update charge function
     548        1368 :       CALL pw_multiply_with(rhob_g, green%p3m_charge)
     549             : 
     550             :       !-------------- ELECTROSTATIC CALCULATION -----------
     551             :       ! allocate intermediate arrays
     552        1368 :       NULLIFY (phi_g)
     553        1368 :       ALLOCATE (phi_g)
     554        1368 :       CALL pw_pool%create_pw(phi_g)
     555        1368 :       CALL pw_poisson_solve(poisson_env, density=rhob_g, vhartree=phi_g)
     556             :       !---------- END OF ELECTROSTATIC CALCULATION --------
     557             : 
     558             :       !-------------- POTENTAIL AT ATOMIC POSITIONS -------
     559        6840 :       ALLOCATE (center(3, npart_b), delta(3, npart_b))
     560        1368 :       CALL get_center(particle_set_b, box, center, delta, npts, n)
     561        1368 :       rpot => rden
     562        1368 :       CALL pw_multiply_with(phi_g, green%p3m_charge)
     563        1368 :       CALL pw_transfer(phi_g, rhob_r)
     564        1368 :       CALL transfer_pw2rs(rpot, rhob_r)
     565        1368 :       ipart = 0
     566        2052 :       DO
     567        3420 :          CALL set_list(particle_set_b, npart_b, center, p1, rden, ipart)
     568        3420 :          IF (p1 == 0) EXIT
     569             :          ! calculate function on small boxes
     570             :          CALL get_patch(particle_set_b, delta, green, p1, rhos, &
     571        2052 :                         is_core=.FALSE., is_shell=.FALSE., unit_charge=.TRUE.)
     572             :          ! integrate box and potential
     573        2052 :          CALL dg_sum_patch_force_1d(rpot, rhos, center(:, p1), fat1)
     574        2052 :          potential(p1) = potential(p1) + fat1*dvols
     575             :       END DO
     576             : 
     577             :       !------------------CLEANING UP ----------------------
     578        1368 :       CALL pw_pool%give_back_pw(phi_g)
     579        1368 :       CALL pw_pool%give_back_pw(rhob_g)
     580        1368 :       CALL pw_pool%give_back_pw(rhob_r)
     581        1368 :       DEALLOCATE (phi_g, rhob_g, rhob_r)
     582        1368 :       CALL rs_grid_release(rden)
     583        1368 :       DEALLOCATE (rden)
     584             : 
     585        1368 :       DEALLOCATE (rhos)
     586        1368 :       DEALLOCATE (center, delta)
     587        1368 :       CALL timestop(handle)
     588             : 
     589        2736 :    END SUBROUTINE spme_potential
     590             : 
     591             : ! **************************************************************************************************
     592             : !> \brief Calculate the forces on particles B for the electrostatic interaction
     593             : !>        betrween particles A and B
     594             : !> \param ewald_env ...
     595             : !> \param ewald_pw ...
     596             : !> \param box ...
     597             : !> \param particle_set_a ...
     598             : !> \param charges_a ...
     599             : !> \param particle_set_b ...
     600             : !> \param charges_b ...
     601             : !> \param forces_b ...
     602             : !> \par History
     603             : !>      JGH (27-Oct-2014) : adapted from SPME evaluate
     604             : !> \author JGH (23-Oct-2014)
     605             : ! **************************************************************************************************
     606          72 :    SUBROUTINE spme_forces(ewald_env, ewald_pw, box, particle_set_a, charges_a, &
     607          72 :                           particle_set_b, charges_b, forces_b)
     608             : 
     609             :       TYPE(ewald_environment_type), POINTER              :: ewald_env
     610             :       TYPE(ewald_pw_type), POINTER                       :: ewald_pw
     611             :       TYPE(cell_type), POINTER                           :: box
     612             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: particle_set_a
     613             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges_a
     614             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: particle_set_b
     615             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges_b
     616             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: forces_b
     617             : 
     618             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'spme_forces'
     619             : 
     620             :       INTEGER                                            :: handle, i, ipart, n, npart_a, npart_b, &
     621             :                                                             o_spline, p1
     622          72 :       INTEGER, ALLOCATABLE, DIMENSION(:, :)              :: center
     623             :       INTEGER, DIMENSION(3)                              :: npts
     624             :       REAL(KIND=dp)                                      :: alpha, dvols
     625          72 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: delta
     626             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: rhos
     627             :       REAL(KIND=dp), DIMENSION(3)                        :: fat
     628             :       TYPE(greens_fn_type), POINTER                      :: green
     629             :       TYPE(mp_comm_type)                                 :: group
     630         288 :       TYPE(pw_c1d_gs_type), DIMENSION(3)                 :: dphi_g
     631             :       TYPE(pw_c1d_gs_type), POINTER                      :: phi_g, rhob_g
     632             :       TYPE(pw_grid_type), POINTER                        :: grid_spme
     633             :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
     634             :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     635             :       TYPE(pw_r3d_rs_type), POINTER                      :: rhob_r
     636             :       TYPE(realspace_grid_desc_type), POINTER            :: rs_desc
     637        2592 :       TYPE(realspace_grid_type), DIMENSION(3)            :: drpot
     638             :       TYPE(realspace_grid_type), POINTER                 :: rden
     639             : 
     640          72 :       NULLIFY (grid_spme, green, poisson_env, phi_g, rhob_g, rhob_r, &
     641          72 :                pw_pool, rden)
     642          72 :       CALL timeset(routineN, handle)
     643          72 :       CALL cite_reference(Essmann1995)
     644             : 
     645             :       !-------------- INITIALISATION ---------------------
     646          72 :       CALL ewald_env_get(ewald_env, alpha=alpha, o_spline=o_spline, group=group)
     647          72 :       CALL ewald_pw_get(ewald_pw, pw_big_pool=pw_pool, rs_desc=rs_desc, poisson_env=poisson_env)
     648          72 :       CALL pw_poisson_rebuild(poisson_env)
     649          72 :       green => poisson_env%green_fft
     650          72 :       grid_spme => pw_pool%pw_grid
     651             : 
     652          72 :       npart_a = SIZE(particle_set_a)
     653          72 :       npart_b = SIZE(particle_set_b)
     654             : 
     655          72 :       CALL get_pw_grid_info(grid_spme, npts=npts, dvol=dvols)
     656             : 
     657          72 :       n = o_spline
     658         360 :       ALLOCATE (rhos(n, n, n))
     659        1512 :       ALLOCATE (rden)
     660          72 :       CALL rs_grid_create(rden, rs_desc)
     661          72 :       CALL rs_grid_set_box(grid_spme, rs=rden)
     662          72 :       CALL rs_grid_zero(rden)
     663             : 
     664         360 :       ALLOCATE (center(3, npart_a), delta(3, npart_a))
     665          72 :       CALL get_center(particle_set_a, box, center, delta, npts, n)
     666             : 
     667             :       !-------------- DENSITY CALCULATION ----------------
     668          72 :       ipart = 0
     669             :       ! Particles
     670         108 :       DO
     671         180 :          CALL set_list(particle_set_a, npart_a, center, p1, rden, ipart)
     672         180 :          IF (p1 == 0) EXIT
     673             : 
     674             :          ! calculate function on small boxes
     675         108 :          CALL get_patch(particle_set_a, delta, green, p1, rhos, charges_a)
     676             : 
     677             :          ! add boxes to real space grid (big box)
     678         180 :          CALL dg_sum_patch(rden, rhos, center(:, p1))
     679             :       END DO
     680          72 :       DEALLOCATE (center, delta)
     681             :       !----------- END OF DENSITY CALCULATION -------------
     682             : 
     683          72 :       NULLIFY (rhob_r)
     684          72 :       ALLOCATE (rhob_r)
     685          72 :       CALL pw_pool%create_pw(rhob_r)
     686          72 :       CALL transfer_rs2pw(rden, rhob_r)
     687             :       ! transform density to G space and add charge function
     688          72 :       NULLIFY (rhob_g)
     689          72 :       ALLOCATE (rhob_g)
     690          72 :       CALL pw_pool%create_pw(rhob_g)
     691          72 :       CALL pw_transfer(rhob_r, rhob_g)
     692             :       ! update charge function
     693          72 :       CALL pw_multiply_with(rhob_g, green%p3m_charge)
     694             : 
     695             :       !-------------- ELECTROSTATIC CALCULATION -----------
     696             :       ! allocate intermediate arrays
     697         288 :       DO i = 1, 3
     698         288 :          CALL pw_pool%create_pw(dphi_g(i))
     699             :       END DO
     700          72 :       NULLIFY (phi_g)
     701          72 :       ALLOCATE (phi_g)
     702          72 :       CALL pw_pool%create_pw(phi_g)
     703             :       CALL pw_poisson_solve(poisson_env, density=rhob_g, vhartree=phi_g, &
     704          72 :                             dvhartree=dphi_g)
     705             :       !---------- END OF ELECTROSTATIC CALCULATION --------
     706             :       ! move derivative of potential to real space grid and
     707             :       ! multiply by charge function in g-space
     708         288 :       DO i = 1, 3
     709         216 :          CALL rs_grid_create(drpot(i), rs_desc)
     710         216 :          CALL rs_grid_set_box(grid_spme, rs=drpot(i))
     711         216 :          CALL pw_multiply_with(dphi_g(i), green%p3m_charge)
     712         216 :          CALL pw_transfer(dphi_g(i), rhob_r)
     713         216 :          CALL pw_pool%give_back_pw(dphi_g(i))
     714         288 :          CALL transfer_pw2rs(drpot(i), rhob_r)
     715             :       END DO
     716             :       !----------------- FORCE CALCULATION ----------------
     717         360 :       ALLOCATE (center(3, npart_b), delta(3, npart_b))
     718          72 :       CALL get_center(particle_set_b, box, center, delta, npts, n)
     719          72 :       ipart = 0
     720         108 :       DO
     721         180 :          CALL set_list(particle_set_b, npart_b, center, p1, rden, ipart)
     722         180 :          IF (p1 == 0) EXIT
     723             :          ! calculate function on small boxes
     724             :          CALL get_patch(particle_set_b, delta, green, p1, rhos, &
     725         108 :                         is_core=.FALSE., is_shell=.FALSE., unit_charge=.FALSE., charges=charges_b)
     726             :          ! add boxes to real space grid (big box)
     727         108 :          CALL dg_sum_patch_force_3d(drpot, rhos, center(:, p1), fat)
     728         108 :          forces_b(1, p1) = forces_b(1, p1) - fat(1)*dvols
     729         108 :          forces_b(2, p1) = forces_b(2, p1) - fat(2)*dvols
     730         180 :          forces_b(3, p1) = forces_b(3, p1) - fat(3)*dvols
     731             :       END DO
     732             :       !------------------CLEANING UP ----------------------
     733         288 :       DO i = 1, 3
     734         288 :          CALL rs_grid_release(drpot(i))
     735             :       END DO
     736          72 :       CALL pw_pool%give_back_pw(phi_g)
     737          72 :       CALL pw_pool%give_back_pw(rhob_g)
     738          72 :       CALL pw_pool%give_back_pw(rhob_r)
     739          72 :       DEALLOCATE (phi_g, rhob_g, rhob_r)
     740          72 :       CALL rs_grid_release(rden)
     741          72 :       DEALLOCATE (rden)
     742             : 
     743          72 :       DEALLOCATE (rhos)
     744          72 :       DEALLOCATE (center, delta)
     745          72 :       CALL timestop(handle)
     746             : 
     747        1008 :    END SUBROUTINE spme_forces
     748             : 
     749             : ! **************************************************************************************************
     750             : !> \brief Calculates local density in a small box
     751             : !> \param part ...
     752             : !> \param delta ...
     753             : !> \param green ...
     754             : !> \param p ...
     755             : !> \param rhos ...
     756             : !> \param is_core ...
     757             : !> \param is_shell ...
     758             : !> \param unit_charge ...
     759             : !> \param charges ...
     760             : !> \par History
     761             : !>      none
     762             : !> \author JGH (21-Mar-2001)
     763             : ! **************************************************************************************************
     764     8255657 :    SUBROUTINE get_patch_a(part, delta, green, p, rhos, is_core, is_shell, &
     765             :                           unit_charge, charges)
     766             : 
     767             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: part
     768             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: delta
     769             :       TYPE(greens_fn_type), INTENT(IN)                   :: green
     770             :       INTEGER, INTENT(IN)                                :: p
     771             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT)     :: rhos
     772             :       LOGICAL, INTENT(IN)                                :: is_core, is_shell, unit_charge
     773             :       REAL(KIND=dp), DIMENSION(:), OPTIONAL, POINTER     :: charges
     774             : 
     775             :       INTEGER                                            :: nbox
     776             :       LOGICAL                                            :: use_charge_array
     777             :       REAL(KIND=dp)                                      :: q
     778             :       REAL(KIND=dp), DIMENSION(3)                        :: r
     779             :       TYPE(shell_kind_type), POINTER                     :: shell
     780             : 
     781     8255657 :       NULLIFY (shell)
     782     8255657 :       use_charge_array = PRESENT(charges)
     783     8255657 :       IF (use_charge_array) use_charge_array = ASSOCIATED(charges)
     784     8255657 :       IF (is_core .AND. is_shell) THEN
     785           0 :          CPABORT("Shell-model: cannot be core and shell simultaneously")
     786             :       END IF
     787             : 
     788     8255657 :       nbox = SIZE(rhos, 1)
     789    33022628 :       r = part(p)%r
     790     8255657 :       q = 1.0_dp
     791     8255657 :       IF (.NOT. unit_charge) THEN
     792     7980579 :          IF (is_core) THEN
     793      832834 :             CALL get_atomic_kind(atomic_kind=part(p)%atomic_kind, shell=shell)
     794      832834 :             q = shell%charge_core
     795     7147745 :          ELSE IF (is_shell) THEN
     796      832834 :             CALL get_atomic_kind(atomic_kind=part(p)%atomic_kind, shell=shell)
     797      832834 :             q = shell%charge_shell
     798             :          ELSE
     799     6314911 :             CALL get_atomic_kind(atomic_kind=part(p)%atomic_kind, qeff=q)
     800             :          END IF
     801     7980579 :          IF (use_charge_array) q = charges(p)
     802             :       END IF
     803     8255657 :       CALL spme_get_patch(rhos, nbox, delta(:, p), q, green%p3m_coeff)
     804             : 
     805     8255657 :    END SUBROUTINE get_patch_a
     806             : 
     807             : ! **************************************************************************************************
     808             : !> \brief Calculates local density in a small box
     809             : !> \param part ...
     810             : !> \param delta ...
     811             : !> \param green ...
     812             : !> \param p ...
     813             : !> \param rhos ...
     814             : !> \param charges ...
     815             : !> \par History
     816             : !>      none
     817             : !> \author JGH (21-Mar-2001)
     818             : ! **************************************************************************************************
     819        2160 :    SUBROUTINE get_patch_b(part, delta, green, p, rhos, charges)
     820             : 
     821             :       TYPE(particle_type), DIMENSION(:), INTENT(IN)      :: part
     822             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: delta
     823             :       TYPE(greens_fn_type), INTENT(IN)                   :: green
     824             :       INTEGER, INTENT(IN)                                :: p
     825             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT)     :: rhos
     826             :       REAL(KIND=dp), DIMENSION(:), POINTER               :: charges
     827             : 
     828             :       INTEGER                                            :: nbox
     829             :       REAL(KIND=dp)                                      :: q
     830             :       REAL(KIND=dp), DIMENSION(3)                        :: r
     831             : 
     832        2160 :       nbox = SIZE(rhos, 1)
     833        8640 :       r = part(p)%r
     834        2160 :       q = charges(p)
     835        2160 :       CALL spme_get_patch(rhos, nbox, delta(:, p), q, green%p3m_coeff)
     836             : 
     837        2160 :    END SUBROUTINE get_patch_b
     838             : 
     839             : ! **************************************************************************************************
     840             : !> \brief Calculates SPME charge assignment
     841             : !> \param rhos ...
     842             : !> \param n ...
     843             : !> \param delta ...
     844             : !> \param q ...
     845             : !> \param coeff ...
     846             : !> \par History
     847             : !>      DG (29-Mar-2001) : code implemented
     848             : !> \author JGH (22-Mar-2001)
     849             : ! **************************************************************************************************
     850     8257817 :    SUBROUTINE spme_get_patch(rhos, n, delta, q, coeff)
     851             : 
     852             :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(OUT)     :: rhos
     853             :       INTEGER, INTENT(IN)                                :: n
     854             :       REAL(KIND=dp), DIMENSION(3), INTENT(IN)            :: delta
     855             :       REAL(KIND=dp), INTENT(IN)                          :: q
     856             :       REAL(KIND=dp), DIMENSION(-(n-1):n-1, 0:n-1), &
     857             :          INTENT(IN)                                      :: coeff
     858             : 
     859             :       INTEGER, PARAMETER                                 :: nmax = 12
     860             : 
     861             :       INTEGER                                            :: i, i1, i2, i3, j, l
     862             :       REAL(KIND=dp)                                      :: r2, r3
     863             :       REAL(KIND=dp), DIMENSION(3, -nmax:nmax)            :: w_assign
     864             :       REAL(KIND=dp), DIMENSION(3, 0:nmax-1)              :: deltal
     865             :       REAL(KIND=dp), DIMENSION(3, 1:nmax)                :: f_assign
     866             : 
     867     8257817 :       IF (n > nmax) THEN
     868           0 :          CPABORT("nmax value too small")
     869             :       END IF
     870             :       ! calculate the assignment function values and
     871             :       ! the charges on the grid (small box)
     872             : 
     873     8257817 :       deltal(1, 0) = 1.0_dp
     874     8257817 :       deltal(2, 0) = 1.0_dp
     875     8257817 :       deltal(3, 0) = 1.0_dp
     876    43605678 :       DO l = 1, n - 1
     877    35347861 :          deltal(1, l) = deltal(1, l - 1)*delta(1)
     878    35347861 :          deltal(2, l) = deltal(2, l - 1)*delta(2)
     879    43605678 :          deltal(3, l) = deltal(3, l - 1)*delta(3)
     880             :       END DO
     881             : 
     882     8257817 :       w_assign = 0.0_dp
     883    51863495 :       DO j = -(n - 1), n - 1, 2
     884   289915207 :          DO l = 0, n - 1
     885   238051712 :             w_assign(1, j) = w_assign(1, j) + coeff(j, l)*deltal(1, l)
     886   238051712 :             w_assign(2, j) = w_assign(2, j) + coeff(j, l)*deltal(2, l)
     887   281657390 :             w_assign(3, j) = w_assign(3, j) + coeff(j, l)*deltal(3, l)
     888             :          END DO
     889             :       END DO
     890    51863495 :       DO i = 1, n
     891    43605678 :          j = n + 1 - 2*i
     892    43605678 :          f_assign(1, i) = w_assign(1, j)
     893    43605678 :          f_assign(2, i) = w_assign(2, j)
     894    51863495 :          f_assign(3, i) = w_assign(3, j)
     895             :       END DO
     896             : 
     897    51863495 :       DO i3 = 1, n
     898    43605678 :          r3 = q*f_assign(3, i3)
     899   289915207 :          DO i2 = 1, n
     900   238051712 :             r2 = r3*f_assign(2, i2)
     901  1617325082 :             DO i1 = 1, n
     902  1573719404 :                rhos(i1, i2, i3) = r2*f_assign(1, i1)
     903             :             END DO
     904             :          END DO
     905             :       END DO
     906             : 
     907     8257817 :    END SUBROUTINE spme_get_patch
     908             : 
     909             : END MODULE spme
     910             : 

Generated by: LCOV version 1.15