feat(newton): first newton solver implementation
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>...>;
|
||||
|
||||
|
||||
83
libmeanfield/interface/preconditioning/stellar_recipe.cppm
Normal file
83
libmeanfield/interface/preconditioning/stellar_recipe.cppm
Normal 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
|
||||
@@ -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<
|
||||
|
||||
Reference in New Issue
Block a user