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) {
69 const double eps = 1.e-3;
71 if ((std::abs(
de_ * ie - e_comp) > eps ||
72 std::abs(
dnb_ * inb - nb_comp) > eps || std::abs(ns_comp) > eps ||
73 std::abs(x.
p - p_comp) > eps) &&
75 std::cout <<
"discrepancy: " <<
de_ * ie <<
" = " << e_comp <<
", " 76 <<
dnb_ * inb <<
" = " << nb_comp <<
", " << x.
p <<
" = " 77 << p_comp <<
", 0 = " << ns_comp << std::endl;
78 table_consistency =
false;
79 goto finish_consistency_check;
84 finish_consistency_check:
86 if (!table_read_success || !table_consistency) {
87 std::cout <<
"Compiling an EoS table..." << std::endl;
88 const double ns = 0.0;
89 for (
size_t ie = 0; ie <
n_e_; ie++) {
90 const double e =
de_ * ie;
91 for (
size_t inb = 0; inb <
n_nb_; inb++) {
92 const double nb =
dnb_ * inb;
100 std::array<double, 3> init_approx;
104 init_approx = {2.0 * x.
T - y.
T, 2.0 * x.
mub - y.
mub,
109 const std::array<double, 3> res = eos.
solve_eos(e, nb, ns, init_approx);
110 const double T = res[0];
111 const double mub = res[1];
112 const double mus = res[2];
117 std::cout <<
"Saving table to file " << eos_savefile_name << std::endl;
119 file.open(eos_savefile_name, std::ios::out);
120 file <<
de_ <<
" " <<
dnb_ << std::endl;
121 file << n_e_ <<
" " <<
n_nb_ << std::endl;
122 file << std::setprecision(7);
124 for (
size_t ie = 0; ie <
n_e_; ie++) {
125 for (
size_t inb = 0; inb <
n_nb_; inb++) {
127 file << x.
p <<
" " << x.
T <<
" " << x.
mub <<
" " << x.
mus << std::endl;
134 const size_t ie =
static_cast<size_t>(std::floor(e /
de_));
135 const size_t inb =
static_cast<size_t>(std::floor(nb /
dnb_));
137 if (ie >=
n_e_ - 1 || inb >=
n_nb_ - 1) {
138 res = {-1.0, -1.0, -1.0, -1.0};
141 const double ae = e /
de_ - ie;
142 const double an = nb /
dnb_ - inb;
147 res.
p = ae * (an * s4.
p + (1.0 - an) * s2.
p) +
148 (1.0 - ae) * (an * s3.
p + (1.0 - an) * s1.
p);
149 res.
T = ae * (an * s4.
T + (1.0 - an) * s2.
T) +
150 (1.0 - ae) * (an * s3.
T + (1.0 - an) * s1.
T);
151 res.
mub = ae * (an * s4.
mub + (1.0 - an) * s2.
mub) +
152 (1.0 - ae) * (an * s3.
mub + (1.0 - an) * s1.
mub);
153 res.
mus = ae * (an * s4.
mus + (1.0 - an) * s2.
mus) +
154 (1.0 - ae) * (an * s3.
mus + (1.0 - an) * s1.
mus);
159 : x_(gsl_vector_alloc(n_equations_)), tabulate_(tabulate) {
160 const gsl_multiroot_fsolver_type *solver_type;
161 solver_type = gsl_multiroot_fsolver_hybrid;
169 gsl_multiroot_fsolver_free(
solver_);
175 double x = mu_over_T - m_over_T;
184 : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
188 double beta,
double mub,
190 const double m_over_T = ptype.
mass() *
beta;
193 const double g = ptype.
spin() + 1;
199 const double m0 = ptype.
mass();
202 const double u_min = std::atan(2.0 * (mth - m0) / w0);
203 const double u_max = 0.5 * M_PI;
205 const double result =
206 g *
integrate(u_min, u_max, [&](
double u) {
209 const double tanu = std::tan(u);
210 const double m = m0 + 0.5 * w0 * tanu;
211 const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
220 double mub,
double mus) {
232 const double beta = 1.0 / T;
238 const double z = ptype.mass() *
beta;
239 double x = beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() -
245 const size_t g = ptype.spin() + 1;
249 (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
250 z * gsl_sf_bessel_K1_scaled(z));
260 const double beta = 1.0 / T;
276 const double beta = 1.0 / T;
293 const double beta = 1.0 / T;
318 const double max_mass = 5.0;
325 const double m0 = ptype.
mass();
327 m0 * m0 * std::exp(-beta * m0) * gsl_sf_bessel_Kn_scaled(2, m0 * beta) *
330 constexpr
int npoints = 31;
331 double m_lower = mth, m_upper = max_mass, m_where_max = m0;
333 for (
size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
334 const double dm = (m_upper - m_lower) / npoints;
335 for (
size_t i = 1; i < npoints; i++) {
336 m = m_lower + dm * i;
337 const double thermal_factor =
338 m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
346 m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
347 m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
356 const double thermal_factor =
357 m * m * std::exp(-beta * m) * gsl_sf_bessel_Kn_scaled(2, m * beta);
362 const auto &log = logger<LogArea::Resonances>();
363 log.warn(ptype.
name(),
" - maximum increased in",
364 " sample_mass_thermal from ", max_ratio,
" to ", q,
366 " previously assumed maximum at m = ", m_where_max);
379 double mus_u = mub + T;
382 size_t iteration = 0;
384 const size_t max_iteration = 50;
386 mus = 0.5 * (mus_u + mus_l);
394 }
while (std::abs(rhos) >
tolerance_ && iteration < max_iteration);
395 if (iteration == max_iteration) {
396 throw std::runtime_error(
"Solving rho_s = 0: too many iterations.");
403 double e =
reinterpret_cast<struct
rparams *
>(params)->e;
404 double nb =
reinterpret_cast<struct
rparams *
>(params)->nb;
405 double ns =
reinterpret_cast<struct
rparams *
>(params)->ns;
407 const double T = gsl_vector_get(x, 0);
408 const double mub = gsl_vector_get(x, 1);
409 const double mus = gsl_vector_get(x, 2);
419 const double edens =
reinterpret_cast<struct
eparams *
>(params)->edens;
427 int degeneracies_sum = 0.0;
430 degeneracies_sum += ptype.spin() + 1;
434 const double T_min = std::pow(e /
prefactor_ / 6 / degeneracies_sum, 1. / 4.);
436 const double T_max = 2.0;
438 struct eparams parameters = {e};
440 const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
441 gsl_root_fsolver *e_solver;
442 e_solver = gsl_root_fsolver_alloc(T);
443 gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
445 int iter = 0, status, max_iter = 100;
450 status = gsl_root_fsolver_iterate(e_solver);
451 if (status != GSL_SUCCESS) {
454 T_init = gsl_root_fsolver_root(e_solver);
455 double x_lo = gsl_root_fsolver_x_lower(e_solver);
456 double x_hi = gsl_root_fsolver_x_upper(e_solver);
457 status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
458 }
while (status == GSL_CONTINUE && iter < max_iter);
460 if (status != GSL_SUCCESS) {
461 std::stringstream err_msg;
462 err_msg <<
"Solver of equation for temperature with e = " << e
463 <<
" failed to converge. Maybe Tmax = " << T_max <<
" is too small?" 465 throw std::runtime_error(gsl_strerror(status) + err_msg.str());
468 gsl_root_fsolver_free(e_solver);
471 double n_only_baryons = 0.0;
477 const double nb_scaled = nb /
prefactor_ / (T_init * T_init * T_init);
478 double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
482 std::array<double, 3> initial_approximation = {T_init, mub_init, 0.0};
483 return initial_approximation;
487 double e,
double nb,
double ns,
488 std::array<double, 3> initial_approximation) {
489 int residual_status = GSL_SUCCESS;
492 struct rparams p = {e, nb, ns};
496 gsl_vector_set(
x_, 0, initial_approximation[0]);
497 gsl_vector_set(
x_, 1, initial_approximation[1]);
498 gsl_vector_set(
x_, 2, initial_approximation[2]);
500 gsl_multiroot_fsolver_set(
solver_, &f,
x_);
503 const auto iterate_status = gsl_multiroot_fsolver_iterate(
solver_);
507 if (gsl_vector_get(
solver_->x, 0) < 0.015) {
508 return {0.0, 0.0, 0.0};
512 if (iterate_status) {
516 }
while (residual_status == GSL_CONTINUE && iter < 1000);
518 if (residual_status != GSL_SUCCESS) {
519 std::stringstream solver_parameters;
520 solver_parameters <<
"Solver run with " 521 <<
"e = " << e <<
", nb = " << nb <<
", ns = " << ns
522 <<
", init. approx.: " << initial_approximation[0] <<
" " 523 << initial_approximation[1] <<
" " 524 << initial_approximation[2] << std::endl;
525 throw std::runtime_error(gsl_strerror(residual_status) +
526 solver_parameters.str() +
530 return {gsl_vector_get(
solver_->x, 0), gsl_vector_get(
solver_->x, 1),
531 gsl_vector_get(
solver_->x, 2)};
537 s <<
"iter = " << iter <<
"," 538 <<
" x = " << gsl_vector_get(
solver_->x, 0) <<
" " 539 << gsl_vector_get(
solver_->x, 1) <<
" " 540 << gsl_vector_get(
solver_->x, 2) <<
", " 541 <<
"f(x) = " << gsl_vector_get(
solver_->f, 0) <<
" " 542 << gsl_vector_get(
solver_->f, 1) <<
" " 543 << gsl_vector_get(
solver_->f, 2) << std::endl;
HadronGasEos(const bool tabulate=false)
Constructor of HadronGasEos.
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...
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
static double net_strange_density(double T, double mub, double mus)
Compute net strangeness density.
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.
static double scaled_partial_density(const ParticleType &ptype, double beta, double mub, double mus)
Compute (unnormalized) density of one hadron sort - helper functions used to reduce code duplication...
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...
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 double net_baryon_density(double T, double mub, double mus)
Compute net baryon density.
static const ParticleTypeList & list_all()
gsl_multiroot_fsolver * solver_
const std::string & name() const
Particle type contains the static properties of a particle species.
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 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.
static double density(double T, double mub, double mus)
Compute particle number density.
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.
static double partial_density(const ParticleType &ptype, double T, double mub, double mus)
Compute partial density of one hadron sort.
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.
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 pressure(double T, double mub, double mus)
Compute pressure .
static Integrator integrate
static double energy_density(double T, double mub, double mus)
Compute energy density.