module; #include #include export module mean_field:operators.stellar_equilibrium_compiler; export import :model.compiled_fixed_angular_momentum; export import :model.compiled_fixed_central_density; export import :model.typed_stellar; export import :utils.blocks; export namespace mean_field::operators { /* * A coupling is the symbolic statement that one Jacobian block may be * nonzero. Specifications contribute these statements independently of * the final row and column layout. */ template struct StellarEquilibriumJacobianCoupling final { using Residual = ResidualBlock; using Value = ValueBlock; using ResidualBlockType = ResidualBlock; using ValueBlockType = ValueBlock; }; template using EquilibriumJacobianCoupling = StellarEquilibriumJacobianCoupling; namespace detail { template struct ConcatenateBlockLists; template <> struct ConcatenateBlockLists<> { using Type = utils::blocks::type_list<>; }; template struct ConcatenateBlockLists> { using Type = utils::blocks::type_list; }; template struct ConcatenateBlockLists, utils::blocks::type_list, Remaining...> { using Type = typename ConcatenateBlockLists< utils::blocks::type_list, Remaining...>::Type; }; template using ConcatenateBlockListsT = typename ConcatenateBlockLists::Type; template struct AppendUniqueBlockType; template struct AppendUniqueBlockType, Type> { using TypeValue = std::conditional_t< utils::blocks::contains_type_v>, utils::blocks::type_list, utils::blocks::type_list>; }; template struct UniqueBlockListImpl; template struct UniqueBlockListImpl> { using Type = Accumulated; }; template struct UniqueBlockListImpl> { using Type = typename UniqueBlockListImpl< typename AppendUniqueBlockType::TypeValue, utils::blocks::type_list>::Type; }; template using UniqueBlockListT = typename UniqueBlockListImpl, List>::Type; template using UniqueConcatenateBlockListsT = UniqueBlockListT>; template struct IsValueBlockList : std::false_type {}; template struct IsValueBlockList> : std::bool_constant< (std::derived_from && ...) && utils::blocks::types_are_unique_v< utils::blocks::type_list>> {}; template struct IsResidualBlockList : std::false_type {}; template struct IsResidualBlockList> : std::bool_constant< (std::derived_from && ...) && utils::blocks::types_are_unique_v< utils::blocks::type_list>> {}; template struct GeneratedValueBlocksFor; template struct GeneratedValueBlocksFor> { using Type = utils::blocks::type_list< utils::blocks::generated_value_block...>; }; template struct GeneratedResidualBlocksFor; template struct GeneratedResidualBlocksFor< models::ModelTypeList> { using Type = utils::blocks::type_list< utils::blocks::generated_residual_block...>; }; /* * One translation boundary turns physics-facing stellar names into backend * blocks. Existing backend block types pass through unchanged, which keeps * the advanced extension API open without making built-in physics declarations * depend on utils.blocks. */ template struct UnmappedStellarDependency final {}; template struct SingleGeneratedBlock { using Type = UnmappedStellarDependency; static constexpr bool available = false; }; template struct SingleGeneratedBlock, DeclaredDependency> { using Type = Block; static constexpr bool available = true; }; template struct StellarDependencyBlock { using Type = UnmappedStellarDependency; static constexpr bool mapped = false; }; template requires(std::derived_from || std::derived_from) struct StellarDependencyBlock { using Type = Block; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::density::mass::value; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::surface_deformation::parameters::value; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::gravity::gradient::value; static constexpr bool mapped = true; }; template struct StellarDependencyBlock< Specification, models::stellar::state::GravitationalPotential> { using Type = utils::blocks::gravity::poisson::value; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::enthalpy::specific::value; static constexpr bool mapped = true; }; template struct StellarDependencyBlock< Specification, models::stellar::state::OwnGeneratedCoordinate> { private: using GeneratedBlocks = typename GeneratedValueBlocksFor< typename models::SpecificationContribution< Specification>::GeneratedValues>::Type; using Selection = SingleGeneratedBlock< GeneratedBlocks, models::stellar::state::OwnGeneratedCoordinate>; public: using Type = typename Selection::Type; static constexpr bool mapped = Selection::available; }; template struct StellarDependencyBlock< Specification, models::stellar::state::GeneratedCoordinateOf> { private: using GeneratedBlocks = typename GeneratedValueBlocksFor< typename models::SpecificationContribution::GeneratedValues>::Type; using Dependency = models::stellar::state::GeneratedCoordinateOf; using Selection = SingleGeneratedBlock; public: using Type = typename Selection::Type; static constexpr bool mapped = Selection::available; }; template struct StellarDependencyBlock< Specification, models::stellar::equation::GravityGradientDefinition> { using Type = utils::blocks::gravity::gradient::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::gravity::poisson::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::density::mass::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock< Specification, models::stellar::equation::SurfaceShapeBalance> { using Type = utils::blocks::surface_deformation::shape_equilibrium::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock< Specification, models::stellar::equation::HydrostaticBalance> { using Type = utils::blocks::enthalpy::specific::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { private: using GeneratedBlocks = typename GeneratedResidualBlocksFor< typename models::SpecificationContribution< Specification>::GeneratedResiduals>::Type; using Selection = SingleGeneratedBlock< GeneratedBlocks, models::stellar::equation::OwnConstraint>; public: using Type = typename Selection::Type; static constexpr bool mapped = Selection::available; }; template struct StellarDependencyBlock< Specification, models::stellar::equation::ConstraintOf> { private: using GeneratedBlocks = typename GeneratedResidualBlocksFor< typename models::SpecificationContribution::GeneratedResiduals>::Type; using Dependency = models::stellar::equation::ConstraintOf; using Selection = SingleGeneratedBlock; public: using Type = typename Selection::Type; static constexpr bool mapped = Selection::available; }; template struct CompileStellarDependencies { using Type = utils::blocks::type_list< UnmappedStellarDependency>; static constexpr bool complete = false; }; template struct CompileStellarDependencies> { using Type = utils::blocks::type_list< typename StellarDependencyBlock::Type...>; static constexpr bool complete = (StellarDependencyBlock::mapped && ...); }; template struct CoupleResidualToValues; template struct CoupleResidualToValues> { using Type = utils::blocks::type_list< StellarEquilibriumJacobianCoupling...>; }; template struct CartesianJacobianCouplings; template struct CartesianJacobianCouplings, Values> { using Type = ConcatenateBlockListsT< typename CoupleResidualToValues::Type...>; }; template struct IsJacobianCoupling : std::false_type {}; template struct IsJacobianCoupling> : std::bool_constant< std::derived_from && std::derived_from> {}; template struct IsJacobianCouplingList : std::false_type {}; template struct IsJacobianCouplingList> : std::bool_constant<(IsJacobianCoupling::value && ...) && utils::blocks::types_are_unique_v< utils::blocks::type_list>> {}; template struct IsGeneratedValueBlock : std::false_type {}; template struct IsGeneratedValueBlock> : std::true_type {}; template struct IsGeneratedResidualBlock : std::false_type {}; template struct IsGeneratedResidualBlock> : std::true_type {}; template inline constexpr bool isGeneratedBorderIncidentCoupling = IsGeneratedValueBlock::value || IsGeneratedResidualBlock::value; template struct GeneratedBorderIncidentCouplings; template <> struct GeneratedBorderIncidentCouplings> { using Type = utils::blocks::type_list<>; }; template struct GeneratedBorderIncidentCouplings< utils::blocks::type_list> { private: using Remaining = typename GeneratedBorderIncidentCouplings< utils::blocks::type_list>::Type; public: using Type = std::conditional_t< isGeneratedBorderIncidentCoupling, ConcatenateBlockListsT, Remaining>, Remaining>; }; template struct DeclarativeStellarEquilibriumSpecificationCompilation { using GeneratedValueBlocks = GeneratedValues; using GeneratedResidualBlocks = GeneratedResiduals; using DependsOnValueBlocks = DependsOn; using AffectedResidualBlocks = Affects; /* * Preserve the two physical meanings in the declaration instead of * flattening their endpoints into independent unions: * * constraint equation <- everything named in Reads * changed equations <- Reads plus the generated coordinate * * The second group deliberately includes Affects x Reads. Nonlinear * constraints and multiplier forces generally contribute Hessian-like * state derivatives there. Linear contributions simply assemble zero on * those structurally permitted edges. */ using ConstraintInputValueBlocks = DependsOnValueBlocks; using ConstraintOutputResidualBlocks = GeneratedResidualBlocks; using ChangedEquationInputValueBlocks = UniqueConcatenateBlockListsT< DependsOnValueBlocks, GeneratedValueBlocks>; using ChangedEquationOutputResidualBlocks = AffectedResidualBlocks; using ConstraintJacobianCouplings = typename CartesianJacobianCouplings::Type; using ChangedEquationJacobianCouplings = typename CartesianJacobianCouplings::Type; // Compatibility names retained for backend code that distinguishes the // generated row from the generated-coordinate column. using GeneratedRowJacobianCouplings = ConstraintJacobianCouplings; using AffectedRowJacobianCouplings = typename CartesianJacobianCouplings::Type; using AffectedStateJacobianCouplings = typename CartesianJacobianCouplings::Type; using JacobianCouplings = UniqueConcatenateBlockListsT< ConstraintJacobianCouplings, ChangedEquationJacobianCouplings>; using IncidentJacobianCouplings = typename GeneratedBorderIncidentCouplings::Type; // Correction is the Newton-facing name for a value coordinate. using GeneratedCorrectionBlocks = GeneratedValueBlocks; static constexpr bool registered = Registered; static constexpr bool complete = registered && IsValueBlockList::value && IsResidualBlockList::value && IsValueBlockList::value && IsResidualBlockList::value && IsJacobianCouplingList::value && (GeneratedValueBlocks::size == GeneratedResidualBlocks::size) && ((GeneratedValueBlocks::size == 0 && DependsOnValueBlocks::size == 0 && AffectedResidualBlocks::size == 0) || (GeneratedValueBlocks::size > 0 && DependsOnValueBlocks::size > 0 && AffectedResidualBlocks::size > 0)); }; using EmptySpecificationCompilation = DeclarativeStellarEquilibriumSpecificationCompilation< false, utils::blocks::type_list<>, utils::blocks::type_list<>, utils::blocks::type_list<>, utils::blocks::type_list<>>; template struct SelfDescribingSpecificationCompilationInputs { using Contribution = models::SpecificationContribution; using DependsOn = CompileStellarDependencies; using Affects = CompileStellarDependencies; using GeneratedValueBlocks = typename GeneratedValueBlocksFor< typename Contribution::GeneratedValues>::Type; using GeneratedResidualBlocks = typename GeneratedResidualBlocksFor< typename Contribution::GeneratedResiduals>::Type; using DependsOnValueBlocks = typename DependsOn::Type; using AffectedResidualBlocks = typename Affects::Type; static constexpr bool registered = Contribution::hasDeclarativeDefinition && DependsOn::complete && Affects::complete; }; template struct SelfDescribingSpecificationCompilation : DeclarativeStellarEquilibriumSpecificationCompilation< SelfDescribingSpecificationCompilationInputs::registered, typename SelfDescribingSpecificationCompilationInputs< Specification>::GeneratedValueBlocks, typename SelfDescribingSpecificationCompilationInputs< Specification>::GeneratedResidualBlocks, typename SelfDescribingSpecificationCompilationInputs< Specification>::DependsOnValueBlocks, typename SelfDescribingSpecificationCompilationInputs< Specification>::AffectedResidualBlocks> {}; } // namespace detail /* * Public, inspectable per-specification compilation metadata. The primary * is deliberately well formed and incomplete, so testing an arbitrary type * in a requires-expression never triggers a diagnostic. */ template struct StellarEquilibriumSpecificationCompilation : detail::EmptySpecificationCompilation {}; template struct StellarEquilibriumSpecificationCompilation : detail::SelfDescribingSpecificationCompilation {}; namespace detail { template struct SpecificationCompilationIsComplete : std::false_type {}; template struct SpecificationCompilationIsComplete< Specification, std::void_t::GeneratedValueBlocks, typename StellarEquilibriumSpecificationCompilation< Specification>::GeneratedResidualBlocks, typename StellarEquilibriumSpecificationCompilation< Specification>::DependsOnValueBlocks, typename StellarEquilibriumSpecificationCompilation< Specification>::AffectedResidualBlocks, typename StellarEquilibriumSpecificationCompilation< Specification>::JacobianCouplings, std::bool_constant::registered>, std::bool_constant::complete>>> : std::bool_constant< StellarEquilibriumSpecificationCompilation< Specification>::registered && StellarEquilibriumSpecificationCompilation::complete && IsValueBlockList::GeneratedValueBlocks>::value && IsResidualBlockList< typename StellarEquilibriumSpecificationCompilation< Specification>::GeneratedResidualBlocks>::value && IsValueBlockList::DependsOnValueBlocks>::value && IsResidualBlockList< typename StellarEquilibriumSpecificationCompilation< Specification>::AffectedResidualBlocks>::value && IsJacobianCouplingList< typename StellarEquilibriumSpecificationCompilation< Specification>::JacobianCouplings>::value> {}; } // namespace detail template inline constexpr bool stellarEquilibriumSpecificationCompilationComplete = detail::SpecificationCompilationIsComplete< std::remove_cvref_t>::value; template concept StellarEquilibriumSpecificationCompilable = stellarEquilibriumSpecificationCompilationComplete; namespace detail { /* * This five-by-five physical core is independent of global constraints. * Even FixedTotalMass is compiled as a contribution, keeping C and R_M * visible in that specification's metadata. */ using StellarPhysicsValueBlocks = utils::blocks::type_list< utils::blocks::density::mass::value, utils::blocks::surface_deformation::parameters::value, utils::blocks::gravity::gradient::value, utils::blocks::gravity::poisson::value, utils::blocks::enthalpy::specific::value>; using StellarPhysicsResidualBlocks = utils::blocks::type_list< utils::blocks::gravity::gradient::residual, utils::blocks::gravity::poisson::residual, utils::blocks::density::mass::residual, utils::blocks::surface_deformation::shape_equilibrium::residual, utils::blocks::enthalpy::specific::residual>; using StellarPhysicsJacobianRows = utils::blocks::type_list< utils::blocks::block_row< utils::blocks::gravity::gradient::residual, utils::blocks::gravity::gradient::value, utils::blocks::gravity::poisson::value, utils::blocks::surface_deformation::parameters::value>, utils::blocks::block_row< utils::blocks::gravity::poisson::residual, utils::blocks::gravity::gradient::value, utils::blocks::density::mass::value, utils::blocks::surface_deformation::parameters::value>, utils::blocks::block_row< utils::blocks::density::mass::residual, utils::blocks::density::mass::value, utils::blocks::enthalpy::specific::value, utils::blocks::surface_deformation::parameters::value>, utils::blocks::block_row< utils::blocks::surface_deformation::shape_equilibrium::residual, utils::blocks::density::mass::value, utils::blocks::surface_deformation::parameters::value, utils::blocks::gravity::gradient::value, utils::blocks::enthalpy::specific::value>, utils::blocks::block_row< utils::blocks::enthalpy::specific::residual, utils::blocks::enthalpy::specific::value, utils::blocks::gravity::poisson::value, utils::blocks::surface_deformation::parameters::value>>; template struct JacobianRowCouplings; template struct JacobianRowCouplings> { using Type = utils::blocks::type_list< StellarEquilibriumJacobianCoupling...>; }; template struct FlattenJacobianRows; template struct FlattenJacobianRows> { using Type = ConcatenateBlockListsT::Type...>; }; using StellarPhysicsJacobianCouplings = typename FlattenJacobianRows::Type; template struct SpecificationSetCompilationsAreComplete; template struct SpecificationSetCompilationsAreComplete< models::detail::SpecificationSetStorage> : std::bool_constant<( stellarEquilibriumSpecificationCompilationComplete && ...)> {}; template struct CollectStellarEquilibriumContributionsImpl { using GeneratedValueBlocks = utils::blocks::type_list<>; using GeneratedResidualBlocks = utils::blocks::type_list<>; using ContributionJacobianCouplings = utils::blocks::type_list<>; using IncidentJacobianCouplings = ContributionJacobianCouplings; static constexpr bool complete = false; }; template struct CollectStellarEquilibriumContributionsImpl< models::detail::SpecificationSetStorage, true> { using GeneratedValueBlocks = ConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation< Specifications>::GeneratedValueBlocks...>; using GeneratedResidualBlocks = ConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation< Specifications>::GeneratedResidualBlocks...>; using ContributionJacobianCouplings = UniqueConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation< Specifications>::JacobianCouplings...>; using IncidentJacobianCouplings = UniqueConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation< Specifications>::IncidentJacobianCouplings...>; static constexpr bool complete = true; }; template using CollectStellarEquilibriumContributions = CollectStellarEquilibriumContributionsImpl< SpecificationSet, SpecificationSetCompilationsAreComplete::value>; template struct ValuesCoupledToResidual; template struct ValuesCoupledToResidual> { using Type = utils::blocks::type_list<>; }; template struct ValuesCoupledToResidual< Residual, utils::blocks::type_list< StellarEquilibriumJacobianCoupling, Tail...>> { private: using Remaining = typename ValuesCoupledToResidual>::Type; public: using Type = std::conditional_t< std::same_as, ConcatenateBlockListsT, Remaining>, Remaining>; }; template struct MakeJacobianRow; template struct MakeJacobianRow> { using Type = utils::blocks::block_row; }; template struct SynthesizeJacobianRows; template struct SynthesizeJacobianRows, Couplings> { using Type = utils::blocks::type_list::Type>::Type...>; }; template struct CouplingEndpointsBelongToForm : std::false_type {}; template struct CouplingEndpointsBelongToForm, ValueBlocks, ResidualBlocks> : std::bool_constant<((utils::blocks::contains_type_v< typename Couplings::Value, ValueBlocks> && utils::blocks::contains_type_v< typename Couplings::Residual, ResidualBlocks>) && ...)> {}; template struct CompileStellarEquilibriumSystem { using GeneratedValueBlocks = utils::blocks::type_list<>; using GeneratedCorrectionBlocks = GeneratedValueBlocks; using GeneratedResidualBlocks = utils::blocks::type_list<>; using BaseJacobianCouplings = utils::blocks::type_list<>; using ContributionJacobianCouplings = utils::blocks::type_list<>; using IncidentJacobianCouplings = ContributionJacobianCouplings; using JacobianCouplings = utils::blocks::type_list<>; static constexpr bool compilable = false; }; template struct CompileStellarEquilibriumSystem { using ModelType = std::remove_cvref_t; using Contributions = CollectStellarEquilibriumContributions< typename ModelType::SpecificationTypes>; using GeneratedValueBlocks = typename Contributions::GeneratedValueBlocks; using GeneratedCorrectionBlocks = GeneratedValueBlocks; using GeneratedResidualBlocks = typename Contributions::GeneratedResidualBlocks; using ValueBlocks = ConcatenateBlockListsT; using ResidualBlocks = ConcatenateBlockListsT; using FormType = utils::blocks::block_form; using BaseJacobianCouplings = StellarPhysicsJacobianCouplings; using ContributionJacobianCouplings = typename Contributions::ContributionJacobianCouplings; using IncidentJacobianCouplings = ContributionJacobianCouplings; using JacobianCouplings = UniqueConcatenateBlockListsT; // Pass two: materialize rows only after all contributed blocks are // present in the final form. using JacobianType = typename SynthesizeJacobianRows::Type; static constexpr bool compilable = Contributions::complete && utils::blocks::block_form_is_valid_v && IsJacobianCouplingList::value && CouplingEndpointsBelongToForm::value && utils::blocks::jacobian_form_is_valid_v; }; } // namespace detail template inline constexpr bool stellarEquilibriumSystemIsCompilable = detail::CompileStellarEquilibriumSystem< std::remove_cvref_t>::compilable; /* * This compiler proves the symbolic block topology only. Keep the explicit * name available to extension authors and tests so that success here is not * mistaken for an assembled numerical runtime. The established spelling is * retained below as a compatibility alias. */ template inline constexpr bool stellarEquilibriumIsSymbolicallyCompilable = stellarEquilibriumSystemIsCompilable; template concept StellarEquilibriumSymbolicallyCompilable = stellarEquilibriumIsSymbolicallyCompilable; template concept StellarEquilibriumSystemCompilable = StellarEquilibriumSymbolicallyCompilable; template requires StellarEquilibriumSystemCompilable struct CompiledStellarEquilibriumSystem final : detail::CompileStellarEquilibriumSystem> { using Base = detail::CompileStellarEquilibriumSystem>; using FormType = typename Base::FormType; using JacobianType = typename Base::JacobianType; // This classification is exposed only after the complete compiler concept // has succeeded; model declarations intentionally do not predict it. static constexpr models::EquilibriumSystemCompilation compilationClass = models::EquilibriumSystemCompilation::complete_equilibrium_system; static_assert(utils::blocks::block_form_is_valid_v); static_assert(utils::blocks::valid_jacobian_form); }; template requires StellarEquilibriumSystemCompilable using CompiledStellarEquilibriumForm = typename CompiledStellarEquilibriumSystem::FormType; template requires StellarEquilibriumSystemCompilable using CompiledStellarEquilibriumJacobianForm = typename CompiledStellarEquilibriumSystem::JacobianType; } // namespace mean_field::operators