Files
MeanField/libmeanfield/interface/operators/stellar_equilibrium_compiler.cppm
2026-09-06 10:15:00 -04:00

816 lines
33 KiB
C++

module;
#include <concepts>
#include <type_traits>
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 <typename ResidualBlock, typename ValueBlock>
struct StellarEquilibriumJacobianCoupling final {
using Residual = ResidualBlock;
using Value = ValueBlock;
using ResidualBlockType = ResidualBlock;
using ValueBlockType = ValueBlock;
};
template <typename ResidualBlock, typename ValueBlock>
using EquilibriumJacobianCoupling =
StellarEquilibriumJacobianCoupling<ResidualBlock, ValueBlock>;
namespace detail {
template <typename... Lists> struct ConcatenateBlockLists;
template <> struct ConcatenateBlockLists<> {
using Type = utils::blocks::type_list<>;
};
template <typename... Types>
struct ConcatenateBlockLists<utils::blocks::type_list<Types...>> {
using Type = utils::blocks::type_list<Types...>;
};
template <typename... First, typename... Second, typename... Remaining>
struct ConcatenateBlockLists<utils::blocks::type_list<First...>,
utils::blocks::type_list<Second...>,
Remaining...> {
using Type = typename ConcatenateBlockLists<
utils::blocks::type_list<First..., Second...>, Remaining...>::Type;
};
template <typename... Lists>
using ConcatenateBlockListsT = typename ConcatenateBlockLists<Lists...>::Type;
template <typename List, typename Type> struct AppendUniqueBlockType;
template <typename... Types, typename Type>
struct AppendUniqueBlockType<utils::blocks::type_list<Types...>, Type> {
using TypeValue = std::conditional_t<
utils::blocks::contains_type_v<Type, utils::blocks::type_list<Types...>>,
utils::blocks::type_list<Types...>,
utils::blocks::type_list<Types..., Type>>;
};
template <typename Accumulated, typename Remaining> struct UniqueBlockListImpl;
template <typename Accumulated>
struct UniqueBlockListImpl<Accumulated, utils::blocks::type_list<>> {
using Type = Accumulated;
};
template <typename Accumulated, typename Head, typename... Tail>
struct UniqueBlockListImpl<Accumulated,
utils::blocks::type_list<Head, Tail...>> {
using Type = typename UniqueBlockListImpl<
typename AppendUniqueBlockType<Accumulated, Head>::TypeValue,
utils::blocks::type_list<Tail...>>::Type;
};
template <typename List>
using UniqueBlockListT =
typename UniqueBlockListImpl<utils::blocks::type_list<>, List>::Type;
template <typename... Lists>
using UniqueConcatenateBlockListsT =
UniqueBlockListT<ConcatenateBlockListsT<Lists...>>;
template <typename Candidate> struct IsValueBlockList : std::false_type {};
template <typename... Blocks>
struct IsValueBlockList<utils::blocks::type_list<Blocks...>>
: std::bool_constant<
(std::derived_from<Blocks, utils::blocks::value_block_base> && ...) &&
utils::blocks::types_are_unique_v<
utils::blocks::type_list<Blocks...>>> {};
template <typename Candidate> struct IsResidualBlockList : std::false_type {};
template <typename... Blocks>
struct IsResidualBlockList<utils::blocks::type_list<Blocks...>>
: std::bool_constant<
(std::derived_from<Blocks, utils::blocks::residual_block_base> &&
...) &&
utils::blocks::types_are_unique_v<
utils::blocks::type_list<Blocks...>>> {};
template <typename GeneratedValues> struct GeneratedValueBlocksFor;
template <typename... GeneratedValues>
struct GeneratedValueBlocksFor<models::ModelTypeList<GeneratedValues...>> {
using Type = utils::blocks::type_list<
utils::blocks::generated_value_block<GeneratedValues>...>;
};
template <typename GeneratedResiduals> struct GeneratedResidualBlocksFor;
template <typename... GeneratedResiduals>
struct GeneratedResidualBlocksFor<
models::ModelTypeList<GeneratedResiduals...>> {
using Type = utils::blocks::type_list<
utils::blocks::generated_residual_block<GeneratedResiduals>...>;
};
/*
* 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 <typename DeclaredDependency>
struct UnmappedStellarDependency final {};
template <typename Blocks, typename DeclaredDependency>
struct SingleGeneratedBlock {
using Type = UnmappedStellarDependency<DeclaredDependency>;
static constexpr bool available = false;
};
template <typename Block, typename DeclaredDependency>
struct SingleGeneratedBlock<utils::blocks::type_list<Block>,
DeclaredDependency> {
using Type = Block;
static constexpr bool available = true;
};
template <models::ModelSpecification Specification, typename Dependency>
struct StellarDependencyBlock {
using Type = UnmappedStellarDependency<Dependency>;
static constexpr bool mapped = false;
};
template <models::ModelSpecification Specification, typename Block>
requires(std::derived_from<Block, utils::blocks::value_block_base> ||
std::derived_from<Block, utils::blocks::residual_block_base>)
struct StellarDependencyBlock<Specification, Block> {
using Type = Block;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification, models::stellar::state::Density> {
using Type = utils::blocks::density::mass::value;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification,
models::stellar::state::SurfaceShape> {
using Type = utils::blocks::surface_deformation::parameters::value;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification,
models::stellar::state::GravityGradient> {
using Type = utils::blocks::gravity::gradient::value;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<
Specification, models::stellar::state::GravitationalPotential> {
using Type = utils::blocks::gravity::poisson::value;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification,
models::stellar::state::SpecificEnthalpy> {
using Type = utils::blocks::enthalpy::specific::value;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
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 <models::ModelSpecification Specification,
models::ModelSpecification Owner>
struct StellarDependencyBlock<
Specification, models::stellar::state::GeneratedCoordinateOf<Owner>> {
private:
using GeneratedBlocks = typename GeneratedValueBlocksFor<
typename models::SpecificationContribution<Owner>::GeneratedValues>::Type;
using Dependency = models::stellar::state::GeneratedCoordinateOf<Owner>;
using Selection = SingleGeneratedBlock<GeneratedBlocks, Dependency>;
public:
using Type = typename Selection::Type;
static constexpr bool mapped = Selection::available;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<
Specification, models::stellar::equation::GravityGradientDefinition> {
using Type = utils::blocks::gravity::gradient::residual;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification,
models::stellar::equation::PoissonEquation> {
using Type = utils::blocks::gravity::poisson::residual;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification,
models::stellar::equation::DensityClosure> {
using Type = utils::blocks::density::mass::residual;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<
Specification, models::stellar::equation::SurfaceShapeBalance> {
using Type =
utils::blocks::surface_deformation::shape_equilibrium::residual;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<
Specification, models::stellar::equation::HydrostaticBalance> {
using Type = utils::blocks::enthalpy::specific::residual;
static constexpr bool mapped = true;
};
template <models::ModelSpecification Specification>
struct StellarDependencyBlock<Specification,
models::stellar::equation::OwnConstraint> {
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 <models::ModelSpecification Specification,
models::ModelSpecification Owner>
struct StellarDependencyBlock<
Specification, models::stellar::equation::ConstraintOf<Owner>> {
private:
using GeneratedBlocks = typename GeneratedResidualBlocksFor<
typename models::SpecificationContribution<Owner>::GeneratedResiduals>::Type;
using Dependency = models::stellar::equation::ConstraintOf<Owner>;
using Selection = SingleGeneratedBlock<GeneratedBlocks, Dependency>;
public:
using Type = typename Selection::Type;
static constexpr bool mapped = Selection::available;
};
template <models::ModelSpecification Specification, typename Dependencies>
struct CompileStellarDependencies {
using Type = utils::blocks::type_list<
UnmappedStellarDependency<Dependencies>>;
static constexpr bool complete = false;
};
template <models::ModelSpecification Specification, typename... Dependencies>
struct CompileStellarDependencies<Specification,
models::ModelTypeList<Dependencies...>> {
using Type = utils::blocks::type_list<
typename StellarDependencyBlock<Specification, Dependencies>::Type...>;
static constexpr bool complete =
(StellarDependencyBlock<Specification, Dependencies>::mapped && ...);
};
template <typename Residual, typename Values> struct CoupleResidualToValues;
template <typename Residual, typename... Values>
struct CoupleResidualToValues<Residual, utils::blocks::type_list<Values...>> {
using Type = utils::blocks::type_list<
StellarEquilibriumJacobianCoupling<Residual, Values>...>;
};
template <typename Residuals, typename Values>
struct CartesianJacobianCouplings;
template <typename... Residuals, typename Values>
struct CartesianJacobianCouplings<utils::blocks::type_list<Residuals...>,
Values> {
using Type = ConcatenateBlockListsT<
typename CoupleResidualToValues<Residuals, Values>::Type...>;
};
template <typename Candidate> struct IsJacobianCoupling : std::false_type {};
template <typename Residual, typename Value>
struct IsJacobianCoupling<StellarEquilibriumJacobianCoupling<Residual, Value>>
: std::bool_constant<
std::derived_from<Residual, utils::blocks::residual_block_base> &&
std::derived_from<Value, utils::blocks::value_block_base>> {};
template <typename Candidate>
struct IsJacobianCouplingList : std::false_type {};
template <typename... Couplings>
struct IsJacobianCouplingList<utils::blocks::type_list<Couplings...>>
: std::bool_constant<(IsJacobianCoupling<Couplings>::value && ...) &&
utils::blocks::types_are_unique_v<
utils::blocks::type_list<Couplings...>>> {};
template <typename Candidate> struct IsGeneratedValueBlock : std::false_type {};
template <typename Owner>
struct IsGeneratedValueBlock<utils::blocks::generated_value_block<Owner>>
: std::true_type {};
template <typename Candidate>
struct IsGeneratedResidualBlock : std::false_type {};
template <typename Owner>
struct IsGeneratedResidualBlock<utils::blocks::generated_residual_block<Owner>>
: std::true_type {};
template <typename Coupling>
inline constexpr bool isGeneratedBorderIncidentCoupling =
IsGeneratedValueBlock<typename Coupling::Value>::value ||
IsGeneratedResidualBlock<typename Coupling::Residual>::value;
template <typename Couplings> struct GeneratedBorderIncidentCouplings;
template <>
struct GeneratedBorderIncidentCouplings<utils::blocks::type_list<>> {
using Type = utils::blocks::type_list<>;
};
template <typename Head, typename... Tail>
struct GeneratedBorderIncidentCouplings<
utils::blocks::type_list<Head, Tail...>> {
private:
using Remaining = typename GeneratedBorderIncidentCouplings<
utils::blocks::type_list<Tail...>>::Type;
public:
using Type = std::conditional_t<
isGeneratedBorderIncidentCoupling<Head>,
ConcatenateBlockListsT<utils::blocks::type_list<Head>, 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<
DependsOnValueBlocks, GeneratedValueBlocks>;
using ChangedEquationOutputResidualBlocks = AffectedResidualBlocks;
using ConstraintJacobianCouplings =
typename CartesianJacobianCouplings<GeneratedResidualBlocks,
DependsOnValueBlocks>::Type;
using ChangedEquationJacobianCouplings =
typename CartesianJacobianCouplings<AffectedResidualBlocks,
ChangedEquationInputValueBlocks>::Type;
// Compatibility names retained for backend code that distinguishes the
// generated row from the generated-coordinate column.
using GeneratedRowJacobianCouplings = ConstraintJacobianCouplings;
using AffectedRowJacobianCouplings =
typename CartesianJacobianCouplings<AffectedResidualBlocks,
GeneratedValueBlocks>::Type;
using AffectedStateJacobianCouplings =
typename CartesianJacobianCouplings<AffectedResidualBlocks,
DependsOnValueBlocks>::Type;
using JacobianCouplings = UniqueConcatenateBlockListsT<
ConstraintJacobianCouplings, ChangedEquationJacobianCouplings>;
using IncidentJacobianCouplings =
typename GeneratedBorderIncidentCouplings<JacobianCouplings>::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<GeneratedValueBlocks>::value &&
IsResidualBlockList<GeneratedResidualBlocks>::value &&
IsValueBlockList<DependsOnValueBlocks>::value &&
IsResidualBlockList<AffectedResidualBlocks>::value &&
IsJacobianCouplingList<JacobianCouplings>::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 <models::ModelSpecification Specification>
struct SelfDescribingSpecificationCompilationInputs {
using Contribution = models::SpecificationContribution<Specification>;
using DependsOn =
CompileStellarDependencies<Specification, typename Contribution::DependsOn>;
using Affects =
CompileStellarDependencies<Specification, typename Contribution::Affects>;
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 <models::ModelSpecification Specification>
struct SelfDescribingSpecificationCompilation
: DeclarativeStellarEquilibriumSpecificationCompilation<
SelfDescribingSpecificationCompilationInputs<Specification>::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 <typename Specification>
struct StellarEquilibriumSpecificationCompilation
: detail::EmptySpecificationCompilation {};
template <models::ModelSpecification Specification>
struct StellarEquilibriumSpecificationCompilation<Specification>
: detail::SelfDescribingSpecificationCompilation<Specification> {};
namespace detail {
template <typename Specification, typename = void>
struct SpecificationCompilationIsComplete : std::false_type {};
template <typename Specification>
struct SpecificationCompilationIsComplete<
Specification,
std::void_t<typename StellarEquilibriumSpecificationCompilation<
Specification>::GeneratedValueBlocks,
typename StellarEquilibriumSpecificationCompilation<
Specification>::GeneratedResidualBlocks,
typename StellarEquilibriumSpecificationCompilation<
Specification>::DependsOnValueBlocks,
typename StellarEquilibriumSpecificationCompilation<
Specification>::AffectedResidualBlocks,
typename StellarEquilibriumSpecificationCompilation<
Specification>::JacobianCouplings,
std::bool_constant<StellarEquilibriumSpecificationCompilation<
Specification>::registered>,
std::bool_constant<StellarEquilibriumSpecificationCompilation<
Specification>::complete>>>
: std::bool_constant<
StellarEquilibriumSpecificationCompilation<
Specification>::registered &&
StellarEquilibriumSpecificationCompilation<Specification>::complete &&
IsValueBlockList<typename StellarEquilibriumSpecificationCompilation<
Specification>::GeneratedValueBlocks>::value &&
IsResidualBlockList<
typename StellarEquilibriumSpecificationCompilation<
Specification>::GeneratedResidualBlocks>::value &&
IsValueBlockList<typename StellarEquilibriumSpecificationCompilation<
Specification>::DependsOnValueBlocks>::value &&
IsResidualBlockList<
typename StellarEquilibriumSpecificationCompilation<
Specification>::AffectedResidualBlocks>::value &&
IsJacobianCouplingList<
typename StellarEquilibriumSpecificationCompilation<
Specification>::JacobianCouplings>::value> {};
} // namespace detail
template <typename Candidate>
inline constexpr bool stellarEquilibriumSpecificationCompilationComplete =
detail::SpecificationCompilationIsComplete<
std::remove_cvref_t<Candidate>>::value;
template <typename Candidate>
concept StellarEquilibriumSpecificationCompilable =
stellarEquilibriumSpecificationCompilationComplete<Candidate>;
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 <typename Row> struct JacobianRowCouplings;
template <typename Residual, typename... Values>
struct JacobianRowCouplings<utils::blocks::block_row<Residual, Values...>> {
using Type = utils::blocks::type_list<
StellarEquilibriumJacobianCoupling<Residual, Values>...>;
};
template <typename Rows> struct FlattenJacobianRows;
template <typename... Rows>
struct FlattenJacobianRows<utils::blocks::type_list<Rows...>> {
using Type =
ConcatenateBlockListsT<typename JacobianRowCouplings<Rows>::Type...>;
};
using StellarPhysicsJacobianCouplings =
typename FlattenJacobianRows<StellarPhysicsJacobianRows>::Type;
template <typename SpecificationSet>
struct SpecificationSetCompilationsAreComplete;
template <models::ModelSpecification... Specifications>
struct SpecificationSetCompilationsAreComplete<
models::detail::SpecificationSetStorage<Specifications...>>
: std::bool_constant<(
stellarEquilibriumSpecificationCompilationComplete<Specifications> &&
...)> {};
template <typename SpecificationSet, bool Complete>
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 <models::ModelSpecification... Specifications>
struct CollectStellarEquilibriumContributionsImpl<
models::detail::SpecificationSetStorage<Specifications...>, 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 <typename SpecificationSet>
using CollectStellarEquilibriumContributions =
CollectStellarEquilibriumContributionsImpl<
SpecificationSet,
SpecificationSetCompilationsAreComplete<SpecificationSet>::value>;
template <typename Residual, typename Couplings> struct ValuesCoupledToResidual;
template <typename Residual>
struct ValuesCoupledToResidual<Residual, utils::blocks::type_list<>> {
using Type = utils::blocks::type_list<>;
};
template <typename Residual, typename HeadResidual, typename HeadValue,
typename... Tail>
struct ValuesCoupledToResidual<
Residual,
utils::blocks::type_list<
StellarEquilibriumJacobianCoupling<HeadResidual, HeadValue>, Tail...>> {
private:
using Remaining =
typename ValuesCoupledToResidual<Residual,
utils::blocks::type_list<Tail...>>::Type;
public:
using Type = std::conditional_t<
std::same_as<Residual, HeadResidual>,
ConcatenateBlockListsT<utils::blocks::type_list<HeadValue>, Remaining>,
Remaining>;
};
template <typename Residual, typename Values> struct MakeJacobianRow;
template <typename Residual, typename... Values>
struct MakeJacobianRow<Residual, utils::blocks::type_list<Values...>> {
using Type = utils::blocks::block_row<Residual, Values...>;
};
template <typename Residuals, typename Couplings> struct SynthesizeJacobianRows;
template <typename... Residuals, typename Couplings>
struct SynthesizeJacobianRows<utils::blocks::type_list<Residuals...>,
Couplings> {
using Type = utils::blocks::type_list<typename MakeJacobianRow<
Residuals,
typename ValuesCoupledToResidual<Residuals, Couplings>::Type>::Type...>;
};
template <typename Couplings, typename ValueBlocks, typename ResidualBlocks>
struct CouplingEndpointsBelongToForm : std::false_type {};
template <typename ValueBlocks, typename ResidualBlocks, typename... Couplings>
struct CouplingEndpointsBelongToForm<utils::blocks::type_list<Couplings...>,
ValueBlocks, ResidualBlocks>
: std::bool_constant<((utils::blocks::contains_type_v<
typename Couplings::Value, ValueBlocks> &&
utils::blocks::contains_type_v<
typename Couplings::Residual, ResidualBlocks>) &&
...)> {};
template <typename Candidate> 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 <model::StellarModelType Model>
struct CompileStellarEquilibriumSystem<Model> {
using ModelType = std::remove_cvref_t<Model>;
using Contributions = CollectStellarEquilibriumContributions<
typename ModelType::SpecificationTypes>;
using GeneratedValueBlocks = typename Contributions::GeneratedValueBlocks;
using GeneratedCorrectionBlocks = GeneratedValueBlocks;
using GeneratedResidualBlocks =
typename Contributions::GeneratedResidualBlocks;
using ValueBlocks =
ConcatenateBlockListsT<StellarPhysicsValueBlocks, GeneratedValueBlocks>;
using ResidualBlocks = ConcatenateBlockListsT<StellarPhysicsResidualBlocks,
GeneratedResidualBlocks>;
using FormType = utils::blocks::block_form<ValueBlocks, ResidualBlocks>;
using BaseJacobianCouplings = StellarPhysicsJacobianCouplings;
using ContributionJacobianCouplings =
typename Contributions::ContributionJacobianCouplings;
using IncidentJacobianCouplings = ContributionJacobianCouplings;
using JacobianCouplings =
UniqueConcatenateBlockListsT<BaseJacobianCouplings,
ContributionJacobianCouplings>;
// Pass two: materialize rows only after all contributed blocks are
// present in the final form.
using JacobianType =
typename SynthesizeJacobianRows<ResidualBlocks, JacobianCouplings>::Type;
static constexpr bool compilable =
Contributions::complete &&
utils::blocks::block_form_is_valid_v<FormType> &&
IsJacobianCouplingList<JacobianCouplings>::value &&
CouplingEndpointsBelongToForm<JacobianCouplings, ValueBlocks,
ResidualBlocks>::value &&
utils::blocks::jacobian_form_is_valid_v<FormType, JacobianType>;
};
} // namespace detail
template <typename Candidate>
inline constexpr bool stellarEquilibriumSystemIsCompilable =
detail::CompileStellarEquilibriumSystem<
std::remove_cvref_t<Candidate>>::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 <typename Candidate>
inline constexpr bool stellarEquilibriumIsSymbolicallyCompilable =
stellarEquilibriumSystemIsCompilable<Candidate>;
template <typename Candidate>
concept StellarEquilibriumSymbolicallyCompilable =
stellarEquilibriumIsSymbolicallyCompilable<Candidate>;
template <typename Candidate>
concept StellarEquilibriumSystemCompilable =
StellarEquilibriumSymbolicallyCompilable<Candidate>;
template <model::StellarModelType Model>
requires StellarEquilibriumSystemCompilable<Model>
struct CompiledStellarEquilibriumSystem final
: detail::CompileStellarEquilibriumSystem<std::remove_cvref_t<Model>> {
using Base =
detail::CompileStellarEquilibriumSystem<std::remove_cvref_t<Model>>;
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<FormType>);
static_assert(utils::blocks::valid_jacobian_form<FormType, JacobianType>);
};
template <model::StellarModelType Model>
requires StellarEquilibriumSystemCompilable<Model>
using CompiledStellarEquilibriumForm =
typename CompiledStellarEquilibriumSystem<Model>::FormType;
template <model::StellarModelType Model>
requires StellarEquilibriumSystemCompilable<Model>
using CompiledStellarEquilibriumJacobianForm =
typename CompiledStellarEquilibriumSystem<Model>::JacobianType;
} // namespace mean_field::operators