16#include "libmesh/utility.h"
17#include "libmesh/int_range.h"
18#include "libmesh/vector_value.h"
22#include <unsupported/Eigen/NonLinearOptimization>
58 using DynamicMatrix = Eigen::Matrix<NSReal, Eigen::Dynamic, Eigen::Dynamic>;
71 typename std::conditional<N == 1,
73 typename std::conditional<N == 0,
75 Eigen::Matrix<NSReal, N, 1>>::type>::type;
80 typename std::conditional<N == 1,
82 typename std::conditional<N == 0,
84 Eigen::Matrix<NSReal, N, N>>::type>::type;
87 template <
typename V,
typename T>
91 template <
typename V,
typename T,
typename C>
96 template <
typename R,
typename J>
98 template <
typename R,
typename J>
99 void nonlinear(
NSReal & guess, R & computeResidual, J & computeJacobian);
100 template <
typename R,
typename J>
106 template <
typename R,
typename J>
108 template <
typename R,
typename J>
110 template <
typename R,
typename J>
115 template <
typename R,
typename J,
typename B>
166 template <
typename V>
174 template <
typename V>
175 static bool isRelSmall(
const V & a,
const V & b,
const V & c);
195 template <
typename V,
typename T>
201 template <
typename J,
typename V>
202 void linear(
const J & A, V & x,
const V & b)
const;
208 bool isConverged(Real r0_square, Real r_square,
bool acceptable);
212 template <
bool store_res
idual_norm,
typename R,
typename J>
214 template <
bool store_res
idual_norm,
typename R,
typename J>
216 template <
bool store_res
idual_norm,
typename R,
typename J>
222template <
typename R,
typename J>
229 auto functor = make_adaptor<true>(computeResidual, computeJacobian);
230 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
231 auto status = solver.solve(guess);
233 if (status == Eigen::HybridNonLinearSolverSpace::RelativeErrorTooSmall)
234 _state = State::CONVERGED_REL;
236 _state = State::NOT_CONVERGED;
240template <
typename R,
typename J>
247 auto functor = make_real_adaptor<true>(computeResidual, computeJacobian);
248 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
250 guess_eigen << guess;
251 const auto & r_square = functor.getResidualNorm();
252 solver.solveInit(guess_eigen);
255 auto r0_square = r_square;
258 _state = State::EXACT_GUESS;
264 while (_n_iterations <= _max_iterations &&
265 solver.solveOneStep(guess_eigen) == Eigen::HybridNonLinearSolverSpace::Running)
268 if (_n_iterations >= _min_iterations && isConverged(r0_square, r_square,
false))
270 guess = guess_eigen(0);
279 if (!isConverged(r0_square, r_square,
true))
280 _state = State::NOT_CONVERGED;
282 guess = guess_eigen(0);
286template <
typename R,
typename J>
295 auto functor = make_realvector_adaptor<true>(computeResidual, computeJacobian);
296 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
298 guess_eigen << guess(0), guess(1), guess(2);
299 auto status = solver.solve(guess_eigen);
300 guess(0) = guess_eigen(0);
301 guess(1) = guess_eigen(1);
302 guess(2) = guess_eigen(2);
304 if (status == Eigen::HybridNonLinearSolverSpace::RelativeErrorTooSmall)
305 _state = State::CONVERGED_REL;
307 _state = State::NOT_CONVERGED;
311template <
typename R,
typename J>
318 auto functor = make_adaptor<false>(computeResidual, computeJacobian);
319 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
320 auto status = solver.solve(guess);
322 if (status == Eigen::HybridNonLinearSolverSpace::RelativeErrorTooSmall)
323 _state = State::CONVERGED_REL;
325 _state = State::NOT_CONVERGED;
329template <
typename R,
typename J>
336 auto functor = make_real_adaptor<false>(computeResidual, computeJacobian);
337 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
339 guess_eigen << guess;
340 auto status = solver.solve(guess_eigen);
341 guess = guess_eigen(0);
343 if (status == Eigen::HybridNonLinearSolverSpace::RelativeErrorTooSmall)
344 _state = State::CONVERGED_REL;
346 _state = State::NOT_CONVERGED;
350template <
typename R,
typename J>
359 auto functor = make_realvector_adaptor<false>(computeResidual, computeJacobian);
360 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
362 guess_eigen << guess(0), guess(1), guess(2);
363 auto status = solver.solve(guess_eigen);
364 guess(0) = guess_eigen(0);
365 guess(1) = guess_eigen(1);
366 guess(2) = guess_eigen(2);
368 if (status == Eigen::HybridNonLinearSolverSpace::RelativeErrorTooSmall)
369 _state = State::CONVERGED_REL;
371 _state = State::NOT_CONVERGED;
375template <
typename R,
typename J,
typename B>
382 auto functor = make_real_adaptor<false>(computeResidual, computeJacobian);
383 Eigen::HybridNonLinearSolver<
decltype(functor),
NSReal> solver(functor);
386 guess_eigen << guess;
388 auto status = solver.solveInit(guess_eigen);
389 if (status == Eigen::HybridNonLinearSolverSpace::ImproperInputParameters)
392 bool bounds_hit =
false;
393 while (status == Eigen::HybridNonLinearSolverSpace::Running)
395 status = solver.solveOneStep(guess_eigen);
396 const std::pair<Real, Real> & bounds = computeBounds();
399 if (guess_eigen(0) < bounds.first || guess_eigen(0) > bounds.second)
401 if (guess_eigen(0) < bounds.first)
402 guess_eigen(0) = bounds.first;
404 guess_eigen(0) = bounds.second;
408 _state = State::CONVERGED_BOUNDS;
416 if (status == Eigen::HybridNonLinearSolverSpace::RelativeErrorTooSmall)
417 _state = State::CONVERGED_REL;
419 _state = State::NOT_CONVERGED;
421 guess = guess_eigen(0);
425template <
typename V,
typename T>
432 sizeItems(guess, residual, jacobian);
435 compute(guess, residual, jacobian);
438 auto r0_square = normSquare(residual);
441 _state = State::EXACT_GUESS;
444 auto r_square = r0_square;
447 while (_n_iterations < _max_iterations)
450 if (_n_iterations >= _min_iterations && isConverged(r0_square, r_square,
false))
454 linear(jacobian, delta, residual);
457 if (isRelSmall(delta, guess, _delta_thresh))
459 _state = State::CONVERGED_XTOL;
467 compute(guess, residual, jacobian);
469 r_square = normSquare(residual);
475 if (!isConverged(r0_square, r_square,
true))
476 _state = State::NOT_CONVERGED;
480template <
typename V,
typename T,
typename C>
487 sizeItems(guess, residual, jacobian);
490 compute(guess, residual, jacobian);
493 auto r0_square = normSquare(residual);
496 _state = State::EXACT_GUESS;
499 auto r_square = r0_square;
502 while (_n_iterations < _max_iterations)
505 if (_n_iterations >= _min_iterations && isConverged(r0_square, r_square,
false))
509 linear(jacobian, delta, residual);
512 if (isRelSmall(delta, guess, _delta_thresh))
514 _state = State::CONVERGED_XTOL;
519 unsigned int damping_iterations = 0;
520 auto prev_guess = guess;
523 while (!computeCondition(guess) && (damping_iterations < _max_damping_iterations))
525 alpha *= _damping_factor;
526 guess = prev_guess - alpha * delta;
527 damping_iterations += 1;
532 compute(guess, residual, jacobian);
534 r_square = normSquare(residual);
539 if (!isConverged(r0_square, r_square,
true))
540 _state = State::NOT_CONVERGED;
544template <
typename J,
typename V>
549 x = A.partialPivLu().solve(b);
558 Real norm_square = 0.0;
559 for (
const auto i : index_range(v))
610 using type = Eigen::Matrix<Real, N, N>;
616 using type = Eigen::Matrix<ADReal, N, N>;
623template <
bool is_ad,
typename R,
typename J,
bool store_res
idual_norm>
636 if constexpr (store_residual_norm)
648 if constexpr (store_residual_norm)
663template <
bool is_ad,
typename R,
typename J,
bool store_res
idual_norm>
676 if constexpr (store_residual_norm)
688 if constexpr (store_residual_norm)
703template <
bool is_ad,
typename R,
typename J,
bool store_res
idual_norm>
718 residual(0) = residual_moose(0);
719 residual(1) = residual_moose(1);
720 residual(2) = residual_moose(2);
721 if constexpr (store_residual_norm)
731 Eigen::Map<typename NestedSolveTempl<is_ad>::DynamicMatrix>(&jacobian_moose(0, 0), 3, 3);
737 if constexpr (store_residual_norm)
751template <
bool store_res
idual_norm,
typename R,
typename J>
756 residual_lambda, jacobian_lambda);
759template <
bool store_res
idual_norm,
typename R,
typename J>
764 residual_lambda, jacobian_lambda);
768template <
bool store_res
idual_norm,
typename R,
typename J>
773 residual_lambda, jacobian_lambda);
782 r_square /= _acceptable_multiplier * _acceptable_multiplier;
783 if (r_square < _absolute_tolerance_square)
785 _state = acceptable ? State::CONVERGED_ACCEPTABLE_ABS : State::CONVERGED_ABS;
788 if (r_square / r0_square < _relative_tolerance_square)
790 _state = acceptable ? State::CONVERGED_ACCEPTABLE_REL : State::CONVERGED_REL;
RankTwoTensorTempl< ADReal > ADRankTwoTensor
DualNumber< Real, DNDerivativeType, true > ADReal
NestedSolveTempl< false > NestedSolve
NestedSolveTempl< true > ADNestedSolve
RankTwoTensorTempl< Real > RankTwoTensor
Adaptor functor for Eigen::Matrix based residual and Jacobian types.
int operator()(V &guess, V &residual)
typename NestedSolveTempl< is_ad >::DynamicVector V
const Real & getResidualNorm()
DynamicMatrixEigenAdaptorFunctor(R &residual_lambda, J &jacobian_lambda)
int df(V &guess, typename NestedSolveTempl< is_ad >::template CorrespondingJacobian< V > &jacobian)
Adaptor functor for scalar Real valued residual and Jacobian types.
RealEigenAdaptorFunctor(R &residual_lambda, J &jacobian_lambda)
typename NestedSolveTempl< is_ad >::DynamicVector V
int df(V &guess, typename NestedSolveTempl< is_ad >::template CorrespondingJacobian< V > &jacobian)
const Real & getResidualNorm()
int operator()(V &guess, V &residual)
Adaptor functor for MOOSE RealVectorValue/RankTwoTensor residual and Jacobian types.
RealVectorEigenAdaptorFunctor(R &residual_lambda, J &jacobian_lambda)
int operator()(V &guess, V &residual)
typename NestedSolveTempl< is_ad >::DynamicVector V
int df(V &guess, typename NestedSolveTempl< is_ad >::template CorrespondingJacobian< V > &jacobian)
const Real & getResidualNorm()
NestedSolveTempl<is_ad> and its instantiations NestedSolve and ADNestedSolve are utility classes that...
auto make_realvector_adaptor(R &residual, J &jacobian)
void nonlinearDamped(V &guess, T &&compute, C &&computeCondition)
Solve the N*N nonlinear equation system using the damped Netwon-Raphson loop.
static Real acceptableMultiplierDefault()
auto make_adaptor(R &residual, J &jacobian)
Build a suitable Eigen adaptor functors to interface between moose and Eigen types.
typename std::conditional< N==1, NSReal, typename std::conditional< N==0, NestedSolveTempl< is_ad >::DynamicVector, Eigen::Matrix< NSReal, N, 1 > >::type >::type Value
Residual and solution type.
unsigned int _max_iterations
const State & getState() const
Get the solver state.
void linear(const NSReal &A, NSReal &x, const NSReal &b) const
void sizeItems(const V &, V &, T &) const
Sizing is a no-op for compile time sized types (and scalars)
static Real absoluteToleranceDefault()
State _state
current solver state
typename NestedSolveInternal::CorrespondingJacobianTempl< T >::type CorrespondingJacobian
static unsigned int maxIterationsDefault()
Moose::GenericType< RankTwoTensor, is_ad > NSRankTwoTensor
Real _damping_factor
Damping factor.
Real _absolute_tolerance_square
bool isConverged(Real r0_square, Real r_square, bool acceptable)
Convergence check (updates _status)
void nonlinear(V &guess, T &&compute)
Solve the N*N nonlinear equation system using a built-in Netwon-Raphson loop.
static bool isRelSmall(const V &a, const V &b, const V &c)
Check if |a| < |b * c| for all elements in a and b. This checks if 'a' is small relative to.
void sizeItems(const NestedSolveTempl< is_ad >::DynamicVector &guess, NestedSolveTempl< is_ad >::DynamicVector &residual, NestedSolveTempl< is_ad >::DynamicMatrix &jacobian) const
Size a dynamic Jacobian matrix correctly.
static Real relativeToleranceDefault()
default values
auto make_real_adaptor(R &residual, J &jacobian)
typename std::conditional< N==1, NSReal, typename std::conditional< N==0, NestedSolveTempl< is_ad >::DynamicMatrix, Eigen::Matrix< NSReal, N, N > >::type >::type Jacobian
Jacobian matrix type.
State
possible solver states
@ CONVERGED_ACCEPTABLE_ABS
@ CONVERGED_ACCEPTABLE_REL
Moose::GenericType< Real, is_ad > NSReal
AD/non-AD switched type shortcuts.
Eigen::Matrix< NSReal, Eigen::Dynamic, 1 > DynamicVector
Eigen type shortcuts.
Moose::GenericType< RealVectorValue, is_ad > NSRealVectorValue
unsigned int _max_damping_iterations
static InputParameters validParams()
static unsigned int minIterationsDefault()
static Real xToleranceDefault()
void setRelativeTolerance(Real rel)
void setAbsoluteTolerance(Real abs)
Real _relative_tolerance_square
Real _acceptable_multiplier
void nonlinearBounded(NSReal &guess, R &computeResidual, J &computeJacobian, B &computeBounds)
Perform a bounded solve use Eigen::HybridNonLinearSolver.
Real _delta_thresh
Threshold for minimum step size of linear iterations.
static unsigned int maxDampingIterationsDefault()
void nonlinear(DynamicVector &guess, R &computeResidual, J &computeJacobian)
unsigned int _min_iterations
void linear(const J &A, V &x, const V &b) const
Solve A*x=b for x.
void setAcceptableMultiplier(Real am)
static Real normSquare(const V &v)
Compute squared norm of v (dropping derivatives as this is only for convergence checking)
Eigen::Matrix< NSReal, Eigen::Dynamic, Eigen::Dynamic > DynamicMatrix
void nonlinearTight(DynamicVector &guess, R &computeResidual, J &computeJacobian)
std::size_t _n_iterations
number of nested iterations
const std::size_t & getIterations()
Get the number of iterations from the last solve.
static Real dampingFactorDefault()
typename std::conditional< is_ad, typename ADType< T >::type, T >::type GenericType
Internal use namespace that contains template helpers to map each residual type to its corresponding ...
Eigen::Matrix< ADReal, N, N > type
Eigen::Matrix< Real, N, N > type
NestedSolveTempl< false >::DynamicMatrix type
NestedSolveTempl< true >::DynamicMatrix type
Deduce the Jacobian type from the solution type.