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;