Add checked harmonic snapshot continuation and matched linear trial diagnostics

This commit is contained in:
2026-09-19 13:43:49 -04:00
parent 77130fa603
commit 53faac1cd2
8 changed files with 582 additions and 7 deletions

View File

@@ -14,6 +14,7 @@
import mean_field;
import test_helpers;
#include "../../experiments/continuation_snapshot.hpp"
namespace stellar_numerical_strategy_test {
using namespace mean_field;
@@ -194,6 +195,54 @@ namespace stellar_numerical_strategy_test {
}
} // namespace stellar_numerical_strategy_test
TEST_CASE("Continuation snapshot transfers named coordinates and explicitly handles the central border",
"[solver][continuation_initial_state]") {
CHECK(experiment::continuation::RunSnapshotCoordinateSelfChecks() == 11);
}
TEST_CASE("Explicit physical restart prepares a new initial guess and rolls back invalid input",
"[solver][continuation_initial_state]") {
using namespace stellar_numerical_strategy_test;
auto context = makeContext<false>();
using Diagnostics = solver::detail::StellarEquilibriumContextDiagnostics;
const auto original = snapshot(context);
mfem::Vector changed(original.physical);
int enthalpyOffset = -1;
Diagnostics::WithState(context, [&](auto &state, const auto &) {
for (const auto &block : state.Problem().GetManifest().valueBlocks()) {
if (block.stableId == "density")
for (int i = block.offset; i < block.offset + block.size; ++i) changed(i) *= 1.001;
if (block.stableId == "specific_enthalpy") enthalpyOffset = block.offset;
}
});
REQUIRE(relativeDifference(original.physical, changed) > 0.);
REQUIRE_NOTHROW(Diagnostics::InitializePhysicalState(context, changed));
const auto installed = snapshot(context);
CHECK(relativeDifference(changed, installed.physical) < 1e-14);
CHECK(relativeDifference(original.residual, installed.residual) > 1e-12);
Diagnostics::WithState(context, [&](auto &state, const auto &) {
CHECK(state.normalizedCorrection.Norml2() == 0.);
CHECK(state.physicalInverse->IsCurrent());
CHECK(state.normalizedInverse->IsCurrent());
});
mfem::Vector wrongSize(changed.Size() - 1);
CHECK_THROWS_AS(Diagnostics::InitializePhysicalState(context, wrongSize), std::invalid_argument);
mfem::Vector nonfinite(changed);
nonfinite(0) = std::numeric_limits<double>::quiet_NaN();
CHECK_THROWS_AS(Diagnostics::InitializePhysicalState(context, nonfinite), std::invalid_argument);
REQUIRE(enthalpyOffset >= 0);
mfem::Vector inadmissible(changed);
inadmissible(enthalpyOffset) = -1e10;
CHECK_THROWS_AS(Diagnostics::InitializePhysicalState(context, inadmissible), std::invalid_argument);
checkPreserved(installed, snapshot(context));
{
auto active = solver::make(context, nonlinear::Newton(oneAttempt()));
CHECK_THROWS_AS(Diagnostics::InitializePhysicalState(context, changed), std::logic_error);
}
REQUIRE_NOTHROW(Diagnostics::InitializePhysicalState(context, original.physical));
checkPreserved(original, snapshot(context));
}
TEST_CASE("Typed numerical policies preserve the existing Newton configuration", "[solver][numerical_strategies]") {
using namespace stellar_numerical_strategy_test;
const nonlinear::Newton original;