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

@@ -1,8 +1,8 @@
module;
#include <cmath>
#include <cstddef>
#include <concepts>
#include <cstddef>
#include <stdexcept>
#include <type_traits>
#include <utility>
@@ -59,13 +59,14 @@ export namespace mean_field::seed {
/* An explicit opt-in for a specification that leaves a radial seed unchanged. */
struct NoStateChange {
static constexpr bool registered = true;
static constexpr bool providesRadialMass = false;
static constexpr bool registered = true;
static constexpr bool providesRadialMass = false;
template <typename Model>
static constexpr bool supports = true;
template <typename Model> static constexpr bool supports = true;
template <typename Specification, typename Model>
template <
typename Specification,
typename Model>
static void validate(
const Specification &,
const Model &,
@@ -74,7 +75,9 @@ export namespace mean_field::seed {
) noexcept {
}
template <typename Specification, typename Model>
template <
typename Specification,
typename Model>
static void initialize(
const Specification &,
const Model &,
@@ -115,19 +118,17 @@ export namespace mean_field::seed {
}
struct UnavailableRadialProjectionPhysics final {
static constexpr bool registered = false;
static constexpr bool providesRadialMass = false;
static constexpr bool registered = false;
static constexpr bool providesRadialMass = false;
template <typename Model>
static constexpr bool supports = false;
template <typename Model> static constexpr bool supports = false;
};
struct FixedTotalMassRadialProjectionPhysics final {
static constexpr bool registered = true;
static constexpr bool providesRadialMass = true;
static constexpr bool registered = true;
static constexpr bool providesRadialMass = true;
template <typename Model>
static constexpr bool supports = true;
template <typename Model> static constexpr bool supports = true;
[[nodiscard]] static dimensions::MassValue targetMass(const models::FixedTotalMass &specification) {
return specification.targetMass();
@@ -164,10 +165,7 @@ export namespace mean_field::seed {
static constexpr bool providesRadialMass = false;
template <typename Model>
static constexpr bool supports = requires(
const Model &model,
const surface::Isobaric &condition
) {
static constexpr bool supports = requires(const Model &model, const surface::Isobaric &condition) {
{
eos::evaluate<dimensions::quantity::SpecificEnthalpy>(
model.equationOfState(), condition.targetPressure()
@@ -213,11 +211,10 @@ export namespace mean_field::seed {
};
struct FixedCentralDensityRadialProjectionPhysics final {
static constexpr bool registered = true;
static constexpr bool providesRadialMass = false;
static constexpr bool registered = true;
static constexpr bool providesRadialMass = false;
template <typename Model>
static constexpr bool supports = true;
template <typename Model> static constexpr bool supports = true;
template <typename Model>
static void validate(
@@ -246,11 +243,10 @@ export namespace mean_field::seed {
};
struct FixedAngularMomentumRadialProjectionPhysics final {
static constexpr bool registered = true;
static constexpr bool providesRadialMass = false;
static constexpr bool registered = true;
static constexpr bool providesRadialMass = false;
template <typename Model>
static constexpr bool supports = true;
template <typename Model> static constexpr bool supports = true;
template <typename Model>
static void validate(
@@ -316,12 +312,12 @@ export namespace mean_field::seed {
};
template <typename Candidate> struct UnwrapRadialProjectionPhysics {
using Type = UnavailableRadialProjectionPhysics;
using Type = UnavailableRadialProjectionPhysics;
static constexpr bool valid = false;
};
template <typename Physics> struct UnwrapRadialProjectionPhysics<projection::Use<Physics>> {
using Type = Physics;
using Type = Physics;
static constexpr bool valid = true;
};
@@ -358,7 +354,9 @@ export namespace mean_field::seed {
}
}
template <typename Specification, typename Model>
template <
typename Specification,
typename Model>
[[nodiscard]] consteval bool radialProjectionPhysicsIsComplete() {
using Physics = typename SelectRadialProjectionPhysics<Specification>::Type;
if constexpr (!radialProjectionPhysicsRegistered<Physics>()) {
@@ -370,12 +368,9 @@ export namespace mean_field::seed {
} else if constexpr (!static_cast<bool>(Physics::template supports<Model>)) {
return false;
} else if constexpr (!requires(
const Specification &specification,
const Model &model,
const RadialProfile &profile,
const StellarEquilibriumProjectionOptions &options,
const RadialProjectionScales &scales,
RadialProjectionState &state,
const Specification &specification, const Model &model,
const RadialProfile &profile, const StellarEquilibriumProjectionOptions &options,
const RadialProjectionScales &scales, RadialProjectionState &state,
mfem::Vector coordinate
) {
Physics::validate(specification, model, profile, options);
@@ -417,21 +412,24 @@ export namespace mean_field::seed {
static constexpr std::size_t radialMassProviderCount =
(std::size_t{0} + ... +
(radialProjectionPhysicsProvidesMass<
typename SelectRadialProjectionPhysics<Specifications>::Type>()
(radialProjectionPhysicsProvidesMass<typename SelectRadialProjectionPhysics<Specifications>::Type>()
? std::size_t{1}
: std::size_t{0}));
static constexpr bool complete = radialMassProviderCount == 1 &&
(radialProjectionPhysicsIsComplete<Specifications, ModelType>() && ...);
static constexpr bool complete =
radialMassProviderCount == 1 && (radialProjectionPhysicsIsComplete<Specifications, ModelType>() && ...);
[[nodiscard]] static dimensions::MassValue targetMass(const ModelType &model) requires complete {
[[nodiscard]] static dimensions::MassValue targetMass(const ModelType &model)
requires complete
{
dimensions::MassValue result{0.0};
([&] {
using Physics = typename SelectRadialProjectionPhysics<Specifications>::Type;
if constexpr (radialProjectionPhysicsProvidesMass<Physics>()) {
result = Physics::targetMass(model.template specification<Specifications>());
}
}(), ...);
(
[&] {
using Physics = typename SelectRadialProjectionPhysics<Specifications>::Type;
if constexpr (radialProjectionPhysicsProvidesMass<Physics>()) {
result = Physics::targetMass(model.template specification<Specifications>());
}
}(),
...);
return result;
}
@@ -439,11 +437,15 @@ export namespace mean_field::seed {
const ModelType &model,
const RadialProfile &profile,
const StellarEquilibriumProjectionOptions &options
) requires complete {
([&] {
using Physics = typename SelectRadialProjectionPhysics<Specifications>::Type;
Physics::validate(model.template specification<Specifications>(), model, profile, options);
}(), ...);
)
requires complete
{
(
[&] {
using Physics = typename SelectRadialProjectionPhysics<Specifications>::Type;
Physics::validate(model.template specification<Specifications>(), model, profile, options);
}(),
...);
}
template <typename StateView>
@@ -452,27 +454,32 @@ export namespace mean_field::seed {
const RadialProjectionScales &scales,
RadialProjectionState &state,
const StateView &stateView
) requires complete {
([&] {
using Contribution = models::SpecificationContribution<Specifications>;
using Physics = typename SelectRadialProjectionPhysics<Specifications>::Type;
if constexpr (Contribution::generatedValueArity == 0) {
Physics::initialize(
model.template specification<Specifications>(), model, scales, state, mfem::Vector{}
);
} else {
static_assert(
Contribution::generatedValueArity == 1,
"Radial projection currently requires each specification contribution to generate at "
"most one scalar coordinate."
);
using Term = RadialProjectionCoordinateTerm<Specifications, Contribution::generatedStateKind>;
Physics::initialize(
model.template specification<Specifications>(), model, scales, state,
stateView.block(Term{})
);
}
}(), ...);
)
requires complete
{
(
[&] {
using Contribution = models::SpecificationContribution<Specifications>;
using Physics = typename SelectRadialProjectionPhysics<Specifications>::Type;
if constexpr (Contribution::generatedValueArity == 0) {
Physics::initialize(
model.template specification<Specifications>(), model, scales, state, mfem::Vector{}
);
} else {
static_assert(
Contribution::generatedValueArity == 1,
"Radial projection currently requires each specification contribution to generate at "
"most one scalar coordinate."
);
using Term =
RadialProjectionCoordinateTerm<Specifications, Contribution::generatedStateKind>;
Physics::initialize(
model.template specification<Specifications>(), model, scales, state,
stateView.block(Term{})
);
}
}(),
...);
}
};
@@ -494,21 +501,25 @@ export namespace mean_field::seed {
concept RadialProfileProjectableModel =
model::StellarModelType<Candidate> && radialProjectionIsCompilable<std::remove_cvref_t<Candidate>>;
template <equilibrium::StellarEquilibriumModel Model, equilibrium::StellarDiscretizationType Discretization>
template <
equilibrium::StellarEquilibriumModel Model,
equilibrium::StellarDiscretizationType Discretization>
requires RadialProfileProjectableModel<Model>
[[nodiscard]] ProjectedEquilibriumState<Model> projectRadialProfile(
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
equilibrium::StellarEquilibriumProblem<
Model,
Discretization> &problem,
const RadialProfile &profile,
const StellarEquilibriumProjectionOptions &options = {}
) {
using Projection = detail::CompileRadialProjection<
std::remove_cvref_t<Model>,
typename std::remove_cvref_t<Model>::SpecificationTypes>;
std::remove_cvref_t<Model>, typename std::remove_cvref_t<Model>::SpecificationTypes>;
const auto &stellarModel = problem.GetStellarModel();
Projection::validate(stellarModel, profile, options);
const dimensions::MassValue targetMass = Projection::targetMass(stellarModel);
const dimensions::MassValue targetMass = Projection::targetMass(stellarModel);
const detail::ProjectedRadialFields fields = detail::projectRadialFields(
problem.GetDiscretization().finiteElementModel(), profile, targetMass, options
equilibrium::detail::StellarEquilibriumProblemFactory::MutableFiniteElementModelForProjection(problem),
profile, targetMass, options
);
mfem::Vector values(problem.StateSize());
@@ -563,11 +574,15 @@ export namespace mean_field::seed {
equilibrium::StellarDiscretizationType Discretization,
typename Strategy>
requires RadialSeedStrategyFor<
Strategy,
typename equilibrium::StellarEquilibriumProblem<Model, Discretization>::ModelType> &&
Strategy,
typename equilibrium::StellarEquilibriumProblem<
Model,
Discretization>::ModelType> &&
RadialProfileProjectableModel<Model>
[[nodiscard]] ProjectedEquilibriumState<Model> makeProjectedEquilibriumState(
const equilibrium::StellarEquilibriumProblem<Model, Discretization> &problem,
equilibrium::StellarEquilibriumProblem<
Model,
Discretization> &problem,
const Strategy &strategy,
const StellarEquilibriumProjectionOptions &options = {}
) {