LCOV - code coverage report
Current view: top level - src/pw - dielectric_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 88.1 % 303 267
Test Date: 2025-07-25 12:55:17 Functions: 81.8 % 11 9

            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 methods for evaluating the dielectric constant
      10              : !> \par History
      11              : !>       06.2014 created [Hossein Bani-Hashemian]
      12              : !> \author Mohammad Hossein Bani-Hashemian
      13              : ! **************************************************************************************************
      14              : MODULE dielectric_methods
      15              : 
      16              :    USE dct, ONLY: pw_expand
      17              :    USE dielectric_types, ONLY: &
      18              :       derivative_cd3, derivative_cd5, derivative_cd7, derivative_fft, derivative_fft_use_deps, &
      19              :       derivative_fft_use_drho, dielectric_parameters, dielectric_type, rho_dependent, &
      20              :       spatially_dependent, spatially_rho_dependent
      21              :    USE kinds, ONLY: dp
      22              :    USE mathconstants, ONLY: twopi
      23              :    USE pw_grid_types, ONLY: pw_grid_type
      24              :    USE pw_methods, ONLY: pw_axpy, &
      25              :                          pw_set, pw_copy, &
      26              :                          pw_derive, &
      27              :                          pw_transfer, &
      28              :                          pw_zero
      29              :    USE pw_pool_types, ONLY: pw_pool_create, &
      30              :                             pw_pool_release, &
      31              :                             pw_pool_type
      32              :    USE pw_types, ONLY: &
      33              :       pw_c1d_gs_type, &
      34              :       pw_r3d_rs_type
      35              :    USE realspace_grid_types, ONLY: realspace_grid_type
      36              :    USE rs_methods, ONLY: derive_fdm_cd3, &
      37              :                          derive_fdm_cd5, &
      38              :                          derive_fdm_cd7, &
      39              :                          pw_mollifier, &
      40              :                          setup_grid_axes
      41              : #include "../base/base_uses.f90"
      42              : 
      43              :    IMPLICIT NONE
      44              :    PRIVATE
      45              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'dielectric_methods'
      46              : 
      47              :    PUBLIC :: dielectric_create, dielectric_compute, derive_fft
      48              : 
      49              :    INTERFACE dielectric_compute
      50              :       MODULE PROCEDURE dielectric_compute_periodic_r3d_rs, &
      51              :          dielectric_compute_neumann_r3d_rs
      52              :       MODULE PROCEDURE dielectric_compute_periodic_c1d_gs, &
      53              :          dielectric_compute_neumann_c1d_gs
      54              :    END INTERFACE dielectric_compute
      55              : 
      56              : CONTAINS
      57              : 
      58              : ! **************************************************************************************************
      59              : !> \brief   allocates memory for a dielectric data type
      60              : !> \param dielectric  the dielectric data type to be allocated
      61              : !> \param pw_pool pool of pw grid
      62              : !> \param dielectric_params dielectric parameters read from input file
      63              : !> \par History
      64              : !>       06.2014 created [Hossein Bani-Hashemian]
      65              : !> \author Mohammad Hossein Bani-Hashemian
      66              : ! **************************************************************************************************
      67           54 :    SUBROUTINE dielectric_create(dielectric, pw_pool, dielectric_params)
      68              :       TYPE(dielectric_type), INTENT(INOUT), POINTER      :: dielectric
      69              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
      70              :       TYPE(dielectric_parameters), INTENT(IN)            :: dielectric_params
      71              : 
      72              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'dielectric_create'
      73              : 
      74              :       INTEGER                                            :: handle, i
      75              : 
      76           54 :       CALL timeset(routineN, handle)
      77              : 
      78           54 :       IF (.NOT. ASSOCIATED(dielectric)) THEN
      79          270 :          ALLOCATE (dielectric)
      80              :          NULLIFY (dielectric%eps)
      81              :          NULLIFY (dielectric%deps_drho)
      82           54 :          ALLOCATE (dielectric%eps, dielectric%deps_drho)
      83           54 :          CALL pw_pool%create_pw(dielectric%eps)
      84           54 :          CALL pw_pool%create_pw(dielectric%deps_drho)
      85           54 :          CALL pw_set(dielectric%eps, 1.0_dp)
      86           54 :          CALL pw_zero(dielectric%deps_drho)
      87          216 :          DO i = 1, 3
      88          162 :             CALL pw_pool%create_pw(dielectric%dln_eps(i))
      89          216 :             CALL pw_zero(dielectric%dln_eps(i))
      90              :          END DO
      91           54 :          dielectric%params = dielectric_params
      92           54 :          dielectric%params%times_called = 0
      93              :       END IF
      94              : 
      95           54 :       CALL timestop(handle)
      96              : 
      97           54 :    END SUBROUTINE dielectric_create
      98              : 
      99              :    #:for kind in ["c1d_gs", "r3d_rs"]
     100              : ! **************************************************************************************************
     101              : !> \brief   evaluates the dielectric constant
     102              : !> \param dielectric  the dielectric data type to be initialized
     103              : !> \param diel_rs_grid real space grid for finite difference derivative
     104              : !> \param pw_pool pool of plane wave grid
     105              : !> \param rho electronic density
     106              : !> \param rho_core core density
     107              : !> \par History
     108              : !>       06.2014 created [Hossein Bani-Hashemian]
     109              : !>       12.2014 added finite difference derivatives [Hossein Bani-Hashemian]
     110              : !>       07.2015 density-independent dielectric regions [Hossein Bani-Hashemian]
     111              : !> \author Mohammad Hossein Bani-Hashemian
     112              : ! **************************************************************************************************
     113          296 :       SUBROUTINE dielectric_compute_periodic_${kind}$ (dielectric, diel_rs_grid, pw_pool, rho, rho_core)
     114              : 
     115              :          TYPE(dielectric_type), INTENT(INOUT), POINTER      :: dielectric
     116              :          TYPE(realspace_grid_type), POINTER                 :: diel_rs_grid
     117              :          TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
     118              :          TYPE(pw_${kind}$_type), INTENT(IN)                          :: rho
     119              :          TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL                :: rho_core
     120              : 
     121              :          CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_compute_periodic'
     122              :          REAL(dp), PARAMETER                                :: small_value = EPSILON(1.0_dp)
     123              : 
     124              :          INTEGER                                            :: derivative_method, dielec_functiontype, &
     125              :                                                                handle, i, idir, j, k, times_called
     126              :          INTEGER, DIMENSION(3)                              :: lb, ub
     127              :          REAL(dp)                                           :: eps0, rho_max, rho_min
     128              :          TYPE(pw_r3d_rs_type)                                      :: ln_eps, rho_elec_rs
     129              :          TYPE(pw_r3d_rs_type) :: rho_core_rs
     130         2072 :          TYPE(pw_r3d_rs_type), DIMENSION(3)                        :: deps, drho
     131              : 
     132          296 :          CALL timeset(routineN, handle)
     133              : 
     134          296 :          rho_min = dielectric%params%rho_min
     135          296 :          rho_max = dielectric%params%rho_max
     136          296 :          eps0 = dielectric%params%eps0
     137          296 :          derivative_method = dielectric%params%derivative_method
     138          296 :          times_called = dielectric%params%times_called
     139          296 :          dielec_functiontype = dielectric%params%dielec_functiontype
     140              : 
     141          296 :          IF (.NOT. dielec_functiontype .EQ. rho_dependent .AND. &
     142              :              ((derivative_method .EQ. derivative_fft_use_deps) .OR. &
     143              :               (derivative_method .EQ. derivative_fft_use_deps))) THEN
     144              :             CALL cp_abort(__LOCATION__, &
     145              :                           "The specified derivative method is not compatible with the type of "// &
     146            0 :                           "the dielectric constant function.")
     147              :          END IF
     148              : 
     149          296 :          CALL pw_pool%create_pw(rho_elec_rs)
     150              : 
     151              :          ! for evaluating epsilon make sure rho is in the real space
     152          296 :          CALL pw_transfer(rho, rho_elec_rs)
     153              : 
     154          296 :          IF (PRESENT(rho_core)) THEN
     155              :             ! make sure rho_core is in the real space
     156          296 :             CALL pw_pool%create_pw(rho_core_rs)
     157          296 :             CALL pw_transfer(rho_core, rho_core_rs)
     158          296 :             IF (dielectric%params%dielec_core_correction) THEN
     159              :                ! use (rho_elec - rho_core) to compute dielectric to avoid obtaining spurious
     160              :                ! epsilon in the core region
     161          296 :                CALL pw_axpy(rho_core_rs, rho_elec_rs, -2.0_dp)
     162              :             ELSE
     163            0 :                CALL pw_axpy(rho_core_rs, rho_elec_rs, -1.0_dp)
     164              :             END IF
     165          296 :             CALL pw_pool%give_back_pw(rho_core_rs)
     166              :          ELSE
     167            0 :             CPABORT("For dielectric constant larger than 1, rho_core has to be present.")
     168              :          END IF
     169              : 
     170              : ! calculate the dielectric constant
     171          250 :          SELECT CASE (dielec_functiontype)
     172              :          CASE (rho_dependent)
     173              :             CALL dielectric_constant_sccs(rho_elec_rs, dielectric%eps, dielectric%deps_drho, &
     174          250 :                                           eps0, rho_max, rho_min)
     175              :          CASE (spatially_dependent)
     176           22 :             IF (times_called .EQ. 0) THEN
     177            2 :                CALL dielectric_constant_spatially_dependent(dielectric%eps, pw_pool, dielectric%params)
     178              :             END IF
     179              :          CASE (spatially_rho_dependent)
     180              :             CALL dielectric_constant_spatially_rho_dependent(rho_elec_rs, dielectric%eps, &
     181          296 :                                                              dielectric%deps_drho, pw_pool, dielectric%params)
     182              :          END SELECT
     183              : 
     184              : ! derivatives
     185              :          IF ((dielec_functiontype .EQ. rho_dependent) .OR. &
     186          296 :              (dielec_functiontype .EQ. spatially_rho_dependent) .OR. &
     187              :              ((dielec_functiontype .EQ. spatially_dependent) .AND. times_called .EQ. 0)) THEN
     188          266 :             SELECT CASE (derivative_method)
     189              :             CASE (derivative_cd3, derivative_cd5, derivative_cd7, derivative_fft)
     190          266 :                CALL pw_pool%create_pw(ln_eps)
     191     43160654 :                ln_eps%array = LOG(dielectric%eps%array)
     192              :             CASE (derivative_fft_use_deps)
     193           40 :                DO i = 1, 3
     194           30 :                   CALL pw_pool%create_pw(deps(i))
     195           40 :                   CALL pw_zero(deps(i))
     196              :                END DO
     197              :             CASE (derivative_fft_use_drho)
     198          276 :                DO i = 1, 3
     199            0 :                   CALL pw_pool%create_pw(deps(i))
     200            0 :                   CALL pw_pool%create_pw(drho(i))
     201            0 :                   CALL pw_zero(deps(i))
     202            0 :                   CALL pw_zero(drho(i))
     203              :                END DO
     204              :             END SELECT
     205              : 
     206           72 :             SELECT CASE (derivative_method)
     207              :             CASE (derivative_cd3)
     208           72 :                CALL derive_fdm_cd3(ln_eps, dielectric%dln_eps, diel_rs_grid)
     209              :             CASE (derivative_cd5)
     210          114 :                CALL derive_fdm_cd5(ln_eps, dielectric%dln_eps, diel_rs_grid)
     211              :             CASE (derivative_cd7)
     212           80 :                CALL derive_fdm_cd7(ln_eps, dielectric%dln_eps, diel_rs_grid)
     213              :             CASE (derivative_fft)
     214            0 :                CALL derive_fft(ln_eps, dielectric%dln_eps, pw_pool)
     215              :             CASE (derivative_fft_use_deps)
     216              :                ! \Nabla ln(\eps) = \frac{\Nabla \eps}{\eps}
     217           10 :                CALL derive_fft(dielectric%eps, deps, pw_pool)
     218              : 
     219           40 :                lb(1:3) = pw_pool%pw_grid%bounds_local(1, 1:3)
     220           40 :                ub(1:3) = pw_pool%pw_grid%bounds_local(2, 1:3)
     221              :                ! damp oscillations cuased by fft-based derivative in the region
     222              :                ! where electron density is zero
     223           40 :                DO idir = 1, 3
     224         2190 :                   DO k = lb(3), ub(3)
     225       157710 :                      DO j = lb(2), ub(2)
     226      5756400 :                         DO i = lb(1), ub(1)
     227      5754240 :                            IF (ABS(dielectric%deps_drho%array(i, j, k)) .LE. small_value) THEN
     228      5193252 :                               deps(idir)%array(i, j, k) = 0.0_dp
     229              :                            END IF
     230              :                         END DO
     231              :                      END DO
     232              :                   END DO
     233      5756440 :                   dielectric%dln_eps(idir)%array = deps(idir)%array/dielectric%eps%array
     234              :                END DO
     235              :             CASE (derivative_fft_use_drho)
     236              :                ! \Nabla \eps = \Nabla \rho \cdot \frac{\partial \eps}{\partial \rho}
     237              :                ! \Nabla ln(\eps) = \frac{\Nabla \eps}{\eps}
     238            0 :                CALL derive_fft(rho_elec_rs, drho, pw_pool)
     239          276 :                DO i = 1, 3
     240            0 :                   deps(i)%array = drho(i)%array*dielectric%deps_drho%array
     241            0 :                   dielectric%dln_eps(i)%array = deps(i)%array/dielectric%eps%array
     242              :                END DO
     243              :             END SELECT
     244              : 
     245          266 :             SELECT CASE (derivative_method)
     246              :             CASE (derivative_cd3, derivative_cd5, derivative_cd7, derivative_fft)
     247          266 :                CALL pw_pool%give_back_pw(ln_eps)
     248              :             CASE (derivative_fft_use_deps)
     249           40 :                DO i = 1, 3
     250           40 :                   CALL pw_pool%give_back_pw(deps(i))
     251              :                END DO
     252              :             CASE (derivative_fft_use_drho)
     253          276 :                DO i = 1, 3
     254            0 :                   CALL pw_pool%give_back_pw(drho(i))
     255            0 :                   CALL pw_pool%give_back_pw(deps(i))
     256              :                END DO
     257              :             END SELECT
     258              :          END IF
     259              : 
     260          296 :          CALL pw_pool%give_back_pw(rho_elec_rs)
     261              : 
     262          296 :          dielectric%params%times_called = dielectric%params%times_called + 1
     263              : 
     264          296 :          CALL timestop(handle)
     265              : 
     266          296 :       END SUBROUTINE dielectric_compute_periodic_${kind}$
     267              : 
     268              : ! **************************************************************************************************
     269              : !> \brief   evaluates the dielectric constant for non-periodic (Neumann-type)
     270              : !>          boundaries
     271              : !> \param dielectric  the dielectric data type to be initialized
     272              : !> \param diel_rs_grid real space grid for finite difference derivative
     273              : !> \param pw_pool_orig pool of plane wave grid
     274              : !> \param dct_pw_grid ...
     275              : !> \param neumann_directions ...
     276              : !> \param recv_msgs_bnds bounds of the messages to be received (pw_expand)
     277              : !> \param dests_expand list of the destination processes (pw_expand)
     278              : !> \param srcs_expand list of the source processes (pw_expand)
     279              : !> \param flipg_stat flipping status for the received data chunks (pw_expand)
     280              : !> \param bounds_shftd bounds of the original grid shifted to have g0 in the
     281              : !>        middle of the cell (pw_expand)
     282              : !> \param rho electronic density
     283              : !> \param rho_core core density
     284              : !> \par History
     285              : !>       11.2015 created [Hossein Bani-Hashemian]
     286              : !> \author Mohammad Hossein Bani-Hashemian
     287              : ! **************************************************************************************************
     288          156 :       SUBROUTINE dielectric_compute_neumann_${kind}$ (dielectric, diel_rs_grid, pw_pool_orig, &
     289              :                                                       dct_pw_grid, neumann_directions, recv_msgs_bnds, &
     290              :                                                       dests_expand, srcs_expand, flipg_stat, bounds_shftd, rho, rho_core)
     291              : 
     292              :          TYPE(dielectric_type), INTENT(INOUT), POINTER      :: dielectric
     293              :          TYPE(realspace_grid_type), POINTER                 :: diel_rs_grid
     294              :          TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool_orig
     295              :          TYPE(pw_grid_type), INTENT(IN), POINTER            :: dct_pw_grid
     296              :          INTEGER, INTENT(IN)                                :: neumann_directions
     297              :          INTEGER, DIMENSION(:, :, :), INTENT(IN), POINTER   :: recv_msgs_bnds
     298              :          INTEGER, DIMENSION(:), INTENT(IN), POINTER         :: dests_expand, srcs_expand, flipg_stat
     299              :          INTEGER, DIMENSION(2, 3), INTENT(IN)               :: bounds_shftd
     300              :          TYPE(pw_${kind}$_type), INTENT(IN)                          :: rho
     301              :          TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL                :: rho_core
     302              : 
     303              :          CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_compute_neumann'
     304              :          REAL(dp), PARAMETER                                :: small_value = EPSILON(1.0_dp)
     305              : 
     306              :          INTEGER                                            :: derivative_method, dielec_functiontype, &
     307              :                                                                handle, i, idir, j, k, times_called
     308              :          INTEGER, DIMENSION(3)                              :: lb, ub
     309              :          REAL(dp)                                           :: eps0, rho_max, rho_min
     310              :          TYPE(pw_pool_type), POINTER                        :: pw_pool_xpndd
     311              :          TYPE(pw_r3d_rs_type)                                      :: ln_eps, rho_core_rs, rho_core_rs_xpndd, &
     312              :                                                                       rho_elec_rs, rho_elec_rs_xpndd
     313         1092 :          TYPE(pw_r3d_rs_type), DIMENSION(3)                        :: deps, drho
     314              : 
     315          156 :          CALL timeset(routineN, handle)
     316              : 
     317          156 :          rho_min = dielectric%params%rho_min
     318          156 :          rho_max = dielectric%params%rho_max
     319          156 :          eps0 = dielectric%params%eps0
     320          156 :          derivative_method = dielectric%params%derivative_method
     321          156 :          times_called = dielectric%params%times_called
     322          156 :          dielec_functiontype = dielectric%params%dielec_functiontype
     323              : 
     324          156 :          IF (.NOT. dielec_functiontype .EQ. rho_dependent .AND. &
     325              :              ((derivative_method .EQ. derivative_fft_use_deps) .OR. &
     326              :               (derivative_method .EQ. derivative_fft_use_deps))) THEN
     327              :             CALL cp_abort(__LOCATION__, &
     328              :                           "The specified derivative method is not compatible with the type of "// &
     329            0 :                           "the dielectric constant function.")
     330              :          END IF
     331              : 
     332          156 :          CALL pw_pool_create(pw_pool_xpndd, pw_grid=dct_pw_grid)
     333              : 
     334              :          ! make sure rho is in the real space
     335          156 :          CALL pw_pool_orig%create_pw(rho_elec_rs)
     336          156 :          CALL pw_transfer(rho, rho_elec_rs)
     337              :          ! expand rho_elec
     338          156 :          CALL pw_pool_xpndd%create_pw(rho_elec_rs_xpndd)
     339              :          CALL pw_expand(neumann_directions, recv_msgs_bnds, dests_expand, srcs_expand, flipg_stat, bounds_shftd, &
     340          156 :                         rho_elec_rs, rho_elec_rs_xpndd)
     341              : 
     342          156 :          IF (PRESENT(rho_core)) THEN
     343              :             ! make sure rho_core is in the real space
     344          156 :             CALL pw_pool_orig%create_pw(rho_core_rs)
     345          156 :             CALL pw_transfer(rho_core, rho_core_rs)
     346              :             ! expand rho_core
     347          156 :             CALL pw_pool_xpndd%create_pw(rho_core_rs_xpndd)
     348              :             CALL pw_expand(neumann_directions, recv_msgs_bnds, dests_expand, srcs_expand, flipg_stat, bounds_shftd, &
     349          156 :                            rho_core_rs, rho_core_rs_xpndd)
     350              : 
     351          156 :             IF (dielectric%params%dielec_core_correction) THEN
     352              :                ! use (rho_elec - rho_core) to compute dielectric
     353          156 :                CALL pw_axpy(rho_core_rs_xpndd, rho_elec_rs_xpndd, -2.0_dp)
     354              :             ELSE
     355            0 :                CALL pw_axpy(rho_core_rs_xpndd, rho_elec_rs_xpndd, -1.0_dp)
     356              :             END IF
     357          156 :             CALL pw_pool_orig%give_back_pw(rho_core_rs)
     358          156 :             CALL pw_pool_xpndd%give_back_pw(rho_core_rs_xpndd)
     359              :          ELSE
     360            0 :             CPABORT("For dielectric constant larger than 1, rho_core has to be present.")
     361              :          END IF
     362              : 
     363              : ! calculate the dielectric constant
     364          156 :          SELECT CASE (dielec_functiontype)
     365              :          CASE (rho_dependent)
     366              :             CALL dielectric_constant_sccs(rho_elec_rs_xpndd, dielectric%eps, dielectric%deps_drho, &
     367          156 :                                           eps0, rho_max, rho_min)
     368              :          CASE (spatially_dependent)
     369            0 :             IF (times_called .EQ. 0) THEN
     370            0 :                CALL dielectric_constant_spatially_dependent(dielectric%eps, pw_pool_xpndd, dielectric%params)
     371              :             END IF
     372              :          CASE (spatially_rho_dependent)
     373              :             CALL dielectric_constant_spatially_rho_dependent(rho_elec_rs_xpndd, dielectric%eps, &
     374          156 :                                                              dielectric%deps_drho, pw_pool_xpndd, dielectric%params)
     375              :          END SELECT
     376              : 
     377              : ! derivatives
     378              :          IF ((dielec_functiontype .EQ. rho_dependent) .OR. &
     379          156 :              (dielec_functiontype .EQ. spatially_rho_dependent) .OR. &
     380              :              ((dielec_functiontype .EQ. spatially_dependent) .AND. times_called .EQ. 0)) THEN
     381          148 :             SELECT CASE (derivative_method)
     382              :             CASE (derivative_cd3, derivative_cd5, derivative_cd7, derivative_fft)
     383          148 :                CALL pw_pool_xpndd%create_pw(ln_eps)
     384     59442756 :                ln_eps%array = LOG(dielectric%eps%array)
     385              :             CASE (derivative_fft_use_deps)
     386           32 :                DO i = 1, 3
     387           24 :                   CALL pw_pool_xpndd%create_pw(deps(i))
     388           32 :                   CALL pw_zero(deps(i))
     389              :                END DO
     390              :             CASE (derivative_fft_use_drho)
     391          156 :                DO i = 1, 3
     392            0 :                   CALL pw_pool_xpndd%create_pw(deps(i))
     393            0 :                   CALL pw_pool_xpndd%create_pw(drho(i))
     394            0 :                   CALL pw_zero(deps(i))
     395            0 :                   CALL pw_zero(drho(i))
     396              :                END DO
     397              :             END SELECT
     398              : 
     399          124 :             SELECT CASE (derivative_method)
     400              :             CASE (derivative_cd3)
     401          124 :                CALL derive_fdm_cd3(ln_eps, dielectric%dln_eps, diel_rs_grid)
     402              :             CASE (derivative_cd5)
     403            0 :                CALL derive_fdm_cd5(ln_eps, dielectric%dln_eps, diel_rs_grid)
     404              :             CASE (derivative_cd7)
     405           24 :                CALL derive_fdm_cd7(ln_eps, dielectric%dln_eps, diel_rs_grid)
     406              :             CASE (derivative_fft)
     407            0 :                CALL derive_fft(ln_eps, dielectric%dln_eps, pw_pool_xpndd)
     408              :             CASE (derivative_fft_use_deps)
     409              :                ! \Nabla ln(\eps) = \frac{\Nabla \eps}{\eps}
     410            8 :                CALL derive_fft(dielectric%eps, deps, pw_pool_xpndd)
     411              : 
     412           32 :                lb(1:3) = pw_pool_xpndd%pw_grid%bounds_local(1, 1:3)
     413           32 :                ub(1:3) = pw_pool_xpndd%pw_grid%bounds_local(2, 1:3)
     414              :                ! damp oscillations cuased by fft-based derivative in the region
     415              :                ! where electron density is zero
     416           32 :                DO idir = 1, 3
     417         2904 :                   DO k = lb(3), ub(3)
     418       348504 :                      DO j = lb(2), ub(2)
     419     21084480 :                         DO i = lb(1), ub(1)
     420     21081600 :                            IF (ABS(dielectric%deps_drho%array(i, j, k)) .LE. small_value) THEN
     421     18486864 :                               deps(idir)%array(i, j, k) = 0.0_dp
     422              :                            END IF
     423              :                         END DO
     424              :                      END DO
     425              :                   END DO
     426     21084512 :                   dielectric%dln_eps(idir)%array = deps(idir)%array/dielectric%eps%array
     427              :                END DO
     428              :             CASE (derivative_fft_use_drho)
     429              :                ! \Nabla \eps = \Nabla \rho \cdot \frac{\partial \eps}{\partial \rho}
     430              :                ! \Nabla ln(\eps) = \frac{\Nabla \eps}{\eps}
     431            0 :                CALL derive_fft(rho_elec_rs_xpndd, drho, pw_pool_xpndd)
     432          156 :                DO i = 1, 3
     433            0 :                   deps(i)%array = drho(i)%array*dielectric%deps_drho%array
     434            0 :                   dielectric%dln_eps(i)%array = deps(i)%array/dielectric%eps%array
     435              :                END DO
     436              :             END SELECT
     437              : 
     438          148 :             SELECT CASE (derivative_method)
     439              :             CASE (derivative_cd3, derivative_cd5, derivative_cd7, derivative_fft)
     440          148 :                CALL pw_pool_xpndd%give_back_pw(ln_eps)
     441              :             CASE (derivative_fft_use_deps)
     442           32 :                DO i = 1, 3
     443           32 :                   CALL pw_pool_xpndd%give_back_pw(deps(i))
     444              :                END DO
     445              :             CASE (derivative_fft_use_drho)
     446          156 :                DO i = 1, 3
     447            0 :                   CALL pw_pool_xpndd%give_back_pw(drho(i))
     448            0 :                   CALL pw_pool_xpndd%give_back_pw(deps(i))
     449              :                END DO
     450              :             END SELECT
     451              :          END IF
     452              : 
     453          156 :          CALL pw_pool_orig%give_back_pw(rho_elec_rs)
     454          156 :          CALL pw_pool_xpndd%give_back_pw(rho_elec_rs_xpndd)
     455          156 :          CALL pw_pool_release(pw_pool_xpndd)
     456              : 
     457          156 :          dielectric%params%times_called = dielectric%params%times_called + 1
     458              : 
     459          156 :          CALL timestop(handle)
     460              : 
     461          156 :       END SUBROUTINE dielectric_compute_neumann_${kind}$
     462              :    #:endfor
     463              : 
     464              : ! **************************************************************************************************
     465              : !> \brief  calculates the dielectric constant as a function of the electronic density
     466              : !>  [see O. Andreussi, I. Dabo, and N. Marzari, J. Chem. Phys., 136, 064102 (2012)]
     467              : !> \param rho electron density
     468              : !> \param eps dielectric constant
     469              : !> \param deps_drho derivative of the dielectric constant wrt the density
     470              : !> \param eps0 dielectric constant in the bulk of the solvent
     471              : !> \param rho_max upper density threshold
     472              : !> \param rho_min lower density threshold
     473              : !> \par History
     474              : !>       06.2014 created [Hossein Bani-Hashemian]
     475              : !> \author Mohammad Hossein Bani-Hashemian
     476              : ! **************************************************************************************************
     477          430 :    SUBROUTINE dielectric_constant_sccs(rho, eps, deps_drho, eps0, rho_max, rho_min)
     478              : 
     479              :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: rho, eps, deps_drho
     480              :       REAL(KIND=dp), INTENT(IN)                          :: eps0, rho_max, rho_min
     481              : 
     482              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_constant_sccs'
     483              : 
     484              :       INTEGER                                            :: handle, i, j, k, lb1, lb2, lb3, ub1, &
     485              :                                                             ub2, ub3
     486              :       INTEGER, DIMENSION(2, 3)                           :: bounds_local
     487              :       REAL(KIND=dp)                                      :: denom, t
     488              : 
     489          430 :       CALL timeset(routineN, handle)
     490              : 
     491          430 :       IF (eps0 .LT. 1.0_dp) THEN
     492            0 :          CPABORT("The dielectric constant has to be greater than or equal to 1.")
     493              :       END IF
     494              : 
     495         4300 :       bounds_local = rho%pw_grid%bounds_local
     496          430 :       lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
     497          430 :       lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
     498          430 :       lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
     499              : 
     500          430 :       denom = LOG(rho_max) - LOG(rho_min)
     501        32686 :       DO k = lb3, ub3
     502      2559678 :          DO j = lb2, ub2
     503    111166196 :             DO i = lb1, ub1
     504    111133940 :                IF (rho%array(i, j, k) .LT. rho_min) THEN
     505     92481859 :                   eps%array(i, j, k) = eps0
     506     92481859 :                   deps_drho%array(i, j, k) = 0.0_dp
     507     16125089 :                ELSE IF (rho%array(i, j, k) .GT. rho_max) THEN
     508      7537971 :                   eps%array(i, j, k) = 1.0_dp
     509      7537971 :                   deps_drho%array(i, j, k) = 0.0_dp
     510              :                ELSE
     511      8587118 :                   t = twopi*(LOG(rho_max) - LOG(rho%array(i, j, k)))/denom
     512      8587118 :                   eps%array(i, j, k) = EXP(LOG(eps0)*(t - SIN(t))/twopi)
     513      8587118 :                   deps_drho%array(i, j, k) = -eps%array(i, j, k)*LOG(eps0)*(1.0_dp - COS(t))/(denom*rho%array(i, j, k))
     514              :                END IF
     515              :             END DO
     516              :          END DO
     517              :       END DO
     518              : 
     519          430 :       CALL timestop(handle)
     520              : 
     521          430 :    END SUBROUTINE dielectric_constant_sccs
     522              : 
     523              : ! **************************************************************************************************
     524              : !> \brief creates an axis-aligned cuboidal dielectric region
     525              : !> \param eps dielectric constant function
     526              : !> \param dielec_const dielectric constant inside the region
     527              : !> \param pw_pool pool of planewave grid
     528              : !> \param zeta the mollifier's width
     529              : !> \param x_xtnt the x extent of the cuboidal region
     530              : !> \param y_xtnt the y extent of the cuboidal region
     531              : !> \param z_xtnt the z extent of the cuboidal region
     532              : !> \param x_glbl x grid vector of the simulation box
     533              : !> \param y_glbl y grid vector of the simulation box
     534              : !> \param z_glbl z grid vector of the simulation box
     535              : !> \param x_locl x grid vector of the simulation box local to this process
     536              : !> \param y_locl y grid vector of the simulation box local to this process
     537              : !> \param z_locl z grid vector of the simulation box local to this process
     538              : !> \par History
     539              : !>       07.2015 created [Hossein Bani-Hashemian]
     540              : !> \author Mohammad Hossein Bani-Hashemian
     541              : ! **************************************************************************************************
     542            2 :    SUBROUTINE dielectric_constant_aa_cuboidal(eps, dielec_const, pw_pool, zeta, &
     543              :                                               x_xtnt, y_xtnt, z_xtnt, &
     544              :                                               x_glbl, y_glbl, z_glbl, &
     545              :                                               x_locl, y_locl, z_locl)
     546              : 
     547              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: eps
     548              :       REAL(KIND=dp), INTENT(IN)                          :: dielec_const
     549              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     550              :       REAL(KIND=dp), INTENT(IN)                          :: zeta
     551              :       REAL(dp), DIMENSION(2), INTENT(IN)                 :: x_xtnt, y_xtnt, z_xtnt
     552              :       REAL(dp), ALLOCATABLE, DIMENSION(:), INTENT(IN)    :: x_glbl, y_glbl, z_glbl, x_locl, y_locl, &
     553              :                                                             z_locl
     554              : 
     555              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_constant_aa_cuboidal'
     556              :       LOGICAL, DIMENSION(6), PARAMETER                   :: test_forb_xtnts = .TRUE.
     557              : 
     558              :       INTEGER                                            :: handle, i, j, k, lb1, lb2, lb3, &
     559              :                                                             n_forb_xtnts, ub1, ub2, ub3
     560              :       INTEGER, DIMENSION(2, 3)                           :: bounds_local
     561              :       LOGICAL                                            :: forb_xtnt1, forb_xtnt2, forb_xtnt3, &
     562              :                                                             forb_xtnt4, forb_xtnt5, forb_xtnt6
     563              :       REAL(KIND=dp)                                      :: dx, dy, dz
     564              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
     565              :       TYPE(pw_r3d_rs_type)                                      :: eps_tmp
     566              : 
     567            2 :       CALL timeset(routineN, handle)
     568              : 
     569            2 :       IF (dielec_const .LT. 1.0_dp) THEN
     570            0 :          CPABORT("The dielectric constant has to be greater than or equal to 1.")
     571              :       END IF
     572              : 
     573            2 :       pw_grid => eps%pw_grid
     574              : 
     575            2 :       dx = pw_grid%dr(1); dy = pw_grid%dr(2); dz = pw_grid%dr(3)
     576              : 
     577            2 :       forb_xtnt1 = x_xtnt(1) .LT. x_glbl(LBOUND(x_glbl, 1))
     578            2 :       forb_xtnt2 = x_xtnt(2) .GT. x_glbl(UBOUND(x_glbl, 1)) + dx
     579            2 :       forb_xtnt3 = y_xtnt(1) .LT. y_glbl(LBOUND(y_glbl, 1))
     580            2 :       forb_xtnt4 = y_xtnt(2) .GT. y_glbl(UBOUND(y_glbl, 1)) + dy
     581            2 :       forb_xtnt5 = z_xtnt(1) .LT. z_glbl(LBOUND(z_glbl, 1))
     582            2 :       forb_xtnt6 = z_xtnt(2) .GT. z_glbl(UBOUND(z_glbl, 1)) + dz
     583              :       n_forb_xtnts = COUNT((/forb_xtnt1, forb_xtnt2, forb_xtnt3, &
     584           14 :                              forb_xtnt4, forb_xtnt5, forb_xtnt6/) .EQV. test_forb_xtnts)
     585            2 :       IF (n_forb_xtnts .GT. 0) THEN
     586              :          CALL cp_abort(__LOCATION__, &
     587              :                        "The given extents for the dielectric region are outside the range of "// &
     588            0 :                        "the simulation cell.")
     589              :       END IF
     590              : 
     591            2 :       CALL pw_pool%create_pw(eps_tmp)
     592            2 :       CALL pw_copy(eps, eps_tmp)
     593              : 
     594           20 :       bounds_local = pw_grid%bounds_local
     595            2 :       lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
     596            2 :       lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
     597            2 :       lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
     598              : 
     599          146 :       DO k = lb3, ub3
     600        10514 :          DO j = lb2, ub2
     601       383760 :             DO i = lb1, ub1
     602              :                IF ((x_locl(i) .GE. x_xtnt(1)) .AND. (x_locl(i) .LE. x_xtnt(2)) .AND. &
     603              :                    (y_locl(j) .GE. y_xtnt(1)) .AND. (y_locl(j) .LE. y_xtnt(2)) .AND. &
     604       383616 :                    (z_locl(k) .GE. z_xtnt(1)) .AND. (z_locl(k) .LE. z_xtnt(2))) THEN
     605        35721 :                   eps_tmp%array(i, j, k) = dielec_const
     606              :                END IF
     607              :             END DO
     608              :          END DO
     609              :       END DO
     610              : 
     611            2 :       CALL pw_mollifier(pw_pool, zeta, x_glbl, y_glbl, z_glbl, eps_tmp, eps)
     612            2 :       CALL pw_pool%give_back_pw(eps_tmp)
     613              : 
     614            2 :       CALL timestop(handle)
     615              : 
     616            2 :    END SUBROUTINE dielectric_constant_aa_cuboidal
     617              : 
     618              : ! **************************************************************************************************
     619              : !> \brief creates an x-axis aligned annular dielectric region
     620              : !> \param eps dielectric constant function
     621              : !> \param dielec_const dielectric constant inside the region
     622              : !> \param pw_pool pool of planewave grid
     623              : !> \param zeta the mollifier's width
     624              : !> \param x_xtnt the x extent of the annular region
     625              : !> \param base_center the y and z coordinates of the cylinder's base
     626              : !> \param base_radii the radii of the annulus' base
     627              : !> \param x_glbl x grid vector of the simulation box
     628              : !> \param y_glbl y grid vector of the simulation box
     629              : !> \param z_glbl z grid vector of the simulation box
     630              : !> \param x_locl x grid vector of the simulation box local to this process
     631              : !> \param y_locl y grid vector of the simulation box local to this process
     632              : !> \param z_locl z grid vector of the simulation box local to this process
     633              : !> \par History
     634              : !>       07.2015 created [Hossein Bani-Hashemian]
     635              : !> \author Mohammad Hossein Bani-Hashemian
     636              : ! **************************************************************************************************
     637           26 :    SUBROUTINE dielectric_constant_xaa_annular(eps, dielec_const, pw_pool, zeta, &
     638              :                                               x_xtnt, base_center, base_radii, &
     639              :                                               x_glbl, y_glbl, z_glbl, &
     640              :                                               x_locl, y_locl, z_locl)
     641              : 
     642              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: eps
     643              :       REAL(KIND=dp), INTENT(IN)                          :: dielec_const
     644              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     645              :       REAL(dp), INTENT(IN)                               :: zeta
     646              :       REAL(dp), DIMENSION(2), INTENT(IN)                 :: x_xtnt, base_center, base_radii
     647              :       REAL(dp), ALLOCATABLE, DIMENSION(:), INTENT(IN)    :: x_glbl, y_glbl, z_glbl, x_locl, y_locl, &
     648              :                                                             z_locl
     649              : 
     650              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_constant_xaa_annular'
     651              :       LOGICAL, DIMENSION(6), PARAMETER                   :: test_forb_xtnts = .TRUE.
     652              : 
     653              :       INTEGER                                            :: handle, i, j, k, lb1, lb2, lb3, &
     654              :                                                             n_forb_xtnts, ub1, ub2, ub3
     655              :       INTEGER, DIMENSION(2, 3)                           :: bounds_local
     656              :       LOGICAL                                            :: forb_xtnt1, forb_xtnt2, forb_xtnt3, &
     657              :                                                             forb_xtnt4, forb_xtnt5, forb_xtnt6
     658              :       REAL(KIND=dp)                                      :: bctry, bctrz, distsq, dx, dy, dz
     659              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
     660              :       TYPE(pw_r3d_rs_type)                                      :: eps_tmp
     661              : 
     662           26 :       CALL timeset(routineN, handle)
     663              : 
     664           26 :       IF (dielec_const .LT. 1.0_dp) THEN
     665            0 :          CPABORT("The dielectric constant has to be greater than or equal to 1.")
     666              :       END IF
     667              : 
     668           26 :       pw_grid => eps%pw_grid
     669              : 
     670           26 :       bctry = base_center(1); bctrz = base_center(2)
     671           26 :       dx = pw_grid%dr(1); dy = pw_grid%dr(2); dz = pw_grid%dr(3)
     672              : 
     673           26 :       forb_xtnt1 = x_xtnt(1) .LT. x_glbl(LBOUND(x_glbl, 1))
     674           26 :       forb_xtnt2 = x_xtnt(2) .GT. x_glbl(UBOUND(x_glbl, 1)) + dx
     675          104 :       forb_xtnt3 = bctry - MAXVAL(base_radii) .LT. y_glbl(LBOUND(y_glbl, 1))
     676          104 :       forb_xtnt4 = bctry + MAXVAL(base_radii) .GT. y_glbl(UBOUND(y_glbl, 1)) + dy
     677          104 :       forb_xtnt5 = bctrz - MAXVAL(base_radii) .LT. z_glbl(LBOUND(z_glbl, 1))
     678          104 :       forb_xtnt6 = bctrz + MAXVAL(base_radii) .GT. z_glbl(UBOUND(z_glbl, 1)) + dz
     679              :       n_forb_xtnts = COUNT((/forb_xtnt1, forb_xtnt2, forb_xtnt3, &
     680          182 :                              forb_xtnt4, forb_xtnt5, forb_xtnt6/) .EQV. test_forb_xtnts)
     681           26 :       IF (n_forb_xtnts .GT. 0) THEN
     682              :          CALL cp_abort(__LOCATION__, &
     683              :                        "The given extents for the dielectric region are outside the range of "// &
     684            0 :                        "the simulation cell.")
     685              :       END IF
     686              : 
     687           26 :       CALL pw_pool%create_pw(eps_tmp)
     688           26 :       CALL pw_copy(eps, eps_tmp)
     689              : 
     690          260 :       bounds_local = pw_grid%bounds_local
     691           26 :       lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
     692           26 :       lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
     693           26 :       lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
     694              : 
     695         1898 :       DO k = lb3, ub3
     696       136682 :          DO j = lb2, ub2
     697      4988880 :             DO i = lb1, ub1
     698      4852224 :                distsq = (y_locl(j) - bctry)**2 + (z_locl(k) - bctrz)**2
     699              :                IF ((x_locl(i) .GE. x_xtnt(1)) .AND. (x_locl(i) .LE. x_xtnt(2)) .AND. &
     700     34100352 :                    (distsq .GE. MINVAL(base_radii)**2) .AND. (distsq .LE. MAXVAL(base_radii)**2)) THEN
     701       390159 :                   eps_tmp%array(i, j, k) = dielec_const
     702              :                END IF
     703              :             END DO
     704              :          END DO
     705              :       END DO
     706              : 
     707           26 :       CALL pw_mollifier(pw_pool, zeta, x_glbl, y_glbl, z_glbl, eps_tmp, eps)
     708           26 :       CALL pw_pool%give_back_pw(eps_tmp)
     709              : 
     710           26 :       CALL timestop(handle)
     711              : 
     712           26 :    END SUBROUTINE dielectric_constant_xaa_annular
     713              : 
     714              : ! **************************************************************************************************
     715              : !> \brief  Sets up density independent dielectric regions
     716              : !> \param eps dielectric constant function
     717              : !> \param pw_pool pool of planewave grid
     718              : !> \param dielectric_params dielectric parameters read from input file
     719              : !> \par History
     720              : !>       07.2015 created [Hossein Bani-Hashemian]
     721              : !> \author Mohammad Hossein Bani-Hashemian
     722              : ! **************************************************************************************************
     723           26 :    SUBROUTINE dielectric_constant_spatially_dependent(eps, pw_pool, dielectric_params)
     724              : 
     725              :       TYPE(pw_r3d_rs_type), INTENT(INOUT)                       :: eps
     726              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
     727              :       TYPE(dielectric_parameters), INTENT(IN)            :: dielectric_params
     728              : 
     729              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_constant_spatially_dependent'
     730              : 
     731              :       INTEGER                                            :: handle, j, n_aa_cuboidal, &
     732              :                                                             n_dielectric_region, n_xaa_annular
     733              :       REAL(dp)                                           :: dielec_const, zeta
     734           26 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: x_glbl, x_locl, y_glbl, y_locl, z_glbl, &
     735           26 :                                                             z_locl
     736              :       REAL(dp), DIMENSION(2)                             :: base_center, base_radii
     737              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
     738              : 
     739           26 :       CALL timeset(routineN, handle)
     740              : 
     741      4988906 :       eps%array = dielectric_params%eps0
     742              : 
     743           26 :       n_aa_cuboidal = dielectric_params%n_aa_cuboidal
     744           26 :       n_xaa_annular = dielectric_params%n_xaa_annular
     745           26 :       pw_grid => pw_pool%pw_grid
     746              :       CALL setup_grid_axes(pw_grid, x_glbl, y_glbl, z_glbl, x_locl, y_locl, z_locl)
     747           26 :       n_dielectric_region = n_aa_cuboidal + n_xaa_annular
     748              : 
     749           26 :       IF (n_dielectric_region .EQ. 0) THEN
     750            0 :          CPABORT("No density independent dielectric region is defined.")
     751              :       END IF
     752              : 
     753           28 :       DO j = 1, n_aa_cuboidal
     754            2 :          dielec_const = dielectric_params%aa_cuboidal_eps(j)
     755            2 :          zeta = dielectric_params%aa_cuboidal_zeta(j)
     756              : 
     757              :          CALL dielectric_constant_aa_cuboidal(eps, dielec_const, pw_pool, zeta, &
     758              :                                               dielectric_params%aa_cuboidal_xxtnt(:, j), &
     759              :                                               dielectric_params%aa_cuboidal_yxtnt(:, j), &
     760              :                                               dielectric_params%aa_cuboidal_zxtnt(:, j), &
     761              :                                               x_glbl, y_glbl, z_glbl, &
     762           28 :                                               x_locl, y_locl, z_locl)
     763              :       END DO
     764              : 
     765           52 :       DO j = 1, n_xaa_annular
     766           78 :          base_center = dielectric_params%xaa_annular_bctr(:, j)
     767           78 :          base_radii = dielectric_params%xaa_annular_brad(:, j)
     768           26 :          dielec_const = dielectric_params%xaa_annular_eps(j)
     769           26 :          zeta = dielectric_params%xaa_annular_zeta(j)
     770              : 
     771              :          CALL dielectric_constant_xaa_annular(eps, dielec_const, pw_pool, zeta, &
     772              :                                               dielectric_params%xaa_annular_xxtnt(:, j), &
     773              :                                               base_center, base_radii, &
     774              :                                               x_glbl, y_glbl, z_glbl, &
     775           52 :                                               x_locl, y_locl, z_locl)
     776              :       END DO
     777              : 
     778           26 :       CALL timestop(handle)
     779              : 
     780           26 :    END SUBROUTINE dielectric_constant_spatially_dependent
     781              : 
     782              : ! **************************************************************************************************
     783              : !> \brief  Sets up various dielectric constant regions. Using the sccs switching
     784              : !> function the dielectric constant smoothly varies between 1, where the density
     785              : !> is present and the values inside the dielectric regions, otherwise.
     786              : !> \param rho electron density
     787              : !> \param eps dielectric constant function
     788              : !> \param deps_drho derivative of the dielectric constant wrt the density
     789              : !> \param pw_pool pool of planewave grid
     790              : !> \param dielectric_params dielectric parameters read from input file
     791              : !> \par History
     792              : !>       07.2015 created [Hossein Bani-Hashemian]
     793              : !> \author Mohammad Hossein Bani-Hashemian
     794              : ! **************************************************************************************************
     795           24 :    SUBROUTINE dielectric_constant_spatially_rho_dependent(rho, eps, deps_drho, &
     796              :                                                           pw_pool, dielectric_params)
     797              : 
     798              :       TYPE(pw_r3d_rs_type), INTENT(IN)                          :: rho, eps, deps_drho
     799              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: pw_pool
     800              :       TYPE(dielectric_parameters), INTENT(IN)            :: dielectric_params
     801              : 
     802              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'dielectric_constant_spatially_rho_dependent'
     803              : 
     804              :       INTEGER                                            :: handle
     805              :       TYPE(pw_r3d_rs_type)                                      :: dswch_func_drho, eps_sptldep, swch_func
     806              : 
     807           24 :       CALL timeset(routineN, handle)
     808              : 
     809           24 :       IF (dielectric_params%eps0 .LT. 1.0_dp) THEN
     810            0 :          CPABORT("The dielectric constant has to be greater than or equal to 1.")
     811              :       END IF
     812              : 
     813           24 :       CALL pw_pool%create_pw(eps_sptldep)
     814           24 :       CALL pw_pool%create_pw(swch_func)
     815           24 :       CALL pw_pool%create_pw(dswch_func_drho)
     816           24 :       CALL pw_zero(eps_sptldep)
     817           24 :       CALL pw_zero(swch_func)
     818           24 :       CALL pw_zero(dswch_func_drho)
     819              : 
     820           24 :       CALL dielectric_constant_spatially_dependent(eps_sptldep, pw_pool, dielectric_params)
     821              :       CALL dielectric_constant_sccs(rho, swch_func, dswch_func_drho, 2.0_dp, &
     822           24 :                                     dielectric_params%rho_max, dielectric_params%rho_min)
     823              : 
     824      4605144 :       eps%array = ((swch_func%array - 1.0_dp)*(eps_sptldep%array - 1.0_dp)) + 1.0_dp
     825      4605144 :       deps_drho%array = dswch_func_drho%array*(eps_sptldep%array - 1.0_dp)
     826              : 
     827           24 :       CALL pw_pool%give_back_pw(dswch_func_drho)
     828           24 :       CALL pw_pool%give_back_pw(swch_func)
     829           24 :       CALL pw_pool%give_back_pw(eps_sptldep)
     830              : 
     831           24 :       CALL timestop(handle)
     832              : 
     833           24 :    END SUBROUTINE dielectric_constant_spatially_rho_dependent
     834              : 
     835              : ! **************************************************************************************************
     836              : !> \brief  computes the derivative of a function using FFT
     837              : !> \param f  input funcition
     838              : !> \param df derivative of f
     839              : !> \param pw_pool pool of plane-wave grid
     840              : ! **************************************************************************************************
     841         5136 :    SUBROUTINE derive_fft(f, df, pw_pool)
     842              : 
     843              :       TYPE(pw_r3d_rs_type), INTENT(IN)                      :: f
     844              :       TYPE(pw_r3d_rs_type), DIMENSION(3), INTENT(INOUT)     :: df
     845              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     846              : 
     847              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'derive_fft_r3d'
     848              : 
     849              :       INTEGER                                            :: handle, i
     850              :       INTEGER, DIMENSION(3)                              :: nd
     851        15408 :       TYPE(pw_c1d_gs_type), DIMENSION(2)                    :: work_gs
     852              : 
     853         5136 :       CALL timeset(routineN, handle)
     854              : 
     855        15408 :       DO i = 1, 2
     856        15408 :          CALL pw_pool%create_pw(work_gs(i))
     857              :       END DO
     858              : 
     859         5136 :       CALL pw_transfer(f, work_gs(1))
     860        20544 :       DO i = 1, 3
     861        15408 :          nd(:) = 0
     862        15408 :          nd(i) = 1
     863        15408 :          CALL pw_copy(work_gs(1), work_gs(2))
     864        15408 :          CALL pw_derive(work_gs(2), nd(:))
     865        20544 :          CALL pw_transfer(work_gs(2), df(i))
     866              :       END DO
     867              : 
     868        15408 :       DO i = 1, 2
     869        15408 :          CALL pw_pool%give_back_pw(work_gs(i))
     870              :       END DO
     871              : 
     872         5136 :       CALL timestop(handle)
     873              : 
     874         5136 :    END SUBROUTINE derive_fft
     875              : 
     876              : END MODULE dielectric_methods
        

Generated by: LCOV version 2.0-1