LCOV - code coverage report
Current view: top level - src - cp_ddapc_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 412 444 92.8 %
Date: 2024-12-21 06:28:57 Functions: 10 10 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief 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         246 :    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         246 :       CALL timeset(routineN, handle)
      74         246 :       gcut2 = gcut*gcut
      75             :       !
      76         246 :       s_dim = rho_tot_g%pw_grid%first_gne0
      77         246 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
      78         984 :       ALLOCATE (gfunc(s_dim:e_dim, SIZE(radii)))
      79         738 :       ALLOCATE (w(s_dim:e_dim))
      80    54440205 :       gfunc = 0.0_dp
      81    18364161 :       w = 0.0_dp
      82         936 :       DO igauss = 1, SIZE(radii)
      83         690 :          rc = radii(igauss)
      84         690 :          rc2 = rc*rc
      85      521214 :          DO ig = s_dim, e_dim
      86      520968 :             g2 = rho_tot_g%pw_grid%gsq(ig)
      87      520968 :             IF (g2 > gcut2) EXIT
      88      520968 :             gfunc(ig, igauss) = EXP(-g2*rc2/4.0_dp)
      89             :          END DO
      90             :       END DO
      91      174988 :       DO ig = s_dim, e_dim
      92      174988 :          g2 = rho_tot_g%pw_grid%gsq(ig)
      93      174988 :          IF (g2 > gcut2) EXIT
      94      174988 :          w(ig) = fourpi*(g2 - gcut2)**2/(g2*gcut2)
      95             :       END DO
      96         246 :       CALL timestop(handle)
      97         246 :    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        1342 :    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        1342 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: my_bv, my_bvw
     128             : 
     129        1342 :       CALL timeset(routineN, handle)
     130        1342 :       NULLIFY (my_bv, my_bvw)
     131        1342 :       gcut2 = gcut*gcut
     132        1342 :       s_dim = rho_tot_g%pw_grid%first_gne0
     133        1342 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     134        1342 :       igmax = 0
     135      821400 :       DO ig = s_dim, e_dim
     136      821400 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     137      821400 :          IF (g2 > gcut2) EXIT
     138      821400 :          igmax = ig
     139             :       END DO
     140        1342 :       IF (igmax .GE. s_dim) THEN
     141        4026 :          ALLOCATE (my_bv(s_dim:igmax))
     142        2684 :          ALLOCATE (my_bvw(s_dim:igmax))
     143             :          !
     144        5196 :          DO iparticle = 1, SIZE(particle_set)
     145       15416 :             rvec = particle_set(iparticle)%r
     146     2916828 :             my_bv = 0.0_dp
     147     2916828 :             DO ig = s_dim, igmax
     148    11651896 :                gvec = rho_tot_g%pw_grid%g(:, ig)
     149    11651896 :                arg = DOT_PRODUCT(gvec, rvec)
     150     2912974 :                phase = CMPLX(COS(arg), -SIN(arg), KIND=dp)
     151     2916828 :                my_bv(ig) = w(ig)*REAL(CONJG(rho_tot_g%array(ig))*phase, KIND=dp)
     152             :             END DO
     153       15354 :             DO igauss = 1, SIZE(radii)
     154       10158 :                idim = (iparticle - 1)*SIZE(radii) + igauss
     155     8630676 :                DO ig = s_dim, igmax
     156     8630676 :                   my_bvw(ig) = my_bv(ig)*gfunc(ig, igauss)
     157             :                END DO
     158       14012 :                bv(idim) = accurate_sum(my_bvw)
     159             :             END DO
     160             :          END DO
     161        1342 :          DEALLOCATE (my_bvw)
     162        1342 :          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        1342 :       CALL timestop(handle)
     172        1342 :    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         246 :    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         246 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: my_Am, my_Amw
     207         246 :       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         246 :       CALL timeset(routineN, handle)
     212         246 :       gcut2 = gcut*gcut
     213         246 :       s_dim = rho_tot_g%pw_grid%first_gne0
     214         246 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     215         246 :       igmax = 0
     216      174988 :       DO ig = s_dim, e_dim
     217      174988 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     218      174988 :          IF (g2 > gcut2) EXIT
     219      174988 :          igmax = ig
     220             :       END DO
     221         246 :       IF (igmax .GE. s_dim) THEN
     222         738 :          ALLOCATE (my_Am(s_dim:igmax))
     223         492 :          ALLOCATE (my_Amw(s_dim:igmax))
     224        1230 :          ALLOCATE (gfunc_sq(s_dim:igmax, SIZE(radii), SIZE(radii)))
     225             : 
     226         936 :          DO igauss1 = 1, SIZE(radii)
     227        2958 :             DO igauss2 = 1, SIZE(radii)
     228     1559598 :                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         992 :          DO iparticle1 = 1, SIZE(particle_set)
     233        4468 :             DO iparticle2 = iparticle1, SIZE(particle_set)
     234     6903904 :                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     6903904 :                                g_dot_rvec_sin(ig - s_dim + 1, iparticle1)*g_dot_rvec_sin(ig - s_dim + 1, iparticle2))
     238             :                END DO
     239       14470 :                DO igauss1 = 1, SIZE(radii)
     240       10248 :                   idim1 = (iparticle1 - 1)*SIZE(radii) + igauss1
     241       10248 :                   istart_g = 1
     242       10248 :                   IF (iparticle2 == iparticle1) istart_g = igauss1
     243       42212 :                   DO igauss2 = istart_g, SIZE(radii)
     244       28488 :                      idim2 = (iparticle2 - 1)*SIZE(radii) + igauss2
     245    59949180 :                      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    59949180 :                      tmp = SUM(my_Amw)
     249       28488 :                      Am(idim2, idim1) = tmp
     250       38736 :                      Am(idim1, idim2) = tmp
     251             :                   END DO
     252             :                END DO
     253             :             END DO
     254             :          END DO
     255         246 :          DEALLOCATE (gfunc_sq)
     256         246 :          DEALLOCATE (my_Amw)
     257         246 :          DEALLOCATE (my_Am)
     258             :       END IF
     259         246 :       CALL timestop(handle)
     260         246 :    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 .GE. 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 .GE. 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         386 :    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         386 :       IF (ALLOCATED(g_dot_rvec_sin)) DEALLOCATE (g_dot_rvec_sin)
     480         386 :       IF (ALLOCATED(g_dot_rvec_cos)) DEALLOCATE (g_dot_rvec_cos)
     481         386 :    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         386 :    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         386 :       gcut2 = gcut*gcut
     501         386 :       s_dim = rho_tot_g%pw_grid%first_gne0
     502         386 :       e_dim = rho_tot_g%pw_grid%ngpts_cut_local
     503         386 :       igmax = 0
     504      323928 :       DO ig = s_dim, e_dim
     505      323928 :          g2 = rho_tot_g%pw_grid%gsq(ig)
     506      323928 :          IF (g2 > gcut2) EXIT
     507      323928 :          igmax = ig
     508             :       END DO
     509             : 
     510         386 :       IF (igmax .GE. s_dim) THEN
     511        1544 :          ALLOCATE (g_dot_rvec_sin(1:igmax - s_dim + 1, SIZE(particle_set)))
     512        1158 :          ALLOCATE (g_dot_rvec_cos(1:igmax - s_dim + 1, SIZE(particle_set)))
     513             : 
     514        1528 :          DO iparticle = 1, SIZE(particle_set)
     515        4568 :             rvec = particle_set(iparticle)%r
     516     1063322 :             DO ig = s_dim, igmax
     517     4247176 :                g_dot_rvec = DOT_PRODUCT(rho_tot_g%pw_grid%g(:, ig), rvec)
     518     1061794 :                g_dot_rvec_sin(ig - s_dim + 1, iparticle) = SIN(g_dot_rvec)
     519     1062936 :                g_dot_rvec_cos(ig - s_dim + 1, iparticle) = COS(g_dot_rvec)
     520             :             END DO
     521             :          END DO
     522             :       END IF
     523             : 
     524         386 :    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         246 :    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         246 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: AmE, cv
     560         246 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :)        :: Am, AmI, Amw, g_dot_rvec_cos, &
     561         246 :                                                             g_dot_rvec_sin
     562             : 
     563             : !NB for precomputation of sin(g.r) and cos(g.r)
     564             : 
     565         246 :       CALL timeset(routineN, handle)
     566         246 :       ndim = SIZE(particle_set)*SIZE(radii)
     567         984 :       ALLOCATE (Am(ndim, ndim))
     568         738 :       ALLOCATE (AmI(ndim, ndim))
     569         738 :       ALLOCATE (GAmI(ndim, ndim))
     570         738 :       ALLOCATE (cv(ndim))
     571       57222 :       Am = 0.0_dp
     572       57222 :       AmI = 0.0_dp
     573        2376 :       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         246 :       CALL prep_g_dot_rvec_sin_cos(rho_tot_g, particle_set, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     576         246 :       CALL build_A_matrix(Am, gfunc, w, particle_set, radii, rho_tot_g, gcut, g_dot_rvec_sin, g_dot_rvec_cos)
     577         246 :       CALL cleanup_g_dot_rvec_sin_cos(g_dot_rvec_sin, g_dot_rvec_cos)
     578       57222 :       Am(:, :) = Am(:, :)/(Vol*Vol)
     579         246 :       CALL rho_tot_g%pw_grid%para%group%sum(Am)
     580         246 :       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         246 :       CALL invert_matrix(Am, AmI, inv_error, "N", improve=.FALSE.)
     598         246 :       IF (iw > 0) THEN
     599           0 :          WRITE (iw, '(T3,A,F15.9)') " Error inverting the A matrix: ", inv_error
     600             :       END IF
     601      117066 :       c0 = DOT_PRODUCT(cv, MATMUL(AmI, cv))
     602         246 :       DEALLOCATE (Am)
     603         246 :       DEALLOCATE (cv)
     604       57222 :       GAmI = AmI
     605         246 :       DEALLOCATE (AmI)
     606         246 :       CALL timestop(handle)
     607         492 :    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         174 :    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         174 :       REAL(KIND=dp), DIMENSION(:), POINTER               :: EwM
     646             : 
     647         174 :       NULLIFY (EwM)
     648         174 :       CALL timeset(routineN, handle)
     649         174 :       CPASSERT(.NOT. ASSOCIATED(M))
     650         174 :       CPASSERT(ASSOCIATED(radii))
     651         174 :       CPASSERT(cell%orthorhombic)
     652         174 :       rcut = MIN(cell%hmat(1, 1), cell%hmat(2, 2), cell%hmat(3, 3))/2.0_dp
     653         174 :       CALL section_vals_val_get(multipole_section, "RCUT", n_rep_val=n_rep)
     654         174 :       IF (n_rep == 1) CALL section_vals_val_get(multipole_section, "RCUT", r_val=rcut)
     655         174 :       CALL section_vals_val_get(multipole_section, "EWALD_PRECISION", r_val=eps)
     656         174 :       CALL section_vals_val_get(multipole_section, "ANALYTICAL_GTERM", l_val=analyt)
     657         174 :       rcut2 = rcut**2
     658             :       !
     659             :       ! Setting-up parameters for Ewald summation
     660             :       !
     661         174 :       eps = MIN(ABS(eps), 0.5_dp)
     662         174 :       tol = SQRT(ABS(LOG(eps*rcut)))
     663         174 :       alpha = SQRT(ABS(LOG(eps*rcut*tol)))/rcut
     664         174 :       galpha = 1.0_dp/(4.0_dp*alpha*alpha)
     665         174 :       tol1 = SQRT(-LOG(eps*rcut*(2.0_dp*tol*alpha)**2))
     666         174 :       nmax1 = NINT(0.25_dp + cell%hmat(1, 1)*alpha*tol1/pi)
     667         174 :       nmax2 = NINT(0.25_dp + cell%hmat(2, 2)*alpha*tol1/pi)
     668         174 :       nmax3 = NINT(0.25_dp + cell%hmat(3, 3)*alpha*tol1/pi)
     669             : 
     670         174 :       rmax1 = CEILING(rcut/cell%hmat(1, 1))
     671         174 :       rmax2 = CEILING(rcut/cell%hmat(2, 2))
     672         174 :       rmax3 = CEILING(rcut/cell%hmat(3, 3))
     673         174 :       fac = 1.e0_dp/cell%deth
     674         174 :       fac3 = fac*pi
     675         696 :       fvec = twopi/(/cell%hmat(1, 1), cell%hmat(2, 2), cell%hmat(3, 3)/)
     676         174 :       ew_neut = -fac*pi/alpha**2
     677             :       !
     678         174 :       ewmdim = SIZE(particle_set)*(SIZE(particle_set) + 1)/2
     679         174 :       ndim = SIZE(particle_set)*SIZE(radii)
     680         522 :       ALLOCATE (EwM(ewmdim))
     681         696 :       ALLOCATE (M(ndim, ndim))
     682       88338 :       M = 0.0_dp
     683             :       !
     684        5276 :       idim = 0
     685        5276 :       EwM = 0.0_dp
     686         786 :       DO iparticle1 = 1, SIZE(particle_set)
     687        5714 :          ip1 = (iparticle1 - 1)*SIZE(radii)
     688        5888 :          DO iparticle2 = 1, iparticle1
     689        5102 :             ij_fac = 1.0_dp
     690        5102 :             IF (iparticle1 == iparticle2) ij_fac = 0.5_dp
     691             : 
     692        5102 :             ip2 = (iparticle2 - 1)*SIZE(radii)
     693        5102 :             idim = idim + 1
     694             :             !NB parallelization, done here so indexing is right
     695        5102 :             IF (MOD(iparticle1, cp_para_env%num_pe) /= cp_para_env%mepos) CYCLE
     696             :             !
     697             :             ! Real-Space Contribution
     698             :             !
     699        2575 :             my_val = 0.0_dp
     700       10300 :             rvec = particle_set(iparticle1)%r - particle_set(iparticle2)%r
     701        2575 :             r_ewald = 0.0_dp
     702        2575 :             IF (iparticle1 /= iparticle2) THEN
     703        2253 :                ra = rvec
     704        9012 :                r2tmp = DOT_PRODUCT(ra, ra)
     705        2253 :                IF (r2tmp <= rcut2) THEN
     706        2165 :                   r = SQRT(r2tmp)
     707        2165 :                   t1 = erfc(alpha*r)/r
     708        2165 :                   r_ewald = t1
     709             :                END IF
     710             :             END IF
     711       14670 :             DO r1 = -rmax1, rmax1
     712       73181 :                DO r2 = -rmax2, rmax2
     713      360381 :                   DO r3 = -rmax3, rmax3
     714      289775 :                      IF ((r1 == 0) .AND. (r2 == 0) .AND. (r3 == 0)) CYCLE
     715      287200 :                      ra(1) = rvec(1) + cell%hmat(1, 1)*r1
     716      287200 :                      ra(2) = rvec(2) + cell%hmat(2, 2)*r2
     717      287200 :                      ra(3) = rvec(3) + cell%hmat(3, 3)*r3
     718     1148800 :                      r2tmp = DOT_PRODUCT(ra, ra)
     719      345711 :                      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        2575 :             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        2345 :                g_ewald = Eval_Interp_Spl3_pbc(rvec, coeff)
     747             :             END IF
     748             :             !
     749             :             ! G-EWALD, R-EWALD
     750             :             !
     751        2575 :             g_ewald = r_ewald + fourpi*g_ewald
     752             :             !
     753             :             ! Self Contribution
     754             :             !
     755        2575 :             IF (iparticle1 == iparticle2) THEN
     756         322 :                g_ewald = g_ewald - 2.0_dp*alpha*oorootpi
     757             :             END IF
     758             :             !
     759        2575 :             IF (iparticle1 /= iparticle2) THEN
     760        2253 :                ra = rvec
     761        9012 :                r = SQRT(DOT_PRODUCT(ra, ra))
     762        2253 :                my_val = factor/r
     763             :             END IF
     764        5714 :             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       10378 :       CALL cp_para_env%sum(EwM)
     769         174 :       idim = 0
     770         786 :       DO iparticle2 = 1, SIZE(particle_set)
     771         612 :          ip2 = (iparticle2 - 1)*SIZE(radii)
     772         612 :          idimo = (iparticle2 - 1)
     773         612 :          idimo = idimo*(idimo + 1)/2
     774        2622 :          DO igauss2 = 1, SIZE(radii)
     775        1836 :             idim2 = ip2 + igauss2
     776        1836 :             rc2 = radii(igauss2)
     777        1836 :             rc22 = rc2*rc2
     778       17754 :             DO iparticle1 = 1, iparticle2
     779       15306 :                ip1 = (iparticle1 - 1)*SIZE(radii)
     780       15306 :                idim = idimo + iparticle1
     781       15306 :                istart_g = 1
     782       15306 :                IF (iparticle1 == iparticle2) istart_g = igauss2
     783       61224 :                DO igauss1 = istart_g, SIZE(radii)
     784       44082 :                   idim1 = ip1 + igauss1
     785       44082 :                   rc1 = radii(igauss1)
     786       44082 :                   rc12 = rc1*rc1
     787       44082 :                   M(idim1, idim2) = EwM(idim) - factor*ew_neut - factor*fac3*(rc12 + rc22)
     788       59388 :                   M(idim2, idim1) = M(idim1, idim2)
     789             :                END DO
     790             :             END DO
     791             :          END DO ! iparticle2
     792             :       END DO ! iparticle1
     793         174 :       DEALLOCATE (EwM)
     794         174 :       CALL timestop(handle)
     795         522 :    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         246 : END MODULE cp_ddapc_methods

Generated by: LCOV version 1.15