Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nulib reader #57

Merged
merged 4 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/SetupOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ option (SINGULARITY_HIDE_MORE_WARNINGS "hide more warnings" OFF)
option (SINGULARITY_BUILD_TESTS "Compile tests" OFF)
option (SINGULARITY_BETTER_DEBUG_FLAGS
"Better debug flags for singularity" ON)
option (SINGULARITY_USE_FMATH "Enable fast-math logarithms" ON)
option (SINGULARITY_USE_FMATH "Enable fast-math logarithms" OFF)

#=======================================
# Dependency options
Expand Down
189 changes: 172 additions & 17 deletions singularity-opac/neutrinos/spiner_opac_neutrinos.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <cmath>
#include <cstdio>
#include <string>
#include <utility>
#include <vector>

#include <fast-math/logs.hpp>
#include <ports-of-call/portability.hpp>
Expand Down Expand Up @@ -64,6 +66,7 @@ class SpinerOpacity {
using PC = pc;
using DataBox = Spiner::DataBox<Real>;

static constexpr Real MEV = 1e6 * pc::eV;
static constexpr Real EPS = 10.0 * std::numeric_limits<Real>::min();
static constexpr Real Hz2MeV = pc::h / (1e6 * pc::eV);
static constexpr Real MeV2Hz = 1 / Hz2MeV;
Expand All @@ -72,6 +75,8 @@ class SpinerOpacity {
static constexpr Real MeV2K = 1.e9 * MeV2GK;
static constexpr Real K2MeV = 1. / MeV2K;

enum class LoadSource { SP5, NuLib };

SpinerOpacity() = default;

// Testing constructor that fills the tables with gray opacities
Expand Down Expand Up @@ -140,18 +145,15 @@ class SpinerOpacity {
ljnu_(ljnu), lJ_(lJ), lJYe_(lJYe) {}

#ifdef SPINER_USE_HDF
SpinerOpacity(const std::string &filename)
SpinerOpacity(const std::string &filename,
const LoadSource load_from = LoadSource::SP5)
: filename_(filename.c_str()), memoryStatus_(impl::DataStatus::OnHost) {
herr_t status = H5_SUCCESS;
hid_t file = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
status += lalphanu_.loadHDF(file, SP5::Opac::AbsorptionCoefficient);
status += ljnu_.loadHDF(file, SP5::Opac::EmissivityPerNu);
status += lJ_.loadHDF(file, SP5::Opac::TotalEmissivity);
status += lJYe_.loadHDF(file, SP5::Opac::NumberEmissivity);
status += H5Fclose(file);

if (status != H5_SUCCESS) {
OPAC_ERROR("neutrinos::SpinerOpacity: HDF5 error\n");
if (load_from == LoadSource::SP5) {
LoadFromSP5_(filename);
} else if (load_from == LoadSource::NuLib) {
LoadFromNuLib_(filename);
} else {
OPAC_ERROR("Unknown file source type\n");
}
}

Expand All @@ -169,7 +171,7 @@ class SpinerOpacity {
OPAC_ERROR("neutrinos::SpinerOpacity: HDF5 error\n");
}
}
#endif
#endif // SPINER_USE_HDF

PORTABLE_INLINE_FUNCTION int nlambda() const noexcept { return 0; }
PORTABLE_INLINE_FUNCTION
Expand Down Expand Up @@ -370,18 +372,171 @@ class SpinerOpacity {
}

private:
#ifdef SPINER_USE_HDF
void LoadFromSP5_(const std::string &filename) {
herr_t status = H5_SUCCESS;
hid_t file = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
status += lalphanu_.loadHDF(file, SP5::Opac::AbsorptionCoefficient);
status += ljnu_.loadHDF(file, SP5::Opac::EmissivityPerNu);
status += lJ_.loadHDF(file, SP5::Opac::TotalEmissivity);
status += lJYe_.loadHDF(file, SP5::Opac::NumberEmissivity);
status += H5Fclose(file);

if (status != H5_SUCCESS) {
OPAC_ERROR("neutrinos::SpinerOpacity: HDF5 error\n");
}
}

void LoadFromNuLib_(const std::string &filename) {
herr_t status = H5_SUCCESS;
hid_t file = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
// table size
const int NR = ReadInt_(file, "nrho");
const int NT = ReadInt_(file, "ntemp");
const int NY = ReadInt_(file, "nye");
const int NE = ReadInt_(file, "number_groups");
const int NTYPE = ReadInt_(file, "number_species");

auto [rho_min, rho_max] = ReadBounds_(file, "rho_points", NR);
auto [T_min, T_max] = ReadBounds_(file, "temp_points", NT);
auto [emin, emax] = ReadBounds_(file, "neutrino_energies", NE);

auto [YeMin, YeMax] = ReadBounds_(file, "ye_points", NY);
const Real lRhoMin = std::log10(rho_min); // g/cm^3
const Real lRhoMax = std::log10(rho_max);
const Real lTMin = std::log10(T_min); // MeV internally. Converted from K
const Real lTMax = std::log10(T_max); // when function calls made.
const Real leMin = std::log10(emin); // MeV internally. Converted from Hz
const Real leMax = std::log10(emax); // when function calls made.

DataBox jnu_file(NE, NTYPE, NY, NT,
NR); // (erg s^{-1} cm^{-3} MeV^{-1} / 4pi)
status = H5LTread_dataset_double(file, "emissivities", jnu_file.data());
if (status != H5_SUCCESS) {
OPAC_ERROR("An HDF5 error ocurred while reading emissivities");
}
DataBox kappa_file(NE, NTYPE, NY, NT, NR); // 1/cm
status =
H5LTread_dataset_double(file, "absorption_opacity", jnu_file.data());
if (status != H5_SUCCESS) {
OPAC_ERROR("An HDF5 error ocurred while reading absorption opacities");
}
status = H5Fclose(file);
if (status != H5_SUCCESS) {
OPAC_ERROR("An HDF5 error ocurred while reading absorption opacities");
}

// Set metadata for lalphanu and ljnu
lalphanu_.resize(NR, NT, NY, NTYPE, NE); // 1/cm
lalphanu_.setRange(0, leMin, leMax, NE);
// index 1 is the species and is not interpolatable
lalphanu_.setRange(2, YeMin, YeMax, NY);
lalphanu_.setRange(3, lTMin, lTMax, NT);
lalphanu_.setRange(4, lRhoMin, lRhoMax, NR);
ljnu_.copyMetadata(lalphanu_); // (erg s^{-1} cm^{-3} Hz^{-1} / 4pi)

// set metadata for lJ and lJYe
lJ_.resize(NR, NT, NY, NTYPE);
lJ_.setRange(1, YeMin, YeMax, NY);
lJ_.setRange(2, lTMin, lTMax, NT);
lJ_.setRange(3, lRhoMin, lRhoMax, NR);
lJYe_.copyMetadata(lJ_);

// Fill lalphanu and lJnu
for (int iR = 0; iR < NR; ++iR) {
for (int iT = 0; iT < NT; ++iT) {
for (int iY = 0; iY < NY; ++iY) {
for (int idx = 0; idx < NTYPE; ++idx) {
for (int ie = 0; ie < NE; ++ie) {
Real kappa = kappa_file(ie, idx, iY, iT, iR);
// log
lalphanu_(iR, iT, iY, idx, ie) = std::log10(kappa);
Real j = jnu_file(ie, idx, iY, iT, iR);
// convert from
// (erg s^{-1} cm^{-3} MeV^{-1} / 4pi)
// to
// (erg s^{-1} cm^{-3} Hz^{-1} / 4pi)
ljnu_(iR, iT, iY, idx, ie) = std::log10(pc::h * j / MEV);
}
}
}
}
}
ComputeIntegrals(ljnu_, lJ_, lJYe_, NTYPE);
}

static int ReadInt_(const hid_t &file_id, const std::string &name) {
int data;
herr_t status = H5LTread_dataset_int(file_id, name.c_str(), &data);
if (status != H5_SUCCESS) {
OPAC_ERROR("Failed to read dataset!\n");
}
return data;
}

static auto ReadBounds_(const hid_t &file_id, const std::string &name,
int size) {
std::vector<Real> table(size);
herr_t status =
H5LTread_dataset_double(file_id, name.c_str(), table.data());
if (status != H5_SUCCESS) {
OPAC_ERROR("An HDF5 error ocurred while reading bounds");
}
Real lo = table[0];
Real hi = table[size - 1];
return std::make_pair(lo, hi);
}

static void ComputeIntegrals(const DataBox &ljnu, DataBox &lJ, DataBox &lJYe,
int RAD_NUM_TYPES) {
auto rhoGrid = ljnu.range(4);
auto TGrid = ljnu.range(3);
auto YeGrid = ljnu.range(2);
auto leGrid = ljnu.range(0);

// integrals performed as Riemann sum in log space
Real dle = leGrid.dx();
for (int iRho = 0; iRho < rhoGrid.nPoints(); ++iRho) {
for (int iT = 0; iT < TGrid.nPoints(); ++iT) {
for (int iYe = 0; iYe < YeGrid.nPoints(); ++iYe) {
for (int itp = 0; itp < RAD_NUM_TYPES; ++itp) {
lJ(iRho, iT, iYe, itp) = 0.0;
lJYe(iRho, iT, iYe, itp) = 0.0;
for (int ie = 0; ie < leGrid.nPoints(); ++ie) {
Real le = leGrid.x(ie);
Real e = std::pow(10., le);
Real lj = ljnu(iRho, iT, iYe, itp, ie);
// convert again to
// (erg s^{-1} cm^{-3} MeV^{-1} / 4pi)
// since we integrate in those units
Real j = std::pow(10., lj) * MEV / pc::h;
Real integrand = 4 * M_PI * j * e;
lJ(iRho, iT, iYe, itp) += integrand;
// divide by energy in ergs for lJYe to get number emissivity
lJYe(iRho, iT, iYe, itp) += integrand / (MEV * e);
}
// multiply by log spacing and take the log
lJ(iRho, iT, iYe, itp) = toLog_(lJ(iRho, iT, iYe, itp) * dle);
lJYe(iRho, iT, iYe, itp) = toLog_(lJYe(iRho, iT, iYe, itp) * dle);
}
}
}
}
}
#endif // SPINER_USE_HDF

// TODO(JMM): Offsets probably not necessary
PORTABLE_INLINE_FUNCTION Real toLog_(const Real x, const Real offset) const {
PORTABLE_INLINE_FUNCTION static Real toLog_(const Real x, const Real offset) {
return std::log10(std::abs(std::max(x, -offset) + offset) + EPS);
}
PORTABLE_INLINE_FUNCTION Real toLog_(const Real x) const {
PORTABLE_INLINE_FUNCTION static Real toLog_(const Real x) {
return toLog_(x, 0);
}
PORTABLE_INLINE_FUNCTION Real fromLog_(const Real lx,
const Real offset) const {
PORTABLE_INLINE_FUNCTION static Real fromLog_(const Real lx,
const Real offset) {
return std::pow(10., lx) - offset;
}
PORTABLE_INLINE_FUNCTION Real fromLog_(const Real lx) const {
PORTABLE_INLINE_FUNCTION static Real fromLog_(const Real lx) {
return fromLog_(lx, 0);
}
PORTABLE_INLINE_FUNCTION void toLogs_(const Real rho, const Real temp,
Expand Down
6 changes: 5 additions & 1 deletion utils/fast-math/logs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,19 @@
#include <cmath>
#include <ports-of-call/portability.hpp>

// TODO(JMM): This has got to go. Replace with sane math.

#ifdef SINGULARITY_USE_FMATH
// herumi-fmath does not work on device
// On CPUS it provides another 10% or so speedup
// for negligible cost in accuracy
#define BD_USE_FMATH
#if defined(PORTABILITY_STRATEGY_KOKKOS) || defined(SINGULARITY_USE_FMATH)
#if defined(PORTABILITY_STRATEGY_KOKKOS)
#undef BD_USE_FMATH
#else
#include <fmath.hpp>
#endif
#endif // SINGULARITY_USE_FMATH

namespace BDMath {

Expand Down
Loading