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

@@ -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