Skip to content

Commit

Permalink
Merge pull request #292 from lanl/bjm/carnstar
Browse files Browse the repository at this point in the history
Bjm/carnstar
  • Loading branch information
Yurlungur authored May 31, 2024
2 parents 1ea1804 + 6af50ff commit 6cc0ba7
Show file tree
Hide file tree
Showing 12 changed files with 1,087 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Current develop

### Added (new features/APIs/variables/...)
- [[PR292]](https://github.com/lanl/singularity-eos/pull/292) Added Carnahan-Starling EoS
- [[PR#362]](https://github.com/lanl/singularity-eos/pull/362) Add lambda to thermalqs
- [[PR#339]](https://github.com/lanl/singularity-eos/pull/339) Added COMPONENTS to singularity-eos CMake install, allowing to select a minimal subset needed e.g. for Fortran bindings only
- [[PR#336]](https://github.com/lanl/singularity-eos/pull/336) Included code and documentation for a full, temperature consistent, Mie-Gruneisen EOS based on a pressure power law expansion in eta = 1-V/V0. PowerMG.
Expand Down
86 changes: 86 additions & 0 deletions doc/sphinx/src/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,92 @@ these values are not set, they will be the same as those returned by the
conditions are given, the return values of the :code:`ValuesAtReferenceState()`
function will not be the same.

Carnahan-Starling
`````````````````

The (quasi-exact) Carnahan-Starling model in ``singularity-eos`` takes
the form

.. math::
P = Z(\rho) \rho (e-q) (\gamma-1)
.. math::
Z(\rho) = \frac{1+\eta+\eta^2-\eta^3}{(1-\eta)^3},
where :math:`\eta` is the packing fraction given by

.. math::
\eta = b\rho.
The energy is related to the temperature through

.. math::
e = C_V T + q,
where :math:`q` is an energy offset.

As with the Noble-Abel EOS, it should be noted that covolume is physically
significant as it represents the maximum compressibility of the gas,
and as a result it should be non-negative.

The Carnahan-Starling EOS is intended to represent a hard sphere fluid, and the
covolume parameter, :math:`b`, can be related to the hard sphere
diameter, :math:`\sigma`, through

.. math::
b = \frac{\pi}{6}\frac{\sigma^3}{M},
where :math:`M` is the molar mass of the gas.

The entropy for the Carnahan-Starling EOS is given by

.. math::
S = C_V \ln\left(\frac{T}{T_0}\right) + C_V (\gamma-1) \left\{ \ln\left(\frac{v}
{v_0}\right) - S^{CS} \right\} + q',
.. math::
S^{CS} = b\left(4\left(\frac{1}{v-b} - \frac{1}{v_0-b}\right)+
b\left(\frac{1}{(v-b)^2} - \frac{1}{(v_0-b)^2}\right)\right)
where :math:`S(\rho_0,T_0)=q'`. By default, :math:`T_0 = 298` K and the
reference density is given by

.. math::
P_0 = \rho_0 Z(\rho_0) C_V T_0(\gamma-1),
where :math:`P_0` is by default 1 bar. Denisty is obtained through root finding methods.

The settable parameters for this EOS are :math:`\gamma-1`, specific
heat capacity (:math:`C_V`), covolume (:math:`b`) and offset internal energy (:math:`q`). Optionally, the reference state for the entropy calculation can
be provided by setting the reference temperature, pressure, and entropy offset.

The ``CarnahanStarling`` EOS constructor has four arguments: ``gm1``, which is :math:`\gamma-1`; ``Cv``, the
specific heat :math:`C_V`; :math:`b`, the covolume; and :math:`q`, the internal energy offset.

.. code-block:: cpp
CarnahanStarling(Real gm1, Real Cv, Real b, Real q)
Optionally, the reference state for the entropy calculation,
can be provided in the constructor via ``qp``, ``T0`` and ``P0``:

.. code-block:: cpp
CarnahanStarling(Real gm1, Real Cv, Real b, Real q, Real qp, Real T0, Real P0)
Note that these parameters are provided solely for the entropy calculation. When
these values are not set, they will be the same as those returned by the
:code:`ValuesAtReferenceState()` function. However, if the entropy reference
conditions are given, the return values of the :code:`ValuesAtReferenceState()`
function will not be the same.

Gruneisen EOS
`````````````

Expand Down
1 change: 1 addition & 0 deletions singularity-eos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ register_headers(
eos/eos_eospac.hpp
eos/eos_noble_abel.hpp
eos/eos_stiff.hpp
eos/eos_carnahan_starling.hpp
)

if (SINGULARITY_BUILD_CLOSURE)
Expand Down
2 changes: 1 addition & 1 deletion singularity-eos/eos/default_variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ using singularity::variadic_utils::transform_variadic_list;
// all eos's
static constexpr const auto full_eos_list =
tl<IdealGas, Gruneisen, Vinet, MGUsup, PowerMG, JWL, DavisReactants, DavisProducts,
StiffGas, SAP_Polynomial, NobleAbel
StiffGas, SAP_Polynomial, NobleAbel, CarnahanStarling
#ifdef SINGULARITY_USE_SPINER_WITH_HDF5
#ifdef SINGULARITY_USE_HELMHOLTZ
,
Expand Down
260 changes: 260 additions & 0 deletions singularity-eos/eos/eos_carnahan_starling.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
//------------------------------------------------------------------------------
// © 2021-2023. Triad National Security, LLC. All rights reserved. This
// program was produced under U.S. Government contract 89233218CNA000001
// for Los Alamos National Laboratory (LANL), which is operated by Triad
// National Security, LLC for the U.S. Department of Energy/National
// Nuclear Security Administration. All rights in the program are
// reserved by Triad National Security, LLC, and the U.S. Department of
// Energy/National Nuclear Security Administration. The Government is
// granted for itself and others acting on its behalf a nonexclusive,
// paid-up, irrevocable worldwide license in this material to reproduce,
// prepare derivative works, distribute copies to the public, perform
// publicly and display publicly, and to permit others to do so.
//------------------------------------------------------------------------------

#ifndef _SINGULARITY_EOS_EOS_EOS_CARNAHAN_STARLING_HPP_
#define _SINGULARITY_EOS_EOS_EOS_CARNAHAN_STARLING_HPP_

// stdlib
#include <cmath>
#include <cstdio>
#include <string>

// Ports-of-call
#include <ports-of-call/portability.hpp>

// Base stuff
#include <singularity-eos/base/constants.hpp>
#include <singularity-eos/base/eos_error.hpp>
#include <singularity-eos/base/math_utils.hpp>
#include <singularity-eos/base/robust_utils.hpp>
#include <singularity-eos/base/root-finding-1d/root_finding.hpp>
#include <singularity-eos/eos/eos_base.hpp>

namespace singularity {

using namespace eos_base;

class CarnahanStarling : public EosBase<CarnahanStarling> {
public:
CarnahanStarling() = default;
PORTABLE_INLINE_FUNCTION CarnahanStarling(Real gm1, Real Cv, Real bb, Real qq)
: _Cv(Cv), _gm1(gm1), _bb(bb), _qq(qq), _T0(ROOM_TEMPERATURE),
_P0(ATMOSPHERIC_PRESSURE), _qp(0.0),
_rho0(DensityFromPressureTemperature(_P0, _T0)), _vol0(robust::ratio(1.0, _rho0)),
_sie0(Cv * _T0 + qq),
_bmod0(_rho0 * Cv * _T0 *
(PartialRhoZedFromDensity(_rho0) +
ZedFromDensity(_rho0) * ZedFromDensity(_rho0) * gm1)),
_dpde0(_rho0 * ZedFromDensity(_rho0) * gm1) {
checkParams();
}
PORTABLE_INLINE_FUNCTION CarnahanStarling(Real gm1, Real Cv, Real bb, Real qq, Real qp,
Real T0, Real P0)
: _Cv(Cv), _gm1(gm1), _bb(bb), _qq(qq), _T0(T0), _P0(P0), _qp(qp),
_rho0(DensityFromPressureTemperature(P0, T0)), _vol0(robust::ratio(1.0, _rho0)),
_sie0(Cv * T0 + qq),
_bmod0(_rho0 * Cv * T0 *
(PartialRhoZedFromDensity(_rho0) +
ZedFromDensity(_rho0) * ZedFromDensity(_rho0) * gm1)),
_dpde0(_rho0 * ZedFromDensity(_rho0) * gm1) {
checkParams();
}
CarnahanStarling GetOnDevice() { return *this; }
PORTABLE_INLINE_FUNCTION Real TemperatureFromDensityInternalEnergy(
const Real rho, const Real sie, Real *lambda = nullptr) const {
return std::max(robust::SMALL(), (sie - _qq) / _Cv);
}
PORTABLE_INLINE_FUNCTION void checkParams() const {
PORTABLE_ALWAYS_REQUIRE(_Cv >= 0, "Heat capacity must be positive");
PORTABLE_ALWAYS_REQUIRE(_gm1 >= 0, "Gruneisen parameter must be positive");
PORTABLE_ALWAYS_REQUIRE(_bb >= 0, "Covolume must be positive");
}
PORTABLE_INLINE_FUNCTION Real ZedFromDensity(const Real rho,
Real *lambda = nullptr) const {
const Real eta = _bb * rho;
const Real zed =
1.0 + robust::ratio(eta * (4.0 - 2.0 * eta), math_utils::pow<3>(1.0 - eta));
return zed;
}
PORTABLE_INLINE_FUNCTION Real PartialRhoZedFromDensity(const Real rho,
Real *lambda = nullptr) const {
const Real eta = _bb * rho;
return 1.0 + robust::ratio(eta * (8.0 - 2.0 * eta), math_utils::pow<4>(1.0 - eta));
}
PORTABLE_INLINE_FUNCTION Real DensityFromPressureTemperature(
const Real press, const Real temperature, const Real guess = robust::SMALL(),
Real *lambda = nullptr) const {
Real real_root;
auto poly = [=](Real dens) {
return _Cv * temperature * _gm1 * dens * ZedFromDensity(dens);
};
using RootFinding1D::findRoot;
using RootFinding1D::Status;
static constexpr Real xtol = 1.0e-12;
static constexpr Real ytol = 1.0e-12;
static constexpr Real lo_bound = robust::SMALL();
const Real hi_bound = robust::ratio(1.0, _bb);
auto status = findRoot(poly, press, guess, lo_bound, hi_bound, xtol, ytol, real_root);
if (status != Status::SUCCESS) {
// Root finder failed even though the solution was bracketed... this is an error
EOS_ERROR("*** (Warning) DensityFromPressureTemperature :: Convergence not met in "
"Carnahan-Starling EoS (root finder util) ***\n");
real_root = -1.0;
}
return std::max(robust::SMALL(), real_root);
}
PORTABLE_INLINE_FUNCTION Real InternalEnergyFromDensityTemperature(
const Real rho, const Real temperature, Real *lambda = nullptr) const {
return std::max(_qq, _Cv * temperature + _qq);
}
PORTABLE_INLINE_FUNCTION Real PressureFromDensityTemperature(
const Real rho, const Real temperature, Real *lambda = nullptr) const {
const Real zed = ZedFromDensity(rho);
return std::max(robust::SMALL(), zed * rho * temperature * _Cv * _gm1);
}
PORTABLE_INLINE_FUNCTION Real PressureFromDensityInternalEnergy(
const Real rho, const Real sie, Real *lambda = nullptr) const {
const Real zed = ZedFromDensity(rho);
return std::max(robust::SMALL(), zed * rho * (sie - _qq) * _gm1);
}
PORTABLE_INLINE_FUNCTION Real EntropyFromDensityTemperature(
const Real rho, const Real temperature, Real *lambda = nullptr) const {
const Real vol = robust::ratio(1.0, rho);
const Real one_by_vb = robust::ratio(1.0, vol - _bb);
const Real one_by_v0b = robust::ratio(1.0, _vol0 - _bb);
return _Cv * std::log(robust::ratio(temperature, _T0) + robust::SMALL()) +
_gm1 * _Cv * std::log(robust::ratio(vol, _vol0) + robust::SMALL()) -
_gm1 * _Cv * _bb * (one_by_vb - one_by_v0b) *
(4.0 + _bb * (one_by_vb + one_by_v0b)) +
_qp;
}
PORTABLE_INLINE_FUNCTION Real EntropyFromDensityInternalEnergy(
const Real rho, const Real sie, Real *lambda = nullptr) const {
const Real vol = robust::ratio(1.0, rho);
const Real one_by_vb = robust::ratio(1.0, vol - _bb);
const Real one_by_v0b = robust::ratio(1.0, _vol0 - _bb);
return _Cv * std::log(robust::ratio(sie - _qq, _sie0 - _qq) + robust::SMALL()) +
_gm1 * _Cv * std::log(robust::ratio(vol, _vol0) + robust::SMALL()) -
_gm1 * _Cv * _bb * (one_by_vb - one_by_v0b) *
(4.0 + _bb * (one_by_vb + one_by_v0b)) +
_qp;
}
PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityTemperature(
const Real rho, const Real temperature, Real *lambda = nullptr) const {
return _Cv;
}
PORTABLE_INLINE_FUNCTION Real SpecificHeatFromDensityInternalEnergy(
const Real rho, const Real sie, Real *lambda = nullptr) const {
return _Cv;
}
PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityTemperature(
const Real rho, const Real temperature, Real *lambda = nullptr) const {
return std::max(robust::SMALL(),
rho * _Cv * temperature * _gm1 *
(PartialRhoZedFromDensity(rho) +
ZedFromDensity(rho) * ZedFromDensity(rho) * _gm1));
}
PORTABLE_INLINE_FUNCTION Real BulkModulusFromDensityInternalEnergy(
const Real rho, const Real sie, Real *lambda = nullptr) const {
return std::max(robust::SMALL(),
rho * (sie - _qq) * _gm1 *
(PartialRhoZedFromDensity(rho) +
ZedFromDensity(rho) * ZedFromDensity(rho) * _gm1));
}
PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityTemperature(
const Real rho, const Real temperature, Real *lambda = nullptr) const {
return ZedFromDensity(rho) * _gm1;
}
PORTABLE_INLINE_FUNCTION Real GruneisenParamFromDensityInternalEnergy(
const Real rho, const Real sie, Real *lambda = nullptr) const {
return ZedFromDensity(rho) * _gm1;
}
PORTABLE_INLINE_FUNCTION Real
MinInternalEnergyFromDensity(const Real rho, Real *lambda = nullptr) const {
return _qq;
}
PORTABLE_INLINE_FUNCTION void FillEos(Real &rho, Real &temp, Real &energy, Real &press,
Real &cv, Real &bmod, const unsigned long output,
Real *lambda = nullptr) const;
PORTABLE_INLINE_FUNCTION
void ValuesAtReferenceState(Real &rho, Real &temp, Real &sie, Real &press, Real &cv,
Real &bmod, Real &dpde, Real &dvdt,
Real *lambda = nullptr) const {
// use STP: 1 atmosphere, room temperature
rho = _rho0;
temp = _T0;
sie = _sie0;
press = _P0;
cv = _Cv;
bmod = _bmod0;
dpde = _dpde0;
}
// Generic functions provided by the base class. These contain e.g. the vector
// overloads that use the scalar versions declared here
SG_ADD_BASE_CLASS_USINGS(CarnahanStarling)
PORTABLE_INLINE_FUNCTION
int nlambda() const noexcept { return 0; }
static constexpr unsigned long PreferredInput() { return _preferred_input; }
static inline unsigned long scratch_size(std::string method, unsigned int nelements) {
return 0;
}
static inline unsigned long max_scratch_size(unsigned int nelements) { return 0; }
PORTABLE_INLINE_FUNCTION void PrintParams() const {
printf("Carnahan-Starling Parameters:\nGamma = %g\nCv = %g\nb = %g\nq = "
"%g\n",
_gm1 + 1.0, _Cv, _bb, _qq);
}
PORTABLE_INLINE_FUNCTION void
DensityEnergyFromPressureTemperature(const Real press, const Real temp, Real *lambda,
Real &rho, Real &sie) const {
sie = std::max(_qq, _Cv * temp + _qq);
rho = DensityFromPressureTemperature(press, temp);
}
inline void Finalize() {}
static std::string EosType() { return std::string("CarnahanStarling"); }
static std::string EosPyType() { return EosType(); }

private:
Real _Cv, _gm1, _bb, _qq;
// optional reference state variables
Real _T0, _P0, _qp;
// reference values
Real _rho0, _vol0, _sie0, _bmod0, _dpde0;
// static constexpr const Real _T0 = ROOM_TEMPERATURE;
// static constexpr const Real _P0 = ATMOSPHERIC_PRESSURE;
static constexpr const unsigned long _preferred_input =
thermalqs::density | thermalqs::specific_internal_energy;
};

PORTABLE_INLINE_FUNCTION
void CarnahanStarling::FillEos(Real &rho, Real &temp, Real &sie, Real &press, Real &cv,
Real &bmod, const unsigned long output,
Real *lambda) const {
if (output & thermalqs::density && output & thermalqs::specific_internal_energy) {
if (output & thermalqs::pressure || output & thermalqs::temperature) {
UNDEFINED_ERROR;
}
DensityEnergyFromPressureTemperature(press, temp, lambda, rho, sie);
}
if (output & thermalqs::pressure && output & thermalqs::specific_internal_energy) {
if (output & thermalqs::density || output & thermalqs::temperature) {
UNDEFINED_ERROR;
}
sie = InternalEnergyFromDensityTemperature(rho, temp, lambda);
}
if (output & thermalqs::temperature && output & thermalqs::specific_internal_energy) {
sie = robust::ratio(press, ZedFromDensity(rho) * rho * _gm1) + _qq;
}
if (output & thermalqs::pressure) press = PressureFromDensityInternalEnergy(rho, sie);
if (output & thermalqs::temperature)
temp = TemperatureFromDensityInternalEnergy(rho, sie);
if (output & thermalqs::bulk_modulus)
bmod = BulkModulusFromDensityInternalEnergy(rho, sie);
if (output & thermalqs::specific_heat)
cv = SpecificHeatFromDensityInternalEnergy(rho, sie);
}

} // namespace singularity

#endif // _SINGULARITY_EOS_EOS_EOS_CARNAHAN_STARLING_HPP_
1 change: 1 addition & 0 deletions singularity-eos/eos/eos_models.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define _SINGULARITY_EOS_EOS_EOS_MODELS_HPP_

// EOS models
#include <singularity-eos/eos/eos_carnahan_starling.hpp>
#include <singularity-eos/eos/eos_davis.hpp>
#include <singularity-eos/eos/eos_eospac.hpp>
#include <singularity-eos/eos/eos_gruneisen.hpp>
Expand Down
3 changes: 1 addition & 2 deletions singularity-eos/eos/eos_noble_abel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ class NobleAbel : public EosBase<NobleAbel> {
template <typename Indexer_t = Real *>
PORTABLE_INLINE_FUNCTION Real MinInternalEnergyFromDensity(
const Real rho, Indexer_t &&lambda = static_cast<Real *>(nullptr)) const {
MinInternalEnergyIsNotEnabled("Noble Abel");
return 0.0;
return _qq;
}

template <typename Indexer_t = Real *>
Expand Down
Loading

0 comments on commit 6cc0ba7

Please sign in to comment.