17 #include "gsl/gsl_sf_bessel.h"
30 : de_(de), dnb_(dnb), dq_(dq), n_e_(n_e), n_nb_(n_nb), n_q_(n_q) {
35 const std::string &eos_savefile_name) {
36 bool table_read_success =
false, table_consistency =
true;
37 if (std::filesystem::exists(eos_savefile_name)) {
38 std::cout <<
"Reading table from file " << eos_savefile_name << std::endl;
40 file.open(eos_savefile_name, std::ios::in);
44 for (
size_t ie = 0; ie <
n_e_; ie++) {
45 for (
size_t inb = 0; inb <
n_nb_; inb++) {
46 for (
size_t iq = 0; iq <
n_q_; iq++) {
47 double p, T, mub, mus, muq;
48 file >>
p >> T >> mub >> mus >> muq;
53 table_read_success =
true;
54 std::cout <<
"Table consumed successfully." << std::endl;
57 if (table_read_success) {
59 std::cout <<
"Checking consistency of the table... " << std::endl;
60 constexpr
size_t number_of_steps = 50;
61 const size_t ie_step = 1 +
n_e_ / number_of_steps;
62 const size_t inb_step = 1 +
n_nb_ / number_of_steps;
63 const size_t iq_step = 1 +
n_q_ / number_of_steps;
64 for (
size_t ie = 0; ie <
n_e_; ie += ie_step) {
65 for (
size_t inb = 0; inb <
n_nb_; inb += inb_step) {
66 for (
size_t iq = 0; iq <
n_q_; iq += iq_step) {
70 const double nb_comp =
72 const double ns_comp =
75 const double nq_comp =
79 const double eps = 1.e-3;
81 if ((std::abs(
de_ * ie - e_comp) > eps ||
82 std::abs(
dnb_ * inb - nb_comp) > eps ||
83 std::abs(ns_comp) > eps || std::abs(x.
p - p_comp) > eps ||
84 std::abs(
dq_ * iq - nq_comp) > eps) &&
86 std::cout <<
"discrepancy: " <<
de_ * ie <<
" = " << e_comp <<
", "
87 <<
dnb_ * inb <<
" = " << nb_comp <<
", " << x.
p <<
" = "
88 << p_comp <<
", 0 = " << ns_comp <<
", " <<
dq_ * iq
89 <<
" = " << nq_comp << std::endl;
90 table_consistency =
false;
91 goto finish_consistency_check;
97 finish_consistency_check:
99 if (!table_read_success || !table_consistency) {
100 std::cout <<
"Compiling an EoS table..." << std::endl;
101 const double ns = 0.0;
102 for (
size_t ie = 0; ie <
n_e_; ie++) {
103 std::cout << ie <<
"/" <<
n_e_ <<
"\r" << std::flush;
104 const double e =
de_ * ie;
105 for (
size_t inb = 0; inb <
n_nb_; inb++) {
106 const double nb =
dnb_ * inb;
107 for (
size_t iq = 0; iq <
n_q_; iq++) {
108 const double q =
dq_ * iq;
111 if (nb >= e || q >= e) {
112 table_[
index(ie, inb, iq)] = {0.0, 0.0, 0.0, 0.0, 0.0};
116 std::array<double, 4> init_approx;
120 init_approx = {2.0 * x.
T - y.
T, 2.0 * x.
mub - y.
mub,
122 }
else if (iq >= 2) {
125 init_approx = {2.0 * x.
T - y.
T, 2.0 * x.
mub - y.
mub,
130 const std::array<double, 4> res =
131 eos.
solve_eos(e, nb, ns, q, init_approx);
132 const double T = res[0];
133 const double mub = res[1];
134 const double mus = res[2];
135 const double muq = res[3];
143 std::cout <<
"Saving table to file " << eos_savefile_name << std::endl;
145 file.open(eos_savefile_name, std::ios::out);
146 file <<
de_ <<
" " <<
dnb_ <<
" " <<
dq_ << std::endl;
148 file << std::setprecision(7);
150 for (
size_t ie = 0; ie <
n_e_; ie++) {
151 for (
size_t inb = 0; inb <
n_nb_; inb++) {
152 for (
size_t iq = 0; iq <
n_q_; iq++) {
154 file << x.
p <<
" " << x.
T <<
" " << x.
mub <<
" " << x.
mus <<
" "
155 << x.
muq << std::endl;
164 const size_t ie =
static_cast<size_t>(std::floor(e /
de_));
165 const size_t inb =
static_cast<size_t>(std::floor(nb /
dnb_));
166 const size_t iq =
static_cast<size_t>(std::floor(q /
dq_));
169 res = {-1.0, -1.0, -1.0, -1.0, -1.0};
172 const double ae = e /
de_ - ie;
173 const double an = nb /
dnb_ - inb;
174 const double aq = q /
dq_ - iq;
185 s5.
p, s6.
p, s7.
p, s8.
p);
187 s5.
T, s6.
T, s7.
T, s8.
T);
201 : x_(gsl_vector_alloc(n_equations_)),
203 account_for_resonance_widths_(account_for_width) {
204 const gsl_multiroot_fsolver_type *solver_type;
205 solver_type = gsl_multiroot_fsolver_hybrid;
209 "Compilation of hadron gas EoS table requested with"
210 " account of resonance spectral functions. This is not "
211 "advised, as it will likely take a few days to finish."
212 " Besides, the effect of resonance widths is currently not "
213 "implemented for energy density computation, so the computed"
214 " table will be inconsistent anyways.");
222 gsl_multiroot_fsolver_free(
solver_);
228 double x = mu_over_T - m_over_T;
237 : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
241 double beta,
double mub,
double mus,
243 bool account_for_width) {
244 const double m_over_T = ptype.
mass() *
beta;
247 const double g = ptype.
spin() + 1;
248 if (ptype.
is_stable() || !account_for_width) {
253 const double m0 = ptype.
mass();
256 const double u_min = std::atan(2.0 * (mth - m0) / w0);
257 const double u_max = 0.5 * M_PI;
259 const double result =
260 g *
integrate(u_min, u_max, [&](
double u) {
263 const double tanu = std::tan(u);
264 const double m = m0 + 0.5 * w0 * tanu;
265 const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
274 double mub,
double mus,
double muq,
275 bool account_for_width) {
289 const double beta = 1.0 / T;
295 const double z = ptype.mass() *
beta;
296 double x =
beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() +
297 muq * ptype.charge() - ptype.mass());
302 const size_t g = ptype.spin() + 1;
306 (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
307 z * gsl_sf_bessel_K1_scaled(z));
314 bool account_for_width) {
318 const double beta = 1.0 / T;
332 double muq,
bool account_for_width) {
336 const double beta = 1.0 / T;
344 ptype.baryon_number();
351 double muq,
bool account_for_width) {
355 const double beta = 1.0 / T;
370 double muq,
bool account_for_width) {
374 const double beta = 1.0 / T;
401 const double max_mass = 5.0;
408 const double m0 = ptype.
mass();
409 double max_ratio = m0 * m0 * std::exp(-
beta * m0) *
410 gsl_sf_bessel_Kn_scaled(2, m0 *
beta) *
414 constexpr
int npoints = 31;
415 double m_lower = mth, m_upper = max_mass, m_where_max = m0;
417 for (
size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
418 const double dm = (m_upper - m_lower) / npoints;
419 for (
size_t i = 1; i < npoints; i++) {
420 m = m_lower + dm * i;
421 const double thermal_factor =
422 m * m * std::exp(-
beta * m) * gsl_sf_bessel_Kn_scaled(2, m *
beta);
430 m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
431 m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
440 const double thermal_factor =
441 m * m * std::exp(-
beta * m) * gsl_sf_bessel_Kn_scaled(2, m *
beta);
447 ptype.
name(),
" - maximum increased in",
448 " sample_mass_thermal from ", max_ratio,
" to ", q,
", mass = ", m,
449 " previously assumed maximum at m = ", m_where_max);
462 double mus_u = mub + T;
465 size_t iteration = 0;
467 const size_t max_iteration = 50;
469 mus = 0.5 * (mus_u + mus_l);
477 }
while (std::abs(rhos) >
tolerance_ && iteration < max_iteration);
478 if (iteration == max_iteration) {
479 throw std::runtime_error(
"Solving rho_s = 0: too many iterations.");
486 double e =
reinterpret_cast<struct
rparams *
>(params)->e;
487 double nb =
reinterpret_cast<struct
rparams *
>(params)->nb;
488 double ns =
reinterpret_cast<struct
rparams *
>(params)->ns;
489 double nq =
reinterpret_cast<struct
rparams *
>(params)->nq;
490 bool w =
reinterpret_cast<struct
rparams *
>(params)->account_for_width;
492 const double T = gsl_vector_get(x, 0);
493 const double mub = gsl_vector_get(x, 1);
494 const double mus = gsl_vector_get(x, 2);
495 const double muq = gsl_vector_get(x, 3);
506 const double edens =
reinterpret_cast<struct
eparams *
>(params)->edens;
515 int degeneracies_sum = 0.0;
518 degeneracies_sum += ptype.spin() + 1;
522 const double T_min = std::pow(e /
prefactor_ / 6 / degeneracies_sum, 1. / 4.);
524 const double T_max = 2.0;
526 struct eparams parameters = {e};
528 const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
529 gsl_root_fsolver *e_solver;
530 e_solver = gsl_root_fsolver_alloc(T);
531 gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
533 int iter = 0, status, max_iter = 100;
538 status = gsl_root_fsolver_iterate(e_solver);
539 if (status != GSL_SUCCESS) {
542 T_init = gsl_root_fsolver_root(e_solver);
543 double x_lo = gsl_root_fsolver_x_lower(e_solver);
544 double x_hi = gsl_root_fsolver_x_upper(e_solver);
545 status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
546 }
while (status == GSL_CONTINUE && iter < max_iter);
548 if (status != GSL_SUCCESS) {
549 std::stringstream err_msg;
550 err_msg <<
"Solver of equation for temperature with e = " << e
551 <<
" failed to converge. Maybe Tmax = " << T_max <<
" is too small?"
553 throw std::runtime_error(gsl_strerror(status) + err_msg.str());
556 gsl_root_fsolver_free(e_solver);
560 double n_only_baryons = 0.0;
567 const double nb_scaled = nb /
prefactor_ / (T_init * T_init * T_init);
568 double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
572 double n_only_charge_1_particles = 0.0;
575 n_only_charge_1_particles +=
579 const double q_scaled = nq /
prefactor_ / (T_init * T_init * T_init);
581 T_init * std::asinh(q_scaled / n_only_charge_1_particles / 2.0);
585 std::array<double, 4> initial_approximation = {T_init, mub_init, 0.0,
587 return initial_approximation;
591 double e,
double nb,
double ns,
double nq,
592 std::array<double, 4> initial_approximation) {
593 int residual_status = GSL_SUCCESS;
600 gsl_vector_set(
x_, 0, initial_approximation[0]);
601 gsl_vector_set(
x_, 1, initial_approximation[1]);
602 gsl_vector_set(
x_, 2, initial_approximation[2]);
603 gsl_vector_set(
x_, 3, initial_approximation[3]);
605 gsl_multiroot_fsolver_set(
solver_, &f,
x_);
608 const auto iterate_status = gsl_multiroot_fsolver_iterate(
solver_);
612 if (gsl_vector_get(
solver_->x, 0) < 0.015) {
613 return {0.0, 0.0, 0.0, 0.0};
617 if (iterate_status) {
621 }
while (residual_status == GSL_CONTINUE && iter < 1000);
623 if (residual_status != GSL_SUCCESS) {
624 std::stringstream solver_parameters;
625 solver_parameters <<
"\nSolver run with "
626 <<
"e = " << e <<
", nb = " << nb <<
", ns = " << ns
628 <<
", init. approx.: " << initial_approximation[0] <<
" "
629 << initial_approximation[1] <<
" "
630 << initial_approximation[2] <<
" "
631 << initial_approximation[3] << std::endl;
636 return {gsl_vector_get(
solver_->x, 0), gsl_vector_get(
solver_->x, 1),
643 s <<
"iter = " << iter <<
","
644 <<
" x = " << gsl_vector_get(
solver_->x, 0) <<
" "
645 << gsl_vector_get(
solver_->x, 1) <<
" "
646 << gsl_vector_get(
solver_->x, 2) <<
", "
647 << gsl_vector_get(
solver_->x, 3) <<
", "
648 <<
"f(x) = " << gsl_vector_get(
solver_->f, 0) <<
" "
649 << gsl_vector_get(
solver_->f, 1) <<
" "
650 << gsl_vector_get(
solver_->f, 2) <<
" "
651 << gsl_vector_get(
solver_->f, 3) << std::endl;
659 double f2,
double f3,
double f4,
double f5,
660 double f6,
double f7,
double f8) {
661 assert(ax >= 0 && ax <= 1);
662 assert(ay >= 0 && ay <= 1);
663 assert(az >= 0 && az <= 1);
664 double res = az * (ax * (ay * f8 + (1.0 - ay) * f6) +
665 (1.0 - ax) * (ay * f7 + (1.0 - ay) * f5)) +
666 (1 - az) * (ax * (ay * f4 + (1.0 - ay) * f2) +
667 (1.0 - ax) * (ay * f3 + (1.0 - ay) * f1));
Guard type that safely disables floating point traps for the scope in which it is placed.
std::vector< table_element > table_
Storage for the tabulated equation of state.
void compile_table(HadronGasEos &eos, const std::string &eos_savefile_name="hadgas_eos.dat")
Computes the actual content of the table (for EosTable description see documentation of the construct...
size_t index(size_t ie, size_t inb, size_t inq) const
proper index in a 1d vector, where the 3d table is stored
double dnb_
Step in net-baryon density.
size_t n_q_
Number of steps in net-charge density.
double de_
Step in energy density.
EosTable(double de, double dnb, double dq, size_t n_e, size_t n_b, size_t n_q)
Sets up a table p/T/muB/mus/muQ versus (e, nb, nq), where e - energy density, nb - net baryon density...
size_t n_e_
Number of steps in energy density.
double dq_
Step in net-charge density.
void get(table_element &res, double e, double nb, double nq) const
Obtain interpolated p/T/muB/muS/muQ from the tabulated equation of state given energy density,...
size_t n_nb_
Number of steps in net-baryon density.
Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included in ...
gsl_multiroot_fsolver * solver_
static double net_charge_density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute net charge density.
static constexpr double prefactor_
Constant factor, that appears in front of many thermodyn. expressions.
static double partial_density(const ParticleType &ptype, double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute partial density of one hadron sort.
static double sample_mass_thermal(const ParticleType &ptype, double beta)
Sample resonance mass in a thermal medium.
std::array< double, 4 > solve_eos(double e, double nb, double ns, double nq, std::array< double, 4 > initial_approximation)
Compute temperature and chemical potentials given energy-, net baryon-, net strangeness- and net char...
static double scaled_partial_density_auxiliary(double m_over_T, double mu_over_T)
Function used to avoid duplications in density calculations.
EosTable eos_table_
EOS Table to be used.
gsl_vector * x_
Variables used by gnu equation solver.
static double mus_net_strangeness0(double T, double mub, double muq)
Compute strangeness chemical potential, requiring that net strangeness = 0.
bool account_for_resonance_widths() const
If resonance spectral functions are taken into account.
static double density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute particle number density.
const bool tabulate_
Create an EoS table or not?
static bool is_eos_particle(const ParticleType &ptype)
Check if a particle belongs to the EoS.
static int set_eos_solver_equations(const gsl_vector *x, void *params, gsl_vector *f)
Interface EoS equations to be solved to gnu library.
std::string print_solver_state(size_t iter) const
Helpful printout, useful for debugging if gnu equation solving goes crazy.
static double e_equation(double T, void *params)
static double net_baryon_density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute net baryon density.
static double energy_density(double T, double mub, double mus, double muq)
Compute energy density.
static double net_strange_density(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute net strangeness density.
const bool account_for_resonance_widths_
Use pole masses of resonances or integrate over spectral functions.
std::array< double, 4 > solve_eos_initial_approximation(double e, double nb, double nq)
Compute a reasonable initial approximation for solve_eos.
static constexpr size_t n_equations_
Number of equations in the system of equations to be solved.
HadronGasEos(bool tabulate, bool account_for_widths)
Constructor of HadronGasEos.
static double pressure(double T, double mub, double mus, double muq, bool account_for_resonance_widths=false)
Compute pressure .
static constexpr double tolerance_
Precision of equation solving.
static double scaled_partial_density(const ParticleType &ptype, double beta, double mub, double mus, double muq, bool account_for_width=false)
Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication.
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions.
Particle type contains the static properties of a particle species.
double min_mass_spectral() const
The minimum mass of the resonance, where the spectral function is non-zero.
double breit_wigner_spectral_function(double m) const
This one is the most simple form of the spectral function, using a Cauchy distribution (non-relativis...
double full_spectral_function(double m) const
Full spectral function of the resonance (relativistic Breit-Wigner distribution with mass-dependent ...
const std::string & name() const
int32_t charge() const
The charge of the particle.
static const ParticleTypeList & list_all()
double width_at_pole() const
unsigned int spin() const
int baryon_number() const
Collection of useful constants that are known at compile time.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > & logg
An array that stores all pre-configured Logger objects.
double interpolate_trilinear(double ax, double ay, double az, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8)
Perform a trilinear 1st order interpolation.
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
T cauchy(T pole, T width, T min, T max)
Draws a random number from a Cauchy distribution (sometimes also called Lorentz or non-relativistic B...
static Integrator integrate
static constexpr int LResonances
constexpr double really_small
Numerical error tolerance.
Define the data structure for one element of the table.
double mub
Net baryochemical potential.
double muq
Net charge chemical potential.
double mus
Net strangeness potential.
Another structure for passing energy density to the gnu library.
A structure for passing equation parameters to the gnu library.