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

@@ -292,7 +292,8 @@ export namespace mean_field::preconditioning {
};
template <equilibrium::DiscretizedStellarEquilibriumProblem Problem, SpecificationBorderBlockType Block>
requires EquilibriumCoordinateComponentFor<Block, typename std::remove_cvref_t<Problem>::FormType>
requires EquilibriumCoordinateComponentFor<Block, typename std::remove_cvref_t<Problem>::FormType> &&
SpecificationBorderPreparableFor<Problem, Block>
class PreparedStellarPreconditioner final : public mfem::Solver {
private:
using ProblemType = std::remove_cvref_t<Problem>;
@@ -324,6 +325,9 @@ export namespace mean_field::preconditioning {
}
}
PreparedStellarPreconditioner(ProblemType &&, BlockType) = delete;
PreparedStellarPreconditioner(const ProblemType &&, BlockType) = delete;
PreparedStellarPreconditioner(const PreparedStellarPreconditioner &) = delete;
PreparedStellarPreconditioner &operator=(const PreparedStellarPreconditioner &) = delete;
PreparedStellarPreconditioner(PreparedStellarPreconditioner &&) = delete;
@@ -367,6 +371,10 @@ export namespace mean_field::preconditioning {
return m_grouped.GetBlock();
}
[[nodiscard]] const ProblemType &GetProblem() const noexcept {
return m_grouped.GetProblem();
}
[[nodiscard]] const GroupedPreconditioner &GetGroupedPreconditioner() const noexcept {
return m_grouped;
}
@@ -392,11 +400,26 @@ export namespace mean_field::preconditioning {
SpecificationBorderBlockType Block>
requires EquilibriumCoordinateComponentFor<
Block,
typename std::remove_cvref_t<Problem>::FormType>
typename std::remove_cvref_t<Problem>::FormType> &&
SpecificationBorderPreparableFor<Problem, Block>
[[nodiscard]] auto prepare(
const Problem &problem,
Block block
) {
return PreparedStellarPreconditioner<Problem, Block>{problem, std::move(block)};
}
template <typename Problem, SpecificationBorderBlockType Block>
requires (!std::is_lvalue_reference_v<Problem>) &&
equilibrium::DiscretizedStellarEquilibriumProblem<std::remove_cvref_t<Problem>> &&
EquilibriumCoordinateComponentFor<
Block,
typename std::remove_cvref_t<Problem>::FormType> &&
SpecificationBorderPreparableFor<std::remove_cvref_t<Problem>, Block>
[[nodiscard]] auto prepare(
Problem &&,
Block
) -> PreparedStellarPreconditioner<
std::remove_cvref_t<Problem>,
std::remove_cvref_t<Block>> = delete;
} // namespace mean_field::preconditioning

View File

@@ -231,10 +231,90 @@ export namespace mean_field::preconditioning {
template <typename Candidate>
concept MaterialSurfaceDescriptor = detail::IsMaterialSurfaceDescriptor<std::remove_cvref_t<Candidate>>::value;
/*
* Capability boundary for EOS-specific material/surface surrogate
* assembly. The current kernels remain polytropic, but selection no
* longer embeds that closed-world type test in the descriptor concept.
*/
template <typename EquationOfState>
struct MaterialSurfaceEquationOfStateBackend {
static constexpr bool registered = false;
};
template <>
struct MaterialSurfaceEquationOfStateBackend<eos::Polytrope> {
static constexpr bool registered = true;
using CoreType = operators::PreparedStellarEquilibriumOperator;
};
template <typename EquationOfState>
concept ImplementedMaterialSurfaceEquationOfState = requires {
{
MaterialSurfaceEquationOfStateBackend<std::remove_cvref_t<EquationOfState>>::registered
} -> std::convertible_to<bool>;
requires MaterialSurfaceEquationOfStateBackend<
std::remove_cvref_t<EquationOfState>>::registered;
typename MaterialSurfaceEquationOfStateBackend<std::remove_cvref_t<EquationOfState>>::CoreType;
};
/*
* Registering an EOS-to-core association is intentionally not enough to
* claim that the material/surface preconditioner can execute it. Every
* implementation listed here must have matching prepared operators and
* prepare(...) overloads below. A future backend should add its pair only
* after those executable pieces exist; this keeps capability queries
* truthful while the current kernels still consume the legacy physical
* core directly.
*/
template <typename EquationOfState, typename PhysicalCore>
struct MaterialSurfaceExecutableRuntime {
static constexpr bool available = false;
};
template <>
struct MaterialSurfaceExecutableRuntime<eos::Polytrope, operators::PreparedStellarEquilibriumOperator> {
static constexpr bool available = true;
};
template <typename EquationOfState, typename PhysicalCore>
concept ExecutableMaterialSurfaceRuntimeFor = requires {
{
MaterialSurfaceExecutableRuntime<
std::remove_cvref_t<EquationOfState>,
std::remove_cvref_t<PhysicalCore>>::available
} -> std::convertible_to<bool>;
requires MaterialSurfaceExecutableRuntime<
std::remove_cvref_t<EquationOfState>,
std::remove_cvref_t<PhysicalCore>>::available;
};
template <typename Descriptor>
concept ImplementedMaterialSurfaceDescriptor =
MaterialSurfaceDescriptor<Descriptor> &&
std::same_as<typename Descriptor::ThermodynamicEquations::EquationOfStateType, eos::Polytrope>;
ImplementedMaterialSurfaceEquationOfState<
typename Descriptor::ThermodynamicEquations::EquationOfStateType>;
template <typename Descriptor, typename PhysicalCore>
concept MaterialSurfaceRuntimeFor =
ImplementedMaterialSurfaceDescriptor<Descriptor> && requires {
typename MaterialSurfaceEquationOfStateBackend<
typename std::remove_cvref_t<Descriptor>::ThermodynamicEquations::EquationOfStateType>::CoreType;
requires std::same_as<
std::remove_cvref_t<PhysicalCore>,
typename MaterialSurfaceEquationOfStateBackend<
typename std::remove_cvref_t<Descriptor>::ThermodynamicEquations::EquationOfStateType>::CoreType>;
requires ExecutableMaterialSurfaceRuntimeFor<
typename std::remove_cvref_t<Descriptor>::ThermodynamicEquations::EquationOfStateType,
PhysicalCore>;
};
template <typename Candidate>
concept MaterialSurfacePreconditionerProblem =
equilibrium::DiscretizedStellarEquilibriumProblem<Candidate> && requires {
requires MaterialSurfaceRuntimeFor<
MaterialSurfaceDescriptorFor<std::remove_cvref_t<Candidate>>,
typename std::remove_cvref_t<Candidate>::PhysicalCoreType>;
};
using DensityMassDiagonalCharacteristics = OperatorCharacteristics<
OperatorCategory::mass_like,
@@ -605,7 +685,7 @@ export namespace mean_field::preconditioning {
};
template <
equilibrium::DiscretizedStellarEquilibriumProblem Problem,
MaterialSurfacePreconditionerProblem Problem,
backend::Registered MaterialBackend = backend::Diagonal,
backend::Registered SurfaceBackend = backend::Diagonal,
MaterialSurfaceFactorizationPolicy Policy = SurfaceThenMaterialTriangular>
@@ -623,7 +703,7 @@ export namespace mean_field::preconditioning {
}
template <
equilibrium::DiscretizedStellarEquilibriumProblem Problem,
MaterialSurfacePreconditionerProblem Problem,
backend::Registered MaterialBackend,
backend::Registered SurfaceBackend,
MaterialSurfaceFactorizationPolicy Policy,
@@ -688,7 +768,7 @@ export namespace mean_field::preconditioning {
// direct coupling actions and does not pay for a full Jacobian
// application.
m_fullDirection = 0.0;
const auto fullDirectionView = m_operation->GetRootManifest().directionView(m_fullDirection);
const auto fullDirectionView = m_operation->GetRootManifest().stateView(m_fullDirection);
mfem::Vector fullDensityDirection = fullDirectionView.block(utils::blocks::density_field.mass_term);
mfem::Vector fullSurfaceDirection =
fullDirectionView.block(utils::blocks::surface_deformation_field.parameters_term);
@@ -699,10 +779,10 @@ export namespace mean_field::preconditioning {
m_operation->Mult(m_fullDirection, m_fullAction);
const auto fullActionView = m_operation->GetRootManifest().residualView(m_fullAction);
const mfem::Vector fullDensityAction = fullActionView.block(utils::blocks::density_field.mass_term);
const mfem::Vector fullSurfaceAction =
const auto fullDensityAction = fullActionView.block(utils::blocks::density_field.mass_term);
const auto fullSurfaceAction =
fullActionView.block(utils::blocks::surface_deformation_field.shape_equilibrium_term);
const mfem::Vector fullEnthalpyAction = fullActionView.block(utils::blocks::enthalpy_field.specific_term);
const auto fullEnthalpyAction = fullActionView.block(utils::blocks::enthalpy_field.specific_term);
densityAction = fullDensityAction;
surfaceAction = fullSurfaceAction;
enthalpyAction = fullEnthalpyAction;
@@ -1108,7 +1188,8 @@ export namespace mean_field::preconditioning {
std::uint64_t surfaceH1Assemblies{0};
};
template <ImplementedMaterialSurfaceDescriptor Descriptor, MaterialSurfaceFactorizationPolicy Policy>
template <MaterialSurfaceDescriptor Descriptor, MaterialSurfaceFactorizationPolicy Policy>
requires MaterialSurfaceRuntimeFor<Descriptor, operators::PreparedStellarEquilibriumOperator>
class PreparedMaterialSurfaceBlock final : public mfem::Solver {
public:
using Block = MaterialSurfaceBlock<Descriptor, backend::Diagonal, backend::Diagonal, Policy>;
@@ -1562,9 +1643,10 @@ export namespace mean_field::preconditioning {
};
template <
ImplementedMaterialSurfaceDescriptor Descriptor,
MaterialSurfaceDescriptor Descriptor,
MaterialSurfaceFactorizationPolicy Policy,
backend::ApplicationMode Mode>
requires MaterialSurfaceRuntimeFor<Descriptor, operators::PreparedStellarEquilibriumOperator>
class PreparedH1MaterialSurfaceBlock final : public mfem::Solver {
public:
using SurfaceBackend = backend::HypreBoomerAMG<Mode>;
@@ -2027,8 +2109,9 @@ export namespace mean_field::preconditioning {
};
template <
ImplementedMaterialSurfaceDescriptor Descriptor,
MaterialSurfaceDescriptor Descriptor,
MaterialSurfaceFactorizationPolicy Policy>
requires MaterialSurfaceRuntimeFor<Descriptor, operators::PreparedStellarEquilibriumOperator>
[[nodiscard]] auto prepare(
const operators::PreparedStellarEquilibriumOperator &operation,
MaterialSurfaceBlock<
@@ -2042,26 +2125,26 @@ export namespace mean_field::preconditioning {
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization,
MaterialSurfaceFactorizationPolicy Policy>
requires MaterialSurfacePreconditionerProblem<
equilibrium::StellarEquilibriumProblem<Model, Discretization>>
[[nodiscard]] auto prepare(
const equilibrium::StellarEquilibriumProblem<Model> &problem,
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
MaterialSurfaceBlock<
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<Model>>,
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<Model, Discretization>>,
backend::Diagonal,
backend::Diagonal,
Policy> block
) {
if constexpr (equilibrium::StellarEquilibriumProblem<Model>::hasFixedCentralDensity) {
return prepare(problem.GetPreparedOperator().GetPhysicalOperator(), std::move(block));
} else {
return prepare(problem.GetPreparedOperator(), std::move(block));
}
return prepare(problem.GetPhysicalOperator(), std::move(block));
}
template <
ImplementedMaterialSurfaceDescriptor Descriptor,
MaterialSurfaceDescriptor Descriptor,
MaterialSurfaceFactorizationPolicy Policy,
backend::ApplicationMode Mode>
requires MaterialSurfaceRuntimeFor<Descriptor, operators::PreparedStellarEquilibriumOperator>
[[nodiscard]] auto prepare(
const operators::PreparedStellarEquilibriumOperator &operation,
MaterialSurfaceBlock<
@@ -2076,21 +2159,20 @@ export namespace mean_field::preconditioning {
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization,
MaterialSurfaceFactorizationPolicy Policy,
backend::ApplicationMode Mode>
requires MaterialSurfacePreconditionerProblem<
equilibrium::StellarEquilibriumProblem<Model, Discretization>>
[[nodiscard]] auto prepare(
const equilibrium::StellarEquilibriumProblem<Model> &problem,
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
MaterialSurfaceBlock<
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<Model>>,
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<Model, Discretization>>,
backend::Diagonal,
backend::HypreBoomerAMG<Mode>,
Policy,
SurfaceH1MassStiffness> block
) {
if constexpr (equilibrium::StellarEquilibriumProblem<Model>::hasFixedCentralDensity) {
return prepare(problem.GetPreparedOperator().GetPhysicalOperator(), std::move(block));
} else {
return prepare(problem.GetPreparedOperator(), std::move(block));
}
return prepare(problem.GetPhysicalOperator(), std::move(block));
}
} // namespace mean_field::preconditioning

View File

@@ -24,6 +24,7 @@ export namespace mean_field::preconditioning {
operators::StellarEquilibriumDependencyStamp geometry;
const void *equationOfStateIdentity{nullptr};
operators::StellarEquilibriumDependencies linearization;
std::uint64_t preparedOperatorGeneration{0};
constexpr bool operator==(const StellarPreconditionerLifecycleSnapshot &) const = default;
};
@@ -61,7 +62,8 @@ export namespace mean_field::preconditioning {
.discretization = prepared.discretization != current.discretization,
.geometry = prepared.geometry != current.geometry,
.equationOfState = prepared.equationOfStateIdentity != current.equationOfStateIdentity,
.linearization = prepared.linearization != current.linearization
.linearization = prepared.linearization != current.linearization ||
prepared.preparedOperatorGeneration != current.preparedOperatorGeneration
};
}
@@ -95,9 +97,11 @@ export namespace mean_field::preconditioning {
static constexpr bool registered = false;
};
template <equilibrium::StellarEquilibriumModel Model>
struct StellarEquilibriumProblemTraits<equilibrium::StellarEquilibriumProblem<Model>> {
using Problem = equilibrium::StellarEquilibriumProblem<Model>;
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization>
struct StellarEquilibriumProblemTraits<equilibrium::StellarEquilibriumProblem<Model, Discretization>> {
using Problem = equilibrium::StellarEquilibriumProblem<Model, Discretization>;
using Form = typename Problem::FormType;
using JacobianForm = typename Problem::JacobianFormType;
using Manifest = typename Problem::ManifestType;
@@ -130,8 +134,9 @@ export namespace mean_field::preconditioning {
.discretization = dependencies.discretization,
.geometry = problem.GetGeometryDependency(),
.equationOfStateIdentity =
std::addressof(problem.GetStellarModel().template specification<eos::Polytrope>()),
.linearization = dependencies
std::addressof(problem.GetStellarModel().equationOfState()),
.linearization = dependencies,
.preparedOperatorGeneration = problem.GetPreparationGeneration()
};
}
};
@@ -139,6 +144,243 @@ export namespace mean_field::preconditioning {
template <typename Candidate>
concept StellarPreconditionerProblem = StellarEquilibriumProblemTraits<std::remove_cvref_t<Candidate>>::registered;
namespace detail {
template <typename Block>
struct IsGeneratedStellarValueBlock : std::false_type { };
template <typename Generated>
struct IsGeneratedStellarValueBlock<utils::blocks::generated_value_block<Generated>>
: std::true_type { };
template <typename Block>
struct IsGeneratedStellarResidualBlock : std::false_type { };
template <typename Generated>
struct IsGeneratedStellarResidualBlock<utils::blocks::generated_residual_block<Generated>>
: std::true_type { };
template <typename Coupling>
inline constexpr bool isPurePhysicalStellarCoupling =
!IsGeneratedStellarValueBlock<
std::remove_cvref_t<typename Coupling::Value>>::value &&
!IsGeneratedStellarResidualBlock<
std::remove_cvref_t<typename Coupling::Residual>>::value;
/* Pure structure contributions owned by a trusted backend are exact
* (core, specification, coupling) capabilities. Future cores and new
* edges start with no privilege: changing a built-in declaration must
* be accompanied by an explicit preconditioner decision. Generated-
* border terms remain the responsibility of specification-border
* machinery. */
template <typename PhysicalCore, typename Specification>
struct StellarStructureBackendHandledCouplings {
using Type = utils::blocks::type_list<>;
};
template <>
struct StellarStructureBackendHandledCouplings<
operators::PreparedStellarEquilibriumOperator,
models::FixedTotalMass> {
using Type = utils::blocks::type_list<
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::enthalpy::specific::residual,
utils::blocks::density::mass::value>,
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::enthalpy::specific::residual,
utils::blocks::surface_deformation::parameters::value>>;
};
template <>
struct StellarStructureBackendHandledCouplings<
operators::PreparedStellarEquilibriumOperator,
models::FixedAngularMomentum> {
using Type = utils::blocks::type_list<
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::surface_deformation::shape_equilibrium::residual,
utils::blocks::density::mass::value>,
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::surface_deformation::shape_equilibrium::residual,
utils::blocks::surface_deformation::parameters::value>,
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::enthalpy::specific::residual,
utils::blocks::density::mass::value>,
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::enthalpy::specific::residual,
utils::blocks::surface_deformation::parameters::value>>;
};
template <>
struct StellarStructureBackendHandledCouplings<
operators::PreparedStellarEquilibriumOperator,
models::FixedCentralDensity> {
using Type = utils::blocks::type_list<
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::enthalpy::specific::residual,
utils::blocks::enthalpy::specific::value>>;
};
template <
typename Coupling,
typename Model,
typename PhysicalCore,
typename ModelSpecifications>
struct EveryCouplingContributionHandled;
template <
typename Coupling,
model::StellarModelType Model,
typename PhysicalCore,
models::ModelSpecification... Specifications>
struct EveryCouplingContributionHandled<
Coupling,
Model,
PhysicalCore,
models::detail::SpecificationSetStorage<Specifications...>> final {
private:
template <typename Specification>
static constexpr bool handled =
!utils::blocks::contains_type_v<
Coupling,
typename operators::StellarEquilibriumSpecificationCompilation<
Specification>::JacobianCouplings> ||
(operators::stellarEquilibriumBackendRuntimeAuthorized<
Specification,
Model> &&
utils::blocks::contains_type_v<
Coupling,
typename StellarStructureBackendHandledCouplings<
PhysicalCore,
Specification>::Type>) ||
operators::stellarEquilibriumSpecificationCouplingIsStructuralZero<
Specification,
Model,
Coupling>;
public:
static constexpr bool value =
(handled<Specifications> && ...);
};
template <
typename Remaining,
typename Model,
typename PhysicalCore,
typename ModelSpecifications,
typename Unsupported>
struct CollectUnsupportedStellarStructureCouplings;
template <
typename Model,
typename PhysicalCore,
typename ModelSpecifications,
typename Unsupported>
struct CollectUnsupportedStellarStructureCouplings<
utils::blocks::type_list<>,
Model,
PhysicalCore,
ModelSpecifications,
Unsupported> {
using Type = Unsupported;
};
template <
typename Head,
typename... Tail,
typename Model,
typename PhysicalCore,
typename ModelSpecifications,
typename... Unsupported>
struct CollectUnsupportedStellarStructureCouplings<
utils::blocks::type_list<Head, Tail...>,
Model,
PhysicalCore,
ModelSpecifications,
utils::blocks::type_list<Unsupported...>> {
private:
static constexpr bool supported =
!isPurePhysicalStellarCoupling<Head> ||
EveryCouplingContributionHandled<
Head,
Model,
PhysicalCore,
ModelSpecifications>::value;
using Next = std::conditional_t<
supported,
utils::blocks::type_list<Unsupported...>,
utils::blocks::type_list<Unsupported..., Head>>;
public:
using Type = typename CollectUnsupportedStellarStructureCouplings<
utils::blocks::type_list<Tail...>,
Model,
PhysicalCore,
ModelSpecifications,
Next>::Type;
};
template <typename Candidate, typename = void>
struct DefaultStellarStructurePhysicalTopologyAudit {
using ContributionCouplings = utils::blocks::type_list<>;
using UnsupportedCouplings = utils::blocks::type_list<>;
static constexpr bool supported = false;
};
template <model::StellarModelType Model>
requires(
operators::StellarEquilibriumSystemCompilable<
std::remove_cvref_t<Model>> &&
operators::hasStellarEquilibriumCoreRuntime<
std::remove_cvref_t<Model>>)
struct DefaultStellarStructurePhysicalTopologyAudit<
Model,
std::void_t<
typename operators::CompiledStellarEquilibriumSystem<
std::remove_cvref_t<Model>>::ContributionJacobianCouplings,
operators::StellarEquilibriumPhysicalCoreType<
std::remove_cvref_t<Model>>>> {
private:
using Compilation = operators::CompiledStellarEquilibriumSystem<
std::remove_cvref_t<Model>>;
using PhysicalCore = operators::StellarEquilibriumPhysicalCoreType<
std::remove_cvref_t<Model>>;
public:
using ContributionCouplings =
typename Compilation::ContributionJacobianCouplings;
using UnsupportedCouplings =
typename CollectUnsupportedStellarStructureCouplings<
ContributionCouplings,
std::remove_cvref_t<Model>,
PhysicalCore,
typename std::remove_cvref_t<Model>::SpecificationTypes,
utils::blocks::type_list<>>::Type;
static constexpr bool supported = UnsupportedCouplings::size == 0;
};
} // namespace detail
/* A generated-border edge is owned by specification-border machinery and
* is deliberately ignored here. Every pure physical edge contributed by a
* model must be owned by the selected numerical structure backend, or
* every non-backend provider of that edge must prove StructuralZero. In
* particular, merely overlapping an existing base-Jacobian edge is not
* sufficient: a custom nonzero coefficient on that edge would otherwise
* disappear silently from the default preconditioner. This audit is
* detection-safe and therefore suitable for constraining factories. */
template <typename Candidate>
struct DefaultStellarStructurePhysicalTopologySupport
: detail::DefaultStellarStructurePhysicalTopologyAudit<
std::remove_cvref_t<Candidate>> { };
template <typename Candidate>
inline constexpr bool defaultStellarStructurePhysicalTopologySupported =
DefaultStellarStructurePhysicalTopologySupport<
std::remove_cvref_t<Candidate>>::supported;
template <typename Candidate>
concept DefaultStellarStructurePhysicalTopologySupportedFor =
defaultStellarStructurePhysicalTopologySupported<Candidate>;
namespace backend {
template <typename Component, typename Problem, typename Backend = typename Component::BackendType>
class PreparedComponent;
@@ -174,56 +416,17 @@ export namespace mean_field::preconditioning {
} // namespace backend
namespace detail {
using DensityIdentity =
IdentityBlock<utils::blocks::density::mass::value, utils::blocks::density::mass::residual>;
using SurfaceIdentity = IdentityBlock<
utils::blocks::surface_deformation::parameters::value,
utils::blocks::surface_deformation::shape_equilibrium::residual>;
using GravityGradientIdentity =
IdentityBlock<utils::blocks::gravity::gradient::value, utils::blocks::gravity::gradient::residual>;
using GravityPotentialIdentity =
IdentityBlock<utils::blocks::gravity::poisson::value, utils::blocks::gravity::poisson::residual>;
using EnthalpyIdentity =
IdentityBlock<utils::blocks::enthalpy::specific::value, utils::blocks::enthalpy::specific::residual>;
using FixedMassIdentity = IdentityBlock<
utils::blocks::fixed_total_mass::mass_normalization::value,
utils::blocks::fixed_total_mass::mass_normalization::residual>;
using FixedCentralDensityIdentity = IdentityBlock<
utils::blocks::fixed_central_density::central_value::value,
utils::blocks::fixed_central_density::central_value::residual>;
template <typename Form> struct IdentityPlanForForm;
template <> struct IdentityPlanForForm<utils::blocks::surface_deformed_stellar_equilibrium_form> {
using Type = PreconditionerPlan<
DensityIdentity,
SurfaceIdentity,
GravityGradientIdentity,
GravityPotentialIdentity,
EnthalpyIdentity,
FixedMassIdentity>;
template <typename... Values, typename... Residuals>
struct IdentityPlanForForm<utils::blocks::block_form<
utils::blocks::type_list<Values...>,
utils::blocks::type_list<Residuals...>>> {
static_assert(sizeof...(Values) == sizeof...(Residuals));
using Type = PreconditionerPlan<IdentityBlock<Values, Residuals>...>;
[[nodiscard]] static constexpr Type Make() {
return Type{DensityIdentity{}, SurfaceIdentity{}, GravityGradientIdentity{},
GravityPotentialIdentity{}, EnthalpyIdentity{}, FixedMassIdentity{}};
}
};
template <> struct IdentityPlanForForm<utils::blocks::central_density_bordered_stellar_equilibrium_form> {
using Type = PreconditionerPlan<
DensityIdentity,
SurfaceIdentity,
GravityGradientIdentity,
GravityPotentialIdentity,
EnthalpyIdentity,
FixedMassIdentity,
FixedCentralDensityIdentity>;
[[nodiscard]] static constexpr Type Make() {
return Type{
DensityIdentity{}, SurfaceIdentity{}, GravityGradientIdentity{}, GravityPotentialIdentity{},
EnthalpyIdentity{}, FixedMassIdentity{}, FixedCentralDensityIdentity{}
};
return Type{IdentityBlock<Values, Residuals>{}...};
}
};

View File

@@ -14,6 +14,7 @@ export module mean_field:preconditioning.stellar_structure;
export import :preconditioning.gravity_field;
export import :preconditioning.material_surface;
export import :preconditioning.stellar_equilibrium;
export namespace mean_field::preconditioning {
struct IndependentStellarSubsystems final { };
@@ -626,28 +627,88 @@ export namespace mean_field::preconditioning {
}
};
/*
* Material/surface execution and stellar-structure execution are separate
* capabilities. The latter also owns the physical cross-Jacobian and
* gravity-context wiring, which currently target the legacy prepared core.
* Add future cores here only together with matching cross-coupling and
* preparation implementations.
*/
template <typename PhysicalCore>
struct StellarStructureExecutableRuntime {
static constexpr bool available = false;
};
template <>
struct StellarStructureExecutableRuntime<operators::PreparedStellarEquilibriumOperator> {
static constexpr bool available = true;
};
template <typename PhysicalCore>
concept ExecutableStellarStructureRuntimeFor = requires {
{
StellarStructureExecutableRuntime<std::remove_cvref_t<PhysicalCore>>::available
} -> std::convertible_to<bool>;
requires StellarStructureExecutableRuntime<std::remove_cvref_t<PhysicalCore>>::available;
};
template <typename Descriptor, typename PhysicalCore>
concept StellarStructureRuntimeFor =
MaterialSurfaceRuntimeFor<Descriptor, PhysicalCore> &&
ExecutableStellarStructureRuntimeFor<PhysicalCore>;
template <typename Candidate>
concept StellarStructurePreconditionerProblem =
equilibrium::DiscretizedStellarEquilibriumProblem<Candidate> &&
DefaultStellarStructurePhysicalTopologySupportedFor<
typename std::remove_cvref_t<Candidate>::ModelType> &&
requires {
requires StellarStructureRuntimeFor<
MaterialSurfaceDescriptorFor<std::remove_cvref_t<Candidate>>,
typename std::remove_cvref_t<Candidate>::PhysicalCoreType>;
};
namespace detail {
template <equilibrium::StellarEquilibriumModel Model>
[[nodiscard]] const operators::PreparedStellarEquilibriumOperator &
physicalOperator(const equilibrium::StellarEquilibriumProblem<Model> &problem) {
if constexpr (equilibrium::StellarEquilibriumProblem<Model>::hasFixedCentralDensity) {
return problem.GetPreparedOperator().GetPhysicalOperator();
} else {
return problem.GetPreparedOperator();
}
template <StellarStructurePreconditionerProblem Problem>
[[nodiscard]] const auto &physicalOperator(const Problem &problem) {
return problem.GetPhysicalOperator();
}
} // namespace detail
template <typename Problem, typename MaterialComponent, typename GravityComponent>
concept StellarStructurePreparableFor =
StellarStructurePreconditionerProblem<std::remove_cvref_t<Problem>> &&
PreconditionerComponent<std::remove_cvref_t<MaterialComponent>> &&
PreconditionerComponent<std::remove_cvref_t<GravityComponent>> &&
requires(
const std::remove_cvref_t<Problem> &problem,
std::remove_cvref_t<MaterialComponent> materialComponent,
std::remove_cvref_t<GravityComponent> gravityComponent
) {
preconditioning::prepare(problem, std::move(materialComponent));
preconditioning::prepare(
problem.GetPhysicalOperator().GetHydrostaticOperator().GetFEM(),
problem.GetPhysicalOperator().GetGravityContext().GetGeometryContext(),
std::move(gravityComponent)
);
StellarStructureCrossJacobianOperator{problem.GetPhysicalOperator()};
};
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization,
typename MaterialComponent,
backend::Registered GravityMassBackend,
backend::ApplicationMode Mode,
GravityFactorizationPolicy GravityPolicy,
StellarStructureFactorizationPolicy StructurePolicy>
requires StellarStructurePreparableFor<
equilibrium::StellarEquilibriumProblem<Model, Discretization>,
MaterialComponent,
GravityFieldBlock<GravityMassBackend, backend::HypreBoomerAMG<Mode>, GravityPolicy>>
class PreparedStellarStructureBlock final : public mfem::Solver {
private:
using Problem = equilibrium::StellarEquilibriumProblem<Model>;
using Problem = equilibrium::StellarEquilibriumProblem<Model, Discretization>;
using GravityComponent = GravityFieldBlock<GravityMassBackend, backend::HypreBoomerAMG<Mode>, GravityPolicy>;
using Structure = StellarStructureBlock<
MaterialComponent,
@@ -769,7 +830,7 @@ export namespace mean_field::preconditioning {
};
template <
equilibrium::DiscretizedStellarEquilibriumProblem Problem,
StellarStructurePreconditionerProblem Problem,
typename MaterialComponent,
backend::Registered GravityMassBackend,
backend::ApplicationMode Mode,
@@ -792,7 +853,7 @@ export namespace mean_field::preconditioning {
};
}
template <equilibrium::DiscretizedStellarEquilibriumProblem Problem>
template <StellarStructurePreconditionerProblem Problem>
[[nodiscard]] constexpr auto stellarStructureBlock(const Problem &problem) {
using FixedAMG = backend::HypreBoomerAMG<backend::FixedCycles>;
auto material = materialSurfaceBlock(problem);
@@ -805,25 +866,30 @@ export namespace mean_field::preconditioning {
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization,
typename MaterialComponent,
backend::Registered GravityMassBackend,
backend::ApplicationMode Mode,
GravityFactorizationPolicy GravityPolicy,
StellarStructureFactorizationPolicy StructurePolicy>
requires StellarStructurePreparableFor<
equilibrium::StellarEquilibriumProblem<Model, Discretization>,
MaterialComponent,
GravityFieldBlock<GravityMassBackend, backend::HypreBoomerAMG<Mode>, GravityPolicy>>
[[nodiscard]] auto prepare(
const equilibrium::StellarEquilibriumProblem<Model> &problem,
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
StellarStructureBlock<
MaterialComponent,
GravityFieldBlock<
GravityMassBackend,
backend::HypreBoomerAMG<Mode>,
GravityPolicy>,
typename equilibrium::StellarEquilibriumProblem<Model>::FormType,
typename equilibrium::StellarEquilibriumProblem<Model>::JacobianFormType,
typename equilibrium::StellarEquilibriumProblem<Model, Discretization>::FormType,
typename equilibrium::StellarEquilibriumProblem<Model, Discretization>::JacobianFormType,
StructurePolicy> structure
) {
return PreparedStellarStructureBlock<
Model, MaterialComponent, GravityMassBackend, Mode, GravityPolicy, StructurePolicy>{
Model, Discretization, MaterialComponent, GravityMassBackend, Mode, GravityPolicy, StructurePolicy>{
problem, std::move(structure)
};
}