Integrate typed Newton strategies with checked trial gravity and feasibility
This commit is contained in:
@@ -20,6 +20,8 @@ import mean_field;
|
||||
#include "plateau_preconditioner_diagnostics.hpp"
|
||||
#include "plateau_pressure_obstruction_diagnostics.hpp"
|
||||
#include "plateau_shape_curvature_diagnostics.hpp"
|
||||
#include "plateau_numerical_strategy_diagnostics.hpp"
|
||||
#include "plateau_positivity_strategy_diagnostics.hpp"
|
||||
|
||||
using namespace mean_field;
|
||||
namespace {
|
||||
@@ -28,6 +30,10 @@ struct Options {
|
||||
double n = 1., angularMomentum = 0., atol = 0., rtol = 1e-8, linearTolerance = .03;
|
||||
int maxNewton = 12, maxLinear = 200, restart = 40, probeRestart = 40;
|
||||
bool probes = false, noCentral = false;
|
||||
bool strategyProbe = false, positivityProbe = false;
|
||||
std::string strategy = "baseline";
|
||||
double gravityTolerance = 1e-10;
|
||||
int gravityIterations = 300, gravityRestart = 80;
|
||||
bool pressureProbe = false, shapeCurvature = false, surfaceTrace = false;
|
||||
std::vector<int> captureIterations;
|
||||
std::string mesh = "sandbox.smesh";
|
||||
@@ -70,6 +76,18 @@ Options Parse(int argc, char **argv) {
|
||||
o.probeDirection = v();
|
||||
else if (a == "--replay-candidate")
|
||||
o.replayCandidate = v();
|
||||
else if (a == "--strategy")
|
||||
o.strategy = v();
|
||||
else if (a == "--gravity-tol")
|
||||
o.gravityTolerance = std::stod(v());
|
||||
else if (a == "--gravity-iterations")
|
||||
o.gravityIterations = std::stoi(v());
|
||||
else if (a == "--gravity-restart")
|
||||
o.gravityRestart = std::stoi(v());
|
||||
else if (a == "--strategy-probe")
|
||||
o.strategyProbe = true;
|
||||
else if (a == "--positivity-probe")
|
||||
o.positivityProbe = true;
|
||||
else if (a == "--pressure-probe")
|
||||
o.pressureProbe = true;
|
||||
else if (a == "--shape-curvature")
|
||||
@@ -100,10 +118,15 @@ Options Parse(int argc, char **argv) {
|
||||
throw std::invalid_argument("Invalid options");
|
||||
if (o.probeRestart != 40 && o.probeRestart != 160)
|
||||
throw std::invalid_argument("--probe-restart must be 40 or 160");
|
||||
if ((o.pressureProbe || o.shapeCurvature || o.surfaceTrace) && (o.probeState.empty() || o.probeDirection.empty()))
|
||||
if ((o.pressureProbe || o.shapeCurvature || o.surfaceTrace || o.strategyProbe || o.positivityProbe) && (o.probeState.empty() || o.probeDirection.empty()))
|
||||
throw std::invalid_argument("Focused probes require --probe-state and --probe-direction");
|
||||
if ((!o.probeDirection.empty() || !o.replayCandidate.empty()) && o.probeState.empty())
|
||||
throw std::invalid_argument("A supplied direction or candidate requires --probe-state");
|
||||
if (o.strategy != "baseline" && o.strategy != "positivity" && o.strategy != "curvature" &&
|
||||
o.strategy != "reduced" && o.strategy != "positivity-curvature" && o.strategy != "positivity-reduced")
|
||||
throw std::invalid_argument("Unknown numerical strategy");
|
||||
if (!std::isfinite(o.gravityTolerance) || o.gravityTolerance <= 0.0 || o.gravityIterations < 1 || o.gravityRestart < 1)
|
||||
throw std::invalid_argument("Invalid gravity solve controls");
|
||||
if (std::filesystem::exists(o.output))
|
||||
throw std::runtime_error("Output directory already exists");
|
||||
std::filesystem::create_directories(o.output);
|
||||
@@ -227,6 +250,10 @@ void FocusedProbes(State &s, const fem::FEM &f, const Options &o, const mfem::Ve
|
||||
for (const auto &[key, value] : experiment::plateau_diagnostics::MeasureEnthalpyStep(s, f, o.n, &physicalBase))
|
||||
bounds << key << ',' << value << '\n';
|
||||
bounds.flush();
|
||||
if (o.strategyProbe)
|
||||
experiment::plateau_diagnostics::ProbeNumericalStrategies(s, f, base, direction, o.output);
|
||||
if (o.positivityProbe)
|
||||
experiment::plateau_diagnostics::ProbePolynomialEnthalpy(s, f, base, direction, o.output);
|
||||
if (o.surfaceTrace)
|
||||
experiment::plateau_diagnostics::ProbeSurfaceTrace(s, f, o.n, base, direction, o.output);
|
||||
if (o.pressureProbe)
|
||||
@@ -357,6 +384,8 @@ template <class Context> int RunContext(Context &context, const Options &o, cons
|
||||
<< "\nfrozen_probe_backend=" << (o.probeDirection.empty() ? "direct_mfem_fgmres_cold" : "supplied_direction_no_linear_solve")
|
||||
<< "\nlinear_tol=" << o.linearTolerance << "\nmax_linear=" << o.maxLinear
|
||||
<< "\nmax_newton=" << o.maxNewton << "\natol=" << o.atol << "\nrtol=" << o.rtol
|
||||
<< "\nstrategy=" << o.strategy << "\ngravity_tolerance=" << o.gravityTolerance
|
||||
<< "\ngravity_iterations=" << o.gravityIterations << "\ngravity_restart=" << o.gravityRestart
|
||||
<< "\ncompiler=" << __VERSION__ << "\ncompiled=" << __DATE__ << ' ' << __TIME__ << '\n';
|
||||
metadata.flush();
|
||||
if (!o.probeState.empty()) {
|
||||
@@ -537,18 +566,44 @@ template <class Context> int RunContext(Context &context, const Options &o, cons
|
||||
});
|
||||
bool converged = false;
|
||||
if (o.maxNewton > 0) {
|
||||
auto report = [&]() {
|
||||
auto solve = solver::make(context,
|
||||
solver::nonlinear::Newton(solver::nonlinear::NewtonOptions{
|
||||
.relativeTolerance = o.rtol,
|
||||
.absoluteTolerance = o.atol,
|
||||
.maximumIterations = o.maxNewton,
|
||||
.linearSolve = {.relativeTolerance = o.linearTolerance,
|
||||
.absoluteTolerance = 0.,
|
||||
.maximumIterations = o.maxLinear}}),
|
||||
observer);
|
||||
namespace nl = solver::nonlinear;
|
||||
const nl::NewtonOptions options{
|
||||
.relativeTolerance = o.rtol, .absoluteTolerance = o.atol, .maximumIterations = o.maxNewton,
|
||||
.linearSolve = {.relativeTolerance = o.linearTolerance, .absoluteTolerance = 0., .maximumIterations = o.maxLinear}};
|
||||
const nl::GravitySolveOptions gravity{
|
||||
.control = {.relativeTolerance = o.gravityTolerance, .absoluteTolerance = 1e-14,
|
||||
.maximumIterations = o.gravityIterations},
|
||||
.backend = {.restartLength = o.gravityRestart}};
|
||||
auto run = [&](auto numerics) {
|
||||
auto solve = solver::make(context, nl::Newton(options, nl::NormalizedResidualMetric{}, numerics), observer);
|
||||
return solve.evaluate();
|
||||
};
|
||||
auto report = [&] {
|
||||
if (o.strategy == "positivity") return run(nl::NewtonNumerics{nl::PolynomialEnthalpy{}, nl::MonolithicGravity{}});
|
||||
if (o.strategy == "curvature") return run(nl::NewtonNumerics{nl::SampledEnthalpy{}, nl::GravityCurvatureCorrection{gravity}});
|
||||
if (o.strategy == "reduced") return run(nl::NewtonNumerics{nl::SampledEnthalpy{}, nl::EliminatedGravity{gravity}});
|
||||
if (o.strategy == "positivity-curvature") return run(nl::NewtonNumerics{nl::PolynomialEnthalpy{}, nl::GravityCurvatureCorrection{gravity}});
|
||||
if (o.strategy == "positivity-reduced") return run(nl::NewtonNumerics{nl::PolynomialEnthalpy{}, nl::EliminatedGravity{gravity}});
|
||||
return run(nl::NewtonNumerics{});
|
||||
}();
|
||||
const auto &strategyDiagnostics = report.diagnostics().numericalStrategies;
|
||||
auto strategyMetrics = File(o.output / "numerical_strategies.csv");
|
||||
strategyMetrics << "metric,value\n";
|
||||
const auto metric = [&](const char *name, auto value) { strategyMetrics << name << ',' << value << '\n'; };
|
||||
metric("polynomial_checks", strategyDiagnostics.polynomialChecks);
|
||||
metric("direction_repairs", strategyDiagnostics.directionRepairs);
|
||||
metric("last_repair_fraction", strategyDiagnostics.lastRepairFraction);
|
||||
metric("last_merit_directional_derivative", strategyDiagnostics.lastMeritDirectionalDerivative);
|
||||
metric("gravity_solves", strategyDiagnostics.gravitySolves);
|
||||
metric("gravity_iterations", strategyDiagnostics.gravityIterations);
|
||||
metric("gravity_failures", strategyDiagnostics.gravityFailures);
|
||||
metric("gravity_solve_seconds", strategyDiagnostics.gravitySolveSeconds);
|
||||
metric("last_gravity_true_residual", strategyDiagnostics.lastGravityTrueResidual);
|
||||
metric("last_gravity_correction_norm", strategyDiagnostics.lastGravityCorrectionNorm);
|
||||
metric("last_gravity_prepared_defect", strategyDiagnostics.lastGravityPreparedDefect);
|
||||
metric("initial_gravity_residual", strategyDiagnostics.initialGravityResidual);
|
||||
metric("completed_initial_gravity_residual", strategyDiagnostics.completedInitialGravityResidual);
|
||||
metric("last_lifted_relative_true_residual", strategyDiagnostics.lastLiftedRelativeTrueResidual);
|
||||
converged = report.converged();
|
||||
metadata << "converged=" << converged << "\naccepted_steps=" << report.completedNonlinearIterations() << '\n';
|
||||
if (!converged)
|
||||
|
||||
Reference in New Issue
Block a user