16 #include "libmesh/utility.h"    17 #include "libmesh/int_range.h"    18 #include "libmesh/vector_value.h"    21 #include <Eigen/Dense>    22 #include <unsupported/Eigen/NonLinearOptimization>    58   using DynamicMatrix = Eigen::Matrix<NSReal, Eigen::Dynamic, Eigen::Dynamic>;
    75                                                           Eigen::Matrix<NSReal, N, 1>>::type>::type;
    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>
   221 template <
bool is_ad>
   222 template <
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;
   239 template <
bool is_ad>
   240 template <
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);
   285 template <
bool is_ad>
   286 template <
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;
   310 template <
bool is_ad>
   311 template <
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;
   328 template <
bool is_ad>
   329 template <
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;
   349 template <
bool is_ad>
   350 template <
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;
   374 template <
bool is_ad>
   375 template <
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);
   424 template <
bool is_ad>
   425 template <
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;
   479 template <
bool is_ad>
   480 template <
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;
   543 template <
bool is_ad>
   544 template <
typename J, 
typename V>
   549   x = A.partialPivLu().solve(b);
   552 template <
bool is_ad>
   553 template <
typename V>
   558   Real norm_square = 0.0;
   610   using type = Eigen::Matrix<Real, N, N>;
   616   using type = Eigen::Matrix<ADReal, N, N>;
   623 template <
bool is_ad, 
typename R, 
typename J, 
bool store_res
idual_norm>
   636     if constexpr (store_residual_norm)
   648     if constexpr (store_residual_norm)
   663 template <
bool is_ad, 
typename R, 
typename J, 
bool store_res
idual_norm>
   676     if constexpr (store_residual_norm)
   688     if constexpr (store_residual_norm)
   703 template <
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)
   750 template <
bool is_ad>
   751 template <
bool store_res
idual_norm, 
typename R, 
typename J>
   756       residual_lambda, jacobian_lambda);
   758 template <
bool is_ad>
   759 template <
bool store_res
idual_norm, 
typename R, 
typename J>
   764       residual_lambda, jacobian_lambda);
   767 template <
bool is_ad>
   768 template <
bool store_res
idual_norm, 
typename R, 
typename J>
   773       residual_lambda, jacobian_lambda);
   777 template <
bool is_ad>
   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;
 int operator()(V &guess, V &residual)
 
void setAcceptableMultiplier(Real am)
 
unsigned int _min_iterations
 
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
 
const Real & getResidualNorm()
 
NestedSolveTempl< false > NestedSolve
 
const std::size_t & getIterations()
Get the number of iterations from the last solve. 
 
Moose::GenericType< RankTwoTensor, is_ad > NSRankTwoTensor
 
RankTwoTensorTempl< Real > RankTwoTensor
 
void sizeItems(const V &, V &, T &) const
Sizing is a no-op for compile time sized types (and scalars) 
 
Real _acceptable_multiplier
 
NestedSolveTempl< true >::DynamicMatrix type
 
static unsigned int maxDampingIterationsDefault()
 
RealEigenAdaptorFunctor(R &residual_lambda, J &jacobian_lambda)
 
RealVectorEigenAdaptorFunctor(R &residual_lambda, J &jacobian_lambda)
 
State
possible solver states 
 
static InputParameters validParams()
 
typename NestedSolveTempl< is_ad >::DynamicVector V
 
State _state
current solver state 
 
DynamicMatrixEigenAdaptorFunctor(R &residual_lambda, J &jacobian_lambda)
 
static Real dampingFactorDefault()
 
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...
 
const Real & getResidualNorm()
 
static Real xToleranceDefault()
 
Real _delta_thresh
Threshold for minimum step size of linear iterations. 
 
DualNumber< Real, DNDerivativeType, true > ADReal
 
Adaptor functor for Eigen::Matrix based residual and Jacobian types. 
 
Eigen::Matrix< NSReal, Eigen::Dynamic, Eigen::Dynamic > DynamicMatrix
 
typename std::conditional< is_ad, typename ADType< T >::type, T >::type GenericType
 
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. 
 
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. 
 
void nonlinearTight(DynamicVector &guess, R &computeResidual, J &computeJacobian)
 
unsigned int _max_iterations
 
Deduce the Jacobian type from the solution type. 
 
int df(V &guess, typename NestedSolveTempl< is_ad >::template CorrespondingJacobian< V > &jacobian)
 
RankTwoTensorTempl< ADReal > ADRankTwoTensor
 
void linear(const J &A, V &x, const V &b) const
Solve A*x=b for x. 
 
int operator()(V &guess, V &residual)
 
void nonlinear(V &guess, T &&compute)
Solve the N*N nonlinear equation system using a built-in Netwon-Raphson loop. 
 
Eigen::Matrix< ADReal, N, N > type
 
Real _absolute_tolerance_square
 
const Real & getResidualNorm()
 
static Real relativeToleranceDefault()
default values 
 
auto make_adaptor(R &residual, J &jacobian)
Build a suitable Eigen adaptor functors to interface between moose and Eigen types. 
 
Eigen::Matrix< NSReal, Eigen::Dynamic, 1 > DynamicVector
Eigen type shortcuts. 
 
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. 
 
void setRelativeTolerance(Real rel)
 
Eigen::Matrix< Real, N, N > type
 
auto make_real_adaptor(R &residual, J &jacobian)
 
bool isConverged(Real r0_square, Real r_square, bool acceptable)
Convergence check (updates _status) 
 
static Real normSquare(const V &v)
Compute squared norm of v (dropping derivatives as this is only for convergence checking) ...
 
auto conditional(const C &, const L &, const R &)
 
typename NestedSolveInternal::CorrespondingJacobianTempl< T >::type CorrespondingJacobian
 
NestedSolveTempl<is_ad> and its instantiations NestedSolve and ADNestedSolve are utility classes that...
 
std::size_t _n_iterations
number of nested iterations 
 
Internal use namespace that contains template helpers to map each residual type to its corresponding ...
 
void nonlinearBounded(NSReal &guess, R &computeResidual, J &computeJacobian, B &computeBounds)
Perform a bounded solve use Eigen::HybridNonLinearSolver. 
 
Adaptor functor for scalar Real valued residual and Jacobian types. 
 
Real _relative_tolerance_square
 
auto make_realvector_adaptor(R &residual, J &jacobian)
 
void linear(const NSReal &A, NSReal &x, const NSReal &b) const
 
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
 
void setAbsoluteTolerance(Real abs)
 
static unsigned int minIterationsDefault()
 
static unsigned int maxIterationsDefault()
 
Moose::GenericType< Real, is_ad > NSReal
AD/non-AD switched type shortcuts. 
 
static Real absoluteToleranceDefault()
 
static Real acceptableMultiplierDefault()
 
typename NestedSolveTempl< is_ad >::DynamicVector V
 
int operator()(V &guess, V &residual)
 
unsigned int _max_damping_iterations
 
Adaptor functor for MOOSE RealVectorValue/RankTwoTensor residual and Jacobian types. 
 
void nonlinearDamped(V &guess, T &&compute, C &&computeCondition)
Solve the N*N nonlinear equation system using the damped Netwon-Raphson loop. 
 
int df(V &guess, typename NestedSolveTempl< is_ad >::template CorrespondingJacobian< V > &jacobian)
 
NestedSolveTempl< true > ADNestedSolve
 
NestedSolveTempl< false >::DynamicMatrix type
 
Moose::GenericType< RealVectorValue, is_ad > NSRealVectorValue
 
typename NestedSolveTempl< is_ad >::DynamicVector V
 
auto index_range(const T &sizable)
 
CTSub CT_OPERATOR_BINARY CTMul CTCompareLess CTCompareGreater CTCompareEqual _arg template pow< 2 >(tan(_arg))+1.0) *_arg.template D< dtag >()) CT_SIMPLE_UNARY_FUNCTION(sqrt
 
const State & getState() const
Get the solver state. 
 
int df(V &guess, typename NestedSolveTempl< is_ad >::template CorrespondingJacobian< V > &jacobian)
 
Real _damping_factor
Damping factor.