Thermal-FIST 1.6
Package for hadron resonance gas model applications
Loading...
Searching...
No Matches
IdealGasFunctions.cpp
Go to the documentation of this file.
1/*
2 * Thermal-FIST package
3 *
4 * Copyright (c) 2017-2019 Volodymyr Vovchenko
5 *
6 * GNU General Public License (GPLv3 or later)
7 */
9
10#include <stdio.h>
11#include <cmath>
12#include <sstream>
13#include <stdexcept>
14#include <cfloat>
15#include <vector>
16#include <cassert>
17
18#include "HRGBase/xMath.h"
20
21using namespace std;
22
23namespace thermalfist {
24
25 namespace IdealGasFunctions {
26
28 std::vector<double> GetSpins(double degSpin) {
29 // Check that spin degeneracy is integer
30 assert(abs(degSpin - round(degSpin)) < 1.e-6);
31 int spinDegeneracy = round(degSpin);
32 std::vector<double> ret;
33 for(int isz = 0; isz < spinDegeneracy; ++isz) {
34 ret.push_back(-(spinDegeneracy - 1.)/2. + isz);
35 }
36 return ret;
37 }
38
40
41 double BoltzmannDensity(double T, double mu, double m, double deg,
42 const IdealGasFunctionsExtraConfig& extraConfig) {
43 // Check for magnetic field effect for charged particles
44 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
45 double Qmod = abs(extraConfig.MagneticField.Q);
46 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
47 // Use Eq. (7) from https://arxiv.org/pdf/2104.06843.pdf
48 // Sum over spins
49 double ret = 0.;
50 for(double sz : spins) {
51 // Sum over Landau levels
52 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
53 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
54 ret += e0 * xMath::BesselKexp(1, e0 / T) * exp((mu - e0) / T);
55 }
56 }
57 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
58 }
59
60 // No magnetic field
61 if (m == 0.)
62 return deg * T * T * T / 2. / xMath::Pi() / xMath::Pi() * 2. * exp(mu/ T) * xMath::GeVtoifm3();
63 return deg * m * m * T / 2. / xMath::Pi() / xMath::Pi() * xMath::BesselKexp(2, m / T) * exp((mu - m) / T) * xMath::GeVtoifm3();
64 }
65
66 double BoltzmannPressure(double T, double mu, double m, double deg,
67 const IdealGasFunctionsExtraConfig& extraConfig) {
68 return T * BoltzmannDensity(T, mu, m, deg, extraConfig);
69 }
70
71 double BoltzmannEnergyDensity(double T, double mu, double m, double deg,
72 const IdealGasFunctionsExtraConfig& extraConfig) {
73 // Check for magnetic field effect for charged particles
74 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
75 // TODO: Check that it's done correctly
76 double Qmod = abs(extraConfig.MagneticField.Q);
77 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
78 // Use e = -p + T (dp/dT) + mu (dp/mu) + B * (dp/dB)
79 // Sum over spins
80 double ret = 0.;
81 for(double sz : spins) {
82 // Sum over Landau levels
83 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
84 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
85 ret += (T + e0 * xMath::BesselKexp(0, e0 / T) / xMath::BesselKexp(1, e0 / T)) * e0 * xMath::BesselKexp(1, e0 / T) * exp((mu - e0) / T);
86 }
87 }
88 ret *= Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
89 return ret + extraConfig.MagneticField.B * BoltzmannMagnetization(T, mu, m, deg, extraConfig) * xMath::GeVtoifm3();
90 }
91
92 // No magnetic field
93 if (m == 0.)
94 return 3 * T * BoltzmannDensity(T, mu, m, deg);
95 return (3 * T + m * xMath::BesselK1exp(m / T) / xMath::BesselKexp(2, m / T)) * BoltzmannDensity(T, mu, m, deg);
96 }
97
98 double BoltzmannEntropyDensity(double T, double mu, double m, double deg,
99 const IdealGasFunctionsExtraConfig& extraConfig) {
100 double ret = (BoltzmannPressure(T, mu, m, deg, extraConfig) +
101 BoltzmannEnergyDensity(T, mu, m, deg, extraConfig) -
102 mu * BoltzmannDensity(T, mu, m, deg, extraConfig)) / T;
103
104 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.)
105 ret -= extraConfig.MagneticField.B * BoltzmannMagnetization(T, mu, m, deg, extraConfig) * xMath::GeVtoifm3() / T;
106
107 return ret;
108 }
109
110 double BoltzmannScalarDensity(double T, double mu, double m, double deg,
111 const IdealGasFunctionsExtraConfig& extraConfig) {
112 // Check for magnetic field effect for charged particles
113 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
114 // TODO: Check that it's done correctly
115 double Qmod = abs(extraConfig.MagneticField.Q);
116 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
117 // Use nsig = -dp/dm
118 // Sum over spins
119 double ret = 0.;
120 for(double sz : spins) {
121 // Sum over Landau levels
122 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
123 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
124 ret += m * xMath::BesselKexp(0, e0 / T) * exp((mu - e0) / T);
125 }
126 }
127 ret *= Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
128 return ret;
129 }
130
131 // No magnetic field
132 if (m == 0.)
133 return 0.;
134 return deg * m * m * T / 2. / xMath::Pi() / xMath::Pi() * xMath::BesselKexp(1, m / T) * exp((mu - m) / T) * xMath::GeVtoifm3();
135 }
136
137 double BoltzmannTdndmu(int /*N*/, double T, double mu, double m, double deg,
138 const IdealGasFunctionsExtraConfig& extraConfig)
139 {
140 return BoltzmannDensity(T, mu, m, deg, extraConfig);
141 }
142
143 double BoltzmannChiN(int N, double T, double mu, double m, double deg,
144 const IdealGasFunctionsExtraConfig& extraConfig)
145 {
146 return BoltzmannTdndmu(N - 1, T, mu, m, deg, extraConfig) / pow(T, 3) / xMath::GeVtoifm3();
147 }
148
149 double BoltzmannChiNDimensionfull(int N, double T, double mu, double m, double deg,
150 const IdealGasFunctionsExtraConfig& extraConfig)
151 {
152 return BoltzmannTdndmu(N - 1, T, mu, m, deg, extraConfig) / pow(T, N - 1) / xMath::GeVtoifm3();
153 }
154
155 double QuantumClusterExpansionDensity(int statistics, double T, double mu, double m, double deg, int order,
156 const IdealGasFunctionsExtraConfig& extraConfig)
157 {
158 bool signchange = true;
159 if (statistics == 1) //Fermi
160 signchange = true;
161 else if (statistics == -1) //Bose
162 signchange = false;
163 else
164 return BoltzmannDensity(T, mu, m, deg, extraConfig);
165
166 // Check for magnetic field effect for charged particles
167 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
168 double Qmod = abs(extraConfig.MagneticField.Q);
169 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
170
171
172 // Use Eq. (7) from https://arxiv.org/pdf/2104.06843.pdf
173 // Sum over spins
174 double ret = 0.;
175 for(double sz : spins) {
176 // Sum over Landau levels
177 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
178 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
179
180 // Sum over clusters
181 double tfug = exp((mu - e0) / T);
182 double EoverT = e0 / T;
183 double cfug = tfug;
184 double sign = 1.;
185 for (int i = 1; i <= order; ++i) {
186 ret += e0 * sign * xMath::BesselKexp(1, i*EoverT) * cfug;
187 cfug *= tfug;
188 if (signchange) sign = -sign;
189 }
190 }
191 }
192 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
193 }
194
195 // No magnetic field
196 double tfug = exp((mu - m) / T);
197 double moverT = m / T;
198 double cfug = tfug;
199 double sign = 1.;
200 double ret = 0.;
201 for (int i = 1; i <= order; ++i) {
202 if (m == 0.)
203 ret += sign * cfug / static_cast<double>(i) / static_cast<double>(i) / static_cast<double>(i);
204 else
205 ret += sign * xMath::BesselKexp(2, i*moverT) * cfug / static_cast<double>(i);
206 cfug *= tfug;
207 if (signchange) sign = -sign;
208 }
209
210 double prefactor = 1.;
211 if (m == 0.)
212 prefactor = deg * T * T * T / 2. / xMath::Pi() / xMath::Pi() * 2.;
213 else
214 prefactor = deg * m * m * T / 2. / xMath::Pi() / xMath::Pi();
215
216 return ret * prefactor * xMath::GeVtoifm3();
217 }
218
219 double QuantumClusterExpansionPressure(int statistics, double T, double mu, double m, double deg, int order,
220 const IdealGasFunctionsExtraConfig& extraConfig)
221 {
222 bool signchange = true;
223 if (statistics == 1) //Fermi
224 signchange = true;
225 else if (statistics == -1) //Bose
226 signchange = false;
227 else
228 return BoltzmannPressure(T, mu, m, deg, extraConfig);
229
230 // Check for magnetic field effect for charged particles
231 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
232 double Qmod = abs(extraConfig.MagneticField.Q);
233 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
234
235
236 // Use Eq. (7) from https://arxiv.org/pdf/2104.06843.pdf
237 // Sum over spins
238 double ret = 0.;
239 for(double sz : spins) {
240 // Sum over Landau levels
241 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
242 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
243
244 // Sum over clusters
245 double tfug = exp((mu - e0) / T);
246 double EoverT = e0 / T;
247 double cfug = tfug;
248 double sign = 1.;
249 for (int i = 1; i <= order; ++i) {
250 ret += e0 * sign * xMath::BesselKexp(1, i*EoverT) * cfug * T / static_cast<double>(i);
251 cfug *= tfug;
252 if (signchange) sign = -sign;
253 }
254 }
255 }
256 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
257 }
258
259 // No magnetic field
260 double tfug = exp((mu - m) / T);
261 double cfug = tfug;
262 double moverT = m / T;
263 double sign = 1.;
264 double ret = 0.;
265 for (int i = 1; i <= order; ++i) {
266 if (m == 0.)
267 ret += sign * cfug / static_cast<double>(i) / static_cast<double>(i) / static_cast<double>(i) / static_cast<double>(i);
268 else
269 ret += sign * xMath::BesselKexp(2, i*moverT) * cfug / static_cast<double>(i) / static_cast<double>(i);
270 cfug *= tfug;
271 if (signchange) sign = -sign;
272 }
273
274 double prefactor = 1.;
275 if (m == 0.)
276 prefactor = deg * T * T * T * T / 2. / xMath::Pi() / xMath::Pi() * 2.;
277 else
278 prefactor = deg * m * m * T * T / 2. / xMath::Pi() / xMath::Pi();
279
280 return ret * prefactor * xMath::GeVtoifm3();
281 }
282
283 double QuantumClusterExpansionEnergyDensity(int statistics, double T, double mu, double m, double deg, int order,
284 const IdealGasFunctionsExtraConfig& extraConfig)
285 {
286 bool signchange = true;
287 if (statistics == 1) //Fermi
288 signchange = true;
289 else if (statistics == -1) //Bose
290 signchange = false;
291 else
292 return BoltzmannEnergyDensity(T, mu, m, deg, extraConfig);
293
294 // Check for magnetic field effect for charged particles
295 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
296 double Qmod = abs(extraConfig.MagneticField.Q);
297 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
298
299
300 // Use Eq. (7) from https://arxiv.org/pdf/2104.06843.pdf
301 // Sum over spins
302 double ret = 0.;
303 for(double sz : spins) {
304 // Sum over Landau levels
305 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
306 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
307
308 // Sum over clusters
309 double tfug = exp((mu - e0) / T);
310 double EoverT = e0 / T;
311 double cfug = tfug;
312 double sign = 1.;
313 for (int i = 1; i <= order; ++i) {
314 ret += sign * e0 * T / static_cast<double>(i) * xMath::BesselKexp(1, i*EoverT) * cfug;
315 ret += sign * e0 * e0 * xMath::BesselKexp(0, i*EoverT) * cfug;
316 cfug *= tfug;
317 if (signchange) sign = -sign;
318 }
319 }
320 }
321 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3()
322 + extraConfig.MagneticField.B * QuantumClusterExpansionMagnetization(statistics, T, mu, m, deg, order, extraConfig) * xMath::GeVtoifm3();
323 }
324
325 // No magnetic field
326 double tfug = exp((mu - m) / T);
327 double cfug = tfug;
328 double moverT = m / T;
329 double sign = 1.;
330 double ret = 0.;
331 for (int i = 1; i <= order; ++i) {
332 if (m == 0.)
333 ret += sign * cfug / static_cast<double>(i) / static_cast<double>(i) / static_cast<double>(i) / static_cast<double>(i);
334 else
335 ret += sign * (xMath::BesselKexp(1, i*moverT) + 3. * xMath::BesselKexp(2, i*moverT) / moverT / static_cast<double>(i)) * cfug / static_cast<double>(i);
336 cfug *= tfug;
337 if (signchange) sign = -sign;
338 }
339
340 double prefactor = 1.;
341 if (m == 0.)
342 prefactor = deg * T * T * T * T / 2. / xMath::Pi() / xMath::Pi() * 6.;
343 else
344 prefactor = deg * m * m * m * T / 2. / xMath::Pi() / xMath::Pi();
345
346 return ret * prefactor * xMath::GeVtoifm3();
347 }
348
349 double QuantumClusterExpansionEntropyDensity(int statistics, double T, double mu, double m, double deg, int order,
350 const IdealGasFunctionsExtraConfig& extraConfig)
351 {
352 double ret = (QuantumClusterExpansionPressure(statistics, T, mu, m, deg, order, extraConfig) +
353 QuantumClusterExpansionEnergyDensity(statistics, T, mu, m, deg, order, extraConfig) -
354 mu * QuantumClusterExpansionDensity(statistics, T, mu, m, deg, order, extraConfig)) / T;
355
356 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.)
357 ret -= extraConfig.MagneticField.B * QuantumClusterExpansionMagnetization(statistics, T, mu, m, deg, order, extraConfig) * xMath::GeVtoifm3() / T;
358
359 return ret;
360 }
361
362 double QuantumClusterExpansionScalarDensity(int statistics, double T, double mu, double m, double deg, int order,
363 const IdealGasFunctionsExtraConfig& extraConfig)
364 {
365 bool signchange = true;
366 if (statistics == 1) //Fermi
367 signchange = true;
368 else if (statistics == -1) //Bose
369 signchange = false;
370 else
371 return BoltzmannScalarDensity(T, mu, m, deg, extraConfig);
372
373 // Check for magnetic field effect for charged particles
374 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
375 double Qmod = abs(extraConfig.MagneticField.Q);
376 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
377
378
379 // Use Eq. (7) from https://arxiv.org/pdf/2104.06843.pdf
380 // Sum over spins
381 double ret = 0.;
382 for(double sz : spins) {
383 // Sum over Landau levels
384 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
385 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
386
387 // Sum over clusters
388 double tfug = exp((mu - e0) / T);
389 double EoverT = e0 / T;
390 double cfug = tfug;
391 double sign = 1.;
392 for (int i = 1; i <= order; ++i) {
393 ret += m * sign * xMath::BesselKexp(0, i*EoverT) * cfug;
394 cfug *= tfug;
395 if (signchange) sign = -sign;
396 }
397 }
398 }
399 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
400 }
401
402 // No magnetic field
403 double tfug = exp((mu - m) / T);
404 double cfug = tfug;
405 double moverT = m / T;
406 double sign = 1.;
407 double ret = 0.;
408
409 if (m == 0.)
410 return ret;
411
412 for (int i = 1; i <= order; ++i) {
413 ret += sign * xMath::BesselKexp(1, i*moverT) * cfug / static_cast<double>(i);
414 cfug *= tfug;
415 if (signchange) sign = -sign;
416 }
417 ret *= deg * m * m * T / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
418 return ret;
419 }
420
421 double QuantumClusterExpansionTdndmu(int N, int statistics, double T, double mu, double m, double deg, int order,
422 const IdealGasFunctionsExtraConfig& extraConfig)
423 {
424 bool signchange = true;
425 if (statistics == 1) //Fermi
426 signchange = true;
427 else if (statistics == -1) //Bose
428 signchange = false;
429 else
430 return BoltzmannTdndmu(N, T, mu, m, deg, extraConfig);
431
432 // Check for magnetic field effect for charged particles
433 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
434 double Qmod = abs(extraConfig.MagneticField.Q);
435 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
436
437
438 // Sum over spins
439 double ret = 0.;
440 for(double sz : spins) {
441 // Sum over Landau levels
442 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
443 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
444
445 // Sum over clusters
446 double tfug = exp((mu - e0) / T);
447 double EoverT = e0 / T;
448 double cfug = tfug;
449 double sign = 1.;
450 for (int i = 1; i <= order; ++i) {
451 ret += e0 * sign * xMath::BesselKexp(1, i*EoverT) * cfug * pow(static_cast<double>(i), N);
452 cfug *= tfug;
453 if (signchange) sign = -sign;
454 }
455 }
456 }
457 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
458 }
459
460 // No magnetic field
461 double tfug = exp((mu - m) / T);
462 double cfug = tfug;
463 double moverT = m / T;
464 double sign = 1.;
465 double ret = 0.;
466 for (int i = 1; i <= order; ++i) {
467 if (m == 0.)
468 ret += sign * cfug * pow(static_cast<double>(i), N - 3);
469 else
470 ret += sign * xMath::BesselKexp(2, i*moverT) * cfug * pow(static_cast<double>(i), N - 1);
471 cfug *= tfug;
472 if (signchange) sign = -sign;
473 }
474
475 double prefactor = 1.;
476 if (m == 0.)
477 prefactor = deg * T * T * T / 2. / xMath::Pi() / xMath::Pi() * 2.;
478 else
479 prefactor = deg * m * m * T / 2. / xMath::Pi() / xMath::Pi();
480
481 return ret * prefactor * xMath::GeVtoifm3();
482 }
483
484 double QuantumClusterExpansionChiN(int N, int statistics, double T, double mu, double m, double deg, int order,
485 const IdealGasFunctionsExtraConfig& extraConfig)
486 {
487 return QuantumClusterExpansionTdndmu(N - 1, statistics, T, mu, m, deg, order, extraConfig) /
488 pow(T, 3) / xMath::GeVtoifm3();
489 }
490
491
492 double QuantumClusterExpansionChiNDimensionfull(int N, int statistics, double T, double mu, double m, double deg, int order,
493 const IdealGasFunctionsExtraConfig& extraConfig)
494 {
495 return QuantumClusterExpansionTdndmu(N - 1, statistics, T, mu, m, deg, order, extraConfig) /
496 pow(T, N - 1) / xMath::GeVtoifm3();
497 }
498
499 // Gauss-Legendre 32-point quadrature for [0,1] interval
502 // Gauss-Laguerre 32-point quadrature for [0,\infty] interval
505
506 double QuantumNumericalIntegrationDensity(int statistics, double T, double mu, double m, double deg,
507 const IdealGasFunctionsExtraConfig& extraConfig)
508 {
509 if (statistics == 0) return BoltzmannDensity(T, mu, m, deg, extraConfig);
510 if (statistics == 1 && T == 0.) return FermiZeroTDensity(mu, m, deg, extraConfig);
511 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuDensity(T, mu, m, deg, extraConfig);
512 if (statistics == -1 && mu > m) {
513 std::cerr << "**WARNING** QuantumNumericalIntegrationDensity: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
515 mu = m;
516 // return 0.;
517 }
518 if (statistics == -1 && T == 0.) return 0.;
519
520 // Check for magnetic field effect for charged particles
521 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
522 double Qmod = abs(extraConfig.MagneticField.Q);
523 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
524
525 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
526 // Sum over spins
527 double ret = 0.;
528 for(double sz : spins) {
529 // Sum over Landau levels
530 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
531
532 // Numerical integration over pz
533 double moverT = m / T;
534 double muoverT = mu / T;
535 double BoverT2 = extraConfig.MagneticField.B / T / T;
536 for (int i = 0; i < 32; i++) {
537 double tx = lagx32[i];
538 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
539 ret += lagw32[i] * T / (exp(EoverT - muoverT) + statistics);
540 }
541 }
542 }
543 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
544 }
545
546 // No magnetic field
547 double ret = 0.;
548 double moverT = m / T;
549 double muoverT = mu / T;
550 for (int i = 0; i < 32; i++) {
551 double tx = lagx32[i];
552 ret += lagw32[i] * T * tx * T * tx * T / (exp(sqrt(tx*tx + moverT * moverT) - muoverT) + statistics);
553 }
554
555 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
556
557 return ret;
558 }
559
560 double QuantumNumericalIntegrationPressure(int statistics, double T, double mu, double m, double deg,
561 const IdealGasFunctionsExtraConfig& extraConfig)
562 {
563 if (statistics == 0) return BoltzmannPressure(T, mu, m, deg, extraConfig);
564 if (statistics == 1 && T == 0.) return FermiZeroTPressure(mu, m, deg, extraConfig);
565 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuPressure(T, mu, m, deg, extraConfig);
566 if (statistics == -1 && mu > m) {
567 std::cerr << "**WARNING** QuantumNumericalIntegrationPressure: Bose-Einstein condensation" << std::endl;
569 mu = m;
570 // return 0.;
571 }
572 if (statistics == -1 && T == 0.) return 0.;
573
574 // Check for magnetic field effect for charged particles
575 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
576 double Qmod = abs(extraConfig.MagneticField.Q);
577 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
578
579 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
580 // Sum over spins
581 double ret = 0.;
582 for(double sz : spins) {
583 // Sum over Landau levels
584 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
585
586 // Numerical integration over pz
587 double moverT = m / T;
588 double muoverT = mu / T;
589 double BoverT2 = extraConfig.MagneticField.B / T / T;
590 for (int i = 0; i < 32; i++) {
591 double tx = lagx32[i];
592 double x2 = tx * T * tx * T;
593 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
594 ret += lagw32[i] * T * x2 / EoverT / T / (exp(EoverT - muoverT) + statistics);
595 }
596 }
597 }
598 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
599 }
600
601 // No magnetic field
602 double ret = 0.;
603 double moverT = m / T;
604 double muoverT = mu / T;
605 for (int i = 0; i < 32; i++) {
606 double tx = lagx32[i];
607 double x2 = tx * T * tx * T;
608 double E = sqrt(tx*tx + moverT * moverT);
609 ret += lagw32[i] * T * x2 * x2 / E / T / (exp(E - muoverT) + statistics);
610 }
611
612 ret *= deg / 6. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
613
614 return ret;
615 }
616
617 double QuantumNumericalIntegrationEnergyDensity(int statistics, double T, double mu, double m, double deg,
618 const IdealGasFunctionsExtraConfig& extraConfig)
619 {
620 if (statistics == 0) return BoltzmannEnergyDensity(T, mu, m, deg, extraConfig);
621 if (statistics == 1 && T == 0.) return FermiZeroTEnergyDensity(mu, m, deg, extraConfig);
622 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuEnergyDensity(T, mu, m, deg, extraConfig);
623 if (statistics == -1 && mu > m) {
624 std::cerr << "**WARNING** QuantumNumericalIntegrationEnergyDensity: Bose-Einstein condensation" << std::endl;
626 mu = m;
627 // return 0.;
628 }
629 if (statistics == -1 && T == 0.) return 0.;
630
631 // Check for magnetic field effect for charged particles
632 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
633 double Qmod = abs(extraConfig.MagneticField.Q);
634 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
635
636 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
637 // Sum over spins
638 double ret = 0.;
639 for(double sz : spins) {
640 // Sum over Landau levels
641 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
642
643 // Numerical integration over pz
644 double moverT = m / T;
645 double muoverT = mu / T;
646 double BoverT2 = extraConfig.MagneticField.B / T / T;
647 for (int i = 0; i < 32; i++) {
648 double tx = lagx32[i];
649 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
650 ret += lagw32[i] * T * EoverT * T / (exp(EoverT - muoverT) + statistics);
651 }
652 }
653 }
654 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3()
655 + extraConfig.MagneticField.B * QuantumNumericalIntegrationMagnetization(statistics, T, mu, m, deg, extraConfig) * xMath::GeVtoifm3();
656 }
657
658 // No magnetic field
659 double ret = 0.;
660 double moverT = m / T;
661 double muoverT = mu / T;
662 for (int i = 0; i < 32; i++) {
663 double tx = lagx32[i];
664 ret += lagw32[i] * T * tx * T * tx * T * sqrt(tx*tx + moverT * moverT) * T / (exp(sqrt(tx*tx + moverT * moverT) - muoverT) + statistics);
665 }
666
667 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
668
669 return ret;
670 }
671
672 double QuantumNumericalIntegrationEntropyDensity(int statistics, double T, double mu, double m, double deg,
673 const IdealGasFunctionsExtraConfig& extraConfig)
674 {
675 if (T == 0.)
676 return 0.;
677
678 if (statistics == -1 && mu > m) {
679 std::cerr << "**WARNING** QuantumNumericalIntegrationEntropyDensity: Bose-Einstein condensation" << std::endl;
681 mu = m;
682 // return 0.;
683 }
684
685 // Use direct entropy integrand for degenerate Fermi gas (avoids (P+e-mu*n)/T cancellation)
686 if (statistics == 1 && mu > m)
687 return FermiNumericalIntegrationLargeMuEntropyDensity(T, mu, m, deg, extraConfig);
688
689 double ret = (QuantumNumericalIntegrationPressure(statistics, T, mu, m, deg, extraConfig)
690 + QuantumNumericalIntegrationEnergyDensity(statistics, T, mu, m, deg, extraConfig)
691 - mu * QuantumNumericalIntegrationDensity(statistics, T, mu, m, deg, extraConfig)) / T;
692
693 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.)
694 ret -= extraConfig.MagneticField.B * QuantumNumericalIntegrationMagnetization(statistics, T, mu, m, deg, extraConfig) * xMath::GeVtoifm3() / T;
695
696 return ret;
697 }
698
699 double QuantumNumericalIntegrationScalarDensity(int statistics, double T, double mu, double m, double deg,
700 const IdealGasFunctionsExtraConfig& extraConfig)
701 {
702 if (statistics == 0) return BoltzmannScalarDensity(T, mu, m, deg, extraConfig);
703 if (statistics == 1 && T == 0.) return FermiZeroTScalarDensity(mu, m, deg, extraConfig);
704 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuScalarDensity(T, mu, m, deg, extraConfig);
705 if (statistics == -1 && mu > m) {
706 std::cerr << "**WARNING** QuantumNumericalIntegrationScalarDensity: Bose-Einstein condensation" << std::endl;
708 mu = m;
709 // return 0.;
710 }
711 if (statistics == -1 && T == 0.) return 0.;
712
713 // Check for magnetic field effect for charged particles
714 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
715 double Qmod = abs(extraConfig.MagneticField.Q);
716 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
717
718 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
719 // Sum over spins
720 double ret = 0.;
721 for(double sz : spins) {
722 // Sum over Landau levels
723 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
724
725 // Numerical integration over pz
726 double moverT = m / T;
727 double muoverT = mu / T;
728 double BoverT2 = extraConfig.MagneticField.B / T / T;
729 for (int i = 0; i < 32; i++) {
730 double tx = lagx32[i];
731 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
732 ret += lagw32[i] * T * moverT / EoverT / (exp(EoverT - muoverT) + statistics);
733 }
734 }
735 }
736 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
737 }
738
739 // No magnetic field
740 double ret = 0.;
741 double moverT = m / T;
742 double muoverT = mu / T;
743 for (int i = 0; i < 32; i++) {
744 double tx = lagx32[i];
745 ret += lagw32[i] * T * tx * T * tx * T * moverT / sqrt(tx*tx + moverT * moverT) / (exp(sqrt(tx*tx + moverT * moverT) - muoverT) + statistics);
746 }
747
748 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
749
750 return ret;
751 }
752
753 double QuantumNumericalIntegrationT1dn1dmu1(int statistics, double T, double mu, double m, double deg,
754 const IdealGasFunctionsExtraConfig& extraConfig)
755 {
756 if (statistics == 0) return BoltzmannTdndmu(1, T, mu, m, deg, extraConfig);
757 if (statistics == 1 && T == 0.) return 0.;
758 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuT1dn1dmu1(T, mu, m, deg, extraConfig);
759 if (statistics == -1 && mu > m) {
760 std::cerr << "**WARNING** QuantumNumericalIntegrationT1dn1dmu1: Bose-Einstein condensation" << std::endl;
762 mu = m;
763 // return 0.;
764 }
765 if (statistics == -1 && T == 0.) return 0.;
766
767 // Check for magnetic field effect for charged particles
768 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
769 double Qmod = abs(extraConfig.MagneticField.Q);
770 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
771
772 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
773 // Sum over spins
774 double ret = 0.;
775 for(double sz : spins) {
776 // Sum over Landau levels
777 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
778
779 // Numerical integration over pz
780 double moverT = m / T;
781 double muoverT = mu / T;
782 double BoverT2 = extraConfig.MagneticField.B / T / T;
783 for (int i = 0; i < 32; i++) {
784 double tx = lagx32[i];
785 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
786 double Eexp = exp(EoverT - muoverT);
787 ret += lagw32[i] * T * 1. / (1. + statistics / Eexp) / (Eexp + statistics);
788 }
789 }
790 }
791 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
792 }
793
794 // No magnetic field
795 double ret = 0.;
796 double moverT = m / T;
797 double muoverT = mu / T;
798 for (int i = 0; i < 32; i++) {
799 double tx = lagx32[i];
800 double Eexp = exp(sqrt(tx*tx + moverT * moverT) - muoverT);
801 ret += lagw32[i] * T * tx * T * tx * T * 1. / (1. + statistics / Eexp) / (Eexp + statistics);
802 }
803
804 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
805
806 return ret;
807 }
808
809 double QuantumNumericalIntegrationT2dn2dmu2(int statistics, double T, double mu, double m, double deg,
810 const IdealGasFunctionsExtraConfig& extraConfig)
811 {
812 if (statistics == 0) return BoltzmannTdndmu(2, T, mu, m, deg, extraConfig);
813 if (statistics == 1 && T == 0.) return 0.;
814 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuT2dn2dmu2(T, mu, m, deg, extraConfig);
815 if (statistics == -1 && mu > m) {
816 std::cerr << "**WARNING** QuantumNumericalIntegrationT2dn2dmu2: Bose-Einstein condensation" << std::endl;
818 mu = m;
819 // return 0.;
820 }
821 if (statistics == -1 && T == 0.) return 0.;
822
823 // Check for magnetic field effect for charged particles
824 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
825 double Qmod = abs(extraConfig.MagneticField.Q);
826 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
827
828 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
829 // Sum over spins
830 double ret = 0.;
831 for(double sz : spins) {
832 // Sum over Landau levels
833 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
834
835 // Numerical integration over pz
836 double moverT = m / T;
837 double muoverT = mu / T;
838 double BoverT2 = extraConfig.MagneticField.B / T / T;
839 for (int i = 0; i < 32; i++) {
840 double tx = lagx32[i];
841 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
842 double Eexp = exp(EoverT - muoverT);
843 ret += lagw32[i] * T * (1. - statistics / Eexp) / (1. + statistics / Eexp) / (1. + statistics / Eexp) / (Eexp + statistics);
844 }
845 }
846 }
847 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
848 }
849
850 // No magnetic field
851 double ret = 0.;
852 double moverT = m / T;
853 double muoverT = mu / T;
854 for (int i = 0; i < 32; i++) {
855 double tx = lagx32[i];
856 double Eexp = exp(sqrt(tx*tx + moverT * moverT) - muoverT);
857 //ret += lagw32[i] * T * tx * T * tx * T * (Eexp*Eexp - statistics * Eexp) / (Eexp + statistics) / (Eexp + statistics) / (Eexp + statistics);
858 ret += lagw32[i] * T * tx * T * tx * T * (1. - statistics / Eexp) / (1. + statistics / Eexp) / (1. + statistics / Eexp) / (Eexp + statistics);
859 }
860
861 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
862
863 return ret;
864 }
865
866 double QuantumNumericalIntegrationT3dn3dmu3(int statistics, double T, double mu, double m, double deg,
867 const IdealGasFunctionsExtraConfig& extraConfig)
868 {
869 if (statistics == 0) return BoltzmannTdndmu(3, T, mu, m, deg, extraConfig);
870 if (statistics == 1 && T == 0.) return 0.;
871 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuT3dn3dmu3(T, mu, m, deg, extraConfig);
872 if (statistics == -1 && mu > m) {
873 std::cerr << "**WARNING** QuantumNumericalIntegrationT3dn3dmu3: Bose-Einstein condensation" << std::endl;
875 mu = m;
876 // return 0.;
877 }
878 if (statistics == -1 && T == 0.) return 0.;
879
880
881 // Check for magnetic field effect for charged particles
882 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
883 double Qmod = abs(extraConfig.MagneticField.Q);
884 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
885
886 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
887 // Sum over spins
888 double ret = 0.;
889 for(double sz : spins) {
890 // Sum over Landau levels
891 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
892
893 // Numerical integration over pz
894 double moverT = m / T;
895 double muoverT = mu / T;
896 double BoverT2 = extraConfig.MagneticField.B / T / T;
897 for (int i = 0; i < 32; i++) {
898 double tx = lagx32[i];
899 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
900 double Eexp = exp(EoverT - muoverT);
901 ret += lagw32[i] * T * (1. - 4.*statistics / Eexp + statistics * statistics / Eexp / Eexp) / (1. + statistics / Eexp) / (1. + statistics / Eexp) / (1. + statistics / Eexp) / (Eexp + statistics);
902 }
903 }
904 }
905 return ret * Qmod * extraConfig.MagneticField.B / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
906 }
907
908 // No magnetic field
909 double ret = 0.;
910 double moverT = m / T;
911 double muoverT = mu / T;
912 for (int i = 0; i < 32; i++) {
913 double tx = lagx32[i];
914 double Eexp = exp(sqrt(tx*tx + moverT * moverT) - muoverT);
915 //ret += lagw32[i] * T * tx * T * tx * T * (Eexp*Eexp*Eexp - 4.*statistics*Eexp*Eexp + statistics*statistics*Eexp) / (Eexp + statistics) / (Eexp + statistics) / (Eexp + statistics) / (Eexp + statistics);
916 ret += lagw32[i] * T * tx * T * tx * T * (1. - 4.*statistics / Eexp + statistics * statistics / Eexp / Eexp) / (1. + statistics / Eexp) / (1. + statistics / Eexp) / (1. + statistics / Eexp) / (Eexp + statistics);
917 //printf("%E %E ", ret, Eexp);
918 }
919 //printf("\n");
920
921 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
922
923 return ret;
924 }
925
926 double QuantumNumericalIntegrationTdndmu(int N, int statistics, double T, double mu, double m, double deg,
927 const IdealGasFunctionsExtraConfig& extraConfig)
928 {
929 if (N < 0 || N>3) {
930 std::cerr << "**WARNING** QuantumNumericalIntegrationTdndmu: N must be between 0 and 3!" << std::endl;
932 exit(1);
933 }
934 if (N == 0)
935 return QuantumNumericalIntegrationDensity(statistics, T, mu, m, deg, extraConfig);
936
937 if (N == 1)
938 return QuantumNumericalIntegrationT1dn1dmu1(statistics, T, mu, m, deg, extraConfig);
939
940 if (N == 2)
941 return QuantumNumericalIntegrationT2dn2dmu2(statistics, T, mu, m, deg, extraConfig);
942
943 return QuantumNumericalIntegrationT3dn3dmu3(statistics, T, mu, m, deg, extraConfig);
944 }
945
946 double QuantumNumericalIntegrationChiN(int N, int statistics, double T, double mu, double m, double deg,
947 const IdealGasFunctionsExtraConfig& extraConfig)
948 {
949 return QuantumNumericalIntegrationTdndmu(N - 1, statistics, T, mu, m, deg, extraConfig) / pow(T, 3) / xMath::GeVtoifm3();
950 }
951
952 double QuantumNumericalIntegrationChiNDimensionfull(int N, int statistics, double T, double mu, double m, double deg,
953 const IdealGasFunctionsExtraConfig& extraConfig)
954 {
955 if (statistics == 1 && T == 0.0)
956 return FermiZeroTChiNDimensionfull(N, mu, m, deg, extraConfig);
957 if (statistics == -1 && T == 0.0) {
958 if (mu >= m) {
959 std::cerr << "**WARNING** QuantumNumericalIntegrationChiNDimensionfull: Bose-Einstein condensation" << std::endl;
961 }
962 return 0.;
963 }
964 return QuantumNumericalIntegrationTdndmu(N - 1, statistics, T, mu, m, deg, extraConfig) / pow(T, N-1) / xMath::GeVtoifm3();
965 }
966
967 double psi(double x)
968 {
969 if (x == 0.0)
970 return 1.;
971 double x2 = x * x;
972 double tmpsqrt = sqrt(1. + x2);
973 return (1. + x2 / 2.) * tmpsqrt - x2 * x2 / 2. * log((1. + tmpsqrt) / x);
974 }
975
976 double psi2(double x)
977 {
978 if (x == 0.0)
979 return 2.;
980 double x2 = x * x;
981 double tmpsqrt = sqrt(1. + x2);
982 return 2. * tmpsqrt + 2. * x2 * log((1. + tmpsqrt) / x);
983 }
984
996 inline void SommerfeldLegendreMap(double s, double pf, double mu, double T,
997 double& p, double& dpds)
998 {
999 double alpha = pf * pf / (mu * T);
1000 if (alpha < 1.e-6) {
1001 // Small alpha: uniform mapping (avoid catastrophic cancellation in beta)
1002 p = s * pf;
1003 dpds = pf;
1004 return;
1005 }
1006 double expmAlpha = exp(-alpha);
1007 double beta = 1. - expmAlpha;
1008 double t = 1. - s;
1009 double oneMinusBetaT = 1. - beta * t;
1010 double u = -log(oneMinusBetaT);
1011 p = pf * (1. - u / alpha);
1012 dpds = pf / alpha * beta / oneMinusBetaT;
1013 }
1014
1015 double FermiNumericalIntegrationLargeMuDensity(double T, double mu, double m, double deg,
1016 const IdealGasFunctionsExtraConfig& extraConfig)
1017 {
1018 if (mu <= m)
1019 return QuantumNumericalIntegrationDensity(1, T, mu, m, deg, extraConfig);
1020
1021 assert(extraConfig.MagneticField.B == 0.0);
1022
1023 double pf = sqrt(mu*mu - m * m);
1024 double ret1 = 0.;
1025 for (int i = 0; i < 32; i++) {
1026 double p, dpds;
1027 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1028 ret1 += -legw32[i] * dpds * p * p / (exp(-(sqrt(p * p + m * m) - mu) / T) + 1.);
1029 }
1030
1031 double moverT = m / T;
1032 double muoverT = mu / T;
1033 for (int i = 0; i < 32; i++) {
1034 double tx = pf / T + lagx32[i];
1035 ret1 += lagw32[i] * T * tx * T * tx * T / (exp(sqrt(tx*tx + moverT * moverT) - muoverT) + 1.);
1036 }
1037
1038 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1039
1040 double ret2 = 0.;
1041 ret2 += deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() * pf * pf * pf / 3.;
1042
1043 // Other terms from differentiating Eq. (55) in https://arxiv.org/pdf/1901.05249.pdf add up to zero
1044
1045 return ret1 + ret2;
1046 }
1047
1048 double FermiNumericalIntegrationLargeMuPressure(double T, double mu, double m, double deg,
1049 const IdealGasFunctionsExtraConfig& extraConfig)
1050 {
1051 if (mu <= m)
1052 return QuantumNumericalIntegrationPressure(1, T, mu, m, deg, extraConfig);
1053
1054 assert(extraConfig.MagneticField.B == 0.0);
1055
1056 double pf = sqrt(mu*mu - m * m);
1057 double ret1 = 0.;
1058 for (int i = 0; i < 32; i++) {
1059 double p, dpds;
1060 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1061 double p2 = p * p;
1062 double E = sqrt(p2 + m * m);
1063 ret1 += -legw32[i] * dpds * p2 * p2 / E / (exp(-(E - mu) / T) + 1.);
1064 }
1065
1066 double moverT = m / T;
1067 double muoverT = mu / T;
1068 for (int i = 0; i < 32; i++) {
1069 double tx = pf / T + lagx32[i];
1070 double x2 = tx * T * tx * T;
1071 double E = sqrt(tx*tx + moverT * moverT);
1072 ret1 += lagw32[i] * T * x2 * x2 / E / T / (exp(E - muoverT) + 1.);
1073 }
1074
1075 ret1 *= deg / 6. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1076
1077 double ret2 = 0.;
1078 ret2 += mu * pf * pf * pf;
1079 ret2 += -3. / 4. * pf * pf * pf * pf * psi(m / pf);
1080 ret2 *= deg / 6. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1081
1082 return ret1 + ret2;
1083 }
1084
1085 double FermiNumericalIntegrationLargeMuEnergyDensity(double T, double mu, double m, double deg,
1086 const IdealGasFunctionsExtraConfig& extraConfig)
1087 {
1088 if (mu <= m)
1089 return QuantumNumericalIntegrationEnergyDensity(1, T, mu, m, deg, extraConfig);
1090
1091 assert(extraConfig.MagneticField.B == 0.0);
1092
1093 double pf = sqrt(mu*mu - m * m);
1094 double ret1 = 0.;
1095 for (int i = 0; i < 32; i++) {
1096 double p, dpds;
1097 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1098 double E = sqrt(p * p + m * m);
1099 ret1 += -legw32[i] * dpds * p * p * E / (exp(-(E - mu) / T) + 1.);
1100 }
1101
1102 double moverT = m / T;
1103 double muoverT = mu / T;
1104 for (int i = 0; i < 32; i++) {
1105 double tx = pf / T + lagx32[i];
1106 ret1 += lagw32[i] * T * tx * T * tx * T * sqrt(tx*tx + moverT * moverT) * T / (exp(sqrt(tx*tx + moverT * moverT) - muoverT) + 1.);
1107 }
1108
1109 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1110
1111 double ret2 = 0.;
1112 ret2 += deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() * pf * pf * pf * pf / 4. * psi(m / pf);
1113
1114 return ret1 + ret2;
1115 }
1116
1121 inline double FermiEntropySigma(double x)
1122 {
1123 double ax = std::abs(x);
1124 return log(1. + exp(-ax)) + ax / (exp(ax) + 1.);
1125 }
1126
1127 double FermiNumericalIntegrationLargeMuEntropyDensity(double T, double mu, double m, double deg,
1128 const IdealGasFunctionsExtraConfig& extraConfig)
1129 {
1130 if (mu <= m)
1131 return QuantumNumericalIntegrationEntropyDensity(1, T, mu, m, deg, extraConfig);
1132
1133 assert(extraConfig.MagneticField.B == 0.0);
1134
1135 double pf = sqrt(mu * mu - m * m);
1136 double ret1 = 0.;
1137
1138 // Legendre on [0, pF] with Sommerfeld mapping: sigma is non-zero only near pF
1139 for (int i = 0; i < 32; i++) {
1140 double p, dpds;
1141 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1142 double E = sqrt(p * p + m * m);
1143 double x = (E - mu) / T;
1144 ret1 += legw32[i] * dpds * p * p * FermiEntropySigma(x);
1145 }
1146
1147 // Shifted Laguerre above pF
1148 double moverT = m / T;
1149 double muoverT = mu / T;
1150 for (int i = 0; i < 32; i++) {
1151 double tx = pf / T + lagx32[i];
1152 double E = sqrt(tx * tx + moverT * moverT);
1153 double x = E - muoverT;
1154 ret1 += lagw32[i] * T * tx * T * tx * T * FermiEntropySigma(x);
1155 }
1156
1157 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1158
1159 // No ret2: at T=0 sigma=0 everywhere, so the analytic T=0 part is exactly zero
1160 return ret1;
1161 }
1162
1163 double FermiNumericalIntegrationLargeMuScalarDensity(double T, double mu, double m, double deg,
1164 const IdealGasFunctionsExtraConfig& extraConfig)
1165 {
1166 if (mu <= m)
1167 return QuantumNumericalIntegrationScalarDensity(1, T, mu, m, deg, extraConfig);
1168
1169 assert(extraConfig.MagneticField.B == 0.0);
1170
1171 double pf = sqrt(mu*mu - m * m);
1172 double ret1 = 0.;
1173 for (int i = 0; i < 32; i++) {
1174 double p, dpds;
1175 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1176 double E = sqrt(p * p + m * m);
1177 ret1 += -legw32[i] * dpds * p * p * m / E / (exp(-(E - mu) / T) + 1.);
1178 }
1179
1180 double moverT = m / T;
1181 double muoverT = mu / T;
1182 for (int i = 0; i < 32; i++) {
1183 double tx = pf / T + lagx32[i];
1184 ret1 += lagw32[i] * T * tx * T * tx * T * moverT / sqrt(tx*tx + moverT * moverT) / (exp(sqrt(tx*tx + moverT * moverT) - muoverT) + 1.);
1185 }
1186
1187 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1188
1189 double ret2 = 0.;
1190 ret2 += deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() * m * pf * (mu - pf / 4. * psi2(m / pf));
1191
1192 return ret1 + ret2;
1193 }
1194
1195 double FermiNumericalIntegrationLargeMuT1dn1dmu1(double T, double mu, double m, double deg,
1196 const IdealGasFunctionsExtraConfig& extraConfig)
1197 {
1198 if (mu <= m)
1199 return QuantumNumericalIntegrationT1dn1dmu1(1, T, mu, m, deg, extraConfig);
1200
1201 assert(extraConfig.MagneticField.B == 0.0);
1202
1203 double pf = sqrt(mu*mu - m * m);
1204
1205 // Integration-by-parts (IBP) decomposition:
1206 // int p^2 f(1-f) dp = T * int (2E - m^2/E) f dp
1207 // (via df/dp = -f(1-f)/T * p/E)
1208 // = T * [ int_0^pF (2E - m^2/E) dp + thermal correction ]
1209 // = T * [ mu*pF + O(T^2) ]
1210 //
1211 // The analytic part mu*pF is extracted exactly, ensuring the correct
1212 // T->0 limit: T * dn/dmu -> g/(2pi^2) * mu * pF (no precision loss).
1213 // The thermal correction (ret1) vanishes as T->0.
1214 //
1215 // The Sommerfeld-Legendre quadrature splits the correction into:
1216 // ret1 = -int_0^pF (2E - m^2/E)(1-f) dp + int_pF^inf (2E - m^2/E) f dp
1217
1218 double m2 = m * m;
1219 double ret1 = 0.;
1220 for (int i = 0; i < 32; i++) {
1221 double p, dpds;
1222 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1223 double E = sqrt(p * p + m2);
1224 ret1 += -legw32[i] * dpds * (2. * E - m2 / E) / (exp(-(E - mu) / T) + 1.);
1225 }
1226
1227 double moverT = m / T;
1228 double muoverT = mu / T;
1229 double moverT2 = moverT * moverT;
1230 for (int i = 0; i < 32; i++) {
1231 double tx = pf / T + lagx32[i];
1232 double EoverT = sqrt(tx * tx + moverT2);
1233 ret1 += lagw32[i] * T * T * (2. * tx * tx + moverT2) / EoverT / (exp(EoverT - muoverT) + 1.);
1234 }
1235
1236 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1237
1238 double ret2 = deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() * mu * pf;
1239
1240 return T * (ret1 + ret2);
1241 }
1242
1243 double FermiNumericalIntegrationLargeMuT2dn2dmu2(double T, double mu, double m, double deg,
1244 const IdealGasFunctionsExtraConfig& extraConfig)
1245 {
1246 if (mu <= m)
1247 return QuantumNumericalIntegrationT2dn2dmu2(1, T, mu, m, deg, extraConfig);
1248
1249 assert(extraConfig.MagneticField.B == 0.0);
1250
1251 double pf = sqrt(mu*mu - m * m);
1252
1253 // Integration-by-parts (IBP) decomposition:
1254 // This function returns T^2 * d^2n/dmu^2
1255 // = g/(2pi^2) * int p^2 f(1-f)(1-2f) dp
1256 // = g/(2pi^2) * T * int (2p^2+m^2)/E f(1-f) dp
1257 //
1258 // via f(1-f)(1-2f) = -T*(E/p) * d/dp[f(1-f)], integrate by parts,
1259 // boundary terms vanish.
1260 //
1261 // The integrand (2p^2+m^2)/E * f(1-f) is a smooth peaked function
1262 // ~1/(4 cosh^2((E-mu)/(2T))) with no explicit 1/T factor.
1263 // The Sommerfeld-Legendre + Laguerre quadrature concentrates points
1264 // near the Fermi surface.
1265 //
1266 // The T->0 limit of d^2n/dmu^2 is (mu^2+pF^2)/pF, recovered via
1267 // d^2n/dmu^2 = (1/T) * int (2p^2+m^2)/E f(1-f) dp
1268 // ~ (1/T) * T*(mu^2+pF^2)/pF = (mu^2+pF^2)/pF
1269 //
1270 // Analytic T=0 term is extracted exactly (ret2), thermal correction
1271 // computed via quadrature (ret1). Since T^2 * (ret2 + ret1) / T^2
1272 // round-trips without precision loss in IEEE double, this ensures
1273 // accuracy even when the caller divides by T^2 to get d^2n/dmu^2.
1274
1275 double m2 = m * m;
1276 double quad = 0.;
1277 for (int i = 0; i < 32; i++) {
1278 double p, dpds;
1279 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1280 double E = sqrt(p * p + m2);
1281 double x = (E - mu) / T;
1282 // f(1-f) = exp(x)/(1+exp(x))^2, stable for x < 0 (below pF)
1283 double ex = exp(x);
1284 double ff1mf = ex / ((1. + ex) * (1. + ex));
1285 quad += legw32[i] * dpds * (2. * p * p + m2) / E * ff1mf;
1286 }
1287
1288 double moverT = m / T;
1289 double muoverT = mu / T;
1290 double moverT2 = moverT * moverT;
1291 for (int i = 0; i < 32; i++) {
1292 double tx = pf / T + lagx32[i];
1293 double EoverT = sqrt(tx * tx + moverT2);
1294 double x = EoverT - muoverT;
1295 // f(1-f) = exp(-x)/(1+exp(-x))^2, stable for x > 0 (above pF)
1296 double emx = exp(-x);
1297 double ff1mf = emx / ((1. + emx) * (1. + emx));
1298 quad += lagw32[i] * T * T * (2. * tx * tx + moverT2) / EoverT * ff1mf;
1299 }
1300
1301 // quad = int (2p^2+m^2)/E f(1-f) dp ~ T*(mu^2+pF^2)/pF as T->0
1302 // d^2n/dmu^2 = quad/T = (mu^2+pF^2)/pF + O(T^2)
1303 double ret2 = (mu * mu + pf * pf) / pf; // analytic T=0 value of d^2n/dmu^2
1304 double ret1 = quad / T - ret2; // thermal correction, -> 0 as T->0
1305
1306 return T * T * (ret2 + ret1) * deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1307 }
1308
1309 double FermiNumericalIntegrationLargeMuT3dn3dmu3(double T, double mu, double m, double deg,
1310 const IdealGasFunctionsExtraConfig& extraConfig)
1311 {
1312 if (mu <= m)
1313 return QuantumNumericalIntegrationT3dn3dmu3(1, T, mu, m, deg, extraConfig);
1314
1315 assert(extraConfig.MagneticField.B == 0.0);
1316
1317 double pf = sqrt(mu*mu - m * m);
1318
1319 // Integration-by-parts (IBP) decomposition:
1320 // This function returns T^3 * d^3n/dmu^3
1321 // = g/(2pi^2) * int p^2 f(1-f)(1-6f(1-f)) dp
1322 // = g/(2pi^2) * T * int (2p^2+m^2)/E f(1-f)(1-2f) dp
1323 //
1324 // via f(1-f)(1-6f(1-f)) = -T*(E/p) * d/dp[f(1-f)(1-2f)],
1325 // integrate by parts, boundary terms vanish.
1326 //
1327 // The T->0 value of d^3n/dmu^3 is mu*(3*pF^2-mu^2)/pF^3,
1328 // extracted analytically (ret2). Thermal correction (ret1)
1329 // computed via quadrature, -> 0 as T->0.
1330
1331 double m2 = m * m;
1332 double quad = 0.;
1333 for (int i = 0; i < 32; i++) {
1334 double p, dpds;
1335 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
1336 double E = sqrt(p * p + m2);
1337 double x = (E - mu) / T;
1338 // f(1-f)(1-2f): use exp(x) form, stable for x < 0 (below pF)
1339 double ex = exp(x);
1340 double f = 1. / (ex + 1.);
1341 double ff1mf = ex / ((1. + ex) * (1. + ex));
1342 double ff1mf_1m2f = ff1mf * (1. - 2. * f);
1343 quad += legw32[i] * dpds * (2. * p * p + m2) / E * ff1mf_1m2f;
1344 }
1345
1346 double moverT = m / T;
1347 double muoverT = mu / T;
1348 double moverT2 = moverT * moverT;
1349 for (int i = 0; i < 32; i++) {
1350 double tx = pf / T + lagx32[i];
1351 double EoverT = sqrt(tx * tx + moverT2);
1352 double x = EoverT - muoverT;
1353 // Above pF: x > 0, use exp(-x) forms for stability
1354 double emx = exp(-x);
1355 double f = emx / (1. + emx);
1356 double ff1mf = emx / ((1. + emx) * (1. + emx));
1357 double ff1mf_1m2f = ff1mf * (1. - 2. * f);
1358 quad += lagw32[i] * T * T * (2. * tx * tx + moverT2) / EoverT * ff1mf_1m2f;
1359 }
1360
1361 // quad = int (2p^2+m^2)/E f(1-f)(1-2f) dp ~ T^2 * mu*(3pF^2-mu^2)/pF^3 as T->0
1362 // d^3n/dmu^3 = quad/T^2 = mu*(3pF^2-mu^2)/pF^3 + O(T^2)
1363 double ret2 = mu * (3. * pf * pf - mu * mu) / (pf * pf * pf); // analytic T=0
1364 double ret1 = quad / (T * T) - ret2; // thermal correction
1365
1366 return T * T * T * (ret2 + ret1) * deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
1367 }
1368
1369 double FermiNumericalIntegrationLargeMuTdndmu(int N, double T, double mu, double m, double deg,
1370 const IdealGasFunctionsExtraConfig& extraConfig)
1371 {
1372 if (N < 0 || N>3) {
1373 throw std::runtime_error("**ERROR** FermiNumericalIntegrationLargeMuTdndmu: N < 0 or N > 3");
1374 }
1375 if (N == 0)
1376 return FermiNumericalIntegrationLargeMuDensity(T, mu, m, deg, extraConfig);
1377
1378 if (N == 1)
1379 return FermiNumericalIntegrationLargeMuT1dn1dmu1(T, mu, m, deg, extraConfig);
1380
1381 if (N == 2)
1382 return FermiNumericalIntegrationLargeMuT2dn2dmu2(T, mu, m, deg, extraConfig);
1383
1384 return FermiNumericalIntegrationLargeMuT3dn3dmu3(T, mu, m, deg, extraConfig);
1385 }
1386
1387 double FermiNumericalIntegrationLargeMuChiN(int N, double T, double mu, double m, double deg,
1388 const IdealGasFunctionsExtraConfig& extraConfig)
1389 {
1390 return FermiNumericalIntegrationLargeMuTdndmu(N - 1, T, mu, m, deg, extraConfig) / pow(T, 3) / xMath::GeVtoifm3();
1391 }
1392
1393 double FermiNumericalIntegrationLargeMuChiNDimensionfull(int N, double T, double mu, double m, double deg,
1394 const IdealGasFunctionsExtraConfig& extraConfig)
1395 {
1396 return FermiNumericalIntegrationLargeMuTdndmu(N - 1, T, mu, m, deg, extraConfig) / pow(T, N-1) / xMath::GeVtoifm3();
1397 }
1398
1399 double FermiZeroTDensity(double mu, double m, double deg,
1400 const IdealGasFunctionsExtraConfig& extraConfig)
1401 {
1402 if (m >= mu)
1403 return 0.0;
1404 double pf = sqrt(mu * mu - m * m);
1405 return deg / 6. / xMath::Pi() / xMath::Pi() * pf * pf * pf * xMath::GeVtoifm3();
1406 }
1407
1408 double FermiZeroTPressure(double mu, double m, double deg,
1409 const IdealGasFunctionsExtraConfig& extraConfig)
1410 {
1411 assert(extraConfig.MagneticField.B == 0.0);
1412 if (m >= mu)
1413 return 0.0;
1414 double pf = sqrt(mu * mu - m * m);
1415 if (m == 0.0) {
1416 return deg / 24. / xMath::Pi() / xMath::Pi() * pf * pf * pf * pf * xMath::GeVtoifm3();
1417 }
1418 double m2 = m * m;
1419 return deg / 48. / xMath::Pi() / xMath::Pi() *
1420 (
1421 mu * pf * (2. * mu * mu - 5. * m2)
1422 - 3. * m2 * m2 * log(m / (mu + pf))
1423 ) * xMath::GeVtoifm3();
1424 }
1425
1426 double FermiZeroTEnergyDensity(double mu, double m, double deg,
1427 const IdealGasFunctionsExtraConfig& extraConfig)
1428 {
1429 assert(extraConfig.MagneticField.B == 0.0);
1430 if (m >= mu)
1431 return 0.0;
1432 double pf = sqrt(mu * mu - m * m);
1433 if (m == 0.0) {
1434 return deg / 8. / xMath::Pi() / xMath::Pi() * pf * pf * pf * pf * xMath::GeVtoifm3();
1435 }
1436 double m2 = m * m;
1437 return deg / 16. / xMath::Pi() / xMath::Pi() *
1438 (
1439 mu * pf * (2. * mu * mu - m2)
1440 + m2 * m2 * log(m / (mu + pf))
1441 ) * xMath::GeVtoifm3();
1442 }
1443
1444 double FermiZeroTEntropyDensity(double mu, double m, double deg,
1445 const IdealGasFunctionsExtraConfig& extraConfig)
1446 {
1447 return 0.0;
1448 }
1449
1450 double FermiZeroTdsdT(double mu, double m, double deg,
1451 const IdealGasFunctionsExtraConfig& extraConfig)
1452 {
1453 // ds/dT|_{T=0} = g/(2pi^2) * pi^2/3 * mu * pF = g * mu * pF / 6
1454 assert(extraConfig.MagneticField.B == 0.0);
1455 if (m >= mu)
1456 return 0.0;
1457 double pf = sqrt(mu * mu - m * m);
1458 return deg * mu * pf / 6. * xMath::GeVtoifm3();
1459 }
1460
1461 double FermiZeroTScalarDensity(double mu, double m, double deg,
1462 const IdealGasFunctionsExtraConfig& extraConfig)
1463 {
1464 assert(extraConfig.MagneticField.B == 0.0);
1465 if (m >= mu)
1466 return 0.0;
1467 double pf = sqrt(mu * mu - m * m);
1468 if (m == 0.0) {
1469 return 0.;
1470 }
1471 double m2 = m * m;
1472 return deg * m / 4. / xMath::Pi() / xMath::Pi() *
1473 (
1474 mu * pf
1475 + m2 * log(m / (mu + pf))
1476 ) * xMath::GeVtoifm3();
1477 }
1478
1479 double FermiZeroTdn1dmu1(double mu, double m, double deg,
1480 const IdealGasFunctionsExtraConfig& extraConfig)
1481 {
1482 assert(extraConfig.MagneticField.B == 0.0);
1483 if (m >= mu)
1484 return 0.0;
1485 double pf = sqrt(mu * mu - m * m);
1486 return deg / 2. / xMath::Pi() / xMath::Pi() * mu * pf * xMath::GeVtoifm3();
1487 }
1488
1489 double FermiZeroTdn2dmu2(double mu, double m, double deg,
1490 const IdealGasFunctionsExtraConfig& extraConfig)
1491 {
1492 assert(extraConfig.MagneticField.B == 0.0);
1493 if (m >= mu)
1494 return 0.0;
1495 double pf = sqrt(mu * mu - m * m);
1496 return deg / 2. / xMath::Pi() / xMath::Pi() * (mu * mu + pf * pf) / pf * xMath::GeVtoifm3();
1497 }
1498
1499 double FermiZeroTdn3dmu3(double mu, double m, double deg,
1500 const IdealGasFunctionsExtraConfig& extraConfig)
1501 {
1502 assert(extraConfig.MagneticField.B == 0.0);
1503 if (m >= mu)
1504 return 0.0;
1505 double pf = sqrt(mu * mu - m * m);
1506 return deg / 2. / xMath::Pi() / xMath::Pi() * mu * (3. * pf * pf - mu * mu) / pf / pf / pf * xMath::GeVtoifm3();
1507 }
1508
1509 double FermiZeroTdndmu(int N, double mu, double m, double deg,
1510 const IdealGasFunctionsExtraConfig& extraConfig)
1511 {
1512 if (N < 0 || N>3) {
1513 throw std::runtime_error("**ERROR** FermiNumericalIntegrationLargeMuTdndmu: N < 0 or N > 3");
1514 }
1515 if (N == 0)
1516 return FermiZeroTDensity(mu, m, deg, extraConfig);
1517
1518 if (N == 1)
1519 return FermiZeroTdn1dmu1(mu, m, deg, extraConfig);
1520
1521 if (N == 2)
1522 return FermiZeroTdn2dmu2(mu, m, deg, extraConfig);
1523
1524 return FermiZeroTdn3dmu3(mu, m, deg, extraConfig);
1525 }
1526
1527 double FermiZeroTChiN(int N, double mu, double m, double deg,
1528 const IdealGasFunctionsExtraConfig& extraConfig)
1529 {
1530 throw std::runtime_error("**ERROR** FermiZeroTChiN: This quantity is infinite by definition at T = 0!");
1531 //return FermiNumericalIntegrationLargeMuTdndmu(N - 1, mu, m, deg) / pow(T, 3) / xMath::GeVtoifm3();
1532 }
1533
1534 double FermiZeroTChiNDimensionfull(int N, double mu, double m, double deg,
1535 const IdealGasFunctionsExtraConfig& extraConfig)
1536 {
1537 return FermiZeroTdndmu(N - 1, mu, m, deg, extraConfig) / xMath::GeVtoifm3();
1538 }
1539
1540 double IdealGasQuantity(Quantity quantity, QStatsCalculationType calctype, int statistics, double T, double mu, double m, double deg, int order,
1541 const IdealGasFunctionsExtraConfig& extraConfig)
1542 {
1543 if (statistics == 0) {
1544 if (quantity == ParticleDensity)
1545 return BoltzmannDensity(T, mu, m, deg, extraConfig);
1546 if (quantity == Pressure)
1547 return BoltzmannPressure(T, mu, m, deg, extraConfig);
1548 if (quantity == EnergyDensity)
1549 return BoltzmannEnergyDensity(T, mu, m, deg, extraConfig);
1550 if (quantity == EntropyDensity)
1551 return BoltzmannEntropyDensity(T, mu, m, deg, extraConfig);
1552 if (quantity == ScalarDensity)
1553 return BoltzmannScalarDensity(T, mu, m, deg, extraConfig);
1554 if (quantity == chi2)
1555 return BoltzmannChiN(2, T, mu, m, deg, extraConfig);
1556 if (quantity == chi3)
1557 return BoltzmannChiN(3, T, mu, m, deg, extraConfig);
1558 if (quantity == chi4)
1559 return BoltzmannChiN(4, T, mu, m, deg, extraConfig);
1560 if (quantity == chi2difull)
1561 return BoltzmannChiNDimensionfull(2, T, mu, m, deg, extraConfig);
1562 if (quantity == chi3difull)
1563 return BoltzmannChiNDimensionfull(3, T, mu, m, deg, extraConfig);
1564 if (quantity == chi4difull)
1565 return BoltzmannChiNDimensionfull(4, T, mu, m, deg, extraConfig);
1566 // Temperature derivatives
1567 if (quantity == dndT)
1568 return BoltzmanndndT(T, mu, m, deg, extraConfig);
1569 if (quantity == d2ndT2)
1570 return Boltzmannd2ndT2(T, mu, m, deg, extraConfig);
1571 if (quantity == dedT)
1572 return BoltzmanndedT(T, mu, m, deg, extraConfig);
1573 if (quantity == dedmu)
1574 return Boltzmanndedmu(T, mu, m, deg, extraConfig);
1575 if (quantity == dchi2dT)
1576 return Boltzmanndchi2dT(T, mu, m, deg, extraConfig);
1577 if (quantity == dsdT)
1578 return BoltzmanndsdT(T, mu, m, deg, extraConfig);
1579 }
1580 else {
1581 if (calctype == ClusterExpansion) {
1582 if (quantity == ParticleDensity)
1583 return QuantumClusterExpansionDensity(statistics, T, mu, m, deg, order, extraConfig);
1584 if (quantity == Pressure)
1585 return QuantumClusterExpansionPressure(statistics, T, mu, m, deg, order, extraConfig);
1586 if (quantity == EnergyDensity)
1587 return QuantumClusterExpansionEnergyDensity(statistics, T, mu, m, deg, order, extraConfig);
1588 if (quantity == EntropyDensity)
1589 return QuantumClusterExpansionEntropyDensity(statistics, T, mu, m, deg, order, extraConfig);
1590 if (quantity == ScalarDensity)
1591 return QuantumClusterExpansionScalarDensity(statistics, T, mu, m, deg, order, extraConfig);
1592 if (quantity == chi2)
1593 return QuantumClusterExpansionChiN(2, statistics, T, mu, m, deg, order, extraConfig);
1594 if (quantity == chi3)
1595 return QuantumClusterExpansionChiN(3, statistics, T, mu, m, deg, order, extraConfig);
1596 if (quantity == chi4)
1597 return QuantumClusterExpansionChiN(4, statistics, T, mu, m, deg, order, extraConfig);
1598 if (quantity == chi2difull)
1599 return QuantumClusterExpansionChiNDimensionfull(2, statistics, T, mu, m, deg, order, extraConfig);
1600 if (quantity == chi3difull)
1601 return QuantumClusterExpansionChiNDimensionfull(3, statistics, T, mu, m, deg, order, extraConfig);
1602 if (quantity == chi4difull)
1603 return QuantumClusterExpansionChiNDimensionfull(4, statistics, T, mu, m, deg, order, extraConfig);
1604 // Temperature derivatives
1605 if (quantity == dndT)
1606 return QuantumClusterExpansiondndT(statistics, T, mu, m, deg, order, extraConfig);
1607 if (quantity == d2ndT2)
1608 return QuantumClusterExpansiond2ndT2(statistics, T, mu, m, deg, order, extraConfig);
1609 if (quantity == dedT)
1610 return QuantumClusterExpansiondedT(statistics, T, mu, m, deg, order, extraConfig);
1611 if (quantity == dedmu)
1612 return QuantumClusterExpansiondedmu(statistics, T, mu, m, deg, order, extraConfig);
1613 if (quantity == dchi2dT)
1614 return QuantumClusterExpansiondchi2dT(statistics, T, mu, m, deg, order, extraConfig);
1615 if (quantity == dsdT)
1616 return QuantumClusterExpansiondsdT(statistics, T, mu, m, deg, order, extraConfig);
1617 }
1618 else {
1619 if (quantity == ParticleDensity)
1620 return QuantumNumericalIntegrationDensity(statistics, T, mu, m, deg, extraConfig);
1621 if (quantity == Pressure)
1622 return QuantumNumericalIntegrationPressure(statistics, T, mu, m, deg, extraConfig);
1623 if (quantity == EnergyDensity)
1624 return QuantumNumericalIntegrationEnergyDensity(statistics, T, mu, m, deg, extraConfig);
1625 if (quantity == EntropyDensity)
1626 return QuantumNumericalIntegrationEntropyDensity(statistics, T, mu, m, deg, extraConfig);
1627 if (quantity == ScalarDensity)
1628 return QuantumNumericalIntegrationScalarDensity(statistics, T, mu, m, deg, extraConfig);
1629 if (quantity == chi2)
1630 return QuantumNumericalIntegrationChiN(2, statistics, T, mu, m, deg, extraConfig);
1631 if (quantity == chi3)
1632 return QuantumNumericalIntegrationChiN(3, statistics, T, mu, m, deg, extraConfig);
1633 if (quantity == chi4)
1634 return QuantumNumericalIntegrationChiN(4, statistics, T, mu, m, deg, extraConfig);
1635 if (quantity == chi2difull)
1636 return QuantumNumericalIntegrationChiNDimensionfull(2, statistics, T, mu, m, deg, extraConfig);
1637 if (quantity == chi3difull)
1638 return QuantumNumericalIntegrationChiNDimensionfull(3, statistics, T, mu, m, deg, extraConfig);
1639 if (quantity == chi4difull)
1640 return QuantumNumericalIntegrationChiNDimensionfull(4, statistics, T, mu, m, deg, extraConfig);
1641 // Temperature derivatives
1642 if (quantity == dndT)
1643 return QuantumNumericalIntegrationdndT(statistics, T, mu, m, deg, extraConfig);
1644 if (quantity == d2ndT2)
1645 return QuantumNumericalIntegrationd2ndT2(statistics, T, mu, m, deg, extraConfig);
1646 if (quantity == dedT)
1647 return QuantumNumericalIntegrationdedT(statistics, T, mu, m, deg, extraConfig);
1648 if (quantity == dedmu)
1649 return QuantumNumericalIntegrationdedmu(statistics, T, mu, m, deg, extraConfig);
1650 if (quantity == dchi2dT)
1651 return QuantumNumericalIntegrationdchi2dT(statistics, T, mu, m, deg, extraConfig);
1652 if (quantity == dsdT)
1653 return QuantumNumericalIntegrationdsdT(statistics, T, mu, m, deg, extraConfig);
1654 }
1655 }
1656 std::cerr << "**WARNING** IdealGasFunctions::IdealGasQuantity: Unknown quantity" << std::endl;
1657 return 0.;
1658 }
1659
1660 double BoltzmannMagnetization(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1661 // Check for magnetic field effect for charged particles
1662 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
1663 // TODO: Check that it's done correctly
1664 double Qmod = abs(extraConfig.MagneticField.Q);
1665 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
1666 // Sum over spins
1667 double ret = 0.;
1668 for(double sz : spins) {
1669 // Sum over Landau levels
1670 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
1671 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
1672 ret += (T * e0 * xMath::BesselKexp(1, e0 / T)
1673 - Qmod * extraConfig.MagneticField.B * (l + 0.5 - sz) * xMath::BesselKexp(0, e0 / T)
1674 ) * exp((mu - e0) / T);
1675 }
1676 }
1677 ret *= Qmod / 2. / xMath::Pi() / xMath::Pi();
1678 return ret;
1679 }
1680
1681 // No magnetic field
1682 return 0.;
1683 }
1684
1685 double QuantumClusterExpansionMagnetization(int statistics, double T, double mu, double m, double deg, int order,
1686 const IdealGasFunctionsExtraConfig &extraConfig) {
1687 bool signchange = true;
1688 if (statistics == 1) //Fermi
1689 signchange = true;
1690 else if (statistics == -1) //Bose
1691 signchange = false;
1692 else
1693 return BoltzmannMagnetization(T, mu, m, deg, extraConfig);
1694
1695 // Check for magnetic field effect for charged particles
1696 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
1697 double Qmod = abs(extraConfig.MagneticField.Q);
1698 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
1699
1700
1701 // Use Eq. (7) from https://arxiv.org/pdf/2104.06843.pdf
1702 // Sum over spins
1703 double ret = 0.;
1704 for(double sz : spins) {
1705 // Sum over Landau levels
1706 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
1707 double e0 = sqrt(m*m + Qmod*extraConfig.MagneticField.B*(2.*l + 1. - 2.*sz));
1708
1709 // Sum over clusters
1710 double tfug = exp((mu - e0) / T);
1711 double EoverT = e0 / T;
1712 double cfug = tfug;
1713 double sign = 1.;
1714 for (int i = 1; i <= order; ++i) {
1715 ret += sign * (T / static_cast<double>(i) * e0 * xMath::BesselKexp(1, i*EoverT)
1716 - Qmod * extraConfig.MagneticField.B * (l + 0.5 - sz) * xMath::BesselKexp(0, i*EoverT)
1717 ) * cfug;
1718
1719 cfug *= tfug;
1720 if (signchange) sign = -sign;
1721 }
1722 }
1723 }
1724 return ret * Qmod / 2. / xMath::Pi() / xMath::Pi();
1725 }
1726
1727 // No magnetic field
1728 return 0.;
1729 }
1730
1731 double QuantumNumericalIntegrationMagnetization(int statistics, double T, double mu, double m, double deg,
1732 const IdealGasFunctionsExtraConfig &extraConfig) {
1733 if (statistics == 0) return BoltzmannMagnetization(T, mu, m, deg, extraConfig);
1734 if (statistics == 1 && T == 0.) return FermiZeroTMagnetization(mu, m, deg, extraConfig);
1735 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMuMagnetization(T, mu, m, deg, extraConfig);
1736 if (statistics == -1 && mu > m) {
1737 std::cerr << "**WARNING** QuantumNumericalIntegrationScalarDensity: Bose-Einstein condensation" << std::endl;
1739 mu = m;
1740 // return 0.;
1741 }
1742 if (statistics == -1 && T == 0.) return 0.;
1743
1744 // Check for magnetic field effect for charged particles
1745 if (extraConfig.MagneticField.B != 0. && extraConfig.MagneticField.Q != 0.) {
1746 double Qmod = abs(extraConfig.MagneticField.Q);
1747 auto spins = GetSpins(extraConfig.MagneticField.degSpin);
1748
1749 // Use Eq. (5) from https://arxiv.org/pdf/2104.06843.pdf
1750 // Sum over spins
1751 double ret = 0.;
1752 for(double sz : spins) {
1753 // Sum over Landau levels
1754 for(int l = 0; l < extraConfig.MagneticField.lmax; ++l) {
1755
1756 // Numerical integration over pz
1757 double moverT = m / T;
1758 double muoverT = mu / T;
1759 double BoverT2 = extraConfig.MagneticField.B / T / T;
1760 for (int i = 0; i < 32; i++) {
1761 double tx = lagx32[i];
1762 double EoverT = sqrt(tx*tx + moverT*moverT + Qmod*BoverT2*(2.*l + 1. - 2.*sz));
1763 ret += lagw32[i] * T * (tx * T * tx - Qmod * BoverT2 * T * (l + 0.5 - sz) ) / EoverT / (exp(EoverT - muoverT) + statistics);
1764 }
1765 }
1766 }
1767 return ret * Qmod / 2. / xMath::Pi() / xMath::Pi();
1768 }
1769
1770 // No magnetic field
1771 return 0.;
1772 }
1773
1774 double FermiNumericalIntegrationLargeMuMagnetization(double T, double mu, double m, double deg,
1775 const IdealGasFunctionsExtraConfig &extraConfig) {
1776 if (mu <= m)
1777 return QuantumNumericalIntegrationMagnetization(1, T, mu, m, deg, extraConfig);
1778
1779 assert(extraConfig.MagneticField.B == 0.0);
1780
1781 return 0.;
1782 }
1783
1784 double FermiZeroTMagnetization(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1785 assert(extraConfig.MagneticField.B == 0.0);
1786 return 0.;
1787 }
1788
1790
1791 double BoltzmanndndT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1792 // Check for magnetic field effect for charged particles
1793 assert(extraConfig.MagneticField.B == 0);
1794
1795 // No magnetic field
1796 if (m == 0.)
1797 return deg / xMath::Pi() / xMath::Pi() * T * exp(mu/ T) * (3. * T - mu) * xMath::GeVtoifm3();
1798 return deg * m * m / 2. / T / xMath::Pi() / xMath::Pi()
1799 * (m * xMath::BesselKexp(1, m / T) - (mu - 3. * T) * xMath::BesselKexp(2, m / T))
1800 * exp((mu - m) / T) * xMath::GeVtoifm3();
1801 }
1802
1803 double Boltzmannd2ndT2(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1804 // Check for magnetic field effect for charged particles
1805 assert(extraConfig.MagneticField.B == 0);
1806
1807 // No magnetic field
1808 if (m == 0.)
1809 return deg / xMath::Pi() / xMath::Pi() / T * exp(mu/ T) *
1810 (mu * mu - 4. * mu * T + 6. * T * T) * xMath::GeVtoifm3();
1811 return deg / 2. / T / T / T / xMath::Pi() / xMath::Pi()
1812 * m * (m * (m * m + mu * mu - 4. * mu * T + 6. * T * T) * xMath::BesselKexp(0, m / T)
1813 + (m * m * (3. * T - 2. * mu) + 2. * T * (mu * mu - 4. * mu * T + 6. * T * T)) * xMath::BesselKexp(1, m / T))
1814 * exp((mu - m) / T) * xMath::GeVtoifm3();
1815 }
1816
1817 double BoltzmanndedT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1818 // Check for magnetic field effect for charged particles
1819 assert(extraConfig.MagneticField.B == 0);
1820
1821 // No magnetic field
1822 if (m == 0.)
1823 return 3. * deg / xMath::Pi() / xMath::Pi() * T * T * exp(mu/ T) *
1824 (4. * T - mu) * xMath::GeVtoifm3();
1825
1826 return deg * m / 2. / T / xMath::Pi() / xMath::Pi()
1827 * (m * (m*m + 3*T*(4.*T-mu))*xMath::BesselKexp(0, m / T)
1828 + (6.*T*T*(4.*T-mu) - m*m*(mu-5.*T) )*xMath::BesselKexp(1, m / T))
1829 * exp((mu - m) / T) * xMath::GeVtoifm3();
1830 }
1831
1832 double Boltzmanndedmu(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1833 return BoltzmannEnergyDensity(T, mu, m, deg, extraConfig) / T;
1834 }
1835
1836 double Boltzmanndchi2dT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1837 // Check for magnetic field effect for charged particles
1838 assert(extraConfig.MagneticField.B == 0);
1839
1840 // No magnetic field
1841 if (m == 0.)
1842 return -deg * mu / T / T / xMath::Pi() / xMath::Pi() * exp(mu/ T);
1843 return deg * m * m / 2. / T / T / T / T / xMath::Pi() / xMath::Pi()
1844 * (m * xMath::BesselKexp(1, m / T) - mu * xMath::BesselKexp(2, m / T))
1845 * exp((mu - m) / T);
1846 }
1847
1848 double BoltzmanndsdT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig) {
1849 return (BoltzmanndedT(T, mu, m, deg, extraConfig) - mu * BoltzmanndndT(T, mu, m, deg, extraConfig)) / T;
1850 }
1851
1852 double QuantumClusterExpansiondndT(int statistics, double T, double mu, double m, double deg, int order,
1853 const IdealGasFunctionsExtraConfig &extraConfig) {
1854 bool signchange = true;
1855 if (statistics == 1) //Fermi
1856 signchange = true;
1857 else if (statistics == -1) //Bose
1858 signchange = false;
1859 else
1860 return BoltzmanndndT(T, mu, m, deg, extraConfig);
1861
1862 // Check for magnetic field effect for charged particles
1863 assert(extraConfig.MagneticField.B == 0);
1864
1865 // No magnetic field
1866 double tfug = exp((mu - m) / T);
1867 double moverT = m / T;
1868 double cfug = tfug;
1869 double sign = 1.;
1870 double ret = 0.;
1871 for (int i = 1; i <= order; ++i) {
1872 if (m == 0.) {
1873 ret += sign * (
1874 - (mu - 3. * T/ static_cast<double>(i)) / static_cast<double>(i) / static_cast<double>(i)
1875 ) * cfug;
1876 }
1877 else {
1878 ret += sign * (
1879 m * xMath::BesselKexp(1, i*moverT)
1880 - (mu - 3. * T/ static_cast<double>(i)) * xMath::BesselKexp(2, i*moverT)
1881 ) * cfug;
1882 }
1883 cfug *= tfug;
1884 if (signchange) sign = -sign;
1885 }
1886 double prefactor = 1.;
1887 if (m == 0.) {
1888 prefactor = deg * T / xMath::Pi() / xMath::Pi();
1889 } else {
1890 prefactor = deg * m * m / T / 2. / xMath::Pi() / xMath::Pi();
1891 }
1892 return ret * prefactor * xMath::GeVtoifm3();
1893 }
1894
1895 double QuantumClusterExpansiond2ndT2(int statistics, double T, double mu, double m, double deg, int order,
1896 const IdealGasFunctionsExtraConfig &extraConfig) {
1897 bool signchange = true;
1898 if (statistics == 1) //Fermi
1899 signchange = true;
1900 else if (statistics == -1) //Bose
1901 signchange = false;
1902 else
1903 return Boltzmannd2ndT2(T, mu, m, deg, extraConfig);
1904
1905 // Check for magnetic field effect for charged particles
1906 assert(extraConfig.MagneticField.B == 0);
1907
1908 // No magnetic field
1909 double tfug = exp((mu - m) / T);
1910 double moverT = m / T;
1911 double cfug = tfug;
1912 double sign = 1.;
1913 double ret = 0.;
1914 for (int i = 1; i <= order; ++i) {
1915 double k = static_cast<double>(i);
1916 if (m == 0.) {
1917 ret += sign * 2. * T * (mu * mu - 4. * mu * T / k + 6. * T / k * T / k) / k * cfug;
1918 } else {
1919 ret += sign * k * (
1920 (m * (m * m + mu * mu - 4. * mu * T / k + 6. * T * T / k / k) * xMath::BesselKexp(0, i*moverT)
1921 + (m * m * (3. * T / k - 2. * mu) + 2. * T / k * (mu * mu - 4. * mu * T / k + 6. * T / k * T / k)) * xMath::BesselKexp(1, i*moverT))
1922 ) * cfug;
1923 }
1924 cfug *= tfug;
1925 if (signchange) sign = -sign;
1926 }
1927 double prefactor = 1.;
1928 if (m == 0.) {
1929 prefactor = deg / T / T / 2. / xMath::Pi() / xMath::Pi();
1930 } else {
1931 prefactor = deg * m / T / T / T / 2. / xMath::Pi() / xMath::Pi();
1932 }
1933 return ret * prefactor * xMath::GeVtoifm3();
1934 }
1935
1936 double QuantumClusterExpansiondedT(int statistics, double T, double mu, double m, double deg, int order,
1937 const IdealGasFunctionsExtraConfig &extraConfig) {
1938 bool signchange = true;
1939 if (statistics == 1) //Fermi
1940 signchange = true;
1941 else if (statistics == -1) //Bose
1942 signchange = false;
1943 else
1944 return BoltzmanndedT(T, mu, m, deg, extraConfig);
1945
1946 // Check for magnetic field effect for charged particles
1947 assert(extraConfig.MagneticField.B == 0);
1948
1949 // No magnetic field
1950 double tfug = exp((mu - m) / T);
1951 double moverT = m / T;
1952 double cfug = tfug;
1953 double sign = 1.;
1954 double ret = 0.;
1955 for (int i = 1; i <= order; ++i) {
1956 double k = static_cast<double>(i);
1957 if (m == 0.) {
1958 ret += sign * 6. * T / k * T / k * (4. * T / k - mu) / k * cfug;
1959 } else {
1960 ret += sign * (
1961 m * (m*m + 3*T/k*(4.*T/k-mu))*xMath::BesselKexp(0, i*moverT)
1962 + (6.*T/k*T/k*(4.*T/k-mu) - m*m*(mu-5.*T/k) )*xMath::BesselKexp(1, i*moverT)
1963 ) * cfug;
1964 }
1965 cfug *= tfug;
1966 if (signchange) sign = -sign;
1967 }
1968 double prefactor = 1.;
1969 if (m == 0.) {
1970 prefactor = deg / 2. / xMath::Pi() / xMath::Pi();
1971 } else {
1972 prefactor = deg * m / T / 2. / xMath::Pi() / xMath::Pi();
1973 }
1974 return ret * prefactor * xMath::GeVtoifm3();
1975 }
1976
1977 double QuantumClusterExpansiondedmu(int statistics, double T, double mu, double m, double deg, int order,
1978 const IdealGasFunctionsExtraConfig &extraConfig) {
1979 bool signchange = true;
1980 if (statistics == 1) //Fermi
1981 signchange = true;
1982 else if (statistics == -1) //Bose
1983 signchange = false;
1984 else
1985 return Boltzmanndedmu(T, mu, m, deg, extraConfig);
1986
1987 // Check for magnetic field effect for charged particles
1988 assert(extraConfig.MagneticField.B == 0);
1989
1990 // No magnetic field
1991 double tfug = exp((mu - m) / T);
1992 double cfug = tfug;
1993 double moverT = m / T;
1994 double sign = 1.;
1995 double ret = 0.;
1996 for (int i = 1; i <= order; ++i) {
1997 if (m == 0.) {
1998 ret += sign * 3. / static_cast<double>(i) / static_cast<double>(i) / static_cast<double>(i) * cfug / T;
1999 } else {
2000 ret += sign * (xMath::BesselKexp(1, i*moverT) + 3. * xMath::BesselKexp(2, i*moverT) / moverT / static_cast<double>(i)) * cfug / T;
2001 }
2002 cfug *= tfug;
2003 if (signchange) sign = -sign;
2004 }
2005 double prefactor = 1.;
2006 if (m == 0.) {
2007 prefactor = deg * T * T * T * T / xMath::Pi() / xMath::Pi();
2008 } else {
2009 prefactor = deg * m * m * m * T / 2. / xMath::Pi() / xMath::Pi();
2010 }
2011 return ret * prefactor * xMath::GeVtoifm3();
2012 }
2013
2014
2015 double QuantumClusterExpansiondchi2dT(int statistics, double T, double mu, double m, double deg, int order,
2016 const IdealGasFunctionsExtraConfig &extraConfig) {
2017 bool signchange = true;
2018 if (statistics == 1) //Fermi
2019 signchange = true;
2020 else if (statistics == -1) //Bose
2021 signchange = false;
2022 else
2023 return Boltzmanndchi2dT(T, mu, m, deg, extraConfig);
2024
2025 // Check for magnetic field effect for charged particles
2026 assert(extraConfig.MagneticField.B == 0);
2027
2028 // No magnetic field
2029 double tfug = exp((mu - m) / T);
2030 double moverT = m / T;
2031 double cfug = tfug;
2032 double sign = 1.;
2033 double ret = 0.;
2034 for (int i = 1; i <= order; ++i) {
2035 double k = static_cast<double>(i);
2036 if (m == 0.) {
2037 ret += sign * k * (-mu / k / k) * cfug;
2038 }
2039 else {
2040 ret += sign * k * (
2041 m * xMath::BesselKexp(1, i*moverT)
2042 - mu * xMath::BesselKexp(2, i*moverT)
2043 ) * cfug;
2044 }
2045 cfug *= tfug;
2046 if (signchange) sign = -sign;
2047 }
2048 double prefactor = 1.;
2049 if (m == 0.) {
2050 prefactor = deg / T / T / xMath::Pi() / xMath::Pi();
2051 } else {
2052 prefactor = deg * m * m / 2. / T / T / T / T / xMath::Pi() / xMath::Pi();
2053 }
2054 return ret * prefactor;
2055 }
2056
2057 double QuantumClusterExpansiondsdT(int statistics, double T, double mu, double m, double deg, int order,
2058 const IdealGasFunctionsExtraConfig &extraConfig) {
2059 return (QuantumClusterExpansiondedT(statistics, T, mu, m, deg, order, extraConfig)
2060 - mu * QuantumClusterExpansiondndT(statistics, T, mu, m, deg, order, extraConfig)) / T;
2061 }
2062
2063 double QuantumNumericalIntegrationdndT(int statistics, double T, double mu, double m, double deg,
2064 const IdealGasFunctionsExtraConfig &extraConfig) {
2065 if (statistics == 0) return BoltzmanndndT(T, mu, m, deg, extraConfig);
2066 if (statistics == 1 && T == 0.) return 0.; //FermiZeroTDensity(mu, m, deg, extraConfig);
2067 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMudndT(T, mu, m, deg, extraConfig);
2068 if (statistics == -1 && mu > m) {
2069 std::cerr << "**WARNING** QuantumNumericalIntegrationDensity: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
2071 mu = m;
2072 // return 0.;
2073 }
2074 if (statistics == -1 && T == 0.) return 0.;
2075
2076 // Check for magnetic field effect for charged particles
2077 assert(extraConfig.MagneticField.B == 0);
2078
2079 // No magnetic field
2080 double ret = 0.;
2081 double moverT = m / T;
2082 double muoverT = mu / T;
2083 for (int i = 0; i < 32; i++) {
2084 double tx = lagx32[i];
2085 double EoverT = sqrt(tx*tx + moverT * moverT);
2086 double Eexp = exp(EoverT - muoverT);
2087 double f = 1. / (Eexp + statistics);
2088 ret += lagw32[i] * T * tx * T * tx * T * f * (EoverT - muoverT) * (1. - statistics * f);
2089 }
2090
2091 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() / T;
2092
2093 return ret;
2094 }
2095
2096 double QuantumNumericalIntegrationd2ndT2(int statistics, double T, double mu, double m, double deg,
2097 const IdealGasFunctionsExtraConfig &extraConfig) {
2098 if (statistics == 0) return Boltzmannd2ndT2(T, mu, m, deg, extraConfig);
2099 if (statistics == 1 && T == 0.) return 0.;//FermiZeroTDensity(mu, m, deg, extraConfig);
2100 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMud2ndT2(T, mu, m, deg, extraConfig);
2101 if (statistics == -1 && mu > m) {
2102 std::cerr << "**WARNING** QuantumNumericalIntegrationDensity: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
2104 mu = m;
2105 // return 0.;
2106 }
2107 if (statistics == -1 && T == 0.) return 0.;
2108
2109 // Check for magnetic field effect for charged particles
2110 assert(extraConfig.MagneticField.B == 0);
2111
2112 // No magnetic field
2113 double ret = 0.;
2114 double moverT = m / T;
2115 double muoverT = mu / T;
2116 for (int i = 0; i < 32; i++) {
2117 double tx = lagx32[i];
2118 double EoverT = sqrt(tx*tx + moverT * moverT);
2119 double Eexp = exp(EoverT - muoverT);
2120 double f = 1. / (Eexp + statistics);
2121 ret += lagw32[i] * T * tx * T * tx * T * f
2122 * (EoverT - muoverT) * (1. - statistics * f)
2123 * ((EoverT - muoverT) * (1. - 2. * statistics * f) - 2.);
2124 }
2125
2126 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() / T / T;
2127
2128 return ret;
2129 }
2130
2131 double QuantumNumericalIntegrationdedT(int statistics, double T, double mu, double m, double deg,
2132 const IdealGasFunctionsExtraConfig &extraConfig) {
2133 if (statistics == 0) return BoltzmanndedT(T, mu, m, deg, extraConfig);
2134 if (statistics == 1 && T == 0.) return 0.; //FermiZeroTDensity(mu, m, deg, extraConfig);
2135 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMudedT(T, mu, m, deg, extraConfig);
2136 if (statistics == -1 && mu > m) {
2137 std::cerr << "**WARNING** QuantumNumericalIntegrationDensity: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
2139 mu = m;
2140 // return 0.;
2141 }
2142 if (statistics == -1 && T == 0.) return 0.;
2143
2144 // No magnetic field
2145 double ret = 0.;
2146 double moverT = m / T;
2147 double muoverT = mu / T;
2148 for (int i = 0; i < 32; i++) {
2149 double tx = lagx32[i];
2150 double EoverT = sqrt(tx*tx + moverT * moverT);
2151 double Eexp = exp(EoverT - muoverT);
2152 double f = 1. / (Eexp + statistics);
2153 ret += lagw32[i] * T * tx * T * tx * T * EoverT * f * (EoverT - muoverT) * (1. - statistics * f);
2154 }
2155
2156 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
2157
2158 return ret;
2159 }
2160
2161 double QuantumNumericalIntegrationdedmu(int statistics, double T, double mu, double m, double deg,
2162 const IdealGasFunctionsExtraConfig &extraConfig) {
2163 if (statistics == 0) return BoltzmanndedT(T, mu, m, deg, extraConfig);
2164 if (statistics == 1 && T == 0.) return 0.; //FermiZeroTDensity(mu, m, deg, extraConfig);
2165 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMudedmu(T, mu, m, deg, extraConfig);
2166 if (statistics == -1 && mu > m) {
2167 std::cerr << "**WARNING** QuantumNumericalIntegrationDensity: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
2169 mu = m;
2170 // return 0.;
2171 }
2172 if (statistics == -1 && T == 0.) return 0.;
2173
2174 // No magnetic field
2175 double ret = 0.;
2176 double moverT = m / T;
2177 double muoverT = mu / T;
2178 for (int i = 0; i < 32; i++) {
2179 double tx = lagx32[i];
2180 double EoverT = sqrt(tx*tx + moverT * moverT);
2181 double Eexp = exp(EoverT - muoverT);
2182 double f = 1. / (Eexp + statistics);
2183 ret += lagw32[i] * T * tx * T * tx * T * EoverT * f * (1. - statistics * f);
2184 }
2185
2186 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
2187
2188 return ret;
2189 }
2190
2191 double QuantumNumericalIntegrationdchi2dT(int statistics, double T, double mu, double m, double deg,
2192 const IdealGasFunctionsExtraConfig &extraConfig) {
2193 if (statistics == 0) return Boltzmanndchi2dT(T, mu, m, deg, extraConfig);
2194 if (statistics == 1 && T == 0.) return 0.;//FermiZeroTDensity(mu, m, deg, extraConfig);
2195 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMudchi2dT(T, mu, m, deg, extraConfig);
2196 if (statistics == -1 && mu > m) {
2197 std::cerr << "**WARNING** QuantumNumericalIntegrationDensity: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
2199 mu = m;
2200 // return 0.;
2201 }
2202 if (statistics == -1 && T == 0.) return 0.;
2203
2204 // Check for magnetic field effect for charged particles
2205 assert(extraConfig.MagneticField.B == 0);
2206
2207 // No magnetic field
2208 double ret = 0.;
2209 double moverT = m / T;
2210 double muoverT = mu / T;
2211 for (int i = 0; i < 32; i++) {
2212 double tx = lagx32[i];
2213 double EoverT = sqrt(tx*tx + moverT * moverT);
2214 double Eexp = exp(EoverT - muoverT);
2215 double f = 1. / (Eexp + statistics);
2216 ret += lagw32[i] * T * tx * T * tx * T * f
2217 * (1. - statistics * f)
2218 * ((EoverT - muoverT) * (1. - 2. * statistics * f) - 3.);
2219 }
2220
2221 ret *= deg / 2. / xMath::Pi() / xMath::Pi() / T / T / T / T;
2222
2223 return ret;
2224 }
2225
2226 double QuantumNumericalIntegrationdsdT(int statistics, double T, double mu, double m, double deg,
2227 const IdealGasFunctionsExtraConfig &extraConfig) {
2228 if (statistics == 0) return BoltzmanndsdT(T, mu, m, deg, extraConfig);
2229 if (statistics == 1 && T == 0.) return FermiZeroTdsdT(mu, m, deg, extraConfig);
2230 if (statistics == 1 && mu > m) return FermiNumericalIntegrationLargeMudsdT(T, mu, m, deg, extraConfig);
2231 if (statistics == -1 && mu > m) {
2232 std::cerr << "**WARNING** QuantumNumericalIntegrationdsdT: Bose-Einstein condensation, mass = " << m << ", mu = " << mu << std::endl;
2234 mu = m;
2235 }
2236 if (statistics == -1 && T == 0.) return 0.;
2237
2238 // ds/dT|_mu = g/(2pi^2) * (1/T) * int p^2 (E-mu)^2/T^2 f(1-f) dp
2239 // = g/(2pi^2) * (1/T^3) * int p^2 (E-mu)^2 f(1 +/- statistics*f) dp [signs differ for B/F]
2240 // For Fermi: f(1-f) = f - f^2; For Bose: f(1+f)
2241 double ret = 0.;
2242 double moverT = m / T;
2243 double muoverT = mu / T;
2244 for (int i = 0; i < 32; i++) {
2245 double tx = lagx32[i];
2246 double EoverT = sqrt(tx*tx + moverT * moverT);
2247 double Eexp = exp(EoverT - muoverT);
2248 double f = 1. / (Eexp + statistics);
2249 double xval = EoverT - muoverT;
2250 ret += lagw32[i] * T * tx * T * tx * T * xval * xval * f * (1. - statistics * f);
2251 }
2252
2253 ret *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() / T;
2254
2255 return ret;
2256 }
2257
2258 double FermiNumericalIntegrationLargeMudndT(double T, double mu, double m, double deg,
2259 const IdealGasFunctionsExtraConfig &extraConfig) {
2260 if (mu <= m)
2261 return QuantumNumericalIntegrationdndT(1, T, mu, m, deg, extraConfig);
2262
2263 assert(extraConfig.MagneticField.B == 0.0);
2264
2265 double pf = sqrt(mu*mu - m * m);
2266 double ret1 = 0.;
2267 for (int i = 0; i < 32; i++) {
2268 double p, dpds;
2269 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
2270 double en = sqrt(p * p + m * m);
2271 double fbar = 1. / (exp(-(en - mu) / T) + 1.);
2272 ret1 += -legw32[i] * dpds * p * p * (mu - en) / T / T * fbar * (1. - fbar);
2273 }
2274
2275 double moverT = m / T;
2276 double muoverT = mu / T;
2277 for (int i = 0; i < 32; i++) {
2278 double tx = pf / T + lagx32[i];
2279 double EoverT = sqrt(tx*tx + moverT * moverT);
2280 double f = 1. / (exp(EoverT - muoverT) + 1.);
2281 ret1 += lagw32[i] * T * tx * T * tx * T * (EoverT - muoverT) / T * f * (1. - f);
2282 }
2283
2284 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
2285
2286 return ret1;
2287 }
2288
2289 double FermiNumericalIntegrationLargeMud2ndT2(double T, double mu, double m, double deg,
2290 const IdealGasFunctionsExtraConfig &extraConfig) {
2291 if (mu <= m)
2292 return QuantumNumericalIntegrationd2ndT2(1, T, mu, m, deg, extraConfig);
2293
2294 assert(extraConfig.MagneticField.B == 0.0);
2295
2296 double pf = sqrt(mu*mu - m * m);
2297 double ret1 = 0.;
2298 for (int i = 0; i < 32; i++) {
2299 double p, dpds;
2300 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
2301 double en = sqrt(p * p + m * m);
2302 double fbar = 1. / (exp(-(en - mu) / T) + 1.);
2303 ret1 += -legw32[i] * dpds * p * p * (mu - en) / T / T / T
2304 * fbar * (1. - fbar) * ((mu - en) / T * (1.-2.*fbar) - 2.);
2305 }
2306
2307 double moverT = m / T;
2308 double muoverT = mu / T;
2309 for (int i = 0; i < 32; i++) {
2310 double tx = pf / T + lagx32[i];
2311 double EoverT = sqrt(tx*tx + moverT * moverT);
2312 double f = 1. / (exp(EoverT - muoverT) + 1.);
2313 ret1 += lagw32[i] * T * tx * T * tx * T * (EoverT - muoverT) / T / T
2314 * f * (1. - f) * ((EoverT - muoverT) * (1. - 2. * f) - 2.);
2315 }
2316
2317 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
2318
2319 return ret1;
2320 }
2321
2322 double FermiNumericalIntegrationLargeMudedT(double T, double mu, double m, double deg,
2323 const IdealGasFunctionsExtraConfig &extraConfig) {
2324 if (mu <= m)
2325 return QuantumNumericalIntegrationdedT(1, T, mu, m, deg, extraConfig);
2326
2327 assert(extraConfig.MagneticField.B == 0.0);
2328
2329 double pf = sqrt(mu*mu - m * m);
2330 double ret1 = 0.;
2331 for (int i = 0; i < 32; i++) {
2332 double p, dpds;
2333 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
2334 double en = sqrt(p * p + m * m);
2335 double fbar = 1. / (exp(-(en - mu) / T) + 1.);
2336 ret1 += -legw32[i] * dpds * p * p * en * (mu - en) / T / T * fbar * (1. - fbar);
2337 }
2338
2339 double moverT = m / T;
2340 double muoverT = mu / T;
2341 for (int i = 0; i < 32; i++) {
2342 double tx = pf / T + lagx32[i];
2343 double EoverT = sqrt(tx*tx + moverT * moverT);
2344 double f = 1. / (exp(EoverT - muoverT) + 1.);
2345 ret1 += lagw32[i] * T * tx * T * tx * T * EoverT * T * (EoverT - muoverT) / T * f * (1. - f);
2346 }
2347
2348 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3();
2349
2350 return ret1;
2351 }
2352
2353 double FermiNumericalIntegrationLargeMudedmu(double T, double mu, double m, double deg,
2354 const IdealGasFunctionsExtraConfig &extraConfig) {
2355 if (mu <= m)
2356 return QuantumNumericalIntegrationdedmu(1, T, mu, m, deg, extraConfig);
2357
2358 assert(extraConfig.MagneticField.B == 0.0);
2359
2360 double pf = sqrt(mu*mu - m * m);
2361 double ret1 = 0.;
2362 for (int i = 0; i < 32; i++) {
2363 double p, dpds;
2364 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
2365 double en = sqrt(p * p + m * m);
2366 double Eexp = exp(-(en - mu) / T);
2367 ret1 += legw32[i] * dpds * p * p * en * 1. / (1. + 1./Eexp) / (Eexp + 1.);
2368 }
2369
2370 double moverT = m / T;
2371 double muoverT = mu / T;
2372 for (int i = 0; i < 32; i++) {
2373 double tx = pf / T + lagx32[i];
2374 double EoverT = sqrt(tx*tx + moverT * moverT);
2375 double Eexp = exp(EoverT - muoverT);
2376 ret1 += lagw32[i] * T * tx * T * tx * T * EoverT * T * 1. / (1. + 1. / Eexp) / (Eexp + 1.);
2377 }
2378
2379 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() / T;
2380
2381 return ret1;
2382 }
2383
2384 double FermiNumericalIntegrationLargeMudchi2dT(double T, double mu, double m, double deg,
2385 const IdealGasFunctionsExtraConfig &extraConfig) {
2386 if (mu <= m)
2387 return QuantumNumericalIntegrationdchi2dT(1, T, mu, m, deg, extraConfig);
2388
2389 assert(extraConfig.MagneticField.B == 0.0);
2390
2391 double pf = sqrt(mu*mu - m * m);
2392 double ret1 = 0.;
2393 for (int i = 0; i < 32; i++) {
2394 double p, dpds;
2395 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
2396 double en = sqrt(p * p + m * m);
2397 double fbar = 1. / (exp(-(en - mu) / T) + 1.);
2398 ret1 += legw32[i] * dpds * p * p
2399 * fbar * (1. - fbar) * ((mu - en) / T * (1. - 2. * fbar) - 3.);
2400 }
2401
2402 double moverT = m / T;
2403 double muoverT = mu / T;
2404 for (int i = 0; i < 32; i++) {
2405 double tx = pf / T + lagx32[i];
2406 double EoverT = sqrt(tx*tx + moverT * moverT);
2407 double f = 1. / (exp(EoverT - muoverT) + 1.);
2408 ret1 += lagw32[i] * T * tx * T * tx * T
2409 * f * (1. - f) * ((EoverT - muoverT) * (1. - 2. * f) - 3.);
2410 }
2411
2412 ret1 *= deg / 2. / xMath::Pi() / xMath::Pi() / T / T / T / T;
2413
2414 return ret1;
2415 }
2416 double FermiNumericalIntegrationLargeMudsdT(double T, double mu, double m, double deg,
2417 const IdealGasFunctionsExtraConfig &extraConfig) {
2418 if (mu <= m)
2419 return QuantumNumericalIntegrationdsdT(1, T, mu, m, deg, extraConfig);
2420
2421 assert(extraConfig.MagneticField.B == 0.0);
2422
2423 double pf = sqrt(mu*mu - m * m);
2424 double m2 = m * m;
2425
2426 // Double-IBP (sigma) form: ds/dT|_mu = g/(2pi^2 T) * int_0^inf sigma(x) H(p) dp
2427 //
2428 // Starting from ds/dT = g/(2pi^2 T) * int p^2 x^2 f(1-f) dp, x = (E-mu)/T:
2429 //
2430 // Step 1: x^2 f(1-f) = -x sigma'(x), sigma = -f ln f - (1-f)ln(1-f)
2431 // Step 2: IBP on p using d(sigma)/dp = sigma'(x) p/(TE):
2432 // int p^2 x^2 f(1-f) dp = int sigma(x) d/dp[pE(E-mu)] dp
2433 //
2434 // H(p) = d/dp[pE(E-mu)] = (E-mu)(2p^2+m^2)/E + p^2
2435 //
2436 // Key: sigma(x) is intrinsically smooth and zero at T=0 (f=0 or 1),
2437 // so the quadrature evaluates the thermal contribution directly
2438 // with no analytical subtraction needed.
2439
2440 double ret1 = 0.;
2441
2442 // Legendre on [0, pF] with Sommerfeld mapping
2443 for (int i = 0; i < 32; i++) {
2444 double p, dpds;
2445 SommerfeldLegendreMap(legx32[i], pf, mu, T, p, dpds);
2446 double E = sqrt(p * p + m2);
2447 double x = (E - mu) / T;
2448 double H = (E - mu) * (2. * p * p + m2) / E + p * p;
2449 ret1 += legw32[i] * dpds * FermiEntropySigma(x) * H;
2450 }
2451
2452 // Laguerre above pF
2453 double moverT = m / T;
2454 double muoverT = mu / T;
2455 double moverT2 = moverT * moverT;
2456 for (int i = 0; i < 32; i++) {
2457 double tx = pf / T + lagx32[i];
2458 double pT = tx * T;
2459 double EoverT = sqrt(tx * tx + moverT2);
2460 double ET = EoverT * T;
2461 double eps = ET - mu;
2462 double H = eps * (2. * pT * pT + m2) / ET + pT * pT;
2463 double x = EoverT - muoverT;
2464 ret1 += lagw32[i] * T * FermiEntropySigma(x) * H;
2465 }
2466
2467 return ret1 * deg / 2. / xMath::Pi() / xMath::Pi() * xMath::GeVtoifm3() / T;
2468 }
2469
2470 } // namespace IdealGasFunctions
2471
2472} // namespace thermalfist
Contains implementation of the thermodynamic functions corresponding to an ideal gas of particles in ...
double FermiNumericalIntegrationLargeMuChiNDimensionfull(int N, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionfull susceptibility for a Fermi-Dirac ideal gas at mu > m.
double FermiNumericalIntegrationLargeMudndT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of particle number density wrt T at constant mu for a Maxwell-Boltzmann gas.
double FermiNumericalIntegrationLargeMud2ndT2(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the second derivative of particle number density wrt T at constant mu for a Maxwell-Boltzman...
double FermiZeroTChiN(int N, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order susceptibility for a Fermi-Dirac ideal gas at zero temperature.
double FermiNumericalIntegrationLargeMuScalarDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the scalar density of a Fermi-Dirac ideal gas at mu > m.
double BoltzmanndsdT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of entropy density wrt T at constant mu for a Maxwell-Boltzmann gas.
double FermiZeroTdn3dmu3(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiNumericalIntegrationLargeMuDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the particle number density of a Fermi-Dirac ideal gas at mu > m.
double QuantumClusterExpansionEntropyDensity(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the entropy density of a quantum ideal gas using cluster expansion.
double QuantumClusterExpansiondedT(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt T at constant mu for a Maxwell-Boltzmann gas.
double FermiNumericalIntegrationLargeMuPressure(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the pressure of a Fermi-Dirac ideal gas at mu > m.
double BoltzmannTdndmu(int N, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the chemical potential derivative of density for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationMagnetization(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the magnetization of a quantum ideal gas using 32-point Gauss-Laguerre quadratures.
double FermiZeroTdn2dmu2(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double QuantumClusterExpansionMagnetization(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the thermal part of the magnetization of a Maxwell-Boltzmann gas, m_B = dP/dB.
double QuantumNumericalIntegrationChiN(int N, int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionless susceptibility for a quantum ideal gas using 32-point Gauss-Lag...
double QuantumClusterExpansionChiNDimensionfull(int N, int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionfull susceptibility for a quantum ideal gas using cluster expansion.
double FermiNumericalIntegrationLargeMuTdndmu(int N, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
void SommerfeldLegendreMap(double s, double pf, double mu, double T, double &p, double &dpds)
Sommerfeld-inspired variable substitution for the Legendre part of the large-mu Fermi integrals.
double psi(double x)
Auxiliary function.
QStatsCalculationType
Identifies whether quantum statistics are to be computed using the cluster expansion or numerical int...
double BoltzmannDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the particle number density of a Maxwell-Boltzmann gas.
double BoltzmanndedT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationdedmu(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt mu at constant T for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationdsdT(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of entropy density wrt T at constant mu using numerical integration.
double BoltzmannChiNDimensionfull(int N, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionfull susceptibility for a Maxwell-Boltzmann gas.
double FermiZeroTEntropyDensity(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the entropy density of a Fermi-Dirac ideal gas at zero temperature.
std::vector< double > GetSpins(double degSpin)
Calculate all the spin values -S, S+1,...,S-1,S.
double FermiNumericalIntegrationLargeMudedmu(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt mu at constant T for a Maxwell-Boltzmann gas.
double FermiNumericalIntegrationLargeMuT3dn3dmu3(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double IdealGasQuantity(Quantity quantity, QStatsCalculationType calctype, int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Calculation of a generic ideal gas function.
double QuantumClusterExpansionScalarDensity(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the scalar density of a quantum ideal gas using cluster expansion.
double FermiZeroTdsdT(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the scalar density of a Fermi-Dirac ideal gas at zero temperature.
bool calculationHadBECIssue
Whether \mu > m Bose-Einstein condensation issue was encountered for a Bose gas.
double BoltzmannEntropyDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the entropy density of a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationdndT(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of particle number density wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationScalarDensity(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the scalar density of a quantum ideal gas using 32-point Gauss-Laguerre quadratures.
double FermiNumericalIntegrationLargeMudchi2dT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of the susceptibility wrt T at constant mu for a Maxwell-Boltzmann gas.
double FermiZeroTEnergyDensity(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the energy density of a Fermi-Dirac ideal gas at zero temperature.
double FermiNumericalIntegrationLargeMuMagnetization(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiNumericalIntegrationLargeMuChiN(int N, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionless susceptibility for a Fermi-Dirac ideal gas at mu > m.
double Boltzmanndchi2dT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of the susceptibility wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationT3dn3dmu3(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiNumericalIntegrationLargeMuT1dn1dmu1(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double Boltzmanndedmu(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt mu at constant T for a Maxwell-Boltzmann gas.
double psi2(double x)
Auxiliary function.
double QuantumClusterExpansiondedmu(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt mu at constant T for a Maxwell-Boltzmann gas.
double FermiNumericalIntegrationLargeMuT2dn2dmu2(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiZeroTMagnetization(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double QuantumNumericalIntegrationdchi2dT(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of the susceptibility wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationTdndmu(int N, int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiZeroTScalarDensity(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double QuantumNumericalIntegrationEnergyDensity(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the energy density of a quantum ideal gas using 32-point Gauss-Laguerre quadratures.
double QuantumClusterExpansionChiN(int N, int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionless susceptibility for a quantum ideal gas using cluster expansion.
double Boltzmannd2ndT2(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the 2nd derivative of particle number density wrt T at constant mu for a Maxwell-Boltzmann g...
double FermiNumericalIntegrationLargeMudedT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumClusterExpansiond2ndT2(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the 2nd derivative of particle number density wrt T at constant mu for a Maxwell-Boltzmann g...
double FermiNumericalIntegrationLargeMuEnergyDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the energy density of a Fermi-Dirac ideal gas at mu > m.
double BoltzmannScalarDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the scalar density of a Maxwell-Boltzmann gas.
double QuantumClusterExpansionDensity(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the particle number density of a quantum ideal gas using cluster expansion.
double BoltzmannMagnetization(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the thermal part of the magnetization of a Maxwell-Boltzmann gas, m_B = dP/dB.
double BoltzmannChiN(int N, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionless susceptibility for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationT2dn2dmu2(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double QuantumClusterExpansionEnergyDensity(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the energy density of a quantum ideal gas using cluster expansion.
double FermiZeroTdn1dmu1(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiNumericalIntegrationLargeMudsdT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of entropy density wrt T at constant mu using Sommerfeld-Legendre + Laguerre ...
double QuantumClusterExpansiondsdT(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of entropy density wrt T at constant mu using the cluster expansion.
double FermiEntropySigma(double x)
Entropy integrand per mode: sigma(x) = -f*ln(f) - (1-f)*ln(1-f) where f = 1/(e^x + 1) and x = (E - mu...
double FermiZeroTPressure(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the pressure of a Fermi-Dirac ideal gas at zero temperature.
double BoltzmannPressure(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the pressure of a Maxwell-Boltzmann gas.
double QuantumClusterExpansionPressure(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the pressure of a quantum ideal gas using cluster expansion.
double QuantumNumericalIntegrationEntropyDensity(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the entropy density of a quantum ideal gas using 32-point Gauss-Laguerre quadratures.
Quantity
Identifies the thermodynamic function.
double QuantumNumericalIntegrationd2ndT2(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the 2nd derivative of particle number density wrt T at constant mu for a Maxwell-Boltzmann g...
double QuantumNumericalIntegrationT1dn1dmu1(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double BoltzmanndndT(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Temperature derivatives.
double QuantumNumericalIntegrationDensity(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the particle number density of a quantum ideal gas using 32-point Gauss-Laguerre quadratures...
double QuantumClusterExpansiondndT(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of particle number density wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationdedT(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of energy density wrt T at constant mu for a Maxwell-Boltzmann gas.
double FermiZeroTdndmu(int N, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
double FermiNumericalIntegrationLargeMuEntropyDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the entropy density of a Fermi-Dirac ideal gas at mu > m.
double QuantumClusterExpansiondchi2dT(int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the derivative of the susceptibility wrt T at constant mu for a Maxwell-Boltzmann gas.
double QuantumNumericalIntegrationChiNDimensionfull(int N, int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order dimensionfull susceptibility for a quantum ideal gas using 32-point Gauss-Lag...
double QuantumClusterExpansionTdndmu(int N, int statistics, double T, double mu, double m, double deg, int order=1, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the chemical potential derivative of density for a quantum ideal gas using cluster expansion...
double FermiZeroTDensity(double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the particle number density of a Fermi-Dirac ideal gas at zero temperature.
double QuantumNumericalIntegrationPressure(int statistics, double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the pressure of a quantum ideal gas using 32-point Gauss-Laguerre quadratures.
double FermiZeroTChiNDimensionfull(int N, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the n-th order susceptibility scaled by T^n for a Fermi-Dirac ideal gas at zero temperature.
double BoltzmannEnergyDensity(double T, double mu, double m, double deg, const IdealGasFunctionsExtraConfig &extraConfig=IdealGasFunctionsExtraConfig())
Computes the energy density of a Maxwell-Boltzmann gas.
const double coefficients_xleg32_zeroone[32]
Nodes of the 32-point Gauss-Legendre quadrature in the interval [0,1].
const double coefficients_wlag32[32]
Weights of the 32-point Gauss-Laguerre quadrature.
const double coefficients_wleg32_zeroone[32]
Weights of the 32-point Gauss-Legendre quadrature in the interval [0,1].
const double coefficients_xlag32[32]
Nodes of the 32-point Gauss-Laguerre quadrature.
constexpr double Pi()
Pi constant.
Definition xMath.h:23
double BesselKexp(int n, double x)
Modified Bessel function K_n(x), divided by exponential factor.
Definition xMath.cpp:693
double BesselK1exp(double x)
Modified Bessel function K_1(x), divided by exponential factor.
Definition xMath.cpp:657
constexpr double GeVtoifm3()
A constant to transform GeV into fm .
Definition xMath.h:31
The main namespace where all classes and functions of the Thermal-FIST library reside.
Definition CosmicEoS.h:9
MagneticFieldConfiguration MagneticField
Magnetic field configuration.
Contains some extra mathematical functions used in the code.