816 lines
33 KiB
C++
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
|