LCOV - code coverage report
Current view: top level - src - cp_ddapc_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 92.9 % 448 416
Test Date: 2026-06-05 07:04:50 Functions: 100.0 % 10 10

            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 contains information regarding the decoupling/recoupling method of Bloechl
      10              : !> \author Teodoro Laino
      11              : ! **************************************************************************************************
      12              : MODULE cp_ddapc_methods
      13              :    USE cell_types,                      ONLY: cell_type
      14              :    USE cp_log_handling,                 ONLY: cp_logger_get_default_io_unit
      15              :    USE input_constants,                 ONLY: weight_type_mass,&
      16              :                                               weight_type_unit
      17              :    USE input_section_types,             ONLY: section_vals_type,&
      18              :                                               section_vals_val_get,&
      19              :                                               section_vals_val_set
      20              :    USE kahan_sum,                       ONLY: accurate_sum
      21              :    USE kinds,                           ONLY: dp
      22              :    USE mathconstants,                   ONLY: fourpi,&
      23              :                                               oorootpi,&
      24              :                                               pi,&
      25              :                                               twopi
      26              :    USE mathlib,                         ONLY: diamat_all,&
      27              :                                               invert_matrix
      28              :    USE message_passing,                 ONLY: mp_para_env_type
      29              :    USE particle_types,                  ONLY: particle_type
      30              :    USE pw_spline_utils,                 ONLY: Eval_Interp_Spl3_pbc
      31              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      32              :                                               pw_r3d_rs_type
      33              :    USE spherical_harmonics,             ONLY: legendre
      34              : #include "./base/base_uses.f90"
      35              : 
      36              :    IMPLICIT NONE
      37              :    PRIVATE
      38              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .FALSE.
      39              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_ddapc_methods'
      40              :    PUBLIC :: ddapc_eval_gfunc, &
      41              :              build_b_vector, &
      42              :              build_der_b_vector, &
      43              :              build_A_matrix, &
      44              :              build_der_A_matrix_rows, &
      45              :              prep_g_dot_rvec_sin_cos, &
      46              :              cleanup_g_dot_rvec_sin_cos, &
      47              :              ddapc_eval_AmI, &
      48              :              ewald_ddapc_pot, &
      49              :              solvation_ddapc_pot
      50              : 
      51              : CONTAINS
      52              : 
      53              : ! **************************************************************************************************
      54              : !> \brief ...
      55              : !> \param gfunc ...
      56              : !> \param w ...
      57              : !> \param gcut ...
      58              : !> \param rho_tot_g ...
      59              : !> \param radii ...
      60              : ! **************************************************************************************************
      61          274 :    SUBROUTINE ddapc_eval_gfunc(gfunc, w, gcut, rho_tot_g, radii)
      62              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gfunc
      63              :       REAL(kind=dp), DIMENSION(:), POINTER               :: w
      64              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
      65              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
      66              :       REAL(kind=dp), DIMENSION(:), POINTER               :: radii
      67              : 
      68              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ddapc_eval_gfunc'
      69              : 
      70              :       INTEGER                                            :: e_dim, handle, ig, igauss, s_dim
      71              :       REAL(KIND=dp)                                      :: g2, gcut2, rc, rc2
      72              : 
      73          274 :       CALL timeset(routineN, handle)
      74          274 :       gcut2 = gcut*gcut
      75              :       !
      76          274 :       s_dim = rho_tot_g%pw_grid%first_gne0
      77          274 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
      78         1096 :       ALLOCATE (gfunc(s_dim:e_dim, SIZE(radii)))
      79          822 :       ALLOCATE (w(s_dim:e_dim))
      80     66546619 :       gfunc = 0.0_dp
      81     22399623 :       w = 0.0_dp
      82         1048 :       DO igauss = 1, SIZE(radii)
      83          774 :          rc = radii(igauss)
      84          774 :          rc2 = rc*rc
      85       545002 :          DO ig = s_dim, e_dim
      86       544728 :             g2 = rho_tot_g%pw_grid%gsq(ig)
      87       544728 :             IF (g2 > gcut2) EXIT
      88       544728 :             gfunc(ig, igauss) = EXP(-g2*rc2/4.0_dp)
      89              :          END DO
      90              :       END DO
      91       182908 :       DO ig = s_dim, e_dim
      92       182908 :          g2 = rho_tot_g%pw_grid%gsq(ig)
      93       182908 :          IF (g2 > gcut2) EXIT
      94       182908 :          w(ig) = fourpi*(g2 - gcut2)**2/(g2*gcut2)
      95              :       END DO
      96          274 :       CALL timestop(handle)
      97          274 :    END SUBROUTINE ddapc_eval_gfunc
      98              : 
      99              : ! **************************************************************************************************
     100              : !> \brief Computes the B vector for the solution of the linear system
     101              : !> \param bv ...
     102              : !> \param gfunc ...
     103              : !> \param w ...
     104              : !> \param particle_set ...
     105              : !> \param radii ...
     106              : !> \param rho_tot_g ...
     107              : !> \param gcut ...
     108              : !> \par History
     109              : !>      08.2005 created [tlaino]
     110              : !> \author Teodoro Laino
     111              : ! **************************************************************************************************
     112         2128 :    SUBROUTINE build_b_vector(bv, gfunc, w, particle_set, radii, rho_tot_g, gcut)
     113              :       REAL(KIND=dp), DIMENSION(:), INTENT(INOUT)         :: bv
     114              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gfunc
     115              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: w
     116              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     117              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     118              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
     119              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
     120              : 
     121              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'build_b_vector'
     122              : 
     123              :       COMPLEX(KIND=dp)                                   :: phase
     124              :       INTEGER                                            :: e_dim, handle, idim, ig, igauss, igmax, &
     125              :                                                             iparticle, s_dim
     126              :       REAL(KIND=dp)                                      :: arg, g2, gcut2, gvec(3), rvec(3)
     127         2128 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: my_bv, my_bvw
     128              : 
     129         2128 :       CALL timeset(routineN, handle)
     130         2128 :       NULLIFY (my_bv, my_bvw)
     131         2128 :       gcut2 = gcut*gcut
     132         2128 :       s_dim = rho_tot_g%pw_grid%first_gne0
     133         2128 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     134         2128 :       igmax = 0
     135       965836 :       DO ig = s_dim, e_dim
     136       965836 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     137       965836 :          IF (g2 > gcut2) EXIT
     138       965836 :          igmax = ig
     139              :       END DO
     140         2128 :       IF (igmax >= s_dim) THEN
     141         6384 :          ALLOCATE (my_bv(s_dim:igmax))
     142         4256 :          ALLOCATE (my_bvw(s_dim:igmax))
     143              :          !
     144         8212 :          DO iparticle = 1, SIZE(particle_set)
     145        24336 :             rvec = particle_set(iparticle)%r
     146      3337980 :             my_bv = 0.0_dp
     147      3337980 :             DO ig = s_dim, igmax
     148     13327584 :                gvec = rho_tot_g%pw_grid%g(:, ig)
     149     13327584 :                arg = DOT_PRODUCT(gvec, rvec)
     150      3331896 :                phase = CMPLX(COS(arg), -SIN(arg), KIND=dp)
     151      3337980 :                my_bv(ig) = w(ig)*REAL(CONJG(rho_tot_g%array(ig))*phase, KIND=dp)
     152              :             END DO
     153        24088 :             DO igauss = 1, SIZE(radii)
     154        15876 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     155      9811188 :                DO ig = s_dim, igmax
     156      9811188 :                   my_bvw(ig) = my_bv(ig)*gfunc(ig, igauss)
     157              :                END DO
     158        21960 :                bv(idim) = accurate_sum(my_bvw)
     159              :             END DO
     160              :          END DO
     161         2128 :          DEALLOCATE (my_bvw)
     162         2128 :          DEALLOCATE (my_bv)
     163              :       ELSE
     164            0 :          DO iparticle = 1, SIZE(particle_set)
     165            0 :             DO igauss = 1, SIZE(radii)
     166            0 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     167            0 :                bv(idim) = 0.0_dp
     168              :             END DO
     169              :          END DO
     170              :       END IF
     171         2128 :       CALL timestop(handle)
     172         2128 :    END SUBROUTINE build_b_vector
     173              : 
     174              : ! **************************************************************************************************
     175              : !> \brief Computes the A matrix for the solution of the linear system
     176              : !> \param Am ...
     177              : !> \param gfunc ...
     178              : !> \param w ...
     179              : !> \param particle_set ...
     180              : !> \param radii ...
     181              : !> \param rho_tot_g ...
     182              : !> \param gcut ...
     183              : !> \param g_dot_rvec_sin ...
     184              : !> \param g_dot_rvec_cos ...
     185              : !> \par History
     186              : !>      08.2005 created [tlaino]
     187              : !> \author Teodoro Laino
     188              : !> \note NB accept g_dot_rvec_* arrays
     189              : ! **************************************************************************************************
     190          274 :    SUBROUTINE build_A_matrix(Am, gfunc, w, particle_set, radii, rho_tot_g, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     191              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: Am
     192              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gfunc
     193              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: w
     194              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     195              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     196              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
     197              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
     198              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: g_dot_rvec_sin, g_dot_rvec_cos
     199              : 
     200              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'build_A_matrix'
     201              : 
     202              :       INTEGER                                            :: e_dim, handle, idim1, idim2, ig, &
     203              :                                                             igauss1, igauss2, igmax, iparticle1, &
     204              :                                                             iparticle2, istart_g, s_dim
     205              :       REAL(KIND=dp)                                      :: g2, gcut2, tmp
     206          274 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: my_Am, my_Amw
     207          274 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :)     :: gfunc_sq(:, :, :)
     208              : 
     209              : !NB precalculate as many things outside of the innermost loop as possible, in particular w(ig)*gfunc(ig,igauus1)*gfunc(ig,igauss2)
     210              : 
     211          274 :       CALL timeset(routineN, handle)
     212          274 :       gcut2 = gcut*gcut
     213          274 :       s_dim = rho_tot_g%pw_grid%first_gne0
     214          274 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     215          274 :       igmax = 0
     216       182908 :       DO ig = s_dim, e_dim
     217       182908 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     218       182908 :          IF (g2 > gcut2) EXIT
     219       182908 :          igmax = ig
     220              :       END DO
     221          274 :       IF (igmax >= s_dim) THEN
     222          822 :          ALLOCATE (my_Am(s_dim:igmax))
     223          548 :          ALLOCATE (my_Amw(s_dim:igmax))
     224         1370 :          ALLOCATE (gfunc_sq(s_dim:igmax, SIZE(radii), SIZE(radii)))
     225              : 
     226         1048 :          DO igauss1 = 1, SIZE(radii)
     227         3322 :             DO igauss2 = 1, SIZE(radii)
     228      1630962 :                gfunc_sq(s_dim:igmax, igauss1, igauss2) = w(s_dim:igmax)*gfunc(s_dim:igmax, igauss1)*gfunc(s_dim:igmax, igauss2)
     229              :             END DO
     230              :          END DO
     231              : 
     232         1100 :          DO iparticle1 = 1, SIZE(particle_set)
     233         4732 :             DO iparticle2 = iparticle1, SIZE(particle_set)
     234      6949714 :                DO ig = s_dim, igmax
     235              :                   !NB replace explicit dot product and cosine with cos(A+B) formula - much faster
     236              :                   my_Am(ig) = (g_dot_rvec_cos(ig - s_dim + 1, iparticle1)*g_dot_rvec_cos(ig - s_dim + 1, iparticle2) + &
     237      6949714 :                                g_dot_rvec_sin(ig - s_dim + 1, iparticle1)*g_dot_rvec_sin(ig - s_dim + 1, iparticle2))
     238              :                END DO
     239        15174 :                DO igauss1 = 1, SIZE(radii)
     240        10716 :                   idim1 = (iparticle1 - 1)*SIZE(radii) + igauss1
     241        10716 :                   istart_g = 1
     242        10716 :                   IF (iparticle2 == iparticle1) istart_g = igauss1
     243        44000 :                   DO igauss2 = istart_g, SIZE(radii)
     244        29652 :                      idim2 = (iparticle2 - 1)*SIZE(radii) + igauss2
     245     60291900 :                      my_Amw(s_dim:igmax) = my_Am(s_dim:igmax)*gfunc_sq(s_dim:igmax, igauss1, igauss2)
     246              :                      !NB no loss of accuracy in my test cases
     247              :                      !tmp = accurate_sum(my_Amw)
     248     60291900 :                      tmp = SUM(my_Amw)
     249        29652 :                      Am(idim2, idim1) = tmp
     250        40368 :                      Am(idim1, idim2) = tmp
     251              :                   END DO
     252              :                END DO
     253              :             END DO
     254              :          END DO
     255          274 :          DEALLOCATE (gfunc_sq)
     256          274 :          DEALLOCATE (my_Amw)
     257          274 :          DEALLOCATE (my_Am)
     258              :       END IF
     259          274 :       CALL timestop(handle)
     260          274 :    END SUBROUTINE build_A_matrix
     261              : 
     262              : ! **************************************************************************************************
     263              : !> \brief Computes the derivative of B vector for the evaluation of the Pulay forces
     264              : !> \param dbv ...
     265              : !> \param gfunc ...
     266              : !> \param w ...
     267              : !> \param particle_set ...
     268              : !> \param radii ...
     269              : !> \param rho_tot_g ...
     270              : !> \param gcut ...
     271              : !> \param iparticle0 ...
     272              : !> \par History
     273              : !>      08.2005 created [tlaino]
     274              : !> \author Teodoro Laino
     275              : ! **************************************************************************************************
     276          420 :    SUBROUTINE build_der_b_vector(dbv, gfunc, w, particle_set, radii, rho_tot_g, gcut, iparticle0)
     277              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(INOUT)      :: dbv
     278              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gfunc
     279              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: w
     280              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     281              :       REAL(KIND=dp), DIMENSION(:), INTENT(IN)            :: radii
     282              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
     283              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
     284              :       INTEGER, INTENT(IN)                                :: iparticle0
     285              : 
     286              :       CHARACTER(len=*), PARAMETER :: routineN = 'build_der_b_vector'
     287              : 
     288              :       COMPLEX(KIND=dp)                                   :: dphase
     289              :       INTEGER                                            :: e_dim, handle, idim, ig, igauss, igmax, &
     290              :                                                             iparticle, s_dim
     291              :       REAL(KIND=dp)                                      :: arg, g2, gcut2
     292          420 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: my_dbvw
     293          420 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: my_dbv
     294              :       REAL(KIND=dp), DIMENSION(3)                        :: gvec, rvec
     295              : 
     296          420 :       CALL timeset(routineN, handle)
     297          420 :       gcut2 = gcut*gcut
     298          420 :       s_dim = rho_tot_g%pw_grid%first_gne0
     299          420 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     300          420 :       igmax = 0
     301       360282 :       DO ig = s_dim, e_dim
     302       360282 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     303       360282 :          IF (g2 > gcut2) EXIT
     304       360282 :          igmax = ig
     305              :       END DO
     306          420 :       IF (igmax >= s_dim) THEN
     307         1260 :          ALLOCATE (my_dbv(3, s_dim:igmax))
     308         1260 :          ALLOCATE (my_dbvw(s_dim:igmax))
     309         1908 :          DO iparticle = 1, SIZE(particle_set)
     310         1488 :             IF (iparticle /= iparticle0) CYCLE
     311         1680 :             rvec = particle_set(iparticle)%r
     312       360282 :             DO ig = s_dim, igmax
     313      1439448 :                gvec = rho_tot_g%pw_grid%g(:, ig)
     314      1439448 :                arg = DOT_PRODUCT(gvec, rvec)
     315       359862 :                dphase = -CMPLX(SIN(arg), COS(arg), KIND=dp)
     316      1439868 :                my_dbv(:, ig) = w(ig)*REAL(CONJG(rho_tot_g%array(ig))*dphase, KIND=dp)*gvec(:)
     317              :             END DO
     318         3060 :             DO igauss = 1, SIZE(radii)
     319         1152 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     320      1071630 :                DO ig = s_dim, igmax
     321      1071630 :                   my_dbvw(ig) = my_dbv(1, ig)*gfunc(ig, igauss)
     322              :                END DO
     323         1152 :                dbv(idim, 1) = accurate_sum(my_dbvw)
     324      1071630 :                DO ig = s_dim, igmax
     325      1071630 :                   my_dbvw(ig) = my_dbv(2, ig)*gfunc(ig, igauss)
     326              :                END DO
     327         1152 :                dbv(idim, 2) = accurate_sum(my_dbvw)
     328      1071630 :                DO ig = s_dim, igmax
     329      1071630 :                   my_dbvw(ig) = my_dbv(3, ig)*gfunc(ig, igauss)
     330              :                END DO
     331         1572 :                dbv(idim, 3) = accurate_sum(my_dbvw)
     332              :             END DO
     333              :          END DO
     334          420 :          DEALLOCATE (my_dbvw)
     335          420 :          DEALLOCATE (my_dbv)
     336              :       ELSE
     337            0 :          DO iparticle = 1, SIZE(particle_set)
     338            0 :             IF (iparticle /= iparticle0) CYCLE
     339            0 :             DO igauss = 1, SIZE(radii)
     340            0 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     341            0 :                dbv(idim, 1:3) = 0.0_dp
     342              :             END DO
     343              :          END DO
     344              :       END IF
     345          420 :       CALL timestop(handle)
     346          420 :    END SUBROUTINE build_der_b_vector
     347              : 
     348              : ! **************************************************************************************************
     349              : !> \brief Computes the derivative of the A matrix for the evaluation of the
     350              : !>      Pulay forces
     351              : !> \param dAm ...
     352              : !> \param gfunc ...
     353              : !> \param w ...
     354              : !> \param particle_set ...
     355              : !> \param radii ...
     356              : !> \param rho_tot_g ...
     357              : !> \param gcut ...
     358              : !> \param iparticle0 ...
     359              : !> \param nparticles ...
     360              : !> \param g_dot_rvec_sin ...
     361              : !> \param g_dot_rvec_cos ...
     362              : !> \par History
     363              : !>      08.2005 created [tlaino]
     364              : !> \author Teodoro Laino
     365              : !> \note NB accept g_dot_rvec_* arrays
     366              : ! **************************************************************************************************
     367          444 :    SUBROUTINE build_der_A_matrix_rows(dAm, gfunc, w, particle_set, radii, &
     368          148 :                                       rho_tot_g, gcut, iparticle0, nparticles, g_dot_rvec_sin, g_dot_rvec_cos)
     369              :       REAL(KIND=dp), DIMENSION(:, :, :), INTENT(INOUT)   :: dAm
     370              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gfunc
     371              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: w
     372              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     373              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     374              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
     375              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
     376              :       INTEGER, INTENT(IN)                                :: iparticle0, nparticles
     377              :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: g_dot_rvec_sin, g_dot_rvec_cos
     378              : 
     379              :       CHARACTER(len=*), PARAMETER :: routineN = 'build_der_A_matrix_rows'
     380              : 
     381              :       INTEGER                                            :: e_dim, handle, ig, igauss2, igmax, &
     382              :                                                             iparticle1, iparticle2, s_dim
     383              :       REAL(KIND=dp)                                      :: g2, gcut2
     384              : 
     385              : !NB calculate derivatives for a block of particles, just the row parts (since derivative matrix is symmetric)
     386              : !NB Use DGEMM to speed up calculation, can't do accurate_sum() anymore because dgemm does the sum over g
     387              : 
     388              :       EXTERNAL DGEMM
     389          148 :       REAL(KIND=dp), ALLOCATABLE :: lhs(:, :), rhs(:, :)
     390              :       INTEGER :: Nr, Np, Ng, icomp, ipp
     391              : 
     392          148 :       CALL timeset(routineN, handle)
     393          148 :       gcut2 = gcut*gcut
     394          148 :       s_dim = rho_tot_g%pw_grid%first_gne0
     395          148 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     396          148 :       igmax = 0
     397       152182 :       DO ig = s_dim, e_dim
     398       152182 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     399       152182 :          IF (g2 > gcut2) EXIT
     400       152182 :          igmax = ig
     401              :       END DO
     402              : 
     403          148 :       Nr = SIZE(radii)
     404          148 :       Np = SIZE(particle_set)
     405          148 :       Ng = igmax - s_dim + 1
     406          148 :       IF (igmax >= s_dim) THEN
     407          592 :          ALLOCATE (lhs(nparticles*Nr, Ng))
     408          592 :          ALLOCATE (rhs(Ng, Np*Nr))
     409              : 
     410              :          ! rhs with first term of sin(g.(rvec1-rvec2))
     411              :          ! rhs has all parts that depend on iparticle2
     412          568 :          DO iparticle2 = 1, Np
     413         1720 :             DO igauss2 = 1, Nr
     414      1072050 :                rhs(1:Ng, (iparticle2 - 1)*Nr + igauss2) = g_dot_rvec_sin(1:Ng, iparticle2)*gfunc(s_dim:igmax, igauss2)
     415              :             END DO
     416              :          END DO
     417          592 :          DO icomp = 1, 3
     418              :             ! create lhs, which has all parts that depend on iparticle1
     419         1704 :             DO ipp = 1, nparticles
     420         1260 :                iparticle1 = iparticle0 + ipp - 1
     421      1081290 :                DO ig = s_dim, igmax
     422              :                   lhs((ipp - 1)*Nr + 1:(ipp - 1)*Nr + Nr, ig - s_dim + 1) = w(ig)*rho_tot_g%pw_grid%g(icomp, ig)* &
     423      4292280 :                                                                           gfunc(ig, 1:Nr)*g_dot_rvec_cos(ig - s_dim + 1, iparticle1)
     424              :                END DO
     425              :             END DO ! ipp
     426              :             ! do main multiply
     427              :             CALL DGEMM('N', 'N', nparticles*Nr, Np*Nr, Ng, 1.0D0, lhs(1, 1), nparticles*Nr, rhs(1, 1), &
     428          444 :                        Ng, 0.0D0, dAm((iparticle0 - 1)*Nr + 1, 1, icomp), Np*Nr)
     429              :             ! do extra multiplies to compensate for missing factor of 2
     430         1852 :             DO ipp = 1, nparticles
     431         1260 :                iparticle1 = iparticle0 + ipp - 1
     432              :                CALL DGEMM('N', 'N', Nr, Nr, Ng, 1.0D0, lhs((ipp - 1)*Nr + 1, 1), nparticles*Nr, rhs(1, (iparticle1 - 1)*Nr + 1), &
     433         1704 :                           Ng, 1.0D0, dAm((iparticle1 - 1)*Nr + 1, (iparticle1 - 1)*Nr + 1, icomp), Np*Nr)
     434              :             END DO
     435              :             ! now extra columns to account for factor of 2 in some rhs columns
     436              :          END DO ! icomp
     437              : 
     438              :          ! rhs with second term of sin(g.(rvec1-rvec2))
     439              :          ! rhs has all parts that depend on iparticle2
     440          568 :          DO iparticle2 = 1, Np
     441         1720 :             DO igauss2 = 1, Nr
     442      1072050 :                rhs(1:Ng, (iparticle2 - 1)*Nr + igauss2) = -g_dot_rvec_cos(1:Ng, iparticle2)*gfunc(s_dim:igmax, igauss2)
     443              :             END DO
     444              :          END DO
     445          592 :          DO icomp = 1, 3
     446              :             ! create lhs, which has all parts that depend on iparticle1
     447         1704 :             DO ipp = 1, nparticles
     448         1260 :                iparticle1 = iparticle0 + ipp - 1
     449      1081290 :                DO ig = s_dim, igmax
     450              :                   lhs((ipp - 1)*Nr + 1:(ipp - 1)*Nr + Nr, ig - s_dim + 1) = w(ig)*rho_tot_g%pw_grid%g(icomp, ig)*gfunc(ig, 1:Nr)* &
     451      4292280 :                                                                             g_dot_rvec_sin(ig - s_dim + 1, iparticle1)
     452              :                END DO
     453              :             END DO
     454              :             ! do main multiply
     455              :             CALL DGEMM('N', 'N', nparticles*Nr, Np*Nr, Ng, 1.0D0, lhs(1, 1), nparticles*Nr, rhs(1, 1), &
     456          444 :                        Ng, 1.0D0, dAm((iparticle0 - 1)*Nr + 1, 1, icomp), Np*Nr)
     457              :             ! do extra multiples to compensate for missing factor of 2
     458         1852 :             DO ipp = 1, nparticles
     459         1260 :                iparticle1 = iparticle0 + ipp - 1
     460              :                CALL DGEMM('N', 'N', Nr, Nr, Ng, 1.0D0, lhs((ipp - 1)*Nr + 1, 1), nparticles*Nr, rhs(1, (iparticle1 - 1)*Nr + 1), &
     461         1704 :                           Ng, 1.0D0, dAm((iparticle1 - 1)*Nr + 1, (iparticle1 - 1)*Nr + 1, icomp), Np*Nr)
     462              :             END DO
     463              :          END DO
     464              : 
     465          148 :          DEALLOCATE (rhs)
     466          148 :          DEALLOCATE (lhs)
     467              :       END IF
     468          148 :       CALL timestop(handle)
     469          148 :    END SUBROUTINE build_der_A_matrix_rows
     470              : 
     471              : ! **************************************************************************************************
     472              : !> \brief deallocate g_dot_rvec_* arrays
     473              : !> \param g_dot_rvec_sin ...
     474              : !> \param g_dot_rvec_cos ...
     475              : ! **************************************************************************************************
     476          422 :    SUBROUTINE cleanup_g_dot_rvec_sin_cos(g_dot_rvec_sin, g_dot_rvec_cos)
     477              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: g_dot_rvec_sin, g_dot_rvec_cos
     478              : 
     479          422 :       IF (ALLOCATED(g_dot_rvec_sin)) DEALLOCATE (g_dot_rvec_sin)
     480          422 :       IF (ALLOCATED(g_dot_rvec_cos)) DEALLOCATE (g_dot_rvec_cos)
     481          422 :    END SUBROUTINE cleanup_g_dot_rvec_sin_cos
     482              : 
     483              : ! **************************************************************************************************
     484              : !> \brief precompute sin(g.r) and cos(g.r) for quicker evaluations of sin(g.(r1-r2)) and cos(g.(r1-r2))
     485              : !> \param rho_tot_g ...
     486              : !> \param particle_set ...
     487              : !> \param gcut ...
     488              : !> \param g_dot_rvec_sin ...
     489              : !> \param g_dot_rvec_cos ...
     490              : ! **************************************************************************************************
     491          422 :    SUBROUTINE prep_g_dot_rvec_sin_cos(rho_tot_g, particle_set, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     492              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
     493              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     494              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
     495              :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: g_dot_rvec_sin, g_dot_rvec_cos
     496              : 
     497              :       INTEGER                                            :: e_dim, ig, igmax, iparticle, s_dim
     498              :       REAL(KIND=dp)                                      :: g2, g_dot_rvec, gcut2, rvec(3)
     499              : 
     500          422 :       gcut2 = gcut*gcut
     501          422 :       s_dim = rho_tot_g%pw_grid%first_gne0
     502          422 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     503          422 :       igmax = 0
     504       335090 :       DO ig = s_dim, e_dim
     505       335090 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     506       335090 :          IF (g2 > gcut2) EXIT
     507       335090 :          igmax = ig
     508              :       END DO
     509              : 
     510          422 :       IF (igmax >= s_dim) THEN
     511         1688 :          ALLOCATE (g_dot_rvec_sin(1:igmax - s_dim + 1, SIZE(particle_set)))
     512         1266 :          ALLOCATE (g_dot_rvec_cos(1:igmax - s_dim + 1, SIZE(particle_set)))
     513              : 
     514         1668 :          DO iparticle = 1, SIZE(particle_set)
     515         4984 :             rvec = particle_set(iparticle)%r
     516      1096274 :             DO ig = s_dim, igmax
     517      4378424 :                g_dot_rvec = DOT_PRODUCT(rho_tot_g%pw_grid%g(:, ig), rvec)
     518      1094606 :                g_dot_rvec_sin(ig - s_dim + 1, iparticle) = SIN(g_dot_rvec)
     519      1095852 :                g_dot_rvec_cos(ig - s_dim + 1, iparticle) = COS(g_dot_rvec)
     520              :             END DO
     521              :          END DO
     522              :       END IF
     523              : 
     524          422 :    END SUBROUTINE prep_g_dot_rvec_sin_cos
     525              : 
     526              : ! **************************************************************************************************
     527              : !> \brief Computes the inverse AmI of the Am matrix
     528              : !> \param GAmI ...
     529              : !> \param c0 ...
     530              : !> \param gfunc ...
     531              : !> \param w ...
     532              : !> \param particle_set ...
     533              : !> \param gcut ...
     534              : !> \param rho_tot_g ...
     535              : !> \param radii ...
     536              : !> \param iw ...
     537              : !> \param Vol ...
     538              : !> \par History
     539              : !>      12.2005 created [tlaino]
     540              : !> \author Teodoro Laino
     541              : ! **************************************************************************************************
     542          274 :    SUBROUTINE ddapc_eval_AmI(GAmI, c0, gfunc, w, particle_set, gcut, &
     543              :                              rho_tot_g, radii, iw, Vol)
     544              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: GAmI
     545              :       REAL(KIND=dp), INTENT(OUT)                         :: c0
     546              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: gfunc
     547              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: w
     548              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     549              :       REAL(KIND=dp), INTENT(IN)                          :: gcut
     550              :       TYPE(pw_c1d_gs_type), INTENT(IN)                   :: rho_tot_g
     551              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     552              :       INTEGER, INTENT(IN)                                :: iw
     553              :       REAL(KIND=dp), INTENT(IN)                          :: Vol
     554              : 
     555              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ddapc_eval_AmI'
     556              : 
     557              :       INTEGER                                            :: handle, ndim
     558              :       REAL(KIND=dp)                                      :: condition_number, inv_error
     559          274 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: AmE, cv
     560          274 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Am, AmI, Amw, g_dot_rvec_cos, &
     561          274 :                                                             g_dot_rvec_sin
     562              : 
     563              : !NB for precomputation of sin(g.r) and cos(g.r)
     564              : 
     565          274 :       CALL timeset(routineN, handle)
     566          274 :       ndim = SIZE(particle_set)*SIZE(radii)
     567         1096 :       ALLOCATE (Am(ndim, ndim))
     568          822 :       ALLOCATE (AmI(ndim, ndim))
     569          822 :       ALLOCATE (GAmI(ndim, ndim))
     570          822 :       ALLOCATE (cv(ndim))
     571          274 :       Am = 0.0_dp
     572          274 :       AmI = 0.0_dp
     573         2644 :       cv = 1.0_dp/Vol
     574              :       !NB precompute sin(g.r) and cos(g.r) for faster evaluation of cos(g.(r1-r2)) in build_A_matrix()
     575          274 :       CALL prep_g_dot_rvec_sin_cos(rho_tot_g, particle_set, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     576          274 :       CALL build_A_matrix(Am, gfunc, w, particle_set, radii, rho_tot_g, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     577          274 :       CALL cleanup_g_dot_rvec_sin_cos(g_dot_rvec_sin, g_dot_rvec_cos)
     578        59578 :       Am(:, :) = Am(:, :)/(Vol*Vol)
     579          274 :       CALL rho_tot_g%pw_grid%para%group%sum(Am)
     580          274 :       IF (iw > 0) THEN
     581              :          ! Checking conditions numbers and eigenvalues
     582            0 :          ALLOCATE (Amw(ndim, ndim))
     583            0 :          ALLOCATE (AmE(ndim))
     584            0 :          Amw(:, :) = Am
     585            0 :          CALL diamat_all(Amw, AmE)
     586            0 :          condition_number = MAXVAL(ABS(AmE))/MINVAL(ABS(AmE))
     587            0 :          WRITE (iw, '(T3,A)') " Eigenvalues of Matrix A:"
     588            0 :          WRITE (iw, '(T3,4E15.8)') AmE
     589            0 :          WRITE (iw, '(T3,A,1E15.9)') " Condition number:", condition_number
     590            0 :          IF (condition_number > 1.0E12_dp) THEN
     591              :             WRITE (iw, FMT="(/,T2,A)") &
     592            0 :                "WARNING: high condition number => possibly ill-conditioned matrix"
     593              :          END IF
     594            0 :          DEALLOCATE (Amw)
     595            0 :          DEALLOCATE (AmE)
     596              :       END IF
     597          274 :       CALL invert_matrix(Am, AmI, inv_error, "N", improve=.FALSE.)
     598          274 :       IF (iw > 0) THEN
     599            0 :          WRITE (iw, '(T3,A,F15.9)') " Error inverting the A matrix: ", inv_error
     600              :       END IF
     601       119430 :       c0 = DOT_PRODUCT(cv, MATMUL(AmI, cv))
     602          274 :       DEALLOCATE (Am)
     603          274 :       DEALLOCATE (cv)
     604        59578 :       GAmI = AmI
     605          274 :       DEALLOCATE (AmI)
     606          274 :       CALL timestop(handle)
     607          548 :    END SUBROUTINE ddapc_eval_AmI
     608              : 
     609              : ! **************************************************************************************************
     610              : !> \brief Evaluates the Ewald term E2 and E3 energy term for the decoupling/coupling
     611              : !>      of periodic images
     612              : !> \param cp_para_env ...
     613              : !> \param coeff ...
     614              : !> \param factor ...
     615              : !> \param cell ...
     616              : !> \param multipole_section ...
     617              : !> \param particle_set ...
     618              : !> \param M ...
     619              : !> \param radii ...
     620              : !> \par History
     621              : !>      08.2005 created [tlaino]
     622              : !> \author Teodoro Laino
     623              : !> \note NB receive cp_para_env for parallelization
     624              : ! **************************************************************************************************
     625          202 :    RECURSIVE SUBROUTINE ewald_ddapc_pot(cp_para_env, coeff, factor, cell, multipole_section, &
     626              :                                         particle_set, M, radii)
     627              :       TYPE(mp_para_env_type), INTENT(IN)                 :: cp_para_env
     628              :       TYPE(pw_r3d_rs_type), INTENT(IN), POINTER          :: coeff
     629              :       REAL(KIND=dp), INTENT(IN)                          :: factor
     630              :       TYPE(cell_type), POINTER                           :: cell
     631              :       TYPE(section_vals_type), POINTER                   :: multipole_section
     632              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     633              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: M
     634              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     635              : 
     636              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'ewald_ddapc_pot'
     637              : 
     638              :       INTEGER :: ewmdim, handle, iaxis, idim, idim1, idim2, idimo, igauss1, igauss2, ip1, ip2, &
     639              :          iparticle1, iparticle2, istart_g, k1, k2, k3, n_rep, ndim, r1, r2, r3
     640              :       INTEGER, DIMENSION(3)                              :: gmax, image_cell, rmax, rmin
     641              :       LOGICAL                                            :: analyt
     642              :       REAL(KIND=dp) :: alpha, eps, ew_neut, fac, fac3, frac_radius, fs, g_ewald, galpha, gsq, &
     643              :          gsqi, ij_fac, my_val, r, r2tmp, r_ewald, rc1, rc12, rc2, rc22, rcut, rcut2, t1, tol, tol1
     644              :       REAL(KIND=dp), DIMENSION(3)                        :: g_index, gvec, ra, rvec, svec
     645          202 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: EwM
     646              : 
     647          202 :       NULLIFY (EwM)
     648          202 :       CALL timeset(routineN, handle)
     649          202 :       CPASSERT(.NOT. ASSOCIATED(M))
     650          202 :       CPASSERT(ASSOCIATED(radii))
     651         2020 :       rcut = MIN(NORM2(cell%hmat(:, 1)), NORM2(cell%hmat(:, 2)), NORM2(cell%hmat(:, 3)))/2.0_dp
     652          202 :       CALL section_vals_val_get(multipole_section, "RCUT", n_rep_val=n_rep)
     653          202 :       IF (n_rep == 1) CALL section_vals_val_get(multipole_section, "RCUT", r_val=rcut)
     654          202 :       CALL section_vals_val_get(multipole_section, "EWALD_PRECISION", r_val=eps)
     655          202 :       CALL section_vals_val_get(multipole_section, "ANALYTICAL_GTERM", l_val=analyt)
     656              :       ! The spline interpolation path is only valid for orthorhombic grids.
     657          202 :       analyt = analyt .OR. .NOT. cell%orthorhombic .OR. .NOT. ASSOCIATED(coeff)
     658          202 :       rcut2 = rcut**2
     659              :       !
     660              :       ! Setting-up parameters for Ewald summation
     661              :       !
     662          202 :       eps = MIN(ABS(eps), 0.5_dp)
     663          202 :       tol = SQRT(ABS(LOG(eps*rcut)))
     664          202 :       alpha = SQRT(ABS(LOG(eps*rcut*tol)))/rcut
     665          202 :       galpha = 1.0_dp/(4.0_dp*alpha*alpha)
     666          202 :       tol1 = SQRT(-LOG(eps*rcut*(2.0_dp*tol*alpha)**2))
     667          202 :       IF (cell%orthorhombic) THEN
     668          768 :          DO iaxis = 1, 3
     669          768 :             gmax(iaxis) = NINT(0.25_dp + cell%hmat(iaxis, iaxis)*alpha*tol1/pi)
     670              :          END DO
     671              :       ELSE
     672           40 :          DO iaxis = 1, 3
     673          130 :             gmax(iaxis) = CEILING(alpha*tol1*NORM2(cell%hmat(:, iaxis))/pi)
     674              :          END DO
     675              :       END IF
     676          202 :       fac = 1.e0_dp/cell%deth
     677          202 :       fac3 = fac*pi
     678          202 :       ew_neut = -fac*pi/alpha**2
     679              :       !
     680          202 :       ewmdim = SIZE(particle_set)*(SIZE(particle_set) + 1)/2
     681          202 :       ndim = SIZE(particle_set)*SIZE(radii)
     682          606 :       ALLOCATE (EwM(ewmdim))
     683          808 :       ALLOCATE (M(ndim, ndim))
     684        90694 :       M = 0.0_dp
     685              :       !
     686         5460 :       idim = 0
     687         5460 :       EwM = 0.0_dp
     688          894 :       DO iparticle1 = 1, SIZE(particle_set)
     689         5950 :          ip1 = (iparticle1 - 1)*SIZE(radii)
     690         6152 :          DO iparticle2 = 1, iparticle1
     691         5258 :             ij_fac = 1.0_dp
     692         5258 :             IF (iparticle1 == iparticle2) ij_fac = 0.5_dp
     693              : 
     694         5258 :             ip2 = (iparticle2 - 1)*SIZE(radii)
     695         5258 :             idim = idim + 1
     696              :             !NB parallelization, done here so indexing is right
     697         5258 :             IF (MOD(iparticle1, cp_para_env%num_pe) /= cp_para_env%mepos) CYCLE
     698              :             !
     699              :             ! Real-Space Contribution
     700              :             !
     701         2653 :             my_val = 0.0_dp
     702        10612 :             rvec = particle_set(iparticle1)%r - particle_set(iparticle2)%r
     703         2653 :             r_ewald = 0.0_dp
     704         2653 :             IF (iparticle1 /= iparticle2) THEN
     705         2291 :                ra = rvec
     706         9164 :                r2tmp = DOT_PRODUCT(ra, ra)
     707         2291 :                IF (r2tmp <= rcut2) THEN
     708         2203 :                   r = SQRT(r2tmp)
     709         2203 :                   t1 = erfc(alpha*r)/r
     710         2203 :                   r_ewald = t1
     711              :                END IF
     712              :             END IF
     713        34489 :             svec = MATMUL(cell%h_inv, rvec)
     714        10612 :             DO iaxis = 1, 3
     715        31836 :                frac_radius = rcut*NORM2(cell%h_inv(iaxis, :))
     716         7959 :                rmin(iaxis) = FLOOR(-svec(iaxis) - frac_radius)
     717        10612 :                rmax(iaxis) = CEILING(-svec(iaxis) + frac_radius)
     718              :             END DO
     719        15985 :             DO r1 = rmin(1), rmax(1)
     720        86065 :                DO r2 = rmin(2), rmax(2)
     721       465868 :                   DO r3 = rmin(3), rmax(3)
     722       382456 :                      IF ((r1 == 0) .AND. (r2 == 0) .AND. (r3 == 0)) CYCLE
     723      1519212 :                      image_cell = [r1, r2, r3]
     724      7216257 :                      ra = rvec + MATMUL(cell%hmat, REAL(image_cell, KIND=dp))
     725      1519212 :                      r2tmp = DOT_PRODUCT(ra, ra)
     726       449883 :                      IF (r2tmp <= rcut2) THEN
     727        47717 :                         r = SQRT(r2tmp)
     728        47717 :                         t1 = erfc(alpha*r)/r
     729        47717 :                         r_ewald = r_ewald + t1*ij_fac
     730              :                      END IF
     731              :                   END DO
     732              :                END DO
     733              :             END DO
     734              :             !
     735              :             ! G-space Contribution
     736              :             !
     737         2653 :             IF (analyt) THEN
     738          278 :                g_ewald = 0.0_dp
     739         3535 :                DO k1 = 0, gmax(1)
     740        88788 :                   DO k2 = -gmax(2), gmax(2)
     741      2516283 :                      DO k3 = -gmax(3), gmax(3)
     742      2427773 :                         IF (k1 == 0 .AND. k2 == 0 .AND. k3 == 0) CYCLE
     743      2427495 :                         fs = 2.0_dp; IF (k1 == 0) fs = 1.0_dp
     744      9709980 :                         g_index = [REAL(k1, KIND=dp), REAL(k2, KIND=dp), REAL(k3, KIND=dp)]
     745     12137475 :                         gvec = twopi*MATMUL(TRANSPOSE(cell%h_inv), g_index)
     746      9709980 :                         gsq = DOT_PRODUCT(gvec, gvec)
     747      2427495 :                         gsqi = fs/gsq
     748      2427495 :                         t1 = fac*gsqi*EXP(-galpha*gsq)
     749      9795511 :                         g_ewald = g_ewald + t1*COS(DOT_PRODUCT(gvec, rvec))
     750              :                      END DO
     751              :                   END DO
     752              :                END DO
     753              :             ELSE
     754         2375 :                g_ewald = Eval_Interp_Spl3_pbc(rvec, coeff)
     755              :             END IF
     756              :             !
     757              :             ! G-EWALD, R-EWALD
     758              :             !
     759         2653 :             g_ewald = r_ewald + fourpi*g_ewald
     760              :             !
     761              :             ! Self Contribution
     762              :             !
     763         2653 :             IF (iparticle1 == iparticle2) THEN
     764          362 :                g_ewald = g_ewald - 2.0_dp*alpha*oorootpi
     765              :             END IF
     766              :             !
     767         2653 :             IF (iparticle1 /= iparticle2) THEN
     768         2291 :                ra = rvec
     769         9164 :                r = SQRT(DOT_PRODUCT(ra, ra))
     770         2291 :                my_val = factor/r
     771              :             END IF
     772         5950 :             EwM(idim) = my_val - factor*g_ewald
     773              :          END DO ! iparticle2
     774              :       END DO ! iparticle1
     775              :       !NB sum over parallelized contributions of different nodes
     776        10718 :       CALL cp_para_env%sum(EwM)
     777          202 :       idim = 0
     778          894 :       DO iparticle2 = 1, SIZE(particle_set)
     779          692 :          ip2 = (iparticle2 - 1)*SIZE(radii)
     780          692 :          idimo = (iparticle2 - 1)
     781          692 :          idimo = idimo*(idimo + 1)/2
     782         2970 :          DO igauss2 = 1, SIZE(radii)
     783         2076 :             idim2 = ip2 + igauss2
     784         2076 :             rc2 = radii(igauss2)
     785         2076 :             rc22 = rc2*rc2
     786        18542 :             DO iparticle1 = 1, iparticle2
     787        15774 :                ip1 = (iparticle1 - 1)*SIZE(radii)
     788        15774 :                idim = idimo + iparticle1
     789        15774 :                istart_g = 1
     790        15774 :                IF (iparticle1 == iparticle2) istart_g = igauss2
     791        63096 :                DO igauss1 = istart_g, SIZE(radii)
     792        45246 :                   idim1 = ip1 + igauss1
     793        45246 :                   rc1 = radii(igauss1)
     794        45246 :                   rc12 = rc1*rc1
     795        45246 :                   M(idim1, idim2) = EwM(idim) - factor*ew_neut - factor*fac3*(rc12 + rc22)
     796        61020 :                   M(idim2, idim1) = M(idim1, idim2)
     797              :                END DO
     798              :             END DO
     799              :          END DO ! iparticle2
     800              :       END DO ! iparticle1
     801          202 :       DEALLOCATE (EwM)
     802          202 :       CALL timestop(handle)
     803          606 :    END SUBROUTINE ewald_ddapc_pot
     804              : 
     805              : ! **************************************************************************************************
     806              : !> \brief Evaluates the electrostatic potential due to a simple solvation model
     807              : !>      Spherical cavity in a dieletric medium
     808              : !> \param solvation_section ...
     809              : !> \param particle_set ...
     810              : !> \param M ...
     811              : !> \param radii ...
     812              : !> \par History
     813              : !>      08.2006 created [tlaino]
     814              : !> \author Teodoro Laino
     815              : ! **************************************************************************************************
     816           26 :    SUBROUTINE solvation_ddapc_pot(solvation_section, particle_set, M, radii)
     817              :       TYPE(section_vals_type), POINTER                   :: solvation_section
     818              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     819              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: M
     820              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     821              : 
     822              :       INTEGER :: i, idim, idim1, idim2, igauss1, igauss2, ip1, ip2, iparticle1, iparticle2, &
     823              :          istart_g, j, l, lmax, n_rep1, n_rep2, ndim, output_unit, weight
     824           26 :       INTEGER, DIMENSION(:), POINTER                     :: list
     825              :       LOGICAL                                            :: fixed_center
     826              :       REAL(KIND=dp)                                      :: center(3), eps_in, eps_out, factor, &
     827              :                                                             mass, mycos, r1, r2, Rs, rvec(3)
     828           26 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: pos, R0
     829           26 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cost, LocP
     830              : 
     831           26 :       fixed_center = .FALSE.
     832           52 :       output_unit = cp_logger_get_default_io_unit()
     833           26 :       ndim = SIZE(particle_set)*SIZE(radii)
     834          104 :       ALLOCATE (M(ndim, ndim))
     835         1274 :       M = 0.0_dp
     836           26 :       eps_in = 1.0_dp
     837           26 :       CALL section_vals_val_get(solvation_section, "EPS_OUT", r_val=eps_out)
     838           26 :       CALL section_vals_val_get(solvation_section, "LMAX", i_val=lmax)
     839           26 :       CALL section_vals_val_get(solvation_section, "SPHERE%RADIUS", r_val=Rs)
     840           26 :       CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%XYZ", n_rep_val=n_rep1)
     841           26 :       IF (n_rep1 /= 0) THEN
     842           24 :          CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%XYZ", r_vals=R0)
     843           96 :          center = R0
     844              :       ELSE
     845              :          CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%ATOM_LIST", &
     846            2 :                                    n_rep_val=n_rep2)
     847            2 :          IF (n_rep2 /= 0) THEN
     848            2 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%ATOM_LIST", i_vals=list)
     849            2 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%WEIGHT_TYPE", i_val=weight)
     850            2 :             ALLOCATE (R0(3))
     851              :             SELECT CASE (weight)
     852              :             CASE (weight_type_unit)
     853            8 :                R0 = 0.0_dp
     854            4 :                DO i = 1, SIZE(list)
     855           10 :                   R0 = R0 + particle_set(list(i))%r
     856              :                END DO
     857            8 :                R0 = R0/REAL(SIZE(list), KIND=dp)
     858              :             CASE (weight_type_mass)
     859            0 :                R0 = 0.0_dp
     860            0 :                mass = 0.0_dp
     861            0 :                DO i = 1, SIZE(list)
     862            0 :                   R0 = R0 + particle_set(list(i))%r*particle_set(list(i))%atomic_kind%mass
     863            0 :                   mass = mass + particle_set(list(i))%atomic_kind%mass
     864              :                END DO
     865            2 :                R0 = R0/mass
     866              :             END SELECT
     867            8 :             center = R0
     868            2 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%FIXED", l_val=fixed_center)
     869            4 :             IF (fixed_center) THEN
     870              :                CALL section_vals_val_set(solvation_section, "SPHERE%CENTER%XYZ", &
     871            2 :                                          r_vals_ptr=R0)
     872              :             ELSE
     873            0 :                DEALLOCATE (R0)
     874              :             END IF
     875              :          END IF
     876              :       END IF
     877           26 :       CPASSERT(n_rep1 /= 0 .OR. n_rep2 /= 0)
     878              :       ! Potential calculation
     879          104 :       ALLOCATE (LocP(0:lmax, SIZE(particle_set)))
     880           78 :       ALLOCATE (pos(SIZE(particle_set)))
     881          104 :       ALLOCATE (cost(SIZE(particle_set), SIZE(particle_set)))
     882              :       ! Determining the single atomic contribution to the dielectric dipole
     883           76 :       DO i = 1, SIZE(particle_set)
     884          200 :          rvec = particle_set(i)%r - center
     885          200 :          r2 = DOT_PRODUCT(rvec, rvec)
     886           50 :          r1 = SQRT(r2)
     887           50 :          IF (r1 >= Rs) THEN
     888            0 :             IF (output_unit > 0) THEN
     889            0 :                WRITE (output_unit, '(A,I6,A)') "Atom number :: ", i, " is out of the solvation sphere"
     890            0 :                WRITE (output_unit, '(2(A,F12.6))') "Distance from the center::", r1, " Radius of the sphere::", rs
     891              :             END IF
     892            0 :             CPABORT("")
     893              :          END IF
     894          250 :          LocP(:, i) = 0.0_dp
     895           50 :          IF (r1 /= 0.0_dp) THEN
     896          230 :             DO l = 0, lmax
     897              :                LocP(l, i) = (r1**l*REAL(l + 1, KIND=dp)*(eps_in - eps_out))/ &
     898          230 :                             (Rs**(2*l + 1)*eps_in*(REAL(l, KIND=dp)*eps_in + REAL(l + 1, KIND=dp)*eps_out))
     899              :             END DO
     900              :          ELSE
     901              :             ! limit for r->0
     902            4 :             LocP(0, i) = (eps_in - eps_out)/(Rs*eps_in*eps_out)
     903              :          END IF
     904           76 :          pos(i) = r1
     905              :       END DO
     906              :       ! Particle-Particle potential energy matrix
     907          198 :       cost = 0.0_dp
     908           76 :       DO i = 1, SIZE(particle_set)
     909          162 :          DO j = 1, i
     910           86 :             factor = 0.0_dp
     911           86 :             IF (pos(i)*pos(j) /= 0.0_dp) THEN
     912          296 :                mycos = DOT_PRODUCT(particle_set(i)%r - center, particle_set(j)%r - center)/(pos(i)*pos(j))
     913           74 :                IF (ABS(mycos) > 1.0_dp) mycos = SIGN(1.0_dp, mycos)
     914          370 :                DO l = 0, lmax
     915          370 :                   factor = factor + LocP(l, i)*pos(j)**l*legendre(mycos, l, 0)
     916              :                END DO
     917              :             ELSE
     918           12 :                factor = LocP(0, i)
     919              :             END IF
     920           86 :             cost(i, j) = factor
     921          136 :             cost(j, i) = factor
     922              :          END DO
     923              :       END DO
     924              :       ! Computes the full potential energy matrix
     925           26 :       idim = 0
     926           76 :       DO iparticle2 = 1, SIZE(particle_set)
     927           50 :          ip2 = (iparticle2 - 1)*SIZE(radii)
     928          226 :          DO igauss2 = 1, SIZE(radii)
     929          150 :             idim2 = ip2 + igauss2
     930          458 :             DO iparticle1 = 1, iparticle2
     931          258 :                ip1 = (iparticle1 - 1)*SIZE(radii)
     932          258 :                istart_g = 1
     933          258 :                IF (iparticle1 == iparticle2) istart_g = igauss2
     934         1032 :                DO igauss1 = istart_g, SIZE(radii)
     935          624 :                   idim1 = ip1 + igauss1
     936          624 :                   M(idim1, idim2) = cost(iparticle1, iparticle2)
     937          882 :                   M(idim2, idim1) = M(idim1, idim2)
     938              :                END DO
     939              :             END DO
     940              :          END DO
     941              :       END DO
     942           26 :       DEALLOCATE (cost)
     943           26 :       DEALLOCATE (pos)
     944           26 :       DEALLOCATE (LocP)
     945           52 :    END SUBROUTINE solvation_ddapc_pot
     946              : 
     947          274 : END MODULE cp_ddapc_methods
        

Generated by: LCOV version 2.0-1