Thermal-FIST 1.5
Package for hadron resonance gas model applications
Loading...
Searching...
No Matches
MomentumDistribution.cpp
Go to the documentation of this file.
1/*
2 * Thermal-FIST package
3 *
4 * Copyright (c) 2015-2019 Volodymyr Vovchenko
5 *
6 * GNU General Public License (GPLv3 or later)
7 */
9
10#include <vector>
11#include <iostream>
12
13#include "HRGBase/xMath.h"
15
16namespace thermalfist {
17
19 m_Norm = 1.;
20 double tmp = 0.;
21
23 for (int i = 0; i < 32; i++) {
24 tmp += m_wlag[i] * dndp(m_xlag[i] * m_T);
25 }
26 tmp *= m_T;
27 m_Norm = 1. / tmp;
28
29 m_Normalized = true;
30 }
31
32 double SiemensRasmussenDistribution::dndp(double p) const {
33 double alphap = alpha(p);
34 double alphamn = 1.;
35 if (alphap != 0.0)
36 alphamn = sinh(alpha(p)) / alpha(p);
37 return m_Norm * p * p * exp(-m_Gamma * w(p) / m_T) * ((1. + m_T / m_Gamma / w(p))*alphamn - m_T / m_Gamma / w(p)*cosh(alpha(p)));
38 }
39
40 double SiemensRasmussenDistribution::dndy(double y) const {
41 std::vector<double> x, w;
43 double ret = 0.;
44 for (int i = 0; i < 32; i++) {
45 double tpt = x[i] * m_T;
46 double tmt = sqrt(m_Mass*m_Mass + tpt * tpt);
47 double tpz = tmt * sinh(y);
48 double tp = sqrt(tpt*tpt + tpz * tpz);
49 double ten = tmt * cosh(y);
50
51 double alphap = alpha(tp);
52 double alphamn = 1.;
53 if (alphap != 0.0)
54 alphamn = sinh(alpha(tp)) / alpha(tp);
55
56 double tadd = w[i] * ten * tpt * exp(-m_Gamma * ten / m_T) * ((1. + m_T / m_Gamma / ten)*alphamn - m_T / m_Gamma / ten * cosh(alpha(tp)));
57 if (tadd != tadd) break;
58 ret += tadd;
59 }
60 return m_T * m_Norm / 2. * ret;
61 }
62
63 double SiemensRasmussenDistribution::dnmtdmt(double mt) const {
64 std::vector<double> x, w;
66 double ret = 0.;
67 for (int i = 0; i < 32; i++) {
68 double ty = x[i];
69 double tmt = mt;
70 double tpt = sqrt(tmt*tmt - m_Mass * m_Mass);
71 double tpz = tmt * sinh(ty);
72 double tp = sqrt(tpt*tpt + tpz * tpz);
73 double ten = tmt * cosh(ty);
74
75 double alphap = alpha(tp);
76 double alphamn = 1.;
77 if (alphap != 0.0)
78 alphamn = sinh(alpha(tp)) / alpha(tp);
79
80 double tadd = w[i] * ten * exp(-m_Gamma * ten / m_T) * ((1. + m_T / m_Gamma / ten)*alphamn - m_T / m_Gamma / ten * cosh(alpha(tp)));
81 if (tadd != tadd) break;
82 ret += tadd;
83 }
84 return m_Norm / 2. * ret;
85 }
86
87 double SiemensRasmussenDistribution::PAv() const {
88 if (!m_useacc) {
89 double tmp1 = 0., tmp2 = 0.;
90 for (int i = 0; i < 32; i++) {
91 double tmp = m_wlag[i] * dndp(m_xlag[i] * m_T);
92 tmp1 += tmp * m_xlag[i] * m_T;
93 tmp2 += tmp;
94 }
95 return tmp1 / tmp2;
96 }
97 else {
98 std::vector<double> xy, wy;
100 std::vector<double> xpt, wpt;
102 double tmp1 = 0., tmp2 = 0.;
103 for (size_t iy = 0; iy < xy.size(); ++iy) {
104 double ty = xy[iy];
105 for (size_t ipt = 0; ipt < xpt.size(); ++ipt) {
106 double tpt = xpt[ipt] * m_T;
107 double tmp = wy[iy] * wpt[ipt] * d2ndptdy(tpt, ty);
108 if (tmp <= 0. || tmp != tmp) continue;
109 double tmt = sqrt(tpt*tpt + m_Mass * m_Mass);
110 double tpz = tmt * sinh(ty);
111 double tp = sqrt(tpt*tpt + tpz * tpz);
112 tmp1 += tmp * tp;
113 tmp2 += tmp;
114 }
115 }
116 return tmp1 / tmp2;
117 }
118 }
119
120
121 double SiemensRasmussenDistribution::d2ndptdy(double pt, double y) const {
122 double tpt = pt, ty = y;
123 double tmt = sqrt(m_Mass*m_Mass + tpt * tpt);
124 double tpz = tmt * sinh(ty);
125 double tp = sqrt(tpt*tpt + tpz * tpz);
126 double ten = tmt * cosh(ty);
127
128 double alphap = alpha(tp);
129 double alphamn = 1.;
130 if (alphap != 0.0)
131 alphamn = sinh(alpha(tp)) / alpha(tp);
132
133 double ret = m_Norm / 2. * ten * tpt * exp(-m_Gamma * ten / m_T) * ((1. + m_T / m_Gamma / ten)*alphamn - m_T / m_Gamma / ten * cosh(alpha(tp)));
134 if (!m_useacc) return ret;
135 else return ret * m_acc->getAcceptance(y + m_ycm, pt);
136 }
137
138
139
141 {
142 if (m_FreezeoutModel != NULL) {
143 delete m_FreezeoutModel;
144 }
145 }
146
148 {
149 m_Norm = m_NormY = m_NormPt = 1.;
150 double tmp = 0.;
151
152 Initialize();
153
154 tmp = 0.;
155 for (size_t i = 0; i < m_xlag.size(); i++) {
156 tmp += m_wlag[i] * dndpt(m_xlag[i] * m_T);
157 }
158 tmp *= m_T;
159 m_NormPt = 1. / tmp;
160
161
162 m_dndy.clearall();
163 m_dndy.add_val(-100., 0.);
164 m_dndyint.clearall();
165 m_dndyint.add_val(-100., 0.);
166 double dy = 0.05;
167 double tmp2 = 0.;
168 for (double yy = -4.; yy < 4.; yy += dy) {
169 tmp = 0.;
170 for (size_t j = 0; j < m_xlag.size(); j++) {
171 tmp += m_wlag[j] * dndptsingle(m_xlag[j] * m_T, yy) * m_T;
172 }
173 tmp2 += tmp * dy;
174 m_dndy.add_val(yy, tmp);
175 m_dndyint.add_val(yy + 0.5 * dy, tmp2);
176 }
177 m_dndy.add_val(100., 0.);
178 m_dndyint.add_val(100., tmp2);
179 tmp = 0.;
180 m_NormY = m_Norm = 1. / tmp2;
181
182 if (m_xlegeta.size() > 1) {
183 m_NormY *= 1. / 2. / m_EtaMax;
184 m_Norm *= 1. / 2. / m_EtaMax;
185 }
186
187 m_Normalized = true;
188 }
189
190 double BoostInvariantMomentumDistribution::ZetaIntegrandpT(double zeta, double pt) const
191 {
192 double R = m_FreezeoutModel->Rfunc(zeta);
193 double tau = m_FreezeoutModel->taufunc(zeta);
194 double dRdZeta = m_FreezeoutModel->dRdZeta(zeta);
195 double dTaudZeta = m_FreezeoutModel->dtaudZeta(zeta);
196 double mT = sqrt(m_Mass * m_Mass + pt * pt);
197 double coshetaperp = m_FreezeoutModel->coshetaperp(zeta);
198 double sinhetaperp = m_FreezeoutModel->sinhetaperp(zeta);
199
200 return R * tau * (mT * dRdZeta * xMath::BesselK1(mT * coshetaperp / m_T) * xMath::BesselI0(pt * sinhetaperp / m_T)
201 - pt * dTaudZeta * xMath::BesselK0(mT * coshetaperp / m_T) * xMath::BesselI1(pt * sinhetaperp / m_T));
202 }
203
205 {
206 if (m_xlegeta.size() > 1)
207 return (m_dndyint.f(m_EtaMax + y) - m_dndyint.f(-m_EtaMax + y)) * m_NormY;
208 else
209 return m_dndy.f(y) * m_NormY;
210 }
211
213 {
214 double ret = 0.;
215 double pt = sqrt(mt * mt - m_Mass * m_Mass);
216 for (size_t i = 0; i < m_xlegT.size(); i++) {
217 double tmp = m_wlegT[i] * ZetaIntegrandpT(m_xlegT[i], pt);
218 if (tmp != tmp) break;
219 ret += tmp;
220 }
221 return ret * m_NormPt;
222 }
223
224 double BoostInvariantMomentumDistribution::d2ndptdy(double pt, double y) const
225 {
226 double ret = 0.;
227 double mt = sqrt(pt * pt + m_Mass * m_Mass);
228
229 for (size_t i = 0; i < m_xlegeta.size(); i++) {
230 for (size_t j = 0; j < m_xlegT.size(); j++) {
231 double tmp = m_wlegeta[i] * m_wlegT[j] * ZetaIntegrandpTYSingleFireball(m_xlegeta[i], pt, y - m_xlegeta[i]);
232 ret += tmp;
233 }
234 }
235
236 if (!m_useacc) return ret * m_Norm * pt;
237 else return ret * m_Norm * pt * m_acc->getAcceptance(y + m_ycm, pt);
238 }
239
240 double BoostInvariantMomentumDistribution::ZetaIntegrandpTYSingleFireball(double zeta, double pt, double y) const
241 {
242 double R = m_FreezeoutModel->Rfunc(zeta);
243 double tau = m_FreezeoutModel->taufunc(zeta);
244 double dRdZeta = m_FreezeoutModel->dRdZeta(zeta);
245 double dTaudZeta = m_FreezeoutModel->dtaudZeta(zeta);
246 double mT = sqrt(m_Mass * m_Mass + pt * pt);
247 double coshetaperp = m_FreezeoutModel->coshetaperp(zeta);
248 double sinhetaperp = m_FreezeoutModel->sinhetaperp(zeta);
249
250 return R * tau * (mT * dRdZeta * cosh(y) * xMath::BesselI0(pt * sinhetaperp / m_T)
251 - pt * dTaudZeta * xMath::BesselI1(pt * sinhetaperp / m_T)) * exp(-mT * coshetaperp * cosh(y) / m_T);
252 }
253
254 void BoostInvariantMomentumDistribution::Initialize()
255 {
257 NumericalIntegration::GetCoefsIntegrateLegendre32(0., 1., &m_xlegT, &m_wlegT);
258 NumericalIntegration::GetCoefsIntegrateLegendre32(-4., 4., &m_xlegY, &m_wlegY);
259
260 if (m_EtaMax > 0.0)
261 NumericalIntegration::GetCoefsIntegrateLegendre32(-m_EtaMax, m_EtaMax, &m_xlegeta, &m_wlegeta);
262 else {
263 m_xlegeta.resize(1);
264 m_xlegeta[0] = 0.;
265 m_wlegeta.resize(1);
266 m_wlegeta[0] = 1.;
267 }
268 }
269
270 double BoostInvariantMomentumDistribution::dndysingle(double y) const
271 {
272 return m_dndy.f(y);
273 }
274
275 double BoostInvariantMomentumDistribution::dndptsingle(double pt, double y) const
276 {
277 double ret = 0.;
278 double mt = sqrt(pt * pt + m_Mass * m_Mass);
279
280 for (size_t j = 0; j < m_xlegT.size(); j++) {
281 double tmp = m_wlegT[j] * ZetaIntegrandpTYSingleFireball(m_xlegT[j], pt, y);
282 ret += tmp;
283 }
284
285 return ret * pt;
286 }
287
288 double BoostInvariantMomentumDistribution::dndpt(double pt, double y) const
289 {
290 double ret = 0.;
291 double mt = sqrt(pt * pt + m_Mass * m_Mass);
292
293 for (size_t i = 0; i < m_xlegeta.size(); i++) {
294 ret += m_wlegeta[i] * dndptsingle(pt, y - m_xlegeta[i]);
295 }
296
297 return ret * m_Norm * pt;
298 }
299
300} // namespace thermalfist
301
302
304// Deprecated code below
305
306namespace thermalfist {
307 void SSHDistribution::Initialize() {
309 NumericalIntegration::GetCoefsIntegrateLegendre32(0., 1., &m_xlegT, &m_wlegT);
310 NumericalIntegration::GetCoefsIntegrateLegendre32(-4., 4., &m_xlegY, &m_wlegY);
311
312 if (m_EtaMax > 0.0)
313 NumericalIntegration::GetCoefsIntegrateLegendre32(-m_EtaMax, m_EtaMax, &m_xlegeta, &m_wlegeta);
314 else {
315 m_xlegeta.resize(1);
316 m_xlegeta[0] = 0.;
317 m_wlegeta.resize(1);
318 m_wlegeta[0] = 1.;
319 }
320 }
321
322
324 m_Norm = m_NormY = m_NormPt = 1.;
325 double tmp = 0.;
326
328 NumericalIntegration::GetCoefsIntegrateLegendre32(0., 1., &m_xlegT, &m_wlegT);
329 NumericalIntegration::GetCoefsIntegrateLegendre32(-4., 4., &m_xlegY, &m_wlegY);
330
331 if (m_EtaMax > 0.0)
332 NumericalIntegration::GetCoefsIntegrateLegendre32(-m_EtaMax, m_EtaMax, &m_xlegeta, &m_wlegeta);
333 else {
334 m_xlegeta.resize(1);
335 m_xlegeta[0] = 0.;
336 m_wlegeta.resize(1);
337 m_wlegeta[0] = 1.;
338 }
339
340 tmp = 0.;
341 for (size_t i = 0; i < m_xlag.size(); i++) {
342 tmp += m_wlag[i] * dndpt(m_xlag[i] * m_T);
343 }
344 tmp *= m_T;
345 m_NormPt = 1. / tmp;
346
347
348 m_dndy.clearall();
349 m_dndy.add_val(-100., 0.);
350 m_dndyint.clearall();
351 m_dndyint.add_val(-100., 0.);
352 double dy = 0.05;
353 double tmp2 = 0.;
354 for (double yy = -4.; yy < 4.; yy += dy) {
355 tmp = 0.;
356 for (size_t j = 0; j < m_xlag.size(); j++) {
357 tmp += m_wlag[j] * dndptsingle(m_xlag[j] * m_T, yy) * m_T;
358 }
359 tmp2 += tmp * dy;
360 m_dndy.add_val(yy, tmp);
361 m_dndyint.add_val(yy + 0.5 * dy, tmp2);
362 }
363 m_dndy.add_val(100., 0.);
364 m_dndyint.add_val(100., tmp2);
365 tmp = 0.;
366 m_NormY = m_Norm = 1. / tmp2;
367
368 if (m_xlegeta.size() > 1) {
369 m_NormY *= 1. / 2. / m_EtaMax;
370 m_Norm *= 1. / 2. / m_EtaMax;
371 }
372
373 m_Normalized = true;
374 }
375
376
377
378 double SSHDistribution::dndy(double y) const {
379 if (m_xlegeta.size() > 1)
380 return (m_dndyint.f(m_EtaMax + y) - m_dndyint.f(-m_EtaMax + y)) * m_NormY;
381 else
382 return m_dndy.f(y) * m_NormY;
383 }
384
385 double SSHDistribution::dndysingle(double y) const {
386 return m_dndy.f(y);
387 }
388
389 double SSHDistribution::dnmtdmt(double mt) const {
390 double ret = 0.;
391 double pt = sqrt(mt * mt - m_Mass * m_Mass);
392 for (size_t i = 0; i < m_xlegT.size(); i++) {
393 double tmp = m_wlegT[i] * m_xlegT[i] * mt * xMath::BesselI0(pt * sinh(rho(m_xlegT[i])) / m_T) * xMath::BesselK1(mt * cosh(rho(m_xlegT[i])) / m_T);
394 if (tmp != tmp) break;
395 ret += tmp;
396 }
397 return ret * m_NormPt;
398 }
399
400 double SSHDistribution::dndy(double y, double pt) const {
401 double ret = 0.;
402 double mt = sqrt(pt * pt + m_Mass * m_Mass);
403
404 for (size_t i = 0; i < m_xlegeta.size(); i++) {
405 for (size_t j = 0; j < m_xlegT.size(); j++) {
406 double tmp = mt * m_wlegeta[i] * m_wlegT[j] * cosh(y - m_xlegeta[i]) * m_xlegT[j] * exp(-mt * cosh(rho(m_xlegT[j])) * cosh(y - m_xlegeta[i]) / m_T) *
407 xMath::BesselI0(pt * sinh(rho(m_xlegT[j])) / m_T);
408 ret += tmp;
409 }
410 }
411
412 return ret * m_Norm;
413 }
414
415 double SSHDistribution::dndysingle(double y, double pt) const {
416 double ret = 0.;
417 double mt = sqrt(pt * pt + m_Mass * m_Mass);
418
419 for (size_t j = 0; j < m_xlegT.size(); j++) {
420 double tmp = mt * m_wlegT[j] * cosh(y) * m_xlegT[j] * exp(-mt * cosh(rho(m_xlegT[j])) * cosh(y) / m_T) *
421 xMath::BesselI0(pt * sinh(rho(m_xlegT[j])) / m_T);
422 ret += tmp;
423 }
424
425 return ret;
426 }
427
428 double SSHDistribution::dndpt(double pt) const {
429 return pt * dnmtdmt(sqrt(pt * pt + m_Mass * m_Mass));
430 }
431
432 double SSHDistribution::dndpt(double pt, double y) const {
433 double ret = 0.;
434 double mt = sqrt(pt * pt + m_Mass * m_Mass);
435
436 for (size_t i = 0; i < m_xlegeta.size(); i++) {
437 for (size_t j = 0; j < m_xlegT.size(); j++) {
438 double tmp = mt * m_wlegeta[i] * m_wlegT[j] * cosh(y - m_xlegeta[i]) * m_xlegT[j] * exp(-mt * cosh(rho(m_xlegT[j])) * cosh(y - m_xlegeta[i]) / m_T) *
439 xMath::BesselI0(pt * sinh(rho(m_xlegT[j])) / m_T);
440 ret += tmp;
441 }
442 }
443
444 return ret * m_Norm * pt;
445 }
446
447 double SSHDistribution::dndptsingle(double pt, double y) const {
448 double ret = 0.;
449 double mt = sqrt(pt * pt + m_Mass * m_Mass);
450
451 for (size_t j = 0; j < m_xlegT.size(); j++) {
452 double tmp = mt * m_wlegT[j] * cosh(y) * m_xlegT[j] * exp(-mt * cosh(rho(m_xlegT[j])) * cosh(y) / m_T) *
453 xMath::BesselI0(pt * sinh(rho(m_xlegT[j])) / m_T);
454 ret += tmp;
455 }
456
457 return ret * pt;
458 }
459
460 double SSHDistribution::MtAv() const {
461 if (0 && !m_useacc) {
462 double tmp1 = 0., tmp2 = 0.;
463 for (int i = 0; i < 32; i++) {
464 double tmppt = m_xlag[i] * m_T;
465 double tmpmt = sqrt(tmppt * tmppt + m_Mass * m_Mass);
466 double tmp = m_wlag[i] * tmppt * dnmtdmt(tmpmt);
467 tmp1 += tmp * tmpmt;
468 tmp2 += tmp;
469 }
470 return tmp1 / tmp2;
471 }
472 else {
473 std::vector<double> xy, wy;
475 std::vector<double> xpt, wpt;
477 double tmp1 = 0., tmp2 = 0.;
478 for (size_t iy = 0; iy < xy.size(); ++iy) {
479 double ty = xy[iy];
480 for (size_t ipt = 0; ipt < xpt.size(); ++ipt) {
481 double tpt = xpt[ipt] * m_T;
482 double tmp = wy[iy] * wpt[ipt] * d2ndptdy(tpt, ty);
483 if (tmp <= 0. || tmp != tmp) continue;
484 double tmt = sqrt(tpt * tpt + m_Mass * m_Mass);
485 tmp1 += tmp * tmt;
486 tmp2 += tmp;
487 }
488 }
489 return tmp1 / tmp2;
490 }
491 }
492
493 double SSHDistribution::y2Av() const {
494 if (0 && !m_useacc) {
495 double tmp1 = 0., tmp2 = 0.;
496 double dy = 0.05;
497 for (double yy = 0.; yy < 4.; yy += dy) {
498 double tmp = dndysingle(yy);
499 tmp1 += tmp * yy * yy;
500 tmp2 += tmp;
501 }
502 return (tmp1 / tmp2 + m_EtaMax * m_EtaMax / 3.);
503 }
504 else {
505 std::vector<double> xy, wy;
507 std::vector<double> xpt, wpt;
509 double tmp1 = 0., tmp2 = 0.;
510 for (size_t iy = 0; iy < xy.size(); ++iy) {
511 double ty = xy[iy];
512 for (size_t ipt = 0; ipt < xpt.size(); ++ipt) {
513 double tpt = xpt[ipt] * m_T;
514 double tmp = wy[iy] * wpt[ipt] * d2ndptdy(tpt, ty);
515 if (tmp <= 0. || tmp != tmp) continue;
516 //double tmt = sqrt(tpt*tpt + m_Mass * m_Mass);
517 tmp1 += tmp * ty * ty;
518 tmp2 += tmp;
519 }
520 }
521 return tmp1 / tmp2;
522 }
523 }
524
525 double SSHDistribution::d2ndptdy(double pt, double y) const {
526 double ret = 0.;
527 double mt = sqrt(pt * pt + m_Mass * m_Mass);
528
529 for (size_t i = 0; i < m_xlegeta.size(); i++) {
530 for (size_t j = 0; j < m_xlegT.size(); j++) {
531 double tmp = mt * m_wlegeta[i] * m_wlegT[j] * cosh(y - m_xlegeta[i]) * m_xlegT[j] * exp(-mt * cosh(rho(m_xlegT[j])) * cosh(y - m_xlegeta[i]) / m_T) *
532 xMath::BesselI0(pt * sinh(rho(m_xlegT[j])) / m_T);
533 ret += tmp;
534 }
535 }
536
537 if (!m_useacc) return ret * m_Norm * pt;
538 else return ret * m_Norm * pt * m_acc->getAcceptance(y + m_ycm, pt);
539 }
540} // namespace thermalfist
virtual double dndy(double y) const
Distribution density over the longitudinal rapidity.
virtual double ZetaIntegrandpT(double zeta, double pt) const
virtual double dnmtdmt(double mt) const
Transverse mass distribution.
virtual double d2ndptdy(double pt, double y) const
2D distribution density in rapidity and transverse momentum
virtual double ZetaIntegrandpTYSingleFireball(double zeta, double pt, double y) const
void Normalize()
Normalizes the momentum distribution to unity.
bool m_Normalized
Whether the distribution has been normalized to unity.
Acceptance::AcceptanceFunction * m_acc
Pointer to acceptance function.
bool m_useacc
Whether the acceptance functions are used.
double m_ycm
Center-of-mass rapidity for the acceptance function.
virtual double dndpt(double pt) const
The pT distribution function.
virtual double dndysingle(double y, double pt) const
Rapidity distribution of a single fireball at fixed pT.
virtual double dnmtdmt(double mt) const
Transverse mass distribution.
virtual double dndy(double y, double pt) const
Rapidity distribution at fixed pT.
virtual double d2ndptdy(double pt, double y) const
2D distribution density in rapidity and transverse momentum
void Normalize()
Normalizes the momentum distribution to unity.
void Normalize()
Normalizes the momentum distribution to unity.
virtual double dndy(double y) const
Distribution density over the longitudinal rapidity.
virtual double d2ndptdy(double pt, double y) const
2D distribution density in rapidity and transverse momentum
virtual double dndp(double p) const
Distribution density over the absolute value of the 3-momentum.
virtual double dnmtdmt(double mt) const
Transverse mass distribution.
double f(double arg) const
void GetCoefsIntegrateLegendre32(double a, double b, std::vector< double > *x, std::vector< double > *w)
void GetCoefsIntegrateLaguerre32(std::vector< double > *x, std::vector< double > *w)
void GetCoefsIntegrateLegendre40(double a, double b, std::vector< double > *x, std::vector< double > *w)
double BesselI0(double x)
Modified Bessel function I_0(x)
Definition xMath.cpp:23
double BesselK1(double x)
Modified Bessel function K_1(x)
Definition xMath.cpp:127
double BesselI1(double x)
Modified Bessel function I_1(x)
Definition xMath.cpp:91
double BesselK0(double x)
Modified Bessel function K_0(x)
Definition xMath.cpp:55
The main namespace where all classes and functions of the Thermal-FIST library reside.
Definition CosmicEoS.h:9
Contains some extra mathematical functions used in the code.