Files
MeanField/libmeanfield/interface/material/thermodynamic_equations.cppm
2026-09-04 07:54:10 -04:00

272 lines
13 KiB
C++

module;
#include <concepts>
#include <type_traits>
export module mean_field:material.thermodynamic_equations;
export import :eos.polytrope;
export import :surface.compiler;
export import :utils.blocks;
export namespace mean_field::material {
/**
* A thermodynamic field identifies the physical quantity represented by
* its discrete degree of freedom. The quantity belongs to the field, not
* to an EOS-specific aggregate description.
*/
template <typename Candidate>
concept ThermodynamicField = surface::SurfaceFieldType<Candidate> && requires {
typename std::remove_cvref_t<Candidate>::PhysicalQuantity;
requires eos::ThermodynamicQuantityType<typename std::remove_cvref_t<Candidate>::PhysicalQuantity>;
};
/**
* Declares the algebraic blocks owned by one thermodynamic governing
* equation. Its physical quantity is inferred from Field.
*/
template <ThermodynamicField Field, typename CorrectionBlock, typename ResidualBlock>
requires std::derived_from<CorrectionBlock, utils::blocks::value_block_base> &&
std::derived_from<ResidualBlock, utils::blocks::residual_block_base>
struct ThermodynamicEquation final {
using FieldType = Field;
using PhysicalQuantity = typename Field::PhysicalQuantity;
using Correction = CorrectionBlock;
using Residual = ResidualBlock;
};
/**
* Registry of thermodynamic governing equations available to a problem.
* The problem form, rather than the registry, selects the active subset.
*/
template <typename... Equations> struct ThermodynamicEquationCatalog final {
static constexpr int size = sizeof...(Equations);
};
namespace detail {
template <typename Candidate> struct IsThermodynamicEquation : std::false_type { };
template <typename Field, typename CorrectionBlock, typename ResidualBlock>
struct IsThermodynamicEquation<ThermodynamicEquation<Field, CorrectionBlock, ResidualBlock>> : std::true_type {
};
template <typename Candidate> struct IsThermodynamicEquationCatalog : std::false_type { };
template <typename... Equations>
struct IsThermodynamicEquationCatalog<ThermodynamicEquationCatalog<Equations...>>
: std::bool_constant<(sizeof...(Equations) > 0) && (IsThermodynamicEquation<Equations>::value && ...)> { };
template <typename Catalog> struct CatalogEntriesAreUnique : std::false_type { };
template <typename... Equations>
struct CatalogEntriesAreUnique<ThermodynamicEquationCatalog<Equations...>>
: std::bool_constant<
utils::blocks::types_are_unique_v<utils::blocks::type_list<typename Equations::FieldType...>> &&
utils::blocks::types_are_unique_v<
utils::blocks::type_list<typename Equations::PhysicalQuantity...>> &&
utils::blocks::types_are_unique_v<utils::blocks::type_list<typename Equations::Correction...>> &&
utils::blocks::types_are_unique_v<utils::blocks::type_list<typename Equations::Residual...>>> { };
template <typename Catalog, typename Field> struct EquationForField;
template <typename Field, typename First, typename... Remaining>
struct EquationForField<ThermodynamicEquationCatalog<First, Remaining...>, Field>
: std::conditional_t<
std::same_as<Field, typename First::FieldType>,
std::type_identity<First>,
EquationForField<ThermodynamicEquationCatalog<Remaining...>, Field>> { };
template <typename Field> struct EquationForField<ThermodynamicEquationCatalog<>, Field> {
using type = void;
};
template <typename Catalog, typename Field> struct EquationFieldCount;
template <typename Field, typename... Equations>
struct EquationFieldCount<ThermodynamicEquationCatalog<Equations...>, Field>
: std::integral_constant<
int,
(int{0} + ... + (std::same_as<Field, typename Equations::FieldType> ? 1 : 0))> { };
template <typename Catalog, typename Correction> struct EquationForCorrection;
template <typename Correction, typename First, typename... Remaining>
struct EquationForCorrection<ThermodynamicEquationCatalog<First, Remaining...>, Correction>
: std::conditional_t<
std::same_as<Correction, typename First::Correction>,
std::type_identity<First>,
EquationForCorrection<ThermodynamicEquationCatalog<Remaining...>, Correction>> { };
template <typename Correction> struct EquationForCorrection<ThermodynamicEquationCatalog<>, Correction> {
using type = void;
};
template <typename Head, typename Catalog> struct PrependEquation;
template <typename Head, typename... Equations>
struct PrependEquation<Head, ThermodynamicEquationCatalog<Equations...>> {
using Type = ThermodynamicEquationCatalog<Head, Equations...>;
};
template <typename ValueBlocks, typename AvailableEquations> struct SelectActiveEquations;
template <typename AvailableEquations>
struct SelectActiveEquations<utils::blocks::type_list<>, AvailableEquations> {
using Type = ThermodynamicEquationCatalog<>;
};
template <typename FirstValue, typename... RemainingValues, typename AvailableEquations>
struct SelectActiveEquations<utils::blocks::type_list<FirstValue, RemainingValues...>, AvailableEquations> {
private:
using Tail =
typename SelectActiveEquations<utils::blocks::type_list<RemainingValues...>, AvailableEquations>::Type;
using Match = typename EquationForCorrection<AvailableEquations, FirstValue>::type;
public:
using Type =
std::conditional_t<std::same_as<Match, void>, Tail, typename PrependEquation<Match, Tail>::Type>;
};
template <typename AvailableEquations, typename Form> struct CatalogMatchesForm : std::false_type { };
template <typename... Equations, typename... Values, typename... Residuals>
struct CatalogMatchesForm<
ThermodynamicEquationCatalog<Equations...>,
utils::blocks::block_form<utils::blocks::type_list<Values...>, utils::blocks::type_list<Residuals...>>>
: std::bool_constant<
((utils::blocks::
contains_type_v<typename Equations::Correction, utils::blocks::type_list<Values...>> ==
utils::blocks::
contains_type_v<typename Equations::Residual, utils::blocks::type_list<Residuals...>>) &&
...)> { };
template <typename Equations> struct SurfaceBindingsForEquations;
template <typename... Equations>
struct SurfaceBindingsForEquations<ThermodynamicEquationCatalog<Equations...>> {
using Type = surface::SurfaceStateBindings<
surface::SurfaceStateBinding<typename Equations::PhysicalQuantity, typename Equations::FieldType>...>;
};
template <typename SurfaceFields, typename Equations>
struct SurfaceFieldsBelongToEquations : std::false_type { };
template <typename... Fields, typename Equations>
struct SurfaceFieldsBelongToEquations<field::TypeList<Fields...>, Equations>
: std::bool_constant<((EquationFieldCount<Equations, Fields>::value == 1) && ...)> { };
template <typename EquationOfState, typename Form, typename AvailableEquations, typename = void>
struct ThermodynamicCompilationIsAvailable : std::false_type { };
template <typename EquationOfState, typename Form, typename AvailableEquations>
struct ThermodynamicCompilationIsAvailable<
EquationOfState,
Form,
AvailableEquations,
std::enable_if_t<
eos::EquationOfStateModel<EquationOfState> && utils::blocks::block_form_is_valid_v<Form> &&
IsThermodynamicEquationCatalog<AvailableEquations>::value &&
CatalogEntriesAreUnique<AvailableEquations>::value &&
CatalogMatchesForm<AvailableEquations, Form>::value>> {
private:
using ActiveEquations =
typename SelectActiveEquations<typename Form::value_blocks, AvailableEquations>::Type;
using StateBindings = typename SurfaceBindingsForEquations<ActiveEquations>::Type;
public:
static constexpr bool value = (ActiveEquations::size > 0) &&
surface::PressureSurfaceFormulationCompilable<StateBindings, EquationOfState>;
};
template <typename Candidate, typename = void> struct IsCompiledThermodynamicEquations : std::false_type { };
template <typename Candidate>
struct IsCompiledThermodynamicEquations<
Candidate,
std::void_t<
typename Candidate::EquationOfStateType,
typename Candidate::Equations,
typename Candidate::StateBindings,
typename Candidate::PressureSurfaceFormulation>>
: std::bool_constant<
eos::EquationOfStateModel<typename Candidate::EquationOfStateType> &&
IsThermodynamicEquationCatalog<typename Candidate::Equations>::value &&
CatalogEntriesAreUnique<typename Candidate::Equations>::value &&
surface::ValidSurfaceStateBindings<typename Candidate::StateBindings> &&
std::same_as<
typename Candidate::StateBindings,
typename SurfaceBindingsForEquations<typename Candidate::Equations>::Type> &&
surface::SurfaceConstraintFormulationType<typename Candidate::PressureSurfaceFormulation> &&
std::same_as<
typename Candidate::PressureSurfaceFormulation::StateBindings,
typename Candidate::StateBindings>> { };
} // namespace detail
template <typename Candidate>
concept ThermodynamicEquationType = detail::IsThermodynamicEquation<std::remove_cvref_t<Candidate>>::value;
template <typename Candidate>
concept ValidThermodynamicEquationCatalog =
detail::IsThermodynamicEquationCatalog<std::remove_cvref_t<Candidate>>::value &&
detail::CatalogEntriesAreUnique<std::remove_cvref_t<Candidate>>::value;
template <typename Candidate>
concept CompiledThermodynamicEquations =
detail::IsCompiledThermodynamicEquations<std::remove_cvref_t<Candidate>>::value;
template <ValidThermodynamicEquationCatalog Equations, surface::SurfaceFieldType Field>
requires(detail::EquationFieldCount<Equations, Field>::value == 1)
using ThermodynamicEquationForFieldT = typename detail::EquationForField<Equations, Field>::type;
template <typename Fields, ValidThermodynamicEquationCatalog Equations>
inline constexpr bool fieldsBelongToThermodynamicEquations =
detail::SurfaceFieldsBelongToEquations<Fields, Equations>::value;
template <typename EquationOfState, typename Form, typename AvailableEquations>
concept ThermodynamicEquationsCompilable = detail::ThermodynamicCompilationIsAvailable<
std::remove_cvref_t<EquationOfState>,
std::remove_cvref_t<Form>,
std::remove_cvref_t<AvailableEquations>>::value;
template <eos::EquationOfStateModel EquationOfState, ValidThermodynamicEquationCatalog ActiveEquations>
requires surface::PressureSurfaceFormulationCompilable<
typename detail::SurfaceBindingsForEquations<ActiveEquations>::Type,
EquationOfState>
struct ThermodynamicEquationSet final {
using EquationOfStateType = EquationOfState;
using Equations = ActiveEquations;
using StateBindings = typename detail::SurfaceBindingsForEquations<Equations>::Type;
using PressureSurfaceFormulation =
surface::CompiledPressureSurfaceFormulationT<StateBindings, EquationOfStateType>;
};
template <
eos::EquationOfStateModel EquationOfState,
typename Form,
ValidThermodynamicEquationCatalog AvailableEquations>
requires ThermodynamicEquationsCompilable<EquationOfState, Form, AvailableEquations>
struct CompileThermodynamicEquations final {
using Equations = typename detail::SelectActiveEquations<typename Form::value_blocks, AvailableEquations>::Type;
using Type = ThermodynamicEquationSet<EquationOfState, Equations>;
};
template <typename EquationOfState, typename Form, typename AvailableEquations>
requires ThermodynamicEquationsCompilable<EquationOfState, Form, AvailableEquations>
using CompiledThermodynamicEquationsT = typename CompileThermodynamicEquations<
std::remove_cvref_t<EquationOfState>,
std::remove_cvref_t<Form>,
std::remove_cvref_t<AvailableEquations>>::Type;
using StellarEquilibriumThermodynamicEquations = ThermodynamicEquationCatalog<
ThermodynamicEquation<
field::Density,
utils::blocks::density::mass::value,
utils::blocks::density::mass::residual>,
ThermodynamicEquation<
field::Enthalpy,
utils::blocks::enthalpy::specific::value,
utils::blocks::enthalpy::specific::residual>>;
static_assert(ValidThermodynamicEquationCatalog<StellarEquilibriumThermodynamicEquations>);
} // namespace mean_field::material