13 #include "MooseEnum.h"
14 #include "MooseObject.h"
15 #include "ConsoleStreamInterface.h"
16 #include "Conversion.h"
17 #include "MathUtils.h"
19 #include "DualRealOps.h"
21 #include "libmesh/auto_ptr.h"
30 template <ComputeStage compute_stage>
34 InputParameters params = emptyInputParameters();
35 params.addParam<Real>(
36 "relative_tolerance", 1e-8,
"Relative convergence tolerance for Newton iteration");
37 params.addParam<Real>(
38 "absolute_tolerance", 1e-11,
"Absolute convergence tolerance for Newton iteration");
39 params.addParam<Real>(
"acceptable_multiplier",
41 "Factor applied to relative and absolute "
42 "tolerance for acceptable convergence if "
43 "iterations are no longer making progress");
46 MooseEnum internal_solve_output_on_enum(
"never on_error always",
"on_error");
47 params.addParam<MooseEnum>(
"internal_solve_output_on",
48 internal_solve_output_on_enum,
49 "When to output internal Newton solve information");
50 params.addParam<
bool>(
"internal_solve_full_iteration_history",
52 "Set true to output full internal Newton iteration history at times "
53 "determined by `internal_solve_output_on`. If false, only a summary is "
55 params.addParamNamesToGroup(
"internal_solve_output_on internal_solve_full_iteration_history",
60 template <ComputeStage compute_stage>
62 const InputParameters & parameters)
63 : _check_range(false),
65 _bracket_solution(true),
66 _internal_solve_output_on(
69 _internal_solve_full_iteration_history(
70 parameters.get<bool>(
"internal_solve_full_iteration_history")),
71 _relative_tolerance(parameters.get<Real>(
"relative_tolerance")),
72 _absolute_tolerance(parameters.get<Real>(
"absolute_tolerance")),
73 _acceptable_multiplier(parameters.get<Real>(
"acceptable_multiplier")),
75 _residual_history(_num_resids, std::numeric_limits<Real>::max()),
77 _initial_residual(0.0),
79 _svrms_name(parameters.get<std::string>(
"_object_name"))
83 template <ComputeStage compute_stage>
86 const ADReal & )
const
88 return std::numeric_limits<Real>::lowest();
91 template <ComputeStage compute_stage>
94 const ADReal & )
const
96 return std::numeric_limits<Real>::max();
99 template <ComputeStage compute_stage>
102 const ADReal & effective_trial_stress, ADReal & scalar,
const ConsoleStream & console)
105 std::unique_ptr<std::stringstream> iter_output =
106 (_internal_solve_output_on == InternalSolveOutput::ALWAYS)
107 ? libmesh_make_unique<std::stringstream>()
113 internalSolve(effective_trial_stress,
115 _internal_solve_full_iteration_history ? iter_output.get() :
nullptr);
116 if (solve_state != SolveState::SUCCESS &&
117 _internal_solve_output_on != InternalSolveOutput::ALWAYS)
120 if (_internal_solve_output_on == InternalSolveOutput::NEVER)
121 throw MooseException(
"");
125 iter_output = libmesh_make_unique<std::stringstream>();
130 case SolveState::NAN_INF:
131 *iter_output <<
"Encountered inf or nan in material return mapping iterations.\n";
134 case SolveState::EXCEEDED_ITERATIONS:
135 *iter_output <<
"Exceeded maximum iterations in material return mapping iterations.\n";
139 mooseError(
"Unhandled solver state");
144 if (_internal_solve_full_iteration_history)
145 internalSolve(effective_trial_stress, scalar, iter_output.get());
148 outputIterationSummary(iter_output.get(), _iteration);
149 throw MooseException(iter_output->str());
152 if (_internal_solve_output_on == InternalSolveOutput::ALWAYS)
155 outputIterationSummary(iter_output.get(), _iteration);
156 console << iter_output->str();
160 template <ComputeStage compute_stage>
163 const ADReal effective_trial_stress, ADReal & scalar, std::stringstream * iter_output)
165 scalar = initialGuess(effective_trial_stress);
166 ADReal scalar_old = scalar;
167 ADReal scalar_increment = 0.0;
168 const ADReal min_permissible_scalar = minimumPermissibleValue(effective_trial_stress);
169 const ADReal max_permissible_scalar = maximumPermissibleValue(effective_trial_stress);
170 ADReal scalar_upper_bound = max_permissible_scalar;
171 ADReal scalar_lower_bound = min_permissible_scalar;
174 _initial_residual = _residual = computeResidual(effective_trial_stress, scalar);
176 ADReal residual_old = _residual;
177 Real init_resid_sign = MathUtils::sign(MetaPhysicL::raw_value(_residual));
178 Real reference_residual = computeReferenceResidual(effective_trial_stress, scalar);
180 if (converged(_residual, reference_residual))
182 iterationFinalize(scalar);
183 outputIterationStep(iter_output, effective_trial_stress, scalar, reference_residual);
184 return SolveState::SUCCESS;
187 _residual_history.assign(_num_resids, std::numeric_limits<Real>::max());
188 _residual_history[0] = MetaPhysicL::raw_value(_residual);
190 while (_iteration < _max_its && !converged(_residual, reference_residual) &&
191 !convergedAcceptable(_iteration, reference_residual))
193 scalar_increment = -_residual / computeDerivative(effective_trial_stress, scalar);
194 scalar = scalar_old + scalar_increment;
197 checkPermissibleRange(scalar,
200 min_permissible_scalar,
201 max_permissible_scalar,
204 _residual = computeResidual(effective_trial_stress, scalar);
205 reference_residual = computeReferenceResidual(effective_trial_stress, scalar);
206 iterationFinalize(scalar);
208 if (_bracket_solution)
210 scalar, _residual, init_resid_sign, scalar_upper_bound, scalar_lower_bound, iter_output);
212 if (converged(_residual, reference_residual))
214 outputIterationStep(iter_output, effective_trial_stress, scalar, reference_residual);
219 bool modified_increment =
false;
224 if (residual_old - _residual != 0.0)
226 ADReal alpha = residual_old / (residual_old - _residual);
227 alpha = MathUtils::clamp(alpha, 1.0e-2, 1.0);
231 modified_increment =
true;
232 scalar_increment *= alpha;
234 *iter_output <<
" Line search alpha = " << MetaPhysicL::raw_value(alpha)
235 <<
" increment = " << MetaPhysicL::raw_value(scalar_increment)
241 if (_bracket_solution)
245 if (scalar_old + scalar_increment >= scalar_upper_bound ||
246 scalar_old + scalar_increment <= scalar_lower_bound)
248 if (scalar_upper_bound != max_permissible_scalar &&
249 scalar_lower_bound != min_permissible_scalar)
251 const Real frac = 0.5;
253 (1.0 - frac) * scalar_lower_bound + frac * scalar_upper_bound - scalar_old;
254 modified_increment =
true;
256 *iter_output <<
" Trial scalar_increment exceeded bounds. Setting between "
257 "lower/upper bounds. frac: "
258 << frac << std::endl;
265 if (modified_increment)
267 scalar = scalar_old + scalar_increment;
268 _residual = computeResidual(effective_trial_stress, scalar);
269 reference_residual = computeReferenceResidual(effective_trial_stress, scalar);
270 iterationFinalize(scalar);
272 if (_bracket_solution)
282 outputIterationStep(iter_output, effective_trial_stress, scalar, reference_residual);
285 residual_old = _residual;
287 _residual_history[_iteration % _num_resids] = MetaPhysicL::raw_value(_residual);
290 if (std::isnan(_residual) || std::isinf(MetaPhysicL::raw_value(_residual)))
291 return SolveState::NAN_INF;
293 if (_iteration == _max_its)
294 return SolveState::EXCEEDED_ITERATIONS;
296 return SolveState::SUCCESS;
299 template <ComputeStage compute_stage>
302 const Real reference)
304 const Real residual = MetaPhysicL::raw_value(ad_residual);
305 return (std::abs(residual) <= _absolute_tolerance ||
306 std::abs(residual / reference) <= _relative_tolerance);
309 template <ComputeStage compute_stage>
312 const Real reference)
316 if (it < _num_resids)
322 const Real convergence_history_factor = 10.0;
323 if (std::abs(_residual * convergence_history_factor) <
324 std::abs(_residual_history[(it + 1) % _num_resids]))
329 return converged(_residual / _acceptable_multiplier, reference);
332 template <ComputeStage compute_stage>
336 ADReal & scalar_increment,
337 const ADReal & scalar_old,
338 const ADReal min_permissible_scalar,
339 const ADReal max_permissible_scalar,
340 std::stringstream * iter_output)
342 if (scalar > max_permissible_scalar)
344 scalar_increment = (max_permissible_scalar - scalar_old) / 2.0;
345 scalar = scalar_old + scalar_increment;
347 *iter_output <<
"Scalar greater than maximum ("
348 << MetaPhysicL::raw_value(max_permissible_scalar)
349 <<
") adjusted scalar=" << MetaPhysicL::raw_value(scalar)
350 <<
" scalar_increment=" << MetaPhysicL::raw_value(scalar_increment) << std::endl;
352 else if (scalar < min_permissible_scalar)
354 scalar_increment = (min_permissible_scalar - scalar_old) / 2.0;
355 scalar = scalar_old + scalar_increment;
357 *iter_output <<
"Scalar less than minimum (" << MetaPhysicL::raw_value(min_permissible_scalar)
358 <<
") adjusted scalar=" << MetaPhysicL::raw_value(scalar)
359 <<
" scalar_increment=" << MetaPhysicL::raw_value(scalar_increment) << std::endl;
363 template <ComputeStage compute_stage>
366 const ADReal & residual,
367 const Real init_resid_sign,
368 ADReal & scalar_upper_bound,
369 ADReal & scalar_lower_bound,
370 std::stringstream * iter_output)
373 if (residual * init_resid_sign < 0.0 && scalar < scalar_upper_bound)
375 scalar_upper_bound = scalar;
376 if (scalar_upper_bound < scalar_lower_bound)
378 scalar_upper_bound = scalar_lower_bound;
379 scalar_lower_bound = 0.0;
381 *iter_output <<
" Corrected for scalar_upper_bound < scalar_lower_bound" << std::endl;
386 else if (residual * init_resid_sign > 0.0 && scalar > scalar_lower_bound &&
387 scalar < scalar_upper_bound)
388 scalar_lower_bound = scalar;
391 template <ComputeStage compute_stage>
394 std::stringstream * iter_output,
395 const ADReal & effective_trial_stress,
396 const ADReal & scalar,
397 const Real reference_residual)
401 const unsigned int it = _iteration;
402 const Real residual = MetaPhysicL::raw_value(_residual);
404 *iter_output <<
" iteration=" << it
405 <<
" trial_stress=" << MetaPhysicL::raw_value(effective_trial_stress)
406 <<
" scalar=" << MetaPhysicL::raw_value(scalar) <<
" residual=" << residual
407 <<
" ref_res=" << reference_residual
408 <<
" rel_res=" << std::abs(residual) / reference_residual
409 <<
" rel_tol=" << _relative_tolerance <<
" abs_res=" << std::abs(residual)
410 <<
" abs_tol=" << _absolute_tolerance <<
'\n';
414 template <ComputeStage compute_stage>
417 std::stringstream * iter_output,
const unsigned int total_it)
420 *iter_output <<
"In " << total_it <<
" iterations the residual went from "
421 << MetaPhysicL::raw_value(_initial_residual) <<
" to "
422 << MetaPhysicL::raw_value(_residual) <<
" in '" << _svrms_name <<
"'.\n";