Skip to content

Add mass fraction multi-phase table to sesame2spiner#600

Open
adamdempsey90 wants to merge 13 commits intomainfrom
dempsey/mass_frac
Open

Add mass fraction multi-phase table to sesame2spiner#600
adamdempsey90 wants to merge 13 commits intomainfrom
dempsey/mass_frac

Conversation

@adamdempsey90
Copy link
Collaborator

@adamdempsey90 adamdempsey90 commented Jan 12, 2026

PR Summary

This adds the mass fraction SESAME table to the spiner tables that sesame2spiner outputs (if it exists). Tested in a downstream code.

Putting this up now for an initial review.

I still need to add the mass fractions to the spiner EOS class. Are we okay with adding new MassFractionFromDensityTemperature functions to all EOS classes?

Still TODO:

  • Add this field to the spiner EOS
  • Some sort of test

PR Checklist

  • Adds a test for any bugs fixed. Adds tests for new features.
  • Format your changes by using the make format command after configuring with cmake.
  • Document any new features, update documentation for changes made.
  • Make sure the copyright notice on any files you modified is up to date.
  • After creating a pull request, note it in the CHANGELOG.md file.
  • LANL employees: make sure tests pass both on the github CI and on the Darwin CI

If preparing for a new release, in addition please check the following:

  • Update the version in cmake.
  • Move the changes in the CHANGELOG.md file under a new header for the new release, and reset the categories.
  • Maintainers: ensure spackages are up to date:
    • LANL-internal team, update XCAP spackages
    • Current maintainer of upstream spackages, submit MR to spack

@adamdempsey90 adamdempsey90 self-assigned this Jan 12, 2026
@adamdempsey90 adamdempsey90 marked this pull request as draft January 12, 2026 20:41
Copy link
Collaborator

@Yurlungur Yurlungur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Glad it was a simple change. Regarding adding mass fractions to every EOS class... Broadly I'd be supportive of this, if we had an error message/stub in the base class as the default behavior. Clearly mass fractions aren't sensible for all EOS's but they are for enough EOS's we might want this.

@adamdempsey90
Copy link
Collaborator Author

Nice! Glad it was a simple change. Regarding adding mass fractions to every EOS class... Broadly I'd be supportive of this, if we had an error message/stub in the base class as the default behavior. Clearly mass fractions aren't sensible for all EOS's but they are for enough EOS's we might want this.

It looks like the StellarCollapse EOS already has MassFractionsFromDensityTemperature

@Yurlungur
Copy link
Collaborator

Nice! Glad it was a simple change. Regarding adding mass fractions to every EOS class... Broadly I'd be supportive of this, if we had an error message/stub in the base class as the default behavior. Clearly mass fractions aren't sensible for all EOS's but they are for enough EOS's we might want this.

It looks like the StellarCollapse EOS already has MassFractionsFromDensityTemperature

I believe Helmholtz does too... or if it doesn't, it could be exposed.

…ssFraction and fill the string rather than the other way around
Comment on lines +354 to +356
std::vector<EOS_REAL> rhos, Ts, phs;
makeInterpPoints(rhos, lRhoBounds);
makeInterpPoints(Ts, lTBounds);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am re-using the EOS rho-T grid for this but in testing we are seeing that maybe that isn't great, e.g., instead of clustering around STP, we probably want to cluster the points around phase transitions. I could add another set of parameters to the inputs that describe the grid decomp for just mass fractions?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes a lot of sense. Yeah there's no reason the two grids have to be the same.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to use different grids, I would just use the sesame grid. (piecewise linear). eospac just does bilinear interpolation for mass fractions so we should not need higher density than sesame.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion for now is you add a TODO to this effect, but we don't let this desired functionality block the merge.

@adamdempsey90
Copy link
Collaborator Author

Updated to include the mass fraction query in the spiner EOS object. The unit test I added passes on my CPU machine, but not sure about the GPU machines (mostly the EOSPAC paths...)

@adamdempsey90 adamdempsey90 marked this pull request as ready for review February 24, 2026 21:53
@Yurlungur
Copy link
Collaborator

Would you like me to do review now? I could also maybe get eospac paths working through the CI?

@adamdempsey90
Copy link
Collaborator Author

Would you like me to do review now? I could also maybe get eospac paths working through the CI?

yes please.

Comment on lines 197 to +205
Indexer_t &&lambda = static_cast<Real *>(nullptr)) const;
template <typename Indexer_t = Real *>
PORTABLE_INLINE_FUNCTION void MassFractionsFromDensityTemperature(
const Real rho, const Real T, Real *scratch,
Indexer_t &&lambda = static_cast<Real *>(nullptr)) const;
template <typename Indexer_t = Real *>
PORTABLE_INLINE_FUNCTION void MassFractionsFromDensityInternalEnergy(
const Real rho, const Real sie, Real *scratch,
Indexer_t &&lambda = static_cast<Real *>(nullptr)) const;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should probably add this functionality to the eospac EOS

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but it can wait to another PR. Maybe just add a TODO?

Copy link
Collaborator

@Yurlungur Yurlungur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamdempsey90 sorry for the delay. Some comments below. Did you want to mess with the paths yourself or did you want me to look at that? I'm happy to poke at it. Should have some time to do so tomorrow.

source ${BUILD_ENV}
pushd ${BUILD_DIR}
if [[ -f ./sesame2spiner/sesame2spiner ]]; then
echo "/usr/projects/data/eos/eos-developmental/Sn2162/v01/sn2162-v01.bin" > sesameFilesDir.txt
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this actually probably is sufficient to getting the paths to work on device.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the gpu tests are working. Although this path shouldn't be correct for LLNL, so I don't know about that

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. We may need a general solution for that. Probably the same problem will show up for the KPT tests. My suggestion is that we set these paths as environment variables in re-git then they can be automatically slurped up here. But before we go down that path... let's ping Richard.

@rbberger what are your thoughts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also have some project level env script that gets loaded by the CI and sets those paths

eosCheckError(errorCode, "eos_GetTableCmnts", eospacWarn);
}

void eosSafeTableMetaData(EOS_INTEGER *table, EOS_INTEGER infoItem, EOS_CHAR *infoString,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}
}

int eosCheckTableExistence(EOS_INTEGER tableType_, int matid_, Verbosity eospacWarn) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice added capability.

void eosColdCurveMask(int matid, const Bounds &lRhoBounds, const int numSie,
const DataBox &sieColdCurve, DataBox &mask,
Verbosity eospacWarn = Verbosity::Quiet);
bool eosMassFraction(int matid, const Bounds &lRhoBounds, const Bounds &lTBounds,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using a boolean return code here is clever. 👍

Comment on lines +354 to +356
std::vector<EOS_REAL> rhos, Ts, phs;
makeInterpPoints(rhos, lRhoBounds);
makeInterpPoints(Ts, lTBounds);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion for now is you add a TODO to this effect, but we don't let this desired functionality block the merge.

Comment on lines 197 to +205
Indexer_t &&lambda = static_cast<Real *>(nullptr)) const;
template <typename Indexer_t = Real *>
PORTABLE_INLINE_FUNCTION void MassFractionsFromDensityTemperature(
const Real rho, const Real T, Real *scratch,
Indexer_t &&lambda = static_cast<Real *>(nullptr)) const;
template <typename Indexer_t = Real *>
PORTABLE_INLINE_FUNCTION void MassFractionsFromDensityInternalEnergy(
const Real rho, const Real sie, Real *scratch,
Indexer_t &&lambda = static_cast<Real *>(nullptr)) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but it can wait to another PR. Maybe just add a TODO?

Comment on lines +339 to +344
bool has_mf = false;
// Need to hold the phase names for multiphase EOS
// This isn't great, but the class needs to be trivially copyable
// I've chosen something reasonable, e.g., 15 phases with 32 character names
char phase_names[480];
int numphases = 1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment in eos_spiner_rho_temp

Comment on lines +694 to +723
PORTABLE_INLINE_FUNCTION void
SpinerEOSDependsRhoSieTransformable<TransformerT>::MassFractionsFromDensityTemperature(
const Real rho, const Real T, Real *scratch, Indexer_t &&lambda) const {
if (!has_mf) {
*scratch = 1.0;
return;
}
const Real lRho = spiner_common::to_log(rho, lRhoOffset_);
const Real lT = spiner_common::to_log(T, lTOffset_);
IndexerUtils::SafeSet<IndexableTypes::LogDensity>(lambda, Lambda::lRho, lRho);
DataBox mf1d(scratch, numphases);
mf1d.interpFromDB(mF_, lRho, lT);
}

template <template <class> class TransformerT>
template <typename Indexer_t>
PORTABLE_INLINE_FUNCTION void
SpinerEOSDependsRhoSieTransformable<TransformerT>::MassFractionsFromDensityInternalEnergy(
const Real rho, const Real sie, Real *scratch, Indexer_t &&lambda) const {
if (!has_mf) {
*scratch = 1.0;
return;
}
const Real lRho = spiner_common::to_log(rho, lRhoOffset_);
const Real lE = spiner_common::to_log(sie, lEOffset_);
const Real T = T_.interpToReal(lRho, lE);
const Real lT = spiner_common::to_log(T, lTOffset_);
DataBox mf1d(scratch, numphases);
mf1d.interpFromDB(mF_, lRho, lT);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment in eos_spiner_rho_temp

return H5Gopen(file, name, property);
}

inline void h5_safe_read_string(hid_t &file, const char *grp, const char *name,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how much this matters, given who would stick a string in a dataset, but perhaps name this h5_safe_read_str_attr or something? Just to emphasize it's an attribute?

}
// We have to allocate sadly
char *tmp = new char[strlen + 1];
std::memset(tmp, 0, strlen + 1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer not to do the temporary allocation this way. I have a comment in the spiner EOS constructor about how you could do something evil with char* and actually return the pointer to memory allocated here. But if you don't choose to go down that route, why not this?

std::vector<char> tmp(0, strlen + 1);

and then you pass in tmp.data() as needed and RAII takes care of cleanup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants