27 use,
intrinsic :: iso_fortran_env
49 integer,
public,
parameter :: &
50 SINGULARITY_NONE = 0, &
58 integer :: coulomb_singularity = 0
59 real(real64),
allocatable :: Fk(:)
61 real(real64) :: energy
64 real(real64) :: rcell_volume
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
84 this%rcell_volume = kpoints%latt%rcell_volume
85 this%nkpt_full = kpoints%full%npoints
87 if (.not.
allocated(this%Fk))
then
88 safe_allocate(this%Fk(1:st%nik))
92 if (space%is_periodic())
then
116 if (space%dim == 2 .or. space%dim > 3) default = singularity_none
118 call parse_variable(namespace,
'HFSingularity', default, this%coulomb_singularity)
121 if(this%coulomb_singularity /= singularity_none)
then
126 if(space%dim == 2)
then
131 if (this%coulomb_singularity /= singularity_none)
then
141 type(singularity_t),
intent(inout) :: this
145 safe_deallocate_a(this%Fk)
146 this%coulomb_singularity = -1
164 integer,
intent(in) :: ik
170 if (this%coulomb_singularity == singularity_none .or. .not.
allocated(this%Fk))
then
175 if (this%dim == 3)
then
176 v0 = -(this%Fk(ik) - this%FF) * this%rcell_volume * this%nkpt_full
178 v0 = -(this%Fk(ik) - this%FF)
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
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
202 real(real64),
parameter :: log2_minus_gamma = 0.11593151565841244881_real64
206 call profiling_in(
"COULOMB_SINGULARITY")
211 kpt_start = st%d%kpt%start
212 kpt_end = st%d%kpt%end
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
220 do ik = kpt_start, kpt_end
221 ikpoint = st%d%get_kpoint_index(ik)
222 kpoint = kpoints%get_point(ikpoint, absolute_coordinates = .false.)
226 do ik2 = 1, kpoints%full%npoints
227 qpoint = kpoint - kpoints%full%red_point(:, ik2)
230 qpoint = qpoint - anint(qpoint + 1e-5_real64)
232 if (all(abs(qpoint) < 1e-6_real64)) cycle
234 this%Fk(ik) = this%Fk(ik) +
aux_funct(qpoint) * kpoints%full%weight(ik2)
236 select case(space%dim)
238 this%Fk(ik) = this%Fk(ik)/kpoints%latt%rcell_volume
240 this%Fk(ik) = this%Fk(ik)*m_four*m_pi/kpoints%latt%rcell_volume
244 if (st%d%kpt%parallel)
then
245 call comm_allreduce(st%d%kpt%mpi_grp, this%Fk)
247 call comm_allreduce(dist_kpt%mpi_grp, this%Fk)
248 call distributed_end(dist_kpt)
263 if(space%dim == 1) default_nk = 1200
264 call parse_variable(namespace,
'HFSingularityNk', default_nk, nk)
266 message(1) =
'HFSingularityNk must be > 0.'
267 call messages_fatal(1, namespace=namespace)
269 if (mod(nk, 3) /= 0)
then
270 message(1) =
'HFSingularityNk must be a multiple of 3.'
271 call messages_fatal(1, namespace=namespace)
284 if(space%dim == 1) default_step = 15
285 call parse_variable(namespace,
'HFSingularityNsteps', default_step, nsteps)
287 select case(space%dim)
291 kvol_element = (m_one/(m_two*nk+m_one))*((m_two*m_pi))/kpoints%latt%rcell_volume
296 qpoint(1) = ikx/(m_two*nk)*length
298 if(abs(ikx)<=nk/3) cycle
299 this%FF = this%FF +
aux_funct(qpoint)*kvol_element
301 if(istep<nsteps)
then
302 length = length/m_three
303 kvol_element = kvol_element/m_three
309 this%FF = this%FF*m_two/((m_two*m_pi))
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)
316 call messages_not_implemented(
"General Coulomb singularity in the 2D case")
321 kvol_element = (m_one/(m_two*nk+m_one))**3*((m_two*m_pi)**3)/kpoints%latt%rcell_volume
325 qpoint(1) = ikx/(m_two*nk)*length
328 qpoint(2) = iky/(m_two*nk)*length
331 qpoint(3) = ikz/(m_two*nk)*length
333 if (abs(ikx) <= nk/3 .and. abs(iky) <= nk/3 .and. abs(ikz) <= nk/3) cycle
335 this%FF = this%FF +
aux_funct(qpoint)*kvol_element
339 if (istep < nsteps)
then
340 length = length / m_three
341 kvol_element = kvol_element / 27.0_real64
347 this%FF = this%FF*8.0_real64*m_pi/((m_two*m_pi)**3)
349 this%FF = this%FF + singul_cnst*(kpoints%latt%rcell_volume)**(m_twothird)/m_pi/kpoints%latt%rcell_volume*length
356 this%FF = 4.423758_real64*(kpoints%latt%rcell_volume*m_four)**(m_twothird)/m_pi/kpoints%latt%rcell_volume
361 this%FF = singul_cnst*(kpoints%latt%rcell_volume)**(m_twothird)/m_pi/kpoints%latt%rcell_volume
366 do ik = st%d%kpt%start, st%d%kpt%end
367 this%energy = this%energy + this%Fk(ik)*st%kweights(ik)
370 if (st%d%kpt%parallel)
then
371 call comm_allreduce(st%d%kpt%mpi_grp, this%energy)
375 if (st%d%ispin == spin_polarized) this%energy = m_half * this%energy
377 this%energy = (this%energy-this%FF)*st%qtot
381 if (space%dim == 3) this%energy = m_zero
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.)
388 call profiling_out(
"COULOMB_SINGULARITY")
393 real(real64) function aux_funct(qq) result(ff)
394 real(real64),
intent(in) :: qq(space%dim)
396 real(real64) :: half_a, qq_abs(space%dim)
401 select case(space%dim)
404 ff = -
log(abs(
sin(qq(1)*m_pi))*kpoints%latt%klattice(1,1)/(m_two*m_pi)) + 0.11593151565841244881_real64
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)))))
416 half_a = m_half*(kpoints%latt%rcell_volume*m_four)**(m_third)
417 call kpoints_to_absolute(kpoints%latt, qq, qq_abs)
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))
double log(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_zero
subroutine, public messages_not_implemented(feature, namespace)
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.
This module defines the unit system, used for input and output.
real(real64) function aux_funct(qq)
Treatment of the singularity in solids.