LCOV - code coverage report
Current view: top level - src - cp_ddapc_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 92.8 % 444 412
Test Date: 2025-12-04 06:27:48 Functions: 100.0 % 10 10

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 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          248 :    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          248 :       CALL timeset(routineN, handle)
      74          248 :       gcut2 = gcut*gcut
      75              :       !
      76          248 :       s_dim = rho_tot_g%pw_grid%first_gne0
      77          248 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
      78          992 :       ALLOCATE (gfunc(s_dim:e_dim, SIZE(radii)))
      79          744 :       ALLOCATE (w(s_dim:e_dim))
      80     55226642 :       gfunc = 0.0_dp
      81     18626306 :       w = 0.0_dp
      82          944 :       DO igauss = 1, SIZE(radii)
      83          696 :          rc = radii(igauss)
      84          696 :          rc2 = rc*rc
      85       522314 :          DO ig = s_dim, e_dim
      86       522066 :             g2 = rho_tot_g%pw_grid%gsq(ig)
      87       522066 :             IF (g2 > gcut2) EXIT
      88       522066 :             gfunc(ig, igauss) = EXP(-g2*rc2/4.0_dp)
      89              :          END DO
      90              :       END DO
      91       175354 :       DO ig = s_dim, e_dim
      92       175354 :          g2 = rho_tot_g%pw_grid%gsq(ig)
      93       175354 :          IF (g2 > gcut2) EXIT
      94       175354 :          w(ig) = fourpi*(g2 - gcut2)**2/(g2*gcut2)
      95              :       END DO
      96          248 :       CALL timestop(handle)
      97          248 :    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         1764 :    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         1764 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: my_bv, my_bvw
     128              : 
     129         1764 :       CALL timeset(routineN, handle)
     130         1764 :       NULLIFY (my_bv, my_bvw)
     131         1764 :       gcut2 = gcut*gcut
     132         1764 :       s_dim = rho_tot_g%pw_grid%first_gne0
     133         1764 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     134         1764 :       igmax = 0
     135       889452 :       DO ig = s_dim, e_dim
     136       889452 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     137       889452 :          IF (g2 > gcut2) EXIT
     138       889452 :          igmax = ig
     139              :       END DO
     140         1764 :       IF (igmax >= s_dim) THEN
     141         5292 :          ALLOCATE (my_bv(s_dim:igmax))
     142         3528 :          ALLOCATE (my_bvw(s_dim:igmax))
     143              :          !
     144         6776 :          DO iparticle = 1, SIZE(particle_set)
     145        20048 :             rvec = particle_set(iparticle)%r
     146      3105312 :             my_bv = 0.0_dp
     147      3105312 :             DO ig = s_dim, igmax
     148     12401200 :                gvec = rho_tot_g%pw_grid%g(:, ig)
     149     12401200 :                arg = DOT_PRODUCT(gvec, rvec)
     150      3100300 :                phase = CMPLX(COS(arg), -SIN(arg), KIND=dp)
     151      3105312 :                my_bv(ig) = w(ig)*REAL(CONJG(rho_tot_g%array(ig))*phase, KIND=dp)
     152              :             END DO
     153        19436 :             DO igauss = 1, SIZE(radii)
     154        12660 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     155      9113184 :                DO ig = s_dim, igmax
     156      9113184 :                   my_bvw(ig) = my_bv(ig)*gfunc(ig, igauss)
     157              :                END DO
     158        17672 :                bv(idim) = accurate_sum(my_bvw)
     159              :             END DO
     160              :          END DO
     161         1764 :          DEALLOCATE (my_bvw)
     162         1764 :          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         1764 :       CALL timestop(handle)
     172         1764 :    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          248 :    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          248 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: my_Am, my_Amw
     207          248 :       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          248 :       CALL timeset(routineN, handle)
     212          248 :       gcut2 = gcut*gcut
     213          248 :       s_dim = rho_tot_g%pw_grid%first_gne0
     214          248 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     215          248 :       igmax = 0
     216       175354 :       DO ig = s_dim, e_dim
     217       175354 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     218       175354 :          IF (g2 > gcut2) EXIT
     219       175354 :          igmax = ig
     220              :       END DO
     221          248 :       IF (igmax >= s_dim) THEN
     222          744 :          ALLOCATE (my_Am(s_dim:igmax))
     223          496 :          ALLOCATE (my_Amw(s_dim:igmax))
     224         1240 :          ALLOCATE (gfunc_sq(s_dim:igmax, SIZE(radii), SIZE(radii)))
     225              : 
     226          944 :          DO igauss1 = 1, SIZE(radii)
     227         2984 :             DO igauss2 = 1, SIZE(radii)
     228      1562898 :                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          998 :          DO iparticle1 = 1, SIZE(particle_set)
     233         4480 :             DO iparticle2 = iparticle1, SIZE(particle_set)
     234      6905002 :                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      6905002 :                                g_dot_rvec_sin(ig - s_dim + 1, iparticle1)*g_dot_rvec_sin(ig - s_dim + 1, iparticle2))
     238              :                END DO
     239        14498 :                DO igauss1 = 1, SIZE(radii)
     240        10266 :                   idim1 = (iparticle1 - 1)*SIZE(radii) + igauss1
     241        10266 :                   istart_g = 1
     242        10266 :                   IF (iparticle2 == iparticle1) istart_g = igauss1
     243        42278 :                   DO igauss2 = istart_g, SIZE(radii)
     244        28530 :                      idim2 = (iparticle2 - 1)*SIZE(radii) + igauss2
     245     59956866 :                      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     59956866 :                      tmp = SUM(my_Amw)
     249        28530 :                      Am(idim2, idim1) = tmp
     250        38796 :                      Am(idim1, idim2) = tmp
     251              :                   END DO
     252              :                END DO
     253              :             END DO
     254              :          END DO
     255          248 :          DEALLOCATE (gfunc_sq)
     256          248 :          DEALLOCATE (my_Amw)
     257          248 :          DEALLOCATE (my_Am)
     258              :       END IF
     259          248 :       CALL timestop(handle)
     260          248 :    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          396 :    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          396 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: my_dbvw
     293          396 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: my_dbv
     294              :       REAL(KIND=dp), DIMENSION(3)                        :: gvec, rvec
     295              : 
     296          396 :       CALL timeset(routineN, handle)
     297          396 :       gcut2 = gcut*gcut
     298          396 :       s_dim = rho_tot_g%pw_grid%first_gne0
     299          396 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     300          396 :       igmax = 0
     301       350556 :       DO ig = s_dim, e_dim
     302       350556 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     303       350556 :          IF (g2 > gcut2) EXIT
     304       350556 :          igmax = ig
     305              :       END DO
     306          396 :       IF (igmax >= s_dim) THEN
     307         1188 :          ALLOCATE (my_dbv(3, s_dim:igmax))
     308         1188 :          ALLOCATE (my_dbvw(s_dim:igmax))
     309         1812 :          DO iparticle = 1, SIZE(particle_set)
     310         1416 :             IF (iparticle /= iparticle0) CYCLE
     311         1584 :             rvec = particle_set(iparticle)%r
     312       350556 :             DO ig = s_dim, igmax
     313      1400640 :                gvec = rho_tot_g%pw_grid%g(:, ig)
     314      1400640 :                arg = DOT_PRODUCT(gvec, rvec)
     315       350160 :                dphase = -CMPLX(SIN(arg), COS(arg), KIND=dp)
     316      1401036 :                my_dbv(:, ig) = w(ig)*REAL(CONJG(rho_tot_g%array(ig))*dphase, KIND=dp)*gvec(:)
     317              :             END DO
     318         2892 :             DO igauss = 1, SIZE(radii)
     319         1080 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     320      1042452 :                DO ig = s_dim, igmax
     321      1042452 :                   my_dbvw(ig) = my_dbv(1, ig)*gfunc(ig, igauss)
     322              :                END DO
     323         1080 :                dbv(idim, 1) = accurate_sum(my_dbvw)
     324      1042452 :                DO ig = s_dim, igmax
     325      1042452 :                   my_dbvw(ig) = my_dbv(2, ig)*gfunc(ig, igauss)
     326              :                END DO
     327         1080 :                dbv(idim, 2) = accurate_sum(my_dbvw)
     328      1042452 :                DO ig = s_dim, igmax
     329      1042452 :                   my_dbvw(ig) = my_dbv(3, ig)*gfunc(ig, igauss)
     330              :                END DO
     331         1476 :                dbv(idim, 3) = accurate_sum(my_dbvw)
     332              :             END DO
     333              :          END DO
     334          396 :          DEALLOCATE (my_dbvw)
     335          396 :          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          396 :       CALL timestop(handle)
     346          396 :    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          420 :    SUBROUTINE build_der_A_matrix_rows(dAm, gfunc, w, particle_set, radii, &
     368          140 :                                       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          140 :       REAL(KIND=dp), ALLOCATABLE :: lhs(:, :), rhs(:, :)
     390              :       INTEGER :: Nr, Np, Ng, icomp, ipp
     391              : 
     392          140 :       CALL timeset(routineN, handle)
     393          140 :       gcut2 = gcut*gcut
     394          140 :       s_dim = rho_tot_g%pw_grid%first_gne0
     395          140 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     396          140 :       igmax = 0
     397       148940 :       DO ig = s_dim, e_dim
     398       148940 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     399       148940 :          IF (g2 > gcut2) EXIT
     400       148940 :          igmax = ig
     401              :       END DO
     402              : 
     403          140 :       Nr = SIZE(radii)
     404          140 :       Np = SIZE(particle_set)
     405          140 :       Ng = igmax - s_dim + 1
     406          140 :       IF (igmax >= s_dim) THEN
     407          560 :          ALLOCATE (lhs(nparticles*Nr, Ng))
     408          560 :          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          536 :          DO iparticle2 = 1, Np
     413         1616 :             DO igauss2 = 1, Nr
     414      1042848 :                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          560 :          DO icomp = 1, 3
     418              :             ! create lhs, which has all parts that depend on iparticle1
     419         1608 :             DO ipp = 1, nparticles
     420         1188 :                iparticle1 = iparticle0 + ipp - 1
     421      1052088 :                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      4175784 :                                                                           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          420 :                        Ng, 0.0D0, dAm((iparticle0 - 1)*Nr + 1, 1, icomp), Np*Nr)
     429              :             ! do extra multiplies to compensate for missing factor of 2
     430         1748 :             DO ipp = 1, nparticles
     431         1188 :                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         1608 :                           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          536 :          DO iparticle2 = 1, Np
     441         1616 :             DO igauss2 = 1, Nr
     442      1042848 :                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          560 :          DO icomp = 1, 3
     446              :             ! create lhs, which has all parts that depend on iparticle1
     447         1608 :             DO ipp = 1, nparticles
     448         1188 :                iparticle1 = iparticle0 + ipp - 1
     449      1052088 :                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      4175784 :                                                                             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          420 :                        Ng, 1.0D0, dAm((iparticle0 - 1)*Nr + 1, 1, icomp), Np*Nr)
     457              :             ! do extra multiples to compensate for missing factor of 2
     458         1748 :             DO ipp = 1, nparticles
     459         1188 :                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         1608 :                           Ng, 1.0D0, dAm((iparticle1 - 1)*Nr + 1, (iparticle1 - 1)*Nr + 1, icomp), Np*Nr)
     462              :             END DO
     463              :          END DO
     464              : 
     465          140 :          DEALLOCATE (rhs)
     466          140 :          DEALLOCATE (lhs)
     467              :       END IF
     468          140 :       CALL timestop(handle)
     469          140 :    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          388 :    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          388 :       IF (ALLOCATED(g_dot_rvec_sin)) DEALLOCATE (g_dot_rvec_sin)
     480          388 :       IF (ALLOCATED(g_dot_rvec_cos)) DEALLOCATE (g_dot_rvec_cos)
     481          388 :    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          388 :    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          388 :       gcut2 = gcut*gcut
     501          388 :       s_dim = rho_tot_g%pw_grid%first_gne0
     502          388 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     503          388 :       igmax = 0
     504       324294 :       DO ig = s_dim, e_dim
     505       324294 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     506       324294 :          IF (g2 > gcut2) EXIT
     507       324294 :          igmax = ig
     508              :       END DO
     509              : 
     510          388 :       IF (igmax >= s_dim) THEN
     511         1552 :          ALLOCATE (g_dot_rvec_sin(1:igmax - s_dim + 1, SIZE(particle_set)))
     512         1164 :          ALLOCATE (g_dot_rvec_cos(1:igmax - s_dim + 1, SIZE(particle_set)))
     513              : 
     514         1534 :          DO iparticle = 1, SIZE(particle_set)
     515         4584 :             rvec = particle_set(iparticle)%r
     516      1064056 :             DO ig = s_dim, igmax
     517      4250088 :                g_dot_rvec = DOT_PRODUCT(rho_tot_g%pw_grid%g(:, ig), rvec)
     518      1062522 :                g_dot_rvec_sin(ig - s_dim + 1, iparticle) = SIN(g_dot_rvec)
     519      1063668 :                g_dot_rvec_cos(ig - s_dim + 1, iparticle) = COS(g_dot_rvec)
     520              :             END DO
     521              :          END DO
     522              :       END IF
     523              : 
     524          388 :    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          248 :    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          248 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: AmE, cv
     560          248 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Am, AmI, Amw, g_dot_rvec_cos, &
     561          248 :                                                             g_dot_rvec_sin
     562              : 
     563              : !NB for precomputation of sin(g.r) and cos(g.r)
     564              : 
     565          248 :       CALL timeset(routineN, handle)
     566          248 :       ndim = SIZE(particle_set)*SIZE(radii)
     567          992 :       ALLOCATE (Am(ndim, ndim))
     568          744 :       ALLOCATE (AmI(ndim, ndim))
     569          744 :       ALLOCATE (GAmI(ndim, ndim))
     570          744 :       ALLOCATE (cv(ndim))
     571        57308 :       Am = 0.0_dp
     572        57308 :       AmI = 0.0_dp
     573         2390 :       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          248 :       CALL prep_g_dot_rvec_sin_cos(rho_tot_g, particle_set, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     576          248 :       CALL build_A_matrix(Am, gfunc, w, particle_set, radii, rho_tot_g, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     577          248 :       CALL cleanup_g_dot_rvec_sin_cos(g_dot_rvec_sin, g_dot_rvec_cos)
     578        57308 :       Am(:, :) = Am(:, :)/(Vol*Vol)
     579          248 :       CALL rho_tot_g%pw_grid%para%group%sum(Am)
     580          248 :       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          248 :       CALL invert_matrix(Am, AmI, inv_error, "N", improve=.FALSE.)
     598          248 :       IF (iw > 0) THEN
     599            0 :          WRITE (iw, '(T3,A,F15.9)') " Error inverting the A matrix: ", inv_error
     600              :       END IF
     601       117254 :       c0 = DOT_PRODUCT(cv, MATMUL(AmI, cv))
     602          248 :       DEALLOCATE (Am)
     603          248 :       DEALLOCATE (cv)
     604        57308 :       GAmI = AmI
     605          248 :       DEALLOCATE (AmI)
     606          248 :       CALL timestop(handle)
     607          496 :    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          176 :    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, idim, idim1, idim2, idimo, igauss1, igauss2, ip1, ip2, &
     639              :          iparticle1, iparticle2, istart_g, k1, k2, k3, n_rep, ndim, nmax1, nmax2, nmax3, r1, r2, &
     640              :          r3, rmax1, rmax2, rmax3
     641              :       LOGICAL                                            :: analyt
     642              :       REAL(KIND=dp) :: alpha, eps, ew_neut, fac, fac3, fs, g_ewald, galpha, gsq, gsqi, ij_fac, &
     643              :          my_val, r, r2tmp, r_ewald, rc1, rc12, rc2, rc22, rcut, rcut2, t1, tol, tol1
     644              :       REAL(KIND=dp), DIMENSION(3)                        :: fvec, gvec, ra, rvec
     645          176 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: EwM
     646              : 
     647          176 :       NULLIFY (EwM)
     648          176 :       CALL timeset(routineN, handle)
     649          176 :       CPASSERT(.NOT. ASSOCIATED(M))
     650          176 :       CPASSERT(ASSOCIATED(radii))
     651          176 :       CPASSERT(cell%orthorhombic)
     652          176 :       rcut = MIN(cell%hmat(1, 1), cell%hmat(2, 2), cell%hmat(3, 3))/2.0_dp
     653          176 :       CALL section_vals_val_get(multipole_section, "RCUT", n_rep_val=n_rep)
     654          176 :       IF (n_rep == 1) CALL section_vals_val_get(multipole_section, "RCUT", r_val=rcut)
     655          176 :       CALL section_vals_val_get(multipole_section, "EWALD_PRECISION", r_val=eps)
     656          176 :       CALL section_vals_val_get(multipole_section, "ANALYTICAL_GTERM", l_val=analyt)
     657          176 :       rcut2 = rcut**2
     658              :       !
     659              :       ! Setting-up parameters for Ewald summation
     660              :       !
     661          176 :       eps = MIN(ABS(eps), 0.5_dp)
     662          176 :       tol = SQRT(ABS(LOG(eps*rcut)))
     663          176 :       alpha = SQRT(ABS(LOG(eps*rcut*tol)))/rcut
     664          176 :       galpha = 1.0_dp/(4.0_dp*alpha*alpha)
     665          176 :       tol1 = SQRT(-LOG(eps*rcut*(2.0_dp*tol*alpha)**2))
     666          176 :       nmax1 = NINT(0.25_dp + cell%hmat(1, 1)*alpha*tol1/pi)
     667          176 :       nmax2 = NINT(0.25_dp + cell%hmat(2, 2)*alpha*tol1/pi)
     668          176 :       nmax3 = NINT(0.25_dp + cell%hmat(3, 3)*alpha*tol1/pi)
     669              : 
     670          176 :       rmax1 = CEILING(rcut/cell%hmat(1, 1))
     671          176 :       rmax2 = CEILING(rcut/cell%hmat(2, 2))
     672          176 :       rmax3 = CEILING(rcut/cell%hmat(3, 3))
     673          176 :       fac = 1.e0_dp/cell%deth
     674          176 :       fac3 = fac*pi
     675          704 :       fvec = twopi/[cell%hmat(1, 1), cell%hmat(2, 2), cell%hmat(3, 3)]
     676          176 :       ew_neut = -fac*pi/alpha**2
     677              :       !
     678          176 :       ewmdim = SIZE(particle_set)*(SIZE(particle_set) + 1)/2
     679          176 :       ndim = SIZE(particle_set)*SIZE(radii)
     680          528 :       ALLOCATE (EwM(ewmdim))
     681          704 :       ALLOCATE (M(ndim, ndim))
     682        88424 :       M = 0.0_dp
     683              :       !
     684         5284 :       idim = 0
     685         5284 :       EwM = 0.0_dp
     686          792 :       DO iparticle1 = 1, SIZE(particle_set)
     687         5724 :          ip1 = (iparticle1 - 1)*SIZE(radii)
     688         5900 :          DO iparticle2 = 1, iparticle1
     689         5108 :             ij_fac = 1.0_dp
     690         5108 :             IF (iparticle1 == iparticle2) ij_fac = 0.5_dp
     691              : 
     692         5108 :             ip2 = (iparticle2 - 1)*SIZE(radii)
     693         5108 :             idim = idim + 1
     694              :             !NB parallelization, done here so indexing is right
     695         5108 :             IF (MOD(iparticle1, cp_para_env%num_pe) /= cp_para_env%mepos) CYCLE
     696              :             !
     697              :             ! Real-Space Contribution
     698              :             !
     699         2578 :             my_val = 0.0_dp
     700        10312 :             rvec = particle_set(iparticle1)%r - particle_set(iparticle2)%r
     701         2578 :             r_ewald = 0.0_dp
     702         2578 :             IF (iparticle1 /= iparticle2) THEN
     703         2254 :                ra = rvec
     704         9016 :                r2tmp = DOT_PRODUCT(ra, ra)
     705         2254 :                IF (r2tmp <= rcut2) THEN
     706         2166 :                   r = SQRT(r2tmp)
     707         2166 :                   t1 = erfc(alpha*r)/r
     708         2166 :                   r_ewald = t1
     709              :                END IF
     710              :             END IF
     711        14682 :             DO r1 = -rmax1, rmax1
     712        73220 :                DO r2 = -rmax2, rmax2
     713       360498 :                   DO r3 = -rmax3, rmax3
     714       289856 :                      IF ((r1 == 0) .AND. (r2 == 0) .AND. (r3 == 0)) CYCLE
     715       287278 :                      ra(1) = rvec(1) + cell%hmat(1, 1)*r1
     716       287278 :                      ra(2) = rvec(2) + cell%hmat(2, 2)*r2
     717       287278 :                      ra(3) = rvec(3) + cell%hmat(3, 3)*r3
     718      1149112 :                      r2tmp = DOT_PRODUCT(ra, ra)
     719       345816 :                      IF (r2tmp <= rcut2) THEN
     720        47717 :                         r = SQRT(r2tmp)
     721        47717 :                         t1 = erfc(alpha*r)/r
     722        47717 :                         r_ewald = r_ewald + t1*ij_fac
     723              :                      END IF
     724              :                   END DO
     725              :                END DO
     726              :             END DO
     727              :             !
     728              :             ! G-space Contribution
     729              :             !
     730         2578 :             IF (analyt) THEN
     731              :                g_ewald = 0.0_dp
     732         2917 :                DO k1 = 0, nmax1
     733        74424 :                   DO k2 = -nmax2, nmax2
     734      2157813 :                      DO k3 = -nmax3, nmax3
     735      2083619 :                         IF (k1 == 0 .AND. k2 == 0 .AND. k3 == 0) CYCLE
     736      2083389 :                         fs = 2.0_dp; IF (k1 == 0) fs = 1.0_dp
     737      8333556 :                         gvec = fvec*[REAL(k1, KIND=dp), REAL(k2, KIND=dp), REAL(k3, KIND=dp)]
     738      8333556 :                         gsq = DOT_PRODUCT(gvec, gvec)
     739      2083389 :                         gsqi = fs/gsq
     740      2083389 :                         t1 = fac*gsqi*EXP(-galpha*gsq)
     741      8405293 :                         g_ewald = g_ewald + t1*COS(DOT_PRODUCT(gvec, rvec))
     742              :                      END DO
     743              :                   END DO
     744              :                END DO
     745              :             ELSE
     746         2348 :                g_ewald = Eval_Interp_Spl3_pbc(rvec, coeff)
     747              :             END IF
     748              :             !
     749              :             ! G-EWALD, R-EWALD
     750              :             !
     751         2578 :             g_ewald = r_ewald + fourpi*g_ewald
     752              :             !
     753              :             ! Self Contribution
     754              :             !
     755         2578 :             IF (iparticle1 == iparticle2) THEN
     756          324 :                g_ewald = g_ewald - 2.0_dp*alpha*oorootpi
     757              :             END IF
     758              :             !
     759         2578 :             IF (iparticle1 /= iparticle2) THEN
     760         2254 :                ra = rvec
     761         9016 :                r = SQRT(DOT_PRODUCT(ra, ra))
     762         2254 :                my_val = factor/r
     763              :             END IF
     764         5724 :             EwM(idim) = my_val - factor*g_ewald
     765              :          END DO ! iparticle2
     766              :       END DO ! iparticle1
     767              :       !NB sum over parallelized contributions of different nodes
     768        10392 :       CALL cp_para_env%sum(EwM)
     769          176 :       idim = 0
     770          792 :       DO iparticle2 = 1, SIZE(particle_set)
     771          616 :          ip2 = (iparticle2 - 1)*SIZE(radii)
     772          616 :          idimo = (iparticle2 - 1)
     773          616 :          idimo = idimo*(idimo + 1)/2
     774         2640 :          DO igauss2 = 1, SIZE(radii)
     775         1848 :             idim2 = ip2 + igauss2
     776         1848 :             rc2 = radii(igauss2)
     777         1848 :             rc22 = rc2*rc2
     778        17788 :             DO iparticle1 = 1, iparticle2
     779        15324 :                ip1 = (iparticle1 - 1)*SIZE(radii)
     780        15324 :                idim = idimo + iparticle1
     781        15324 :                istart_g = 1
     782        15324 :                IF (iparticle1 == iparticle2) istart_g = igauss2
     783        61296 :                DO igauss1 = istart_g, SIZE(radii)
     784        44124 :                   idim1 = ip1 + igauss1
     785        44124 :                   rc1 = radii(igauss1)
     786        44124 :                   rc12 = rc1*rc1
     787        44124 :                   M(idim1, idim2) = EwM(idim) - factor*ew_neut - factor*fac3*(rc12 + rc22)
     788        59448 :                   M(idim2, idim1) = M(idim1, idim2)
     789              :                END DO
     790              :             END DO
     791              :          END DO ! iparticle2
     792              :       END DO ! iparticle1
     793          176 :       DEALLOCATE (EwM)
     794          176 :       CALL timestop(handle)
     795          528 :    END SUBROUTINE ewald_ddapc_pot
     796              : 
     797              : ! **************************************************************************************************
     798              : !> \brief Evaluates the electrostatic potential due to a simple solvation model
     799              : !>      Spherical cavity in a dieletric medium
     800              : !> \param solvation_section ...
     801              : !> \param particle_set ...
     802              : !> \param M ...
     803              : !> \param radii ...
     804              : !> \par History
     805              : !>      08.2006 created [tlaino]
     806              : !> \author Teodoro Laino
     807              : ! **************************************************************************************************
     808           26 :    SUBROUTINE solvation_ddapc_pot(solvation_section, particle_set, M, radii)
     809              :       TYPE(section_vals_type), POINTER                   :: solvation_section
     810              :       TYPE(particle_type), DIMENSION(:), POINTER         :: particle_set
     811              :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: M
     812              :       REAL(KIND=dp), DIMENSION(:), POINTER               :: radii
     813              : 
     814              :       INTEGER :: i, idim, idim1, idim2, igauss1, igauss2, ip1, ip2, iparticle1, iparticle2, &
     815              :          istart_g, j, l, lmax, n_rep1, n_rep2, ndim, output_unit, weight
     816           26 :       INTEGER, DIMENSION(:), POINTER                     :: list
     817              :       LOGICAL                                            :: fixed_center
     818              :       REAL(KIND=dp)                                      :: center(3), eps_in, eps_out, factor, &
     819              :                                                             mass, mycos, r1, r2, Rs, rvec(3)
     820           26 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: pos, R0
     821           26 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: cost, LocP
     822              : 
     823           26 :       fixed_center = .FALSE.
     824           52 :       output_unit = cp_logger_get_default_io_unit()
     825           26 :       ndim = SIZE(particle_set)*SIZE(radii)
     826          104 :       ALLOCATE (M(ndim, ndim))
     827         1274 :       M = 0.0_dp
     828           26 :       eps_in = 1.0_dp
     829           26 :       CALL section_vals_val_get(solvation_section, "EPS_OUT", r_val=eps_out)
     830           26 :       CALL section_vals_val_get(solvation_section, "LMAX", i_val=lmax)
     831           26 :       CALL section_vals_val_get(solvation_section, "SPHERE%RADIUS", r_val=Rs)
     832           26 :       CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%XYZ", n_rep_val=n_rep1)
     833           26 :       IF (n_rep1 /= 0) THEN
     834           24 :          CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%XYZ", r_vals=R0)
     835           96 :          center = R0
     836              :       ELSE
     837              :          CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%ATOM_LIST", &
     838            2 :                                    n_rep_val=n_rep2)
     839            2 :          IF (n_rep2 /= 0) THEN
     840            2 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%ATOM_LIST", i_vals=list)
     841            2 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%WEIGHT_TYPE", i_val=weight)
     842            2 :             ALLOCATE (R0(3))
     843              :             SELECT CASE (weight)
     844              :             CASE (weight_type_unit)
     845            8 :                R0 = 0.0_dp
     846            4 :                DO i = 1, SIZE(list)
     847           10 :                   R0 = R0 + particle_set(list(i))%r
     848              :                END DO
     849            8 :                R0 = R0/REAL(SIZE(list), KIND=dp)
     850              :             CASE (weight_type_mass)
     851            0 :                R0 = 0.0_dp
     852            0 :                mass = 0.0_dp
     853            0 :                DO i = 1, SIZE(list)
     854            0 :                   R0 = R0 + particle_set(list(i))%r*particle_set(list(i))%atomic_kind%mass
     855            0 :                   mass = mass + particle_set(list(i))%atomic_kind%mass
     856              :                END DO
     857            2 :                R0 = R0/mass
     858              :             END SELECT
     859            8 :             center = R0
     860            2 :             CALL section_vals_val_get(solvation_section, "SPHERE%CENTER%FIXED", l_val=fixed_center)
     861            4 :             IF (fixed_center) THEN
     862              :                CALL section_vals_val_set(solvation_section, "SPHERE%CENTER%XYZ", &
     863            2 :                                          r_vals_ptr=R0)
     864              :             ELSE
     865            0 :                DEALLOCATE (R0)
     866              :             END IF
     867              :          END IF
     868              :       END IF
     869           26 :       CPASSERT(n_rep1 /= 0 .OR. n_rep2 /= 0)
     870              :       ! Potential calculation
     871          104 :       ALLOCATE (LocP(0:lmax, SIZE(particle_set)))
     872           78 :       ALLOCATE (pos(SIZE(particle_set)))
     873          104 :       ALLOCATE (cost(SIZE(particle_set), SIZE(particle_set)))
     874              :       ! Determining the single atomic contribution to the dielectric dipole
     875           76 :       DO i = 1, SIZE(particle_set)
     876          200 :          rvec = particle_set(i)%r - center
     877          200 :          r2 = DOT_PRODUCT(rvec, rvec)
     878           50 :          r1 = SQRT(r2)
     879           50 :          IF (r1 >= Rs) THEN
     880            0 :             IF (output_unit > 0) THEN
     881            0 :                WRITE (output_unit, '(A,I6,A)') "Atom number :: ", i, " is out of the solvation sphere"
     882            0 :                WRITE (output_unit, '(2(A,F12.6))') "Distance from the center::", r1, " Radius of the sphere::", rs
     883              :             END IF
     884            0 :             CPABORT("")
     885              :          END IF
     886          250 :          LocP(:, i) = 0.0_dp
     887           50 :          IF (r1 /= 0.0_dp) THEN
     888          230 :             DO l = 0, lmax
     889              :                LocP(l, i) = (r1**l*REAL(l + 1, KIND=dp)*(eps_in - eps_out))/ &
     890          230 :                             (Rs**(2*l + 1)*eps_in*(REAL(l, KIND=dp)*eps_in + REAL(l + 1, KIND=dp)*eps_out))
     891              :             END DO
     892              :          ELSE
     893              :             ! limit for r->0
     894            4 :             LocP(0, i) = (eps_in - eps_out)/(Rs*eps_in*eps_out)
     895              :          END IF
     896           76 :          pos(i) = r1
     897              :       END DO
     898              :       ! Particle-Particle potential energy matrix
     899          198 :       cost = 0.0_dp
     900           76 :       DO i = 1, SIZE(particle_set)
     901          162 :          DO j = 1, i
     902           86 :             factor = 0.0_dp
     903           86 :             IF (pos(i)*pos(j) /= 0.0_dp) THEN
     904          296 :                mycos = DOT_PRODUCT(particle_set(i)%r - center, particle_set(j)%r - center)/(pos(i)*pos(j))
     905           74 :                IF (ABS(mycos) > 1.0_dp) mycos = SIGN(1.0_dp, mycos)
     906          370 :                DO l = 0, lmax
     907          370 :                   factor = factor + LocP(l, i)*pos(j)**l*legendre(mycos, l, 0)
     908              :                END DO
     909              :             ELSE
     910           12 :                factor = LocP(0, i)
     911              :             END IF
     912           86 :             cost(i, j) = factor
     913          136 :             cost(j, i) = factor
     914              :          END DO
     915              :       END DO
     916              :       ! Computes the full potential energy matrix
     917           26 :       idim = 0
     918           76 :       DO iparticle2 = 1, SIZE(particle_set)
     919           50 :          ip2 = (iparticle2 - 1)*SIZE(radii)
     920          226 :          DO igauss2 = 1, SIZE(radii)
     921          150 :             idim2 = ip2 + igauss2
     922          458 :             DO iparticle1 = 1, iparticle2
     923          258 :                ip1 = (iparticle1 - 1)*SIZE(radii)
     924          258 :                istart_g = 1
     925          258 :                IF (iparticle1 == iparticle2) istart_g = igauss2
     926         1032 :                DO igauss1 = istart_g, SIZE(radii)
     927          624 :                   idim1 = ip1 + igauss1
     928          624 :                   M(idim1, idim2) = cost(iparticle1, iparticle2)
     929          882 :                   M(idim2, idim1) = M(idim1, idim2)
     930              :                END DO
     931              :             END DO
     932              :          END DO
     933              :       END DO
     934           26 :       DEALLOCATE (cost)
     935           26 :       DEALLOCATE (pos)
     936           26 :       DEALLOCATE (LocP)
     937           52 :    END SUBROUTINE solvation_ddapc_pot
     938              : 
     939          248 : END MODULE cp_ddapc_methods
        

Generated by: LCOV version 2.0-1