LCOV - code coverage report
Current view: top level - src/pw - pw_poisson_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:e08e82d) Lines: 65.6 % 556 365
Test Date: 2026-10-16 00:55:08 Functions: 62.1 % 29 18

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 CP2K developers group <https://cp2k.org>                                   !
       4              : !                                                                                                  !
       5              : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6              : !--------------------------------------------------------------------------------------------------!
       7              : 
       8              : ! **************************************************************************************************
       9              : !> \par History
      10              : !>      09.2005 created [fawzi]
      11              : !> \author fawzi
      12              : ! **************************************************************************************************
      13              : MODULE pw_poisson_methods
      14              : 
      15              :    USE cp_log_handling, ONLY: cp_to_string
      16              :    USE dielectric_methods, ONLY: dielectric_compute
      17              :    USE kinds, ONLY: dp
      18              :    USE mathconstants, ONLY: fourpi
      19              :    USE mt_util, ONLY: MT0D, &
      20              :                       MT1D, &
      21              :                       MT2D, mt2d_kernel_strain
      22              :    USE ps_implicit_methods, ONLY: implicit_poisson_solver_mixed, &
      23              :                                   implicit_poisson_solver_mixed_periodic, &
      24              :                                   implicit_poisson_solver_neumann, &
      25              :                                   implicit_poisson_solver_periodic, &
      26              :                                   ps_implicit_create
      27              :    USE ps_implicit_types, ONLY: MIXED_BC, &
      28              :                                 MIXED_PERIODIC_BC, &
      29              :                                 NEUMANN_BC, &
      30              :                                 PERIODIC_BC
      31              :    USE ps_wavelet_methods, ONLY: cp2k_distribution_to_z_slices, &
      32              :                                  ps_wavelet_create, &
      33              :                                  ps_wavelet_solve, &
      34              :                                  z_slices_to_cp2k_distribution
      35              :    USE ps_wavelet_types, ONLY: WAVELET0D, &
      36              :                                WAVELET1D, &
      37              :                                WAVELET2D, &
      38              :                                WAVELET3D, &
      39              :                                ps_wavelet_type
      40              :    USE pw_grid_types, ONLY: pw_grid_type
      41              :    USE pw_grids, ONLY: pw_grid_compare, &
      42              :                        pw_grid_release, &
      43              :                        pw_grid_retain
      44              :    USE pw_methods, ONLY: pw_copy, &
      45              :                          pw_derive, &
      46              :                          pw_integral_ab, &
      47              :                          pw_transfer, pw_multiply_with
      48              :    USE pw_poisson_types, ONLY: &
      49              :       ANALYTIC0D, ANALYTIC1D, ANALYTIC2D, MULTIPOLE0D, PERIODIC3D, PS_IMPLICIT, do_ewald_spme, &
      50              :       greens_fn_type, pw_green_create, pw_green_release, pw_poisson_analytic, &
      51              :       pw_poisson_implicit, pw_poisson_mt, pw_poisson_multipole, pw_poisson_none, &
      52              :       pw_poisson_parameter_type, pw_poisson_periodic, pw_poisson_type, pw_poisson_wavelet
      53              :    USE pw_pool_types, ONLY: pw_pool_p_type, &
      54              :                             pw_pool_type, &
      55              :                             pw_pools_copy, &
      56              :                             pw_pools_dealloc
      57              :    USE pw_types, ONLY: &
      58              :       pw_r3d_rs_type, pw_c1d_gs_type, pw_r3d_rs_type
      59              : #include "../base/base_uses.f90"
      60              : 
      61              :    IMPLICIT NONE
      62              :    PRIVATE
      63              : 
      64              :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
      65              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pw_poisson_methods'
      66              : 
      67              :    PUBLIC :: pw_poisson_rebuild, &
      68              :              pw_poisson_solve, pw_poisson_set, pw_func_u_convolution
      69              : 
      70              :    INTEGER, PARAMETER                       :: use_rs_grid = 0, &
      71              :                                                use_gs_grid = 1
      72              : 
      73              :    INTERFACE pw_poisson_rebuild
      74              :       MODULE PROCEDURE pw_poisson_rebuild_nodens
      75              :       MODULE PROCEDURE pw_poisson_rebuild_c1d_gs, pw_poisson_rebuild_r3d_rs
      76              :    END INTERFACE
      77              : 
      78              :    INTERFACE pw_poisson_solve
      79              :       #:for kindd in ['r3d_rs', 'c1d_gs']
      80              :          MODULE PROCEDURE pw_poisson_solve_nov_nodv_${kindd}$
      81              :          #:for kindv in ['r3d_rs', 'c1d_gs']
      82              :             MODULE PROCEDURE pw_poisson_solve_v_nodv_${kindd}$_${kindv}$
      83              :          #:endfor
      84              :          #:for kindg in ['r3d_rs', 'c1d_gs']
      85              :             MODULE PROCEDURE pw_poisson_solve_nov_dv_${kindd}$_${kindg}$
      86              :             #:for kindv in ['r3d_rs', 'c1d_gs']
      87              :                MODULE PROCEDURE pw_poisson_solve_v_dv_${kindd}$_${kindv}$_${kindg}$
      88              :             #:endfor
      89              :          #:endfor
      90              :       #:endfor
      91              :    END INTERFACE
      92              : 
      93              :    INTERFACE mt2d_hartree_stress
      94              :       MODULE PROCEDURE mt2d_hartree_stress_r3d_rs, mt2d_hartree_stress_c1d_gs
      95              :    END INTERFACE
      96              : 
      97              : CONTAINS
      98              : 
      99              : ! **************************************************************************************************
     100              : !> \brief removes all the object created from the parameters pw_pools and cell
     101              : !>      and used to solve the poisson equation like the green function and
     102              : !>      all the things allocated in pw_poisson_rebuild
     103              : !> \param poisson_env ...
     104              : !> \par History
     105              : !>      none
     106              : ! **************************************************************************************************
     107        75057 :    SUBROUTINE pw_poisson_cleanup(poisson_env)
     108              :       TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     109              : 
     110              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
     111              : 
     112        75057 :       NULLIFY (pw_pool)
     113        75057 :       IF (ASSOCIATED(poisson_env%pw_pools)) THEN
     114        62022 :          pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
     115              :       END IF
     116        75057 :       IF (ASSOCIATED(poisson_env%green_fft)) THEN
     117        10506 :          CALL pw_green_release(poisson_env%green_fft, pw_pool=pw_pool)
     118        10506 :          DEALLOCATE (poisson_env%green_fft)
     119              :       END IF
     120        75057 :       poisson_env%rebuild = .TRUE.
     121              : 
     122        75057 :    END SUBROUTINE pw_poisson_cleanup
     123              : 
     124              : ! **************************************************************************************************
     125              : !> \brief checks if pw_poisson_rebuild has to be called and calls it if needed
     126              : !> \param poisson_env the object to be checked
     127              : !> \author fawzi
     128              : ! **************************************************************************************************
     129        27989 :    SUBROUTINE pw_poisson_check(poisson_env)
     130              :       TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     131              : 
     132              :       LOGICAL                                            :: rebuild
     133              :       TYPE(greens_fn_type), POINTER                      :: green
     134              :       TYPE(ps_wavelet_type), POINTER                     :: wavelet
     135              : 
     136        27989 :       CPASSERT(ASSOCIATED(poisson_env%pw_pools))
     137        55978 :       CPASSERT(poisson_env%pw_level >= LBOUND(poisson_env%pw_pools, 1))
     138        55978 :       CPASSERT(poisson_env%pw_level <= UBOUND(poisson_env%pw_pools, 1))
     139        27989 :       green => poisson_env%green_fft
     140        27989 :       wavelet => poisson_env%wavelet
     141        27989 :       rebuild = poisson_env%rebuild
     142              :       rebuild = rebuild .OR. (poisson_env%method /= poisson_env%parameters%solver) &
     143        27989 :                 .OR. .NOT. ASSOCIATED(green)
     144        27989 :       poisson_env%method = poisson_env%parameters%solver
     145              : 
     146        27989 :       IF (poisson_env%method == pw_poisson_wavelet) THEN
     147          964 :          poisson_env%used_grid = use_rs_grid
     148              :       ELSE
     149        27025 :          poisson_env%used_grid = use_gs_grid
     150              :       END IF
     151        27989 :       IF (.NOT. rebuild) THEN
     152            0 :          IF (poisson_env%parameters%ewald_type == do_ewald_spme) THEN
     153            0 :             rebuild = (poisson_env%parameters%ewald_alpha /= green%p3m_alpha) .OR. rebuild
     154            0 :             rebuild = (poisson_env%parameters%ewald_o_spline /= green%p3m_order) .OR. rebuild
     155              :          END IF
     156            0 :          SELECT CASE (poisson_env%method)
     157              :          CASE (pw_poisson_analytic)
     158            0 :             SELECT CASE (green%method)
     159              :             CASE (ANALYTIC0D, ANALYTIC1D, ANALYTIC2D, PERIODIC3D)
     160              :             CASE default
     161            0 :                rebuild = .TRUE.
     162              :             END SELECT
     163              :          CASE (pw_poisson_mt)
     164            0 :             SELECT CASE (green%method)
     165              :             CASE (MT0D, MT1D, MT2D)
     166              :             CASE default
     167            0 :                rebuild = .TRUE.
     168              :             END SELECT
     169            0 :             rebuild = (poisson_env%parameters%mt_alpha /= green%mt_alpha) .OR. rebuild
     170              :          CASE (pw_poisson_wavelet)
     171            0 :             rebuild = (poisson_env%parameters%wavelet_scf_type /= wavelet%itype_scf) .OR. rebuild
     172              :          CASE default
     173            0 :             CPABORT("Unknown Poisson solver")
     174              :          END SELECT
     175              :       END IF
     176            0 :       IF (rebuild) THEN
     177        27989 :          poisson_env%rebuild = .TRUE.
     178        27989 :          CALL pw_poisson_cleanup(poisson_env)
     179              :       END IF
     180        27989 :    END SUBROUTINE pw_poisson_check
     181              : 
     182              : ! **************************************************************************************************
     183              : !> \brief rebuilds all the internal values needed to use the poisson solver
     184              : !> \param poisson_env the environment to rebuild
     185              : !> \param density ...
     186              : !> \author fawzi
     187              : !> \note
     188              : !>      rebuilds if poisson_env%rebuild is true
     189              : ! **************************************************************************************************
     190        78736 :    SUBROUTINE pw_poisson_rebuild_nodens(poisson_env)
     191              :       TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     192              : 
     193              :       CHARACTER(len=*), PARAMETER :: routineN = 'pw_poisson_rebuild'
     194              : 
     195              :       INTEGER                                            :: handle
     196              : 
     197        78736 :       CALL timeset(routineN, handle)
     198              : 
     199        78736 :       CPASSERT(ASSOCIATED(poisson_env%pw_pools))
     200              : 
     201        78736 :       IF (poisson_env%rebuild) THEN
     202        12316 :          CALL pw_poisson_cleanup(poisson_env)
     203        24632 :          SELECT CASE (poisson_env%parameters%solver)
     204              :          CASE (pw_poisson_periodic, pw_poisson_analytic, pw_poisson_mt, pw_poisson_multipole)
     205        12316 :             ALLOCATE (poisson_env%green_fft)
     206              :             CALL pw_green_create(poisson_env%green_fft, cell_hmat=poisson_env%cell_hmat, &
     207              :                                  pw_pool=poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     208              :                                  poisson_params=poisson_env%parameters, &
     209              :                                  mt_super_ref_pw_grid=poisson_env%mt_super_ref_pw_grid, &
     210        12316 :                                  dct_pw_grid=poisson_env%dct_pw_grid)
     211              :          CASE (pw_poisson_wavelet)
     212            0 :             CPABORT("Wavelet solver requires a density!")
     213              :          CASE (pw_poisson_implicit)
     214            0 :             ALLOCATE (poisson_env%green_fft)
     215              :             CALL pw_green_create(poisson_env%green_fft, cell_hmat=poisson_env%cell_hmat, &
     216              :                                  pw_pool=poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     217              :                                  poisson_params=poisson_env%parameters, &
     218              :                                  mt_super_ref_pw_grid=poisson_env%mt_super_ref_pw_grid, &
     219            0 :                                  dct_pw_grid=poisson_env%dct_pw_grid)
     220              :             CALL ps_implicit_create(poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     221              :                                     poisson_env%parameters, &
     222              :                                     poisson_env%dct_pw_grid, &
     223            0 :                                     poisson_env%green_fft, poisson_env%implicit_env)
     224              :          CASE (pw_poisson_none)
     225              :          CASE default
     226        12316 :             CPABORT("Unknown Poisson solver")
     227              :          END SELECT
     228        12316 :          poisson_env%rebuild = .FALSE.
     229              :       END IF
     230              : 
     231        78736 :       CALL timestop(handle)
     232              : 
     233        78736 :    END SUBROUTINE pw_poisson_rebuild_nodens
     234              : 
     235              :    #:for kindd in ["r3d_rs", "c1d_gs"]
     236              : ! **************************************************************************************************
     237              : !> \brief rebuilds all the internal values needed to use the poisson solver
     238              : !> \param poisson_env the environment to rebuild
     239              : !> \param density ...
     240              : !> \author fawzi
     241              : !> \note
     242              : !>      rebuilds if poisson_env%rebuild is true
     243              : ! **************************************************************************************************
     244       305494 :       SUBROUTINE pw_poisson_rebuild_${kindd}$ (poisson_env, density)
     245              :          TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     246              :          TYPE(pw_${kindd}$_type), INTENT(IN)                :: density
     247              : 
     248              :          CHARACTER(len=*), PARAMETER :: routineN = 'pw_poisson_rebuild'
     249              : 
     250              :          INTEGER                                            :: handle
     251              : 
     252       305494 :          CALL timeset(routineN, handle)
     253              : 
     254       305494 :          CPASSERT(ASSOCIATED(poisson_env%pw_pools))
     255              : 
     256       305494 :          IF (poisson_env%rebuild) THEN
     257         8473 :             CALL pw_poisson_cleanup(poisson_env)
     258        15942 :             SELECT CASE (poisson_env%parameters%solver)
     259              :             CASE (pw_poisson_periodic, pw_poisson_analytic, pw_poisson_mt, pw_poisson_multipole)
     260         7469 :                ALLOCATE (poisson_env%green_fft)
     261              :                CALL pw_green_create(poisson_env%green_fft, cell_hmat=poisson_env%cell_hmat, &
     262              :                                     pw_pool=poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     263              :                                     poisson_params=poisson_env%parameters, &
     264              :                                     mt_super_ref_pw_grid=poisson_env%mt_super_ref_pw_grid, &
     265         7469 :                                     dct_pw_grid=poisson_env%dct_pw_grid)
     266              :             CASE (pw_poisson_wavelet)
     267          948 :                CPASSERT(ASSOCIATED(density%pw_grid))
     268              :                CALL ps_wavelet_create(poisson_env%parameters, poisson_env%wavelet, &
     269          948 :                                       density%pw_grid)
     270              :             CASE (pw_poisson_implicit)
     271           56 :                ALLOCATE (poisson_env%green_fft)
     272              :                CALL pw_green_create(poisson_env%green_fft, cell_hmat=poisson_env%cell_hmat, &
     273              :                                     pw_pool=poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     274              :                                     poisson_params=poisson_env%parameters, &
     275              :                                     mt_super_ref_pw_grid=poisson_env%mt_super_ref_pw_grid, &
     276           56 :                                     dct_pw_grid=poisson_env%dct_pw_grid)
     277              :                CALL ps_implicit_create(poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     278              :                                        poisson_env%parameters, &
     279              :                                        poisson_env%dct_pw_grid, &
     280           56 :                                        poisson_env%green_fft, poisson_env%implicit_env)
     281              :             CASE (pw_poisson_none)
     282              :             CASE default
     283         8473 :                CPABORT("Unknown Poisson solver")
     284              :             END SELECT
     285         8473 :             poisson_env%rebuild = .FALSE.
     286              :          END IF
     287              : 
     288       305494 :          CALL timestop(handle)
     289              : 
     290       305494 :       END SUBROUTINE pw_poisson_rebuild_${kindd}$
     291              :    #:endfor
     292              : 
     293              :    #:for kindd in ['r3d_rs', 'c1d_gs']
     294              : ! **************************************************************************************************
     295              : !> \brief Solve Poisson equation in a plane wave basis set
     296              : !>      Obtains electrostatic potential and its derivatives with respect to r
     297              : !>      from the density
     298              : !> \param poisson_env ...
     299              : !> \param density ...
     300              : !> \param ehartree ...
     301              : !> \param h_stress ...
     302              : !> \param rho_core ...
     303              : !> \param greenfn ...
     304              : !> \param aux_density Hartree energy and stress tensor between 2 different densities
     305              : !> \par History
     306              : !>      JGH (13-Mar-2001) : completely revised
     307              : !> \author apsi
     308              : ! **************************************************************************************************
     309           16 :       SUBROUTINE pw_poisson_solve_nov_nodv_${kindd}$ (poisson_env, density, ehartree, &
     310              :                                                       h_stress, rho_core, greenfn, aux_density)
     311              : 
     312              :          TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     313              :          TYPE(pw_${kindd}$_type), INTENT(IN)                          :: density
     314              :          REAL(kind=dp), INTENT(out), OPTIONAL               :: ehartree
     315              :          REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), &
     316              :             OPTIONAL                                        :: h_stress
     317              :          TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL                :: rho_core, greenfn
     318              :          TYPE(pw_${kindd}$_type), INTENT(IN), OPTIONAL :: aux_density
     319              : 
     320              :          CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_poisson_solve'
     321              : 
     322              :          INTEGER                                            :: handle
     323              :          LOGICAL                                            :: has_dielectric
     324              :          TYPE(pw_grid_type), POINTER                        :: pw_grid
     325              :          TYPE(pw_pool_type), POINTER                        :: pw_pool
     326              :          TYPE(pw_r3d_rs_type)                                    ::             rhor, vhartree_rs
     327              :          TYPE(pw_c1d_gs_type) :: influence_fn, rhog, rhog_aux, tmpg
     328              : 
     329           16 :          CALL timeset(routineN, handle)
     330              : 
     331           16 :          CALL pw_poisson_rebuild(poisson_env, density)
     332              : 
     333           16 :          has_dielectric = poisson_env%parameters%has_dielectric
     334              : 
     335              :          ! point pw
     336           16 :          pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
     337           16 :          pw_grid => pw_pool%pw_grid
     338              :          ! density in G space
     339           16 :          CALL pw_pool%create_pw(rhog)
     340           16 :          IF (PRESENT(aux_density)) THEN
     341           16 :             CALL pw_pool%create_pw(rhog_aux)
     342              :          END IF
     343              : 
     344           32 :          SELECT CASE (poisson_env%used_grid)
     345              :          CASE (use_gs_grid)
     346              : 
     347           32 :             SELECT CASE (poisson_env%green_fft%method)
     348              :             CASE (PERIODIC3D, ANALYTIC2D, ANALYTIC1D, ANALYTIC0D, MT2D, MT1D, MT0D, MULTIPOLE0D)
     349              : 
     350           16 :                CALL pw_transfer(density, rhog)
     351           16 :                IF (PRESENT(aux_density)) THEN
     352           16 :                   CALL pw_transfer(aux_density, rhog_aux)
     353              :                END IF
     354           16 :                IF (PRESENT(ehartree)) THEN
     355            8 :                   CALL pw_pool%create_pw(tmpg)
     356            8 :                   CALL pw_copy(rhog, tmpg)
     357              :                END IF
     358           16 :                IF (PRESENT(greenfn)) THEN
     359            0 :                   influence_fn = greenfn
     360              :                ELSE
     361           16 :                   influence_fn = poisson_env%green_fft%influence_fn
     362              :                END IF
     363           16 :                CALL pw_multiply_with(rhog, influence_fn)
     364           16 :                IF (PRESENT(aux_density)) THEN
     365           16 :                   CALL pw_multiply_with(rhog_aux, influence_fn)
     366              :                END IF
     367           16 :                IF (PRESENT(ehartree)) THEN
     368            8 :                   IF (PRESENT(aux_density)) THEN
     369            8 :                      ehartree = 0.5_dp*pw_integral_ab(rhog_aux, tmpg)
     370              :                   ELSE
     371            0 :                      ehartree = 0.5_dp*pw_integral_ab(rhog, tmpg)
     372              :                   END IF
     373            8 :                   CALL pw_pool%give_back_pw(tmpg)
     374              :                END IF
     375              : 
     376              :             CASE (PS_IMPLICIT)
     377              : 
     378            0 :                IF (PRESENT(h_stress)) THEN
     379            0 :                   CPABORT("No stress tensor is implemented for the implicit Poisson solver.")
     380              :                END IF
     381              : 
     382            0 :                IF (has_dielectric .AND. PRESENT(rho_core)) THEN
     383            0 :                   SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
     384              :                   CASE (PERIODIC_BC, MIXED_PERIODIC_BC)
     385              :                      CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
     386              :                                              poisson_env%diel_rs_grid, &
     387              :                                              poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     388            0 :                                              density, rho_core=rho_core)
     389              :                   CASE (NEUMANN_BC, MIXED_BC)
     390              :                      CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
     391              :                                              poisson_env%diel_rs_grid, &
     392              :                                              poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     393              :                                              poisson_env%dct_pw_grid, &
     394              :                                              poisson_env%parameters%ps_implicit_params%neumann_directions, &
     395              :                                              poisson_env%implicit_env%dct_env%recv_msgs_bnds, &
     396              :                                              poisson_env%implicit_env%dct_env%dests_expand, &
     397              :                                              poisson_env%implicit_env%dct_env%srcs_expand, &
     398              :                                              poisson_env%implicit_env%dct_env%flipg_stat, &
     399              :                                              poisson_env%implicit_env%dct_env%bounds_shftd, &
     400            0 :                                              density, rho_core=rho_core)
     401              :                   END SELECT
     402              :                END IF
     403              : 
     404            0 :                CALL pw_pool%create_pw(rhor)
     405            0 :                CALL pw_pool%create_pw(vhartree_rs)
     406            0 :                CALL pw_transfer(density, rhor)
     407              : 
     408            0 :                SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
     409              :                CASE (PERIODIC_BC)
     410              :                   CALL implicit_poisson_solver_periodic(poisson_env, rhor, vhartree_rs, &
     411            0 :                                                         ehartree=ehartree)
     412              :                CASE (NEUMANN_BC)
     413              :                   CALL implicit_poisson_solver_neumann(poisson_env, rhor, vhartree_rs, &
     414            0 :                                                        ehartree=ehartree)
     415              :                CASE (MIXED_PERIODIC_BC)
     416              :                   CALL implicit_poisson_solver_mixed_periodic(poisson_env, rhor, vhartree_rs, &
     417            0 :                                                               electric_enthalpy=ehartree)
     418              :                CASE (MIXED_BC)
     419              :                   CALL implicit_poisson_solver_mixed(poisson_env, rhor, vhartree_rs, &
     420            0 :                                                      electric_enthalpy=ehartree)
     421              :                END SELECT
     422              : 
     423            0 :                IF (PRESENT(aux_density)) THEN
     424            0 :                   CALL pw_transfer(aux_density, rhor)
     425            0 :                   ehartree = 0.5_dp*pw_integral_ab(rhor, vhartree_rs)
     426              :                END IF
     427              : 
     428            0 :                CALL pw_pool%give_back_pw(rhor)
     429            0 :                CALL pw_pool%give_back_pw(vhartree_rs)
     430              : 
     431              :             CASE DEFAULT
     432              :                CALL cp_abort(__LOCATION__, &
     433              :                              "unknown poisson method "// &
     434           16 :                              cp_to_string(poisson_env%green_fft%method))
     435              :             END SELECT
     436              : 
     437              :          CASE (use_rs_grid)
     438              : 
     439            0 :             CALL pw_pool%create_pw(rhor)
     440            0 :             CALL pw_transfer(density, rhor)
     441            0 :             CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
     442            0 :             CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
     443            0 :             CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
     444            0 :             IF (PRESENT(ehartree)) THEN
     445            0 :                IF (PRESENT(aux_density)) THEN
     446              :                   #:if kindd=="r3d_rs"
     447            0 :                      ehartree = 0.5_dp*pw_integral_ab(aux_density, rhor)
     448              :                   #:else
     449            0 :                      IF (.NOT. PRESENT(h_stress)) CALL pw_pool%create_pw(rhog)
     450            0 :                      CALL pw_transfer(rhor, rhog)
     451            0 :                      ehartree = 0.5_dp*pw_integral_ab(aux_density, rhog)
     452            0 :                      IF (.NOT. PRESENT(h_stress)) CALL pw_pool%give_back_pw(rhog)
     453              :                   #:endif
     454              :                ELSE
     455              :                   #:if kindd=="r3d_rs"
     456            0 :                      ehartree = 0.5_dp*pw_integral_ab(density, rhor)
     457              :                   #:else
     458            0 :                      IF (.NOT. PRESENT(h_stress)) CALL pw_pool%create_pw(rhog)
     459            0 :                      CALL pw_transfer(rhor, rhog)
     460            0 :                      ehartree = 0.5_dp*pw_integral_ab(density, rhog)
     461            0 :                      IF (.NOT. PRESENT(h_stress)) CALL pw_pool%give_back_pw(rhog)
     462              :                   #:endif
     463              :                END IF
     464              :             END IF
     465            0 :             IF (PRESENT(h_stress)) THEN
     466            0 :                CALL pw_transfer(rhor, rhog)
     467            0 :                IF (PRESENT(aux_density)) THEN
     468            0 :                   CALL pw_transfer(aux_density, rhor)
     469            0 :                   CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
     470            0 :                   CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
     471            0 :                   CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
     472            0 :                   CALL pw_transfer(rhor, rhog_aux)
     473              :                END IF
     474              :             END IF
     475           16 :             CALL pw_pool%give_back_pw(rhor)
     476              : 
     477              :          END SELECT
     478              : 
     479           16 :          IF (PRESENT(aux_density)) THEN
     480           16 :             CALL calc_stress_and_gradient_${kindd}$ (poisson_env, rhog, ehartree, rhog_aux, h_stress)
     481              :          ELSE
     482            0 :             CALL calc_stress_and_gradient_${kindd}$ (poisson_env, rhog, ehartree, h_stress=h_stress)
     483              :          END IF
     484           16 :          CALL mt2d_hartree_stress(poisson_env, density, ehartree, h_stress, aux_density, greenfn)
     485              : 
     486           16 :          CALL pw_pool%give_back_pw(rhog)
     487           16 :          IF (PRESENT(aux_density)) THEN
     488           16 :             CALL pw_pool%give_back_pw(rhog_aux)
     489              :          END IF
     490              : 
     491           16 :          CALL timestop(handle)
     492              : 
     493           16 :       END SUBROUTINE pw_poisson_solve_nov_nodv_${kindd}$
     494              :    #:endfor
     495              : 
     496              :    #:for kindd in ['r3d_rs', 'c1d_gs']
     497              :       #:for kindv in ['r3d_rs', 'c1d_gs']
     498              : ! **************************************************************************************************
     499              : !> \brief Solve Poisson equation in a plane wave basis set
     500              : !>      Obtains electrostatic potential and its derivatives with respect to r
     501              : !>      from the density
     502              : !> \param poisson_env ...
     503              : !> \param density ...
     504              : !> \param ehartree ...
     505              : !> \param vhartree ...
     506              : !> \param h_stress ...
     507              : !> \param rho_core ...
     508              : !> \param greenfn ...
     509              : !> \param aux_density Hartree energy and stress tensor between 2 different densities
     510              : !> \par History
     511              : !>      JGH (13-Mar-2001) : completely revised
     512              : !> \author apsi
     513              : ! **************************************************************************************************
     514       238121 :          SUBROUTINE pw_poisson_solve_v_nodv_${kindd}$_${kindv}$ (poisson_env, density, ehartree, vhartree, &
     515              :                                                                  h_stress, rho_core, greenfn, aux_density)
     516              : 
     517              :             TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     518              :             TYPE(pw_${kindd}$_type), INTENT(IN)                          :: density
     519              :             REAL(kind=dp), INTENT(out), OPTIONAL               :: ehartree
     520              :             TYPE(pw_${kindv}$_type), INTENT(INOUT)             :: vhartree
     521              :             REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), &
     522              :                OPTIONAL                                        :: h_stress
     523              :             TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL                :: rho_core, greenfn
     524              :             TYPE(pw_${kindd}$_type), INTENT(IN), OPTIONAL :: aux_density
     525              : 
     526              :             CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_poisson_solve'
     527              : 
     528              :             INTEGER                                            :: handle
     529              :             LOGICAL                                            :: has_dielectric
     530              :             TYPE(pw_grid_type), POINTER                        :: pw_grid
     531              :             TYPE(pw_pool_type), POINTER                        :: pw_pool
     532              :             TYPE(pw_r3d_rs_type)                                      :: &
     533              :                rhor, vhartree_rs
     534              :             TYPE(pw_c1d_gs_type) :: influence_fn, rhog, rhog_aux
     535              : 
     536       238121 :             CALL timeset(routineN, handle)
     537              : 
     538       238121 :             CALL pw_poisson_rebuild(poisson_env, density)
     539              : 
     540       238121 :             has_dielectric = poisson_env%parameters%has_dielectric
     541              : 
     542              :             ! point pw
     543       238121 :             pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
     544       238121 :             pw_grid => pw_pool%pw_grid
     545       238121 :             IF (.NOT. pw_grid_compare(pw_pool%pw_grid, vhartree%pw_grid)) THEN
     546            0 :                CPABORT("vhartree has a different grid than the poisson solver")
     547              :             END IF
     548              :             ! density in G space
     549       238121 :             CALL pw_pool%create_pw(rhog)
     550       238121 :             IF (PRESENT(aux_density)) THEN
     551          408 :                CALL pw_pool%create_pw(rhog_aux)
     552              :             END IF
     553              : 
     554       442197 :             SELECT CASE (poisson_env%used_grid)
     555              :             CASE (use_gs_grid)
     556              : 
     557       441699 :                SELECT CASE (poisson_env%green_fft%method)
     558              :                CASE (PERIODIC3D, ANALYTIC2D, ANALYTIC1D, ANALYTIC0D, MT2D, MT1D, MT0D, MULTIPOLE0D)
     559              : 
     560       203578 :                   CALL pw_transfer(density, rhog)
     561       203578 :                   IF (PRESENT(aux_density)) THEN
     562          408 :                      CALL pw_transfer(aux_density, rhog_aux)
     563              :                   END IF
     564       203578 :                   IF (PRESENT(greenfn)) THEN
     565          302 :                      influence_fn = greenfn
     566              :                   ELSE
     567       203276 :                      influence_fn = poisson_env%green_fft%influence_fn
     568              :                   END IF
     569       203578 :                   CALL pw_multiply_with(rhog, influence_fn)
     570       203578 :                   IF (PRESENT(aux_density)) THEN
     571          408 :                      CALL pw_multiply_with(rhog_aux, influence_fn)
     572              :                   END IF
     573       203578 :                   CALL pw_transfer(rhog, vhartree)
     574       203578 :                   IF (PRESENT(ehartree)) THEN
     575       153368 :                      IF (PRESENT(aux_density)) THEN
     576              :                         #:if kindd==kindv
     577          408 :                            ehartree = 0.5_dp*pw_integral_ab(aux_density, vhartree)
     578              :                         #:elif kindd=="c1d_gs"
     579            0 :                            ehartree = 0.5_dp*pw_integral_ab(aux_density, rhog)
     580              :                         #:else
     581            0 :                            CALL pw_transfer(aux_density, rhog)
     582            0 :                            ehartree = 0.5_dp*pw_integral_ab(rhog, vhartree)
     583              :                         #:endif
     584              :                      ELSE
     585              :                         #:if kindd==kindv
     586       152960 :                            ehartree = 0.5_dp*pw_integral_ab(density, vhartree)
     587              :                         #:elif kindd=="c1d_gs"
     588            0 :                            ehartree = 0.5_dp*pw_integral_ab(density, rhog)
     589              :                         #:else
     590            0 :                            CALL pw_transfer(density, rhog)
     591            0 :                            ehartree = 0.5_dp*pw_integral_ab(rhog, vhartree)
     592              :                         #:endif
     593              :                      END IF
     594              :                   END IF
     595              : 
     596              :                CASE (PS_IMPLICIT)
     597          498 :                   IF (PRESENT(h_stress)) THEN
     598            0 :                      CPABORT("No stress tensor is implemented for the implicit Poisson solver.")
     599              :                   END IF
     600              : 
     601          498 :                   IF (has_dielectric .AND. PRESENT(rho_core)) THEN
     602          748 :                      SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
     603              :                      CASE (PERIODIC_BC, MIXED_PERIODIC_BC)
     604              :                         CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
     605              :                                                 poisson_env%diel_rs_grid, &
     606              :                                                 poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     607          296 :                                                 density, rho_core=rho_core)
     608              :                      CASE (NEUMANN_BC, MIXED_BC)
     609              :                         CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
     610              :                                                 poisson_env%diel_rs_grid, &
     611              :                                                 poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     612              :                                                 poisson_env%dct_pw_grid, &
     613              :                                                 poisson_env%parameters%ps_implicit_params%neumann_directions, &
     614              :                                                 poisson_env%implicit_env%dct_env%recv_msgs_bnds, &
     615              :                                                 poisson_env%implicit_env%dct_env%dests_expand, &
     616              :                                                 poisson_env%implicit_env%dct_env%srcs_expand, &
     617              :                                                 poisson_env%implicit_env%dct_env%flipg_stat, &
     618              :                                                 poisson_env%implicit_env%dct_env%bounds_shftd, &
     619          452 :                                                 density, rho_core=rho_core)
     620              :                      END SELECT
     621              :                   END IF
     622              : 
     623          498 :                   CALL pw_pool%create_pw(rhor)
     624          498 :                   CALL pw_pool%create_pw(vhartree_rs)
     625          498 :                   CALL pw_transfer(density, rhor)
     626              : 
     627          648 :                   SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
     628              :                   CASE (PERIODIC_BC)
     629              :                      CALL implicit_poisson_solver_periodic(poisson_env, rhor, vhartree_rs, &
     630          174 :                                                            ehartree=ehartree)
     631              :                   CASE (NEUMANN_BC)
     632              :                      CALL implicit_poisson_solver_neumann(poisson_env, rhor, vhartree_rs, &
     633          216 :                                                           ehartree=ehartree)
     634              :                   CASE (MIXED_PERIODIC_BC)
     635              :                      CALL implicit_poisson_solver_mixed_periodic(poisson_env, rhor, vhartree_rs, &
     636          324 :                                                                  electric_enthalpy=ehartree)
     637              :                   CASE (MIXED_BC)
     638              :                      CALL implicit_poisson_solver_mixed(poisson_env, rhor, vhartree_rs, &
     639          498 :                                                         electric_enthalpy=ehartree)
     640              :                   END SELECT
     641              : 
     642          498 :                   IF (PRESENT(aux_density)) THEN
     643            0 :                      CALL pw_transfer(aux_density, rhor)
     644            0 :                      ehartree = 0.5_dp*pw_integral_ab(rhor, vhartree_rs)
     645              :                   END IF
     646              : 
     647          498 :                   CALL pw_transfer(vhartree_rs, vhartree)
     648              : 
     649          498 :                   CALL pw_pool%give_back_pw(rhor)
     650          498 :                   CALL pw_pool%give_back_pw(vhartree_rs)
     651              : 
     652              :                CASE DEFAULT
     653              :                   CALL cp_abort(__LOCATION__, &
     654              :                                 "unknown poisson method "// &
     655       204076 :                                 cp_to_string(poisson_env%green_fft%method))
     656              :                END SELECT
     657              : 
     658              :             CASE (use_rs_grid)
     659              : 
     660        34045 :                CALL pw_pool%create_pw(rhor)
     661        34045 :                CALL pw_transfer(density, rhor)
     662        34045 :                CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
     663        34045 :                CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
     664        34045 :                CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
     665        34045 :                CALL pw_transfer(rhor, vhartree)
     666        34045 :                IF (PRESENT(ehartree)) THEN
     667        10166 :                   IF (PRESENT(aux_density)) THEN
     668              :                      #:if kindd==kindv
     669            0 :                         ehartree = 0.5_dp*pw_integral_ab(aux_density, vhartree)
     670              :                      #:elif kindd=="r3d_rs"
     671            0 :                         ehartree = 0.5_dp*pw_integral_ab(aux_density, rhor)
     672              :                      #:else
     673            0 :                         CALL pw_transfer(vhartree, rhog)
     674            0 :                         ehartree = 0.5_dp*pw_integral_ab(aux_density, rhog)
     675              :                      #:endif
     676              :                   ELSE
     677              :                      #:if kindd==kindv
     678        10166 :                         ehartree = 0.5_dp*pw_integral_ab(density, vhartree)
     679              :                      #:elif kindd=="r3d_rs"
     680            0 :                         ehartree = 0.5_dp*pw_integral_ab(density, rhor)
     681              :                      #:else
     682            0 :                         CALL pw_transfer(vhartree, rhog)
     683            0 :                         ehartree = 0.5_dp*pw_integral_ab(density, rhog)
     684              :                      #:endif
     685              :                   END IF
     686              :                END IF
     687        34045 :                IF (PRESENT(h_stress)) THEN
     688           12 :                   CALL pw_transfer(rhor, rhog)
     689           12 :                   IF (PRESENT(aux_density)) THEN
     690            0 :                      CALL pw_transfer(aux_density, rhor)
     691            0 :                      CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
     692            0 :                      CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
     693            0 :                      CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
     694            0 :                      CALL pw_transfer(rhor, rhog_aux)
     695              :                   END IF
     696              :                END IF
     697       272166 :                CALL pw_pool%give_back_pw(rhor)
     698              : 
     699              :             END SELECT
     700              : 
     701       238121 :             IF (PRESENT(aux_density)) THEN
     702          408 :                CALL calc_stress_and_gradient_${kindd}$ (poisson_env, rhog, ehartree, rhog_aux, h_stress)
     703              :             ELSE
     704       237713 :                CALL calc_stress_and_gradient_${kindd}$ (poisson_env, rhog, ehartree, h_stress=h_stress)
     705              :             END IF
     706       238121 :             CALL mt2d_hartree_stress(poisson_env, density, ehartree, h_stress, aux_density, greenfn)
     707              : 
     708       238121 :             CALL pw_pool%give_back_pw(rhog)
     709       238121 :             IF (PRESENT(aux_density)) THEN
     710          408 :                CALL pw_pool%give_back_pw(rhog_aux)
     711              :             END IF
     712              : 
     713       238121 :             CALL timestop(handle)
     714              : 
     715       238121 :          END SUBROUTINE pw_poisson_solve_v_nodv_${kindd}$_${kindv}$
     716              :       #:endfor
     717              :    #:endfor
     718              : 
     719              :    #:for kindd in ['r3d_rs', 'c1d_gs']
     720              :       #:for kindg in ['r3d_rs', 'c1d_gs']
     721              : ! **************************************************************************************************
     722              : !> \brief Solve Poisson equation in a plane wave basis set
     723              : !>      Obtains electrostatic potential and its derivatives with respect to r
     724              : !>      from the density
     725              : !> \param poisson_env ...
     726              : !> \param density ...
     727              : !> \param ehartree ...
     728              : !> \param dvhartree ...
     729              : !> \param h_stress ...
     730              : !> \param rho_core ...
     731              : !> \param greenfn ...
     732              : !> \param aux_density Hartree energy and stress tensor between 2 different densities
     733              : !> \par History
     734              : !>      JGH (13-Mar-2001) : completely revised
     735              : !> \author apsi
     736              : ! **************************************************************************************************
     737            8 :          SUBROUTINE pw_poisson_solve_nov_dv_${kindd}$_${kindg}$ (poisson_env, density, ehartree, &
     738              :                                                                  dvhartree, h_stress, rho_core, greenfn, aux_density)
     739              : 
     740              :             TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     741              :             TYPE(pw_${kindd}$_type), INTENT(IN)                          :: density
     742              :             REAL(kind=dp), INTENT(out), OPTIONAL               :: ehartree
     743              :             TYPE(pw_${kindg}$_type), DIMENSION(3)              :: dvhartree
     744              :             REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), &
     745              :                OPTIONAL                                        :: h_stress
     746              :             TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL                :: rho_core, greenfn
     747              :             TYPE(pw_${kindd}$_type), INTENT(IN), OPTIONAL :: aux_density
     748              : 
     749              :             CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_poisson_solve'
     750              : 
     751              :             INTEGER                                            :: handle
     752              :             LOGICAL                                            :: has_dielectric
     753              :             TYPE(pw_grid_type), POINTER                        :: pw_grid
     754              :             TYPE(pw_pool_type), POINTER                        :: pw_pool
     755              :             TYPE(pw_r3d_rs_type)                                      :: &
     756              :                rhor, vhartree_rs
     757              :             TYPE(pw_c1d_gs_type) :: influence_fn, rhog, rhog_aux, tmpg
     758              : 
     759            8 :             CALL timeset(routineN, handle)
     760              : 
     761            8 :             CALL pw_poisson_rebuild(poisson_env, density)
     762              : 
     763            8 :             has_dielectric = poisson_env%parameters%has_dielectric
     764              : 
     765              :             ! point pw
     766            8 :             pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
     767            8 :             pw_grid => pw_pool%pw_grid
     768              :             ! density in G space
     769            8 :             CALL pw_pool%create_pw(rhog)
     770            8 :             IF (PRESENT(aux_density)) THEN
     771            8 :                CALL pw_pool%create_pw(rhog_aux)
     772              :             END IF
     773              : 
     774           16 :             SELECT CASE (poisson_env%used_grid)
     775              :             CASE (use_gs_grid)
     776              : 
     777           16 :                SELECT CASE (poisson_env%green_fft%method)
     778              :                CASE (PERIODIC3D, ANALYTIC2D, ANALYTIC1D, ANALYTIC0D, MT2D, MT1D, MT0D, MULTIPOLE0D)
     779              : 
     780            8 :                   CALL pw_transfer(density, rhog)
     781            8 :                   IF (PRESENT(aux_density)) THEN
     782            8 :                      CALL pw_transfer(aux_density, rhog_aux)
     783              :                   END IF
     784            8 :                   IF (PRESENT(ehartree)) THEN
     785            8 :                      CALL pw_pool%create_pw(tmpg)
     786            8 :                      CALL pw_copy(rhog, tmpg)
     787              :                   END IF
     788            8 :                   IF (PRESENT(greenfn)) THEN
     789            0 :                      influence_fn = greenfn
     790              :                   ELSE
     791            8 :                      influence_fn = poisson_env%green_fft%influence_fn
     792              :                   END IF
     793            8 :                   CALL pw_multiply_with(rhog, influence_fn)
     794            8 :                   IF (PRESENT(aux_density)) THEN
     795            8 :                      CALL pw_multiply_with(rhog_aux, influence_fn)
     796              :                   END IF
     797            8 :                   IF (PRESENT(ehartree)) THEN
     798            8 :                      IF (PRESENT(aux_density)) THEN
     799            8 :                         ehartree = 0.5_dp*pw_integral_ab(rhog_aux, tmpg)
     800              :                      ELSE
     801            0 :                         ehartree = 0.5_dp*pw_integral_ab(rhog, tmpg)
     802              :                      END IF
     803            8 :                      CALL pw_pool%give_back_pw(tmpg)
     804              :                   END IF
     805              : 
     806              :                CASE (PS_IMPLICIT)
     807            0 :                   IF (PRESENT(h_stress)) THEN
     808            0 :                      CPABORT("No stress tensor is implemented for the implicit Poisson solver.")
     809              :                   END IF
     810              : 
     811            0 :                   IF (has_dielectric .AND. PRESENT(rho_core)) THEN
     812            0 :                      SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
     813              :                      CASE (PERIODIC_BC, MIXED_PERIODIC_BC)
     814              :                         CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
     815              :                                                 poisson_env%diel_rs_grid, &
     816              :                                                 poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     817            0 :                                                 density, rho_core=rho_core)
     818              :                      CASE (NEUMANN_BC, MIXED_BC)
     819              :                         CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
     820              :                                                 poisson_env%diel_rs_grid, &
     821              :                                                 poisson_env%pw_pools(poisson_env%pw_level)%pool, &
     822              :                                                 poisson_env%dct_pw_grid, &
     823              :                                                 poisson_env%parameters%ps_implicit_params%neumann_directions, &
     824              :                                                 poisson_env%implicit_env%dct_env%recv_msgs_bnds, &
     825              :                                                 poisson_env%implicit_env%dct_env%dests_expand, &
     826              :                                                 poisson_env%implicit_env%dct_env%srcs_expand, &
     827              :                                                 poisson_env%implicit_env%dct_env%flipg_stat, &
     828              :                                                 poisson_env%implicit_env%dct_env%bounds_shftd, &
     829            0 :                                                 density, rho_core=rho_core)
     830              :                      END SELECT
     831              :                   END IF
     832              : 
     833            0 :                   CALL pw_pool%create_pw(rhor)
     834            0 :                   CALL pw_pool%create_pw(vhartree_rs)
     835            0 :                   CALL pw_transfer(density, rhor)
     836              : 
     837            0 :                   SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
     838              :                   CASE (PERIODIC_BC)
     839              :                      CALL implicit_poisson_solver_periodic(poisson_env, rhor, vhartree_rs, &
     840            0 :                                                            ehartree=ehartree)
     841              :                   CASE (NEUMANN_BC)
     842              :                      CALL implicit_poisson_solver_neumann(poisson_env, rhor, vhartree_rs, &
     843            0 :                                                           ehartree=ehartree)
     844              :                   CASE (MIXED_PERIODIC_BC)
     845              :                      CALL implicit_poisson_solver_mixed_periodic(poisson_env, rhor, vhartree_rs, &
     846            0 :                                                                  electric_enthalpy=ehartree)
     847              :                   CASE (MIXED_BC)
     848              :                      CALL implicit_poisson_solver_mixed(poisson_env, rhor, vhartree_rs, &
     849            0 :                                                         electric_enthalpy=ehartree)
     850              :                   END SELECT
     851              : 
     852            0 :                   CALL pw_transfer(rhor, rhog)
     853              : 
     854            0 :                   IF (PRESENT(aux_density)) THEN
     855            0 :                      CALL pw_transfer(aux_density, rhor)
     856            0 :                      ehartree = 0.5_dp*pw_integral_ab(rhor, vhartree_rs)
     857              :                   END IF
     858              : 
     859            0 :                   CALL pw_pool%give_back_pw(rhor)
     860            0 :                   CALL pw_pool%give_back_pw(vhartree_rs)
     861              : 
     862              :                CASE DEFAULT
     863              :                   CALL cp_abort(__LOCATION__, &
     864              :                                 "unknown poisson method "// &
     865            8 :                                 cp_to_string(poisson_env%green_fft%method))
     866              :                END SELECT
     867              : 
     868              :             CASE (use_rs_grid)
     869              : 
     870            0 :                CALL pw_pool%create_pw(rhor)
     871            0 :                CALL pw_transfer(density, rhor)
     872            0 :                CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
     873            0 :                CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
     874            0 :                CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
     875            0 :                CALL pw_transfer(rhor, rhog)
     876            0 :                IF (PRESENT(ehartree)) THEN
     877              :                   #! This is actually not consequent but to keep it working, I leave it that way
     878              :                   #! Correctly, one checks the spaces but in CP2K, there is a separation in r-space/3D and g-space/1D in most cases
     879              :                   #:if kindd=="r3d_rs"
     880            0 :                      ehartree = 0.5_dp*pw_integral_ab(density, rhor)
     881              :                   #:else
     882            0 :                      ehartree = 0.5_dp*pw_integral_ab(density, rhog)
     883              :                   #:endif
     884              :                END IF
     885            8 :                CALL pw_pool%give_back_pw(rhor)
     886              : 
     887              :             END SELECT
     888              : 
     889            8 :             IF (PRESENT(aux_density)) THEN
     890            8 :                CALL calc_stress_and_gradient_${kindg}$ (poisson_env, rhog, ehartree, rhog_aux, h_stress, dvhartree=dvhartree)
     891              :             ELSE
     892            0 :                CALL calc_stress_and_gradient_${kindg}$ (poisson_env, rhog, ehartree, h_stress=h_stress, dvhartree=dvhartree)
     893              :             END IF
     894            8 :             CALL mt2d_hartree_stress(poisson_env, density, ehartree, h_stress, aux_density, greenfn)
     895              : 
     896            8 :             CALL pw_pool%give_back_pw(rhog)
     897            8 :             IF (PRESENT(aux_density)) THEN
     898            8 :                CALL pw_pool%give_back_pw(rhog_aux)
     899              :             END IF
     900              : 
     901            8 :             CALL timestop(handle)
     902              : 
     903            8 :          END SUBROUTINE pw_poisson_solve_nov_dv_${kindd}$_${kindg}$
     904              :       #:endfor
     905              :    #:endfor
     906              : 
     907              :    #:for kindd in ['r3d_rs', 'c1d_gs']
     908              :       #:for kindg in ['r3d_rs', 'c1d_gs']
     909              :          #:for kindv in ['r3d_rs', 'c1d_gs']
     910              : ! **************************************************************************************************
     911              : !> \brief Solve Poisson equation in a plane wave basis set
     912              : !>      Obtains electrostatic potential and its derivatives with respect to r
     913              : !>      from the density
     914              : !> \param poisson_env ...
     915              : !> \param density ...
     916              : !> \param ehartree ...
     917              : !> \param vhartree ...
     918              : !> \param dvhartree ...
     919              : !> \param h_stress ...
     920              : !> \param rho_core ...
     921              : !> \param greenfn ...
     922              : !> \param aux_density Hartree energy and stress tensor between 2 different densities
     923              : !> \par History
     924              : !>      JGH (13-Mar-2001) : completely revised
     925              : !> \author apsi
     926              : ! **************************************************************************************************
     927        67349 :             SUBROUTINE pw_poisson_solve_v_dv_${kindd}$_${kindv}$_${kindg}$ (poisson_env, density, ehartree, vhartree, &
     928              :                                                                             dvhartree, h_stress, rho_core, greenfn, aux_density)
     929              : 
     930              :                TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
     931              :                TYPE(pw_${kindd}$_type), INTENT(IN)                          :: density
     932              :                REAL(kind=dp), INTENT(out), OPTIONAL               :: ehartree
     933              :                TYPE(pw_${kindv}$_type), INTENT(INOUT)             :: vhartree
     934              :                TYPE(pw_${kindg}$_type), DIMENSION(3)              :: dvhartree
     935              :                REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), &
     936              :                   OPTIONAL                                        :: h_stress
     937              :                TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL                :: rho_core, greenfn
     938              :                TYPE(pw_${kindd}$_type), INTENT(IN), OPTIONAL :: aux_density
     939              : 
     940              :                CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_poisson_solve'
     941              : 
     942              :                INTEGER                                            ::  handle
     943              :                LOGICAL                                            :: has_dielectric
     944              :                TYPE(pw_grid_type), POINTER                        :: pw_grid
     945              :                TYPE(pw_pool_type), POINTER                        :: pw_pool
     946              :                TYPE(pw_r3d_rs_type)                                      ::  rhor, vhartree_rs
     947              :                TYPE(pw_c1d_gs_type) :: influence_fn, rhog, rhog_aux
     948              : 
     949        67349 :                CALL timeset(routineN, handle)
     950              : 
     951        67349 :                CALL pw_poisson_rebuild(poisson_env, density)
     952              : 
     953        67349 :                has_dielectric = poisson_env%parameters%has_dielectric
     954              : 
     955              :                ! point pw
     956        67349 :                pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
     957        67349 :                pw_grid => pw_pool%pw_grid
     958        67349 :                IF (.NOT. pw_grid_compare(pw_pool%pw_grid, vhartree%pw_grid)) THEN
     959            0 :                   CPABORT("vhartree has a different grid than the poisson solver")
     960              :                END IF
     961              :                ! density in G space
     962        67349 :                CALL pw_pool%create_pw(rhog)
     963        67349 :                IF (PRESENT(aux_density)) THEN
     964            8 :                   CALL pw_pool%create_pw(rhog_aux)
     965              :                END IF
     966              : 
     967       134230 :                SELECT CASE (poisson_env%used_grid)
     968              :                CASE (use_gs_grid)
     969              : 
     970       134230 :                   SELECT CASE (poisson_env%green_fft%method)
     971              :                   CASE (PERIODIC3D, ANALYTIC2D, ANALYTIC1D, ANALYTIC0D, MT2D, MT1D, MT0D, MULTIPOLE0D)
     972              : 
     973        66881 :                      CALL pw_transfer(density, rhog)
     974        66881 :                      IF (PRESENT(aux_density)) THEN
     975            8 :                         CALL pw_transfer(aux_density, rhog_aux)
     976              :                      END IF
     977        66881 :                      IF (PRESENT(greenfn)) THEN
     978            0 :                         influence_fn = greenfn
     979              :                      ELSE
     980        66881 :                         influence_fn = poisson_env%green_fft%influence_fn
     981              :                      END IF
     982        66881 :                      CALL pw_multiply_with(rhog, influence_fn)
     983        66881 :                      IF (PRESENT(aux_density)) THEN
     984            8 :                         CALL pw_multiply_with(rhog_aux, influence_fn)
     985              :                      END IF
     986        66881 :                      CALL pw_transfer(rhog, vhartree)
     987        66881 :                      IF (PRESENT(ehartree)) THEN
     988        63056 :                         IF (PRESENT(aux_density)) THEN
     989              :                            #:if kindd==kindv
     990            8 :                               ehartree = 0.5_dp*pw_integral_ab(aux_density, vhartree)
     991              :                            #:elif kindd=="c1d_gs"
     992            0 :                               ehartree = 0.5_dp*pw_integral_ab(aux_density, rhog)
     993              :                            #:else
     994            0 :                               CALL pw_transfer(aux_density, rhog)
     995            0 :                               ehartree = 0.5_dp*pw_integral_ab(rhog, vhartree)
     996              :                            #:endif
     997              :                         ELSE
     998              :                            #:if kindd==kindv
     999        63048 :                               ehartree = 0.5_dp*pw_integral_ab(density, vhartree)
    1000              :                            #:elif kindd=="c1d_gs"
    1001            0 :                               ehartree = 0.5_dp*pw_integral_ab(density, rhog)
    1002              :                            #:else
    1003            0 :                               CALL pw_transfer(density, rhog)
    1004            0 :                               ehartree = 0.5_dp*pw_integral_ab(rhog, vhartree)
    1005              :                            #:endif
    1006              :                         END IF
    1007              :                      END IF
    1008              : 
    1009              :                   CASE (PS_IMPLICIT)
    1010            0 :                      IF (PRESENT(h_stress)) THEN
    1011              :                         CALL cp_abort(__LOCATION__, &
    1012            0 :                                       "No stress tensor is implemented for the implicit Poisson solver.")
    1013              :                      END IF
    1014              : 
    1015            0 :                      IF (has_dielectric .AND. PRESENT(rho_core)) THEN
    1016            0 :                         SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
    1017              :                         CASE (PERIODIC_BC, MIXED_PERIODIC_BC)
    1018              :                            CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
    1019              :                                                    poisson_env%diel_rs_grid, &
    1020              :                                                    poisson_env%pw_pools(poisson_env%pw_level)%pool, &
    1021            0 :                                                    density, rho_core=rho_core)
    1022              :                         CASE (NEUMANN_BC, MIXED_BC)
    1023              :                            CALL dielectric_compute(poisson_env%implicit_env%dielectric, &
    1024              :                                                    poisson_env%diel_rs_grid, &
    1025              :                                                    poisson_env%pw_pools(poisson_env%pw_level)%pool, &
    1026              :                                                    poisson_env%dct_pw_grid, &
    1027              :                                                    poisson_env%parameters%ps_implicit_params%neumann_directions, &
    1028              :                                                    poisson_env%implicit_env%dct_env%recv_msgs_bnds, &
    1029              :                                                    poisson_env%implicit_env%dct_env%dests_expand, &
    1030              :                                                    poisson_env%implicit_env%dct_env%srcs_expand, &
    1031              :                                                    poisson_env%implicit_env%dct_env%flipg_stat, &
    1032              :                                                    poisson_env%implicit_env%dct_env%bounds_shftd, &
    1033            0 :                                                    density, rho_core=rho_core)
    1034              :                         END SELECT
    1035              :                      END IF
    1036              : 
    1037            0 :                      CALL pw_pool%create_pw(rhor)
    1038            0 :                      CALL pw_pool%create_pw(vhartree_rs)
    1039            0 :                      CALL pw_transfer(density, rhor)
    1040              : 
    1041            0 :                      SELECT CASE (poisson_env%parameters%ps_implicit_params%boundary_condition)
    1042              :                      CASE (PERIODIC_BC)
    1043              :                         CALL implicit_poisson_solver_periodic(poisson_env, rhor, vhartree_rs, &
    1044            0 :                                                               ehartree=ehartree)
    1045              :                      CASE (NEUMANN_BC)
    1046              :                         CALL implicit_poisson_solver_neumann(poisson_env, rhor, vhartree_rs, &
    1047            0 :                                                              ehartree=ehartree)
    1048              :                      CASE (MIXED_PERIODIC_BC)
    1049              :                         CALL implicit_poisson_solver_mixed_periodic(poisson_env, rhor, vhartree_rs, &
    1050            0 :                                                                     electric_enthalpy=ehartree)
    1051              :                      CASE (MIXED_BC)
    1052              :                         CALL implicit_poisson_solver_mixed(poisson_env, rhor, vhartree_rs, &
    1053            0 :                                                            electric_enthalpy=ehartree)
    1054              :                      END SELECT
    1055              : 
    1056            0 :                      CALL pw_transfer(vhartree_rs, vhartree)
    1057            0 :                      CALL pw_transfer(rhor, rhog)
    1058              : 
    1059            0 :                      IF (PRESENT(aux_density)) THEN
    1060            0 :                         CALL pw_transfer(aux_density, rhor)
    1061            0 :                         ehartree = 0.5_dp*pw_integral_ab(rhor, vhartree_rs)
    1062              :                      END IF
    1063              : 
    1064            0 :                      CALL pw_pool%give_back_pw(rhor)
    1065            0 :                      CALL pw_pool%give_back_pw(vhartree_rs)
    1066              : 
    1067              :                   CASE DEFAULT
    1068              :                      CALL cp_abort(__LOCATION__, &
    1069              :                                    "unknown poisson method "// &
    1070        66881 :                                    cp_to_string(poisson_env%green_fft%method))
    1071              :                   END SELECT
    1072              : 
    1073              :                CASE (use_rs_grid)
    1074              : 
    1075          468 :                   CALL pw_pool%create_pw(rhor)
    1076          468 :                   CALL pw_transfer(density, rhor)
    1077          468 :                   CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
    1078          468 :                   CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
    1079          468 :                   CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
    1080          468 :                   CALL pw_transfer(rhor, vhartree)
    1081          468 :                   CALL pw_transfer(rhor, rhog)
    1082          468 :                   IF (PRESENT(ehartree)) THEN
    1083            0 :                      IF (PRESENT(aux_density)) THEN
    1084              :                         #:if kindd==kindv
    1085            0 :                            ehartree = 0.5_dp*pw_integral_ab(aux_density, vhartree)
    1086              :                         #:elif kindd=="r3d_rs"
    1087            0 :                            ehartree = 0.5_dp*pw_integral_ab(aux_density, rhor)
    1088              :                         #:else
    1089            0 :                            ehartree = 0.5_dp*pw_integral_ab(aux_density, rhog)
    1090              :                         #:endif
    1091              :                      ELSE
    1092              :                         #:if kindd==kindv
    1093            0 :                            ehartree = 0.5_dp*pw_integral_ab(density, vhartree)
    1094              :                         #:elif kindd=="r3d_rs"
    1095            0 :                            ehartree = 0.5_dp*pw_integral_ab(density, rhor)
    1096              :                         #:else
    1097            0 :                            ehartree = 0.5_dp*pw_integral_ab(density, rhog)
    1098              :                         #:endif
    1099              :                      END IF
    1100              :                   END IF
    1101          468 :                   CALL pw_transfer(rhor, rhog)
    1102          468 :                   IF (PRESENT(aux_density)) THEN
    1103            0 :                      CALL pw_transfer(aux_density, rhor)
    1104            0 :                      CALL cp2k_distribution_to_z_slices(rhor, poisson_env%wavelet, rhor%pw_grid)
    1105            0 :                      CALL ps_wavelet_solve(poisson_env%wavelet, rhor%pw_grid)
    1106            0 :                      CALL z_slices_to_cp2k_distribution(rhor, poisson_env%wavelet, rhor%pw_grid)
    1107            0 :                      CALL pw_transfer(rhor, rhog_aux)
    1108              :                   END IF
    1109        67817 :                   CALL pw_pool%give_back_pw(rhor)
    1110              : 
    1111              :                END SELECT
    1112              : 
    1113        67349 :                IF (PRESENT(aux_density)) THEN
    1114            8 :                   CALL calc_stress_and_gradient_${kindg}$ (poisson_env, rhog, ehartree, rhog_aux, h_stress, dvhartree=dvhartree)
    1115              :                ELSE
    1116        67341 :                   CALL calc_stress_and_gradient_${kindg}$ (poisson_env, rhog, ehartree, h_stress=h_stress, dvhartree=dvhartree)
    1117              :                END IF
    1118        67349 :                CALL mt2d_hartree_stress(poisson_env, density, ehartree, h_stress, aux_density, greenfn)
    1119              : 
    1120        67349 :                CALL pw_pool%give_back_pw(rhog)
    1121        67349 :                IF (PRESENT(aux_density)) THEN
    1122            8 :                   CALL pw_pool%give_back_pw(rhog_aux)
    1123              :                END IF
    1124              : 
    1125        67349 :                CALL timestop(handle)
    1126              : 
    1127        67349 :             END SUBROUTINE pw_poisson_solve_v_dv_${kindd}$_${kindv}$_${kindg}$
    1128              :          #:endfor
    1129              :       #:endfor
    1130              :    #:endfor
    1131              : 
    1132              :    #:for kind in ["r3d_rs", "c1d_gs"]
    1133              : ! **************************************************************************************************
    1134              : !> \brief Contract the MT2D kernel strain derivative against the original reciprocal densities.
    1135              : !> \param poisson_env Poisson environment.
    1136              : !> \param density Original charge density before multiplication by the Coulomb kernel.
    1137              : !> \param ehartree Hartree energy, supplying the existing plane-wave volume contribution.
    1138              : !> \param h_stress Hartree virial in the physical periodic subspace.
    1139              : !> \param aux_density Optional second density for the bilinear Hartree energy.
    1140              : !> \param greenfn Optional custom kernel, whose strain dependence is unavailable.
    1141              : ! **************************************************************************************************
    1142       305494 :       SUBROUTINE mt2d_hartree_stress_${kind}$ (poisson_env, density, ehartree, h_stress, aux_density, greenfn)
    1143              :          TYPE(pw_poisson_type), INTENT(IN)                  :: poisson_env
    1144              :          TYPE(pw_${kind}$_type), INTENT(IN)                 :: density
    1145              :          REAL(KIND=dp), INTENT(IN), OPTIONAL                :: ehartree
    1146              :          REAL(KIND=dp), INTENT(INOUT), OPTIONAL             :: h_stress(3, 3)
    1147              :          TYPE(pw_${kind}$_type), INTENT(IN), OPTIONAL       :: aux_density
    1148              :          TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL          :: greenfn
    1149              : 
    1150              :          INTEGER                                            :: alpha, beta, ig, iz
    1151              :          REAL(KIND=dp)                                      :: energy, kernel, strain(3, 3), tolerance
    1152              :          TYPE(pw_c1d_gs_type)                               :: rho_g, rho_aux_g, weighted_g
    1153              :          TYPE(pw_grid_type), POINTER                        :: grid
    1154              :          TYPE(pw_pool_type), POINTER                        :: pool
    1155              : 
    1156       305446 :          IF (.NOT. PRESENT(h_stress)) RETURN
    1157        32624 :          IF (poisson_env%used_grid /= use_gs_grid) RETURN
    1158        32612 :          IF (poisson_env%green_fft%method /= MT2D) RETURN
    1159           48 :          IF (PRESENT(greenfn)) THEN
    1160            0 :             CPABORT("MT2D stress for a custom Green function is not implemented")
    1161              :          END IF
    1162           48 :          iz = poisson_env%green_fft%special_dimension
    1163           48 :          CPASSERT(iz >= 1 .AND. iz <= 3)
    1164              :          ! The existing MT2D kernel uses a Cartesian slab normal. Permit shear
    1165              :          ! within the periodic plane, but not mixing the vacuum axis with it.
    1166          624 :          tolerance = 64.0_dp*EPSILON(1.0_dp)*MAXVAL(ABS(poisson_env%cell_hmat))
    1167          192 :          DO alpha = 1, 3
    1168          144 :             IF (alpha == iz) CYCLE
    1169           96 :             IF (ABS(poisson_env%cell_hmat(alpha, iz)) > tolerance .OR. &
    1170           48 :                 ABS(poisson_env%cell_hmat(iz, alpha)) > tolerance) THEN
    1171            0 :                CPABORT("MT2D stress requires a Cartesian slab normal")
    1172              :             END IF
    1173              :          END DO
    1174           48 :          pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
    1175           48 :          CALL pool%create_pw(rho_g)
    1176           48 :          CALL pool%create_pw(weighted_g)
    1177           48 :          CALL pw_transfer(density, rho_g)
    1178           48 :          IF (PRESENT(aux_density)) THEN
    1179           40 :             CALL pool%create_pw(rho_aux_g)
    1180           40 :             CALL pw_transfer(aux_density, rho_aux_g)
    1181              :          END IF
    1182           48 :          grid => rho_g%pw_grid
    1183           48 :          IF (PRESENT(ehartree)) THEN
    1184           40 :             energy = ehartree
    1185              :          ELSE
    1186          384 :             weighted_g%array = rho_g%array*poisson_env%green_fft%influence_fn%array
    1187            8 :             IF (PRESENT(aux_density)) THEN
    1188            8 :                energy = 0.5_dp*pw_integral_ab(rho_aux_g, weighted_g)
    1189              :             ELSE
    1190            0 :                energy = 0.5_dp*pw_integral_ab(rho_g, weighted_g)
    1191              :             END IF
    1192              :          END IF
    1193           48 :          h_stress = 0.0_dp
    1194          192 :          DO alpha = 1, 3
    1195          144 :             IF (alpha == iz) CYCLE
    1196           96 :             h_stress(alpha, alpha) = energy
    1197          384 :             DO beta = alpha, 3
    1198          240 :                IF (beta == iz) CYCLE
    1199              :                ! The Maxwell K**2 identity holds for K=4*pi/G**2.
    1200              :                ! For MT2D use -1/2 rho_aux* rho dK/dstrain instead. The PW
    1201              :                ! integral supplies volume, reciprocal multiplicity and MPI sum.
    1202       379032 :                DO ig = 1, grid%ngpts_cut_local
    1203       378888 :                   CALL mt2d_kernel_strain(grid%g(:, ig), iz, poisson_env%green_fft%slab_size, kernel, strain)
    1204       379032 :                   weighted_g%array(ig) = rho_g%array(ig)*strain(alpha, beta)
    1205              :                END DO
    1206          144 :                IF (PRESENT(aux_density)) THEN
    1207              :                   h_stress(alpha, beta) = h_stress(alpha, beta) &
    1208          120 :                                           - 0.5_dp*pw_integral_ab(rho_aux_g, weighted_g)
    1209              :                ELSE
    1210              :                   h_stress(alpha, beta) = h_stress(alpha, beta) &
    1211           24 :                                           - 0.5_dp*pw_integral_ab(rho_g, weighted_g)
    1212              :                END IF
    1213          384 :                h_stress(beta, alpha) = h_stress(alpha, beta)
    1214              :             END DO
    1215              :          END DO
    1216           48 :          CALL pool%give_back_pw(rho_g)
    1217           48 :          CALL pool%give_back_pw(weighted_g)
    1218           48 :          IF (PRESENT(aux_density)) CALL pool%give_back_pw(rho_aux_g)
    1219       305494 :       END SUBROUTINE mt2d_hartree_stress_${kind}$
    1220              :    #:endfor
    1221              : 
    1222              :    #:for kind in ["c1d_gs", "r3d_rs"]
    1223       305494 :       SUBROUTINE calc_stress_and_gradient_${kind}$ (poisson_env, rhog, ehartree, rhog_aux, h_stress, dvhartree)
    1224              :          TYPE(pw_poisson_type), INTENT(IN) :: poisson_env
    1225              :          TYPE(pw_c1d_gs_type), INTENT(IN) :: rhog
    1226              :          REAL(KIND=dp), INTENT(IN), OPTIONAL :: ehartree
    1227              :          TYPE(pw_c1d_gs_type), INTENT(IN), OPTIONAL :: rhog_aux
    1228              :          REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT), OPTIONAL :: h_stress
    1229              :          TYPE(pw_${kind}$_type), DIMENSION(3), INTENT(INOUT), OPTIONAL :: dvhartree
    1230              : 
    1231              :          CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_poisson_set'
    1232              : 
    1233              :          REAL(KIND=dp) :: ffa
    1234              :          INTEGER :: alpha, beta, n(3), handle, i
    1235              :          LOGICAL :: calculate_stress
    1236      2443952 :          TYPE(pw_c1d_gs_type) :: dvg(3), dvg_aux(3)
    1237              :          TYPE(pw_pool_type), POINTER                        :: pw_pool
    1238              : 
    1239       305494 :          CALL timeset(routineN, handle)
    1240              : 
    1241       305494 :          pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
    1242              : 
    1243      1221976 :          DO i = 1, 3
    1244       916482 :             CALL pw_pool%create_pw(dvg(i))
    1245       916482 :             n = 0
    1246       916482 :             n(i) = 1
    1247       916482 :             CALL pw_copy(rhog, dvg(i))
    1248       916482 :             CALL pw_derive(dvg(i), n)
    1249      1221976 :             IF (PRESENT(rhog_aux)) THEN
    1250         1320 :                CALL pw_pool%create_pw(dvg_aux(i))
    1251         1320 :                CALL pw_copy(rhog_aux, dvg_aux(i))
    1252         1320 :                CALL pw_derive(dvg_aux(i), n)
    1253              :             END IF
    1254              :          END DO
    1255              :          ! save the derivatives
    1256       305494 :          IF (PRESENT(dvhartree)) THEN
    1257       269428 :             DO i = 1, 3
    1258       269428 :                CALL pw_transfer(dvg(i), dvhartree(i))
    1259              :             END DO
    1260              :          END IF
    1261              :          ! Calculate the contribution to the stress tensor this is only the contribution from
    1262              :          ! the Greens FUNCTION and the volume factor of the plane waves
    1263       305494 :          calculate_stress = PRESENT(h_stress)
    1264       305494 :          IF (calculate_stress .AND. poisson_env%used_grid == use_gs_grid) THEN
    1265              :             ! MT2D is contracted against the original density by the caller.
    1266              :             ! Its kernel derivative does not obey the Maxwell K**2 identity.
    1267        32612 :             calculate_stress = poisson_env%green_fft%method /= MT2D
    1268              :          END IF
    1269       305494 :          IF (calculate_stress) THEN
    1270        32576 :             CPASSERT(PRESENT(ehartree))
    1271        32576 :             ffa = -1.0_dp/fourpi
    1272        32576 :             h_stress = 0.0_dp
    1273       130304 :             DO alpha = 1, 3
    1274        97728 :                h_stress(alpha, alpha) = ehartree
    1275       130304 :                IF (PRESENT(rhog_aux)) THEN
    1276         3600 :                   DO beta = alpha, 3
    1277              :                      h_stress(alpha, beta) = h_stress(alpha, beta) &
    1278         2400 :                                              + ffa*pw_integral_ab(dvg_aux(alpha), dvg(beta))
    1279         3600 :                      h_stress(beta, alpha) = h_stress(alpha, beta)
    1280              :                   END DO
    1281              :                ELSE
    1282       289584 :                   DO beta = alpha, 3
    1283              :                      h_stress(alpha, beta) = h_stress(alpha, beta) &
    1284       193056 :                                              + ffa*pw_integral_ab(dvg(alpha), dvg(beta))
    1285       289584 :                      h_stress(beta, alpha) = h_stress(alpha, beta)
    1286              :                   END DO
    1287              :                END IF
    1288              :             END DO
    1289              : 
    1290              :             ! Handle the periodicity cases for the Stress Tensor
    1291        65140 :             SELECT CASE (poisson_env%used_grid)
    1292              :             CASE (use_gs_grid)
    1293              : 
    1294              :                ! FFT based Poisson-Solver
    1295        32584 :                SELECT CASE (poisson_env%green_fft%method)
    1296              :                CASE (PERIODIC3D, PS_IMPLICIT)
    1297              :                   ! Do Nothing
    1298              :                CASE (ANALYTIC2D, MT2D)
    1299              :                   ! Zero the 1 non-periodic component. Only the periodic-subspace
    1300              :                   ! stress components are defined for 2D systems.
    1301            8 :                   alpha = poisson_env%green_fft%special_dimension
    1302           32 :                   h_stress(:, alpha) = 0.0_dp
    1303           32 :                   h_stress(alpha, :) = 0.0_dp
    1304              :                CASE (ANALYTIC1D, MT1D)
    1305              :                   ! Zero the 2 non-periodic components
    1306            0 :                   DO alpha = 1, 3
    1307            0 :                      DO beta = alpha, 3
    1308            0 :                         IF ((alpha /= poisson_env%green_fft%special_dimension) .OR. &
    1309            0 :                             (beta /= poisson_env%green_fft%special_dimension)) THEN
    1310            0 :                            h_stress(alpha, beta) = 0.0_dp
    1311            0 :                            h_stress(beta, alpha) = 0.0_dp
    1312              :                         END IF
    1313              :                      END DO
    1314              :                   END DO
    1315            0 :                   CPABORT("Stress Tensor not tested for 1D systems.")
    1316              :                CASE (ANALYTIC0D, MT0D, MULTIPOLE0D)
    1317              :                   ! Zero the full stress tensor
    1318          304 :                   h_stress = 0.0_dp
    1319              :                CASE DEFAULT
    1320              :                   CALL cp_abort(__LOCATION__, &
    1321              :                                 "unknown poisson method"// &
    1322        32564 :                                 cp_to_string(poisson_env%green_fft%method))
    1323              :                END SELECT
    1324              : 
    1325              :             CASE (use_rs_grid)
    1326              : 
    1327              :                ! Wavelet based Poisson-Solver
    1328        32576 :                SELECT CASE (poisson_env%wavelet%method)
    1329              :                CASE (WAVELET3D)
    1330              :                   ! Do Nothing
    1331              :                CASE (WAVELET2D)
    1332              :                   ! Zero the 1 non-periodic component
    1333            0 :                   alpha = poisson_env%wavelet%special_dimension
    1334            0 :                   h_stress(:, alpha) = 0.0_dp
    1335            0 :                   h_stress(alpha, :) = 0.0_dp
    1336            0 :                   CPABORT("Stress Tensor not tested for WAVELET 2D.")
    1337              :                CASE (WAVELET1D)
    1338              :                   ! Zero the 2 non-periodic components
    1339            0 :                   CPABORT("WAVELET 1D not implemented!")
    1340              :                CASE (WAVELET0D)
    1341              :                   ! Zero the full stress tensor
    1342           12 :                   h_stress = 0.0_dp
    1343              :                END SELECT
    1344              : 
    1345              :             END SELECT
    1346              :          END IF
    1347              : 
    1348      1221976 :          DO i = 1, 3
    1349       916482 :             CALL pw_pool%give_back_pw(dvg(i))
    1350      1221976 :             IF (PRESENT(rhog_aux)) THEN
    1351         1320 :                CALL pw_pool%give_back_pw(dvg_aux(i))
    1352              :             END IF
    1353              :          END DO
    1354              : 
    1355       305494 :          CALL timestop(handle)
    1356              : 
    1357       305494 :       END SUBROUTINE calc_stress_and_gradient_${kind}$
    1358              :    #:endfor
    1359              : 
    1360              : ! **************************************************************************************************
    1361              : !> \brief sets cell, grids and parameters used by the poisson solver
    1362              : !>      You should call this at least once (and set everything)
    1363              : !>      before using the poisson solver.
    1364              : !>      Smart, doesn't set the thing twice to the same value
    1365              : !>      Keeps track of the need to rebuild the poisson_env
    1366              : !> \param poisson_env ...
    1367              : !> \param cell_hmat ...
    1368              : !> \param parameters ...
    1369              : !> \param pw_pools ...
    1370              : !> \param use_level ...
    1371              : !> \param mt_super_ref_pw_grid ...
    1372              : !> \param dct_pw_grid ...
    1373              : !> \param force_rebuild ...
    1374              : !> \author fawzi
    1375              : !> \note
    1376              : !>      Checks everything at the end. This means that after *each* call to
    1377              : !>      this method the poisson env must be fully ready, so the first time
    1378              : !>      you have to set everything at once. Change this behaviour?
    1379              : ! **************************************************************************************************
    1380        27989 :    SUBROUTINE pw_poisson_set(poisson_env, cell_hmat, parameters, pw_pools, use_level, &
    1381              :                              mt_super_ref_pw_grid, dct_pw_grid, force_rebuild)
    1382              : 
    1383              :       TYPE(pw_poisson_type), INTENT(INOUT)               :: poisson_env
    1384              :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(IN), &
    1385              :          OPTIONAL                                        :: cell_hmat
    1386              :       TYPE(pw_poisson_parameter_type), INTENT(IN), &
    1387              :          OPTIONAL                                        :: parameters
    1388              :       TYPE(pw_pool_p_type), DIMENSION(:), OPTIONAL, &
    1389              :          POINTER                                         :: pw_pools
    1390              :       INTEGER, INTENT(in), OPTIONAL                      :: use_level
    1391              :       TYPE(pw_grid_type), OPTIONAL, POINTER              :: mt_super_ref_pw_grid, dct_pw_grid
    1392              :       LOGICAL, INTENT(in), OPTIONAL                      :: force_rebuild
    1393              : 
    1394              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_poisson_set'
    1395              : 
    1396              :       INTEGER                                            :: handle, i
    1397              :       LOGICAL                                            :: same
    1398        27989 :       TYPE(pw_pool_p_type), DIMENSION(:), POINTER        :: tmp_pools
    1399              : 
    1400        27989 :       CALL timeset(routineN, handle)
    1401              : 
    1402        27989 :       IF (PRESENT(parameters)) poisson_env%parameters = parameters
    1403              : 
    1404        27989 :       IF (PRESENT(cell_hmat)) THEN
    1405        65279 :          IF (ANY(poisson_env%cell_hmat /= cell_hmat)) THEN
    1406        26279 :             CALL pw_poisson_cleanup(poisson_env)
    1407              :          END IF
    1408       363857 :          poisson_env%cell_hmat(:, :) = cell_hmat(:, :)
    1409        27989 :          poisson_env%rebuild = .TRUE.
    1410              :       END IF
    1411              : 
    1412        27989 :       IF (PRESENT(pw_pools)) THEN
    1413        27985 :          CPASSERT(ASSOCIATED(pw_pools))
    1414        27985 :          same = .FALSE.
    1415        27985 :          IF (ASSOCIATED(poisson_env%pw_pools)) THEN
    1416        14950 :             same = SIZE(poisson_env%pw_pools) == SIZE(pw_pools)
    1417        14950 :             IF (same) THEN
    1418        32264 :                DO i = 1, SIZE(pw_pools)
    1419        17314 :                   IF (.NOT. ASSOCIATED(poisson_env%pw_pools(i)%pool, &
    1420        20356 :                                        pw_pools(i)%pool)) same = .FALSE.
    1421              :                END DO
    1422              :             END IF
    1423              :          END IF
    1424        14950 :          IF (.NOT. same) THEN
    1425        16263 :             poisson_env%rebuild = .TRUE.
    1426        16263 :             CALL pw_pools_copy(pw_pools, tmp_pools)
    1427        16263 :             CALL pw_pools_dealloc(poisson_env%pw_pools)
    1428        16263 :             poisson_env%pw_pools => tmp_pools
    1429              :          END IF
    1430              :       END IF
    1431              : 
    1432        27989 :       IF (PRESENT(use_level)) poisson_env%pw_level = use_level
    1433              : 
    1434        27989 :       IF (PRESENT(dct_pw_grid)) THEN
    1435        13691 :          IF (ASSOCIATED(dct_pw_grid)) THEN
    1436            0 :             CALL pw_grid_retain(dct_pw_grid)
    1437              :          END IF
    1438        13691 :          CALL pw_grid_release(poisson_env%dct_pw_grid)
    1439        13691 :          poisson_env%dct_pw_grid => dct_pw_grid
    1440              :       END IF
    1441              : 
    1442        27989 :       IF (PRESENT(mt_super_ref_pw_grid)) THEN
    1443        13691 :          IF (ASSOCIATED(mt_super_ref_pw_grid)) THEN
    1444         1630 :             CALL pw_grid_retain(mt_super_ref_pw_grid)
    1445              :          END IF
    1446        13691 :          CALL pw_grid_release(poisson_env%mt_super_ref_pw_grid)
    1447        13691 :          poisson_env%mt_super_ref_pw_grid => mt_super_ref_pw_grid
    1448              :       END IF
    1449              : 
    1450        27989 :       IF (PRESENT(force_rebuild)) THEN
    1451            0 :          IF (force_rebuild) poisson_env%rebuild = .TRUE.
    1452              :       END IF
    1453              : 
    1454        27989 :       CALL pw_poisson_check(poisson_env)
    1455              : 
    1456        27989 :       CALL timestop(handle)
    1457              : 
    1458        27989 :    END SUBROUTINE pw_poisson_set
    1459              : 
    1460              : ! **************************************************************************************************
    1461              : !> \brief computes the convolution f * u using reciprocal-space multiplication
    1462              : !> \par
    1463              : !>      Given two real-space functions f and u, this routine evaluates their
    1464              : !>      convolution by transforming both to G space, multiplying their Fourier
    1465              : !>      components, and transforming the product back to real space.
    1466              : !> \param poisson_env   poisson environment
    1467              : !> \param func          input function f in real space
    1468              : !> \param convolution   convolution result (f * u) in real space
    1469              : !> \param u             input function/kernel u in real space
    1470              : !> \author Ziwei Chai
    1471              : !> \date   12.03.2026
    1472              : ! **************************************************************************************************
    1473            0 :    SUBROUTINE pw_func_u_convolution(poisson_env, func, convolution, u)
    1474              : 
    1475              :       TYPE(pw_poisson_type), POINTER                     :: poisson_env
    1476              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: func, u
    1477              :       TYPE(pw_r3d_rs_type), INTENT(INOUT), OPTIONAL      :: convolution
    1478              :       CHARACTER(len=*), PARAMETER                        :: routineN = 'pw_func_u_convolution'
    1479              :       INTEGER                                            :: handle
    1480              :       TYPE(pw_grid_type), POINTER                        :: pw_grid
    1481              :       TYPE(pw_pool_type), POINTER                        :: pw_pool
    1482              :       TYPE(pw_c1d_gs_type)                               :: funcg, ug
    1483              : 
    1484            0 :       CALL timeset(routineN, handle)
    1485              : 
    1486            0 :       CPASSERT(ASSOCIATED(poisson_env))
    1487            0 :       CALL pw_poisson_rebuild(poisson_env, func)
    1488              : 
    1489              :       ! point pw
    1490            0 :       pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
    1491            0 :       pw_grid => pw_pool%pw_grid
    1492              :       ! func and u in G space
    1493            0 :       CALL pw_pool%create_pw(funcg)
    1494            0 :       CALL pw_pool%create_pw(ug)
    1495              : 
    1496            0 :       CALL pw_transfer(func, funcg)
    1497            0 :       CALL pw_transfer(u, ug)
    1498              : 
    1499            0 :       funcg%array(:) = funcg%array(:)*ug%array(:)
    1500              : 
    1501            0 :       CALL pw_transfer(funcg, convolution)
    1502              : 
    1503            0 :       CALL pw_pool%give_back_pw(funcg)
    1504            0 :       CALL pw_pool%give_back_pw(ug)
    1505              : 
    1506            0 :       CALL timestop(handle)
    1507              : 
    1508            0 :    END SUBROUTINE pw_func_u_convolution
    1509              : 
    1510              : END MODULE pw_poisson_methods
        

Generated by: LCOV version 2.0-1