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, utils::blocks::type_list, Remaining...> { using Type = typename ConcatenateBlockLists, 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>> { }; template struct IsResidualBlockList : std::false_type { }; template struct IsResidualBlockList> : std::bool_constant< (std::derived_from && ...) && utils::blocks::types_are_unique_v>> { }; template struct GeneratedValueBlocksFor; template struct GeneratedValueBlocksFor> { using Type = utils::blocks::type_list...>; }; template struct GeneratedResidualBlocksFor; template struct GeneratedResidualBlocksFor> { using Type = utils::blocks::type_list...>; }; /* * 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 { 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 { private: using GeneratedBlocks = typename GeneratedValueBlocksFor< typename models::SpecificationContribution::GeneratedValues>::Type; using Selection = SingleGeneratedBlock; public: using Type = typename Selection::Type; static constexpr bool mapped = Selection::available; }; template struct StellarDependencyBlock> { 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 { 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 { using Type = utils::blocks::surface_deformation::shape_equilibrium::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { using Type = utils::blocks::enthalpy::specific::residual; static constexpr bool mapped = true; }; template struct StellarDependencyBlock { private: using GeneratedBlocks = typename GeneratedResidualBlocksFor< typename models::SpecificationContribution::GeneratedResiduals>::Type; using Selection = SingleGeneratedBlock; public: using Type = typename Selection::Type; static constexpr bool mapped = Selection::available; }; template struct StellarDependencyBlock> { 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>; static constexpr bool complete = false; }; template struct CompileStellarDependencies> { using Type = utils::blocks::type_list::Type...>; static constexpr bool complete = (StellarDependencyBlock::mapped && ...); }; template struct CoupleResidualToValues; template struct CoupleResidualToValues> { using Type = utils::blocks::type_list...>; }; template struct CartesianJacobianCouplings; template struct CartesianJacobianCouplings, Values> { using Type = ConcatenateBlockListsT::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>> { }; 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> { private: using Remaining = typename GeneratedBorderIncidentCouplings>::Type; public: using Type = std::conditional_t< isGeneratedBorderIncidentCoupling, ConcatenateBlockListsT, Remaining>, Remaining>; }; template < bool Registered, typename GeneratedValues, typename GeneratedResiduals, typename DependsOn, typename Affects> 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; 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; 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::Type; using GeneratedResidualBlocks = typename GeneratedResidualBlocksFor::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::GeneratedValueBlocks, typename SelfDescribingSpecificationCompilationInputs::GeneratedResidualBlocks, typename SelfDescribingSpecificationCompilationInputs::DependsOnValueBlocks, typename SelfDescribingSpecificationCompilationInputs::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< typename StellarEquilibriumSpecificationCompilation::GeneratedValueBlocks, typename StellarEquilibriumSpecificationCompilation::GeneratedResidualBlocks, typename StellarEquilibriumSpecificationCompilation::DependsOnValueBlocks, typename StellarEquilibriumSpecificationCompilation::AffectedResidualBlocks, typename StellarEquilibriumSpecificationCompilation::JacobianCouplings, std::bool_constant::registered>, std::bool_constant::complete>>> : std::bool_constant< StellarEquilibriumSpecificationCompilation::registered && StellarEquilibriumSpecificationCompilation::complete && IsValueBlockList::GeneratedValueBlocks>::value && IsResidualBlockList::GeneratedResidualBlocks>::value && IsValueBlockList::DependsOnValueBlocks>::value && IsResidualBlockList::AffectedResidualBlocks>::value && IsJacobianCouplingList< typename StellarEquilibriumSpecificationCompilation::JacobianCouplings>::value> { }; } // namespace detail template inline constexpr bool stellarEquilibriumSpecificationCompilationComplete = detail::SpecificationCompilationIsComplete>::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...>; }; template struct FlattenJacobianRows; template struct FlattenJacobianRows> { using Type = ConcatenateBlockListsT::Type...>; }; using StellarPhysicsJacobianCouplings = typename FlattenJacobianRows::Type; template struct SpecificationSetCompilationsAreComplete; template struct SpecificationSetCompilationsAreComplete> : 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::GeneratedValueBlocks...>; using GeneratedResidualBlocks = ConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation::GeneratedResidualBlocks...>; using ContributionJacobianCouplings = UniqueConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation::JacobianCouplings...>; using IncidentJacobianCouplings = UniqueConcatenateBlockListsT< typename StellarEquilibriumSpecificationCompilation::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, 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 && utils::blocks::contains_type_v) && ...)> { }; 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; 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>::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< FormType, JacobianType>); }; template requires StellarEquilibriumSystemCompilable using CompiledStellarEquilibriumForm = typename CompiledStellarEquilibriumSystem::FormType; template requires StellarEquilibriumSystemCompilable using CompiledStellarEquilibriumJacobianForm = typename CompiledStellarEquilibriumSystem::JacobianType; } // namespace mean_field::operators