10 #include <gsl/gsl_sf_bessel.h> 16 #include <boost/filesystem.hpp> 30 : de_(de), dnb_(dnb), n_e_(n_e), n_nb_(n_nb) {
35 const std::string &eos_savefile_name) {
36 bool table_read_success =
false, table_consistency =
true;
37 if (boost::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 double p, T, mub, mus;
47 file >> p >> T >> mub >> mus;
51 table_read_success =
true;
52 std::cout <<
"Table consumed successfully." << std::endl;
55 if (table_read_success) {
57 std::cout <<
"Checking consistency of the table... " << std::endl;
58 constexpr
size_t number_of_steps = 50;
59 const size_t ie_step = 1 +
n_e_ / number_of_steps;
60 const size_t inb_step = 1 +
n_nb_ / number_of_steps;
61 for (
size_t ie = 0; ie <
n_e_; ie += ie_step) {
62 for (
size_t inb = 0; inb <
n_nb_; inb += inb_step) {
70 const double eps = 1.e-3;
72 if ((std::abs(
de_ * ie - e_comp) > eps ||
73 std::abs(
dnb_ * inb - nb_comp) > eps || std::abs(ns_comp) > eps ||
74 std::abs(x.
p - p_comp) > eps) &&
76 std::cout <<
"discrepancy: " <<
de_ * ie <<
" = " << e_comp <<
", " 77 <<
dnb_ * inb <<
" = " << nb_comp <<
", " << x.
p <<
" = " 78 << p_comp <<
", 0 = " << ns_comp << std::endl;
79 table_consistency =
false;
80 goto finish_consistency_check;
85 finish_consistency_check:
87 if (!table_read_success || !table_consistency) {
88 std::cout <<
"Compiling an EoS table..." << std::endl;
89 const double ns = 0.0;
90 for (
size_t ie = 0; ie <
n_e_; ie++) {
91 std::cout << ie <<
"/" << n_e_ <<
"\r" << std::flush;
92 const double e =
de_ * ie;
93 for (
size_t inb = 0; inb <
n_nb_; inb++) {
94 const double nb =
dnb_ * inb;
102 std::array<double, 3> init_approx;
106 init_approx = {2.0 * x.
T - y.
T, 2.0 * x.
mub - y.
mub,
111 const std::array<double, 3> res = eos.
solve_eos(e, nb, ns, init_approx);
112 const double T = res[0];
113 const double mub = res[1];
114 const double mus = res[2];
120 std::cout <<
"Saving table to file " << eos_savefile_name << std::endl;
122 file.open(eos_savefile_name, std::ios::out);
123 file <<
de_ <<
" " <<
dnb_ << std::endl;
124 file << n_e_ <<
" " <<
n_nb_ << std::endl;
125 file << std::setprecision(7);
127 for (
size_t ie = 0; ie <
n_e_; ie++) {
128 for (
size_t inb = 0; inb <
n_nb_; inb++) {
130 file << x.
p <<
" " << x.
T <<
" " << x.
mub <<
" " << x.
mus << std::endl;
137 const size_t ie =
static_cast<size_t>(std::floor(e /
de_));
138 const size_t inb =
static_cast<size_t>(std::floor(nb /
dnb_));
140 if (ie >=
n_e_ - 1 || inb >=
n_nb_ - 1) {
141 res = {-1.0, -1.0, -1.0, -1.0};
144 const double ae = e /
de_ - ie;
145 const double an = nb /
dnb_ - inb;
150 res.
p = ae * (an * s4.
p + (1.0 - an) * s2.
p) +
151 (1.0 - ae) * (an * s3.
p + (1.0 - an) * s1.
p);
152 res.
T = ae * (an * s4.
T + (1.0 - an) * s2.
T) +
153 (1.0 - ae) * (an * s3.
T + (1.0 - an) * s1.
T);
154 res.
mub = ae * (an * s4.
mub + (1.0 - an) * s2.
mub) +
155 (1.0 - ae) * (an * s3.
mub + (1.0 - an) * s1.
mub);
156 res.
mus = ae * (an * s4.
mus + (1.0 - an) * s2.
mus) +
157 (1.0 - ae) * (an * s3.
mus + (1.0 - an) * s1.
mus);
162 : x_(gsl_vector_alloc(n_equations_)),
164 account_for_resonance_widths_(account_for_width) {
165 const gsl_multiroot_fsolver_type *solver_type;
166 solver_type = gsl_multiroot_fsolver_hybrid;
169 const auto &log = logger<LogArea::Resonances>();
171 "Compilation of hadron gas EoS table requested with" 172 " account of resonance spectral functions. This is not " 173 "advised, as it will likely take a few days to finish." 174 " Besides, the effect of resonance widths is currently not " 175 "implemented for energy density computation, so the computed" 176 " table will be inconsistent anyways.");
184 gsl_multiroot_fsolver_free(
solver_);
190 double x = mu_over_T - m_over_T;
199 : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
203 double beta,
double mub,
double mus,
204 bool account_for_width) {
205 const double m_over_T = ptype.
mass() *
beta;
208 const double g = ptype.
spin() + 1;
209 if (ptype.
is_stable() || !account_for_width) {
214 const double m0 = ptype.
mass();
217 const double u_min = std::atan(2.0 * (mth - m0) / w0);
218 const double u_max = 0.5 * M_PI;
220 const double result =
221 g *
integrate(u_min, u_max, [&](
double u) {
224 const double tanu = std::tan(u);
225 const double m = m0 + 0.5 * w0 * tanu;
226 const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
235 double mub,
double mus,
236 bool account_for_width) {
248 const double beta = 1.0 / T;
254 const double z = ptype.mass() *
beta;
255 double x = beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() -
261 const size_t g = ptype.spin() + 1;
265 (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
266 z * gsl_sf_bessel_K1_scaled(z));
273 bool account_for_width) {
277 const double beta = 1.0 / T;
290 bool account_for_width) {
294 const double beta = 1.0 / T;
301 ptype.baryon_number();
308 bool account_for_width) {
312 const double beta = 1.0 / T;
338 const double max_mass = 5.0;
345 const double m0 = ptype.
mass();
347 m0 * m0 * std::exp(-beta * m0) * gsl_sf_bessel_Kn_scaled(2, m0 * beta) *
350 constexpr
int npoints = 31;
351 double m_lower = mth, m_upper = max_mass, m_where_max = m0;
353 for (
size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
354 const double dm = (m_upper - m_lower) / npoints;
355 for (
size_t i = 1; i < npoints; i++) {
356 m = m_lower + dm * i;
357 const double thermal_factor =
358 m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
366 m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
367 m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
376 const double thermal_factor =
377 m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
382 const auto &log = logger<LogArea::Resonances>();
383 log.warn(ptype.
name(),
" - maximum increased in",
384 " sample_mass_thermal from ", max_ratio,
" to ", q,
386 " previously assumed maximum at m = ", m_where_max);
399 double mus_u = mub + T;
402 size_t iteration = 0;
404 const size_t max_iteration = 50;
406 mus = 0.5 * (mus_u + mus_l);
414 }
while (std::abs(rhos) >
tolerance_ && iteration < max_iteration);
415 if (iteration == max_iteration) {
416 throw std::runtime_error(
"Solving rho_s = 0: too many iterations.");
423 double e =
reinterpret_cast<struct
rparams *
>(params)->e;
424 double nb =
reinterpret_cast<struct
rparams *
>(params)->nb;
425 double ns =
reinterpret_cast<struct
rparams *
>(params)->ns;
426 bool w =
reinterpret_cast<struct
rparams *
>(params)->account_for_width;
428 const double T = gsl_vector_get(x, 0);
429 const double mub = gsl_vector_get(x, 1);
430 const double mus = gsl_vector_get(x, 2);
440 const double edens =
reinterpret_cast<struct
eparams *
>(params)->edens;
448 int degeneracies_sum = 0.0;
451 degeneracies_sum += ptype.spin() + 1;
455 const double T_min = std::pow(e /
prefactor_ / 6 / degeneracies_sum, 1. / 4.);
457 const double T_max = 2.0;
459 struct eparams parameters = {e};
461 const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
462 gsl_root_fsolver *e_solver;
463 e_solver = gsl_root_fsolver_alloc(T);
464 gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
466 int iter = 0, status, max_iter = 100;
471 status = gsl_root_fsolver_iterate(e_solver);
472 if (status != GSL_SUCCESS) {
475 T_init = gsl_root_fsolver_root(e_solver);
476 double x_lo = gsl_root_fsolver_x_lower(e_solver);
477 double x_hi = gsl_root_fsolver_x_upper(e_solver);
478 status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
479 }
while (status == GSL_CONTINUE && iter < max_iter);
481 if (status != GSL_SUCCESS) {
482 std::stringstream err_msg;
483 err_msg <<
"Solver of equation for temperature with e = " << e
484 <<
" failed to converge. Maybe Tmax = " << T_max <<
" is too small?" 486 throw std::runtime_error(gsl_strerror(status) + err_msg.str());
489 gsl_root_fsolver_free(e_solver);
492 double n_only_baryons = 0.0;
498 const double nb_scaled = nb /
prefactor_ / (T_init * T_init * T_init);
499 double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
503 std::array<double, 3> initial_approximation = {T_init, mub_init, 0.0};
504 return initial_approximation;
508 double e,
double nb,
double ns,
509 std::array<double, 3> initial_approximation) {
510 int residual_status = GSL_SUCCESS;
517 gsl_vector_set(
x_, 0, initial_approximation[0]);
518 gsl_vector_set(
x_, 1, initial_approximation[1]);
519 gsl_vector_set(
x_, 2, initial_approximation[2]);
521 gsl_multiroot_fsolver_set(
solver_, &f,
x_);
524 const auto iterate_status = gsl_multiroot_fsolver_iterate(
solver_);
528 if (gsl_vector_get(
solver_->x, 0) < 0.015) {
529 return {0.0, 0.0, 0.0};
533 if (iterate_status) {
537 }
while (residual_status == GSL_CONTINUE && iter < 1000);
539 if (residual_status != GSL_SUCCESS) {
540 std::stringstream solver_parameters;
541 solver_parameters <<
"\nSolver run with " 542 <<
"e = " << e <<
", nb = " << nb <<
", ns = " << ns
543 <<
", init. approx.: " << initial_approximation[0] <<
" " 544 << initial_approximation[1] <<
" " 545 << initial_approximation[2] << std::endl;
546 const auto &log = logger<LogArea::HadronGasEos>();
547 log.warn(gsl_strerror(residual_status) + solver_parameters.str() +
551 return {gsl_vector_get(
solver_->x, 0), gsl_vector_get(
solver_->x, 1),
552 gsl_vector_get(
solver_->x, 2)};
558 s <<
"iter = " << iter <<
"," 559 <<
" x = " << gsl_vector_get(
solver_->x, 0) <<
" " 560 << gsl_vector_get(
solver_->x, 1) <<
" " 561 << gsl_vector_get(
solver_->x, 2) <<
", " 562 <<
"f(x) = " << gsl_vector_get(
solver_->f, 0) <<
" " 563 << gsl_vector_get(
solver_->f, 1) <<
" " 564 << gsl_vector_get(
solver_->f, 2) << std::endl;
static double net_baryon_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net baryon density.
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...
static double scaled_partial_density(const ParticleType &ptype, double beta, double mub, double mus, bool account_for_width=false)
Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication...
constexpr double really_small
Numerical error tolerance.
double mub
Net baryochemical potential.
std::array< double, 3 > solve_eos(double e, double nb, double ns, std::array< double, 3 > initial_approximation)
Compute temperature and chemical potentials given energy-, net baryon-, net strangeness density and a...
int baryon_number() const
Class to handle the equation of state (EoS) of the hadron gas, consisting of all hadrons included int...
Guard type that safely disables floating point traps for the scope in which it is placed...
Collection of useful constants that are known at compile time.
static int set_eos_solver_equations(const gsl_vector *x, void *params, gsl_vector *f)
Interface EoS equations to be solved to gnu library.
double mus
Net strangeness potential.
std::string print_solver_state(size_t iter) const
Helpful printout, useful for debugging if gnu equation solving goes crazy.
double dnb_
Step in net-baryon density.
double spectral_function(double m) const
Full spectral function of the resonance (relativistic Breit-Wigner distribution with mass-dependent ...
static constexpr size_t n_equations_
Number of equations in the system of equations to be solved.
EosTable(double de, double dnb, size_t n_e, size_t n_b)
Sets up a table p/T/muB/mus versus (e, nb), where e is energy density, nb is net baryon density...
static bool is_eos_particle(const ParticleType &ptype)
Check if a particle belongs to the EoS.
void get(table_element &res, double e, double nb) const
Obtain interpolated p/T/muB/muS from the tabulated equation of state given energy density and net bar...
static double density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute particle number density.
static double partial_density(const ParticleType &ptype, double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute partial density of one hadron sort.
EosTable eos_table_
EOS Table to be used.
static constexpr double prefactor_
Constant factor, that appears in front of many thermodyn. expressions.
size_t n_nb_
Number of steos in net-baryon density.
static constexpr double tolerance_
Precision of equation solving.
size_t n_e_
Number of steps in energy density.
static const ParticleTypeList & list_all()
gsl_multiroot_fsolver * solver_
const bool account_for_resonance_widths_
Use pole masses of resonances or integrate over spectral functions.
const std::string & name() const
Particle type contains the static properties of a particle species.
HadronGasEos(bool tabulate, bool account_for_widths)
Constructor of HadronGasEos.
A structure for passing equation parameters to the gnu library.
double min_mass_spectral() const
The minimum mass of the resonance, where the spectral function is non-zero.
size_t index(size_t ie, size_t inb) const
proper index in a 1d vector, where the 2d table is stored
static double pressure(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute pressure .
static double sample_mass_thermal(const ParticleType &ptype, double beta)
Sample resonance mass in a thermal medium.
Define the data structure for one element of the table.
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...
std::array< double, 3 > solve_eos_initial_approximation(double e, double nb)
Compute a reasonable initial approximation for solve_eos.
gsl_vector * x_
Variables used by gnu equation solver.
double width_at_pole() const
A C++ interface for numerical integration in one dimension with the GSL CQUAD integration functions...
const bool tabulate_
Create an EoS table or not?
Another structure for passing energy density to the gnu library.
static double mus_net_strangeness0(double T, double mub)
Compute strangeness chemical potential, requiring that net strangeness = 0.
static double scaled_partial_density_auxiliary(double m_over_T, double mu_over_T)
Function used to avoid duplications in density calculations.
bool account_for_resonance_widths() const
If resonance spectral functions are taken into account.
double de_
Step in energy density.
std::vector< table_element > table_
Storage for the tabulated equation of state.
double spectral_function_simple(double m) const
This one is the most simple form of the spectral function, using a Cauchy distribution (non-relativis...
static double e_equation(double T, void *params)
unsigned int spin() const
T beta(T a, T b)
Draws a random number from a beta-distribution, where probability density of is .
static double net_strange_density(double T, double mub, double mus, bool account_for_resonance_widths=false)
Compute net strangeness density.
static Integrator integrate
static double energy_density(double T, double mub, double mus)
Compute energy density.