26 use,
intrinsic :: iso_fortran_env
57 integer,
public :: method
58 real(real64),
public :: dsmear
59 real(real64) :: dsmear_cond
60 real(real64),
public :: e_fermi
61 real(real64) :: e_fermi_cond
63 integer,
public :: el_per_state
64 real(real64),
public :: ef_occ
65 real(real64) :: ef_occ_cond
66 logical,
public :: integral_occs
67 integer,
public :: MP_n
68 integer :: fermi_count
72 type(simplex_t),
pointer :: tetra_simplex => null()
75 logical,
public:: photodop
76 real(real64) :: nephotodop
77 integer :: photodop_bandmin
81 integer,
parameter,
public :: &
82 SMEAR_SEMICONDUCTOR = 1, &
93 real(real64),
parameter :: TOL_SMEAR = 1e-6_real64
98 subroutine smear_init(this, namespace, ispin, fixed_occ, integral_occs, kpoints)
99 type(smear_t),
intent(out) :: this
100 type(namespace_t),
intent(in) :: namespace
101 integer,
intent(in) :: ispin
102 logical,
intent(in) :: fixed_occ
103 logical,
intent(in) :: integral_occs
104 type(kpoints_t),
intent(in) :: kpoints
108 this%integral_occs = integral_occs
146 call parse_variable(namespace,
'SmearingFunction', smear_semiconductor, this%method)
160 this%dsmear = 1e-14_real64
174 this%dsmear_cond = this%dsmear
175 if (this%method /= smear_semiconductor .and. this%method /=
smear_fixed_occ)
then
192 this%photodop=.false.
203 call parse_variable(namespace,
'PhotoDopingBand', 1, this%photodop_bandmin)
209 this%el_per_state = 2
211 this%el_per_state = 1
220 if (this%method == smear_semiconductor)
then
223 if (this%nik_factor == 0)
then
224 message(1) =
"k-point weights in KPoints or KPointsReduced blocks must be rational numbers for semiconducting smearing."
228 if (.not.
associated(kpoints%reduced%simplex))
then
229 message(1) =
"Tetrahedron smearing requires a simplex mesh for the k-point grid."
233 this%tetra_simplex => kpoints%reduced%simplex
254 type(
smear_t),
intent(out) :: to
255 type(
smear_t),
intent(in) :: from
259 to%method = from%method
260 to%dsmear = from%dsmear
261 to%e_fermi = from%e_fermi
262 to%el_per_state = from%el_per_state
263 to%ef_occ = from%ef_occ
265 to%fermi_count = from%fermi_count
266 to%nik_factor = from%nik_factor
267 to%tetra_simplex => from%tetra_simplex
269 to%dsmear_cond = from%dsmear_cond
270 to%e_fermi_cond = from%e_fermi_cond
271 to%ef_occ_cond = from%ef_occ_cond
272 to%integral_occs = from%integral_occs
273 to%nspins = from%nspins
274 to%photodop = from%photodop
275 to%nephotodop = from%nephotodop
276 to%photodop_bandmin = from%photodop_bandmin
284 qtot, nik, nst, kweights)
285 type(
smear_t),
intent(inout) :: this
287 real(real64),
intent(in) :: eigenvalues(:,:), occupations(:,:)
288 real(real64),
intent(in) :: qtot, kweights(:)
289 integer,
intent(in) :: nik, nst
291 real(real64),
parameter :: tol = 1.0e-10_real64
292 integer :: ist, ik, iter, maxq, weight, sumq_int, sum_weight
293 real(real64) :: sumq_frac
295 real(real64),
allocatable :: eigenval_list(:)
296 integer,
allocatable :: k_list(:), reorder(:)
297 integer :: fermi_count_up, fermi_count_down
301 maxq = this%el_per_state * nst * this%nspins
302 if (maxq - qtot <= -tol)
then
303 message(1) =
'Not enough states'
304 write(
message(2),
'(6x,a,f12.6,a,i10)')
'(total charge = ', qtot, &
305 ' max charge = ', maxq
311 ist_cycle:
do ist = nst, 1, -1
312 if (any(occupations(ist, :) >
m_min_occ))
then
313 this%e_fermi = eigenvalues(ist, 1)
314 this%ef_occ = occupations(ist, 1) / this%el_per_state
316 if (eigenvalues(ist, ik) > this%e_fermi .and. occupations(ist, ik) >
m_min_occ)
then
317 this%e_fermi = eigenvalues(ist, ik)
318 this%ef_occ = occupations(ist, ik) / this%el_per_state
325 else if (this%method == smear_semiconductor)
then
327 safe_allocate(eigenval_list(1:nst * nik))
328 safe_allocate( k_list(1:nst * nik))
329 safe_allocate( reorder(1:nst * nik))
334 eigenval_list(iter) = eigenvalues(ist, ik)
341 call sort(eigenval_list, reorder)
343 sumq_int =
floor(qtot) * this%nik_factor
344 sumq_frac = qtot * this%nik_factor - sumq_int
345 if ( sumq_frac + tol > this%nik_factor )
then
346 sumq_int = sumq_int + this%nik_factor
347 sumq_frac = sumq_frac - this%nik_factor
349 if (sumq_frac < tol) sumq_frac =
m_zero
351 do iter = 1, nst * nik
352 weight = int(kweights(k_list(reorder(iter))) * this%nik_factor +
m_half)
353 if (weight <= 0) cycle
354 this%e_fermi = eigenval_list(iter)
355 this%ef_occ = (sumq_int + sumq_frac) / (weight * this%el_per_state)
357 if (sumq_int - weight * this%el_per_state <= 0)
then
365 if (iter - fermi_count_down < 1)
exit
366 if (abs(this%e_fermi - eigenval_list(iter - fermi_count_down)) > tol_smear)
exit
367 weight = int(kweights(k_list(reorder(iter - fermi_count_down))) * this%nik_factor +
m_half)
369 sumq_int = sumq_int + weight * this%el_per_state
370 sum_weight = sum_weight + weight
372 fermi_count_down = fermi_count_down + 1
375 if (iter + fermi_count_up > nst*nik)
exit
376 if (abs(this%e_fermi - eigenval_list(iter + fermi_count_up)) > tol_smear)
exit
377 weight = int(kweights(k_list(reorder(iter + fermi_count_up))) * this%nik_factor +
m_half)
379 sum_weight = sum_weight + weight
381 fermi_count_up = fermi_count_up + 1
383 this%fermi_count = fermi_count_up + fermi_count_down - 1
384 this%ef_occ = (sumq_int + sumq_frac) / (sum_weight * this%el_per_state)
388 sumq_int = sumq_int - weight * this%el_per_state
392 safe_deallocate_a(eigenval_list)
393 safe_deallocate_a(k_list)
394 safe_deallocate_a(reorder)
397 if (this%photodop)
then
402 if (this%photodop)
then
405 eigenvalues, kweights, nik, qtot-this%nephotodop, 1, this%photodop_bandmin-1, &
406 this%e_fermi, this%ef_occ)
410 eigenvalues, kweights, nik, this%nephotodop, this%photodop_bandmin, nst, &
411 this%e_fermi_cond, this%ef_occ_cond)
414 eigenvalues, kweights, nik, qtot, 1, nst, this%e_fermi, this%ef_occ)
423 eigenvalues, kweights, nik, q_in, start_band, end_band, e_fermi, ef_occ)
424 type(
smear_t),
intent(inout) :: this
426 real(real64),
intent(in) :: dsmear_in
427 real(real64),
intent(in) :: tol
428 integer,
intent(in) :: nik
429 real(real64),
intent(in) :: eigenvalues(:,:)
430 real(real64),
intent(in) :: kweights(:), q_in
431 integer,
intent(in) :: start_band, end_band
432 real(real64),
intent(out) :: e_fermi, ef_occ
434 integer,
parameter :: nitmax = 200
435 integer :: ist, ik, iter
436 real(real64) :: drange, dsmear, emin, emax, xx, sumq
441 dsmear = max(1e-14_real64, dsmear_in)
442 drange = dsmear *
sqrt(-
log(tol * 0.01_real64))
444 emin = minval(eigenvalues) - drange
445 emax = maxval(eigenvalues) + drange
448 e_fermi =
m_half * (emin + emax)
452 do ist = start_band, end_band
453 xx = (e_fermi - eigenvalues(ist, ik))/dsmear
454 sumq = sumq + kweights(ik) * this%el_per_state * &
459 conv = (abs(sumq - q_in) <= tol)
462 if (sumq <= q_in) emin = e_fermi
463 if (sumq >= q_in) emax = e_fermi
469 message(1) =
'Fermi: did not converge.'
497 type(
smear_t),
intent(inout) :: this
499 real(real64),
intent(in) :: tol
500 integer,
intent(in) :: nik, nst
501 real(real64),
intent(in) :: eigenvalues(:,:)
502 real(real64),
intent(in) :: q_in
503 real(real64),
intent(out) :: e_fermi
505 integer,
parameter :: nitmax = 200
507 real(real64) :: emin, emax, sumq
510 integer :: ist, ii, ll, is, ik, ns, nik_red, nvertices
511 real(real64) :: e_simplex(20), w_simplex(4), dos_simplex(4)
515 assert(
associated(this%tetra_simplex))
516 assert(this%tetra_simplex%n_simplices > 0)
517 assert(this%tetra_simplex%sdim > 0)
521 assert(mod(nik, ns) == 0)
524 assert(maxval(this%tetra_simplex%simplices) <= nik_red)
526 nvertices = this%tetra_simplex%rdim + 1
527 assert(nvertices > 0)
528 assert(nvertices <= this%tetra_simplex%sdim)
530 emin = minval(eigenvalues)
531 emax = maxval(eigenvalues)
532 if (.not. (emin < emax))
then
533 write(
message(1),
'(a)')
'Tetra bisection: invalid energy bracket from eigenvalues.'
538 e_fermi =
m_half * (emin + emax)
542 do ii = 1, this%tetra_simplex%n_simplices
544 do ll = 1, this%tetra_simplex%sdim
545 ik = ns * (this%tetra_simplex%simplices(ii, ll) - 1) + 1
546 e_simplex(ll) = eigenvalues(ist, ik + is)
550 call simplex_weights(this%tetra_simplex%rdim, e_simplex(1:this%tetra_simplex%sdim), e_fermi, &
551 w_simplex(1:nvertices), dos_simplex(1:nvertices))
554 sumq = sumq + this%el_per_state * w_simplex(ll) / this%tetra_simplex%n_points
561 conv = (abs(sumq - q_in) <= tol)
564 if (sumq <= q_in) emin = e_fermi
565 if (sumq >= q_in) emax = e_fermi
569 message(1) =
'Fermi (tetrahedra): did not converge.'
578 type(
smear_t),
intent(in) :: this
579 real(real64),
intent(in) :: eigenvalues(:,:)
580 real(real64),
intent(inout) :: occupations(:,:)
581 real(real64),
intent(in) :: kweights(:)
582 integer,
intent(in) :: nik, nst
584 integer :: ik, ist, ifermi
585 real(real64) :: dsmear, xx, dsmear_cond
591 else if (this%method == smear_semiconductor)
then
592 assert(this%fermi_count > 0 .and. this%fermi_count <= nik*nst)
597 xx = eigenvalues(ist, ik) - this%e_fermi
598 if (xx < -tol_smear)
then
599 occupations(ist, ik) = this%el_per_state
600 else if (abs(xx) <= tol_smear .and. ifermi < this%fermi_count)
then
601 occupations(ist, ik) = this%ef_occ * this%el_per_state
604 occupations(ist, ik) =
m_zero
610 if (this%photodop)
then
614 integer :: ii, ll, is, ns, nik_red, nvertices
615 real(real64) :: e_simplex(20), w_simplex(4), dos_simplex(4)
617 assert(
associated(this%tetra_simplex))
618 assert(this%tetra_simplex%n_simplices > 0)
619 assert(this%tetra_simplex%sdim > 0)
623 assert(mod(nik, ns) == 0)
626 assert(maxval(this%tetra_simplex%simplices) <= nik_red)
628 nvertices = this%tetra_simplex%rdim + 1
629 assert(nvertices > 0)
630 assert(nvertices <= this%tetra_simplex%sdim)
632 occupations(:, :) =
m_zero
635 do ii = 1, this%tetra_simplex%n_simplices
637 do ll = 1, this%tetra_simplex%sdim
638 ik = ns * (this%tetra_simplex%simplices(ii, ll) - 1) + 1
639 e_simplex(ll) = eigenvalues(ist, ik + is)
643 call simplex_weights(this%tetra_simplex%rdim, e_simplex(1:this%tetra_simplex%sdim), this%e_fermi, &
644 w_simplex(1:nvertices), dos_simplex(1:nvertices))
647 ik = ns * (this%tetra_simplex%simplices(ii, ll) - 1) + 1
649 occupations(ist, ik + is) = occupations(ist, ik + is) + this%el_per_state * &
650 w_simplex(ll) / (this%tetra_simplex%n_points * kweights(ik + is))
658 dsmear = max(1e-14_real64, this%dsmear)
659 if (this%photodop)
then
660 dsmear_cond = max(1e-14_real64, this%dsmear_cond)
663 if (ist < this%photodop_bandmin)
then
665 xx = (this%e_fermi - eigenvalues(ist, ik))/dsmear
668 xx = (this%e_fermi_cond - eigenvalues(ist, ik))/dsmear_cond
676 xx = (this%e_fermi - eigenvalues(ist, ik))/dsmear
688 nik, nst, kweights, occ) result(entropy)
689 type(
smear_t),
intent(in) :: this
690 real(real64),
intent(in) :: eigenvalues(:,:)
691 real(real64),
intent(in) :: kweights(:)
692 integer,
intent(in) :: nik, nst
693 real(real64),
intent(in) :: occ(:, :)
696 real(real64) :: dsmear, xx, term, ff
708 ff = occ(ist, ik) / this%el_per_state
709 if (ff > m_zero .and. ff < m_one)
then
710 term = ff *
log(ff) + (1 - ff) *
log(1 - ff)
714 entropy = entropy - kweights(ik) * this%el_per_state * term
718 dsmear = max(1e-14_real64, this%dsmear)
722 if (eigenvalues(ist, ik) < huge(m_one))
then
723 xx = (this%e_fermi - eigenvalues(ist, ik)) / dsmear
724 entropy = entropy - kweights(ik) * this%el_per_state * &
737 type(
smear_t),
intent(in) :: this
738 real(real64),
intent(in) :: xx
740 real(real64),
parameter :: maxarg = 200.0_real64
741 real(real64) :: xp, arg, hd, hp, aa
750 select case (this%method)
752 if (abs(xx) <= m_epsilon)
then
757 if (abs(xx) <= 36.0_real64)
then
758 deltaf = m_one / (m_two +
exp(-xx) +
exp(xx))
762 xp = xx - m_one /
sqrt(m_two)
763 arg = min(maxarg, xp**2)
765 deltaf =
exp(-arg) /
sqrt(m_pi) * (m_two -
sqrt(m_two) * xx)
768 arg = min(maxarg, xx**2)
769 deltaf =
exp(-arg) /
sqrt(m_pi)
771 if (this%MP_n > 0)
then
775 aa = m_one /
sqrt(m_pi)
777 hd = m_two * xx * hp - m_two * ni * hd
779 aa = -aa / (m_four * ii)
780 hp = m_two * xx * hd - m_two * ni * hp
782 deltaf = deltaf + aa * hp
787 xp = abs(xx) + m_one /
sqrt(m_two)
788 deltaf =
sqrt(m_e) * xp *
exp(-xp * xp)
791 deltaf =
exp(-xx * xx) /
sqrt(m_pi)
794 deltaf = m_one / (m_pi * (xx * xx + m_one))
803 type(
smear_t),
intent(in) :: this
804 real(real64),
intent(in) :: xx
806 real(real64),
parameter :: maxarg = 200.0_real64
807 real(real64) :: xp, arg, hd, hp, aa
816 select case (this%method)
818 if (xx > m_zero)
then
820 else if (abs(xx) <= m_epsilon)
then
825 if (xx > maxarg)
then
827 else if (xx > -maxarg)
then
828 stepf = m_one / (m_one +
exp(-xx))
832 xp = xx - m_one /
sqrt(m_two)
833 arg = min(maxarg, xp**2)
835 stepf = m_half * erf(xp) + &
836 m_one /
sqrt(m_two * m_pi) *
exp(-arg) + m_half
839 stepf = m_half * erfc(-xx)
841 if (this%MP_n > 0)
then
843 arg = min(maxarg, xx**2)
846 aa = m_one /
sqrt(m_pi)
848 hd = m_two * xx * hp - m_two * ni * hd
850 aa = -aa / (m_four * ii)
851 stepf = stepf - aa * hd
852 hp = m_two * xx * hd - m_two * ni * hp
858 if (xx <= m_zero)
then
859 xp = xx - m_one /
sqrt(m_two)
860 stepf = m_half *
sqrt(m_e) *
exp(-xp * xp)
862 xp = xx + m_one /
sqrt(m_two)
863 stepf = m_one - m_half *
sqrt(m_e) *
exp(-xp * xp)
867 stepf = m_half * erfc(-xx)
870 stepf =
atan(xx) / m_pi + m_half
881 type(
smear_t),
intent(in) :: this
882 real(real64),
intent(in) :: xx
884 real(real64),
parameter :: maxarg = 200.0_real64
885 real(real64) :: xp, arg, hd, hp, hpm1, aa
894 select case (this%method)
898 if (abs(xx) <= 36.0_real64)
then
899 xp = m_one / (m_one +
exp(-xx))
900 entropyf = xp *
log(xp) + (m_one - xp) *
log(m_one - xp)
904 xp = xx - m_one /
sqrt(m_two)
905 arg = min(maxarg, xp**2)
907 entropyf = m_one /
sqrt(m_two * m_pi) * xp *
exp(-arg)
910 arg = min(maxarg, xx**2)
911 entropyf = -m_half *
exp(-arg) /
sqrt(m_pi)
913 if (this%MP_n > 0)
then
917 aa = m_one /
sqrt(m_pi)
919 hd = m_two * xx * hp - m_two * ni * hd
922 hp = m_two * xx * hd - m_two * ni * hp
924 aa = -aa / (m_four * ii)
925 entropyf = entropyf - aa * (m_half * hp + hpm1 * ni)
930 xp = abs(xx) + m_one /
sqrt(m_two)
931 entropyf = -
sqrt(m_e) * (abs(xx) *
exp(-xp * xp) / m_two +
sqrt(m_pi) / m_four * erfc(xp))
934 entropyf = -
exp(-xx * xx) / m_two /
sqrt(m_pi)
947 type(
smear_t),
intent(in) :: this
954 type(
smear_t),
intent(in) :: this
955 type(namespace_t),
intent(in) :: namespace
956 integer,
optional,
intent(in) :: iunit
960 if (this%photodop)
then
961 write(message(1),
'(a,f12.6,1x,a)')
"Fermi energy (valence ) = ", &
962 units_from_atomic(units_out%energy, this%e_fermi), units_abbrev(units_out%energy)
963 write(message(2),
'(a,f12.6,1x,a)')
"Fermi energy (conduction) = ", &
964 units_from_atomic(units_out%energy, this%e_fermi_cond), units_abbrev(units_out%energy)
965 call messages_info(2, iunit=iunit, namespace=namespace)
967 write(message(1),
'(a,f12.6,1x,a)')
"Fermi energy = ", &
968 units_from_atomic(units_out%energy, this%e_fermi), units_abbrev(units_out%energy)
969 call messages_info(1, iunit=iunit, namespace=namespace)
This is the common interface to a sorting routine. It performs the shell algorithm,...
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
double atan(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double floor(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
real(real64), parameter, public p_ry
real(real64), parameter, public m_epsilon
real(real64), parameter, public m_half
real(real64), parameter, public m_one
real(real64), parameter, public m_min_occ
Minimal occupation that is considered to be non-zero.
integer function, public kpoints_kweight_denominator(this)
subroutine, public messages_not_implemented(feature, namespace)
subroutine, public messages_obsolete_variable(namespace, name, rep)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_input_error(namespace, var, details, row, column)
integer, parameter, public smear_tetrahedra_opt
real(real64) function, public smear_calc_entropy(this, eigenvalues, nik, nst, kweights, occ)
integer, parameter, public smear_tetrahedra
subroutine, public smear_find_fermi_energy(this, namespace, eigenvalues, occupations, qtot, nik, nst, kweights)
real(real64) function, public smear_entropy_function(this, xx)
This function is defined as .
real(real64) function, public smear_delta_function(this, xx)
integer, parameter, public smear_fermi_dirac
subroutine bisection_find_fermi_energy_tetra(this, namespace, tol, eigenvalues, nik, nst, q_in, e_fermi)
Finds the Fermi energy using the tetrahedron method via bisection.
integer, parameter, public smear_methfessel_paxton
subroutine, public smear_write_info(this, namespace, iunit)
real(real64) function, public smear_step_function(this, xx)
integer, parameter, public smear_semiconductor
subroutine, public smear_fill_occupations(this, eigenvalues, occupations, kweights, nik, nst)
integer, parameter, public smear_lorentzian
subroutine, public smear_copy(to, from)
integer, parameter, public smear_fixed_occ
integer, parameter, public smear_spline
subroutine bisection_find_fermi_energy(this, namespace, dsmear_in, tol, eigenvalues, kweights, nik, q_in, start_band, end_band, e_fermi, ef_occ)
subroutine, public smear_init(this, namespace, ispin, fixed_occ, integral_occs, kpoints)
integer, parameter, public smear_cold
logical pure function, public smear_is_semiconducting(this)
integer, parameter, public smear_gaussian
This module is intended to contain "only mathematical" functions and procedures.
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.
type(unit_system_t), public units_inp
the units systems for reading and writing