Add bounded fully coupled second-order trial correction and frozen screen

This commit is contained in:
2026-09-18 09:41:00 -04:00
parent 2944dd5019
commit 0d87b8b919
14 changed files with 2442 additions and 35 deletions

View File

@@ -21,6 +21,7 @@ namespace stellar_numerical_strategy_test {
struct UnregisteredEnthalpy { };
struct UnregisteredGravity { };
struct UnregisteredTrial { };
template <typename Enthalpy, typename Gravity>
concept MakesNumerics = requires { typename nonlinear::NewtonNumerics<Enthalpy, Gravity>; };
static_assert(!MakesNumerics<UnregisteredEnthalpy, nonlinear::MonolithicGravity>);
@@ -32,6 +33,21 @@ namespace stellar_numerical_strategy_test {
nonlinear::NormalizedResidualMetric{})), nonlinear::Newton<>>);
static_assert(MakesNumerics<nonlinear::PolynomialEnthalpy, nonlinear::GravityCurvatureCorrection>);
static_assert(MakesNumerics<nonlinear::PolynomialEnthalpy, nonlinear::EliminatedGravity>);
template <typename Enthalpy, typename Gravity, typename Trial>
concept MakesTrialNumerics = requires { typename nonlinear::NewtonNumerics<Enthalpy, Gravity, Trial>; };
static_assert(std::same_as<typename nonlinear::NewtonNumerics<>::TrialType, nonlinear::UncorrectedTrial>);
static_assert(std::same_as<decltype(nonlinear::NewtonNumerics{nonlinear::SampledEnthalpy{},
nonlinear::MonolithicGravity{}}), nonlinear::NewtonNumerics<>>);
static_assert(MakesTrialNumerics<nonlinear::SampledEnthalpy, nonlinear::MonolithicGravity,
nonlinear::CoupledCurvatureCorrection>);
static_assert(MakesTrialNumerics<nonlinear::PolynomialEnthalpy, nonlinear::GravityCurvatureCorrection,
nonlinear::CoupledCurvatureCorrection>);
static_assert(!MakesTrialNumerics<nonlinear::SampledEnthalpy, nonlinear::EliminatedGravity,
nonlinear::CoupledCurvatureCorrection>);
static_assert(!MakesTrialNumerics<nonlinear::PolynomialEnthalpy, nonlinear::EliminatedGravity,
nonlinear::CoupledCurvatureCorrection>);
static_assert(!MakesTrialNumerics<nonlinear::SampledEnthalpy, nonlinear::MonolithicGravity, UnregisteredTrial>);
[[nodiscard]] double matchingCentralDensity() {
return std::numbers::pi_v<double> * utils::MASS / (4.0 * utils::RADIUS * utils::RADIUS * utils::RADIUS);
@@ -284,4 +300,47 @@ TEST_CASE("Polynomial admissibility is invoked by each production gravity strate
check(nonlinear::EliminatedGravity{permissiveGravity()});
REQUIRE(context.isReady());
checkPreserved(original, snapshot(context));
{
const auto report = evaluate(context, nonlinear::NewtonNumerics{polynomial,
nonlinear::MonolithicGravity{}, nonlinear::CoupledCurvatureCorrection{}});
CHECK_FALSE(report.converged());
CHECK(report.diagnostics().numericalStrategies.polynomialChecks > 0);
CHECK(report.diagnostics().acceptedNonlinearIterations == 0);
CHECK(report.lastAcceptedCheckpointView().valid());
}
REQUIRE(context.isReady());
checkPreserved(original, snapshot(context));
}
TEST_CASE("Coupled trial selection keeps the outer linear report and rejected stellar checkpoint",
"[solver][numerical_strategies][coupled_trial_correction][rollback]") {
using namespace stellar_numerical_strategy_test;
auto context = makeContext<false>();
const auto original = snapshot(context);
const auto check = [&](auto gravity) {
const nonlinear::CoupledCurvatureCorrection correction{};
const auto report = evaluate(context, nonlinear::NewtonNumerics{
nonlinear::SampledEnthalpy{}, gravity, correction});
CHECK_FALSE(report.converged());
CHECK(report.diagnostics().acceptedNonlinearIterations == 0);
REQUIRE(report.diagnostics().lastLinearSolve.has_value());
const auto &outer = *report.diagnostics().lastLinearSolve;
CHECK(outer.iterations == 0);
CHECK(outer.control.absoluteTolerance == 1.e100);
CHECK(report.diagnostics().numericalStrategies.lastLinearReportSpace == nonlinear::LinearReportSpace::full_system);
const auto &auxiliary = report.diagnostics().numericalStrategies.coupledTrial;
REQUIRE(auxiliary.currentSolve.has_value());
CHECK(auxiliary.attempts == 1);
CHECK(auxiliary.kept == 0);
CHECK(auxiliary.fallbacks == 1);
CHECK(auxiliary.currentSolve->linearSolve.control.relativeTolerance == correction.correction.control.relativeTolerance);
CHECK(auxiliary.currentSolve->linearSolve.control.absoluteTolerance == correction.correction.control.absoluteTolerance);
CHECK(report.lastAcceptedCheckpointView().valid());
};
check(nonlinear::MonolithicGravity{});
REQUIRE(context.isReady());
checkPreserved(original, snapshot(context));
check(nonlinear::GravityCurvatureCorrection{permissiveGravity()});
REQUIRE(context.isReady());
checkPreserved(original, snapshot(context));
}