perf(allocations): reduced overall allocations by 95%, increaseed jacobian applicatin by 2x

This commit uses global pre allocated work space to dramatically reduce memory usage and allocation time
This commit is contained in:
2026-09-10 06:50:56 -04:00
parent b3c04d507a
commit 75cc638739
66 changed files with 207183 additions and 99552 deletions

View File

@@ -76,17 +76,20 @@ namespace stellar_solver_architecture_test {
std::shared_ptr<LifetimeProbe> probe;
double correctionValue{0.0};
bool resizeCorrection{false};
bool surfaceCorrectionOnly{false};
ScriptedBackend() = default;
explicit ScriptedBackend(
std::shared_ptr<LifetimeProbe> lifetimeProbe,
const double scriptedCorrectionValue = 0.0,
const bool resizeScriptedCorrection = false
const double scriptedCorrectionValue = 0.0,
const bool resizeScriptedCorrection = false,
const bool scriptOnlySurfaceCorrection = false
)
: probe(std::move(lifetimeProbe)),
correctionValue(scriptedCorrectionValue),
resizeCorrection(resizeScriptedCorrection) {
resizeCorrection(resizeScriptedCorrection),
surfaceCorrectionOnly(scriptOnlySurfaceCorrection) {
}
};
@@ -98,14 +101,16 @@ namespace stellar_solver_architecture_test {
const MPI_Comm communicator,
std::shared_ptr<LifetimeProbe> probe,
const double correctionValue,
const bool resizeCorrection
const bool resizeCorrection,
const bool surfaceCorrectionOnly
)
: m_operation(std::addressof(operation)),
m_preconditioner(std::addressof(preconditioner)),
m_communicator(communicator),
m_probe(std::move(probe)),
m_correctionValue(correctionValue),
m_resizeCorrection(resizeCorrection) {
m_resizeCorrection(resizeCorrection),
m_surfaceCorrectionOnly(surfaceCorrectionOnly) {
if (m_probe != nullptr) {
m_probe->problemIdentity = std::addressof(operation.GetProblem());
}
@@ -181,7 +186,17 @@ namespace stellar_solver_architecture_test {
m_probe->incomingCorrectionNorms.push_back(GlobalNorm(correction));
}
correction = m_correctionValue;
if (m_surfaceCorrectionOnly) {
mfem::Vector physicalCorrection(CorrectionSize());
physicalCorrection = 0.0;
auto physicalDirection = m_operation->GetProblem().GetManifest().stateView(physicalCorrection);
mfem::Vector surfaceDirection =
physicalDirection.block(mean_field::utils::blocks::surface_deformation_field.parameters_term);
surfaceDirection = m_correctionValue;
m_operation->NormalizeState(physicalCorrection, correction);
} else {
correction = m_correctionValue;
}
if (m_probe != nullptr) {
m_probe->returnedCorrectionNorms.push_back(GlobalNorm(correction));
}
@@ -226,6 +241,7 @@ namespace stellar_solver_architecture_test {
std::shared_ptr<LifetimeProbe> m_probe;
double m_correctionValue;
bool m_resizeCorrection;
bool m_surfaceCorrectionOnly;
};
template <
@@ -243,7 +259,8 @@ namespace stellar_solver_architecture_test {
communicator,
std::move(configuration.probe),
configuration.correctionValue,
configuration.resizeCorrection
configuration.resizeCorrection,
configuration.surfaceCorrectionOnly
};
}
@@ -1013,11 +1030,14 @@ TEST_CASE(
event.normalizedState.begin(), event.normalizedState.end()
);
CHECK(event.iterationSeconds >= 0.0);
CHECK(event.geometryPreflightSeconds >= 0.0);
CHECK(event.lineSearchSeconds >= 0.0);
CHECK(event.trialPreparationSeconds >= 0.0);
CHECK(event.metricEvaluationSeconds >= 0.0);
CHECK(event.preconditionerRefreshSeconds >= 0.0);
CHECK(event.rollbackSeconds >= 0.0);
REQUIRE(event.geometryPreflight.has_value());
CHECK(event.geometryPreflight->sampledQuadraturePointCount > 0);
}
);
auto newton = solver::nonlinear::Newton(
@@ -1050,11 +1070,14 @@ TEST_CASE(
CHECK(report.diagnostics().nonFiniteLineSearchTrials == 0);
CHECK(report.diagnostics().insufficientDecreaseTrials == 2);
CHECK(report.diagnostics().totalLinearSolveSeconds >= 0.0);
CHECK(report.diagnostics().totalGeometryPreflightSeconds >= 0.0);
CHECK(report.diagnostics().totalLineSearchSeconds >= 0.0);
CHECK(report.diagnostics().totalTrialPreparationSeconds >= 0.0);
CHECK(report.diagnostics().totalMetricEvaluationSeconds >= 0.0);
CHECK(report.diagnostics().totalPreconditionerRefreshSeconds >= 0.0);
CHECK(report.diagnostics().totalRollbackSeconds >= 0.0);
REQUIRE(report.diagnostics().lastGeometryPreflight.has_value());
CHECK(report.diagnostics().lastGeometryPreflight->sampledQuadraturePointCount > 0);
CHECK(metricState->next == metricState->evaluations.size());
REQUIRE(observerRecord->beforeCalls == 2);
REQUIRE(observerRecord->afterCalls == 2);
@@ -1105,6 +1128,82 @@ TEST_CASE(
);
}
TEST_CASE(
"Newton Geometry Preflight Caps A Surface Step Before Trial Preparation",
"[solver][newton][geometry][preflight][backtracking][wiring]"
) {
using namespace mean_field;
using namespace stellar_solver_architecture_test;
using Catch::Approx;
auto finiteElements = makeFiniteElements();
REQUIRE(finiteElements.okay());
auto discretization = equilibrium::makeStellarDiscretization(
std::move(finiteElements),
normalization::PhysicalRieszDiagonal{dimensions::LengthValue{utils::RADIUS}, utils::G}
);
auto context = solver::makeContext(
makeModel(), std::move(discretization), preconditioning::makePreconditioner(),
ScriptedBackend{nullptr, -10.0, false, true}
);
auto metricState = std::make_shared<MetricSequenceState>();
metricState->evaluations = {{.residualNorm = 2.0, .merit = 2.0}, {.residualNorm = 1.0, .merit = 0.5}};
std::optional<deformation::LargestSafeNewtonStepSizeEstimate> observedPreflight;
auto observer = solver::nonlinear::makeObserver(
[](const solver::nonlinear::BeforeIteration &) { },
[&observedPreflight](const solver::nonlinear::AfterIteration &event) {
observedPreflight = event.geometryPreflight;
CHECK(event.geometryPreflightSeconds >= 0.0);
CHECK(event.stepAccepted);
CHECK(event.lineSearchTrials == 1);
}
);
auto newton = solver::nonlinear::Newton(
solver::nonlinear::NewtonOptions{
.relativeTolerance = 0.0,
.absoluteTolerance = 0.0,
.maximumIterations = 1,
.linearSolve =
{.relativeTolerance = 0.0,
.absoluteTolerance = std::numeric_limits<double>::max(),
.maximumIterations = 1},
.backtracking =
{.initialStepLength = 1.0,
.contractionFactor = 0.5,
.fractionToBoundarySafety = 0.5,
.sufficientDecrease = 1.0e-4,
.minimumStepLength = 1.0e-8,
.maximumTrials = 1}
},
SequencedMetric{metricState}
);
auto equilibriumSolver = solver::make(context, std::move(newton), std::move(observer));
const auto report = equilibriumSolver.evaluate();
REQUIRE_FALSE(report.converged());
CHECK(report.failure().reason == solver::StellarEquilibriumFailureReason::iteration_limit);
CHECK(report.diagnostics().attemptedNonlinearIterations == 1);
CHECK(report.diagnostics().acceptedNonlinearIterations == 1);
CHECK(report.diagnostics().totalLineSearchTrials == 1);
CHECK(report.diagnostics().inadmissibleLineSearchTrials == 0);
CHECK(report.diagnostics().geometryLimitedIterations == 1);
REQUIRE(report.diagnostics().lastGeometryPreflight.has_value());
const auto &preflight = *report.diagnostics().lastGeometryPreflight;
CHECK(preflight.limitedByGeometry);
CHECK(preflight.sampledQuadraturePointCount > 0);
CHECK(preflight.minimumDeterminantAtAcceptedState > 0.0);
CHECK(preflight.minimumDeterminantAtMaximumStepSize <= 0.0);
CHECK(preflight.stepSize > 0.0);
CHECK(preflight.stepSize < 1.0);
CHECK(preflight.stepSize == Approx(0.5 * preflight.boundaryStepSize));
CHECK(report.diagnostics().lastAcceptedStepLength == Approx(preflight.stepSize));
REQUIRE(observedPreflight.has_value());
CHECK(observedPreflight->stepSize == Approx(preflight.stepSize));
CHECK(report.lastAcceptedCheckpointView().valid());
}
TEST_CASE(
"An Accepted Final Newton Step Reports The Iteration Limit To Its Observer",
"[solver][newton][iteration-limit][observer][checkpoint]"