Add bounded coupled damping and prediction-based attempt selection

This commit is contained in:
2026-09-18 10:45:45 -04:00
parent 46249d0758
commit 422c46bcbf
11 changed files with 2296 additions and 101 deletions

View File

@@ -44,8 +44,8 @@ namespace mean_field::solver::detail {
using Enthalpy = typename Recipe::EnthalpyType;
using Gravity = typename Recipe::GravityType;
using Trial = typename Recipe::TrialType;
std::array<int, 13> integers{};
std::array<double, 5> reals{};
std::array<int, 14> integers{};
std::array<double, 7> reals{};
integers[0] = std::same_as<Enthalpy, nonlinear::PolynomialEnthalpy>;
integers[1] = std::same_as<Gravity, nonlinear::GravityCurvatureCorrection> ? 1 :
std::same_as<Gravity, nonlinear::EliminatedGravity> ? 2 : 0;
@@ -61,8 +61,9 @@ namespace mean_field::solver::detail {
reals[0] = options.control.relativeTolerance;
reals[1] = options.control.absoluteTolerance;
}
integers[8] = std::same_as<Trial, nonlinear::CoupledCurvatureCorrection>;
if constexpr (std::same_as<Trial, nonlinear::CoupledCurvatureCorrection>) {
integers[8] = std::same_as<Trial, nonlinear::CoupledCurvatureCorrection> ? 1 :
std::same_as<Trial, nonlinear::BacktrackedCoupledCurvatureCorrection> ? 2 : 0;
if constexpr (nonlinear::CoupledTrialNumerics<Trial>) {
const auto &options = recipe.trial.correction;
integers[9] = options.control.maximumIterations;
integers[10] = options.backend.restartLength;
@@ -72,13 +73,18 @@ namespace mean_field::solver::detail {
reals[3] = options.control.absoluteTolerance;
reals[4] = options.maximumCorrectionRatio;
}
if constexpr (std::same_as<Trial, nonlinear::BacktrackedCoupledCurvatureCorrection>) {
integers[13] = recipe.trial.search.maximumSteps;
reals[5] = recipe.trial.search.reduction;
reals[6] = recipe.trial.attempt.maximumExcessRatio;
}
integers[7] = std::all_of(reals.begin(), reals.end(), [](double value) { return std::isfinite(value); });
std::array<int, 13> minimumIntegers{}, maximumIntegers{};
std::array<double, 5> minimumReals{}, maximumReals{};
if (MPI_Allreduce(integers.data(), minimumIntegers.data(), 13, MPI_INT, MPI_MIN, communicator) != MPI_SUCCESS ||
MPI_Allreduce(integers.data(), maximumIntegers.data(), 13, MPI_INT, MPI_MAX, communicator) != MPI_SUCCESS ||
MPI_Allreduce(reals.data(), minimumReals.data(), 5, MPI_DOUBLE, MPI_MIN, communicator) != MPI_SUCCESS ||
MPI_Allreduce(reals.data(), maximumReals.data(), 5, MPI_DOUBLE, MPI_MAX, communicator) != MPI_SUCCESS) {
std::array<int, 14> minimumIntegers{}, maximumIntegers{};
std::array<double, 7> minimumReals{}, maximumReals{};
if (MPI_Allreduce(integers.data(), minimumIntegers.data(), 14, MPI_INT, MPI_MIN, communicator) != MPI_SUCCESS ||
MPI_Allreduce(integers.data(), maximumIntegers.data(), 14, MPI_INT, MPI_MAX, communicator) != MPI_SUCCESS ||
MPI_Allreduce(reals.data(), minimumReals.data(), 7, MPI_DOUBLE, MPI_MIN, communicator) != MPI_SUCCESS ||
MPI_Allreduce(reals.data(), maximumReals.data(), 7, MPI_DOUBLE, MPI_MAX, communicator) != MPI_SUCCESS) {
throw std::runtime_error("Newton could not compare numerical strategies across ranks.");
}
if (minimumIntegers != maximumIntegers || minimumReals != maximumReals ||
@@ -86,7 +92,7 @@ namespace mean_field::solver::detail {
throw std::invalid_argument("Newton numerical strategies and controls must agree on every rank.");
}
if constexpr (!std::same_as<Gravity, nonlinear::MonolithicGravity>) { recipe.gravity.gravity.Validate(); }
if constexpr (std::same_as<Trial, nonlinear::CoupledCurvatureCorrection>) { recipe.trial.Validate(); }
if constexpr (nonlinear::CoupledTrialNumerics<Trial>) { recipe.trial.Validate(); }
}
template <typename State, typename Policy> class PreparedGravityStrategy;
@@ -431,6 +437,11 @@ namespace mean_field::solver::detail {
: transaction(state, policy.correction, policy.maximumAttemptsPerIteration) { }
PreparedCoupledTrialTransaction<State> transaction;
};
template <typename State> struct PreparedTrialPath<State, nonlinear::BacktrackedCoupledCurvatureCorrection> {
PreparedTrialPath(State &state, const nonlinear::BacktrackedCoupledCurvatureCorrection &policy)
: transaction(state, policy.correction, policy.maximumAttemptsPerIteration, policy.search, policy.attempt) { }
PreparedCoupledTrialTransaction<State, BacktrackedCoupledStep, NearAcceptanceCoupledAttempt> transaction;
};
template <typename State, nonlinear::NewtonNumericalConfiguration Recipe>
class PreparedNewtonStrategy final : public NewtonStrategyStorage {
@@ -439,7 +450,7 @@ namespace mean_field::solver::detail {
using Gravity = typename Recipe::GravityType;
using Trial = typename Recipe::TrialType;
static constexpr bool altersDirection = std::same_as<Enthalpy, nonlinear::PolynomialEnthalpy>;
static constexpr bool correctsTrial = std::same_as<Trial, nonlinear::CoupledCurvatureCorrection>;
static constexpr bool correctsTrial = nonlinear::CoupledTrialNumerics<Trial>;
PreparedNewtonStrategy(State &state, const Recipe &recipe)
: m_enthalpy(state, recipe.enthalpy), m_gravity(state, recipe.gravity), m_trial(state, recipe.trial) { }