Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <boost/preprocessor/arithmetic/sub.hpp>
7 : #include <boost/preprocessor/list/for_each.hpp>
8 : #include <boost/preprocessor/punctuation/comma_if.hpp>
9 : #include <boost/preprocessor/repetition/repeat.hpp>
10 : #include <boost/preprocessor/tuple/enum.hpp>
11 : #include <boost/preprocessor/tuple/to_list.hpp>
12 :
13 : #include "DataStructures/DataVector.hpp"
14 : #include "DataStructures/Tensor/Tensor.hpp"
15 : #include "PointwiseFunctions/Hydro/Units.hpp"
16 : #include "Utilities/CallWithDynamicType.hpp"
17 : #include "Utilities/Serialization/CharmPupable.hpp"
18 : #include "Utilities/TMPL.hpp"
19 : #include "Utilities/TypeTraits.hpp"
20 :
21 : /// \cond
22 : namespace EquationsOfState {
23 : template <typename ColdEos>
24 : class Barotropic2D;
25 : template <typename ColdEquilEos>
26 : class Barotropic3D;
27 : template <bool IsRelativistic>
28 : class DarkEnergyFluid;
29 : template <typename EquilEos>
30 : class Equilibrium3D;
31 : template <typename ColdEquationOfState>
32 : class HybridEos;
33 : template <bool IsRelativistic>
34 : class IdealFluid;
35 : template <bool IsRelativistic>
36 : class PolytropicFluid;
37 : template <bool IsRelativistic>
38 : class PiecewisePolytropicFluid;
39 : class Spectral;
40 : template <typename LowDensityEoS>
41 : class Enthalpy;
42 : template <bool IsRelativistic>
43 : class Tabulated3D;
44 : } // namespace EquationsOfState
45 : /// \endcond
46 :
47 : /// Contains all equations of state, including base class
48 : namespace EquationsOfState {
49 :
50 : namespace detail {
51 : template <bool IsRelativistic, size_t ThermodynamicDim>
52 : struct DerivedClasses {};
53 :
54 : template <>
55 : struct DerivedClasses<true, 1> {
56 : using type = tmpl::list<PolytropicFluid<true>, PiecewisePolytropicFluid<true>,
57 : Spectral, Enthalpy<PolytropicFluid<true>>,
58 : Enthalpy<Enthalpy<PolytropicFluid<true>>>,
59 : Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>,
60 : Enthalpy<Spectral>, Enthalpy<Enthalpy<Spectral>>,
61 : Enthalpy<Enthalpy<Enthalpy<Spectral>>>>;
62 : };
63 :
64 : template <>
65 : struct DerivedClasses<false, 1> {
66 : using type =
67 : tmpl::list<PolytropicFluid<false>, PiecewisePolytropicFluid<false>>;
68 : };
69 :
70 : template <>
71 : struct DerivedClasses<true, 2> {
72 : using type = tmpl::list<
73 : DarkEnergyFluid<true>, IdealFluid<true>,
74 : Barotropic2D<PolytropicFluid<true>>,
75 : Barotropic2D<PiecewisePolytropicFluid<true>>, Barotropic2D<Spectral>,
76 : Barotropic2D<Enthalpy<PolytropicFluid<true>>>,
77 : Barotropic2D<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>,
78 : Barotropic2D<Enthalpy<Spectral>>,
79 : Barotropic2D<Enthalpy<Enthalpy<Spectral>>>,
80 : Barotropic2D<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>,
81 : HybridEos<PolytropicFluid<true>>, HybridEos<Spectral>,
82 : HybridEos<Enthalpy<PolytropicFluid<true>>>,
83 : HybridEos<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>,
84 : HybridEos<Enthalpy<Spectral>>, HybridEos<Enthalpy<Enthalpy<Spectral>>>,
85 : HybridEos<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>>;
86 : };
87 :
88 : template <>
89 : struct DerivedClasses<false, 2> {
90 : using type =
91 : tmpl::list<IdealFluid<false>, Barotropic2D<PolytropicFluid<false>>,
92 : Barotropic2D<PiecewisePolytropicFluid<false>>,
93 : HybridEos<PolytropicFluid<false>>>;
94 : };
95 :
96 : template <>
97 : struct DerivedClasses<true, 3> {
98 : using type = tmpl::list<
99 : Tabulated3D<true>, Barotropic3D<PolytropicFluid<true>>,
100 : Barotropic3D<PiecewisePolytropicFluid<true>>, Barotropic3D<Spectral>,
101 : Barotropic3D<Enthalpy<PolytropicFluid<true>>>,
102 : Barotropic3D<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>,
103 : Barotropic3D<Enthalpy<Spectral>>,
104 : Barotropic3D<Enthalpy<Enthalpy<Spectral>>>,
105 : Barotropic3D<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>,
106 : Equilibrium3D<DarkEnergyFluid<true>>, Equilibrium3D<IdealFluid<true>>,
107 : Equilibrium3D<HybridEos<PolytropicFluid<true>>>,
108 : Equilibrium3D<HybridEos<Enthalpy<PolytropicFluid<true>>>>,
109 : Equilibrium3D<
110 : HybridEos<Enthalpy<Enthalpy<Enthalpy<PolytropicFluid<true>>>>>>,
111 : Equilibrium3D<HybridEos<Enthalpy<Spectral>>>,
112 : Equilibrium3D<HybridEos<Enthalpy<Enthalpy<Spectral>>>>,
113 : Equilibrium3D<HybridEos<Enthalpy<Enthalpy<Enthalpy<Spectral>>>>>,
114 : Equilibrium3D<HybridEos<Spectral>>>;
115 : };
116 :
117 : template <>
118 : struct DerivedClasses<false, 3> {
119 : using type =
120 : tmpl::list<Tabulated3D<false>, Barotropic3D<PolytropicFluid<false>>,
121 : Barotropic3D<PiecewisePolytropicFluid<false>>,
122 : Equilibrium3D<IdealFluid<false>>,
123 : Equilibrium3D<HybridEos<PolytropicFluid<false>>>>;
124 : };
125 :
126 : } // namespace detail
127 :
128 : /*!
129 : * \ingroup EquationsOfStateGroup
130 : * \brief Base class for equations of state depending on whether or not the
131 : * system is relativistic, and the number of independent thermodynamic variables
132 : * (`ThermodynamicDim`) needed to determine the pressure.
133 : *
134 : * The template parameter `IsRelativistic` is `true` for relativistic equations
135 : * of state and `false` for non-relativistic equations of state.
136 : */
137 : template <bool IsRelativistic, size_t ThermodynamicDim>
138 1 : class EquationOfState;
139 :
140 : template <typename T>
141 0 : struct get_eos_base_impl {
142 0 : using type = EquationsOfState::EquationOfState<T::is_relativistic,
143 : T::thermodynamic_dim>;
144 : };
145 :
146 : template <bool IsRelativistic, size_t ThermodynamicDim>
147 0 : struct get_eos_base_impl<
148 : EquationsOfState::EquationOfState<IsRelativistic, ThermodynamicDim>> {
149 0 : using type =
150 : EquationsOfState::EquationOfState<IsRelativistic, ThermodynamicDim>;
151 : };
152 :
153 : template <typename T>
154 0 : using get_eos_base = typename get_eos_base_impl<T>::type;
155 :
156 : /*!
157 : * \ingroup EquationsOfStateGroup
158 : * \brief Base class for equations of state which need one thermodynamic
159 : * variable in order to determine the pressure.
160 : *
161 : * The template parameter `IsRelativistic` is `true` for relativistic equations
162 : * of state and `false` for non-relativistic equations of state.
163 : */
164 : template <bool IsRelativistic>
165 1 : class EquationOfState<IsRelativistic, 1> : public PUP::able {
166 : public:
167 0 : static constexpr bool is_relativistic = IsRelativistic;
168 0 : static constexpr size_t thermodynamic_dim = 1;
169 0 : using creatable_classes =
170 : typename detail::DerivedClasses<IsRelativistic, 1>::type;
171 :
172 0 : EquationOfState() = default;
173 0 : EquationOfState(const EquationOfState&) = default;
174 0 : EquationOfState& operator=(const EquationOfState&) = default;
175 0 : EquationOfState(EquationOfState&&) = default;
176 0 : EquationOfState& operator=(EquationOfState&&) = default;
177 0 : ~EquationOfState() override = default;
178 :
179 0 : explicit EquationOfState(CkMigrateMessage* msg) : PUP::able(msg) {}
180 :
181 0 : WRAPPED_PUPable_abstract(EquationOfState); // NOLINT
182 :
183 0 : virtual std::unique_ptr<EquationOfState<IsRelativistic, 1>> get_clone()
184 : const = 0;
185 :
186 0 : virtual bool is_equal(
187 : const EquationOfState<IsRelativistic, 1>& rhs) const = 0;
188 :
189 : /// Create a 3D EOS from the 1D EOS
190 : virtual std::unique_ptr<EquationOfState<IsRelativistic, 3>>
191 1 : promote_to_3d_eos() const = 0;
192 :
193 : /// Create a 2D EOS from the 1D EOS
194 : virtual std::unique_ptr<EquationOfState<IsRelativistic, 2>>
195 1 : promote_to_2d_eos() const = 0;
196 :
197 : /// \brief Returns `true` if the EOS is barotropic
198 1 : bool is_barotropic() const { return true; }
199 : /// @{
200 : /*!
201 : * Computes the electron fraction in beta-equilibrium \f$Y_e^{\rm eq}\f$ from
202 : * the rest mass density \f$\rho\f$.
203 : */
204 1 : virtual Scalar<double> equilibrium_electron_fraction_from_density_temperature(
205 : const Scalar<double>& rest_mass_density,
206 : const Scalar<double>& /*temperature*/) const {
207 : return make_with_value<Scalar<double>>(rest_mass_density, 0.1);
208 : }
209 :
210 : virtual Scalar<DataVector>
211 1 : equilibrium_electron_fraction_from_density_temperature(
212 : const Scalar<DataVector>& rest_mass_density,
213 : const Scalar<DataVector>& /*temperature*/) const {
214 : return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.1);
215 : }
216 : /// @}
217 :
218 : /// @{
219 : /*!
220 : * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$.
221 : */
222 1 : virtual Scalar<double> pressure_from_density(
223 : const Scalar<double>& /*rest_mass_density*/) const = 0;
224 1 : virtual Scalar<DataVector> pressure_from_density(
225 : const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
226 : /// @}
227 :
228 : /// @{
229 : /*!
230 : * Computes the rest mass density \f$\rho\f$ from the specific enthalpy
231 : * \f$h\f$.
232 : */
233 1 : virtual Scalar<double> rest_mass_density_from_enthalpy(
234 : const Scalar<double>& /*specific_enthalpy*/) const = 0;
235 1 : virtual Scalar<DataVector> rest_mass_density_from_enthalpy(
236 : const Scalar<DataVector>& /*specific_enthalpy*/) const = 0;
237 : /// @}
238 :
239 : /// @{
240 : /*!
241 : * Computes the specific entropy \f$s\f$ from the rest mass density
242 : * \f$\rho\f$.
243 : */
244 1 : virtual Scalar<double> specific_entropy_from_density(
245 : const Scalar<double>& /*rest_mass_density*/) const {
246 : return Scalar<double>{0.0};
247 : }
248 1 : virtual Scalar<DataVector> specific_entropy_from_density(
249 : const Scalar<DataVector>& rest_mass_density) const {
250 : return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.0);
251 : }
252 : /// @}
253 :
254 : /// @{
255 : /*!
256 : * Computes the specific entropy \f$s\f$ from the specific internal energy
257 : * \f$\epsilon\f$.
258 : */
259 1 : virtual Scalar<double> specific_entropy_from_specific_internal_energy(
260 : const Scalar<double>& /*specific_internal_energy*/) const {
261 : return Scalar<double>{0.0};
262 : }
263 1 : virtual Scalar<DataVector> specific_entropy_from_specific_internal_energy(
264 : const Scalar<DataVector>& specific_internal_energy) const {
265 : return make_with_value<Scalar<DataVector>>(specific_internal_energy, 0.0);
266 : }
267 : /// @}
268 :
269 : /// @{
270 : /*!
271 : * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
272 : * density \f$\rho\f$.
273 : */
274 1 : virtual Scalar<double> specific_internal_energy_from_density(
275 : const Scalar<double>& /*rest_mass_density*/) const = 0;
276 1 : virtual Scalar<DataVector> specific_internal_energy_from_density(
277 : const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
278 : /// @}
279 :
280 : /// @{
281 : /*!
282 : * Computes the temperature \f$T\f$ from the rest mass
283 : * density \f$\rho\f$.
284 : */
285 1 : virtual Scalar<double> temperature_from_density(
286 : const Scalar<double>& /*rest_mass_density*/) const {
287 : return Scalar<double>{0.0};
288 : }
289 1 : virtual Scalar<DataVector> temperature_from_density(
290 : const Scalar<DataVector>& rest_mass_density) const {
291 : return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.0);
292 : }
293 : /// @}
294 :
295 : /// @{
296 : /*!
297 : * Computes the temperature \f$\T\f$ from the specific internal energy
298 : * \f$\epsilon\f$.
299 : */
300 1 : virtual Scalar<double> temperature_from_specific_internal_energy(
301 : const Scalar<double>& /*specific_internal_energy*/) const {
302 : return Scalar<double>{0.0};
303 : }
304 1 : virtual Scalar<DataVector> temperature_from_specific_internal_energy(
305 : const Scalar<DataVector>& specific_internal_energy) const {
306 : return make_with_value<Scalar<DataVector>>(specific_internal_energy, 0.0);
307 : }
308 : /// @}
309 :
310 : /// @{
311 : /*!
312 : * Computes \f$\chi=\partial p / \partial \rho\f$ from \f$\rho\f$, where
313 : * \f$p\f$ is the pressure and \f$\rho\f$ is the rest mass density.
314 : */
315 1 : virtual Scalar<double> chi_from_density(
316 : const Scalar<double>& /*rest_mass_density*/) const = 0;
317 1 : virtual Scalar<DataVector> chi_from_density(
318 : const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
319 : /// @}
320 :
321 : /// @{
322 : /*!
323 : * Computes \f$\kappa p/\rho^2=(p/\rho^2)\partial p / \partial \epsilon\f$
324 : * from \f$\rho\f$, where \f$p\f$ is the pressure, \f$\rho\f$ is the rest mass
325 : * density, and \f$\epsilon\f$ is the specific internal energy.
326 : *
327 : * The reason for not returning just
328 : * \f$\kappa=\partial p / \partial \epsilon\f$ is to avoid division by zero
329 : * for small values of \f$\rho\f$ when assembling the speed of sound with
330 : * some equations of state.
331 : */
332 1 : virtual Scalar<double> kappa_times_p_over_rho_squared_from_density(
333 : const Scalar<double>& /*rest_mass_density*/) const = 0;
334 1 : virtual Scalar<DataVector> kappa_times_p_over_rho_squared_from_density(
335 : const Scalar<DataVector>& /*rest_mass_density*/) const = 0;
336 :
337 : /// The lower bound of the electron fraction that is valid for this EOS
338 1 : virtual double electron_fraction_lower_bound() const { return 0.0; }
339 :
340 : /// The upper bound of the electron fraction that is valid for this EOS
341 1 : virtual double electron_fraction_upper_bound() const { return 1.0; }
342 :
343 : /// The lower bound of the rest mass density that is valid for this EOS
344 1 : virtual double rest_mass_density_lower_bound() const = 0;
345 :
346 : /// The upper bound of the rest mass density that is valid for this EOS
347 1 : virtual double rest_mass_density_upper_bound() const = 0;
348 :
349 : /// The lower bound of the temperature that is valid for this EOS
350 1 : virtual double temperature_lower_bound() const { return 0.0; };
351 :
352 : /// The upper bound of the temperature that is valid for this EOS
353 1 : virtual double temperature_upper_bound() const {
354 : return std::numeric_limits<double>::max();
355 : };
356 :
357 : /// The lower bound of the specific internal energy that is valid for this EOS
358 1 : virtual double specific_internal_energy_lower_bound() const { return 0.0; };
359 :
360 : /// The upper bound of the specific internal energy that is valid for this EOS
361 1 : virtual double specific_internal_energy_upper_bound() const {
362 : return std::numeric_limits<double>::max();
363 : };
364 :
365 : /// The lower bound of the specific enthalpy that is valid for this EOS
366 1 : virtual double specific_enthalpy_lower_bound() const = 0;
367 :
368 : /// The vacuum mass of a baryon for this EOS
369 1 : virtual double baryon_mass() const {
370 : return hydro::units::geometric::default_baryon_mass;
371 : }
372 : };
373 :
374 : /*!
375 : * \ingroup EquationsOfStateGroup
376 : * \brief Base class for equations of state which need two independent
377 : * thermodynamic variables in order to determine the pressure.
378 : *
379 : * The template parameter `IsRelativistic` is `true` for relativistic equations
380 : * of state and `false` for non-relativistic equations of state.
381 : */
382 : template <bool IsRelativistic>
383 1 : class EquationOfState<IsRelativistic, 2> : public PUP::able {
384 : public:
385 0 : static constexpr bool is_relativistic = IsRelativistic;
386 0 : static constexpr size_t thermodynamic_dim = 2;
387 0 : using creatable_classes =
388 : typename detail::DerivedClasses<IsRelativistic, 2>::type;
389 :
390 0 : EquationOfState() = default;
391 0 : EquationOfState(const EquationOfState&) = default;
392 0 : EquationOfState& operator=(const EquationOfState&) = default;
393 0 : EquationOfState(EquationOfState&&) = default;
394 0 : EquationOfState& operator=(EquationOfState&&) = default;
395 0 : ~EquationOfState() override = default;
396 :
397 0 : explicit EquationOfState(CkMigrateMessage* msg) : PUP::able(msg) {}
398 :
399 0 : WRAPPED_PUPable_abstract(EquationOfState); // NOLINT
400 :
401 0 : virtual inline std::unique_ptr<EquationOfState<IsRelativistic, 2>> get_clone()
402 : const = 0;
403 :
404 0 : virtual bool is_equal(
405 : const EquationOfState<IsRelativistic, 2>& rhs) const = 0;
406 :
407 : virtual std::unique_ptr<EquationOfState<IsRelativistic, 2>>
408 0 : promote_to_2d_eos() const {
409 : return this->get_clone();
410 : }
411 :
412 : virtual std::unique_ptr<EquationOfState<IsRelativistic, 3>>
413 0 : promote_to_3d_eos() const = 0;
414 :
415 : /// \brief Returns `true` if the EOS is barotropic
416 1 : virtual bool is_barotropic() const = 0;
417 :
418 : /// \brief Returns `true` if the EOS is in beta-equilibrium
419 1 : virtual bool is_equilibrium() const { return true; }
420 :
421 : /// @{
422 : /*!
423 : * Computes the electron fraction in beta-equilibrium \f$Y_e^{\rm eq}\f$ from
424 : * the rest mass density \f$\rho\f$ and the temperature \f$T\f$.
425 : */
426 1 : virtual Scalar<double> equilibrium_electron_fraction_from_density_temperature(
427 : const Scalar<double>& rest_mass_density,
428 : const Scalar<double>& /*temperature*/) const {
429 : return make_with_value<Scalar<double>>(rest_mass_density, 0.1);
430 : }
431 :
432 : virtual Scalar<DataVector>
433 1 : equilibrium_electron_fraction_from_density_temperature(
434 : const Scalar<DataVector>& rest_mass_density,
435 : const Scalar<DataVector>& /*temperature*/) const {
436 : return make_with_value<Scalar<DataVector>>(rest_mass_density, 0.1);
437 : }
438 : /// @}
439 :
440 : /// @{
441 : /*!
442 : * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$ and the
443 : * specific internal energy \f$\epsilon\f$.
444 : */
445 1 : virtual Scalar<double> pressure_from_density_and_energy(
446 : const Scalar<double>& /*rest_mass_density*/,
447 : const Scalar<double>& /*specific_internal_energy*/) const = 0;
448 1 : virtual Scalar<DataVector> pressure_from_density_and_energy(
449 : const Scalar<DataVector>& /*rest_mass_density*/,
450 : const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
451 : /// @}
452 :
453 : /// @{
454 : /*!
455 : * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$ and the
456 : * specific enthalpy \f$h\f$.
457 : */
458 1 : virtual Scalar<double> pressure_from_density_and_enthalpy(
459 : const Scalar<double>& /*rest_mass_density*/,
460 : const Scalar<double>& /*specific_enthalpy*/) const = 0;
461 1 : virtual Scalar<DataVector> pressure_from_density_and_enthalpy(
462 : const Scalar<DataVector>& /*rest_mass_density*/,
463 : const Scalar<DataVector>& /*specific_enthalpy*/) const = 0;
464 : /// @}
465 :
466 : /// @{
467 : /*!
468 : * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
469 : * and the specific internal energy \f$\epsilon\f$.
470 : */
471 1 : virtual Scalar<double> specific_entropy_from_density_and_energy(
472 : const Scalar<double>& /*rest_mass_density*/,
473 : const Scalar<double>& /*specific_internal_energy*/) const = 0;
474 :
475 1 : virtual Scalar<DataVector> specific_entropy_from_density_and_energy(
476 : const Scalar<DataVector>& /*rest_mass_density*/,
477 : const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
478 : /// @}
479 :
480 : /// @{
481 : /*!
482 : * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
483 : * and the temperature \f$T\f$.
484 : */
485 1 : virtual Scalar<double> specific_entropy_from_density_and_temperature(
486 : const Scalar<double>& /*rest_mass_density*/,
487 : const Scalar<double>& /*temperature*/) const = 0;
488 :
489 1 : virtual Scalar<DataVector> specific_entropy_from_density_and_temperature(
490 : const Scalar<DataVector>& /*rest_mass_density*/,
491 : const Scalar<DataVector>& /*temperature*/) const = 0;
492 : /// @}
493 :
494 : /// @{
495 : /*!
496 : * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
497 : * density \f$\rho\f$ and the pressure \f$p\f$.
498 : */
499 1 : virtual Scalar<double> specific_internal_energy_from_density_and_pressure(
500 : const Scalar<double>& /*rest_mass_density*/,
501 : const Scalar<double>& /*pressure*/) const = 0;
502 1 : virtual Scalar<DataVector> specific_internal_energy_from_density_and_pressure(
503 : const Scalar<DataVector>& /*rest_mass_density*/,
504 : const Scalar<DataVector>& /*pressure*/) const = 0;
505 : /// @}
506 :
507 : /// @{
508 : /*!
509 : * Computes the temperature \f$T\f$ from the rest mass
510 : * density \f$\rho\f$ and the specific internal energy \f$\epsilon\f$.
511 : */
512 1 : virtual Scalar<double> temperature_from_density_and_energy(
513 : const Scalar<double>& /*rest_mass_density*/,
514 : const Scalar<double>& /*specific_internal_energy*/) const = 0;
515 1 : virtual Scalar<DataVector> temperature_from_density_and_energy(
516 : const Scalar<DataVector>& /*rest_mass_density*/,
517 : const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
518 : /// @}
519 :
520 : /// @{
521 : /*!
522 : * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
523 : * density \f$\rho\f$ and the temperature \f$T\f$.
524 : */
525 1 : virtual Scalar<double> specific_internal_energy_from_density_and_temperature(
526 : const Scalar<double>& /*rest_mass_density*/,
527 : const Scalar<double>& /*temperature*/) const = 0;
528 : virtual Scalar<DataVector>
529 1 : specific_internal_energy_from_density_and_temperature(
530 : const Scalar<DataVector>& /*rest_mass_density*/,
531 : const Scalar<DataVector>& /*temperature*/) const = 0;
532 : /// @}
533 :
534 : /// @{
535 : /*!
536 : * Computes \f$\chi=\partial p / \partial \rho |_{\epsilon}\f$ from the
537 : * \f$\rho\f$ and \f$\epsilon\f$, where \f$p\f$ is the pressure, \f$\rho\f$ is
538 : * the rest mass density, and \f$\epsilon\f$ is the specific internal energy.
539 : */
540 1 : virtual Scalar<double> chi_from_density_and_energy(
541 : const Scalar<double>& /*rest_mass_density*/,
542 : const Scalar<double>& /*specific_internal_energy*/) const = 0;
543 1 : virtual Scalar<DataVector> chi_from_density_and_energy(
544 : const Scalar<DataVector>& /*rest_mass_density*/,
545 : const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
546 : /// @}
547 :
548 : /// @{
549 : /*!
550 : * Computes \f$\kappa p/\rho^2=(p/\rho^2)\partial p / \partial \epsilon
551 : * |_{\rho}\f$ from \f$\rho\f$ and \f$\epsilon\f$, where \f$p\f$ is the
552 : * pressure, \f$\rho\f$ is the rest mass density, and \f$\epsilon\f$ is the
553 : * specific internal energy.
554 : *
555 : * The reason for not returning just
556 : * \f$\kappa=\partial p / \partial \epsilon\f$ is to avoid division by zero
557 : * for small values of \f$\rho\f$ when assembling the speed of sound with
558 : * some equations of state.
559 : */
560 1 : virtual Scalar<double> kappa_times_p_over_rho_squared_from_density_and_energy(
561 : const Scalar<double>& /*rest_mass_density*/,
562 : const Scalar<double>& /*specific_internal_energy*/) const = 0;
563 : virtual Scalar<DataVector>
564 1 : kappa_times_p_over_rho_squared_from_density_and_energy(
565 : const Scalar<DataVector>& /*rest_mass_density*/,
566 : const Scalar<DataVector>& /*specific_internal_energy*/) const = 0;
567 : /// @}
568 :
569 : /// The lower bound of the electron fraction that is valid for this EOS
570 1 : virtual double electron_fraction_lower_bound() const { return 0.0; }
571 :
572 : /// The upper bound of the electron fraction that is valid for this EOS
573 1 : virtual double electron_fraction_upper_bound() const { return 1.0; }
574 :
575 : /// The lower bound of the rest mass density that is valid for this EOS
576 1 : virtual double rest_mass_density_lower_bound() const = 0;
577 :
578 : /// The upper bound of the rest mass density that is valid for this EOS
579 1 : virtual double rest_mass_density_upper_bound() const = 0;
580 :
581 : /// The lower bound of the specific internal energy that is valid for this EOS
582 : /// at the given rest mass density \f$\rho\f$
583 1 : virtual double specific_internal_energy_lower_bound(
584 : const double rest_mass_density) const = 0;
585 :
586 : /// The upper bound of the specific internal energy that is valid for this EOS
587 : /// at the given rest mass density \f$\rho\f$
588 1 : virtual double specific_internal_energy_upper_bound(
589 : const double rest_mass_density) const = 0;
590 :
591 : /// The lower bound of the temperature that is valid for this EOS
592 1 : virtual double temperature_lower_bound() const { return 0.0; };
593 :
594 : /// The upper bound of the temperature that is valid for this EOS
595 1 : virtual double temperature_upper_bound() const {
596 : return std::numeric_limits<double>::max();
597 : };
598 :
599 : /// The lower bound of the specific enthalpy that is valid for this EOS
600 1 : virtual double specific_enthalpy_lower_bound() const = 0;
601 :
602 : /// The vacuum mass of a baryon for this EOS
603 1 : virtual double baryon_mass() const {
604 : return hydro::units::geometric::default_baryon_mass;
605 : }
606 : };
607 :
608 : /*!
609 : * \ingroup EquationsOfStateGroup
610 : * \brief Base class for equations of state which need three independent
611 : * thermodynamic variables in order to determine the pressure.
612 : *
613 : * The template parameter `IsRelativistic` is `true` for relativistic equations
614 : * of state and `false` for non-relativistic equations of state.
615 : */
616 : template <bool IsRelativistic>
617 : class EquationOfState<IsRelativistic, 3> : public PUP::able {
618 : public:
619 : static constexpr bool is_relativistic = IsRelativistic;
620 : static constexpr size_t thermodynamic_dim = 3;
621 : using creatable_classes =
622 : typename detail::DerivedClasses<IsRelativistic, 3>::type;
623 :
624 : EquationOfState() = default;
625 : EquationOfState(const EquationOfState&) = default;
626 : EquationOfState& operator=(const EquationOfState&) = default;
627 : EquationOfState(EquationOfState&&) = default;
628 : EquationOfState& operator=(EquationOfState&&) = default;
629 : ~EquationOfState() override = default;
630 :
631 : explicit EquationOfState(CkMigrateMessage* msg) : PUP::able(msg) {}
632 :
633 : WRAPPED_PUPable_abstract(EquationOfState); // NOLINT
634 :
635 : virtual inline std::unique_ptr<EquationOfState<IsRelativistic, 3>> get_clone()
636 : const = 0;
637 :
638 : virtual bool is_equal(
639 : const EquationOfState<IsRelativistic, 3>& rhs) const = 0;
640 :
641 : virtual std::unique_ptr<EquationOfState<IsRelativistic, 3>>
642 : promote_to_3d_eos() const {
643 : return this->get_clone();
644 : }
645 :
646 : /// \brief Returns `true` if the EOS is barotropic
647 : virtual bool is_barotropic() const = 0;
648 :
649 : /// \brief Returns `true` if the EOS is in beta-equilibrium
650 : virtual bool is_equilibrium() const = 0;
651 :
652 : /// @{
653 : /*!
654 : * Computes the electron fraction in beta-equilibrium \f$Y_e^{\rm eq}\f$ from
655 : * the rest mass density \f$\rho\f$ and the temperature \f$T\f$.
656 : */
657 : virtual Scalar<double> equilibrium_electron_fraction_from_density_temperature(
658 : const Scalar<double>& /*rest_mass_density*/,
659 : const Scalar<double>& /*temperature*/) const = 0;
660 :
661 : virtual Scalar<DataVector>
662 : equilibrium_electron_fraction_from_density_temperature(
663 : const Scalar<DataVector>& /*rest_mass_density*/,
664 : const Scalar<DataVector>& /*temperature*/) const = 0;
665 : /// @}
666 :
667 : /// @{
668 : /*!
669 : * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$, the
670 : * specific internal energy \f$\epsilon\f$ and electron fraction \f$Y_e\f$.
671 : */
672 : virtual Scalar<double> pressure_from_density_and_energy(
673 : const Scalar<double>& /*rest_mass_density*/,
674 : const Scalar<double>& /*specific_internal_energy*/,
675 : const Scalar<double>& /*electron_fraction*/) const = 0;
676 : virtual Scalar<DataVector> pressure_from_density_and_energy(
677 : const Scalar<DataVector>& /*rest_mass_density*/,
678 : const Scalar<DataVector>& /*specific_internal_energy*/,
679 : const Scalar<DataVector>& /*electron_fraction*/) const = 0;
680 : /// @}
681 :
682 : /// @{
683 : /*!
684 : * Computes the pressure \f$p\f$ from the rest mass density \f$\rho\f$, the
685 : * temperature \f$T\f$, and electron fraction \f$Y_e\f$.
686 : */
687 : virtual Scalar<double> pressure_from_density_and_temperature(
688 : const Scalar<double>& /*rest_mass_density*/,
689 : const Scalar<double>& /*temperature*/,
690 : const Scalar<double>& /*electron_fraction*/) const = 0;
691 : virtual Scalar<DataVector> pressure_from_density_and_temperature(
692 : const Scalar<DataVector>& /*rest_mass_density*/,
693 : const Scalar<DataVector>& /*temperature*/,
694 : const Scalar<DataVector>& /*electron_fraction*/) const = 0;
695 : /// @}
696 :
697 : /// @{
698 : /*!
699 : * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
700 : * and the specific internal energy \f$\epsilon\f$ and electron fraction
701 : * \f$Y_e\f$.
702 : */
703 : virtual Scalar<double> specific_entropy_from_density_and_energy(
704 : const Scalar<double>& /*rest_mass_density*/,
705 : const Scalar<double>& /*specific_internal_energy*/,
706 : const Scalar<double>& /*electron_fraction*/) const = 0;
707 :
708 : virtual Scalar<DataVector> specific_entropy_from_density_and_energy(
709 : const Scalar<DataVector>& /*rest_mass_density*/,
710 : const Scalar<DataVector>& /*specific_internal_energy*/,
711 : const Scalar<DataVector>& /*electron_fraction*/) const = 0;
712 : /// @}
713 :
714 : /// @{
715 : /*!
716 : * Computes the specific entropy \f$s\f$ from the rest mass density \f$\rho\f$
717 : * and the temperature \f$T\f$ and electron fraction \f$Y_e\f$.
718 : */
719 : virtual Scalar<double> specific_entropy_from_density_and_temperature(
720 : const Scalar<double>& /*rest_mass_density*/,
721 : const Scalar<double>& /*temperature*/,
722 : const Scalar<double>& /*electron_fraction*/) const = 0;
723 :
724 : virtual Scalar<DataVector> specific_entropy_from_density_and_temperature(
725 : const Scalar<DataVector>& /*rest_mass_density*/,
726 : const Scalar<DataVector>& /*temperature*/,
727 : const Scalar<DataVector>& /*electron_fraction*/) const = 0;
728 : /// @}
729 :
730 : /// @{
731 : /*!
732 : * Computes the temperature \f$T\f$ from the rest mass
733 : * density \f$\rho\f$, the specific internal energy \f$\epsilon\f$,
734 : * and electron fraction \f$Y_e\f$.
735 : */
736 : virtual Scalar<double> temperature_from_density_and_energy(
737 : const Scalar<double>& /*rest_mass_density*/,
738 : const Scalar<double>& /*specific_internal_energy*/,
739 : const Scalar<double>& /*electron_fraction*/) const = 0;
740 : virtual Scalar<DataVector> temperature_from_density_and_energy(
741 : const Scalar<DataVector>& /*rest_mass_density*/,
742 : const Scalar<DataVector>& /*specific_internal_energy*/,
743 : const Scalar<DataVector>& /*electron_fraction*/) const = 0;
744 : /// @}
745 :
746 : /// @{
747 : /*!
748 : * Computes the specific internal energy \f$\epsilon\f$ from the rest mass
749 : * density \f$\rho\f$, the temperature \f$T\f$, and electron fraction
750 : * \f$Y_e\f$.
751 : */
752 : virtual Scalar<double> specific_internal_energy_from_density_and_temperature(
753 : const Scalar<double>& /*rest_mass_density*/,
754 : const Scalar<double>& /*temperature*/,
755 : const Scalar<double>& /*electron_fraction*/
756 : ) const = 0;
757 : virtual Scalar<DataVector>
758 : specific_internal_energy_from_density_and_temperature(
759 : const Scalar<DataVector>& /*rest_mass_density*/,
760 : const Scalar<DataVector>& /*temperature*/,
761 : const Scalar<DataVector>& /*electron_fraction*/
762 : ) const = 0;
763 : /// @}
764 :
765 : /// @{
766 : /*!
767 : * Computes adiabatic sound speed squared
768 : * \f[
769 : * c_s^2 \equiv \frac{\partial p}{\partial e} |_{s, Y_e} =
770 : * \frac{\rho}{h}\frac{\partial p}{\partial \rho} |_{e, Y_e} +
771 : * \frac{\partial p}{\partial e}|_{\rho, Y_e}
772 : * \f].
773 : * With \f$p, e\f$ the pressure and energy density respectively,
774 : * \f$s\f$ the entropy density, \f$Y_e\f$ the electron fraction
775 : * \f$\rho\f$ the rest-mass density, and \f$h\f$ the enthalpy density.
776 : * Note that \f$e\f$ is the total energy density and not the internal energy,
777 : * therefore
778 : * \f[
779 : * \frac{\partial p}{\partial \rho} |_{e, Y_e} \neq \chi \equiv \frac{\partial
780 : * p}{\partial \rho} |_{\epsilon, Y_e}
781 : * \f]
782 : * as defined in the 2-d EoS above. By definition
783 : * \f$ e = (1+\epsilon) \rho \f$ so holding \f$e\f$ constant
784 : * \f[
785 : * 0 = \frac{d e}{d \rho} = \frac{\partial e}{\partial \rho} +
786 : * \frac{\partial e}{\partial \epsilon} \frac{\partial \epsilon}{\rho}.
787 : * \f]
788 : * (where we have suppressed \f$ Y_e\f$ dependence)
789 : * So \f$ \partial \epsilon / \partial \rho |_{e} = (1 + \epsilon)/\rho \f$
790 : * and we can expand
791 : * \f[
792 : * \frac{\partial p}{\partial \rho} |_{e, Y_e} = \frac{\partial e}{\partial
793 : * \rho}_{\epsilon, Y_e} + \frac{(1 + \epsilon)}{\rho} \frac{\partial
794 : * e}{\partial \epsilon}|_{\rho, Y_e}
795 : * \f]
796 : * Finally, we can rewrite the entire sound speed using only the rest-mass
797 : * density, specific internal energy, and electron fraction as variables,
798 : * by using \f$ \frac{\partial e}{\partial \epsilon}|_{\rho, Y_e} = 1 \f$
799 : * \f[
800 : * c_s^2 =
801 : * \frac{\rho}{h}\frac{\partial p}{\partial \rho} |_{\epsilon, Y_e} +
802 : * \frac{1}{\rho} \frac{\partial p}{\partial \epsilon}|_{\rho, Y_e} \left(
803 : * 1 - \frac{(1 + \epsilon)\rho}{h}\right)
804 : * \f]
805 : * Which reduces to our preferred form
806 : * \f[
807 : * c_s^2 =
808 : * \frac{\rho}{h}(\chi + \kappa)
809 : * \f]
810 : *
811 : * Computed as a function of temperature, rest-mass density and electron
812 : * fraction. Note that this will break thermodynamic consistency if the
813 : * pressure and internal energy interpolated separately. The precise impact of
814 : * this will depend on the EoS and numerical scheme used for the evolution.
815 : */
816 : virtual Scalar<double> sound_speed_squared_from_density_and_temperature(
817 : const Scalar<double>& /*rest_mass_density*/,
818 : const Scalar<double>& /*temperature*/,
819 : const Scalar<double>& /*electron_fraction*/) const = 0;
820 : virtual Scalar<DataVector> sound_speed_squared_from_density_and_temperature(
821 : const Scalar<DataVector>& /*rest_mass_density*/,
822 : const Scalar<DataVector>& /*temperature*/,
823 : const Scalar<DataVector>& /*electron_fraction*/) const = 0;
824 : /// @}
825 :
826 : /// The lower bound of the electron fraction that is valid for this EOS
827 : virtual double electron_fraction_lower_bound() const = 0;
828 :
829 : /// The upper bound of the electron fraction that is valid for this EOS
830 : virtual double electron_fraction_upper_bound() const = 0;
831 :
832 : /// The lower bound of the rest mass density that is valid for this EOS
833 : virtual double rest_mass_density_lower_bound() const = 0;
834 :
835 : /// The upper bound of the rest mass density that is valid for this EOS
836 : virtual double rest_mass_density_upper_bound() const = 0;
837 :
838 : /// The lower bound of the specific internal energy that is valid for this EOS
839 : /// at the given rest mass density \f$\rho\f$ and electron fraction \f$Y_e\f$.
840 : virtual double specific_internal_energy_lower_bound(
841 : const double rest_mass_density, const double electron_fraction) const = 0;
842 :
843 : /// The upper bound of the specific internal energy that is valid for this EOS
844 : /// at the given rest mass density \f$\rho\f$ and electron fraction \f$Y_e\f$.
845 : virtual double specific_internal_energy_upper_bound(
846 : const double rest_mass_density, const double electron_fraction) const = 0;
847 :
848 : /// The lower bound of the specific enthalpy that is valid for this EOS
849 : virtual double specific_enthalpy_lower_bound() const = 0;
850 :
851 : /// The lower bound of the temperature that is valid for this EOS
852 : virtual double temperature_lower_bound() const = 0;
853 :
854 : /// The upper bound of the temperature that is valid for this EOS
855 : virtual double temperature_upper_bound() const = 0;
856 :
857 : /// The vacuum mass of a baryon for this EOS
858 : virtual double baryon_mass() const {
859 : return hydro::units::geometric::default_baryon_mass;
860 : }
861 : };
862 :
863 : /// Compare two equations of state for equality
864 : template <bool IsRelLhs, bool IsRelRhs, size_t ThermoDimLhs,
865 : size_t ThermoDimRhs>
866 1 : bool operator==(const EquationOfState<IsRelLhs, ThermoDimLhs>& lhs,
867 : const EquationOfState<IsRelRhs, ThermoDimRhs>& rhs) {
868 : if constexpr (IsRelLhs == IsRelRhs and ThermoDimLhs == ThermoDimRhs) {
869 : return typeid(lhs) == typeid(rhs) and lhs.is_equal(rhs);
870 : } else {
871 : return false;
872 : }
873 : }
874 : template <bool IsRelLhs, bool IsRelRhs, size_t ThermoDimLhs,
875 : size_t ThermoDimRhs>
876 0 : bool operator!=(const EquationOfState<IsRelLhs, ThermoDimLhs>& lhs,
877 : const EquationOfState<IsRelRhs, ThermoDimRhs>& rhs) {
878 : return not(lhs == rhs);
879 : }
880 : } // namespace EquationsOfState
881 :
882 : /// \cond
883 : #define EQUATION_OF_STATE_FUNCTIONS_1D \
884 : (pressure_from_density, rest_mass_density_from_enthalpy, \
885 : specific_internal_energy_from_density, chi_from_density, \
886 : kappa_times_p_over_rho_squared_from_density)
887 :
888 : #define EQUATION_OF_STATE_FUNCTIONS_2D \
889 : (pressure_from_density_and_energy, pressure_from_density_and_enthalpy, \
890 : specific_entropy_from_density_and_energy, \
891 : specific_entropy_from_density_and_temperature, \
892 : specific_internal_energy_from_density_and_pressure, \
893 : temperature_from_density_and_energy, \
894 : specific_internal_energy_from_density_and_temperature, \
895 : chi_from_density_and_energy, \
896 : kappa_times_p_over_rho_squared_from_density_and_energy)
897 :
898 : #define EQUATION_OF_STATE_FUNCTIONS_3D \
899 : (pressure_from_density_and_energy, pressure_from_density_and_temperature, \
900 : specific_entropy_from_density_and_energy, \
901 : specific_entropy_from_density_and_temperature, \
902 : temperature_from_density_and_energy, \
903 : specific_internal_energy_from_density_and_temperature, \
904 : sound_speed_squared_from_density_and_temperature)
905 :
906 : #define EQUATION_OF_STATE_ARGUMENTS_EXPAND(z, n, type) \
907 : BOOST_PP_COMMA_IF(n) const Scalar<type>&
908 :
909 : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS_HELPER(r, DIM, \
910 : FUNCTION_NAME) \
911 : Scalar<double> FUNCTION_NAME(BOOST_PP_REPEAT( \
912 : DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND, double)) const override; \
913 : Scalar<DataVector> FUNCTION_NAME(BOOST_PP_REPEAT( \
914 : DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND, DataVector)) const override;
915 :
916 : /// \endcond
917 :
918 : /*!
919 : * \ingroup EquationsOfStateGroup
920 : * \brief Macro used to generate forward declarations of member functions in
921 : * derived classes
922 : */
923 1 : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS(DERIVED, DIM) \
924 : BOOST_PP_LIST_FOR_EACH( \
925 : EQUATION_OF_STATE_FORWARD_DECLARE_MEMBERS_HELPER, DIM, \
926 : BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM( \
927 : BOOST_PP_SUB(DIM, 1), \
928 : (EQUATION_OF_STATE_FUNCTIONS_1D, EQUATION_OF_STATE_FUNCTIONS_2D, \
929 : EQUATION_OF_STATE_FUNCTIONS_3D)))) \
930 : \
931 : /* clang-tidy: do not use non-const references */ \
932 : void pup(PUP::er& p) override; /* NOLINT */ \
933 : \
934 : explicit DERIVED(CkMigrateMessage* msg);
935 :
936 : /// \cond
937 : #define EQUATION_OF_STATE_FORWARD_ARGUMENTS(z, n, unused) \
938 : BOOST_PP_COMMA_IF(n) arg##n
939 :
940 : #define EQUATION_OF_STATE_ARGUMENTS_EXPAND_NAMED(z, n, type) \
941 : BOOST_PP_COMMA_IF(n) const Scalar<type>& arg##n
942 :
943 : #define EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER( \
944 : TEMPLATE, DERIVED, DATA_TYPE, DIM, FUNCTION_NAME) \
945 : TEMPLATE \
946 : Scalar<DATA_TYPE> DERIVED::FUNCTION_NAME(BOOST_PP_REPEAT( \
947 : DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND_NAMED, DATA_TYPE)) const { \
948 : return FUNCTION_NAME##_impl( \
949 : BOOST_PP_REPEAT(DIM, EQUATION_OF_STATE_FORWARD_ARGUMENTS, UNUSED)); \
950 : }
951 :
952 : #define EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER_2(r, ARGS, FUNCTION_NAME) \
953 : EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER( \
954 : BOOST_PP_TUPLE_ELEM(0, ARGS), BOOST_PP_TUPLE_ELEM(1, ARGS), \
955 : BOOST_PP_TUPLE_ELEM(2, ARGS), BOOST_PP_TUPLE_ELEM(3, ARGS), \
956 : FUNCTION_NAME)
957 : /// \endcond
958 :
959 : #define EQUATION_OF_STATE_MEMBER_DEFINITIONS(TEMPLATE, DERIVED, DATA_TYPE, \
960 0 : DIM) \
961 : BOOST_PP_LIST_FOR_EACH( \
962 : EQUATION_OF_STATE_MEMBER_DEFINITIONS_HELPER_2, \
963 : (TEMPLATE, DERIVED, DATA_TYPE, DIM), \
964 : BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM( \
965 : BOOST_PP_SUB(DIM, 1), \
966 : (EQUATION_OF_STATE_FUNCTIONS_1D, EQUATION_OF_STATE_FUNCTIONS_2D, \
967 : EQUATION_OF_STATE_FUNCTIONS_3D))))
968 :
969 : /// \cond
970 : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS_HELPER(r, DIM, \
971 : FUNCTION_NAME) \
972 : template <class DataType> \
973 : Scalar<DataType> FUNCTION_NAME##_impl(BOOST_PP_REPEAT( \
974 : DIM, EQUATION_OF_STATE_ARGUMENTS_EXPAND, DataType)) const;
975 : /// \endcond
976 :
977 0 : #define EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS(DIM) \
978 : BOOST_PP_LIST_FOR_EACH( \
979 : EQUATION_OF_STATE_FORWARD_DECLARE_MEMBER_IMPLS_HELPER, DIM, \
980 : BOOST_PP_TUPLE_TO_LIST(BOOST_PP_TUPLE_ELEM( \
981 : BOOST_PP_SUB(DIM, 1), \
982 : (EQUATION_OF_STATE_FUNCTIONS_1D, EQUATION_OF_STATE_FUNCTIONS_2D, \
983 : EQUATION_OF_STATE_FUNCTIONS_3D))))
|