10 #include <gsl/gsl_sf_bessel.h>
16 #include <boost/filesystem.hpp>
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 (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 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;
198 : x_(gsl_vector_alloc(n_equations_)),
200 account_for_resonance_widths_(account_for_width) {
201 const gsl_multiroot_fsolver_type *solver_type;
202 solver_type = gsl_multiroot_fsolver_hybrid;
206 "Compilation of hadron gas EoS table requested with"
207 " account of resonance spectral functions. This is not "
208 "advised, as it will likely take a few days to finish."
209 " Besides, the effect of resonance widths is currently not "
210 "implemented for energy density computation, so the computed"
211 " table will be inconsistent anyways.");
219 gsl_multiroot_fsolver_free(
solver_);
225 double x = mu_over_T - m_over_T;
234 : m_over_T * m_over_T * x * gsl_sf_bessel_Kn_scaled(2, m_over_T);
238 double beta,
double mub,
double mus,
240 bool account_for_width) {
241 const double m_over_T = ptype.
mass() *
beta;
244 const double g = ptype.
spin() + 1;
245 if (ptype.
is_stable() || !account_for_width) {
250 const double m0 = ptype.
mass();
253 const double u_min = std::atan(2.0 * (mth - m0) / w0);
254 const double u_max = 0.5 * M_PI;
256 const double result =
257 g *
integrate(u_min, u_max, [&](
double u) {
260 const double tanu = std::tan(u);
261 const double m = m0 + 0.5 * w0 * tanu;
262 const double jacobian = 0.5 * w0 * (1.0 + tanu * tanu);
271 double mub,
double mus,
double muq,
272 bool account_for_width) {
286 const double beta = 1.0 / T;
292 const double z = ptype.mass() *
beta;
293 double x =
beta * (mub * ptype.baryon_number() + mus * ptype.strangeness() +
294 muq * ptype.charge() - ptype.mass());
299 const size_t g = ptype.spin() + 1;
303 (3.0 * gsl_sf_bessel_Kn_scaled(2, z) +
304 z * gsl_sf_bessel_K1_scaled(z));
311 bool account_for_width) {
315 const double beta = 1.0 / T;
329 double muq,
bool account_for_width) {
333 const double beta = 1.0 / T;
341 ptype.baryon_number();
348 double muq,
bool account_for_width) {
352 const double beta = 1.0 / T;
367 double muq,
bool account_for_width) {
371 const double beta = 1.0 / T;
398 const double max_mass = 5.0;
405 const double m0 = ptype.
mass();
407 m0 * m0 * std::exp(-
beta * m0) * gsl_sf_bessel_Kn_scaled(2, m0 *
beta) *
410 constexpr
int npoints = 31;
411 double m_lower = mth, m_upper = max_mass, m_where_max = m0;
413 for (
size_t n_iterations = 0; n_iterations < 2; n_iterations++) {
414 const double dm = (m_upper - m_lower) / npoints;
415 for (
size_t i = 1; i < npoints; i++) {
416 m = m_lower + dm * i;
417 const double thermal_factor =
418 m * m * std::exp(-
beta * m) * gsl_sf_bessel_Kn_scaled(2, m *
beta);
426 m_lower = m_where_max - (m_where_max - m_lower) * 0.1;
427 m_upper = m_where_max + (m_upper - m_where_max) * 0.1;
436 const double thermal_factor =
437 m * m * std::exp(-
beta * m) * gsl_sf_bessel_Kn_scaled(2, m *
beta);
443 ptype.
name(),
" - maximum increased in",
444 " sample_mass_thermal from ", max_ratio,
" to ", q,
", mass = ", m,
445 " previously assumed maximum at m = ", m_where_max);
458 double mus_u = mub + T;
461 size_t iteration = 0;
463 const size_t max_iteration = 50;
465 mus = 0.5 * (mus_u + mus_l);
473 }
while (std::abs(rhos) >
tolerance_ && iteration < max_iteration);
474 if (iteration == max_iteration) {
475 throw std::runtime_error(
"Solving rho_s = 0: too many iterations.");
482 double e =
reinterpret_cast<struct
rparams *
>(params)->e;
483 double nb =
reinterpret_cast<struct
rparams *
>(params)->nb;
484 double ns =
reinterpret_cast<struct
rparams *
>(params)->ns;
485 double nq =
reinterpret_cast<struct
rparams *
>(params)->nq;
486 bool w =
reinterpret_cast<struct
rparams *
>(params)->account_for_width;
488 const double T = gsl_vector_get(x, 0);
489 const double mub = gsl_vector_get(x, 1);
490 const double mus = gsl_vector_get(x, 2);
491 const double muq = gsl_vector_get(x, 3);
502 const double edens =
reinterpret_cast<struct
eparams *
>(params)->edens;
511 int degeneracies_sum = 0.0;
514 degeneracies_sum += ptype.spin() + 1;
518 const double T_min = std::pow(e /
prefactor_ / 6 / degeneracies_sum, 1. / 4.);
520 const double T_max = 2.0;
522 struct eparams parameters = {e};
524 const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
525 gsl_root_fsolver *e_solver;
526 e_solver = gsl_root_fsolver_alloc(T);
527 gsl_root_fsolver_set(e_solver, &F, T_min, T_max);
529 int iter = 0, status, max_iter = 100;
534 status = gsl_root_fsolver_iterate(e_solver);
535 if (status != GSL_SUCCESS) {
538 T_init = gsl_root_fsolver_root(e_solver);
539 double x_lo = gsl_root_fsolver_x_lower(e_solver);
540 double x_hi = gsl_root_fsolver_x_upper(e_solver);
541 status = gsl_root_test_interval(x_lo, x_hi, 0.0, 0.001);
542 }
while (status == GSL_CONTINUE && iter < max_iter);
544 if (status != GSL_SUCCESS) {
545 std::stringstream err_msg;
546 err_msg <<
"Solver of equation for temperature with e = " << e
547 <<
" failed to converge. Maybe Tmax = " << T_max <<
" is too small?"
549 throw std::runtime_error(gsl_strerror(status) + err_msg.str());
552 gsl_root_fsolver_free(e_solver);
556 double n_only_baryons = 0.0;
563 const double nb_scaled = nb /
prefactor_ / (T_init * T_init * T_init);
564 double mub_init = T_init * std::asinh(nb_scaled / n_only_baryons / 2.0);
568 double n_only_charge_1_particles = 0.0;
571 n_only_charge_1_particles +=
575 const double q_scaled = nq /
prefactor_ / (T_init * T_init * T_init);
577 T_init * std::asinh(q_scaled / n_only_charge_1_particles / 2.0);
581 std::array<double, 4> initial_approximation = {T_init, mub_init, 0.0,
583 return initial_approximation;
587 double e,
double nb,
double ns,
double nq,
588 std::array<double, 4> initial_approximation) {
589 int residual_status = GSL_SUCCESS;
596 gsl_vector_set(
x_, 0, initial_approximation[0]);
597 gsl_vector_set(
x_, 1, initial_approximation[1]);
598 gsl_vector_set(
x_, 2, initial_approximation[2]);
599 gsl_vector_set(
x_, 3, initial_approximation[3]);
601 gsl_multiroot_fsolver_set(
solver_, &f,
x_);
604 const auto iterate_status = gsl_multiroot_fsolver_iterate(
solver_);
608 if (gsl_vector_get(
solver_->x, 0) < 0.015) {
609 return {0.0, 0.0, 0.0, 0.0};
613 if (iterate_status) {
617 }
while (residual_status == GSL_CONTINUE && iter < 1000);
619 if (residual_status != GSL_SUCCESS) {
620 std::stringstream solver_parameters;
621 solver_parameters <<
"\nSolver run with "
622 <<
"e = " << e <<
", nb = " << nb <<
", ns = " << ns
624 <<
", init. approx.: " << initial_approximation[0] <<
" "
625 << initial_approximation[1] <<
" "
626 << initial_approximation[2] <<
" "
627 << initial_approximation[3] << std::endl;
632 return {gsl_vector_get(
solver_->x, 0), gsl_vector_get(
solver_->x, 1),
639 s <<
"iter = " << iter <<
","
640 <<
" x = " << gsl_vector_get(
solver_->x, 0) <<
" "
641 << gsl_vector_get(
solver_->x, 1) <<
" "
642 << gsl_vector_get(
solver_->x, 2) <<
", "
643 << gsl_vector_get(
solver_->x, 3) <<
", "
644 <<
"f(x) = " << gsl_vector_get(
solver_->f, 0) <<
" "
645 << gsl_vector_get(
solver_->f, 1) <<
" "
646 << gsl_vector_get(
solver_->f, 2) <<
" "
647 << gsl_vector_get(
solver_->f, 3) << std::endl;