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.