feat(eos): added helmholtz eos as module

Aaron Dotter implimented a C++ version of Frank Timmes' fortran code helmholtz.f90. I have taken that and refactored it to work in the 4DSEE code style. This has mostly involved some light moving of stuff around. The biggest change is removing all globals, and reorienting memory to be heap allocated and contiguous. This is because there was too much memory being stack allocated.
This commit is contained in:
2025-03-05 16:59:04 -05:00
parent e43caf3027
commit 154004c8ca
4 changed files with 1205 additions and 865 deletions

359
src/eos/public/helm.h Normal file
View File

@@ -0,0 +1,359 @@
// this file contains a C++ conversion of Frank Timmes' fortran code
// helmholtz.f90, which implements the Helmholtz Free Energy EOS described
// by Timmes & Swesty (2000) doi:10.1086/313304 -- Aaron Dotter 2025
#ifndef HELM_H
#define HELM_H
#define IMAX 541
#define JMAX 201
#include <array>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
/**
* @brief 2D array template alias.
* @tparam T Type of the array elements.
* @tparam J Number of columns.
* @tparam I Number of rows.
*/
template <typename T, std::size_t J, std::size_t I>
using array2D = std::array<std::array<T, J>, I>;
double** heap_allocate_contiguous_2D_memory(int rows, int cols);
void heap_deallocate_contiguous_2D_memory(double **array);
namespace helmholtz
{
const double tlo = 3.0, thi = 13.0;
const double dlo = -12.0, dhi = 15.0;
const double tstp = (thi - tlo) / (JMAX - 1), tstpi = 1 / tstp;
const double dstp = (dhi - dlo) / (IMAX - 1), dstpi = 1 / dstp;
/**
* @struct HELMTable
* @brief Structure to hold the Helmholtz EOS table data.
*/
struct HELMTable
{
bool loaded = false;
const int imax = IMAX, jmax = JMAX;
double t[JMAX], d[IMAX];
double** f;
double** fd;
double** ft;
double** fdd;
double** ftt;
double** fdt;
double** fddt;
double** fdtt;
double** fddtt;
double** dpdf;
double** dpdfd;
double** dpdft;
double** dpdfdt;
double** ef;
double** efd;
double** eft;
double** efdt;
double** xf;
double** xfd;
double** xft;
double** xfdt;
double dt_sav[JMAX], dt2_sav[JMAX], dti_sav[JMAX], dt2i_sav[JMAX];
double dd_sav[IMAX], dd2_sav[IMAX], ddi_sav[IMAX];
// Constructor
HELMTable() {
f = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
fd = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
ft = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
fdd = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
ftt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
fdt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
fddt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
fdtt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
fddtt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
dpdf = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
dpdfd = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
dpdft = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
dpdfdt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
ef = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
efd = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
eft = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
efdt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
xf = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
xfd = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
xft = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
xfdt = heap_allocate_contiguous_2D_memory(IMAX, JMAX);
}
// Destructor
~HELMTable() {
heap_deallocate_contiguous_2D_memory(f);
heap_deallocate_contiguous_2D_memory(fd);
heap_deallocate_contiguous_2D_memory(ft);
heap_deallocate_contiguous_2D_memory(fdd);
heap_deallocate_contiguous_2D_memory(ftt);
heap_deallocate_contiguous_2D_memory(fdt);
heap_deallocate_contiguous_2D_memory(fddt);
heap_deallocate_contiguous_2D_memory(fdtt);
heap_deallocate_contiguous_2D_memory(fddtt);
heap_deallocate_contiguous_2D_memory(dpdf);
heap_deallocate_contiguous_2D_memory(dpdfd);
heap_deallocate_contiguous_2D_memory(dpdft);
heap_deallocate_contiguous_2D_memory(dpdfdt);
heap_deallocate_contiguous_2D_memory(ef);
heap_deallocate_contiguous_2D_memory(efd);
heap_deallocate_contiguous_2D_memory(eft);
heap_deallocate_contiguous_2D_memory(efdt);
heap_deallocate_contiguous_2D_memory(xf);
heap_deallocate_contiguous_2D_memory(xfd);
heap_deallocate_contiguous_2D_memory(xft);
heap_deallocate_contiguous_2D_memory(xfdt);
}
friend std::ostream& operator<<(std::ostream& os, const helmholtz::HELMTable& table) {
if (!table.loaded) {
os << "HELMTable not loaded\n";
return os;
}
double tMin = std::numeric_limits<double>::max(), tMax = std::numeric_limits<double>::lowest();
double dMin = std::numeric_limits<double>::max(), dMax = std::numeric_limits<double>::lowest();
for (const auto& temp : table.t) {
if (temp < tMin) tMin = temp;
if (temp > tMax) tMax = temp;
}
for (const auto& dens : table.d) {
if (dens < dMin) dMin = dens;
if (dens > dMax) dMax = dens;
}
os << "HELMTable Data:\n";
os << " imax: " << table.imax << ", jmax: " << table.jmax << "\n";
os << " Temperature Range: [" << tMin << ", " << tMax << "]\n";
os << " Density Range: [" << dMin << ", " << dMax << "]\n";
return os;
}
};
/**
* @struct EOSInput
* @brief Structure to hold the input parameters for the EOS calculation.
*/
struct EOSInput
{
double T; ///< Temperature.
double rho; ///< Density.
double abar; ///< Mean atomic mass.
double zbar; ///< Mean atomic number.
friend std::ostream& operator<<(std::ostream& os, const helmholtz::EOSInput& eosInput) {
os << "EOSInput Data:\n";
os << " Temperature: " << eosInput.T << "\n";
os << " Density: " << eosInput.rho << "\n";
os << " Mean Atomic Mass: " << eosInput.abar << "\n";
os << " Mean Atomic Number: " << eosInput.zbar << "\n";
return os;
}
};
/**
* @struct EOS
* @brief Structure to hold the output parameters and derivatives of the EOS calculation.
*/
struct EOS
{
// output
double ye, etaele, xnefer; //
double ptot, pgas, prad; // pressure
double etot, egas, erad; // energy
double stot, sgas, srad; // entropy
// derivatives
double dpresdd, dpresdt, dpresda, dpresdz;
double dentrdd, dentrdt, dentrda, dentrdz;
double denerdd, denerdt, denerda, denerdz;
// these could become functions:
double chiT, chiRho, csound, grad_ad; // derived quantities
double gamma1, gamma2, gamma3, cV, cP; // derived quantities
double dse, dpe, dsp; // Maxwell relations
friend std::ostream& operator<<(std::ostream& os, const helmholtz::EOS& eos) {
os << "EOS Data:\n" << std::setw(20) << std::left;
os << " Electron Fraction: " << eos.ye << "\n";
os << " Electron Chemical Potential: " << eos.etaele << "\n";
os << " Electron Number Density: " << eos.xnefer << "\n";
os << " Total Pressure: " << eos.ptot << "\n";
os << " Gas Pressure: " << eos.pgas << "\n";
os << " Radiation Pressure: " << eos.prad << "\n";
os << " Total Energy: " << eos.etot << "\n";
os << " Gas Energy: " << eos.egas << "\n";
os << " Radiation Energy: " << eos.erad << "\n";
os << " Total Entropy: " << eos.stot << "\n";
os << " Gas Entropy: " << eos.sgas << "\n";
os << " Radiation Entropy: " << eos.srad;
return os;
}
};
// interpolating polynomial function definitions
/**
* @brief Interpolating polynomial function psi0.
* @param z Input value.
* @return Result of the polynomial.
*/
double psi0(double z);
/**
* @brief Derivative of the interpolating polynomial function psi0.
* @param z Input value.
* @return Derivative of the polynomial.
*/
double dpsi0(double z);
/**
* @brief Second derivative of the interpolating polynomial function psi0.
* @param z Input value.
* @return Second derivative of the polynomial.
*/
double ddpsi0(double z);
/**
* @brief Interpolating polynomial function psi1.
* @param z Input value.
* @return Result of the polynomial.
*/
double psi1(double z);
/**
* @brief Derivative of the interpolating polynomial function psi1.
* @param z Input value.
* @return Derivative of the polynomial.
*/
double dpsi1(double z);
/**
* @brief Second derivative of the interpolating polynomial function psi1.
* @param z Input value.
* @return Second derivative of the polynomial.
*/
double ddpsi1(double z);
/**
* @brief Interpolating polynomial function psi2.
* @param z Input value.
* @return Result of the polynomial.
*/
double psi2(double z);
/**
* @brief Derivative of the interpolating polynomial function psi2.
* @param z Input value.
* @return Derivative of the polynomial.
*/
double dpsi2(double z);
/**
* @brief Second derivative of the interpolating polynomial function psi2.
* @param z Input value.
* @return Second derivative of the polynomial.
*/
double ddpsi2(double z);
/**
* @brief Interpolating polynomial function xpsi0.
* @param z Input value.
* @return Result of the polynomial.
*/
double xpsi0(double z);
/**
* @brief Derivative of the interpolating polynomial function xpsi0.
* @param z Input value.
* @return Derivative of the polynomial.
*/
double xdpsi0(double z);
/**
* @brief Interpolating polynomial function xpsi1.
* @param z Input value.
* @return Result of the polynomial.
*/
double xpsi1(double z);
/**
* @brief Derivative of the interpolating polynomial function xpsi1.
* @param z Input value.
* @return Derivative of the polynomial.
*/
double xdpsi1(double z);
/**
* @brief Interpolating polynomial function h3.
* @param fi Array of coefficients.
* @param w0t Weight 0 for temperature.
* @param w1t Weight 1 for temperature.
* @param w0mt Weight 0 for temperature (minus).
* @param w1mt Weight 1 for temperature (minus).
* @param w0d Weight 0 for density.
* @param w1d Weight 1 for density.
* @param w0md Weight 0 for density (minus).
* @param w1md Weight 1 for density (minus).
* @return Result of the polynomial.
*/
double h3(double fi[36], double w0t, double w1t, double w0mt, double w1mt,
double w0d, double w1d, double w0md, double w1md);
/**
* @brief Interpolating polynomial function h5.
* @param fi Array of coefficients.
* @param w0t Weight 0 for temperature.
* @param w1t Weight 1 for temperature.
* @param w2t Weight 2 for temperature.
* @param w0mt Weight 0 for temperature (minus).
* @param w1mt Weight 1 for temperature (minus).
* @param w2mt Weight 2 for temperature (minus).
* @param w0d Weight 0 for density.
* @param w1d Weight 1 for density.
* @param w2d Weight 2 for density.
* @param w0md Weight 0 for density (minus).
* @param w1md Weight 1 for density (minus).
* @param w2md Weight 2 for density (minus).
* @return Result of the polynomial.
*/
double h5(double fi[36], double w0t, double w1t, double w2t, double w0mt,
double w1mt, double w2mt, double w0d, double w1d, double w2d,
double w0md, double w1md, double w2md);
/**
* @brief Read the Helmholtz EOS table from a file.
* @param filename Path to the file containing the table.
* @return HELMTable structure containing the table data.
*/
HELMTable read_helm_table(const std::string filename);
/**
* @brief Calculate the Helmholtz EOS components.
* @param q EOSInput parameters for the EOS calculation.
* @param table HELMTable structure containing the table data.
* @return EOS structure containing the calculated quantities.
*/
EOS get_helm_EOS(EOSInput &q, const HELMTable &table);
}
#endif // HELM_H