PLaSK library
Loading...
Searching...
No Matches
fd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include <limits>
15#include "plask/math.hpp"
16
17#include "fd.hpp"
18
19namespace plask {
20
21
22static double clenshaw(std::size_t n, const double* coeffs, double x, double left, double right) {
23 double b1 = 0.;
24 double b2 = 0.;
25
26 double t = (2.*x - left - right) / (right - left);
27 double t2 = 2. * t;
28
29 for(std::size_t k = n-1; k >= 1; k--) {
30 double b0 = coeffs[k] + t2 * b1 - b2;
31 b2 = b1; b1 = b0;
32 }
33
34 return 0.5 * coeffs[0] + t * b1 - b2 ;
35}
36
37// F_{1/2}(t); -1 < x < 1
38static const double fd_half_coeffs_1_1[] = {
39 1.7177138871306189157,
40 0.6192579515822668460,
41 0.0932802275119206269,
42 0.0047094853246636182,
43 -0.0004243667967864481,
44 -0.0000452569787686193,
45 5.2426509519168e-6,
46 6.387648249080e-7,
47 -8.05777004848e-8,
48 -1.04290272415e-8,
49 1.3769478010e-9,
50 1.847190359e-10,
51 -2.51061890e-11,
52 -3.4497818e-12,
53 4.784373e-13,
54 6.68828e-14,
55 -9.4147e-15,
56 -1.3333e-15,
57 1.898e-16,
58 2.72e-17,
59 -3.9e-18,
60 -6.e-19,
61 1.e-19
62};
63
64// F_{1/2}(3/2(t+1) + 1); 1 < x < 4
65static const double fd_half_coeffs_1_4[] = {
66 7.651013792074984027,
67 2.475545606866155737,
68 0.218335982672476128,
69 -0.007730591500584980,
70 -0.000217443383867318,
71 0.000147663980681359,
72 -0.000021586361321527,
73 8.07712735394e-7,
74 3.28858050706e-7,
75 -7.9474330632e-8,
76 6.940207234e-9,
77 6.75594681e-10,
78 -3.10200490e-10,
79 4.2677233e-11,
80 -2.1696e-14,
81 -1.170245e-12,
82 2.34757e-13,
83 -1.4139e-14,
84 -3.864e-15,
85 1.202e-15
86};
87
88// F_{1/2}(3(t+1) + 4); 4 < x < 10
89static const double fd_half_coeffs_4_10[] = {
90 29.584339348839816528,
91 8.808344283250615592,
92 0.503771641883577308,
93 -0.021540694914550443,
94 0.002143341709406890,
95 -0.000257365680646579,
96 0.000027933539372803,
97 -1.678525030167e-6,
98 -2.78100117693e-7,
99 1.35218065147e-7,
100 -3.3740425009e-8,
101 6.474834942e-9,
102 -1.009678978e-9,
103 1.20057555e-10,
104 -6.636314e-12,
105 -1.710566e-12,
106 7.75069e-13,
107 -1.97973e-13,
108 3.9414e-14,
109 -6.374e-15,
110 7.77e-16,
111 -4.0e-17,
112 -1.4e-17
113};
114
115// F_{1/2}(x) / x^(3/2); 10 < x < 30
116static const double fd_half_coeffs_10_30[] = {
117 1.5116909434145508537,
118 -0.0036043405371630468,
119 0.0014207743256393359,
120 -0.0005045399052400260,
121 0.0001690758006957347,
122 -0.0000546305872688307,
123 0.0000172223228484571,
124 -5.3352603788706e-6,
125 1.6315287543662e-6,
126 -4.939021084898e-7,
127 1.482515450316e-7,
128 -4.41552276226e-8,
129 1.30503160961e-8,
130 -3.8262599802e-9,
131 1.1123226976e-9,
132 -3.204765534e-10,
133 9.14870489e-11,
134 -2.58778946e-11,
135 7.2550731e-12,
136 -2.0172226e-12,
137 5.566891e-13,
138 -1.526247e-13,
139 4.16121e-14,
140 -1.12933e-14,
141 3.0537e-15,
142 -8.234e-16,
143 2.215e-16,
144 -5.95e-17,
145 1.59e-17,
146 -4.0e-18
147};
148
149#define WITH_SIZE(arr) sizeof(arr)/sizeof(double), arr
150
151static const double eta_table[] = {
152 0.50000000000000000000000000000, // eta(0)
153 plask::LN2, // eta(1)
154 0.82246703342411321823620758332,
155 0.90154267736969571404980362113,
156 0.94703282949724591757650323447,
157 0.97211977044690930593565514355,
158 0.98555109129743510409843924448,
159 0.99259381992283028267042571313,
160 0.99623300185264789922728926008,
161 0.99809429754160533076778303185,
162 0.99903950759827156563922184570,
163 0.99951714349806075414409417483,
164 0.99975768514385819085317967871,
165 0.99987854276326511549217499282,
166 0.99993917034597971817095419226,
167 0.99996955121309923808263293263,
168 0.99998476421490610644168277496,
169 0.99999237829204101197693787224,
170 0.99999618786961011347968922641,
171 0.99999809350817167510685649297,
172 0.99999904661158152211505084256,
173 0.99999952325821554281631666433,
174 0.99999976161323082254789720494,
175 0.99999988080131843950322382485,
176 0.99999994039889239462836140314,
177 0.99999997019885696283441513311,
178 0.99999998509923199656878766181,
179 0.99999999254955048496351585274,
180 0.99999999627475340010872752767,
181 0.99999999813736941811218674656,
182 0.99999999906868228145397862728,
183 0.99999999953434033145421751469,
184 0.99999999976716989595149082282,
185 0.99999999988358485804603047265,
186 0.99999999994179239904531592388,
187 0.99999999997089618952980952258,
188 0.99999999998544809143388476396,
189 0.99999999999272404460658475006,
190 0.99999999999636202193316875550,
191 0.99999999999818101084320873555,
192 0.99999999999909050538047887809,
193 0.99999999999954525267653087357,
194 0.99999999999977262633369589773,
195 0.99999999999988631316532476488,
196 0.99999999999994315658215465336,
197 0.99999999999997157829090808339,
198 0.99999999999998578914539762720,
199 0.99999999999999289457268000875,
200 0.99999999999999644728633373609,
201 0.99999999999999822364316477861,
202 0.99999999999999911182158169283,
203 0.99999999999999955591079061426,
204 0.99999999999999977795539522974,
205 0.99999999999999988897769758908,
206 0.99999999999999994448884878594,
207 0.99999999999999997224442439010,
208 0.99999999999999998612221219410,
209 0.99999999999999999306110609673,
210 0.99999999999999999653055304826,
211 0.99999999999999999826527652409,
212 0.99999999999999999913263826204,
213 0.99999999999999999956631913101,
214 0.99999999999999999978315956551,
215 0.99999999999999999989157978275,
216 0.99999999999999999994578989138,
217 0.99999999999999999997289494569,
218 0.99999999999999999998644747284,
219 0.99999999999999999999322373642,
220 0.99999999999999999999661186821,
221 0.99999999999999999999830593411,
222 0.99999999999999999999915296705,
223 0.99999999999999999999957648353,
224 0.99999999999999999999978824176,
225 0.99999999999999999999989412088,
226 0.99999999999999999999994706044,
227 0.99999999999999999999997353022,
228 0.99999999999999999999998676511,
229 0.99999999999999999999999338256,
230 0.99999999999999999999999669128,
231 0.99999999999999999999999834564,
232 0.99999999999999999999999917282,
233 0.99999999999999999999999958641,
234 0.99999999999999999999999979320,
235 0.99999999999999999999999989660,
236 0.99999999999999999999999994830,
237 0.99999999999999999999999997415,
238 0.99999999999999999999999998708,
239 0.99999999999999999999999999354,
240 0.99999999999999999999999999677,
241 0.99999999999999999999999999838,
242 0.99999999999999999999999999919,
243 0.99999999999999999999999999960,
244 0.99999999999999999999999999980,
245 0.99999999999999999999999999990,
246 0.99999999999999999999999999995,
247 0.99999999999999999999999999997,
248 0.99999999999999999999999999999,
249 0.99999999999999999999999999999,
250 1.00000000000000000000000000000,
251 1.00000000000000000000000000000,
252 1.00000000000000000000000000000,
253};
254
255double fermiDiracHalf(double x)
256{
257 if(x < -1.) {
258 // Series [Goano]
259 double ex = exp(x);
260 double term = ex;
261 double sum = term;
262 for(int n = 2; n < 100 ; n++) {
263 double rat = (n - 1.) / n;
264 term *= -ex * rat * sqrt(rat);
265 sum += term;
266 if(fabs(term/sum) < std::numeric_limits<double>::epsilon()) break;
267 }
268 return sum;
269
270 } else if(x < 1.) {
271 return clenshaw(WITH_SIZE(fd_half_coeffs_1_1), x, -1., 1.);
272
273 } else if(x < 4.) {
274 return clenshaw(WITH_SIZE(fd_half_coeffs_1_4), x, 1., 4.);
275
276 } else if(x < 10.) {
277 return clenshaw(WITH_SIZE(fd_half_coeffs_4_10), x, 4., 10.);
278
279 } else if(x < 30.) {
280 double val = clenshaw(WITH_SIZE(fd_half_coeffs_10_30), x, 10., 30.);
281 return x * sqrt(x) * val;
282
283 } else {
284 // Asymptotic expansion [Goano]
285 const int itmax = 200;
286 const double lg = 0.28468287047291918; // gammaln(ord + 2);
287 double seqn = 0.5;
288 double xm2 = 1. / x / x;
289 double xgam = 1.;
290 double add = std::numeric_limits<double>::max();
291
292 for(int n = 1; n <= itmax; n++) {
293 double add_previous = add;
294 const double eta = (n <= 50)? eta_table[2*n]: 1.;
295 xgam = xgam * xm2 * (1.5 - (2*n-2)) * (1.5 - (2*n-1));
296 add = eta * xgam;
297 if(fabs(add) > fabs(add_previous)) throw "Divergent series";
298 if(fabs(add/seqn) < std::numeric_limits<double>::epsilon()) break;
299 seqn += add;
300 }
301 return 2.0 * seqn * exp(1.5 * log(x) - lg);
302 }
303}
304
305
306} // namespace plask