LCOV - code coverage report
Current view: top level - src - gce_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:06f838d) Lines: 83.1 % 59 49
Test Date: 2026-06-05 07:04:50 Functions: 100.0 % 3 3

            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              : !> \author  Ziwei Chai
       9              : !> \date    09.04.2026
      10              : !> \version 1.0
      11              : ! **************************************************************************************************
      12              : MODULE gce_methods
      13              : 
      14              :    USE cp_control_types,                ONLY: dft_control_type,&
      15              :                                               pcc_control_type
      16              :    USE kinds,                           ONLY: dp
      17              :    USE message_passing,                 ONLY: mp_para_env_type
      18              :    USE pw_methods,                      ONLY: pw_axpy,&
      19              :                                               pw_integrate_function,&
      20              :                                               pw_scale,&
      21              :                                               pw_transfer,&
      22              :                                               pw_zero
      23              :    USE pw_pool_types,                   ONLY: pw_pool_type
      24              :    USE pw_types,                        ONLY: pw_c1d_gs_type,&
      25              :                                               pw_r3d_rs_type
      26              : #include "./base/base_uses.f90"
      27              : 
      28              :    IMPLICIT NONE
      29              : 
      30              :    PRIVATE
      31              : 
      32              :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gce_methods'
      33              : 
      34              :    PUBLIC :: planar_averaged_v_hartree_3d, planar_counter_charge
      35              : 
      36              : CONTAINS
      37              : 
      38              : ! **************************************************************************************************
      39              : !> \brief map the surface normal to the two in-plane axes and one normal axis
      40              : !> \param surf_normal ...
      41              : !> \param a ...
      42              : !> \param b ...
      43              : !> \param c ...
      44              : !> \author Ziwei Chai
      45              : ! **************************************************************************************************
      46           36 :    SUBROUTINE get_planar_axes(surf_normal, a, b, c)
      47              : 
      48              :       INTEGER, INTENT(IN)                                :: surf_normal
      49              :       INTEGER, INTENT(OUT)                               :: a, b, c
      50              : 
      51           36 :       SELECT CASE (surf_normal)
      52              :       CASE (3)
      53            0 :          a = 1
      54            0 :          b = 2
      55            0 :          c = 3
      56              :       CASE (1)
      57           18 :          a = 2
      58           18 :          b = 3
      59           18 :          c = 1
      60              :       CASE (2)
      61           18 :          a = 3
      62           18 :          b = 1
      63           18 :          c = 2
      64              :       CASE DEFAULT
      65           36 :          CPABORT("Invalid planar surface normal.")
      66              :       END SELECT
      67              : 
      68           36 :    END SUBROUTINE get_planar_axes
      69              : 
      70              : ! **************************************************************************************************
      71              : !> \brief calculate the planar averaged real space potential (e.g. Hartree potential) along the
      72              : !>        surface normal of a slab model and the corresponding reference (electrostatic) energy
      73              : !>        near the simulation cell edge.
      74              : !> \param v_rspace ...
      75              : !> \param dft_control ...
      76              : !> \param do_gce ...
      77              : !> \param ref_esp ...
      78              : !> \param para_env ...
      79              : !> \author Ziwei Chai
      80              : ! **************************************************************************************************
      81           18 :    SUBROUTINE planar_averaged_v_hartree_3d(v_rspace, dft_control, do_gce, ref_esp, para_env)
      82              : 
      83              :       TYPE(pw_r3d_rs_type), INTENT(IN)                   :: v_rspace
      84              :       TYPE(dft_control_type), POINTER                    :: dft_control
      85              :       LOGICAL, INTENT(IN)                                :: do_gce
      86              :       REAL(KIND=dp), INTENT(INOUT)                       :: ref_esp
      87              :       TYPE(mp_para_env_type), POINTER                    :: para_env
      88              : 
      89              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'planar_averaged_v_hartree_3d'
      90              : 
      91              :       INTEGER                                            :: a, b, c, handle, x, y, z
      92              :       REAL(KIND=dp)                                      :: my_ref_esp, ngrids_in_plane
      93           18 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: profile, profile_local
      94              : 
      95           18 :       CALL timeset(routineN, handle)
      96              : 
      97           18 :       IF (do_gce) THEN
      98              : 
      99              :          ! a and b cell vectors are parallel to the surface, c vector is not.
     100            0 :          CALL get_planar_axes(dft_control%pcc_control%surf_normal, a, b, c)
     101              : 
     102              :          my_ref_esp = 0.0_dp
     103            0 :          z = v_rspace%pw_grid%npts(a)*v_rspace%pw_grid%npts(b)
     104            0 :          ngrids_in_plane = REAL(z, dp)
     105              : 
     106              : !$OMP    PARALLEL DO DEFAULT(NONE) &
     107              : !$OMP                PRIVATE(x,y,z) &
     108              : !$OMP                SHARED(v_rspace,A,b,c)&
     109            0 : !$OMP                REDUCTION(+:my_ref_esp)
     110              :          DO y = v_rspace%pw_grid%bounds_local(1, b), v_rspace%pw_grid%bounds_local(2, b)
     111              :             DO x = v_rspace%pw_grid%bounds_local(1, a), v_rspace%pw_grid%bounds_local(2, a)
     112              :                DO z = v_rspace%pw_grid%bounds_local(1, c), v_rspace%pw_grid%bounds_local(2, c)
     113              :                   IF (z == v_rspace%pw_grid%bounds(2, c)) THEN
     114              :                      IF (c == 3) THEN
     115              :                         my_ref_esp = v_rspace%array(x, y, z) + my_ref_esp
     116              :                      ELSE IF (c == 2) THEN
     117              :                         my_ref_esp = v_rspace%array(y, z, x) + my_ref_esp
     118              :                      ELSE
     119              :                         my_ref_esp = v_rspace%array(z, x, y) + my_ref_esp
     120              :                      END IF
     121              :                   END IF
     122              :                END DO
     123              :             END DO
     124              :          END DO
     125              : !$OMP    END PARALLEL DO
     126              : 
     127            0 :          CALL para_env%sum(my_ref_esp)
     128            0 :          my_ref_esp = my_ref_esp/ngrids_in_plane
     129            0 :          ref_esp = my_ref_esp
     130              : 
     131              :       END IF
     132              : 
     133           18 :       IF (dft_control%do_paep) THEN
     134              : 
     135           18 :          CALL get_planar_axes(dft_control%paep_control%surf_normal, a, b, c)
     136              : 
     137           18 :          z = v_rspace%pw_grid%npts(a)*v_rspace%pw_grid%npts(b)
     138           18 :          ngrids_in_plane = REAL(z, dp)
     139              : 
     140           54 :          ALLOCATE (profile(v_rspace%pw_grid%bounds(1, c):v_rspace%pw_grid%bounds(2, c)))
     141           18 :          profile(:) = 0.0_dp
     142              : 
     143              : !$OMP    PARALLEL    DEFAULT(NONE) &
     144              : !$OMP                PRIVATE(x,y,z,profile_local) &
     145              : !$OMP                SHARED(v_rspace,A,b,c) &
     146           18 : !$OMP                SHARED(profile)
     147              : 
     148              :          ALLOCATE (profile_local(v_rspace%pw_grid%bounds(1, c):v_rspace%pw_grid%bounds(2, c)))
     149              :          profile_local(:) = 0.0_dp
     150              : 
     151              : !$OMP DO
     152              :          DO z = v_rspace%pw_grid%bounds_local(1, c), v_rspace%pw_grid%bounds_local(2, c)
     153              :             DO y = v_rspace%pw_grid%bounds_local(1, b), v_rspace%pw_grid%bounds_local(2, b)
     154              :                DO x = v_rspace%pw_grid%bounds_local(1, a), v_rspace%pw_grid%bounds_local(2, a)
     155              :                   IF (c == 3) profile_local(z) = profile_local(z) + v_rspace%array(x, y, z)
     156              :                   IF (c == 2) profile_local(z) = profile_local(z) + v_rspace%array(y, z, x)
     157              :                   IF (c == 1) profile_local(z) = profile_local(z) + v_rspace%array(z, x, y)
     158              :                END DO
     159              :             END DO
     160              :          END DO
     161              : !$OMP END DO
     162              : 
     163              : !$OMP CRITICAL
     164              :          profile(:) = profile(:) + profile_local(:)
     165              : !$OMP END CRITICAL
     166              : 
     167              :          DEALLOCATE (profile_local)
     168              : 
     169              : !$OMP    END PARALLEL
     170              : 
     171           18 :          CALL para_env%sum(profile(:))
     172          990 :          profile(:) = profile(:)/ngrids_in_plane
     173              : 
     174           36 :          DEALLOCATE (profile)
     175              : 
     176              :       END IF
     177              : 
     178           18 :       CALL timestop(handle)
     179              : 
     180           18 :    END SUBROUTINE planar_averaged_v_hartree_3d
     181              : 
     182              : ! **************************************************************************************************
     183              : !> \brief add the planar counter charge density to the total charge density
     184              : !> \param rho_tot_gspace ...
     185              : !> \param pcc_env ...
     186              : !> \param auxbas_pw_pool ...
     187              : !> \author Ziwei Chai
     188              : ! **************************************************************************************************
     189           36 :    SUBROUTINE planar_counter_charge(rho_tot_gspace, pcc_env, auxbas_pw_pool)
     190              : 
     191              :       TYPE(pw_c1d_gs_type), INTENT(INOUT)                :: rho_tot_gspace
     192              :       TYPE(pcc_control_type), POINTER                    :: pcc_env
     193              :       TYPE(pw_pool_type), INTENT(IN), POINTER            :: auxbas_pw_pool
     194              : 
     195              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'planar_counter_charge'
     196              : 
     197              :       INTEGER                                            :: a, b, c, handle, lcenter, ucenter, x, y, &
     198              :                                                             z
     199              :       REAL(KIND=dp)                                      :: dz, gau_a, tot_charge, val
     200              :       TYPE(pw_c1d_gs_type)                               :: pcc_density_g
     201              :       TYPE(pw_r3d_rs_type)                               :: pcc_density_r
     202              : 
     203           18 :       CALL timeset(routineN, handle)
     204              : 
     205              :       ! a and b cell vectors are parallel to the surface, c vector is not.
     206           18 :       CALL get_planar_axes(pcc_env%surf_normal, a, b, c)
     207              : 
     208           18 :       CALL auxbas_pw_pool%create_pw(pcc_density_r)
     209           18 :       CALL auxbas_pw_pool%create_pw(pcc_density_g)
     210           18 :       CALL pw_zero(pcc_density_r)
     211           18 :       CALL pw_zero(pcc_density_g)
     212              : 
     213           18 :       tot_charge = pw_integrate_function(rho_tot_gspace, isign=-1)
     214              : 
     215           18 :       dz = pcc_density_r%pw_grid%dr(c)
     216              : 
     217           18 :       ucenter = pcc_density_r%pw_grid%bounds(2, c) - INT(pcc_env%dist_edge/dz)
     218           18 :       lcenter = pcc_density_r%pw_grid%bounds(1, c) + INT(pcc_env%dist_edge/dz)
     219           18 :       gau_a = 1.0_dp
     220              : !$OMP    PARALLEL DO DEFAULT(NONE) &
     221              : !$OMP                PRIVATE(x,y,z,val) &
     222           18 : !$OMP                SHARED(pcc_density_r,gau_a,ucenter,lcenter,A,b,c,dz,pcc_env)
     223              :       DO z = pcc_density_r%pw_grid%bounds_local(1, c), pcc_density_r%pw_grid%bounds_local(2, c)
     224              :          val = gau_a*EXP(-(dz*REAL(z - ucenter, dp))**2.0_dp/(2.0_dp*pcc_env%gau_c**2.0_dp))
     225              :          val = val + gau_a*EXP(-(dz*REAL(z - lcenter, dp))**2.0_dp/(2.0_dp*pcc_env%gau_c**2.0_dp))
     226              :          IF (val < 1.0E-15_dp) val = 0.0_dp
     227              :          DO y = pcc_density_r%pw_grid%bounds_local(1, b), pcc_density_r%pw_grid%bounds_local(2, b)
     228              :             DO x = pcc_density_r%pw_grid%bounds_local(1, a), pcc_density_r%pw_grid%bounds_local(2, a)
     229              :                IF (c == 3) pcc_density_r%array(x, y, z) = val
     230              :                IF (c == 2) pcc_density_r%array(y, z, x) = val
     231              :                IF (c == 1) pcc_density_r%array(z, x, y) = val
     232              :             END DO
     233              :          END DO
     234              :       END DO
     235              : !$OMP    END PARALLEL DO
     236              : 
     237           18 :       tot_charge = tot_charge/pw_integrate_function(pcc_density_r, isign=1)
     238           18 :       CALL pw_scale(pcc_density_r, tot_charge)
     239           18 :       CALL pw_transfer(pcc_density_r, pcc_density_g)
     240           18 :       CALL pw_axpy(pcc_density_g, rho_tot_gspace)
     241           18 :       CALL pw_transfer(rho_tot_gspace, pcc_density_r)
     242              : 
     243           18 :       tot_charge = pw_integrate_function(rho_tot_gspace, isign=-1)
     244              : 
     245           18 :       CALL auxbas_pw_pool%give_back_pw(pcc_density_r)
     246           18 :       CALL auxbas_pw_pool%give_back_pw(pcc_density_g)
     247              : 
     248           18 :       CALL timestop(handle)
     249              : 
     250           18 :    END SUBROUTINE planar_counter_charge
     251              : 
     252              : END MODULE gce_methods
        

Generated by: LCOV version 2.0-1