Files
MeanField/tests/operators/stellar_equilibrium_compiler.cpp

2391 lines
105 KiB
C++

#include <concepts>
#include <memory>
#include <type_traits>
#include <utility>
#include <catch2/catch_test_macros.hpp>
#include <mfem.hpp>
import mean_field;
namespace stellar_runtime_contract_test {
template <mean_field::model::StellarModelType Model> class PreparedMissingRieszScalarConstraint;
template <mean_field::model::StellarModelType Model> class PreparedSecondRotationController;
template <mean_field::model::StellarModelType Model> class PreparedRawNestedProtocolConstraint;
struct NonDefaultRuntimeReport final {
NonDefaultRuntimeReport() = delete;
explicit constexpr NonDefaultRuntimeReport(const bool changed) noexcept : m_changed(changed) {
}
[[nodiscard]] constexpr bool DidAnyWork() const noexcept {
return m_changed;
}
private:
bool m_changed;
};
struct NonAssignableRuntimeReport final {
constexpr NonAssignableRuntimeReport() noexcept = default;
NonAssignableRuntimeReport(const NonAssignableRuntimeReport &) = default;
NonAssignableRuntimeReport(NonAssignableRuntimeReport &&) = default;
NonAssignableRuntimeReport &operator=(const NonAssignableRuntimeReport &) = delete;
NonAssignableRuntimeReport &operator=(NonAssignableRuntimeReport &&) = delete;
[[nodiscard]] constexpr bool DidAnyWork() const noexcept {
return false;
}
};
/* Deliberately carries no framework-specific work-reporting method. A
* third-party report is storage for its author's diagnostics, not an input to
* residual-cache correctness. */
struct OpaqueRuntimeReport final {
bool prepared{true};
};
template <mean_field::model::StellarModelType Model, typename ReportType>
class PreparedReportContractRuntime final {
public:
using Report = ReportType;
template <mean_field::models::ModelSpecification Specification>
explicit PreparedReportContractRuntime(const Specification &) noexcept {
}
template <typename StateView> [[nodiscard]] Report PrepareAfterPhysical(const StateView &) noexcept {
if constexpr (std::default_initializable<Report>) {
return {};
} else {
return Report{false};
}
}
template <
typename Equation,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddResidual(
Equation,
Row &
) const noexcept {
return mean_field::stellar::structuralZero;
}
template <
typename Equation,
typename State,
typename Direction,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
Equation,
State>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
[[nodiscard]] constexpr bool IsPrepared() const noexcept {
return true;
}
};
template <mean_field::model::StellarModelType Model>
using PreparedNonDefaultReportRuntime = PreparedReportContractRuntime<Model, NonDefaultRuntimeReport>;
template <mean_field::model::StellarModelType Model>
using PreparedNonAssignableReportRuntime = PreparedReportContractRuntime<Model, NonAssignableRuntimeReport>;
template <mean_field::model::StellarModelType Model>
using PreparedOpaqueReportRuntime = PreparedReportContractRuntime<Model, OpaqueRuntimeReport>;
template <mean_field::model::StellarModelType Model>
using PreparedAmbiguousRegistrationRuntime =
PreparedReportContractRuntime<Model, mean_field::operators::EmptySpecificationPreparationReport>;
struct NonDefaultReportConstraint final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
"runtime.non_default.value",
"lambda_nd",
"runtime.non_default.residual",
"R_nd">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
NonDefaultReportConstraint,
"NonDefaultReportConstraint",
mean_field::stellar::Reads<mean_field::stellar::state::SpecificEnthalpy>,
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
ScalarDescription>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<PreparedNonDefaultReportRuntime>;
explicit constexpr NonDefaultReportConstraint(Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] constexpr auto target() const noexcept {
return m_target;
}
private:
mean_field::dimensions::SpecificEnthalpyValue m_target;
};
struct NonAssignableReportConstraint final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
"runtime.non_assignable.value",
"lambda_na",
"runtime.non_assignable.residual",
"R_na">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
NonAssignableReportConstraint,
"NonAssignableReportConstraint",
mean_field::stellar::Reads<mean_field::stellar::state::SpecificEnthalpy>,
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
ScalarDescription>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<PreparedNonAssignableReportRuntime>;
explicit constexpr NonAssignableReportConstraint(Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] constexpr auto target() const noexcept {
return m_target;
}
private:
mean_field::dimensions::SpecificEnthalpyValue m_target;
};
struct OpaqueReportConstraint final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
"runtime.opaque.value",
"lambda_opaque",
"runtime.opaque.residual",
"R_opaque">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
OpaqueReportConstraint,
"OpaqueReportConstraint",
mean_field::stellar::Reads<mean_field::stellar::state::SpecificEnthalpy>,
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
ScalarDescription>;
using EquilibriumPhysics = mean_field::operators::SpecificationEquilibriumPhysics<PreparedOpaqueReportRuntime>;
explicit constexpr OpaqueReportConstraint(Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] constexpr auto target() const noexcept {
return m_target;
}
private:
mean_field::dimensions::SpecificEnthalpyValue m_target;
};
/* This fixture implements the former nested protocol verbatim. It is a
* physics-facing declaration, so raw backend access must not make it an
* executable contribution. */
struct RawNestedProtocolConstraint final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
"runtime.raw.value",
"lambda_raw",
"runtime.raw.residual",
"R_raw">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
RawNestedProtocolConstraint,
"RawNestedProtocolConstraint",
mean_field::stellar::Reads<mean_field::stellar::state::SpecificEnthalpy>,
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
ScalarDescription>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<PreparedRawNestedProtocolConstraint>;
explicit constexpr RawNestedProtocolConstraint(Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] constexpr auto target() const noexcept {
return m_target;
}
private:
mean_field::dimensions::SpecificEnthalpyValue m_target;
};
struct AmbiguousRuntimeRegistrationConstraint final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
"runtime.ambiguous.value",
"lambda_ar",
"runtime.ambiguous.residual",
"R_ar">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
AmbiguousRuntimeRegistrationConstraint,
"AmbiguousRuntimeRegistrationConstraint",
mean_field::stellar::Reads<mean_field::stellar::state::SpecificEnthalpy>,
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
ScalarDescription>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<PreparedAmbiguousRegistrationRuntime>;
explicit constexpr AmbiguousRuntimeRegistrationConstraint(Parameters parameters) noexcept
: m_target(parameters.target) {
}
[[nodiscard]] constexpr auto target() const noexcept {
return m_target;
}
private:
mean_field::dimensions::SpecificEnthalpyValue m_target;
};
/* A complete aggregate backend candidate with no nested provider. Its raw
* registration is deliberately not authorized by the built-in concrete core,
* so the runtime capability must reject it at exactly that boundary. */
struct UnauthorizedAggregateConstraint final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::SpecificEnthalpy,
"runtime.unauthorized.value",
"lambda_unauthorized",
"runtime.unauthorized.residual",
"R_unauthorized">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
UnauthorizedAggregateConstraint,
"UnauthorizedAggregateConstraint",
mean_field::stellar::Reads<mean_field::stellar::state::SpecificEnthalpy>,
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
ScalarDescription>;
explicit constexpr UnauthorizedAggregateConstraint(Parameters parameters) noexcept
: m_target(parameters.target) {
}
[[nodiscard]] constexpr auto target() const noexcept {
return m_target;
}
private:
mean_field::dimensions::SpecificEnthalpyValue m_target;
};
struct RegisteredWithoutMakeEquationOfState final {
struct Parameters final { };
using ModelDefinition = mean_field::models::
ConstitutiveLaw<RegisteredWithoutMakeEquationOfState, "RegisteredWithoutMakeEquationOfState">;
explicit RegisteredWithoutMakeEquationOfState(Parameters) noexcept {
}
};
struct IncompleteSurfaceRuntime final {
struct Parameters final { };
using ModelDefinition =
mean_field::surface::BoundaryCondition<IncompleteSurfaceRuntime, "IncompleteSurfaceRuntime">;
explicit IncompleteSurfaceRuntime(Parameters) noexcept {
}
};
/*
* This constraint is executable and has complete diagnostic metadata, but it
* deliberately omits its generated-coordinate Physical Riesz declaration.
* It isolates model/discretization compatibility from every other runtime
* capability in the rejection-boundary tests below.
*/
struct MissingRieszScalarConstraint final {
struct Parameters final {
mean_field::dimensions::MassValue target;
};
using TargetValue = mean_field::dimensions::MassValue;
using ModelDefinition = mean_field::integral::FixedIntegralWithMultiplier<
MissingRieszScalarConstraint,
"MissingRieszScalarConstraint",
mean_field::models::DependsOn<mean_field::models::stellar::state::Density>,
mean_field::models::Affects<mean_field::models::stellar::equation::HydrostaticBalance>,
mean_field::models::UnavailableGeneratedNormalization,
mean_field::models::GeneratedManifest<
"missing_riesz.multiplier",
"lambda_mr",
"missing_riesz.residual",
"R_mr",
"mass",
"mass">>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<PreparedMissingRieszScalarConstraint>;
explicit MissingRieszScalarConstraint(Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] TargetValue target() const noexcept {
return m_target;
}
private:
TargetValue m_target;
};
/* A second, independently inferred rotation source. Its numerical runtime is
* otherwise complete; pairing it with FixedAngularMomentum must fail solely
* because a physical model cannot have two owners for the generated rotation
* control. */
struct SecondRotationController final {
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using TargetValue = mean_field::dimensions::SpecificEnthalpyValue;
using ModelDefinition = mean_field::constraint::PhaseCondition<
SecondRotationController,
"SecondRotationController",
mean_field::models::DependsOn<mean_field::models::stellar::state::SpecificEnthalpy>,
mean_field::models::Affects<mean_field::models::stellar::equation::HydrostaticBalance>,
mean_field::models::GlobalScalarNormalization<
mean_field::models::PhysicalScaleLaw::specific_energy,
mean_field::models::PhysicalScaleLaw::specific_energy>,
mean_field::models::GeneratedManifest<
"second_rotation.control",
"omega_2",
"second_rotation.residual",
"R_omega_2",
"specific_enthalpy",
"specific_enthalpy">>;
using EquilibriumPhysics =
mean_field::operators::SpecificationEquilibriumPhysics<PreparedSecondRotationController, 1>;
explicit SecondRotationController(Parameters parameters) noexcept : m_target(parameters.target) {
}
[[nodiscard]] TargetValue target() const noexcept {
return m_target;
}
private:
TargetValue m_target;
};
struct AlternateCoreEquationOfState final {
struct Parameters final { };
using ModelDefinition =
mean_field::models::ConstitutiveLaw<AlternateCoreEquationOfState, "AlternateCoreEquationOfState">;
using Relations = mean_field::eos::RelationCatalog<mean_field::eos::SpecificEnthalpyFromPressure>;
explicit AlternateCoreEquationOfState(Parameters) noexcept {
}
[[nodiscard]] mean_field::dimensions::SpecificEnthalpyValue evaluate(
mean_field::eos::SpecificEnthalpyFromPressure,
mean_field::dimensions::PressureValue
) const;
};
struct WrongOwnerEquationOfState final {
struct Parameters final { };
using ModelDefinition =
mean_field::models::ConstitutiveLaw<WrongOwnerEquationOfState, "WrongOwnerEquationOfState">;
explicit WrongOwnerEquationOfState(Parameters) noexcept {
}
};
/*
* A deliberately tiny alternate core. No MFEM stellar assembly is needed:
* this type exists to prove that the extension protocol is structural and
* does not name the Polytrope implementation.
*/
class AlternatePhysicalCore : public mfem::Operator {
public:
using BackendSpecifications = mean_field::models::ModelTypeList<
AlternateCoreEquationOfState,
WrongOwnerEquationOfState,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass,
mean_field::models::FixedAngularMomentum,
AmbiguousRuntimeRegistrationConstraint>;
using mfem::Operator::Operator;
void Mult(
const mfem::Vector &,
mfem::Vector &
) const override;
[[nodiscard]] const mean_field::operators::StellarEquilibriumLayout &GetLayout() const noexcept;
[[nodiscard]] mean_field::operators::PreparedStellarEquilibriumReport Prepare(
const mfem::Vector &,
const mean_field::operators::StellarEquilibriumDependencies &,
const mean_field::physics::RigidRotation &
);
void BuildResidual(mfem::Vector &) const;
[[nodiscard]] bool IsPrepared() const noexcept;
[[nodiscard]] mean_field::operators::RootConstraintReport GetFixedMassReport() const;
[[nodiscard]] const mean_field::operators::StellarEquilibriumDependencies &GetDependencies() const;
[[nodiscard]] const mean_field::operators::StellarEquilibriumDependencyStamp &
GetGeneratedDisplacementDependency() const;
[[nodiscard]] const mean_field::operators::PreparedPressureSurfaceConstraint &
GetSurfaceConstraintOperator() const;
};
class PhysicalRieszGravityContext final {
public:
[[nodiscard]] const mean_field::field::FieldDofMap &GetDensityMap() const noexcept;
[[nodiscard]] const mean_field::field::FieldDofMap &GetGravityGradientMap() const noexcept;
[[nodiscard]] const mean_field::field::FieldDofMap &GetGravityPotentialMap() const noexcept;
};
class PhysicalRieszHydrostaticOperator final {
public:
[[nodiscard]] const mean_field::field::FieldDofMap &GetEnthalpyMap() const noexcept;
};
class PhysicalRieszDomainDeformation final {
public:
[[nodiscard]] int parameterCount() const noexcept;
};
/*
* Declaration-only opt-in mock: the normalization capability is structural,
* so none of the heavyweight MFEM physical assembly needs to be constructed
* to prove that a distinct core can satisfy it.
*/
class PhysicalRieszCapableCore final : public AlternatePhysicalCore {
public:
using AlternatePhysicalCore::AlternatePhysicalCore;
[[nodiscard]] const PhysicalRieszGravityContext &GetGravityContext() const noexcept;
[[nodiscard]] const PhysicalRieszHydrostaticOperator &GetHydrostaticOperator() const noexcept;
[[nodiscard]] const PhysicalRieszDomainDeformation &GetDomainDeformation() const noexcept;
};
template <mean_field::model::StellarModelType Model> class AlternateEquationOfStateRuntime final {
public:
using Report = mean_field::operators::EmptySpecificationPreparationReport;
AlternateEquationOfStateRuntime(
mean_field::fem::FEM &,
const mean_field::mapping::DomainMapper &,
AlternatePhysicalCore &,
const Model &
) noexcept {
}
template <
typename StateView,
typename Controls>
void ReadPhysicalControls(
const StateView &,
Controls &
) noexcept {
}
template <typename StateView>
[[nodiscard]] Report PrepareAfterPhysical(
const StateView &,
const mean_field::operators::StellarEquilibriumDependencies &,
const AlternatePhysicalCore &
) noexcept {
return {};
}
template <typename ResidualView> void AddResidual(const ResidualView &) const noexcept {
}
template <
typename DirectionView,
typename ActionView>
void AddJacobianAction(
const DirectionView &,
const ActionView &,
const AlternatePhysicalCore &
) const noexcept {
}
[[nodiscard]] bool IsPrepared() const noexcept {
return true;
}
};
template <mean_field::model::StellarModelType Model> class IncompletePreparedSurfaceRuntime final {
public:
struct Report final {
[[nodiscard]] constexpr bool DidAnyWork() const noexcept {
return false;
}
};
IncompletePreparedSurfaceRuntime(
mean_field::fem::FEM &,
const mean_field::mapping::DomainMapper &,
mean_field::operators::PreparedStellarEquilibriumOperator &,
const Model &
) noexcept {
}
// Intentionally omits the preparation and operator-action interface.
};
template <mean_field::model::StellarModelType Model> class PreparedMissingRieszScalarConstraint final {
public:
using Report = mean_field::operators::EmptySpecificationPreparationReport;
explicit PreparedMissingRieszScalarConstraint(const MissingRieszScalarConstraint &) noexcept {
}
template <typename StateView> [[nodiscard]] Report PrepareAfterPhysical(const StateView &) noexcept {
return {};
}
template <
typename Equation,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddResidual(
Equation,
Row &
) const noexcept {
return mean_field::stellar::structuralZero;
}
template <
typename Equation,
typename State,
typename Direction,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
Equation,
State>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
[[nodiscard]] constexpr bool IsPrepared() const noexcept {
return true;
}
};
template <mean_field::model::StellarModelType Model> class PreparedSecondRotationController final {
public:
using Report = mean_field::operators::EmptySpecificationPreparationReport;
explicit PreparedSecondRotationController(const SecondRotationController &) noexcept {
}
template <typename StateView>
[[nodiscard]] mean_field::physics::RigidRotation GenerateRotation(const StateView &) const {
mfem::Vector angularVelocity(3);
mfem::Vector center(3);
angularVelocity = 0.0;
center = 0.0;
return {angularVelocity, center};
}
template <typename StateView> [[nodiscard]] Report PrepareAfterPhysical(const StateView &) noexcept {
return {};
}
template <
typename Equation,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddResidual(
Equation,
Row &
) const noexcept {
return mean_field::stellar::structuralZero;
}
template <
typename Equation,
typename State,
typename Direction,
typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
Equation,
State>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
[[nodiscard]] constexpr bool IsPrepared() const noexcept {
return true;
}
};
template <mean_field::model::StellarModelType Model> class PreparedRawNestedProtocolConstraint final {
public:
using Report = OpaqueRuntimeReport;
template <mean_field::operators::PreparedStellarEquilibriumPhysicalCore Core>
PreparedRawNestedProtocolConstraint(
mean_field::fem::FEM &,
const mean_field::mapping::DomainMapper &,
Core &,
const Model &
) noexcept {
}
template <
typename StateView,
typename Controls>
void ReadPhysicalControls(
const StateView &,
Controls &
) noexcept {
}
template <
typename StateView,
mean_field::operators::PreparedStellarEquilibriumPhysicalCore Core>
[[nodiscard]] Report PrepareAfterPhysical(
const StateView &,
const mean_field::operators::StellarEquilibriumDependencies &,
const Core &
) noexcept {
return {};
}
template <typename ResidualView> void AddResidual(const ResidualView &) const noexcept {
}
template <
typename DirectionView,
typename ActionView,
mean_field::operators::PreparedStellarEquilibriumPhysicalCore Core>
void AddJacobianAction(
const DirectionView &,
const ActionView &,
const Core &
) const noexcept {
}
[[nodiscard]] constexpr bool IsPrepared() const noexcept {
return true;
}
};
} // namespace stellar_runtime_contract_test
namespace mean_field::operators {
template <>
struct StellarEquilibriumCoreRuntime<stellar_runtime_contract_test::RegisteredWithoutMakeEquationOfState> {
static constexpr bool registered = true;
// Intentionally no Make(). Capability follows the callable interface.
};
template <> struct StellarEquilibriumCoreRuntime<stellar_runtime_contract_test::AlternateCoreEquationOfState> {
static constexpr bool registered = true;
using CoreType = stellar_runtime_contract_test::AlternatePhysicalCore;
[[nodiscard]] static std::unique_ptr<CoreType> Make(
fem::FEM &,
const mapping::DomainMapper &,
const stellar_runtime_contract_test::AlternateCoreEquationOfState &,
const models::CompiledFixedMass &,
PressureSurfaceConstraintView,
deformation::PreparedDomainDeformationRuntime
);
[[nodiscard]] static int SurfaceEquationCount(const CoreType &) noexcept;
};
template <>
struct StellarEquilibriumRuntimeContribution<stellar_runtime_contract_test::AlternateCoreEquationOfState>
: PreparedStellarEquilibriumContribution<stellar_runtime_contract_test::AlternateEquationOfStateRuntime> { };
template <> struct StellarEquilibriumCoreRuntime<stellar_runtime_contract_test::WrongOwnerEquationOfState> {
static constexpr bool registered = true;
using CoreType = stellar_runtime_contract_test::AlternatePhysicalCore;
// Intentionally owns the Polytrope core instead of the advertised type.
[[nodiscard]] static std::unique_ptr<PreparedStellarEquilibriumOperator> Make(
fem::FEM &,
const mapping::DomainMapper &,
const stellar_runtime_contract_test::WrongOwnerEquationOfState &,
const models::CompiledFixedMass &,
PressureSurfaceConstraintView,
deformation::PreparedDomainDeformationRuntime
);
[[nodiscard]] static int SurfaceEquationCount(const CoreType &) noexcept;
};
template <>
struct StellarEquilibriumRuntimeContribution<stellar_runtime_contract_test::WrongOwnerEquationOfState>
: PreparedStellarEquilibriumContribution<stellar_runtime_contract_test::AlternateEquationOfStateRuntime> { };
template <>
struct StellarEquilibriumRuntimeContribution<stellar_runtime_contract_test::IncompleteSurfaceRuntime>
: PreparedStellarEquilibriumContribution<stellar_runtime_contract_test::IncompletePreparedSurfaceRuntime> { };
template <>
struct StellarEquilibriumRuntimeContribution<stellar_runtime_contract_test::UnauthorizedAggregateConstraint>
: PreparedStellarEquilibriumContribution<stellar_runtime_contract_test::PreparedRawNestedProtocolConstraint> {
};
/* Deliberately duplicates the constraint's nested package. Whether that is an
* ambiguity depends on the selected core's own privileged allow-list. */
template <>
struct StellarEquilibriumRuntimeContribution<stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint>
: PreparedStellarEquilibriumContribution<stellar_runtime_contract_test::AlternateEquationOfStateRuntime> { };
} // namespace mean_field::operators
namespace {
using namespace mean_field;
using BaseModel =
model::StellarModel<models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass>>;
using CentralDensityModel = model::StellarModel<
models::
SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, models::FixedCentralDensity>>;
using AngularMomentumModel = model::StellarModel<
models::
SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, models::FixedAngularMomentum>>;
using AngularCentralDensityModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
models::FixedAngularMomentum,
models::FixedCentralDensity>>;
using DensityValue = utils::blocks::density::mass::value;
using SurfaceValue = utils::blocks::surface_deformation::parameters::value;
using GravityGradientValue = utils::blocks::gravity::gradient::value;
using GravityPotentialValue = utils::blocks::gravity::poisson::value;
using EnthalpyValue = utils::blocks::enthalpy::specific::value;
using MassValue = utils::blocks::fixed_total_mass::mass_normalization::value;
using AngularVelocityValue = utils::blocks::fixed_angular_momentum::angular_velocity::value;
using CentralDensityValue = utils::blocks::fixed_central_density::central_value::value;
using GravityGradientResidual = utils::blocks::gravity::gradient::residual;
using GravityPotentialResidual = utils::blocks::gravity::poisson::residual;
using DensityResidual = utils::blocks::density::mass::residual;
using SurfaceResidual = utils::blocks::surface_deformation::shape_equilibrium::residual;
using EnthalpyResidual = utils::blocks::enthalpy::specific::residual;
using MassResidual = utils::blocks::fixed_total_mass::mass_normalization::residual;
using AngularMomentumResidual = utils::blocks::fixed_angular_momentum::angular_velocity::residual;
using CentralDensityResidual = utils::blocks::fixed_central_density::central_value::residual;
using ExpectedAngularMomentumForm = utils::blocks::block_form<
utils::blocks::type_list<
DensityValue,
SurfaceValue,
GravityGradientValue,
GravityPotentialValue,
EnthalpyValue,
MassValue,
AngularVelocityValue>,
utils::blocks::type_list<
GravityGradientResidual,
GravityPotentialResidual,
DensityResidual,
SurfaceResidual,
EnthalpyResidual,
MassResidual,
AngularMomentumResidual>>;
using ExpectedAngularMomentumJacobian = utils::blocks::type_list<
utils::blocks::block_row<GravityGradientResidual, GravityGradientValue, GravityPotentialValue, SurfaceValue>,
utils::blocks::block_row<GravityPotentialResidual, GravityGradientValue, DensityValue, SurfaceValue>,
utils::blocks::block_row<DensityResidual, DensityValue, EnthalpyValue, SurfaceValue>,
utils::blocks::block_row<
SurfaceResidual,
DensityValue,
SurfaceValue,
GravityGradientValue,
EnthalpyValue,
AngularVelocityValue>,
utils::blocks::block_row<
EnthalpyResidual,
EnthalpyValue,
GravityPotentialValue,
SurfaceValue,
DensityValue,
MassValue,
AngularVelocityValue>,
utils::blocks::block_row<MassResidual, DensityValue, SurfaceValue>,
utils::blocks::block_row<AngularMomentumResidual, DensityValue, SurfaceValue, AngularVelocityValue>>;
using ExpectedAngularCentralDensityForm = utils::blocks::block_form<
utils::blocks::type_list<
DensityValue,
SurfaceValue,
GravityGradientValue,
GravityPotentialValue,
EnthalpyValue,
MassValue,
AngularVelocityValue,
CentralDensityValue>,
utils::blocks::type_list<
GravityGradientResidual,
GravityPotentialResidual,
DensityResidual,
SurfaceResidual,
EnthalpyResidual,
MassResidual,
AngularMomentumResidual,
CentralDensityResidual>>;
using ExpectedAngularCentralDensityJacobian = utils::blocks::type_list<
utils::blocks::block_row<GravityGradientResidual, GravityGradientValue, GravityPotentialValue, SurfaceValue>,
utils::blocks::block_row<GravityPotentialResidual, GravityGradientValue, DensityValue, SurfaceValue>,
utils::blocks::block_row<DensityResidual, DensityValue, EnthalpyValue, SurfaceValue>,
utils::blocks::block_row<
SurfaceResidual,
DensityValue,
SurfaceValue,
GravityGradientValue,
EnthalpyValue,
AngularVelocityValue>,
utils::blocks::block_row<
EnthalpyResidual,
EnthalpyValue,
GravityPotentialValue,
SurfaceValue,
DensityValue,
MassValue,
AngularVelocityValue,
CentralDensityValue>,
utils::blocks::block_row<MassResidual, DensityValue, SurfaceValue>,
utils::blocks::block_row<AngularMomentumResidual, DensityValue, SurfaceValue, AngularVelocityValue>,
utils::blocks::block_row<CentralDensityResidual, EnthalpyValue>>;
using MissingMassModel = model::StellarModel<models::SpecificationSet<eos::Polytrope, surface::Isobaric>>;
using RegisteredWithoutMakeModel = model::StellarModel<models::SpecificationSet<
stellar_runtime_contract_test::RegisteredWithoutMakeEquationOfState,
surface::Isobaric,
models::FixedTotalMass>>;
using AlternateCoreModel = model::StellarModel<models::SpecificationSet<
stellar_runtime_contract_test::AlternateCoreEquationOfState,
surface::Isobaric,
models::FixedTotalMass>>;
using AlternateCoreAngularMomentumModel = model::StellarModel<models::SpecificationSet<
stellar_runtime_contract_test::AlternateCoreEquationOfState,
surface::Isobaric,
models::FixedTotalMass,
models::FixedAngularMomentum>>;
using MissingRieszModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::MissingRieszScalarConstraint>>;
using TwoRotationProvidersModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
models::FixedAngularMomentum,
stellar_runtime_contract_test::SecondRotationController>>;
using NonDefaultReportModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::NonDefaultReportConstraint>>;
using NonAssignableReportModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::NonAssignableReportConstraint>>;
using OpaqueReportModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::OpaqueReportConstraint>>;
using RawNestedProtocolModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::RawNestedProtocolConstraint>>;
/*
* Focused fixtures for the exact physics-provider contract. Every class is
* constructible from the same valid specification, so a failed provider
* concept below can only come from its residual/Jacobian overload set.
*
* RawNestedProtocolConstraint declares one owned constraint row, one changed
* physical row, one read physical state, and one owned generated coordinate.
* The compiler therefore requires exactly two residual providers and three
* derivative providers.
*/
class CompleteExplicitZeroProvider final {
public:
explicit CompleteExplicitZeroProvider(
const stellar_runtime_contract_test::RawNestedProtocolConstraint &
) noexcept {
}
template <typename Row>
[[nodiscard]] stellar::StructuralZero AddResidual(
stellar::equation::OwnConstraint,
Row &
) const noexcept {
return stellar::structuralZero;
}
template <typename Row>
[[nodiscard]] stellar::StructuralZero AddResidual(
stellar::equation::HydrostaticBalance,
Row &
) const noexcept {
return stellar::structuralZero;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::OwnConstraint,
stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::HydrostaticBalance,
stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::HydrostaticBalance,
stellar::state::OwnGeneratedCoordinate>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
};
class MissingHydrostaticResidualProvider final {
public:
explicit MissingHydrostaticResidualProvider(
const stellar_runtime_contract_test::RawNestedProtocolConstraint &
) noexcept {
}
template <typename Row>
[[nodiscard]] stellar::StructuralZero AddResidual(
stellar::equation::OwnConstraint,
Row &
) const noexcept {
return stellar::structuralZero;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::OwnConstraint,
stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::HydrostaticBalance,
stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::HydrostaticBalance,
stellar::state::OwnGeneratedCoordinate>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
};
class MissingGeneratedControlDerivativeProvider final {
public:
explicit MissingGeneratedControlDerivativeProvider(
const stellar_runtime_contract_test::RawNestedProtocolConstraint &
) noexcept {
}
template <typename Row>
[[nodiscard]] stellar::StructuralZero AddResidual(
stellar::equation::OwnConstraint,
Row &
) const noexcept {
return stellar::structuralZero;
}
template <typename Row>
[[nodiscard]] stellar::StructuralZero AddResidual(
stellar::equation::HydrostaticBalance,
Row &
) const noexcept {
return stellar::structuralZero;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::OwnConstraint,
stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
template <
typename Direction,
typename Row>
[[nodiscard]] stellar::StructuralZero AddJacobianAction(
stellar::Derivative<
stellar::equation::HydrostaticBalance,
stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return stellar::zeroDerivative;
}
};
/* The pre-refactor imperative shape can be constructed, but neither callback
* identifies a compiler-enumerated equation/state pair or returns the token
* required to prove that the pair was handled. */
class LegacyBroadEmptyProvider final {
public:
explicit LegacyBroadEmptyProvider(const stellar_runtime_contract_test::RawNestedProtocolConstraint &) noexcept {
}
template <typename ResidualView> void AddResidual(const ResidualView &) const noexcept {
}
template <
typename DirectionView,
typename ActionView,
typename Core>
void AddJacobianAction(
const DirectionView &,
const ActionView &,
const Core &
) const noexcept {
}
};
template <typename Physics, typename Equation>
concept HasExactProviderResidual = requires(
const Physics &physics,
operators::StellarEquilibriumContributionRow<
stellar_runtime_contract_test::RawNestedProtocolConstraint,
RawNestedProtocolModel,
Equation> &row
) {
{ physics.AddResidual(Equation{}, row) } -> stellar::ContributionResult;
};
template <typename Physics, typename Equation, typename State>
concept HasExactProviderDerivative = requires(
const Physics &physics,
const operators::StellarEquilibriumContributionDirection<
stellar_runtime_contract_test::RawNestedProtocolConstraint,
RawNestedProtocolModel,
State> &direction,
operators::StellarEquilibriumContributionRow<
stellar_runtime_contract_test::RawNestedProtocolConstraint,
RawNestedProtocolModel,
Equation> &row
) {
{
physics.AddJacobianAction(stellar::Derivative<Equation, State>{}, direction, row)
} -> stellar::ContributionResult;
};
using AmbiguousRuntimeRegistrationModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint>>;
using UnauthorizedAggregateModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::UnauthorizedAggregateConstraint>>;
using AuthorizedAmbiguousRuntimeRegistrationModel = model::StellarModel<models::SpecificationSet<
stellar_runtime_contract_test::AlternateCoreEquationOfState,
surface::Isobaric,
models::FixedTotalMass,
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint>>;
using PhysicalRieszDiscretization = equilibrium::StellarDiscretizationFor<normalization::PhysicalRieszDiagonal<>>;
using BaseProblem = equilibrium::StellarEquilibriumProblem<BaseModel>;
using BasePhysicalRieszProblem = equilibrium::StellarEquilibriumProblem<BaseModel, PhysicalRieszDiscretization>;
using AlternateCoreProblem = equilibrium::StellarEquilibriumProblem<AlternateCoreModel>;
using MissingRieszUnnormalizedProblem = equilibrium::StellarEquilibriumProblem<MissingRieszModel>;
using WrongOwnerModel = model::StellarModel<models::SpecificationSet<
stellar_runtime_contract_test::WrongOwnerEquationOfState,
surface::Isobaric,
models::FixedTotalMass>>;
using IncompleteSurfaceRuntimeModel = model::StellarModel<models::SpecificationSet<
eos::Polytrope,
stellar_runtime_contract_test::IncompleteSurfaceRuntime,
models::FixedTotalMass>>;
using CarrierlessManifestForm = utils::blocks::block_form<
utils::blocks::type_list<utils::blocks::fixed_total_mass::mass_normalization::value>,
utils::blocks::type_list<utils::blocks::fixed_total_mass::mass_normalization::residual>>;
struct UnsupportedCentralDensityEquationOfState final {
struct Parameters final { };
using ModelDefinition = models::
ConstitutiveLaw<UnsupportedCentralDensityEquationOfState, "UnsupportedCentralDensityEquationOfState">;
explicit UnsupportedCentralDensityEquationOfState(Parameters) noexcept {
}
};
using UnsupportedCentralDensityModel = model::StellarModel<models::SpecificationSet<
UnsupportedCentralDensityEquationOfState,
surface::Isobaric,
models::FixedTotalMass,
models::FixedCentralDensity>>;
struct EarlierMultiplier final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithMultiplier<
EarlierMultiplier,
"AardvarkMultiplier",
models::DependsOn<utils::blocks::density::mass::value>,
models::Affects<utils::blocks::enthalpy::specific::residual>>;
explicit EarlierMultiplier(Parameters) noexcept {
}
};
using EarlierMultiplierValue = utils::blocks::generated_value_block<models::MultiplierFor<EarlierMultiplier>>;
using EarlierMultiplierModel = model::StellarModel<
models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, EarlierMultiplier>>;
struct FullPhysicsStateReader final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
FullPhysicsStateReader,
"FullPhysicsStateReader",
models::DependsOn<
models::stellar::state::Density,
models::stellar::state::SurfaceShape,
models::stellar::state::GravityGradient,
models::stellar::state::GravitationalPotential,
models::stellar::state::SpecificEnthalpy>,
models::Affects<models::stellar::equation::HydrostaticBalance>>;
explicit FullPhysicsStateReader(Parameters) noexcept {
}
};
using FullPhysicsStateReaderModel = model::StellarModel<
models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, FullPhysicsStateReader>>;
struct CrossAlpha;
struct CrossBeta;
using CrossAlphaValue = utils::blocks::generated_value_block<models::PhysicalCoordinateFor<CrossAlpha>>;
using CrossAlphaResidual = utils::blocks::generated_residual_block<models::ResidualFor<CrossAlpha>>;
using CrossBetaValue = utils::blocks::generated_value_block<models::PhysicalCoordinateFor<CrossBeta>>;
using CrossBetaResidual = utils::blocks::generated_residual_block<models::ResidualFor<CrossBeta>>;
struct CrossAlphaTerm final {
using value = CrossAlphaValue;
using residual = CrossAlphaResidual;
};
struct CrossBetaTerm final {
using value = CrossBetaValue;
using residual = CrossBetaResidual;
};
inline constexpr CrossAlphaTerm crossAlphaTerm{};
inline constexpr CrossBetaTerm crossBetaTerm{};
struct NoOpJacobianCallback final {
template <
typename DirectionView,
typename ActionView>
void operator()(
DirectionView &,
ActionView &
) const noexcept {
}
};
struct OneArgumentJacobianCallback final {
template <typename DirectionView> void operator()(DirectionView &) const noexcept {
}
};
struct NonVoidJacobianCallback final {
template <
typename DirectionView,
typename ActionView>
[[nodiscard]] int operator()(
DirectionView &,
ActionView &
) const noexcept {
return 0;
}
};
template <
typename JacobianView,
typename ResidualTerm,
typename ValueTerm,
typename Callback = NoOpJacobianCallback>
concept CanBindDeclaredJacobianCallback = requires(
const JacobianView &jacobian,
const ResidualTerm &residual,
const ValueTerm &value,
Callback callback
) { jacobian.add(residual, value, std::move(callback)); };
template <typename JacobianView, typename ResidualTerm, typename ValueTerm>
concept CanAddRawJacobianContribution =
requires(const JacobianView &jacobian, const ResidualTerm &residual, const ValueTerm &value) {
jacobian.add(residual, value, 1.0);
};
template <typename JacobianView, typename ResidualTerm, typename ValueTerm>
concept CanAddRawJacobianEntry =
requires(const JacobianView &jacobian, const ResidualTerm &residual, const ValueTerm &value) {
jacobian.addEntry(residual, value, 0, 1.0);
};
/*
* Alpha is canonicalized before Beta, yet both of Alpha's edges name a
* block contributed by Beta. A sequential compiler loses Alpha's affected
* edge because Beta's residual row does not exist yet.
*/
struct CrossAlpha final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
CrossAlpha,
"CompilerCrossAlpha",
models::DependsOn<CrossBetaValue>,
models::Affects<CrossBetaResidual>>;
explicit CrossAlpha(Parameters) noexcept {
}
};
struct CrossBeta final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
CrossBeta,
"CompilerCrossBeta",
models::DependsOn<utils::blocks::density::mass::value>,
models::Affects<utils::blocks::surface_deformation::shape_equilibrium::residual>>;
explicit CrossBeta(Parameters) noexcept {
}
};
using CrossModel = model::StellarModel<
models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, CrossAlpha, CrossBeta>>;
using PermutedCrossModel = model::StellarModel<
models::SpecificationSet<CrossBeta, models::FixedTotalMass, surface::Isobaric, CrossAlpha, eos::Polytrope>>;
struct MalformedDeclaration final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
MalformedDeclaration,
"MalformedCompilerDeclaration",
models::DependsOn<int>,
models::Affects<utils::blocks::enthalpy::specific::residual>>;
explicit MalformedDeclaration(Parameters) noexcept {
}
};
using MalformedModel = model::StellarModel<
models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, MalformedDeclaration>>;
struct UnmappedStellarState final { };
struct UnmappedPhysicsDependency final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
UnmappedPhysicsDependency,
"UnmappedPhysicsDependency",
models::DependsOn<UnmappedStellarState>,
models::Affects<models::stellar::equation::HydrostaticBalance>>;
explicit UnmappedPhysicsDependency(Parameters) noexcept {
}
};
using UnmappedPhysicsModel = model::StellarModel<
models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, UnmappedPhysicsDependency>>;
struct UnmappedStellarEquation final { };
struct UnmappedPhysicsEffect final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
UnmappedPhysicsEffect,
"UnmappedPhysicsEffect",
models::DependsOn<models::stellar::state::Density>,
models::Affects<UnmappedStellarEquation>>;
explicit UnmappedPhysicsEffect(Parameters) noexcept {
}
};
using UnmappedPhysicsEffectModel = model::StellarModel<
models::SpecificationSet<eos::Polytrope, surface::Isobaric, models::FixedTotalMass, UnmappedPhysicsEffect>>;
struct ForeignValueBlock final : utils::blocks::value_block_base { };
struct OrphanEndpoint final {
struct Parameters final { };
using ModelDefinition = models::FixedIntegralWithPhysicalCoordinate<
OrphanEndpoint,
"OrphanCompilerEndpoint",
models::DependsOn<ForeignValueBlock>,
models::Affects<utils::blocks::enthalpy::specific::residual>>;
explicit OrphanEndpoint(Parameters) noexcept {
}
};
using OrphanEndpointModel = model::StellarModel<models::SpecificationSet<eos::Polytrope, OrphanEndpoint>>;
template <typename Candidate>
concept HasCompiledStellarEquilibriumSystem =
requires { typename operators::CompiledStellarEquilibriumSystem<Candidate>; };
template <typename Candidate>
concept HasPreparedVariadicStellarEquilibriumOperator =
requires { typename operators::PreparedVariadicStellarEquilibriumOperator<Candidate>; };
template <typename Problem>
concept HasNormalizedStellarEquilibriumOperator =
requires { typename normalization::NormalizedStellarEquilibriumOperator<Problem>; };
template <typename Problem>
concept CanMakeNormalizedStellarEquilibriumOperator =
requires(Problem &problem) { normalization::makeNormalizedStellarEquilibriumOperator(problem); };
template <typename Problem>
concept CanMakeDefaultStellarPreconditioner =
requires(const Problem &problem) { preconditioning::makePreconditioner(problem); };
template <typename Model, typename Discretization>
concept HasStellarEquilibriumProblem =
requires { typename equilibrium::StellarEquilibriumProblem<Model, Discretization>; };
template <typename Model, typename Discretization>
concept CanDiscretizeStellarModel = requires(Model &&model, Discretization discretization) {
equilibrium::discretize(std::move(model), std::move(discretization));
};
template <typename View, typename Term>
concept CanAccessContributionBlock = requires(const View &view, const Term &term) { view.block(term); };
template <typename View, typename Term>
concept CanAddContributionBlock = requires(const View &view, const Term &term) { view.add(term, 0.0); };
template <typename View, typename Term>
concept CanAddContributionVectorAndEntry =
requires(const View &view, const Term &term, const mfem::Vector &contribution) {
view.add(term, contribution);
view.addEntry(term, 0, 0.0);
};
template <typename View>
concept HasPhysicsDensity = requires(const View &view) { view.density(); };
template <typename View>
concept HasPhysicsSurfaceShape = requires(const View &view) { view.surfaceShape(); };
template <typename View>
concept HasPhysicsGravityGradient = requires(const View &view) { view.gravityGradient(); };
template <typename View>
concept HasPhysicsGravitationalPotential = requires(const View &view) { view.gravitationalPotential(); };
template <typename View>
concept HasPhysicsSpecificEnthalpy = requires(const View &view) { view.specificEnthalpy(); };
template <typename View>
concept HasPhysicsGeneratedCoordinate = requires(const View &view) { view.generatedCoordinate(); };
template <typename View>
concept ExposesUnrestrictedRootVector = requires(const View &view) { view.vector(); };
template <
typename ExpectedSourceTerm,
typename OtherSourceTerm,
typename ExpectedResidualTerm,
typename OtherResidualTerm,
bool NamesOwnGeneratedCoordinate>
struct ExactPairAuditCallback final {
template <
typename DirectionView,
typename ActionView>
requires CanAccessContributionBlock<
DirectionView,
ExpectedSourceTerm> &&
(!CanAccessContributionBlock<
DirectionView,
OtherSourceTerm>) &&
(HasPhysicsGeneratedCoordinate<DirectionView> == NamesOwnGeneratedCoordinate) &&
(!HasPhysicsDensity<DirectionView>) && (!HasPhysicsSpecificEnthalpy<DirectionView>) &&
CanAddContributionBlock<
ActionView,
ExpectedResidualTerm> &&
CanAddContributionVectorAndEntry<
ActionView,
ExpectedResidualTerm> &&
(!CanAddContributionBlock<
ActionView,
OtherResidualTerm>) &&
(!ExposesUnrestrictedRootVector<DirectionView>) && (!ExposesUnrestrictedRootVector<ActionView>)
void operator()(
DirectionView &,
ActionView &
) const noexcept {
}
};
struct RequiresCrossProductDirectionCallback final {
template <
typename DirectionView,
typename ActionView>
requires CanAccessContributionBlock<
DirectionView,
CrossAlphaTerm> &&
CanAccessContributionBlock<
DirectionView,
CrossBetaTerm>
void operator()(
DirectionView &,
ActionView &
) const noexcept {
}
};
struct RequiresCrossProductActionCallback final {
template <
typename DirectionView,
typename ActionView>
requires CanAddContributionBlock<
ActionView,
CrossAlphaTerm> &&
CanAddContributionBlock<
ActionView,
CrossBetaTerm>
void operator()(
DirectionView &,
ActionView &
) const noexcept {
}
};
} // namespace
TEST_CASE(
"Two-Pass Stellar Compiler Preserves Established Physical Forms",
"[stellar-equilibrium][compiler][type-contract]"
) {
using namespace mean_field;
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<BaseModel>);
STATIC_CHECK(BaseModel::hasCompleteEquilibriumDeclaration);
STATIC_CHECK(
operators::CompiledStellarEquilibriumSystem<BaseModel>::compilationClass ==
models::EquilibriumSystemCompilation::complete_equilibrium_system
);
STATIC_CHECK(operators::hasStellarEquilibriumCoreRuntime<BaseModel>);
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<BaseModel>);
STATIC_CHECK(equilibrium::hasStellarEquilibriumSurfaceCompilation<BaseModel>);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<CentralDensityModel>);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<AngularMomentumModel>);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<AngularCentralDensityModel>);
STATIC_CHECK((std::same_as<
operators::CompiledStellarEquilibriumForm<BaseModel>,
utils::blocks::surface_deformed_stellar_equilibrium_form>));
STATIC_CHECK((std::same_as<
operators::CompiledStellarEquilibriumJacobianForm<BaseModel>,
utils::blocks::surface_deformed_stellar_equilibrium_jacobian_form>));
STATIC_CHECK((std::same_as<
operators::CompiledStellarEquilibriumForm<CentralDensityModel>,
utils::blocks::central_density_bordered_stellar_equilibrium_form>));
STATIC_CHECK((std::same_as<
operators::CompiledStellarEquilibriumJacobianForm<CentralDensityModel>,
utils::blocks::central_density_bordered_stellar_equilibrium_jacobian_form>));
STATIC_CHECK((
std::same_as<operators::CompiledStellarEquilibriumForm<AngularMomentumModel>, ExpectedAngularMomentumForm>
));
STATIC_CHECK((
std::same_as<
operators::CompiledStellarEquilibriumJacobianForm<AngularMomentumModel>, ExpectedAngularMomentumJacobian>
));
STATIC_CHECK((
std::same_as<
operators::CompiledStellarEquilibriumForm<AngularCentralDensityModel>, ExpectedAngularCentralDensityForm>
));
STATIC_CHECK((std::same_as<
operators::CompiledStellarEquilibriumJacobianForm<AngularCentralDensityModel>,
ExpectedAngularCentralDensityJacobian>));
}
TEST_CASE(
"Runtime Contributions See Only Their Declared Physics Blocks",
"[stellar-equilibrium][runtime][sparsity][type-contract]"
) {
using namespace mean_field;
using AngularState =
operators::StellarEquilibriumContributionStateView<models::FixedAngularMomentum, AngularMomentumModel>;
using AngularResidual =
operators::StellarEquilibriumContributionResidualView<models::FixedAngularMomentum, AngularMomentumModel>;
using CentralState =
operators::StellarEquilibriumContributionStateView<models::FixedCentralDensity, CentralDensityModel>;
using CentralResidual =
operators::StellarEquilibriumContributionResidualView<models::FixedCentralDensity, CentralDensityModel>;
using FullPhysicsState =
operators::StellarEquilibriumContributionStateView<FullPhysicsStateReader, FullPhysicsStateReaderModel>;
STATIC_CHECK(CanAccessContributionBlock<AngularState, decltype(utils::blocks::density_field.mass_term)>);
STATIC_CHECK(
CanAccessContributionBlock<AngularState, decltype(utils::blocks::surface_deformation_field.parameters_term)>
);
STATIC_CHECK(
CanAccessContributionBlock<
AngularState, decltype(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term)>
);
STATIC_CHECK_FALSE(CanAccessContributionBlock<AngularState, decltype(utils::blocks::gravity_field.poisson_term)>);
STATIC_CHECK(HasPhysicsDensity<AngularState>);
STATIC_CHECK(HasPhysicsSurfaceShape<AngularState>);
STATIC_CHECK(HasPhysicsGeneratedCoordinate<AngularState>);
STATIC_CHECK_FALSE(HasPhysicsGravityGradient<AngularState>);
STATIC_CHECK_FALSE(HasPhysicsGravitationalPotential<AngularState>);
STATIC_CHECK_FALSE(HasPhysicsSpecificEnthalpy<AngularState>);
STATIC_CHECK(
CanAddContributionBlock<
AngularResidual, decltype(utils::blocks::fixed_angular_momentum_constraint.angular_velocity_term)>
);
STATIC_CHECK(
CanAddContributionBlock<
AngularResidual, decltype(utils::blocks::surface_deformation_field.shape_equilibrium_term)>
);
STATIC_CHECK(CanAddContributionBlock<AngularResidual, decltype(utils::blocks::enthalpy_field.specific_term)>);
STATIC_CHECK_FALSE(CanAddContributionBlock<AngularResidual, decltype(utils::blocks::density_field.mass_term)>);
STATIC_CHECK(CanAccessContributionBlock<CentralState, decltype(utils::blocks::enthalpy_field.specific_term)>);
STATIC_CHECK(
CanAccessContributionBlock<
CentralState, decltype(utils::blocks::fixed_central_density_phase.central_value_term)>
);
STATIC_CHECK_FALSE(CanAccessContributionBlock<CentralState, decltype(utils::blocks::density_field.mass_term)>);
STATIC_CHECK(HasPhysicsSpecificEnthalpy<CentralState>);
STATIC_CHECK(HasPhysicsGeneratedCoordinate<CentralState>);
STATIC_CHECK_FALSE(HasPhysicsDensity<CentralState>);
STATIC_CHECK_FALSE(HasPhysicsSurfaceShape<CentralState>);
// The astronomer-facing names span the complete current barotropic core
// and the specification's inferred scalar without exposing backend block
// types. Each accessor remains absent unless its dependency was declared.
STATIC_CHECK(HasPhysicsDensity<FullPhysicsState>);
STATIC_CHECK(HasPhysicsSurfaceShape<FullPhysicsState>);
STATIC_CHECK(HasPhysicsGravityGradient<FullPhysicsState>);
STATIC_CHECK(HasPhysicsGravitationalPotential<FullPhysicsState>);
STATIC_CHECK(HasPhysicsSpecificEnthalpy<FullPhysicsState>);
STATIC_CHECK(HasPhysicsGeneratedCoordinate<FullPhysicsState>);
STATIC_CHECK(CanAddContributionBlock<CentralResidual, decltype(utils::blocks::enthalpy_field.specific_term)>);
STATIC_CHECK(
CanAddContributionBlock<
CentralResidual, decltype(utils::blocks::fixed_central_density_phase.central_value_term)>
);
// Residual access is additive-only: declared rows are writable through add,
// but no specification can obtain a mutable block and overwrite an earlier
// contribution. There is also no escape hatch to the full root vector.
STATIC_CHECK_FALSE(
CanAccessContributionBlock<AngularResidual, decltype(utils::blocks::enthalpy_field.specific_term)>
);
STATIC_CHECK_FALSE(
CanAccessContributionBlock<CentralResidual, decltype(utils::blocks::enthalpy_field.specific_term)>
);
STATIC_CHECK_FALSE(ExposesUnrestrictedRootVector<AngularState>);
STATIC_CHECK_FALSE(ExposesUnrestrictedRootVector<AngularResidual>);
STATIC_CHECK_FALSE(ExposesUnrestrictedRootVector<CentralState>);
STATIC_CHECK_FALSE(ExposesUnrestrictedRootVector<CentralResidual>);
}
TEST_CASE(
"Built-In Physics Declarations Are The Compiler's Single Source",
"[stellar-equilibrium][compiler][metadata][physics-api]"
) {
using namespace mean_field;
using EmptyBlocks = utils::blocks::type_list<>;
using PolytropeCompilation = operators::StellarEquilibriumSpecificationCompilation<eos::Polytrope>;
using IsobaricCompilation = operators::StellarEquilibriumSpecificationCompilation<surface::Isobaric>;
using MassContribution = models::SpecificationContribution<models::FixedTotalMass>;
using AngularContribution = models::SpecificationContribution<models::FixedAngularMomentum>;
using CentralContribution = models::SpecificationContribution<models::FixedCentralDensity>;
STATIC_CHECK((std::same_as<
typename MassContribution::DependsOn,
models::DependsOn<models::stellar::state::Density, models::stellar::state::SurfaceShape>>));
STATIC_CHECK((
std::same_as<typename MassContribution::Affects, models::Affects<models::stellar::equation::HydrostaticBalance>>
));
STATIC_CHECK((std::same_as<
typename AngularContribution::DependsOn,
models::DependsOn<
models::stellar::state::Density, models::stellar::state::SurfaceShape,
models::stellar::state::OwnGeneratedCoordinate>>));
STATIC_CHECK((std::same_as<
typename AngularContribution::Affects,
models::Affects<
models::stellar::equation::SurfaceShapeBalance, models::stellar::equation::HydrostaticBalance>>));
STATIC_CHECK((
std::same_as<
typename CentralContribution::DependsOn, models::DependsOn<models::stellar::state::SpecificEnthalpy>>
));
STATIC_CHECK((
std::same_as<
typename CentralContribution::Affects, models::Affects<models::stellar::equation::HydrostaticBalance>>
));
using MassCompilation = operators::StellarEquilibriumSpecificationCompilation<models::FixedTotalMass>;
using AngularCompilation = operators::StellarEquilibriumSpecificationCompilation<models::FixedAngularMomentum>;
using CentralCompilation = operators::StellarEquilibriumSpecificationCompilation<models::FixedCentralDensity>;
STATIC_CHECK(operators::stellarEquilibriumSpecificationCompilationComplete<eos::Polytrope>);
STATIC_CHECK(operators::stellarEquilibriumSpecificationCompilationComplete<surface::Isobaric>);
STATIC_CHECK((std::same_as<typename PolytropeCompilation::GeneratedValueBlocks, EmptyBlocks>));
STATIC_CHECK((std::same_as<typename PolytropeCompilation::GeneratedResidualBlocks, EmptyBlocks>));
STATIC_CHECK((std::same_as<typename IsobaricCompilation::GeneratedValueBlocks, EmptyBlocks>));
STATIC_CHECK((std::same_as<typename IsobaricCompilation::GeneratedResidualBlocks, EmptyBlocks>));
STATIC_CHECK((
std::same_as<
typename MassCompilation::DependsOnValueBlocks, utils::blocks::type_list<DensityValue, SurfaceValue>>
));
STATIC_CHECK((
std::same_as<typename MassCompilation::AffectedResidualBlocks, utils::blocks::type_list<EnthalpyResidual>>
));
STATIC_CHECK((std::same_as<
typename AngularCompilation::DependsOnValueBlocks,
utils::blocks::type_list<DensityValue, SurfaceValue, AngularVelocityValue>>));
STATIC_CHECK((std::same_as<
typename AngularCompilation::AffectedResidualBlocks,
utils::blocks::type_list<SurfaceResidual, EnthalpyResidual>>));
STATIC_CHECK((
std::same_as<typename CentralCompilation::DependsOnValueBlocks, utils::blocks::type_list<EnthalpyValue>>
));
STATIC_CHECK((
std::same_as<typename CentralCompilation::AffectedResidualBlocks, utils::blocks::type_list<EnthalpyResidual>>
));
const auto descriptors = AngularCentralDensityModel::runtimeSpecificationDescriptors();
REQUIRE(descriptors.size() == 5);
CHECK(descriptors[2].specification.name == "FixedTotalMass");
CHECK(descriptors[3].specification.name == "FixedAngularMomentum");
CHECK(descriptors[4].specification.name == "FixedCentralDensity");
CHECK(descriptors[2].hasDeclarativeDefinition);
CHECK(descriptors[3].hasDeclarativeDefinition);
CHECK(descriptors[4].hasDeclarativeDefinition);
}
TEST_CASE(
"Fixed Total Mass Exposes Its Generated Blocks And Incident Edges",
"[stellar-equilibrium][compiler][metadata]"
) {
using namespace mean_field;
using Compilation = operators::StellarEquilibriumSpecificationCompilation<models::FixedTotalMass>;
using MassValue = utils::blocks::fixed_total_mass::mass_normalization::value;
using MassResidual = utils::blocks::fixed_total_mass::mass_normalization::residual;
STATIC_CHECK(operators::stellarEquilibriumSpecificationCompilationComplete<models::FixedTotalMass>);
STATIC_CHECK((std::same_as<typename Compilation::GeneratedValueBlocks, utils::blocks::type_list<MassValue>>));
STATIC_CHECK((std::same_as<typename Compilation::GeneratedCorrectionBlocks, utils::blocks::type_list<MassValue>>));
STATIC_CHECK((std::same_as<typename Compilation::GeneratedResidualBlocks, utils::blocks::type_list<MassResidual>>));
STATIC_CHECK(
utils::blocks::contains_type_v<
operators::EquilibriumJacobianCoupling<MassResidual, utils::blocks::density::mass::value>,
typename Compilation::IncidentJacobianCouplings>
);
STATIC_CHECK(
utils::blocks::contains_type_v<
operators::EquilibriumJacobianCoupling<utils::blocks::enthalpy::specific::residual, MassValue>,
typename Compilation::IncidentJacobianCouplings>
);
}
TEST_CASE(
"Core Coordinates Are Identified By Type Rather Than Pack Position",
"[stellar-equilibrium][compiler][ordering]"
) {
using namespace mean_field;
using Form = operators::CompiledStellarEquilibriumForm<EarlierMultiplierModel>;
using MassValue = utils::blocks::fixed_total_mass::mass_normalization::value;
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<EarlierMultiplierModel>);
STATIC_CHECK(utils::blocks::type_index_v<EarlierMultiplierValue, typename Form::value_blocks> == 5);
STATIC_CHECK(utils::blocks::type_index_v<MassValue, typename Form::value_blocks> == 6);
STATIC_CHECK(
utils::blocks::has_jacobian_coupling_v<
utils::blocks::enthalpy::specific::residual, EarlierMultiplierValue,
operators::CompiledStellarEquilibriumJacobianForm<EarlierMultiplierModel>>
);
}
TEST_CASE(
"Two-Pass Compiler Resolves Couplings Across Independently Declared "
"Constraints",
"[stellar-equilibrium][compiler][variadic][order-independence]"
) {
using namespace mean_field;
using System = operators::CompiledStellarEquilibriumSystem<CrossModel>;
using Form = typename System::FormType;
using Jacobian = typename System::JacobianType;
STATIC_CHECK(models::ModelSpecification<CrossAlpha>);
STATIC_CHECK(models::ModelSpecification<CrossBeta>);
STATIC_CHECK((std::same_as<CrossModel, PermutedCrossModel>));
STATIC_CHECK(operators::stellarEquilibriumSpecificationCompilationComplete<CrossAlpha>);
STATIC_CHECK(operators::stellarEquilibriumSpecificationCompilationComplete<CrossBeta>);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<CrossModel>);
STATIC_CHECK(Form::value_block_count == 8);
STATIC_CHECK(Form::residual_block_count == 8);
STATIC_CHECK(utils::blocks::valid_jacobian_form<Form, Jacobian>);
// Both endpoints are introduced by different declarations. In particular,
// R_B does not exist when a one-pass compiler visits Alpha.
STATIC_CHECK(utils::blocks::has_jacobian_coupling_v<CrossBetaResidual, CrossAlphaValue, Jacobian>);
STATIC_CHECK(utils::blocks::has_jacobian_coupling_v<CrossAlphaResidual, CrossBetaValue, Jacobian>);
STATIC_CHECK(
utils::blocks::has_jacobian_coupling_v<CrossBetaResidual, utils::blocks::density::mass::value, Jacobian>
);
STATIC_CHECK(
utils::blocks::has_jacobian_coupling_v<
utils::blocks::surface_deformation::shape_equilibrium::residual, CrossBetaValue, Jacobian>
);
// Changes are conservatively state dependent on every declared Read. This
// is the Hessian-like block required by nonlinear constrained systems.
STATIC_CHECK(utils::blocks::has_jacobian_coupling_v<CrossBetaResidual, CrossBetaValue, Jacobian>);
STATIC_CHECK(
utils::blocks::contains_type_v<
operators::EquilibriumJacobianCoupling<CrossBetaResidual, CrossAlphaValue>,
typename System::ContributionJacobianCouplings>
);
STATIC_CHECK((std::same_as<
typename System::GeneratedCorrectionBlocks,
utils::blocks::type_list<
utils::blocks::fixed_total_mass::mass_normalization::value, CrossAlphaValue, CrossBetaValue>>));
using CrossAlphaJacobian = operators::StellarEquilibriumContributionJacobianView<CrossAlpha, CrossModel>;
using AlphaResidualFromBetaValue =
ExactPairAuditCallback<CrossBetaTerm, CrossAlphaTerm, CrossAlphaTerm, CrossBetaTerm, false>;
using BetaResidualFromAlphaValue =
ExactPairAuditCallback<CrossAlphaTerm, CrossBetaTerm, CrossBetaTerm, CrossAlphaTerm, true>;
using BetaResidualFromBetaValue =
ExactPairAuditCallback<CrossBetaTerm, CrossAlphaTerm, CrossBetaTerm, CrossAlphaTerm, false>;
STATIC_CHECK(
CanBindDeclaredJacobianCallback<CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm, AlphaResidualFromBetaValue>
);
STATIC_CHECK(
CanBindDeclaredJacobianCallback<CrossAlphaJacobian, CrossBetaTerm, CrossAlphaTerm, BetaResidualFromAlphaValue>
);
STATIC_CHECK(
CanBindDeclaredJacobianCallback<CrossAlphaJacobian, CrossBetaTerm, CrossBetaTerm, BetaResidualFromBetaValue>
);
// Alpha's residual does not read Alpha's coordinate. Although that row and
// column are independently present in other callbacks, their undeclared
// diagonal cannot bind a callback. Raw scalar writes and malformed callback
// protocols are rejected too: all numeric accumulation happens through the
// one-row action supplied to a valid callback.
STATIC_CHECK_FALSE(CanBindDeclaredJacobianCallback<CrossAlphaJacobian, CrossAlphaTerm, CrossAlphaTerm>);
STATIC_CHECK_FALSE(CanAddRawJacobianContribution<CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm>);
STATIC_CHECK_FALSE(CanAddRawJacobianEntry<CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm>);
STATIC_CHECK_FALSE(
CanBindDeclaredJacobianCallback<CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm, OneArgumentJacobianCallback>
);
STATIC_CHECK_FALSE(
CanBindDeclaredJacobianCallback<CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm, NonVoidJacobianCallback>
);
STATIC_CHECK_FALSE(
CanBindDeclaredJacobianCallback<
CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm, RequiresCrossProductDirectionCallback>
);
STATIC_CHECK_FALSE(
CanBindDeclaredJacobianCallback<
CrossAlphaJacobian, CrossAlphaTerm, CrossBetaTerm, RequiresCrossProductActionCallback>
);
STATIC_CHECK_FALSE(CanBindDeclaredJacobianCallback<CrossAlphaJacobian, int, CrossBetaTerm>);
}
TEST_CASE(
"Exact Physics Providers Must Cover Every Compiler-Inferred Pair",
"[stellar-equilibrium][compiler][physics-provider][contracts]"
) {
using Specification = stellar_runtime_contract_test::RawNestedProtocolConstraint;
using Model = RawNestedProtocolModel;
using Topology = operators::StellarEquilibriumContributionTopology<Specification, Model>;
STATIC_CHECK(Topology::ResidualEquations::size == 2);
STATIC_CHECK(Topology::Derivatives::size == 3);
STATIC_CHECK((std::constructible_from<CompleteExplicitZeroProvider, const Specification &>));
STATIC_CHECK((HasExactProviderResidual<CompleteExplicitZeroProvider, stellar::equation::OwnConstraint>));
STATIC_CHECK((HasExactProviderResidual<CompleteExplicitZeroProvider, stellar::equation::HydrostaticBalance>));
STATIC_CHECK((HasExactProviderDerivative<
CompleteExplicitZeroProvider, stellar::equation::OwnConstraint, stellar::state::SpecificEnthalpy>));
STATIC_CHECK((
HasExactProviderDerivative<
CompleteExplicitZeroProvider, stellar::equation::HydrostaticBalance, stellar::state::SpecificEnthalpy>
));
STATIC_CHECK((
HasExactProviderDerivative<
CompleteExplicitZeroProvider, stellar::equation::HydrostaticBalance, stellar::state::OwnGeneratedCoordinate>
));
STATIC_CHECK((
operators::CompleteStellarEquilibriumPhysicsProvider<CompleteExplicitZeroProvider, Specification, Model>
));
// This provider has the valid constructor and all three inferred
// derivatives. Omitting only the changed physical residual rejects it.
STATIC_CHECK((std::constructible_from<MissingHydrostaticResidualProvider, const Specification &>));
STATIC_CHECK((HasExactProviderResidual<MissingHydrostaticResidualProvider, stellar::equation::OwnConstraint>));
STATIC_CHECK_FALSE((
HasExactProviderResidual<MissingHydrostaticResidualProvider, stellar::equation::HydrostaticBalance>
));
STATIC_CHECK((
HasExactProviderDerivative<
MissingHydrostaticResidualProvider, stellar::equation::OwnConstraint, stellar::state::SpecificEnthalpy>
));
STATIC_CHECK((
HasExactProviderDerivative<
MissingHydrostaticResidualProvider, stellar::equation::HydrostaticBalance, stellar::state::SpecificEnthalpy>
));
STATIC_CHECK((HasExactProviderDerivative<
MissingHydrostaticResidualProvider, stellar::equation::HydrostaticBalance,
stellar::state::OwnGeneratedCoordinate>));
STATIC_CHECK_FALSE((
operators::CompleteStellarEquilibriumPhysicsProvider<MissingHydrostaticResidualProvider, Specification, Model>
));
// This provider has the valid constructor and both inferred residuals.
// Omitting only d(hydrostatic)/d(owned coordinate) rejects it.
STATIC_CHECK((std::constructible_from<MissingGeneratedControlDerivativeProvider, const Specification &>));
STATIC_CHECK((
HasExactProviderResidual<MissingGeneratedControlDerivativeProvider, stellar::equation::OwnConstraint>
));
STATIC_CHECK((
HasExactProviderResidual<MissingGeneratedControlDerivativeProvider, stellar::equation::HydrostaticBalance>
));
STATIC_CHECK((HasExactProviderDerivative<
MissingGeneratedControlDerivativeProvider, stellar::equation::OwnConstraint,
stellar::state::SpecificEnthalpy>));
STATIC_CHECK((HasExactProviderDerivative<
MissingGeneratedControlDerivativeProvider, stellar::equation::HydrostaticBalance,
stellar::state::SpecificEnthalpy>));
STATIC_CHECK_FALSE((HasExactProviderDerivative<
MissingGeneratedControlDerivativeProvider, stellar::equation::HydrostaticBalance,
stellar::state::OwnGeneratedCoordinate>));
STATIC_CHECK_FALSE((operators::CompleteStellarEquilibriumPhysicsProvider<
MissingGeneratedControlDerivativeProvider, Specification, Model>));
// Construction alone does not grandfather in the former broad/imperative
// callbacks. They provide neither an equation-tagged residual result nor
// a derivative-tagged Jacobian result.
STATIC_CHECK((std::constructible_from<LegacyBroadEmptyProvider, const Specification &>));
STATIC_CHECK_FALSE((HasExactProviderResidual<LegacyBroadEmptyProvider, stellar::equation::OwnConstraint>));
STATIC_CHECK_FALSE((HasExactProviderDerivative<
LegacyBroadEmptyProvider, stellar::equation::OwnConstraint, stellar::state::SpecificEnthalpy>));
STATIC_CHECK_FALSE((
operators::CompleteStellarEquilibriumPhysicsProvider<LegacyBroadEmptyProvider, Specification, Model>
));
}
TEST_CASE(
"Compiler Capability Queries Reject Invalid Declarations Without "
"Hard Errors",
"[stellar-equilibrium][compiler][sfinae]"
) {
using namespace mean_field;
STATIC_CHECK_FALSE(operators::stellarEquilibriumSpecificationCompilationComplete<int>);
STATIC_CHECK_FALSE(operators::stellarEquilibriumSpecificationCompilationComplete<MalformedDeclaration>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumSystemCompilable<MalformedModel>);
STATIC_CHECK_FALSE(HasCompiledStellarEquilibriumSystem<MalformedModel>);
STATIC_CHECK(models::ModelSpecification<UnmappedPhysicsDependency>);
// A valid declaration is not a claim that the numerical compiler knows how
// to map every name it contains.
STATIC_CHECK(UnmappedPhysicsModel::hasCompleteEquilibriumDeclaration);
STATIC_CHECK_FALSE(operators::stellarEquilibriumSpecificationCompilationComplete<UnmappedPhysicsDependency>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumSystemCompilable<UnmappedPhysicsModel>);
STATIC_CHECK_FALSE(HasCompiledStellarEquilibriumSystem<UnmappedPhysicsModel>);
STATIC_CHECK(models::ModelSpecification<UnmappedPhysicsEffect>);
STATIC_CHECK_FALSE(operators::stellarEquilibriumSpecificationCompilationComplete<UnmappedPhysicsEffect>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumSystemCompilable<UnmappedPhysicsEffectModel>);
STATIC_CHECK_FALSE(HasCompiledStellarEquilibriumSystem<UnmappedPhysicsEffectModel>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumSystemCompilable<int>);
STATIC_CHECK_FALSE(HasCompiledStellarEquilibriumSystem<int>);
STATIC_CHECK(
operators::StellarEquilibriumBackendSpecificationList<models::ModelTypeList<eos::Polytrope, surface::Isobaric>>
);
STATIC_CHECK(operators::StellarEquilibriumBackendSpecificationList<models::ModelTypeList<>>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumBackendSpecificationList<models::ModelTypeList<int>>);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumBackendSpecificationList<models::ModelTypeList<eos::Polytrope, eos::Polytrope>>
);
STATIC_CHECK_FALSE(operators::StellarEquilibriumBackendSpecificationList<int>);
STATIC_CHECK_FALSE(operators::stellarEquilibriumBackendRuntimeAuthorized<int, int>);
STATIC_CHECK(operators::stellarEquilibriumBackendRuntimeAuthorized<eos::Polytrope, BaseModel>);
STATIC_CHECK(operators::stellarEquilibriumBackendRuntimeAuthorized<models::FixedTotalMass, BaseModel>);
STATIC_CHECK(
operators::StellarEquilibriumCoreRuntime<
stellar_runtime_contract_test::RegisteredWithoutMakeEquationOfState>::registered
);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<RegisteredWithoutMakeModel>);
STATIC_CHECK_FALSE(operators::hasStellarEquilibriumCoreRuntime<RegisteredWithoutMakeModel>);
STATIC_CHECK(
operators::PreparedStellarEquilibriumPhysicalCore<stellar_runtime_contract_test::AlternatePhysicalCore>
);
STATIC_CHECK(operators::hasStellarEquilibriumCoreRuntime<AlternateCoreModel>);
STATIC_CHECK((std::same_as<
operators::StellarEquilibriumPhysicalCoreType<AlternateCoreModel>,
stellar_runtime_contract_test::AlternatePhysicalCore>));
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<AlternateCoreModel>);
STATIC_CHECK(
operators::stellarEquilibriumBackendRuntimeAuthorized<
stellar_runtime_contract_test::AlternateCoreEquationOfState, AlternateCoreModel>
);
STATIC_CHECK(operators::stellarEquilibriumBackendRuntimeAuthorized<surface::Isobaric, AlternateCoreModel>);
STATIC_CHECK(operators::stellarEquilibriumBackendRuntimeAuthorized<models::FixedTotalMass, AlternateCoreModel>);
STATIC_CHECK(HasPreparedVariadicStellarEquilibriumOperator<AlternateCoreModel>);
// Core support and constraint support are separate contracts. This tiny
// core supports the common outer root, but does not advertise the physical
// facilities required by FixedAngularMomentum.
STATIC_CHECK(operators::hasStellarEquilibriumCoreRuntime<AlternateCoreAngularMomentumModel>);
STATIC_CHECK(
operators::stellarEquilibriumBackendRuntimeAuthorized<
models::FixedAngularMomentum, AlternateCoreAngularMomentumModel>
);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<AlternateCoreAngularMomentumModel>);
STATIC_CHECK_FALSE(HasPreparedVariadicStellarEquilibriumOperator<AlternateCoreAngularMomentumModel>);
// The pack fold also rejects ambiguous physical-control ownership. Both
// contributions are independently executable, but exactly one runtime may
// generate the rotation used by the shared physical core.
STATIC_CHECK_FALSE(
operators::StellarEquilibriumRuntimeContribution<
stellar_runtime_contract_test::SecondRotationController>::registered
);
STATIC_CHECK(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::SecondRotationController, TwoRotationProvidersModel>
);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<TwoRotationProvidersModel>);
STATIC_CHECK(operators::hasStellarEquilibriumCoreRuntime<TwoRotationProvidersModel>);
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<TwoRotationProvidersModel>);
STATIC_CHECK(HasPreparedVariadicStellarEquilibriumOperator<TwoRotationProvidersModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<TwoRotationProvidersModel>);
STATIC_CHECK(operators::stellarEquilibriumRotationProviderCount<TwoRotationProvidersModel> == 2);
using AmbiguousRotationRoot = operators::PreparedVariadicStellarEquilibriumOperator<TwoRotationProvidersModel>;
STATIC_CHECK_FALSE(
std::constructible_from<
AmbiguousRotationRoot, fem::FEM &, const mapping::DomainMapper &,
std::shared_ptr<const TwoRotationProvidersModel>, operators::PressureSurfaceConstraintView,
deformation::PreparedDomainDeformationRuntime>
);
// Report storage is part of the real runtime protocol: preparation creates
// the complete report tuple and assigns each per-specification result into
// it. Capability queries must reject both failures without reaching a hard
// error inside PreparedVariadicStellarEquilibriumOperator::Prepare().
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<NonDefaultReportModel>);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::NonDefaultReportConstraint, NonDefaultReportModel>
);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<NonDefaultReportModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<NonDefaultReportModel>);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<NonAssignableReportModel>);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::NonAssignableReportConstraint, NonAssignableReportModel>
);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<NonAssignableReportModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<NonAssignableReportModel>);
// Reports are deliberately opaque to the framework. Default construction
// and assignment are sufficient for tuple storage; no DidAnyWork member is
// required to keep the residual correct.
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<OpaqueReportModel>);
STATIC_CHECK(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::OpaqueReportConstraint, OpaqueReportModel>
);
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<OpaqueReportModel>);
STATIC_CHECK(equilibrium::StellarEquilibriumModel<OpaqueReportModel>);
// A nested declaration is the restricted physics-author path. Merely
// implementing the former raw FEM/model/core/dependency protocol must not
// recover the privileged backend access reserved for explicit registry
// specializations.
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<RawNestedProtocolModel>);
STATIC_CHECK_FALSE(
std::constructible_from<
stellar_runtime_contract_test::PreparedRawNestedProtocolConstraint<RawNestedProtocolModel>,
const stellar_runtime_contract_test::RawNestedProtocolConstraint &>
);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::RawNestedProtocolConstraint, RawNestedProtocolModel>
);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<RawNestedProtocolModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<RawNestedProtocolModel>);
// Even a structurally complete aggregate runtime cannot select itself for
// an existing core. Symbolic compilation and core availability remain
// independently true, isolating authorization as the failed rung.
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<UnauthorizedAggregateModel>);
STATIC_CHECK(operators::hasStellarEquilibriumCoreRuntime<UnauthorizedAggregateModel>);
STATIC_CHECK(
operators::StellarEquilibriumRuntimeContribution<
stellar_runtime_contract_test::UnauthorizedAggregateConstraint>::registered
);
STATIC_CHECK_FALSE(
operators::stellarEquilibriumBackendRuntimeAuthorized<
stellar_runtime_contract_test::UnauthorizedAggregateConstraint, UnauthorizedAggregateModel>
);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::UnauthorizedAggregateConstraint, UnauthorizedAggregateModel>
);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<UnauthorizedAggregateModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<UnauthorizedAggregateModel>);
// A raw registry specialization cannot grant itself privileged access to
// the built-in core and cannot shadow a valid restricted nested package.
STATIC_CHECK(
operators::StellarEquilibriumRuntimeContribution<
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint>::registered
);
STATIC_CHECK_FALSE(
operators::stellarEquilibriumBackendRuntimeAuthorized<
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint, AmbiguousRuntimeRegistrationModel>
);
STATIC_CHECK(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint, AmbiguousRuntimeRegistrationModel>
);
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<AmbiguousRuntimeRegistrationModel>);
STATIC_CHECK(equilibrium::StellarEquilibriumModel<AmbiguousRuntimeRegistrationModel>);
// A core owner can deliberately authorize an aggregate backend candidate.
// If that exact model then also supplies nested physics, the two valid
// providers are genuinely ambiguous and are rejected.
STATIC_CHECK(
operators::stellarEquilibriumBackendRuntimeAuthorized<
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint,
AuthorizedAmbiguousRuntimeRegistrationModel>
);
STATIC_CHECK_FALSE(
operators::StellarEquilibriumPhysicsAvailableFor<
stellar_runtime_contract_test::AmbiguousRuntimeRegistrationConstraint,
AuthorizedAmbiguousRuntimeRegistrationModel>
);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<AuthorizedAmbiguousRuntimeRegistrationModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<AuthorizedAmbiguousRuntimeRegistrationModel>);
// A registration bit and a plausible core type are insufficient: the
// factory must return ownership of the advertised concrete core.
STATIC_CHECK_FALSE(operators::hasStellarEquilibriumCoreRuntime<WrongOwnerModel>);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<WrongOwnerModel>);
STATIC_CHECK(
operators::StellarEquilibriumRuntimeContribution<
stellar_runtime_contract_test::IncompleteSurfaceRuntime>::registered
);
STATIC_CHECK_FALSE(
operators::stellarEquilibriumBackendRuntimeAuthorized<
stellar_runtime_contract_test::IncompleteSurfaceRuntime, IncompleteSurfaceRuntimeModel>
);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<IncompleteSurfaceRuntimeModel>);
STATIC_CHECK(operators::hasStellarEquilibriumCoreRuntime<IncompleteSurfaceRuntimeModel>);
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<IncompleteSurfaceRuntimeModel>);
STATIC_CHECK_FALSE(equilibrium::hasStellarEquilibriumSurfaceCompilation<IncompleteSurfaceRuntimeModel>);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModel<IncompleteSurfaceRuntimeModel>);
STATIC_CHECK_FALSE(operators::hasCompatibleStellarEquilibriumPhysicalRoot<MissingMassModel>);
STATIC_CHECK_FALSE(HasPreparedVariadicStellarEquilibriumOperator<MissingMassModel>);
STATIC_CHECK_FALSE(
operators::CompilableRootManifestFor<
CentralDensityModel, utils::blocks::surface_deformed_stellar_equilibrium_form>
);
STATIC_CHECK_FALSE(operators::CompilableRootManifestFor<BaseModel, CarrierlessManifestForm>);
STATIC_CHECK_FALSE(
operators::CompilableRootManifestFor<
UnsupportedCentralDensityModel, operators::CompiledStellarEquilibriumForm<UnsupportedCentralDensityModel>>
);
// This declaration is internally well formed, but its dependency is not
// supplied by the final model. Completeness is therefore contextual.
STATIC_CHECK(operators::stellarEquilibriumSpecificationCompilationComplete<OrphanEndpoint>);
STATIC_CHECK_FALSE(operators::StellarEquilibriumSystemCompilable<OrphanEndpointModel>);
STATIC_CHECK_FALSE(HasCompiledStellarEquilibriumSystem<OrphanEndpointModel>);
}
TEST_CASE(
"Direct Variadic Root Construction Requires Shared Model Ownership",
"[stellar-equilibrium][runtime][lifetime][type-contract]"
) {
using namespace mean_field;
using Operator = operators::PreparedVariadicStellarEquilibriumOperator<BaseModel>;
STATIC_CHECK_FALSE(
std::constructible_from<
Operator, fem::FEM &, const mapping::DomainMapper &, const BaseModel &,
operators::PressureSurfaceConstraintView, deformation::PreparedDomainDeformationRuntime>
);
STATIC_CHECK(
std::constructible_from<
Operator, fem::FEM &, const mapping::DomainMapper &, std::shared_ptr<const BaseModel>,
operators::PressureSurfaceConstraintView, deformation::PreparedDomainDeformationRuntime>
);
}
TEST_CASE(
"Physical Riesz Runtime Capability Follows The Selected Core",
"[normalization][stellar-equilibrium][type-contract]"
) {
using namespace mean_field;
using AlternateForm = operators::CompiledStellarEquilibriumForm<AlternateCoreModel>;
using AlternateSpecifications = AlternateCoreModel::SpecificationTypes;
STATIC_CHECK(normalization::PhysicalRieszStellarEquilibriumCore<operators::PreparedStellarEquilibriumOperator>);
STATIC_CHECK_FALSE(
normalization::PhysicalRieszStellarEquilibriumCore<stellar_runtime_contract_test::AlternatePhysicalCore>
);
STATIC_CHECK(
normalization::PhysicalRieszStellarEquilibriumCore<stellar_runtime_contract_test::PhysicalRieszCapableCore>
);
STATIC_CHECK(
normalization::StellarNormalizationRuntimeAvailableFor<
normalization::Unnormalized, AlternateForm, stellar_runtime_contract_test::AlternatePhysicalCore,
AlternateSpecifications>
);
STATIC_CHECK_FALSE(
normalization::StellarNormalizationRuntimeAvailableFor<
normalization::PhysicalRieszDiagonal<>, AlternateForm, stellar_runtime_contract_test::AlternatePhysicalCore,
AlternateSpecifications>
);
STATIC_CHECK(
normalization::StellarNormalizationRuntimeAvailableFor<
normalization::PhysicalRieszDiagonal<>, AlternateForm,
stellar_runtime_contract_test::PhysicalRieszCapableCore, AlternateSpecifications>
);
STATIC_CHECK_FALSE(normalization::StellarNormalizationRuntimeAvailableFor<int, int, int, int>);
// Runtime normalization is selected by the discretization type. A lean
// alternate core remains fully usable without scaling, while the Physical
// Riesz pairing is rejected at the public capability boundary rather than
// failing in the normalized operator's constructor body.
STATIC_CHECK(equilibrium::StellarEquilibriumModel<AlternateCoreModel>);
STATIC_CHECK(
equilibrium::StellarEquilibriumModelDiscretizationCompatible<
AlternateCoreModel, equilibrium::StellarDiscretization>
);
STATIC_CHECK_FALSE(
equilibrium::StellarEquilibriumModelDiscretizationCompatible<AlternateCoreModel, PhysicalRieszDiscretization>
);
STATIC_CHECK_FALSE(HasStellarEquilibriumProblem<AlternateCoreModel, PhysicalRieszDiscretization>);
STATIC_CHECK_FALSE(CanDiscretizeStellarModel<AlternateCoreModel, PhysicalRieszDiscretization>);
STATIC_CHECK(normalization::NormalizableStellarEquilibriumProblem<BaseProblem>);
STATIC_CHECK(normalization::PhysicalRieszStellarEquilibriumProblem<BasePhysicalRieszProblem>);
STATIC_CHECK(normalization::NormalizableStellarEquilibriumProblem<BasePhysicalRieszProblem>);
STATIC_CHECK(normalization::NormalizableStellarEquilibriumProblem<AlternateCoreProblem>);
STATIC_CHECK_FALSE(normalization::PhysicalRieszStellarEquilibriumProblem<int>);
STATIC_CHECK_FALSE(normalization::NormalizableStellarEquilibriumProblem<int>);
STATIC_CHECK(HasNormalizedStellarEquilibriumOperator<BaseProblem>);
STATIC_CHECK(HasNormalizedStellarEquilibriumOperator<BasePhysicalRieszProblem>);
STATIC_CHECK(HasNormalizedStellarEquilibriumOperator<AlternateCoreProblem>);
STATIC_CHECK(CanMakeNormalizedStellarEquilibriumOperator<BaseProblem>);
STATIC_CHECK(CanMakeNormalizedStellarEquilibriumOperator<AlternateCoreProblem>);
STATIC_CHECK_FALSE(CanMakeNormalizedStellarEquilibriumOperator<int>);
}
TEST_CASE(
"Model And Discretization Compatibility Rejects Missing Riesz "
"Metadata Without Instantiating A Problem",
"[normalization][stellar-equilibrium][type-contract][sfinae]"
) {
using namespace mean_field;
using MissingRieszForm = operators::CompiledStellarEquilibriumForm<MissingRieszModel>;
using MissingConstraint = stellar_runtime_contract_test::MissingRieszScalarConstraint;
// Every non-normalization rung is complete for this model.
STATIC_CHECK(equilibrium::StellarEquilibriumModel<MissingRieszModel>);
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<MissingRieszModel>);
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<MissingRieszModel>);
STATIC_CHECK(operators::CompilableRootManifestFor<MissingRieszModel, MissingRieszForm>);
STATIC_CHECK(models::CompleteGeneratedManifestFor<MissingConstraint>);
// Identity normalization covers the generated pair without physical scale
// metadata. Physical Riesz correctly requires that missing declaration.
STATIC_CHECK_FALSE(models::CompleteGeneratedNormalizationFor<MissingConstraint>);
STATIC_CHECK_FALSE(normalization::CompleteGeneratedPhysicalRieszNormalizationFor<MissingConstraint>);
STATIC_CHECK_FALSE(normalization::CompleteGeneratedPhysicalRieszRuntimeNormalizationFor<MissingConstraint>);
STATIC_CHECK(normalization::CompleteGeneratedPhysicalRieszRuntimeNormalizationFor<models::FixedTotalMass>);
STATIC_CHECK(normalization::CompilableNormalizationFor<normalization::Unnormalized, MissingRieszForm>);
STATIC_CHECK_FALSE(
normalization::CompilableNormalizationFor<normalization::PhysicalRieszDiagonal<>, MissingRieszForm>
);
STATIC_CHECK_FALSE(normalization::CompleteStellarNormalizationFor<MissingRieszModel, MissingRieszForm>);
STATIC_CHECK(
equilibrium::StellarEquilibriumModelDiscretizationCompatible<
MissingRieszModel, equilibrium::StellarDiscretization>
);
STATIC_CHECK_FALSE(
equilibrium::StellarEquilibriumModelDiscretizationCompatible<MissingRieszModel, PhysicalRieszDiscretization>
);
STATIC_CHECK_FALSE(equilibrium::StellarEquilibriumModelDiscretizationCompatible<int, int>);
STATIC_CHECK(HasStellarEquilibriumProblem<MissingRieszModel, equilibrium::StellarDiscretization>);
STATIC_CHECK_FALSE(HasStellarEquilibriumProblem<MissingRieszModel, PhysicalRieszDiscretization>);
STATIC_CHECK_FALSE(HasStellarEquilibriumProblem<int, int>);
STATIC_CHECK(CanDiscretizeStellarModel<MissingRieszModel, equilibrium::StellarDiscretization>);
STATIC_CHECK_FALSE(CanDiscretizeStellarModel<MissingRieszModel, PhysicalRieszDiscretization>);
STATIC_CHECK(equilibrium::DiscretizedStellarEquilibriumProblem<MissingRieszUnnormalizedProblem>);
STATIC_CHECK(normalization::NormalizableStellarEquilibriumProblem<MissingRieszUnnormalizedProblem>);
}
TEST_CASE(
"Restricted Equilibrium Physics Automatically Supplies The Default "
"Constraint Border",
"[preconditioning][stellar-equilibrium][type-contract][sfinae]"
) {
using namespace mean_field;
// The ordinary nested provider is the single source of numerical formulas.
// Border-incident edges are projected from it automatically, while the
// custom pure-structure edge is explicitly proven to be StructuralZero.
STATIC_CHECK(equilibrium::StellarEquilibriumModel<MissingRieszModel>);
STATIC_CHECK(operators::hasCompleteStellarEquilibriumRuntime<MissingRieszModel>);
STATIC_CHECK(equilibrium::DiscretizedStellarEquilibriumProblem<MissingRieszUnnormalizedProblem>);
STATIC_CHECK(preconditioning::CompleteSpecificationBorderActionsFor<MissingRieszUnnormalizedProblem>);
STATIC_CHECK(preconditioning::DefaultStellarPreconditionerAvailableFor<MissingRieszUnnormalizedProblem>);
STATIC_CHECK(CanMakeDefaultStellarPreconditioner<MissingRieszUnnormalizedProblem>);
}