feat(newton): first newton solver implementation

This commit is contained in:
2026-09-08 06:36:39 -04:00
parent 76818f2f82
commit b3c04d507a
98 changed files with 20397 additions and 11040 deletions

View File

@@ -325,8 +325,14 @@ export namespace mean_field::preconditioning {
}
}
PreparedStellarPreconditioner(ProblemType &&, BlockType) = delete;
PreparedStellarPreconditioner(const ProblemType &&, BlockType) = delete;
PreparedStellarPreconditioner(
ProblemType &&,
BlockType
) = delete;
PreparedStellarPreconditioner(
const ProblemType &&,
BlockType
) = delete;
PreparedStellarPreconditioner(const PreparedStellarPreconditioner &) = delete;
PreparedStellarPreconditioner &operator=(const PreparedStellarPreconditioner &) = delete;
@@ -399,9 +405,11 @@ export namespace mean_field::preconditioning {
equilibrium::DiscretizedStellarEquilibriumProblem Problem,
SpecificationBorderBlockType Block>
requires EquilibriumCoordinateComponentFor<
Block,
typename std::remove_cvref_t<Problem>::FormType> &&
SpecificationBorderPreparableFor<Problem, Block>
Block,
typename std::remove_cvref_t<Problem>::FormType> &&
SpecificationBorderPreparableFor<
Problem,
Block>
[[nodiscard]] auto prepare(
const Problem &problem,
Block block
@@ -409,17 +417,22 @@ export namespace mean_field::preconditioning {
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>
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;
)
-> PreparedStellarPreconditioner<
std::remove_cvref_t<Problem>,
std::remove_cvref_t<Block>> = delete;
} // namespace mean_field::preconditioning

View File

@@ -236,15 +236,13 @@ export namespace mean_field::preconditioning {
* 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 {
template <typename EquationOfState> struct MaterialSurfaceEquationOfStateBackend {
static constexpr bool registered = false;
};
template <>
struct MaterialSurfaceEquationOfStateBackend<eos::Polytrope> {
template <> struct MaterialSurfaceEquationOfStateBackend<eos::Polytrope> {
static constexpr bool registered = true;
using CoreType = operators::PreparedStellarEquilibriumOperator;
using CoreType = operators::PreparedStellarEquilibriumOperator;
};
template <typename EquationOfState>
@@ -252,8 +250,7 @@ export namespace mean_field::preconditioning {
{
MaterialSurfaceEquationOfStateBackend<std::remove_cvref_t<EquationOfState>>::registered
} -> std::convertible_to<bool>;
requires MaterialSurfaceEquationOfStateBackend<
std::remove_cvref_t<EquationOfState>>::registered;
requires MaterialSurfaceEquationOfStateBackend<std::remove_cvref_t<EquationOfState>>::registered;
typename MaterialSurfaceEquationOfStateBackend<std::remove_cvref_t<EquationOfState>>::CoreType;
};
@@ -266,13 +263,11 @@ export namespace mean_field::preconditioning {
* truthful while the current kernels still consume the legacy physical
* core directly.
*/
template <typename EquationOfState, typename PhysicalCore>
struct MaterialSurfaceExecutableRuntime {
template <typename EquationOfState, typename PhysicalCore> struct MaterialSurfaceExecutableRuntime {
static constexpr bool available = false;
};
template <>
struct MaterialSurfaceExecutableRuntime<eos::Polytrope, operators::PreparedStellarEquilibriumOperator> {
template <> struct MaterialSurfaceExecutableRuntime<eos::Polytrope, operators::PreparedStellarEquilibriumOperator> {
static constexpr bool available = true;
};
@@ -280,33 +275,28 @@ export namespace mean_field::preconditioning {
concept ExecutableMaterialSurfaceRuntimeFor = requires {
{
MaterialSurfaceExecutableRuntime<
std::remove_cvref_t<EquationOfState>,
std::remove_cvref_t<PhysicalCore>>::available
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;
std::remove_cvref_t<EquationOfState>, std::remove_cvref_t<PhysicalCore>>::available;
};
template <typename Descriptor>
concept ImplementedMaterialSurfaceDescriptor =
MaterialSurfaceDescriptor<Descriptor> &&
ImplementedMaterialSurfaceEquationOfState<
typename Descriptor::ThermodynamicEquations::EquationOfStateType>;
ImplementedMaterialSurfaceEquationOfState<typename Descriptor::ThermodynamicEquations::EquationOfStateType>;
template <typename Descriptor, typename PhysicalCore>
concept MaterialSurfaceRuntimeFor =
ImplementedMaterialSurfaceDescriptor<Descriptor> && requires {
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 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>;
};
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 =
@@ -778,14 +768,14 @@ export namespace mean_field::preconditioning {
fullEnthalpyDirection = enthalpyDirection;
m_operation->Mult(m_fullDirection, m_fullAction);
const auto fullActionView = m_operation->GetRootManifest().residualView(m_fullAction);
const auto fullActionView = m_operation->GetRootManifest().residualView(m_fullAction);
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 auto fullEnthalpyAction = fullActionView.block(utils::blocks::enthalpy_field.specific_term);
densityAction = fullDensityAction;
surfaceAction = fullSurfaceAction;
enthalpyAction = fullEnthalpyAction;
densityAction = fullDensityAction;
surfaceAction = fullSurfaceAction;
enthalpyAction = fullEnthalpyAction;
}
void ApplyEnthalpyToDensity(
@@ -1121,6 +1111,79 @@ export namespace mean_field::preconditioning {
std::uint64_t regularizedEntries{0};
};
namespace detail {
[[nodiscard]] inline DiagonalPreparationQuality regularizeMaterialSurfaceDiagonal(
mfem::Vector &diagonal,
const MaterialSurfaceDiagonalOptions options,
const MPI_Comm communicator
) {
const int localOptionsAreValid = std::isfinite(options.relativeFloor) && options.relativeFloor >= 0.0 &&
std::isfinite(options.absoluteFloor) && options.absoluteFloor > 0.0
? 1
: 0;
int globalOptionsAreValid = 0;
if (MPI_Allreduce(&localOptionsAreValid, &globalOptionsAreValid, 1, MPI_INT, MPI_MIN, communicator) !=
MPI_SUCCESS) {
throw std::runtime_error("Material-surface regularization could not validate its options.");
}
if (globalOptionsAreValid == 0) {
throw std::invalid_argument("Material-surface diagonal floors must be finite and nonnegative.");
}
double localMaximum = 0.0;
double localMinimum = std::numeric_limits<double>::infinity();
int localEntriesAreFinite = 1;
for (int index = 0; index < diagonal.Size(); ++index) {
if (!std::isfinite(diagonal(index))) {
localEntriesAreFinite = 0;
continue;
}
const double magnitude = std::abs(diagonal(index));
localMaximum = std::max(localMaximum, magnitude);
localMinimum = std::min(localMinimum, magnitude);
}
int globalEntriesAreFinite = 0;
if (MPI_Allreduce(&localEntriesAreFinite, &globalEntriesAreFinite, 1, MPI_INT, MPI_MIN, communicator) !=
MPI_SUCCESS) {
throw std::runtime_error("Material-surface regularization could not validate its diagonal.");
}
if (globalEntriesAreFinite == 0) {
throw std::invalid_argument("A material-surface diagonal contains a non-finite entry.");
}
double globalMaximum = 0.0;
double globalMinimum = 0.0;
const int maximumStatus =
MPI_Allreduce(&localMaximum, &globalMaximum, 1, MPI_DOUBLE, MPI_MAX, communicator);
const int minimumStatus =
MPI_Allreduce(&localMinimum, &globalMinimum, 1, MPI_DOUBLE, MPI_MIN, communicator);
if (maximumStatus != MPI_SUCCESS || minimumStatus != MPI_SUCCESS) {
throw std::runtime_error("Material-surface regularization could not reduce diagonal magnitudes.");
}
const double floor = std::max(options.absoluteFloor, options.relativeFloor * globalMaximum);
std::uint64_t localRegularized = 0;
for (int index = 0; index < diagonal.Size(); ++index) {
if (std::abs(diagonal(index)) < floor) {
diagonal(index) = std::copysign(floor, diagonal(index) == 0.0 ? 1.0 : diagonal(index));
++localRegularized;
}
}
std::uint64_t globalRegularized = 0;
if (MPI_Allreduce(&localRegularized, &globalRegularized, 1, MPI_UINT64_T, MPI_SUM, communicator) !=
MPI_SUCCESS) {
throw std::runtime_error("Material-surface regularization could not count regularized entries.");
}
return {
.minimumAbsoluteEntryBeforeRegularization = globalMinimum,
.maximumAbsoluteEntryBeforeRegularization = globalMaximum,
.appliedFloor = floor,
.regularizedEntries = globalRegularized
};
}
} // namespace detail
struct SurfaceRieszCalibrationReport final {
SurfaceRieszCalibrationTarget target{SurfaceRieszCalibrationTarget::none};
int probeCount{0};
@@ -1522,40 +1585,7 @@ export namespace mean_field::preconditioning {
const MaterialSurfaceDiagonalOptions options,
const MPI_Comm communicator
) {
if (!std::isfinite(options.relativeFloor) || options.relativeFloor < 0.0 ||
!std::isfinite(options.absoluteFloor) || options.absoluteFloor <= 0.0) {
throw std::invalid_argument("Material-surface diagonal floors must be finite and nonnegative.");
}
double localMaximum = 0.0;
double localMinimum = std::numeric_limits<double>::infinity();
for (int index = 0; index < diagonal.Size(); ++index) {
if (!std::isfinite(diagonal(index))) {
throw std::invalid_argument("A material-surface diagonal contains a non-finite entry.");
}
const double magnitude = std::abs(diagonal(index));
localMaximum = std::max(localMaximum, magnitude);
localMinimum = std::min(localMinimum, magnitude);
}
double globalMaximum = 0.0;
double globalMinimum = 0.0;
MPI_Allreduce(&localMaximum, &globalMaximum, 1, MPI_DOUBLE, MPI_MAX, communicator);
MPI_Allreduce(&localMinimum, &globalMinimum, 1, MPI_DOUBLE, MPI_MIN, communicator);
const double floor = std::max(options.absoluteFloor, options.relativeFloor * globalMaximum);
std::uint64_t localRegularized = 0;
for (int index = 0; index < diagonal.Size(); ++index) {
if (std::abs(diagonal(index)) < floor) {
diagonal(index) = std::copysign(floor, diagonal(index) == 0.0 ? 1.0 : diagonal(index));
++localRegularized;
}
}
std::uint64_t globalRegularized = 0;
MPI_Allreduce(&localRegularized, &globalRegularized, 1, MPI_UINT64_T, MPI_SUM, communicator);
return {
.minimumAbsoluteEntryBeforeRegularization = globalMinimum,
.maximumAbsoluteEntryBeforeRegularization = globalMaximum,
.appliedFloor = floor,
.regularizedEntries = globalRegularized
};
return detail::regularizeMaterialSurfaceDiagonal(diagonal, options, communicator);
}
Block m_block;
@@ -2051,40 +2081,7 @@ export namespace mean_field::preconditioning {
const MaterialSurfaceDiagonalOptions options,
const MPI_Comm communicator
) {
if (!std::isfinite(options.relativeFloor) || options.relativeFloor < 0.0 ||
!std::isfinite(options.absoluteFloor) || options.absoluteFloor <= 0.0) {
throw std::invalid_argument("Material-surface diagonal floors must be finite and nonnegative.");
}
double localMaximum = 0.0;
double localMinimum = std::numeric_limits<double>::infinity();
for (int index = 0; index < diagonal.Size(); ++index) {
if (!std::isfinite(diagonal(index))) {
throw std::invalid_argument("A material-surface diagonal contains a non-finite entry.");
}
const double magnitude = std::abs(diagonal(index));
localMaximum = std::max(localMaximum, magnitude);
localMinimum = std::min(localMinimum, magnitude);
}
double globalMaximum = 0.0;
double globalMinimum = 0.0;
MPI_Allreduce(&localMaximum, &globalMaximum, 1, MPI_DOUBLE, MPI_MAX, communicator);
MPI_Allreduce(&localMinimum, &globalMinimum, 1, MPI_DOUBLE, MPI_MIN, communicator);
const double floor = std::max(options.absoluteFloor, options.relativeFloor * globalMaximum);
std::uint64_t localRegularized = 0;
for (int index = 0; index < diagonal.Size(); ++index) {
if (std::abs(diagonal(index)) < floor) {
diagonal(index) = std::copysign(floor, diagonal(index) == 0.0 ? 1.0 : diagonal(index));
++localRegularized;
}
}
std::uint64_t globalRegularized = 0;
MPI_Allreduce(&localRegularized, &globalRegularized, 1, MPI_UINT64_T, MPI_SUM, communicator);
return {
.minimumAbsoluteEntryBeforeRegularization = globalMinimum,
.maximumAbsoluteEntryBeforeRegularization = globalMaximum,
.appliedFloor = floor,
.regularizedEntries = globalRegularized
};
return detail::regularizeMaterialSurfaceDiagonal(diagonal, options, communicator);
}
Block m_block;
@@ -2111,7 +2108,9 @@ export namespace mean_field::preconditioning {
template <
MaterialSurfaceDescriptor Descriptor,
MaterialSurfaceFactorizationPolicy Policy>
requires MaterialSurfaceRuntimeFor<Descriptor, operators::PreparedStellarEquilibriumOperator>
requires MaterialSurfaceRuntimeFor<
Descriptor,
operators::PreparedStellarEquilibriumOperator>
[[nodiscard]] auto prepare(
const operators::PreparedStellarEquilibriumOperator &operation,
MaterialSurfaceBlock<
@@ -2127,12 +2126,17 @@ export namespace mean_field::preconditioning {
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization,
MaterialSurfaceFactorizationPolicy Policy>
requires MaterialSurfacePreconditionerProblem<
equilibrium::StellarEquilibriumProblem<Model, Discretization>>
requires MaterialSurfacePreconditionerProblem<equilibrium::StellarEquilibriumProblem<
Model,
Discretization>>
[[nodiscard]] auto prepare(
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
const equilibrium::StellarEquilibriumProblem<
Model,
Discretization> &problem,
MaterialSurfaceBlock<
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<Model, Discretization>>,
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<
Model,
Discretization>>,
backend::Diagonal,
backend::Diagonal,
Policy> block
@@ -2144,7 +2148,9 @@ export namespace mean_field::preconditioning {
MaterialSurfaceDescriptor Descriptor,
MaterialSurfaceFactorizationPolicy Policy,
backend::ApplicationMode Mode>
requires MaterialSurfaceRuntimeFor<Descriptor, operators::PreparedStellarEquilibriumOperator>
requires MaterialSurfaceRuntimeFor<
Descriptor,
operators::PreparedStellarEquilibriumOperator>
[[nodiscard]] auto prepare(
const operators::PreparedStellarEquilibriumOperator &operation,
MaterialSurfaceBlock<
@@ -2162,12 +2168,17 @@ export namespace mean_field::preconditioning {
equilibrium::StellarDiscretizationType Discretization,
MaterialSurfaceFactorizationPolicy Policy,
backend::ApplicationMode Mode>
requires MaterialSurfacePreconditionerProblem<
equilibrium::StellarEquilibriumProblem<Model, Discretization>>
requires MaterialSurfacePreconditionerProblem<equilibrium::StellarEquilibriumProblem<
Model,
Discretization>>
[[nodiscard]] auto prepare(
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
const equilibrium::StellarEquilibriumProblem<
Model,
Discretization> &problem,
MaterialSurfaceBlock<
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<Model, Discretization>>,
MaterialSurfaceDescriptorFor<equilibrium::StellarEquilibriumProblem<
Model,
Discretization>>,
backend::Diagonal,
backend::HypreBoomerAMG<Mode>,
Policy,

View File

@@ -9,3 +9,4 @@ export import :preconditioning.stellar_equilibrium;
export import :preconditioning.stellar_structure;
export import :preconditioning.specification_border;
export import :preconditioning.equilibrium_coordinates;
export import :preconditioning.stellar_recipe;

View File

@@ -63,7 +63,7 @@ export namespace mean_field::preconditioning {
.geometry = prepared.geometry != current.geometry,
.equationOfState = prepared.equationOfStateIdentity != current.equationOfStateIdentity,
.linearization = prepared.linearization != current.linearization ||
prepared.preparedOperatorGeneration != current.preparedOperatorGeneration
prepared.preparedOperatorGeneration != current.preparedOperatorGeneration
};
}
@@ -97,9 +97,7 @@ export namespace mean_field::preconditioning {
static constexpr bool registered = false;
};
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization>
template <equilibrium::StellarEquilibriumModel Model, equilibrium::StellarDiscretizationType Discretization>
struct StellarEquilibriumProblemTraits<equilibrium::StellarEquilibriumProblem<Model, Discretization>> {
using Problem = equilibrium::StellarEquilibriumProblem<Model, Discretization>;
using Form = typename Problem::FormType;
@@ -131,10 +129,9 @@ export namespace mean_field::preconditioning {
[[nodiscard]] static StellarPreconditionerLifecycleSnapshot Snapshot(const Problem &problem) {
const operators::StellarEquilibriumDependencies &dependencies = problem.GetLinearizationDependencies();
return {
.discretization = dependencies.discretization,
.geometry = problem.GetGeometryDependency(),
.equationOfStateIdentity =
std::addressof(problem.GetStellarModel().equationOfState()),
.discretization = dependencies.discretization,
.geometry = problem.GetGeometryDependency(),
.equationOfStateIdentity = std::addressof(problem.GetStellarModel().equationOfState()),
.linearization = dependencies,
.preparedOperatorGeneration = problem.GetPreparationGeneration()
};
@@ -145,26 +142,20 @@ export namespace mean_field::preconditioning {
concept StellarPreconditionerProblem = StellarEquilibriumProblemTraits<std::remove_cvref_t<Candidate>>::registered;
namespace detail {
template <typename Block>
struct IsGeneratedStellarValueBlock : std::false_type { };
template <typename Block> struct IsGeneratedStellarValueBlock : std::false_type { };
template <typename Generated>
struct IsGeneratedStellarValueBlock<utils::blocks::generated_value_block<Generated>>
: std::true_type { };
struct IsGeneratedStellarValueBlock<utils::blocks::generated_value_block<Generated>> : std::true_type { };
template <typename Block>
struct IsGeneratedStellarResidualBlock : std::false_type { };
template <typename Block> struct IsGeneratedStellarResidualBlock : std::false_type { };
template <typename Generated>
struct IsGeneratedStellarResidualBlock<utils::blocks::generated_residual_block<Generated>>
: std::true_type { };
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;
!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
@@ -172,8 +163,7 @@ export namespace mean_field::preconditioning {
* be accompanied by an explicit preconditioner decision. Generated-
* border terms remain the responsibility of specification-border
* machinery. */
template <typename PhysicalCore, typename Specification>
struct StellarStructureBackendHandledCouplings {
template <typename PhysicalCore, typename Specification> struct StellarStructureBackendHandledCouplings {
using Type = utils::blocks::type_list<>;
};
@@ -213,17 +203,12 @@ export namespace mean_field::preconditioning {
struct StellarStructureBackendHandledCouplings<
operators::PreparedStellarEquilibriumOperator,
models::FixedCentralDensity> {
using Type = utils::blocks::type_list<
operators::StellarEquilibriumJacobianCoupling<
utils::blocks::enthalpy::specific::residual,
utils::blocks::enthalpy::specific::value>>;
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>
template <typename Coupling, typename Model, typename PhysicalCore, typename ModelSpecifications>
struct EveryCouplingContributionHandled;
template <
@@ -235,30 +220,22 @@ export namespace mean_field::preconditioning {
Coupling,
Model,
PhysicalCore,
models::detail::SpecificationSetStorage<Specifications...>> final {
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> &&
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>;
typename StellarStructureBackendHandledCouplings<PhysicalCore, Specification>::Type>) ||
operators::stellarEquilibriumSpecificationCouplingIsStructuralZero<Specification, Model, Coupling>;
public:
static constexpr bool value =
(handled<Specifications> && ...);
static constexpr bool value = (handled<Specifications> && ...);
};
template <
@@ -269,11 +246,7 @@ export namespace mean_field::preconditioning {
typename Unsupported>
struct CollectUnsupportedStellarStructureCouplings;
template <
typename Model,
typename PhysicalCore,
typename ModelSpecifications,
typename Unsupported>
template <typename Model, typename PhysicalCore, typename ModelSpecifications, typename Unsupported>
struct CollectUnsupportedStellarStructureCouplings<
utils::blocks::type_list<>,
Model,
@@ -299,11 +272,7 @@ export namespace mean_field::preconditioning {
private:
static constexpr bool supported =
!isPurePhysicalStellarCoupling<Head> ||
EveryCouplingContributionHandled<
Head,
Model,
PhysicalCore,
ModelSpecifications>::value;
EveryCouplingContributionHandled<Head, Model, PhysicalCore, ModelSpecifications>::value;
using Next = std::conditional_t<
supported,
utils::blocks::type_list<Unsupported...>,
@@ -318,42 +287,36 @@ export namespace mean_field::preconditioning {
Next>::Type;
};
template <typename Candidate, typename = void>
struct DefaultStellarStructurePhysicalTopologyAudit {
using ContributionCouplings = utils::blocks::type_list<>;
using UnsupportedCouplings = utils::blocks::type_list<>;
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>>)
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>>>> {
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>>;
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;
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;
};
@@ -369,13 +332,11 @@ export namespace mean_field::preconditioning {
* detection-safe and therefore suitable for constraining factories. */
template <typename Candidate>
struct DefaultStellarStructurePhysicalTopologySupport
: detail::DefaultStellarStructurePhysicalTopologyAudit<
std::remove_cvref_t<Candidate>> { };
: detail::DefaultStellarStructurePhysicalTopologyAudit<std::remove_cvref_t<Candidate>> { };
template <typename Candidate>
inline constexpr bool defaultStellarStructurePhysicalTopologySupported =
DefaultStellarStructurePhysicalTopologySupport<
std::remove_cvref_t<Candidate>>::supported;
DefaultStellarStructurePhysicalTopologySupport<std::remove_cvref_t<Candidate>>::supported;
template <typename Candidate>
concept DefaultStellarStructurePhysicalTopologySupportedFor =
@@ -419,9 +380,8 @@ export namespace mean_field::preconditioning {
template <typename Form> struct IdentityPlanForForm;
template <typename... Values, typename... Residuals>
struct IdentityPlanForForm<utils::blocks::block_form<
utils::blocks::type_list<Values...>,
utils::blocks::type_list<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>...>;

View File

@@ -0,0 +1,83 @@
module;
#include <concepts>
#include <type_traits>
#include <utility>
#include <mfem.hpp>
export module mean_field:preconditioning.stellar_recipe;
export import :preconditioning.equilibrium_coordinates;
export namespace mean_field::preconditioning {
/*
* A stellar-preconditioner prescription is an unbound, owning value. It
* may therefore be created before a problem exists and safely moved into
* the eventual user-owned solve context. A prepared inverse is deliberately a
* separate, problem-bound object with a stable address.
*/
struct StellarPreconditionerPrescriptionTag { };
template <typename Candidate>
concept StellarPreconditionerPrescription =
std::derived_from<std::remove_cvref_t<Candidate>, StellarPreconditionerPrescriptionTag> &&
std::move_constructible<std::remove_cvref_t<Candidate>>;
struct DefaultStellarPreconditioner final : StellarPreconditionerPrescriptionTag { };
/*
* This overload is the user-facing, problem-independent factory. The
* existing makePreconditioner(problem) overload remains the low-level
* factory for the typed, unprepared block assembled below.
*/
[[nodiscard]] constexpr DefaultStellarPreconditioner makePreconditioner() noexcept {
return {};
}
template <typename Candidate, typename Problem>
concept PreparedStellarInverseFor =
equilibrium::DiscretizedStellarEquilibriumProblem<std::remove_cvref_t<Problem>> &&
std::derived_from<std::remove_cvref_t<Candidate>, mfem::Solver> &&
std::destructible<std::remove_cvref_t<Candidate>> &&
requires(std::remove_cvref_t<Candidate> &prepared, const std::remove_cvref_t<Candidate> &constantPrepared) {
{ constantPrepared.GetProblem() } -> std::same_as<const std::remove_cvref_t<Problem> &>;
{ constantPrepared.IsCurrent() } -> std::same_as<bool>;
prepared.Refresh();
};
/*
* Built-in preparation is intentionally policy-first. The same spelling
* can be supplied beside a third-party prescription and found by ADL,
* without adding that prescription to a central registry or switch.
* Preparation requires an already-prepared problem because the current
* physical inverse assembles state-dependent numerical data.
*/
template <DefaultStellarPreconditionerAvailableFor Problem>
[[nodiscard]] auto prepareStellarPreconditioner(
DefaultStellarPreconditioner,
const Problem &problem
) {
return preconditioning::prepare(problem, preconditioning::makePreconditioner(problem));
}
template <typename Prescription, typename Problem>
concept StellarPreconditionerRuntimeAvailableFor =
StellarPreconditionerPrescription<Prescription> &&
equilibrium::DiscretizedStellarEquilibriumProblem<std::remove_cvref_t<Problem>> &&
requires(std::remove_cvref_t<Prescription> prescription, const std::remove_cvref_t<Problem> &problem) {
requires std::same_as<
decltype(prepareStellarPreconditioner(std::move(prescription), problem)),
std::remove_cvref_t<decltype(prepareStellarPreconditioner(std::move(prescription), problem))>>;
{
prepareStellarPreconditioner(std::move(prescription), problem)
} -> PreparedStellarInverseFor<std::remove_cvref_t<Problem>>;
};
template <StellarPreconditionerPrescription Prescription, typename Problem>
requires StellarPreconditionerRuntimeAvailableFor<Prescription, Problem>
using PreparedStellarInverseType = std::remove_cvref_t<decltype(prepareStellarPreconditioner(
std::declval<std::remove_cvref_t<Prescription> &&>(),
std::declval<const std::remove_cvref_t<Problem> &>()
))>;
} // namespace mean_field::preconditioning

View File

@@ -634,13 +634,11 @@ export namespace mean_field::preconditioning {
* Add future cores here only together with matching cross-coupling and
* preparation implementations.
*/
template <typename PhysicalCore>
struct StellarStructureExecutableRuntime {
template <typename PhysicalCore> struct StellarStructureExecutableRuntime {
static constexpr bool available = false;
};
template <>
struct StellarStructureExecutableRuntime<operators::PreparedStellarEquilibriumOperator> {
template <> struct StellarStructureExecutableRuntime<operators::PreparedStellarEquilibriumOperator> {
static constexpr bool available = true;
};
@@ -654,14 +652,12 @@ export namespace mean_field::preconditioning {
template <typename Descriptor, typename PhysicalCore>
concept StellarStructureRuntimeFor =
MaterialSurfaceRuntimeFor<Descriptor, PhysicalCore> &&
ExecutableStellarStructureRuntimeFor<PhysicalCore>;
MaterialSurfaceRuntimeFor<Descriptor, PhysicalCore> && ExecutableStellarStructureRuntimeFor<PhysicalCore>;
template <typename Candidate>
concept StellarStructurePreconditionerProblem =
equilibrium::DiscretizedStellarEquilibriumProblem<Candidate> &&
DefaultStellarStructurePhysicalTopologySupportedFor<
typename std::remove_cvref_t<Candidate>::ModelType> &&
DefaultStellarStructurePhysicalTopologySupportedFor<typename std::remove_cvref_t<Candidate>::ModelType> &&
requires {
requires StellarStructureRuntimeFor<
MaterialSurfaceDescriptorFor<std::remove_cvref_t<Candidate>>,
@@ -688,8 +684,7 @@ export namespace mean_field::preconditioning {
preconditioning::prepare(problem, std::move(materialComponent));
preconditioning::prepare(
problem.GetPhysicalOperator().GetHydrostaticOperator().GetFEM(),
problem.GetPhysicalOperator().GetGravityContext().GetGeometryContext(),
std::move(gravityComponent)
problem.GetPhysicalOperator().GetGravityContext().GetGeometryContext(), std::move(gravityComponent)
);
StellarStructureCrossJacobianOperator{problem.GetPhysicalOperator()};
};
@@ -873,19 +868,30 @@ export namespace mean_field::preconditioning {
GravityFactorizationPolicy GravityPolicy,
StellarStructureFactorizationPolicy StructurePolicy>
requires StellarStructurePreparableFor<
equilibrium::StellarEquilibriumProblem<Model, Discretization>,
equilibrium::StellarEquilibriumProblem<
Model,
Discretization>,
MaterialComponent,
GravityFieldBlock<GravityMassBackend, backend::HypreBoomerAMG<Mode>, GravityPolicy>>
GravityFieldBlock<
GravityMassBackend,
backend::HypreBoomerAMG<Mode>,
GravityPolicy>>
[[nodiscard]] auto prepare(
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
const equilibrium::StellarEquilibriumProblem<
Model,
Discretization> &problem,
StellarStructureBlock<
MaterialComponent,
GravityFieldBlock<
GravityMassBackend,
backend::HypreBoomerAMG<Mode>,
GravityPolicy>,
typename equilibrium::StellarEquilibriumProblem<Model, Discretization>::FormType,
typename equilibrium::StellarEquilibriumProblem<Model, Discretization>::JacobianFormType,
typename equilibrium::StellarEquilibriumProblem<
Model,
Discretization>::FormType,
typename equilibrium::StellarEquilibriumProblem<
Model,
Discretization>::JacobianFormType,
StructurePolicy> structure
) {
return PreparedStellarStructureBlock<