(git:1f285aa)
surface_dipole.F
Go to the documentation of this file.
1 !--------------------------------------------------------------------------------------------------!
2 ! CP2K: A general program to perform molecular dynamics simulations !
3 ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 ! !
5 ! SPDX-License-Identifier: GPL-2.0-or-later !
6 !--------------------------------------------------------------------------------------------------!
7 
8 ! **************************************************************************************************
10 
11  USE cell_types, ONLY: cell_type
12  USE cp_control_types, ONLY: dft_control_type
13  USE kahan_sum, ONLY: accurate_sum
14  USE kinds, ONLY: dp
15  USE mathconstants, ONLY: pi
16  USE physcon, ONLY: bohr
17  USE pw_env_types, ONLY: pw_env_get,&
18  pw_env_type
19  USE pw_grid_types, ONLY: pw_mode_local
20  USE pw_methods, ONLY: pw_axpy,&
21  pw_integral_ab,&
22  pw_scale,&
23  pw_transfer,&
24  pw_zero
25  USE pw_pool_types, ONLY: pw_pool_p_type,&
26  pw_pool_type
27  USE pw_types, ONLY: pw_c1d_gs_type,&
28  pw_r3d_rs_type
29  USE qs_energy_types, ONLY: qs_energy_type
30  USE qs_environment_types, ONLY: get_qs_env,&
31  qs_environment_type
32  USE qs_rho_types, ONLY: qs_rho_get,&
33  qs_rho_type
34  USE qs_subsys_types, ONLY: qs_subsys_type
35 #include "./base/base_uses.f90"
36 
37  IMPLICIT NONE
38 
39  PRIVATE
40 
41  CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'surface_dipole'
42 
43  PUBLIC :: calc_dipsurf_potential
44 
45 CONTAINS
46 
47 ! **************************************************************************************************
48 !> \brief compute the surface dipole and the correction to the hartree potential
49 !> \param qs_env the qs environment
50 !> \param energy ...
51 !> \par History
52 !> 01.2014 created [MI]
53 !> \author MI
54 !> \author Soumya Ghosh added SURF_DIP_POS 19.11.2018
55 ! **************************************************************************************************
56 
57  SUBROUTINE calc_dipsurf_potential(qs_env, energy)
58 
59  TYPE(qs_environment_type), POINTER :: qs_env
60  TYPE(qs_energy_type), POINTER :: energy
61 
62  CHARACTER(len=*), PARAMETER :: routinen = 'calc_dipsurf_potential'
63 
64  INTEGER :: handle, i, idir_surfdip, ilayer_min, &
65  ilow, irho, ispin, isurf, iup, jsurf, &
66  width
67  INTEGER, DIMENSION(3) :: ngrid
68  INTEGER, DIMENSION(:, :), POINTER :: bo
69  REAL(dp) :: cutoff, dh(3, 3), dip_fac, dip_hh, &
70  dsurf, height_min, hh, pos_surf_dip, &
71  rhoav_min, surfarea, vdip, vdip_fac
72  REAL(dp), ALLOCATABLE, DIMENSION(:) :: rhoavsurf
73  TYPE(cell_type), POINTER :: cell
74  TYPE(dft_control_type), POINTER :: dft_control
75  TYPE(pw_c1d_gs_type), POINTER :: rho0_s_gs, rho_core
76  TYPE(pw_env_type), POINTER :: pw_env
77  TYPE(pw_pool_p_type), DIMENSION(:), POINTER :: pw_pools
78  TYPE(pw_pool_type), POINTER :: auxbas_pw_pool
79  TYPE(pw_r3d_rs_type) :: vdip_r, wf_r
80  TYPE(pw_r3d_rs_type), DIMENSION(:), POINTER :: rho_r
81  TYPE(pw_r3d_rs_type), POINTER :: v_hartree_rspace
82  TYPE(qs_rho_type), POINTER :: rho
83  TYPE(qs_subsys_type), POINTER :: subsys
84 
85  CALL timeset(routinen, handle)
86  NULLIFY (cell, dft_control, rho, pw_env, auxbas_pw_pool, &
87  pw_pools, subsys, v_hartree_rspace, rho_r)
88 
89  CALL get_qs_env(qs_env, &
90  dft_control=dft_control, &
91  rho=rho, &
92  rho_core=rho_core, &
93  rho0_s_gs=rho0_s_gs, &
94  cell=cell, &
95  pw_env=pw_env, &
96  subsys=subsys, &
97  v_hartree_rspace=v_hartree_rspace)
98 
99  CALL pw_env_get(pw_env, auxbas_pw_pool=auxbas_pw_pool, &
100  pw_pools=pw_pools)
101  CALL auxbas_pw_pool%create_pw(wf_r)
102  CALL auxbas_pw_pool%create_pw(vdip_r)
103 
104  IF (dft_control%qs_control%gapw) THEN
105  IF (dft_control%qs_control%gapw_control%nopaw_as_gpw) THEN
106  CALL pw_axpy(rho_core, rho0_s_gs)
107  CALL pw_transfer(rho0_s_gs, wf_r)
108  CALL pw_axpy(rho_core, rho0_s_gs, -1.0_dp)
109  ELSE
110  CALL pw_transfer(rho0_s_gs, wf_r)
111  END IF
112  ELSE
113  CALL pw_transfer(rho_core, wf_r)
114  END IF
115  CALL qs_rho_get(rho, rho_r=rho_r)
116  DO ispin = 1, dft_control%nspins
117  CALL pw_axpy(rho_r(ispin), wf_r)
118  END DO
119 
120  ngrid(1:3) = wf_r%pw_grid%npts(1:3)
121  idir_surfdip = dft_control%dir_surf_dip
122 
123  width = 4
124 
125  DO i = 1, 3
126  IF (i /= idir_surfdip) THEN
127  IF (abs(wf_r%pw_grid%dh(idir_surfdip, i)) > 1.e-7_dp) THEN
128  ! stop surface dipole defined only for slab perpendigular to one of the Cartesian axis
129  CALL cp_abort(__location__, &
130  "Dipole correction only for surface perpendicular to one Cartesian axis")
131 ! not properly general, we assume that vectors A, B, and C are along x y and z respectively,
132 ! in the ortorhombic cell, but in principle it does not need to be this way, importan
133 ! is that the cell angles are 90 degrees.
134  END IF
135  END IF
136  END DO
137 
138  ilow = wf_r%pw_grid%bounds(1, idir_surfdip)
139  iup = wf_r%pw_grid%bounds(2, idir_surfdip)
140 
141  ALLOCATE (rhoavsurf(ilow:iup))
142  rhoavsurf = 0.0_dp
143 
144  bo => wf_r%pw_grid%bounds_local
145  dh = wf_r%pw_grid%dh
146 
147  CALL pw_scale(wf_r, wf_r%pw_grid%vol)
148  IF (idir_surfdip == 3) THEN
149  isurf = 1
150  jsurf = 2
151 
152  DO i = bo(1, 3), bo(2, 3)
153  rhoavsurf(i) = accurate_sum(wf_r%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), i))
154  END DO
155 
156  ELSEIF (idir_surfdip == 2) THEN
157  isurf = 3
158  jsurf = 1
159 
160  DO i = bo(1, 2), bo(2, 2)
161  rhoavsurf(i) = accurate_sum(wf_r%array(bo(1, 1):bo(2, 1), i, bo(1, 3):bo(2, 3)))
162  END DO
163  ELSE
164  isurf = 2
165  jsurf = 3
166 
167  DO i = bo(1, 1), bo(2, 1)
168  rhoavsurf(i) = accurate_sum(wf_r%array(i, bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)))
169  END DO
170  END IF
171  CALL pw_scale(wf_r, 1.0_dp/wf_r%pw_grid%vol)
172  rhoavsurf = rhoavsurf/wf_r%pw_grid%vol
173 
174  surfarea = cell%hmat(isurf, isurf)*cell%hmat(jsurf, jsurf) - &
175  cell%hmat(isurf, jsurf)*cell%hmat(jsurf, isurf)
176  dsurf = surfarea/real(ngrid(isurf)*ngrid(jsurf), dp)
177 
178  IF (wf_r%pw_grid%para%mode /= pw_mode_local) THEN
179  CALL wf_r%pw_grid%para%group%sum(rhoavsurf)
180  END IF
181  rhoavsurf(ilow:iup) = dsurf*rhoavsurf(ilow:iup)
182 
183  ! locate where the vacuum is, and set the reference point for the calculation of the dipole
184  rhoavsurf(ilow:iup) = rhoavsurf(ilow:iup)/surfarea
185  ! Note: rhosurf has the same dimension as rho
186  IF (dft_control%pos_dir_surf_dip < 0.0_dp) THEN
187  ilayer_min = ilow - 1 + minloc(abs(rhoavsurf(ilow:iup)), 1)
188  ELSE
189  pos_surf_dip = dft_control%pos_dir_surf_dip*bohr
190  ilayer_min = ilow - 1 + nint(pos_surf_dip/dh(idir_surfdip, idir_surfdip)) + 1
191  END IF
192  rhoav_min = abs(rhoavsurf(ilayer_min))
193  IF (rhoav_min >= 1.e-5_dp) THEN
194  cpabort(" Dipole correction needs more vacuum space above the surface ")
195  END IF
196 
197  height_min = real((ilayer_min - ilow), dp)*dh(idir_surfdip, idir_surfdip)
198 
199 ! surface dipole form average rhoavsurf
200 ! \sum_i NjdjNkdkdi rhoav_i (i-imin)di
201  dip_hh = 0.0_dp
202  dip_fac = wf_r%pw_grid%vol*dh(idir_surfdip, idir_surfdip)/real(ngrid(idir_surfdip), dp)
203 
204  DO i = ilayer_min + 1, ilayer_min + ngrid(idir_surfdip)
205  hh = real((i - ilayer_min), dp)
206  IF (i > iup) THEN
207  irho = i - ngrid(idir_surfdip)
208  ELSE
209  irho = i
210  END IF
211 ! introduce a cutoff function to smoothen the edges
212  IF (abs(irho - ilayer_min) > width) THEN
213  cutoff = 1.0_dp
214  ELSE
215  cutoff = abs(sin(0.5_dp*pi*real(abs(irho - ilayer_min), dp)/real(width, dp)))
216  END IF
217  dip_hh = dip_hh + rhoavsurf(irho)*hh*dip_fac*cutoff
218  END DO
219 
220  DEALLOCATE (rhoavsurf)
221 ! for printing purposes [SGh]
222  qs_env%surface_dipole_moment = dip_hh/bohr
223 
224 ! Calculation of the dipole potential as a function of the perpendicular coordinate
225  CALL pw_zero(vdip_r)
226  vdip_fac = dip_hh*4.0_dp*pi
227 
228  DO i = ilayer_min + 1, ilayer_min + ngrid(idir_surfdip)
229  hh = real((i - ilayer_min), dp)*dh(idir_surfdip, idir_surfdip)
230  vdip = vdip_fac*(-0.5_dp + (hh/cell%hmat(idir_surfdip, idir_surfdip)))* &
231  v_hartree_rspace%pw_grid%dvol/surfarea
232  IF (i > iup) THEN
233  irho = i - ngrid(idir_surfdip)
234  ELSE
235  irho = i
236  END IF
237 ! introduce a cutoff function to smoothen the edges
238  IF (abs(irho - ilayer_min) > width) THEN
239  cutoff = 1.0_dp
240  ELSE
241  cutoff = abs(sin(0.5_dp*pi*real(abs(irho - ilayer_min), dp)/real(width, dp)))
242  END IF
243  vdip = vdip*cutoff
244 
245  IF (idir_surfdip == 3) THEN
246  vdip_r%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), irho) = &
247  vdip_r%array(bo(1, 1):bo(2, 1), bo(1, 2):bo(2, 2), irho) + vdip
248  ELSEIF (idir_surfdip == 2) THEN
249  IF (irho >= bo(1, 2) .AND. irho <= bo(2, 2)) THEN
250  vdip_r%array(bo(1, 1):bo(2, 1), irho, bo(1, 3):bo(2, 3)) = &
251  vdip_r%array(bo(1, 1):bo(2, 1), irho, bo(1, 3):bo(2, 3)) + vdip
252  END IF
253  ELSE
254  IF (irho >= bo(1, 1) .AND. irho <= bo(2, 1)) THEN
255  vdip_r%array(irho, bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)) = &
256  vdip_r%array(irho, bo(1, 2):bo(2, 2), bo(1, 3):bo(2, 3)) + vdip
257  END IF
258  END IF
259 
260  END DO
261 
262 ! Dipole correction contribution to the energy
263  energy%surf_dipole = 0.5_dp*pw_integral_ab(vdip_r, wf_r, just_sum=.true.)
264 
265 ! Add the dipole potential to the hartree potential on the realspace grid
266  CALL pw_axpy(vdip_r, v_hartree_rspace)
267 
268  CALL auxbas_pw_pool%give_back_pw(wf_r)
269  CALL auxbas_pw_pool%give_back_pw(vdip_r)
270 
271  CALL timestop(handle)
272 
273  END SUBROUTINE calc_dipsurf_potential
274 
275 END MODULE surface_dipole
Handles all functions related to the CELL.
Definition: cell_types.F:15
Defines control structures, which contain the parameters and the settings for the DFT-based calculati...
sums arrays of real/complex numbers with much reduced round-off as compared to a naive implementation...
Definition: kahan_sum.F:29
Defines the basic variable types.
Definition: kinds.F:23
integer, parameter, public dp
Definition: kinds.F:34
Definition of mathematical constants and functions.
Definition: mathconstants.F:16
real(kind=dp), parameter, public pi
Definition of physical constants:
Definition: physcon.F:68
real(kind=dp), parameter, public bohr
Definition: physcon.F:147
container for various plainwaves related things
Definition: pw_env_types.F:14
subroutine, public pw_env_get(pw_env, pw_pools, cube_info, gridlevel_info, auxbas_pw_pool, auxbas_grid, auxbas_rs_desc, auxbas_rs_grid, rs_descs, rs_grids, xc_pw_pool, vdw_pw_pool, poisson_env, interp_section)
returns the various attributes of the pw env
Definition: pw_env_types.F:113
integer, parameter, public pw_mode_local
Definition: pw_grid_types.F:29
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
Definition: pw_pool_types.F:24
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_RI_aux_kp, matrix_s, matrix_s_RI_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, ecoul_1c, rho0_s_rs, rho0_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, WannierCentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, rhs)
Get the QUICKSTEP environment.
superstucture that hold various representations of the density and keeps track of which ones are vali...
Definition: qs_rho_types.F:18
subroutine, public qs_rho_get(rho_struct, rho_ao, rho_ao_im, rho_ao_kp, rho_ao_im_kp, rho_r, drho_r, rho_g, drho_g, tau_r, tau_g, rho_r_valid, drho_r_valid, rho_g_valid, drho_g_valid, tau_r_valid, tau_g_valid, tot_rho_r, tot_rho_g, rho_r_sccs, soft_valid, complex_rho_ao)
returns info about the density described by this object. If some representation is not available an e...
Definition: qs_rho_types.F:229
types that represent a quickstep subsys
subroutine, public calc_dipsurf_potential(qs_env, energy)
compute the surface dipole and the correction to the hartree potential