Files
MeanField/tests/operators/stellar_equilibrium_compiler.cpp
2026-09-06 10:15:00 -04:00

2410 lines
102 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>);
}