Octopus
singularity.F90
Go to the documentation of this file.
1!! Copyright (C) 2019-2022 N. Tancogne-Dejean
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
22 use comm_oct_m
23 use debug_oct_m
26 use global_oct_m
27 use, intrinsic :: iso_fortran_env
31 use mpi_oct_m
32 use parser_oct_m
35 use space_oct_m
38 use unit_oct_m
40
41 implicit none
42
43 private
44 public :: &
48
49 integer, public, parameter :: &
50 SINGULARITY_NONE = 0, &
52 singularity_gygi = 2, &
54
55
57 type singularity_t
58 integer :: coulomb_singularity = 0
59 real(real64), allocatable :: Fk(:)
60 real(real64) :: FF
61 real(real64) :: energy
62 integer :: dim
63 integer :: nkpt_full
64 real(real64) :: rcell_volume
65 contains
66 procedure :: kernel_value => singularity_kernel_value
67 end type singularity_t
68
69contains
70
71 subroutine singularity_init(this, namespace, space, st, kpoints)
72 type(singularity_t), intent(inout) :: this
73 type(namespace_t), intent(in) :: namespace
74 class(space_t), intent(in) :: space
75 type(states_elec_t), intent(in) :: st
76 type(kpoints_t), intent(in) :: kpoints
77
78 integer :: default
79
80 push_sub(singularity_init)
81
82 this%energy = m_zero
83 this%dim = space%dim
84 this%rcell_volume = kpoints%latt%rcell_volume
85 this%nkpt_full = kpoints%full%npoints
86
87 if (.not. allocated(this%Fk)) then
88 safe_allocate(this%Fk(1:st%nik))
89 this%Fk(1:st%nik) = m_zero
90 this%FF = m_zero
91
92 if (space%is_periodic()) then
93
94 !%Variable HFSingularity
95 !%Type integer
96 !%Default general
97 !%Section Hamiltonian::XC
98 !%Description
99 !% (Experimental) This variable selects the method used for the treatment of the
100 !% singularity of the Coulomb potential in Hatree-Fock and hybrid-functional DFT calculations.
101 !% This shoulbe be only applied for periodic systems and is only
102 !% used for FFT kernels of the Poisson solvers.
103 !%Option none 0
104 !% The singularity is replaced by zero.
105 !%Option general 1
106 !% The general treatment of the singularity, as described in Carrier et al, PRB 75 205126 (2007).
107 !% This is the default option
108 !%Option fcc 2
109 !% The treatment of the singulariy as described in Gygi and Baldereschi, PRB 34, 4405 (1986).
110 !% This is formally valid for cubic systems only.
111 !%Option spherical_bz 3
112 !% The divergence in q=0 is treated analytically assuming a spherical Brillouin zone
113 !%End
114
115 default = singularity_general
116 if (space%dim == 2 .or. space%dim > 3) default = singularity_none
117
118 call parse_variable(namespace, 'HFSingularity', default, this%coulomb_singularity)
119 call messages_print_var_option('HFSingularity', this%coulomb_singularity, namespace=namespace)
120
121 if(this%coulomb_singularity /= singularity_none) then
122 if(this%coulomb_singularity /= singularity_general .and. space%dim == 1) then
123 call messages_not_implemented("HFSingularity /= general for 1D")
124 end if
125
126 if(space%dim == 2) then
127 call messages_not_implemented("HFSingularity /= none for 2D")
128 end if
129 end if
130
131 if (this%coulomb_singularity /= singularity_none) then
132 call singularity_correction(this, namespace, space, st, kpoints)
133 end if
134 end if
135 end if
136
137 pop_sub(singularity_init)
138 end subroutine singularity_init
139
140 subroutine singularity_end(this)
141 type(singularity_t), intent(inout) :: this
142
143 push_sub(singularity_end)
145 safe_deallocate_a(this%Fk)
146 this%coulomb_singularity = -1
147
148 pop_sub(singularity_end)
149 end subroutine singularity_end
150
151
162 real(real64) function singularity_kernel_value(this, ik) result(v0)
163 class(singularity_t), intent(in) :: this
164 integer, intent(in) :: ik
165
167
168 v0 = m_zero
169
170 if (this%coulomb_singularity == singularity_none .or. .not. allocated(this%Fk)) then
172 return
173 endif
174
175 if (this%dim == 3) then
176 v0 = -(this%Fk(ik) - this%FF) * this%rcell_volume * this%nkpt_full
177 else
178 v0 = -(this%Fk(ik) - this%FF)
179 end if
180
182
183 end function singularity_kernel_value
184
187 subroutine singularity_correction(this, namespace, space, st, kpoints)
188 type(singularity_t), intent(inout) :: this
189 type(namespace_t), intent(in) :: namespace
190 class(space_t), intent(in) :: space
191 type(states_elec_t), intent(in) :: st
192 type(kpoints_t), intent(in) :: kpoints
193
194 integer :: ik, ik2, ikpoint, nk, nsteps
195 integer :: ikx, iky, ikz, istep, kpt_start, kpt_end
196 real(real64) :: length
197 real(real64) :: kpoint(space%dim), qpoint(space%dim)
198 real(real64) :: kvol_element
199 type(distributed_t) :: dist_kpt
200 integer :: default_nk, default_step
201 real(real64), parameter :: singul_cnst = 7.7955541794415_real64 ! The constant is 4*pi*(3/(4*pi))^1/3
202 real(real64), parameter :: log2_minus_gamma = 0.11593151565841244881_real64 ! The constant is log(2) - gamma,
203 ! where gamma is the Euler-Mascheroni constant
204 push_sub(singularity_correction)
205
206 call profiling_in("COULOMB_SINGULARITY")
207
208 !At the moment this is only implemented in 3D and in 1D.
209 assert(space%dim == 3 .or. this%coulomb_singularity == singularity_general)
210
211 kpt_start = st%d%kpt%start
212 kpt_end = st%d%kpt%end
213
214 if (.not. st%d%kpt%parallel) then
215 call distributed_init(dist_kpt, st%nik, st%system_grp%comm, "singularity")
216 kpt_start = dist_kpt%start
217 kpt_end = dist_kpt%end
218 end if
219
220 do ik = kpt_start, kpt_end
221 ikpoint = st%d%get_kpoint_index(ik)
222 kpoint = kpoints%get_point(ikpoint, absolute_coordinates = .false.)
223
224 this%Fk(ik) = m_zero
225
226 do ik2 = 1, kpoints%full%npoints
227 qpoint = kpoint - kpoints%full%red_point(:, ik2)
228
229 !We remove potential umklapp
230 qpoint = qpoint - anint(qpoint + 1e-5_real64)
231
232 if (all(abs(qpoint) < 1e-6_real64)) cycle
233
234 this%Fk(ik) = this%Fk(ik) + aux_funct(qpoint) * kpoints%full%weight(ik2)
235 end do
236 select case(space%dim)
237 case(1)
238 this%Fk(ik) = this%Fk(ik)/kpoints%latt%rcell_volume
239 case(3)
240 this%Fk(ik) = this%Fk(ik)*m_four*m_pi/kpoints%latt%rcell_volume
241 end select
242 end do
243
244 if (st%d%kpt%parallel) then
245 call comm_allreduce(st%d%kpt%mpi_grp, this%Fk)
246 else
247 call comm_allreduce(dist_kpt%mpi_grp, this%Fk)
248 call distributed_end(dist_kpt)
249 end if
250
251 if (this%coulomb_singularity == singularity_general) then
252 !%Variable HFSingularityNk
253 !%Type integer
254 !%Default 60 in 3D, 1200 in 1D
255 !%Section Hamiltonian::XC
256 !%Description
257 !% Number of k-point used (total number of k-points) is (2*Nk+1)^3) in the numerical integration
258 !% of the auxiliary function f(q). See PRB 75, 205126 (2007) for more details.
259 !% Only for HFSingularity=general.
260 !% Also used in 1D.
261 !%End
262 default_nk = 60
263 if(space%dim == 1) default_nk = 1200
264 call parse_variable(namespace, 'HFSingularityNk', default_nk, nk)
265 if (nk <= 0) then
266 message(1) = 'HFSingularityNk must be > 0.'
267 call messages_fatal(1, namespace=namespace)
268 end if
269 if (mod(nk, 3) /= 0) then
270 message(1) = 'HFSingularityNk must be a multiple of 3.'
271 call messages_fatal(1, namespace=namespace)
272 end if
273
274 !%Variable HFSingularityNsteps
275 !%Type integer
276 !%Default 7 in 3D, 15 in 1D
277 !%Section Hamiltonian::XC
278 !%Description
279 !% Number of grid refinement steps in the numerical integration of the auxiliary function f(q).
280 !% See PRB 75, 205126 (2007) for more details. Only for HFSingularity=general.
281 !% Also used in 1D.
282 !%End
283 default_step = 7
284 if(space%dim == 1) default_step = 15
285 call parse_variable(namespace, 'HFSingularityNsteps', default_step, nsteps)
286
287 select case(space%dim)
288 case(1)
289 this%FF = m_zero
290 length = m_one
291 kvol_element = (m_one/(m_two*nk+m_one))*((m_two*m_pi))/kpoints%latt%rcell_volume
292 qpoint = m_zero
293 do istep = 1, nsteps
294
295 do ikx = 0, nk
296 qpoint(1) = ikx/(m_two*nk)*length
297
298 if(abs(ikx)<=nk/3) cycle
299 this%FF = this%FF + aux_funct(qpoint)*kvol_element
300 end do
301 if(istep<nsteps) then
302 length = length/m_three
303 kvol_element = kvol_element/m_three
304 end if
305 end do
306
307 !We have a factor two because we used the fact that f(q)=f(-q)
308 !We multiply by 1/((2*pi)^1)
309 this%FF = this%FF*m_two/((m_two*m_pi))
310
311 !We add the remaining part
312 !The constant is log(2) - gamma, where gamma is the Euler-Mascheroni constant
313 this%FF = this%FF + m_two * (m_pi)/kpoints%latt%rcell_volume * length &
314 * (m_one-log(m_pi / kpoints%latt%rcell_volume * length) + log2_minus_gamma)
315 case(2)
316 call messages_not_implemented("General Coulomb singularity in the 2D case")
317
318 case(3)
319 this%FF = m_zero
320 length = m_one
321 kvol_element = (m_one/(m_two*nk+m_one))**3*((m_two*m_pi)**3)/kpoints%latt%rcell_volume
322 do istep = 1, nsteps
323
324 do ikx = 0, nk
325 qpoint(1) = ikx/(m_two*nk)*length
326
327 do iky = -nk, nk
328 qpoint(2) = iky/(m_two*nk)*length
329
330 do ikz = -nk, nk
331 qpoint(3) = ikz/(m_two*nk)*length
332
333 if (abs(ikx) <= nk/3 .and. abs(iky) <= nk/3 .and. abs(ikz) <= nk/3) cycle
334
335 this%FF = this%FF + aux_funct(qpoint)*kvol_element
336 end do
337 end do
338 end do
339 if (istep < nsteps) then
340 length = length / m_three
341 kvol_element = kvol_element / 27.0_real64
342 end if
343 end do
344
345 !We have a factor two because we used the fact that f(q)=f(-q)
346 !We multiply by 4*pi/((2*pi)^3)
347 this%FF = this%FF*8.0_real64*m_pi/((m_two*m_pi)**3)
348 !The remaining part is treated as a spherical BZ
349 this%FF = this%FF + singul_cnst*(kpoints%latt%rcell_volume)**(m_twothird)/m_pi/kpoints%latt%rcell_volume*length
350
351 end select
352
353 else if (this%coulomb_singularity == singularity_gygi) then
354 !See Eq. (7) of PRB 34, 4405 (1986)
355 !Here we use the fact that the fcc volume is a^3/4
356 this%FF = 4.423758_real64*(kpoints%latt%rcell_volume*m_four)**(m_twothird)/m_pi/kpoints%latt%rcell_volume
357
358 else
359 !The constant is 4*pi*(3/(4*pi))^1/3
360 !We multiply by 4*pi/(2*pi^3)
361 this%FF = singul_cnst*(kpoints%latt%rcell_volume)**(m_twothird)/m_pi/kpoints%latt%rcell_volume
362 end if
363
364
365 this%energy = m_zero
366 do ik = st%d%kpt%start, st%d%kpt%end
367 this%energy = this%energy + this%Fk(ik)*st%kweights(ik)
368 end do
369
370 if (st%d%kpt%parallel) then
371 call comm_allreduce(st%d%kpt%mpi_grp, this%energy)
372 end if
373
374 ! In the case, the number of k-point is doubled, so the energy is twice larger
375 if (st%d%ispin == spin_polarized) this%energy = m_half * this%energy
376
377 this%energy = (this%energy-this%FF)*st%qtot
378 ! In 3D the q+G=0 kernel value (singularity_kernel_value) carries the whole correction, which in the
379 ! exchange energy amounts to half of the expression above: nothing has to be added to the expectation
380 ! value of the exchange operator. The 1D convention is kept.
381 if (space%dim == 3) this%energy = m_zero
382
383 write(message(1), '(a,f12.6,a,a,a)') 'Debug: Singularity energy ', &
384 units_from_atomic(units_out%energy, this%energy), &
385 ' [',trim(units_abbrev(units_out%energy)),']'
386 call messages_info(1, namespace=namespace, debug_only=.true.)
387
388 call profiling_out("COULOMB_SINGULARITY")
390
391 contains
392
393 real(real64) function aux_funct(qq) result(ff)
394 real(real64), intent(in) :: qq(space%dim)
395
396 real(real64) :: half_a, qq_abs(space%dim)
397
398 ! no PUSH/POP as called too often
399
400 if (this%coulomb_singularity == singularity_general) then
401 select case(space%dim)
402 case(1)
403 !The constant is -log(2) + gamma, where gamma is the Euler-Mascheroni constant
404 ff = -log(abs(sin(qq(1)*m_pi))*kpoints%latt%klattice(1,1)/(m_two*m_pi)) + 0.11593151565841244881_real64
405 case(3)
406 !See Eq. (16) of PRB 75, 205126 (2007)
407 ff = (m_two*m_pi)**2/(m_two*( &
408 (m_two*sin(qq(1)*m_pi)*sin(qq(1)*m_pi)*dot_product(kpoints%latt%klattice(:,1), kpoints%latt%klattice(:,1)) &
409 + sin(qq(1)*m_two*m_pi)*sin(qq(2)*m_two*m_pi)*dot_product(kpoints%latt%klattice(:,1), kpoints%latt%klattice(:,2))) &
410 + (m_two*sin(qq(2)*m_pi)*sin(qq(2)*m_pi)*dot_product(kpoints%latt%klattice(:,2), kpoints%latt%klattice(:,2)) &
411 + sin(qq(2)*m_two*m_pi)*sin(qq(3)*m_two*m_pi)*dot_product(kpoints%latt%klattice(:,2), kpoints%latt%klattice(:,3))) &
412 + (m_two*sin(qq(3)*m_pi)*sin(qq(3)*m_pi)*dot_product(kpoints%latt%klattice(:,3), kpoints%latt%klattice(:,3)) &
413 + sin(qq(3)*m_two*m_pi)*sin(qq(1)*m_two*m_pi)*dot_product(kpoints%latt%klattice(:,3), kpoints%latt%klattice(:,1)))))
414 end select
415 else
416 half_a = m_half*(kpoints%latt%rcell_volume*m_four)**(m_third)
417 call kpoints_to_absolute(kpoints%latt, qq, qq_abs)
418 !See Eq. (6) of PRB 34, 4405 (1986)
419 ff = (half_a)**2/(m_three-cos(qq_abs(1)*half_a)*cos(qq_abs(2)*half_a) &
420 -cos(qq_abs(1)*half_a)*cos(qq_abs(3)*half_a) &
421 -cos(qq_abs(3)*half_a)*cos(qq_abs(2)*half_a))
422 end if
423
424 end function aux_funct
425
426 end subroutine singularity_correction
427
428end module singularity_oct_m
429
430!! Local Variables:
431!! mode: f90
432!! coding: utf-8
433!! End:
double log(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_zero
Definition: global.F90:200
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1068
subroutine singularity_correction(this, namespace, space, st, kpoints)
This routine implements the general treatment of the singularity for periodic solids,...
integer, parameter, public singularity_general
subroutine, public singularity_end(this)
integer, parameter, public singularity_sphere
real(real64) function singularity_kernel_value(this, ik)
Value of the exchange kernel at for the k-point ik.
subroutine, public singularity_init(this, namespace, space, st, kpoints)
integer, parameter, public singularity_gygi
This module handles spin dimensions of the states and the k-point distribution.
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
This module defines the unit system, used for input and output.
real(real64) function aux_funct(qq)
Treatment of the singularity in solids.
int true(void)