84 lines
3.8 KiB
C++
84 lines
3.8 KiB
C++
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
|