Detect local-Newton non-convergence + singular Jacobian (#85) - #124
Open
petlenz wants to merge 2 commits into
Open
Detect local-Newton non-convergence + singular Jacobian (#85)#124petlenz wants to merge 2 commits into
petlenz wants to merge 2 commits into
Conversation
added 2 commits
July 27, 2026 17:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #85.
The in-function local Newton solvers emitted only a max-iteration guard: on non-convergence or a singular Jacobian they silently wrote the last (un-converged) iterate to the state out-params, corrupting the host FE solve with no signal. This closes the gap for both the single-scalar path (Phase 3a-2) and the coupled N×N path (Phase 3b-2b).
Detection
<sv>_convergedflag, set true only on a genuine‖R‖ < tolexit — so max-iter exhaustion is detectable after the loop.std::isfinite(a singular/ill-scaled Jacobian makes it non-finite → stop, don't propagate inf/nan).partialPivLu().solveresult checked with.allFinite(); Armadillo switched toarma::solve's bool overload (false on a rank-deficient system). Near-singular-but-finite steps are caught by the outer convergence flag (loop exhausts max_iter).Failure policy (the issue's design decision)
A new
NewtonOptions::on_failure:NaN(default) — write a quiet NaN to the failed state variable(s); it propagates into every derived output so the host detects a non-finite result. MOOSE-QP-safe (no throw in a QP loop).Throw— throwstd::runtime_errorfrom the generated compute function (clean for standalone drivers).Threaded from
NewtonOptions→NewtonSegment/NewtonSystemIR →Rendered*→render_compute_function(as a plain bool, sopass.hneedn't depend onrecipe.h). Line search / regularization remain a separate future enhancement, as the issue scopes.Tests
emit_newton_stepsingular guard + converged flag for both Eigen and Armadillo backends.K·dt = 1⇒∂R/∂α = 0) compiles and runs, asserting the output is NaN — proving the runtime signal fires rather than returning bogus-but-finite garbage.Affected code
include/numsim_codegen/recipe.h—NewtonOptions::on_failure; scalar-loop emit +detail::emit_newton_failure_policy; coupled-loop frame.include/numsim_codegen/code_emit/linear_algebra_emitter.h—emit_newton_steprecords convergence + guards the solve (Eigen + Armadillo).passes/pass.h,recipe_render.h,passes/internal/pass_bodies.h— thread the policy through the IR.src/targets/{standalone_cxx,moose_material}.cpp— emit<limits>/<stdexcept>.LocalNewtonTest.cpp,LinearAlgebraEmitterTest.cpp,generated/compile_check_driver.cpp.