module; #include #include #include #include #include #include #include #include #include #include #include #include export module mean_field:model.specifications; export import :eos.polytrope; export import :surface.constant; export namespace mean_field::models { enum class SpecificationRole { constitutive_law, boundary_condition, invariant, phase_condition, gauge_choice, rotation_law }; struct SpecificationKey final { SpecificationRole role; std::size_t ordinal; constexpr auto operator<=>(const SpecificationKey &) const = default; }; struct SpecificationDescriptor final { std::string_view name; SpecificationRole role; SpecificationKey key; std::size_t generatedValueArity; std::size_t generatedResidualArity; constexpr bool operator==(const SpecificationDescriptor &) const = default; }; enum class EquilibriumSystemCompilation { complete_equilibrium_system, equation_contributions_only, // Transitional spellings retained while internal solver code is // migrated to physics-facing equilibrium-system terminology. isolated_root = complete_equilibrium_system, assembly_only = equation_contributions_only }; using ModelCompilationClass = EquilibriumSystemCompilation; struct RuntimeSpecificationDescriptor final { SpecificationDescriptor specification; std::size_t canonicalIndex; bool hasRootCompiler; constexpr bool operator==(const RuntimeSpecificationDescriptor &) const = default; }; template struct SpecificationTraits; template concept ModelSpecification = requires { typename std::remove_cvref_t::Parameters; { SpecificationTraits>::name } -> std::convertible_to; { SpecificationTraits>::role } -> std::convertible_to; { SpecificationTraits>::key } -> std::convertible_to; } && std::constructible_from, typename std::remove_cvref_t::Parameters>; class FixedTotalMass final { public: struct Parameters final { dimensions::MassValue Mtotal; }; using TargetValue = dimensions::MassValue; explicit FixedTotalMass(const Parameters parameters) : FixedTotalMass(parameters.Mtotal) { } explicit FixedTotalMass(const TargetValue targetMass) : m_targetMass(targetMass) { if (!std::isfinite(targetMass.value()) || targetMass.value() <= 0.0) { throw std::invalid_argument( std::format( "The fixed total mass must be finite and positive. Instead M = {} was provided.", targetMass.value() ) ); } } [[nodiscard]] TargetValue targetMass() const noexcept { return m_targetMass; } private: TargetValue m_targetMass; }; class FixedCentralDensity final { public: struct Parameters final { dimensions::DensityValue RhoC; }; using TargetValue = dimensions::DensityValue; explicit FixedCentralDensity(const Parameters parameters) : FixedCentralDensity(parameters.RhoC) { } explicit FixedCentralDensity(const TargetValue targetDensity) : m_targetDensity(targetDensity) { if (!std::isfinite(targetDensity.value()) || targetDensity.value() <= 0.0) { throw std::invalid_argument( std::format( "The fixed central density must be finite and positive. Instead rho_c = {} was provided.", targetDensity.value() ) ); } } [[nodiscard]] TargetValue targetDensity() const noexcept { return m_targetDensity; } private: TargetValue m_targetDensity; }; template <> struct SpecificationTraits { static constexpr std::string_view name = "Polytrope"; static constexpr SpecificationRole role = SpecificationRole::constitutive_law; static constexpr SpecificationKey key{role, 0}; }; template <> struct SpecificationTraits { static constexpr std::string_view name = "IsobaricSurface"; static constexpr SpecificationRole role = SpecificationRole::boundary_condition; static constexpr SpecificationKey key{role, 0}; }; template <> struct SpecificationTraits { static constexpr std::string_view name = "FixedTotalMass"; static constexpr SpecificationRole role = SpecificationRole::invariant; static constexpr SpecificationKey key{role, 0}; }; template <> struct SpecificationTraits { static constexpr std::string_view name = "FixedCentralDensity"; static constexpr SpecificationRole role = SpecificationRole::phase_condition; static constexpr SpecificationKey key{role, 0}; }; template struct ModelTypeList final { static constexpr std::size_t size = sizeof...(Types); }; template struct ModelTypeListContains; template struct ModelTypeListContains> : std::bool_constant<(std::same_as || ...)> { }; template inline constexpr bool modelTypeListContains = ModelTypeListContains::value; template struct ResidualFor final { using SpecificationType = Specification; static constexpr std::size_t scalarArity = 1; }; template struct MultiplierFor final { using SpecificationType = Specification; static constexpr std::size_t scalarArity = 1; }; template struct BorderFor final { using SpecificationType = Specification; static constexpr std::size_t scalarArity = 1; }; template struct SpecificationContribution { using GeneratedValues = ModelTypeList<>; using GeneratedResiduals = ModelTypeList<>; static constexpr bool isDefined = false; static constexpr bool hasRootCompiler = false; }; template <> struct SpecificationContribution { using GeneratedValues = ModelTypeList<>; using GeneratedResiduals = ModelTypeList<>; static constexpr bool isDefined = true; static constexpr bool hasRootCompiler = true; }; template <> struct SpecificationContribution { using GeneratedValues = ModelTypeList<>; using GeneratedResiduals = ModelTypeList<>; static constexpr bool isDefined = true; static constexpr bool hasRootCompiler = true; }; template <> struct SpecificationContribution { using GeneratedValues = ModelTypeList>; using GeneratedResiduals = ModelTypeList>; static constexpr bool isDefined = true; static constexpr bool hasRootCompiler = true; }; template <> struct SpecificationContribution { using GeneratedValues = ModelTypeList>; using GeneratedResiduals = ModelTypeList>; static constexpr bool isDefined = true; static constexpr bool hasRootCompiler = true; }; template concept ResolvedModelSpecification = ModelSpecification && SpecificationContribution>::isDefined; namespace detail { template struct SpecificationSetStorage final { static constexpr std::size_t size = sizeof...(Specifications); }; template struct ConcatenateModelTypeLists; template <> struct ConcatenateModelTypeLists<> { using Type = ModelTypeList<>; }; template struct ConcatenateModelTypeLists> { using Type = ModelTypeList; }; template struct ConcatenateModelTypeLists, ModelTypeList, Remaining...> { using Type = typename ConcatenateModelTypeLists, Remaining...>::Type; }; template struct InsertSpecification; template struct InsertSpecification> { using Type = SpecificationSetStorage; }; template struct InsertSpecification> { private: using InsertedTail = typename InsertSpecification>::Type; template struct PrependSpecification; template struct PrependSpecification> { using Type = SpecificationSetStorage; }; public: using Type = std::conditional_t< (SpecificationTraits::key < SpecificationTraits::key), SpecificationSetStorage, typename PrependSpecification::Type>; }; template struct CanonicalizeSpecifications; template struct CanonicalizeSpecifications { using Type = Set; }; template struct CanonicalizeSpecifications { using Inserted = typename InsertSpecification::Type; using Type = typename CanonicalizeSpecifications::Type; }; template using CanonicalSpecificationSet = typename CanonicalizeSpecifications, Specifications...>::Type; template < ModelSpecification Head, ModelSpecification... Tail> consteval bool specificationKeyIsUnique() { return ((SpecificationTraits::key != SpecificationTraits::key) && ...); } template struct SpecificationKeysAreUnique; template <> struct SpecificationKeysAreUnique<> : std::true_type { }; template struct SpecificationKeysAreUnique : std::bool_constant< specificationKeyIsUnique() && SpecificationKeysAreUnique::value> { }; template inline constexpr std::size_t specificationRoleCount = (std::size_t{0} + ... + (SpecificationTraits::role == Role ? 1 : 0)); template struct ModelTypeListScalarArity; template struct ModelTypeListScalarArity> : std::integral_constant { }; template inline constexpr bool isOneOf = (std::same_as || ...); template inline constexpr std::size_t typeCount = (std::size_t{0} + ... + (std::same_as> ? std::size_t{1} : std::size_t{0})); template struct ArgumentsMatchCanonicalSpecifications; template struct ArgumentsMatchCanonicalSpecifications, Arguments...> : std::bool_constant< sizeof...(CanonicalSpecifications) == sizeof...(Arguments) && (isOneOf, CanonicalSpecifications...> && ...) && ((typeCount == 1) && ...)> { }; } // namespace detail template inline constexpr bool specificationKeysAreUnique = detail::SpecificationKeysAreUnique::value; template concept ValidModelSpecificationPack = (ResolvedModelSpecification && ...) && specificationKeysAreUnique && detail::specificationRoleCount == 1; template requires specificationKeysAreUnique using SpecificationSet = detail::CanonicalSpecificationSet; template struct SpecificationOperatorSignature; template struct SpecificationOperatorSignature> final { using GeneratedValues = typename detail::ConcatenateModelTypeLists< typename SpecificationContribution::GeneratedValues...>::Type; using GeneratedResiduals = typename detail::ConcatenateModelTypeLists< typename SpecificationContribution::GeneratedResiduals...>::Type; static constexpr std::size_t generatedValueArity = detail::ModelTypeListScalarArity::value; static constexpr std::size_t generatedResidualArity = detail::ModelTypeListScalarArity::value; static constexpr bool symbolicallySquare = generatedValueArity == generatedResidualArity; }; template [[nodiscard]] consteval SpecificationDescriptor specificationDescriptor() { using Contribution = SpecificationContribution; return { .name = SpecificationTraits::name, .role = SpecificationTraits::role, .key = SpecificationTraits::key, .generatedValueArity = detail::ModelTypeListScalarArity::value, .generatedResidualArity = detail::ModelTypeListScalarArity::value }; } namespace detail { template class SpecifiedModel; template class SpecifiedModel> final { public: using SpecificationTypes = SpecificationSetStorage; using OperatorSignature = SpecificationOperatorSignature; static constexpr bool symbolicallySquare = OperatorSignature::symbolicallySquare; static constexpr bool hasCompleteRootCompiler = (SpecificationContribution::hasRootCompiler && ...); static constexpr EquilibriumSystemCompilation compilationClass = symbolicallySquare && hasCompleteRootCompiler ? EquilibriumSystemCompilation::complete_equilibrium_system : EquilibriumSystemCompilation::equation_contributions_only; template requires ArgumentsMatchCanonicalSpecifications< SpecificationTypes, Arguments...>::value explicit SpecifiedModel(Arguments &&...arguments) : m_specifications( std::get( std::tuple...>{std::forward(arguments)...} )... ) { } template requires isOneOf< Specification, Specifications...> [[nodiscard]] const Specification &specification() const noexcept { return std::get(m_specifications); } template static constexpr bool containsSpecification = isOneOf; [[nodiscard]] static constexpr std::span runtimeSpecificationDescriptors() noexcept { return runtimeDescriptors; } private: inline static constexpr std::array runtimeDescriptors = [] { std::array descriptors{}; std::size_t index = 0; ((descriptors[index] = {.specification = specificationDescriptor(), .canonicalIndex = index, .hasRootCompiler = SpecificationContribution::hasRootCompiler}, ++index), ...); return descriptors; }(); std::tuple m_specifications; }; } // namespace detail template requires ValidModelSpecificationPack && SpecificationOperatorSignature>::symbolicallySquare using Model = detail::SpecifiedModel>; template concept SpecifiedModelType = requires { typename std::remove_cvref_t::SpecificationTypes; typename std::remove_cvref_t::OperatorSignature; requires std::remove_cvref_t::symbolicallySquare; { std::remove_cvref_t::compilationClass } -> std::convertible_to; { std::remove_cvref_t::runtimeSpecificationDescriptors() } -> std::same_as>; }; static_assert(ModelSpecification); static_assert(ModelSpecification); static_assert(ModelSpecification); static_assert(ModelSpecification); static_assert(ResolvedModelSpecification); static_assert(ResolvedModelSpecification); static_assert(ResolvedModelSpecification); static_assert(ResolvedModelSpecification); } // namespace mean_field::models export namespace mean_field::integral { using FixedTotalMass = models::FixedTotalMass; } export namespace mean_field::constraint { using FixedCentralDensity = models::FixedCentralDensity; }