Clear unavailable gravity measurements before each attempt

This commit is contained in:
2026-09-17 11:01:13 -04:00
parent 7e1ab69fcd
commit a2871e11e2
4 changed files with 77 additions and 7 deletions

View File

@@ -81,9 +81,17 @@ export namespace mean_field::solver::nonlinear {
std::uint64_t gravityPreparedFailures{0};
bool compactGravityOperator{false};
bool compactGravityInverse{false};
// Coordinates of the evaluation's lastLinearSolve report. A later
// feasibility relift or trial solve has its own auxiliary diagnostics
// and does not replace that report or relabel its stored norms.
LinearReportSpace lastLinearReportSpace{LinearReportSpace::full_system};
double gravitySolveSeconds{0.0};
// Last completed auxiliary solve; a later failure before Solve leaves
// this value and the cumulative counters unchanged.
double lastGravityTrueResidual{0.0};
// Current gravity attempt: NaN until that attempt measures the value.
// Candidates rejected before invoking gravity leave its prior attempt
// untouched because no auxiliary work was attempted.
double lastGravityCorrectionNorm{0.0};
double lastGravityPreparedDefect{0.0};
double lastGravityAffineDisagreement{0.0};

View File

@@ -140,6 +140,17 @@ namespace mean_field::solver::detail {
}
protected:
void BeginGravityAttempt() noexcept {
trialSolveSucceeded = true;
// These measurements belong to this attempt. An early preparation
// or inner-solve failure must not publish the preceding trial's
// successful assessment. The last completed solve and cumulative
// counters deliberately retain their separate lifetime.
lastCorrectionNorm = lastPreparedDefect = lastAffineDisagreement =
lastArithmeticAllowance = lastPreparedTargetThreshold =
std::numeric_limits<double>::quiet_NaN();
}
void Refresh(State &state) {
// Preparing a trial invalidates both normalized and physical
// inverses. Refreshing only the restricted wrapper would hide this.
@@ -157,8 +168,6 @@ namespace mean_field::solver::detail {
}
auto ApplyCorrection(State &state) {
lastPreparedDefect = lastAffineDisagreement = lastArithmeticAllowance =
lastPreparedTargetThreshold = std::numeric_limits<double>::quiet_NaN();
const auto &partition = subsystem.GetPartition();
partition.InjectGravityValues(gravityCorrection, fullCorrection);
subsystem.GetOperator().Mult(gravityCorrection, gravityAction);
@@ -249,7 +258,7 @@ namespace mean_field::solver::detail {
return true;
}
auto PrepareTrial(State &state, const double alpha) {
this->trialSolveSucceeded = true;
this->BeginGravityAttempt();
auto preparation = state.PrepareTrial();
if (!preparation) { return preparation; }
this->Refresh(state);
@@ -281,6 +290,7 @@ namespace mean_field::solver::detail {
m_rhs(m_operator.Height()), m_correction(m_operator.Width()) { }
bool Initialize(State &state, nonlinear::NumericalStrategyDiagnostics &diagnostics) {
this->BeginGravityAttempt();
const auto &partition = this->subsystem.GetPartition();
partition.GatherGravityResiduals(state.acceptedNormalizedResidual, this->gravityResidual);
diagnostics.initialGravityResidual = StrategyNorm(this->gravityResidual, this->subsystem.GetCommunicator());
@@ -343,11 +353,14 @@ namespace mean_field::solver::detail {
this->subsystem.GetPartition().GatherRetainedValues(state.normalizedCorrection, m_correction);
this->lastSolve = m_operator.TryLiftCorrection(m_correction, state.linearRightHandSide,
state.normalizedCorrection);
// Keep the report space attached to the outer Solve result; this
// later auxiliary failure is reported through DirectionSolveFailed
// and the gravity counters/last completed inner defect.
return this->lastSolve.Converged();
}
auto PrepareTrial(State &state, double) {
this->trialSolveSucceeded = true;
this->BeginGravityAttempt();
auto preparation = state.PrepareTrial();
if (!preparation) { return preparation; }
this->Refresh(state);