SIRIUS 7.5.0
Electronic structure library and applications
smearing.cpp
1#include <cmath>
2#include "smearing.hpp"
3#include "core/constants.hpp"
5
6namespace sirius {
7
8namespace smearing {
9
10const double pi = 3.1415926535897932385;
11
12const double sqrt2 = std::sqrt(2.0);
13
14double
15gaussian::delta(double x__, double width__)
16{
17 double t = std::pow(x__ / width__, 2);
18 return std::exp(-t) / std::sqrt(pi) / width__;
19}
20
21double
22gaussian::occupancy(double x__, double width__)
23{
24 return 0.5 * (1 + std::erf(x__ / width__));
25}
26
27double
28gaussian::entropy(double x__, double width__)
29{
30 double t = std::pow(x__ / width__, 2);
31 return -std::exp(-t) * width__ / 2.0 / std::sqrt(pi);
32}
33
34double
35fermi_dirac::delta(double x__, double width__)
36{
37 double t = x__ / 2.0 / width__;
38 return 1.0 / std::pow(std::exp(t) + std::exp(-t), 2) / width__;
39}
40
41double
42fermi_dirac::occupancy(double x__, double width__)
43{
44 return 1.0 - 1.0 / (1.0 + std::exp(x__ / width__));
45}
46
47double
48fermi_dirac::entropy(double x__, double width__)
49{
50 double t = x__ / width__;
51 double f = 1.0 / (1.0 + std::exp(t));
52 if (std::abs(f - 1.0) * std::abs(f) < 1e-16) {
53 return 0;
54 }
55 return width__ * ((1 - f) * std::log(1 - f) + f * std::log(f));
56}
57
58/** Second derivative of occupation function.
59 * \f[
60 * -\frac{e^{x/w} \left(e^{x/w}-1\right)}{w^2 \left(e^{x/w}+1\right)^3}
61 * \f]
62 */
63double
64fermi_dirac::dxdelta(double x__, double width__)
65{
66 double exw = std::exp(x__ / width__);
67 double w2 = width__ * width__;
68 return -exw * (exw - 1) / (std::pow(1 + exw, 3) * w2);
69}
70
71double
72cold::occupancy(double x__, double width__)
73{
74 double x = x__ / width__ - 1.0 / sqrt2;
75 double x2 = x * x;
76 double f = std::erf(x) / 2.0 + 0.5;
77
78 if (x2 > 700)
79 return f;
80
81 // std::erf(x) / 2.0 + std::exp(-x2) / std::sqrt(2 * pi) + 0.5;
82 return f + std::exp(-x2) / std::sqrt(2 * pi);
83}
84
85double
86cold::delta(double x__, double width__)
87{
88 double x = x__ / width__ - 1.0 / sqrt2;
89 double x2 = x * x;
90 if (x2 > 700)
91 return 0;
92 return std::exp(-x2) * (2 * width__ - sqrt2 * x__) / std::sqrt(pi) / width__ / width__;
93}
94
95/** Second derivative of the occupation function \f$f(x,w)\f$.
96 * \f[
97 * \frac{\partial^2 f(x,w)}{\partial x^2} = \frac{e^{-y^2} \left(2 \sqrt{2} y^2-2 y-\sqrt{2}\right)}{\sqrt{\pi }
98 * w^2}, \qquad y=\frac{x}{w} - \frac{1}{\sqrt{2}} \f]
99 */
100double
101cold::dxdelta(double x__, double width__)
102{
103 double sqrt2 = std::sqrt(2.0);
104 double z = x__ / width__ - 1 / sqrt2;
105 double z2 = z * z;
106 if (z2 > 700)
107 return 0;
108 double expmz2 = std::exp(-z2);
109 return expmz2 * (-sqrt2 - 2 * z + 2 * sqrt2 * z * z) / std::sqrt(pi) / width__ / width__;
110}
111
112double
113cold::entropy(double x__, double width__)
114{
115 double x = x__ / width__ - 1.0 / sqrt2;
116 double x2 = x * x;
117 if (x2 > 700)
118 return 0;
119 return -std::exp(-x2) * (width__ - sqrt2 * x__) / 2 / std::sqrt(pi);
120}
121
122/**
123 Coefficients \f$A_n\f$ required to compute the MP-smearing:
124 \f[
125 \frac{(-1)^n}{n! 4^n \sqrt{\pi}}
126 \f]
127 */
128double
130{
131 double sqrtpi = std::sqrt(pi);
132 int sign = n % 2 == 0 ? 1 : -1;
133 return sign / tgamma(n + 1) / std::pow(4, n) / sqrtpi;
134}
135
136double
137methfessel_paxton::occupancy(double x__, double width__, int n__)
138{
139 double z = -x__ / width__;
140 double result{0};
141 result = 0.5 * (1 - std::erf(z));
142 // todo s0 is missing
143 for (int i = 1; i <= n__; ++i) {
144 double A = mp_coefficients(i);
145 result += A * sf::hermiteh(2 * i - 1, z) * std::exp(-z * z);
146 }
147 return result;
148}
149
150double
151methfessel_paxton::delta(double x__, double width__, int n__)
152{
153 double z = -x__ / width__;
154 double result = -std::exp(-z * z) / std::sqrt(pi) / width__ * (-1);
155 for (int i = 1; i <= n__; ++i) {
156 double A = mp_coefficients(i);
157 result += A * sf::hermiteh(2 * i, z) * std::exp(-z * z);
158 }
159 return result;
160}
161
162double
163methfessel_paxton::dxdelta(double x__, double width__, int n__)
164{
165 double z = -x__ / width__;
166 double result = 2 * std::exp(-z * z) * z / std::sqrt(pi) / (width__ * width__);
167 for (int i = 1; i <= n__; ++i) {
168 double A = mp_coefficients(i);
169 result += A * sf::hermiteh(2 * i + 1, z) * std::exp(-z * z);
170 }
171 return result;
172}
173
174double
175methfessel_paxton::entropy(double x__, double width__, int n__)
176{
177 // see Moodules/w1gauss.f90:74 in function w1gauss (QE code)
178 double x = x__ / width__;
179 double arg = std::min(200.0, x * x);
180 double S = -0.5 * std::exp(-arg) / std::sqrt(pi);
181 if (n__ == 0)
182 return S;
183 double hd{0};
184 double hp = std::exp(-arg);
185 int ni = 0;
186 double a = 1 / std::sqrt(pi);
187 for (int i = 1; i <= n__; ++i) {
188 hd = 2 * x * hp - 2 * ni * hd;
189 ni += 1;
190 double hpm1 = hp;
191 hp = 2 * x * hd - 2 * ni * hp;
192 ni += 1;
193 a = -a / (i + 4.0);
194 S = S - a * (0.5 * hp + ni * hpm1);
195 }
196 return S;
197}
198
199} // namespace smearing
200
201} // namespace sirius
Various constants.
double mp_coefficients(int n)
Definition: smearing.cpp:129
Namespace of the SIRIUS library.
Definition: sirius.f90:5
const double pi
Definition: constants.hpp:42
int sign(T val)
Sign of the variable.
Definition: math_tools.hpp:52
Smearing functions used in finding the band occupancies.
Special functions.
static double dxdelta(double x__, double width__)
Definition: smearing.cpp:101
static double dxdelta(double x__, double width__)
Definition: smearing.cpp:64