feat(libmeanfield): variadic refactor

also added normaliztion operator
This commit is contained in:
2026-09-06 10:15:00 -04:00
parent 71423d543f
commit 76818f2f82
63 changed files with 28794 additions and 1119 deletions

View File

@@ -6,6 +6,7 @@
#include <numbers>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <catch2/catch_test_macros.hpp>
#include <mfem.hpp>
@@ -56,6 +57,33 @@ namespace {
blocks::type_list<>,
preconditioning::IdentityOperatorCharacteristics,
preconditioning::backend::Identity>;
using LifetimeModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass,
mean_field::models::FixedCentralDensity>>;
using LifetimeProblem = mean_field::equilibrium::StellarEquilibriumProblem<LifetimeModel>;
using LifetimeBlock = decltype(preconditioning::makePreconditioner(
std::declval<const LifetimeProblem &>()
));
using LifetimePrepared = preconditioning::PreparedStellarPreconditioner<
LifetimeProblem,
LifetimeBlock>;
template <typename Problem, typename Block>
concept CanPrepareStellarPreconditioner = requires(const Problem &problem, Block block) {
preconditioning::prepare(problem, std::move(block));
};
template <typename Problem, typename Block>
concept CanPrepareStellarPreconditionerFromTemporary = requires(Block block) {
preconditioning::prepare(std::declval<Problem &&>(), std::move(block));
};
template <typename Problem, typename Block>
concept CanPrepareStellarPreconditionerFromConstTemporary = requires(Block block) {
preconditioning::prepare(std::declval<const Problem &&>(), std::move(block));
};
[[nodiscard]] blocks::form_layout<Form> makeUnevenLayout() {
return {
@@ -102,6 +130,12 @@ TEST_CASE(
) {
STATIC_CHECK(preconditioning::EquilibriumCoordinateComponentFor<GroupedComponent, Form>);
STATIC_CHECK_FALSE(preconditioning::EquilibriumCoordinateComponentFor<IncompleteComponent, Form>);
STATIC_CHECK(CanPrepareStellarPreconditioner<LifetimeProblem, LifetimeBlock>);
STATIC_CHECK_FALSE(CanPrepareStellarPreconditionerFromTemporary<LifetimeProblem, LifetimeBlock>);
STATIC_CHECK_FALSE(CanPrepareStellarPreconditionerFromConstTemporary<LifetimeProblem, LifetimeBlock>);
STATIC_CHECK(std::constructible_from<LifetimePrepared, const LifetimeProblem &, LifetimeBlock>);
STATIC_CHECK_FALSE(std::constructible_from<LifetimePrepared, LifetimeProblem &&, LifetimeBlock>);
STATIC_CHECK_FALSE(std::constructible_from<LifetimePrepared, const LifetimeProblem &&, LifetimeBlock>);
const auto layout = makeUnevenLayout();
preconditioning::EquilibriumPreconditionerCoordinateMap<Form, GroupedComponent> coordinates(layout);

View File

@@ -2,6 +2,7 @@
#include <array>
#include <cmath>
#include <concepts>
#include <memory>
#include <numbers>
#include <stdexcept>
#include <type_traits>
@@ -13,6 +14,130 @@
import mean_field;
import test_helpers;
namespace material_surface_runtime_contract_test {
struct RegisteredAlternateEquationOfState final {
struct Parameters final { };
using ModelDefinition = mean_field::models::ConstitutiveLaw<
RegisteredAlternateEquationOfState,
"RegisteredAlternateMaterialSurfaceEquationOfState">;
using Relations = mean_field::eos::RelationCatalog<mean_field::eos::SpecificEnthalpyFromPressure>;
explicit RegisteredAlternateEquationOfState(Parameters) noexcept { }
[[nodiscard]] mean_field::dimensions::SpecificEnthalpyValue evaluate(
mean_field::eos::SpecificEnthalpyFromPressure,
mean_field::dimensions::PressureValue
) const;
};
class AlternatePhysicalCore final : public mfem::Operator {
public:
using BackendSpecifications = mean_field::models::ModelTypeList<
RegisteredAlternateEquationOfState,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass>;
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;
};
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]] constexpr bool IsPrepared() const noexcept {
return true;
}
};
} // namespace material_surface_runtime_contract_test
namespace mean_field::operators {
template <>
struct StellarEquilibriumCoreRuntime<
material_surface_runtime_contract_test::RegisteredAlternateEquationOfState> {
static constexpr bool registered = true;
using CoreType = material_surface_runtime_contract_test::AlternatePhysicalCore;
[[nodiscard]] static std::unique_ptr<CoreType> Make(
fem::FEM &,
const mapping::DomainMapper &,
const material_surface_runtime_contract_test::RegisteredAlternateEquationOfState &,
const models::CompiledFixedMass &,
PressureSurfaceConstraintView,
deformation::PreparedDomainDeformationRuntime
);
[[nodiscard]] static int SurfaceEquationCount(const CoreType &) noexcept;
};
template <>
struct StellarEquilibriumRuntimeContribution<
material_surface_runtime_contract_test::RegisteredAlternateEquationOfState>
: PreparedStellarEquilibriumContribution<
material_surface_runtime_contract_test::AlternateEquationOfStateRuntime> { };
} // namespace mean_field::operators
namespace mean_field::preconditioning {
/*
* This registration deliberately advertises a distinct core without an
* executable material/surface implementation. Registration alone must
* therefore remain insufficient for MaterialSurfaceRuntimeFor.
*/
template <>
struct MaterialSurfaceEquationOfStateBackend<
material_surface_runtime_contract_test::RegisteredAlternateEquationOfState> {
static constexpr bool registered = true;
using CoreType = material_surface_runtime_contract_test::AlternatePhysicalCore;
};
} // namespace mean_field::preconditioning
namespace {
namespace backend = mean_field::preconditioning::backend;
namespace blocks = mean_field::utils::blocks;
@@ -25,6 +150,11 @@ namespace {
mean_field::constraint::FixedCentralDensity>>;
using PolytropicProblem = mean_field::equilibrium::StellarEquilibriumProblem<PolytropicModel>;
using PolytropicMaterialSurfaceDescriptor = preconditioning::MaterialSurfaceDescriptorFor<PolytropicProblem>;
using RegisteredAlternateModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
material_surface_runtime_contract_test::RegisteredAlternateEquationOfState,
mean_field::surface::Isobaric,
mean_field::integral::FixedTotalMass>>;
using RegisteredAlternateProblem = mean_field::equilibrium::StellarEquilibriumProblem<RegisteredAlternateModel>;
using MaterialSurfaceDiagonal = preconditioning::MaterialSurfaceBlock<
PolytropicMaterialSurfaceDescriptor,
backend::Diagonal,
@@ -44,6 +174,30 @@ namespace {
PolytropicMaterialSurfaceDescriptor,
preconditioning::ApproximateMaterialSurfaceLDU,
backend::FixedCycles>;
using RegisteredAlternateGravityComponent = preconditioning::GravityFieldBlock<
backend::Diagonal,
FixedCycleAMG,
preconditioning::GravityApproximateLDU>;
using RegisteredAlternateMaterialSurfaceDescriptor =
preconditioning::MaterialSurfaceDescriptorFor<RegisteredAlternateProblem>;
struct DistinctPhysicalCore final { };
template <typename Problem>
concept CanMakeDefaultMaterialSurface = requires(const Problem &problem) {
preconditioning::materialSurfaceBlock(problem);
};
template <typename Problem>
concept CanPrepareDefaultMaterialSurface = requires(const Problem &problem) {
preconditioning::prepare(problem, preconditioning::materialSurfaceBlock(problem));
};
template <typename Problem>
concept CanMakeDefaultStellarStructure = requires(const Problem &problem) {
preconditioning::stellarStructureBlock(problem);
};
class KnownCouplings final {
public:
@@ -161,6 +315,53 @@ TEST_CASE(
STATIC_CHECK(preconditioning::PreconditionerComponent<MaterialSurfaceDiagonal>);
STATIC_CHECK(preconditioning::PreconditionerComponent<MaterialSurfaceH1>);
STATIC_CHECK(preconditioning::MaterialSurfaceDescriptor<PolytropicMaterialSurfaceDescriptor>);
STATIC_CHECK(preconditioning::ImplementedMaterialSurfaceEquationOfState<
mean_field::eos::Polytrope>);
STATIC_CHECK_FALSE(
preconditioning::ImplementedMaterialSurfaceEquationOfState<int>);
STATIC_CHECK(preconditioning::ImplementedMaterialSurfaceDescriptor<
PolytropicMaterialSurfaceDescriptor>);
STATIC_CHECK(preconditioning::ExecutableMaterialSurfaceRuntimeFor<
mean_field::eos::Polytrope,
mean_field::operators::PreparedStellarEquilibriumOperator>);
STATIC_CHECK(std::same_as<
typename preconditioning::MaterialSurfaceEquationOfStateBackend<
mean_field::eos::Polytrope>::CoreType,
mean_field::operators::PreparedStellarEquilibriumOperator>);
STATIC_CHECK(preconditioning::MaterialSurfaceRuntimeFor<
PolytropicMaterialSurfaceDescriptor,
mean_field::operators::PreparedStellarEquilibriumOperator>);
STATIC_CHECK_FALSE(preconditioning::MaterialSurfaceRuntimeFor<
PolytropicMaterialSurfaceDescriptor,
DistinctPhysicalCore>);
STATIC_CHECK(preconditioning::MaterialSurfaceDescriptor<
RegisteredAlternateMaterialSurfaceDescriptor>);
STATIC_CHECK(mean_field::equilibrium::StellarEquilibriumModel<RegisteredAlternateModel>);
STATIC_CHECK(std::same_as<
typename RegisteredAlternateProblem::PhysicalCoreType,
material_surface_runtime_contract_test::AlternatePhysicalCore>);
STATIC_CHECK(preconditioning::ImplementedMaterialSurfaceEquationOfState<
material_surface_runtime_contract_test::RegisteredAlternateEquationOfState>);
STATIC_CHECK(preconditioning::ImplementedMaterialSurfaceDescriptor<
RegisteredAlternateMaterialSurfaceDescriptor>);
STATIC_CHECK_FALSE(preconditioning::ExecutableMaterialSurfaceRuntimeFor<
material_surface_runtime_contract_test::RegisteredAlternateEquationOfState,
material_surface_runtime_contract_test::AlternatePhysicalCore>);
STATIC_CHECK_FALSE(preconditioning::MaterialSurfaceRuntimeFor<
RegisteredAlternateMaterialSurfaceDescriptor,
material_surface_runtime_contract_test::AlternatePhysicalCore>);
STATIC_CHECK(preconditioning::MaterialSurfacePreconditionerProblem<PolytropicProblem>);
STATIC_CHECK_FALSE(preconditioning::MaterialSurfacePreconditionerProblem<RegisteredAlternateProblem>);
STATIC_CHECK(CanMakeDefaultMaterialSurface<PolytropicProblem>);
STATIC_CHECK_FALSE(CanMakeDefaultMaterialSurface<RegisteredAlternateProblem>);
STATIC_CHECK(CanPrepareDefaultMaterialSurface<PolytropicProblem>);
STATIC_CHECK_FALSE(CanPrepareDefaultMaterialSurface<RegisteredAlternateProblem>);
STATIC_CHECK_FALSE(preconditioning::StellarStructurePreconditionerProblem<RegisteredAlternateProblem>);
STATIC_CHECK_FALSE(preconditioning::StellarStructurePreparableFor<
RegisteredAlternateProblem,
MaterialSurfaceDiagonal,
RegisteredAlternateGravityComponent>);
STATIC_CHECK_FALSE(CanMakeDefaultStellarStructure<RegisteredAlternateProblem>);
STATIC_CHECK(
mean_field::material::CompiledThermodynamicEquations<typename PolytropicProblem::ThermodynamicEquationsType>
);
@@ -171,7 +372,7 @@ TEST_CASE(
);
STATIC_CHECK(MaterialSurfaceDiagonal::CorrectionBlocks::size == 3);
STATIC_CHECK(MaterialSurfaceDiagonal::ResidualBlocks::size == 3);
STATIC_CHECK(MaterialSurfaceDiagonal::RequiredCouplings::size == 8);
STATIC_CHECK(MaterialSurfaceDiagonal::RequiredCouplings::size == 9);
STATIC_CHECK(preconditioning::CompletePreconditionerFor<Plan, Form>);
STATIC_CHECK(preconditioning::CompatiblePreconditionerFor<Plan, Form, JacobianForm>);
STATIC_CHECK(preconditioning::backend::ArnoldiAdmissible<typename MaterialSurfaceDiagonal::BackendType>);
@@ -409,7 +610,7 @@ TEST_CASE(
mfem::Vector fullDirection(physical.Width());
fullDirection = 0.0;
const auto fullDirectionView = physical.GetRootManifest().directionView(fullDirection);
const auto fullDirectionView = physical.GetRootManifest().stateView(fullDirection);
const auto &offsets = restricted.GetOffsets();
const mfem::Vector densityDirection(restrictedDirection.GetData(), offsets[1]);
const mfem::Vector surfaceDirection(restrictedDirection.GetData() + offsets[1], offsets[2] - offsets[1]);

File diff suppressed because it is too large Load Diff

View File

@@ -71,6 +71,10 @@ namespace preconditioning_runtime_test {
++m_snapshot.geometry.revision;
}
void AdvancePreparation() noexcept {
++m_snapshot.preparedOperatorGeneration;
}
void SetPrepared(const bool prepared) noexcept {
m_prepared = prepared;
}
@@ -108,6 +112,136 @@ namespace preconditioning_runtime_test {
};
} // namespace preconditioning_runtime_test
namespace unsupported_physical_preconditioner_test {
class Constraint;
class PreparedConstraint;
class Constraint final {
public:
struct Parameters final {
mean_field::dimensions::SpecificEnthalpyValue target;
};
using TargetValue = mean_field::dimensions::SpecificEnthalpyValue;
using ScalarDescription = mean_field::stellar::ScalarConstraint<
mean_field::dimensions::quantity::SpecificEnthalpy,
mean_field::dimensions::quantity::Dimensionless,
mean_field::dimensions::quantity::SpecificEnthalpy,
"test.unsupported_physical_edge.coordinate",
"q_u",
"test.unsupported_physical_edge.residual",
"R_u">;
using ModelDefinition = mean_field::constraint::ScalarPhaseCondition<
Constraint,
"UnsupportedPhysicalPreconditionerEdge",
mean_field::stellar::Reads<
mean_field::stellar::state::SpecificEnthalpy,
mean_field::stellar::state::OwnGeneratedCoordinate>,
mean_field::stellar::Changes<
mean_field::stellar::equation::PoissonEquation>,
ScalarDescription>;
using EquilibriumPhysics =
mean_field::operators::LocalSpecificationEquilibriumPhysics<
PreparedConstraint>;
explicit constexpr Constraint(const Parameters parameters) noexcept
: m_target(parameters.target) {
}
[[nodiscard]] constexpr TargetValue target() const noexcept {
return m_target;
}
private:
TargetValue m_target;
};
struct PreparationReport final {
bool stateChanged{true};
};
class PreparedConstraint final {
public:
using Report = PreparationReport;
explicit PreparedConstraint(const Constraint &) noexcept {
}
template <typename StateView>
[[nodiscard]] Report PrepareAfterPhysical(const StateView &) noexcept {
m_isPrepared = true;
return {};
}
template <typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddResidual(
mean_field::stellar::equation::OwnConstraint,
Row &
) const noexcept {
return mean_field::stellar::structuralZero;
}
template <typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddResidual(
mean_field::stellar::equation::PoissonEquation,
Row &
) const noexcept {
return mean_field::stellar::structuralZero;
}
template <typename Direction, typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
mean_field::stellar::equation::OwnConstraint,
mean_field::stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
template <typename Direction, typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
mean_field::stellar::equation::OwnConstraint,
mean_field::stellar::state::OwnGeneratedCoordinate>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
template <typename Direction, typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
mean_field::stellar::equation::PoissonEquation,
mean_field::stellar::state::SpecificEnthalpy>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
template <typename Direction, typename Row>
[[nodiscard]] mean_field::stellar::StructuralZero AddJacobianAction(
mean_field::stellar::Derivative<
mean_field::stellar::equation::PoissonEquation,
mean_field::stellar::state::OwnGeneratedCoordinate>,
const Direction &,
Row &
) const noexcept {
return mean_field::stellar::zeroDerivative;
}
[[nodiscard]] bool IsPrepared() const noexcept {
return m_isPrepared;
}
private:
bool m_isPrepared{false};
};
} // namespace unsupported_physical_preconditioner_test
template <> struct mean_field::preconditioning::StellarEquilibriumProblemTraits<preconditioning_runtime_test::Problem> {
using Problem = preconditioning_runtime_test::Problem;
using Form = preconditioning_runtime_test::Form;
@@ -146,14 +280,40 @@ namespace {
namespace blocks = mean_field::utils::blocks;
namespace preconditioning = mean_field::preconditioning;
using ModelWithoutPhase = mean_field::operators::StellarEquilibriumSpecificationModel;
using CentralDensityModel = mean_field::operators::CentralDensityStellarEquilibriumSpecificationModel;
using ModelWithoutPhase = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass>>;
using CentralDensityModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass,
mean_field::models::FixedCentralDensity>>;
using AngularMomentumModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass,
mean_field::models::FixedAngularMomentum>>;
using ProvenZeroPhysicalEdgeModel = mean_field::model::StellarModel<
mean_field::models::SpecificationSet<
mean_field::eos::Polytrope,
mean_field::surface::Isobaric,
mean_field::models::FixedTotalMass,
unsupported_physical_preconditioner_test::Constraint>>;
using ProblemWithoutPhase = mean_field::equilibrium::StellarEquilibriumProblem<ModelWithoutPhase>;
using CentralDensityProblem = mean_field::equilibrium::StellarEquilibriumProblem<CentralDensityModel>;
using AngularMomentumProblem = mean_field::equilibrium::StellarEquilibriumProblem<AngularMomentumModel>;
using ProvenZeroPhysicalEdgeProblem =
mean_field::equilibrium::StellarEquilibriumProblem<ProvenZeroPhysicalEdgeModel>;
using PlanWithoutPhase = preconditioning::IdentityPreconditionerPlanFor<ProblemWithoutPhase>;
using CentralDensityPlan = preconditioning::IdentityPreconditionerPlanFor<CentralDensityProblem>;
template <typename Problem>
concept CanMakeDefaultStellarStructureBlock = requires(const Problem &problem) {
preconditioning::stellarStructureBlock(problem);
};
using RefreshingDensityIdentity = preconditioning::ComponentDeclaration<
blocks::type_list<blocks::density::mass::value>,
blocks::type_list<blocks::density::mass::residual>,
@@ -203,6 +363,73 @@ TEST_CASE(
STATIC_CHECK(CentralDensityPlan::ComponentTypes::size == 7);
}
TEST_CASE(
"Default Stellar Structure Availability Distinguishes Proven Zeros From Unhandled Physical Edges",
"[preconditioning][stellar_structure][type_contract][compiler]"
) {
using BaseCompilation =
mean_field::operators::CompiledStellarEquilibriumSystem<ModelWithoutPhase>;
using BaseSupport =
preconditioning::DefaultStellarStructurePhysicalTopologySupport<
ModelWithoutPhase>;
using ProvenZeroSupport =
preconditioning::DefaultStellarStructurePhysicalTopologySupport<
ProvenZeroPhysicalEdgeModel>;
using TrustedFixedMassEdge =
mean_field::operators::StellarEquilibriumJacobianCoupling<
blocks::enthalpy::specific::residual,
blocks::density::mass::value>;
using ProvenZeroPoissonEnthalpyEdge =
mean_field::operators::StellarEquilibriumJacobianCoupling<
blocks::gravity::poisson::residual,
blocks::enthalpy::specific::value>;
// FixedTotalMass contributes h <- rho outside the generic five-field base
// graph. It remains supported because that specification is explicitly
// embedded in the trusted numerical core, not because of a model-pack
// special case.
STATIC_CHECK_FALSE(mean_field::utils::blocks::contains_type_v<
TrustedFixedMassEdge,
typename BaseCompilation::BaseJacobianCouplings>);
STATIC_CHECK(mean_field::utils::blocks::contains_type_v<
TrustedFixedMassEdge,
typename BaseCompilation::ContributionJacobianCouplings>);
STATIC_CHECK(BaseSupport::UnsupportedCouplings::size == 0);
STATIC_CHECK(preconditioning::DefaultStellarStructurePhysicalTopologySupportedFor<
ModelWithoutPhase>);
STATIC_CHECK(preconditioning::DefaultStellarStructurePhysicalTopologySupportedFor<
CentralDensityModel>);
STATIC_CHECK(preconditioning::DefaultStellarStructurePhysicalTopologySupportedFor<
AngularMomentumModel>);
STATIC_CHECK(preconditioning::StellarStructurePreconditionerProblem<
ProblemWithoutPhase>);
STATIC_CHECK(CanMakeDefaultStellarStructureBlock<ProblemWithoutPhase>);
STATIC_CHECK(preconditioning::DefaultStellarPreconditionerAvailableFor<
ProblemWithoutPhase>);
// The mock's novel Poisson <- enthalpy edge is absent from the structure
// backend, but its exact nested provider returns StructuralZero. That is
// a compile-time proof that no preconditioner term is missing; generated-
// coordinate edges are handled independently by the inferred border.
STATIC_CHECK(mean_field::equilibrium::StellarEquilibriumModel<
ProvenZeroPhysicalEdgeModel>);
STATIC_CHECK(mean_field::equilibrium::DiscretizedStellarEquilibriumProblem<
ProvenZeroPhysicalEdgeProblem>);
STATIC_CHECK(ProvenZeroSupport::UnsupportedCouplings::size == 0);
STATIC_CHECK(mean_field::utils::blocks::contains_type_v<
ProvenZeroPoissonEnthalpyEdge,
typename mean_field::operators::CompiledStellarEquilibriumSystem<
ProvenZeroPhysicalEdgeModel>::ContributionJacobianCouplings>);
STATIC_CHECK(preconditioning::DefaultStellarStructurePhysicalTopologySupportedFor<
ProvenZeroPhysicalEdgeModel>);
STATIC_CHECK(preconditioning::StellarStructurePreconditionerProblem<
ProvenZeroPhysicalEdgeProblem>);
STATIC_CHECK(CanMakeDefaultStellarStructureBlock<
ProvenZeroPhysicalEdgeProblem>);
STATIC_CHECK(preconditioning::DefaultStellarPreconditionerAvailableFor<
ProvenZeroPhysicalEdgeProblem>);
}
TEST_CASE(
"Prepared Stellar Identity Preconditioning Is Bitwise Equivalent To The P0 Baseline",
tags::preconditioning_runtime_unit
@@ -286,6 +513,14 @@ TEST_CASE(
CHECK_FALSE(geometryRefresh.changes.linearization);
CHECK(preconditioner.GetStatistics().refreshes == 2);
problem.AdvancePreparation();
CHECK_FALSE(preconditioner.IsCurrent());
const auto preparationRefresh = preconditioner.Refresh();
CHECK(preparationRefresh.changes.linearization);
CHECK_FALSE(preparationRefresh.changes.geometry);
CHECK(preconditioner.IsCurrent());
CHECK(preconditioner.GetStatistics().refreshes == 3);
problem.SetPrepared(false);
CHECK_FALSE(preconditioner.IsCurrent());
CHECK_THROWS_AS(preconditioner.Refresh(), std::logic_error);

View File

@@ -114,6 +114,7 @@ namespace {
mean_field::integral::FixedTotalMass,
mean_field::constraint::FixedCentralDensity>>;
using PolytropicProblem = mean_field::equilibrium::StellarEquilibriumProblem<PolytropicModel>;
using PolytropicMaterialSurfaceDescriptor = preconditioning::MaterialSurfaceDescriptorFor<PolytropicProblem>;
using MaterialComponent =
decltype(preconditioning::materialSurfaceBlock(std::declval<const PolytropicProblem &>()));
using FixedAMG = backend::HypreBoomerAMG<backend::FixedCycles>;
@@ -126,6 +127,13 @@ namespace {
preconditioning::IndependentStellarSubsystems{}
));
template <typename Problem>
concept CanPrepareDefaultStellarStructure = requires(const Problem &problem) {
preconditioning::prepare(problem, preconditioning::stellarStructureBlock(problem));
};
struct DistinctPhysicalCore final { };
[[nodiscard]] mean_field::operators::StellarEquilibriumDependencies
makeDependencies(const std::uint64_t revision = 1) {
return {
@@ -173,11 +181,26 @@ TEST_CASE(
preconditioning::Coupling<blocks::enthalpy::specific::residual, blocks::gravity::poisson::value>>;
STATIC_CHECK(preconditioning::PreconditionerComponent<PolytropicStructure>);
STATIC_CHECK(preconditioning::ExecutableStellarStructureRuntimeFor<
mean_field::operators::PreparedStellarEquilibriumOperator>);
STATIC_CHECK_FALSE(preconditioning::ExecutableStellarStructureRuntimeFor<DistinctPhysicalCore>);
STATIC_CHECK(preconditioning::StellarStructureRuntimeFor<
PolytropicMaterialSurfaceDescriptor,
mean_field::operators::PreparedStellarEquilibriumOperator>);
STATIC_CHECK_FALSE(preconditioning::StellarStructureRuntimeFor<
PolytropicMaterialSurfaceDescriptor,
DistinctPhysicalCore>);
STATIC_CHECK(preconditioning::StellarStructurePreconditionerProblem<PolytropicProblem>);
STATIC_CHECK(preconditioning::StellarStructurePreparableFor<
PolytropicProblem,
MaterialComponent,
GravityComponent>);
STATIC_CHECK(CanPrepareDefaultStellarStructure<PolytropicProblem>);
STATIC_CHECK(std::same_as<typename PolytropicStructure::MaterialToGravityCouplings, ExpectedMaterialToGravity>);
STATIC_CHECK(std::same_as<typename PolytropicStructure::GravityToMaterialCouplings, ExpectedGravityToMaterial>);
STATIC_CHECK(PolytropicStructure::MaterialToGravityCouplings::size == 3);
STATIC_CHECK(PolytropicStructure::GravityToMaterialCouplings::size == 2);
STATIC_CHECK(PolytropicStructure::RequiredCouplings::size == 16);
STATIC_CHECK(PolytropicStructure::RequiredCouplings::size == 17);
STATIC_CHECK(preconditioning::backend::ArnoldiAdmissible<typename PolytropicStructure::BackendType>);
using FixedMassIdentity = preconditioning::IdentityBlock<
@@ -265,7 +288,7 @@ TEST_CASE(
mfem::Vector materialOnlyDirection(physical.Width());
materialOnlyDirection = 0.0;
auto materialOnlyView = physical.GetRootManifest().directionView(materialOnlyDirection);
auto materialOnlyView = physical.GetRootManifest().stateView(materialOnlyDirection);
mfem::Vector materialDensity = materialOnlyView.block(blocks::density_field.mass_term);
mfem::Vector materialSurface = materialOnlyView.block(blocks::surface_deformation_field.parameters_term);
mfem::Vector materialEnthalpy = materialOnlyView.block(blocks::enthalpy_field.specific_term);
@@ -290,7 +313,7 @@ TEST_CASE(
mfem::Vector gravityOnlyDirection(physical.Width());
gravityOnlyDirection = 0.0;
auto gravityOnlyView = physical.GetRootManifest().directionView(gravityOnlyDirection);
auto gravityOnlyView = physical.GetRootManifest().stateView(gravityOnlyDirection);
mfem::Vector gravityGradient = gravityOnlyView.block(blocks::gravity_field.gradient_term);
mfem::Vector gravityPotential = gravityOnlyView.block(blocks::gravity_field.poisson_term);
const mfem::Vector sourceGravityGradient(