www.mooseframework.org
SingleVariableReturnMappingSolution.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 
12 #include "InputParameters.h"
13 #include "Conversion.h"
14 #include "MooseEnum.h"
15 #include "Moose.h"
16 #include "MathUtils.h"
17 
18 #include "libmesh/auto_ptr.h" // libmesh_make_unique
19 
20 #include <limits>
21 #include <string>
22 #include <cmath>
23 #include <memory>
24 
26 
27 InputParameters
29 {
30  InputParameters params = emptyInputParameters();
31 
32  // Newton iteration control parameters
33  params.addParam<Real>(
34  "relative_tolerance", 1e-8, "Relative convergence tolerance for Newton iteration");
35  params.addParam<Real>(
36  "absolute_tolerance", 1e-11, "Absolute convergence tolerance for Newton iteration");
37  params.addParam<Real>("acceptable_multiplier",
38  10,
39  "Factor applied to relative and absolute "
40  "tolerance for acceptable convergence if "
41  "iterations are no longer making progress");
42 
43  // diagnostic output parameters
44  MooseEnum internal_solve_output_on_enum("never on_error always", "on_error");
45  params.addParam<MooseEnum>("internal_solve_output_on",
46  internal_solve_output_on_enum,
47  "When to output internal Newton solve information");
48  params.addParam<bool>("internal_solve_full_iteration_history",
49  false,
50  "Set true to output full internal Newton iteration history at times "
51  "determined by `internal_solve_output_on`. If false, only a summary is "
52  "output.");
53  params.addParamNamesToGroup("internal_solve_output_on internal_solve_full_iteration_history",
54  "Debug");
55 
56  return params;
57 }
58 
60  const InputParameters & parameters)
61  : _check_range(false),
62  _line_search(true),
63  _bracket_solution(true),
64  _internal_solve_output_on(
65  parameters.get<MooseEnum>("internal_solve_output_on").getEnum<InternalSolveOutput>()),
66  _max_its(1000), // Far larger than ever expected to be needed
67  _internal_solve_full_iteration_history(
68  parameters.get<bool>("internal_solve_full_iteration_history")),
69  _relative_tolerance(parameters.get<Real>("relative_tolerance")),
70  _absolute_tolerance(parameters.get<Real>("absolute_tolerance")),
71  _acceptable_multiplier(parameters.get<Real>("acceptable_multiplier")),
72  _num_resids(30),
73  _residual_history(_num_resids, std::numeric_limits<Real>::max()),
74  _iteration(0),
75  _initial_residual(0.0),
76  _residual(0.0),
77  _svrms_name(parameters.get<std::string>("_object_name"))
78 {
79 }
80 
81 Real
83  const Real /*effective_trial_stress*/) const
84 {
85  return std::numeric_limits<Real>::lowest();
86 }
87 
88 Real
90  const Real /*effective_trial_stress*/) const
91 {
92  return std::numeric_limits<Real>::max();
93 }
94 
95 void
97  Real & scalar,
98  const ConsoleStream & console)
99 {
100  // construct the stringstream here only if the debug level is set to ALL
101  std::unique_ptr<std::stringstream> iter_output =
103  ? libmesh_make_unique<std::stringstream>()
104  : nullptr;
105 
106  // do the internal solve and capture iteration info during the first round
107  // iff full history output is requested regardless of whether the solve failed or succeeded
108  auto solve_state =
109  internalSolve(effective_trial_stress,
110  scalar,
111  _internal_solve_full_iteration_history ? iter_output.get() : nullptr);
112  if (solve_state != SolveState::SUCCESS &&
114  {
115  // output suppressed by user, throw immediately
117  throw MooseException("");
118 
119  // user expects some kind of output, if necessary setup output stream now
120  if (!iter_output)
121  iter_output = libmesh_make_unique<std::stringstream>();
122 
123  // add the appropriate error message to the output
124  switch (solve_state)
125  {
126  case SolveState::NAN_INF:
127  *iter_output << "Encountered inf or nan in material return mapping iterations.\n";
128  break;
129 
131  *iter_output << "Exceeded maximum iterations in material return mapping iterations.\n";
132  break;
133 
134  default:
135  mooseError("Unhandled solver state");
136  }
137 
138  // if full history output is only requested for failed solves we have to repeat
139  // the solve a second time
141  internalSolve(effective_trial_stress, scalar, iter_output.get());
142 
143  // Append summary and throw exception
144  outputIterationSummary(iter_output.get(), _iteration);
145  throw MooseException(iter_output->str());
146  }
147 
149  {
150  // the solve did not fail but the user requested debug output anyways
151  outputIterationSummary(iter_output.get(), _iteration);
152  console << iter_output->str();
153  }
154 }
155 
157 SingleVariableReturnMappingSolution::internalSolve(const Real effective_trial_stress,
158  Real & scalar,
159  std::stringstream * iter_output)
160 {
161  scalar = initialGuess(effective_trial_stress);
162  Real scalar_old = scalar;
163  Real scalar_increment = 0.0;
164  const Real min_permissible_scalar = minimumPermissibleValue(effective_trial_stress);
165  const Real max_permissible_scalar = maximumPermissibleValue(effective_trial_stress);
166  Real scalar_upper_bound = max_permissible_scalar;
167  Real scalar_lower_bound = min_permissible_scalar;
168  _iteration = 0;
169 
170  _initial_residual = _residual = computeResidual(effective_trial_stress, scalar);
171 
172  Real residual_old = _residual;
173  Real init_resid_sign = MathUtils::sign(_residual);
174  Real reference_residual = computeReferenceResidual(effective_trial_stress, scalar);
175 
176  if (converged(_residual, reference_residual))
177  {
178  iterationFinalize(scalar);
180  iter_output, _iteration, effective_trial_stress, scalar, _residual, reference_residual);
181  return SolveState::SUCCESS;
182  }
183 
184  _residual_history.assign(_num_resids, std::numeric_limits<Real>::max());
186 
187  while (_iteration < _max_its && !converged(_residual, reference_residual) &&
188  !convergedAcceptable(_iteration, _residual, reference_residual))
189  {
190  scalar_increment = -_residual / computeDerivative(effective_trial_stress, scalar);
191  scalar = scalar_old + scalar_increment;
192 
193  if (_check_range)
194  checkPermissibleRange(scalar,
195  scalar_increment,
196  scalar_old,
197  min_permissible_scalar,
198  max_permissible_scalar,
199  iter_output);
200 
201  _residual = computeResidual(effective_trial_stress, scalar);
202  reference_residual = computeReferenceResidual(effective_trial_stress, scalar);
203  iterationFinalize(scalar);
204 
205  if (_bracket_solution)
206  updateBounds(
207  scalar, _residual, init_resid_sign, scalar_upper_bound, scalar_lower_bound, iter_output);
208 
209  if (converged(_residual, reference_residual))
210  {
212  iter_output, _iteration, effective_trial_stress, scalar, _residual, reference_residual);
213  break;
214  }
215  else
216  {
217  bool modified_increment = false;
218 
219  // Line Search
220  if (_line_search)
221  {
222  if (residual_old - _residual != 0.0)
223  {
224  Real alpha = residual_old / (residual_old - _residual);
225  alpha = MathUtils::clamp(alpha, 1.0e-2, 1.0);
226 
227  if (alpha != 1.0)
228  {
229  modified_increment = true;
230  scalar_increment *= alpha;
231  if (iter_output)
232  *iter_output << " Line search alpha = " << alpha
233  << " increment = " << scalar_increment << std::endl;
234  }
235  }
236  }
237 
238  if (_bracket_solution)
239  {
240  // Check to see whether trial scalar_increment is outside the bounds, and set it to a point
241  // within the bounds if it is
242  if (scalar_old + scalar_increment >= scalar_upper_bound ||
243  scalar_old + scalar_increment <= scalar_lower_bound)
244  {
245  if (scalar_upper_bound != max_permissible_scalar &&
246  scalar_lower_bound != min_permissible_scalar)
247  {
248  const Real frac = 0.5;
249  scalar_increment =
250  (1.0 - frac) * scalar_lower_bound + frac * scalar_upper_bound - scalar_old;
251  modified_increment = true;
252  if (iter_output)
253  *iter_output << " Trial scalar_increment exceeded bounds. Setting between "
254  "lower/upper bounds. frac: "
255  << frac << std::endl;
256  }
257  }
258  }
259 
260  // Update the trial scalar and recompute residual if the line search or bounds checking
261  // modified the increment
262  if (modified_increment)
263  {
264  scalar = scalar_old + scalar_increment;
265  _residual = computeResidual(effective_trial_stress, scalar);
266  reference_residual = computeReferenceResidual(effective_trial_stress, scalar);
267  iterationFinalize(scalar);
268 
269  if (_bracket_solution)
270  updateBounds(scalar,
271  _residual,
272  init_resid_sign,
273  scalar_upper_bound,
274  scalar_lower_bound,
275  iter_output);
276  }
277  }
278 
280  iter_output, _iteration, effective_trial_stress, scalar, _residual, reference_residual);
281 
282  ++_iteration;
283  residual_old = _residual;
284  scalar_old = scalar;
286  }
287 
288  if (std::isnan(_residual) || std::isinf(_residual))
289  return SolveState::NAN_INF;
290 
291  if (_iteration == _max_its)
293 
294  return SolveState::SUCCESS;
295 }
296 
297 bool
298 SingleVariableReturnMappingSolution::converged(const Real residual, const Real reference)
299 {
300  return (std::abs(residual) <= _absolute_tolerance ||
301  std::abs(residual / reference) <= _relative_tolerance);
302 }
303 
304 bool
306  const Real residual,
307  const Real reference)
308 {
309  // Require that we have at least done _num_resids evaluations before we allow for
310  // acceptable convergence
311  if (it < _num_resids)
312  return false;
313 
314  // Check to see whether the residual has dropped by convergence_history_factor over
315  // the last _num_resids iterations. If it has (which means it's still making progress),
316  // don't consider it to be converged within the acceptable limits.
317  const Real convergence_history_factor = 10.0;
318  if (std::abs(residual * convergence_history_factor) <
319  std::abs(_residual_history[(it + 1) % _num_resids]))
320  return false;
321 
322  // Now that it's determined that progress is not being made, treat it as converged if
323  // we're within the acceptable convergence limits
324  return converged(residual / _acceptable_multiplier, reference);
325 }
326 
327 void
329  const unsigned int it,
330  const Real effective_trial_stress,
331  const Real scalar,
332  const Real residual,
333  const Real reference_residual)
334 {
335  if (iter_output)
336  {
337  *iter_output << " iteration=" << it << " trial_stress=" << effective_trial_stress
338  << " scalar=" << scalar << " residual=" << residual
339  << " ref_res=" << reference_residual
340  << " rel_res=" << std::abs(residual) / reference_residual
341  << " rel_tol=" << _relative_tolerance << " abs_res=" << std::abs(residual)
342  << " abs_tol=" << _absolute_tolerance << '\n';
343  }
344 }
345 
346 void
348  const unsigned int total_it)
349 {
350  if (iter_output)
351  *iter_output << "In " << total_it << " iterations the residual went from " << _initial_residual
352  << " to " << _residual << " in '" << _svrms_name << "'.\n";
353 }
354 
355 void
357  Real & scalar_increment,
358  const Real scalar_old,
359  const Real min_permissible_scalar,
360  const Real max_permissible_scalar,
361  std::stringstream * iter_output)
362 {
363  if (scalar > max_permissible_scalar)
364  {
365  scalar_increment = (max_permissible_scalar - scalar_old) / 2.0;
366  scalar = scalar_old + scalar_increment;
367  if (iter_output)
368  *iter_output << "Scalar greater than maximum (" << max_permissible_scalar
369  << ") adjusted scalar=" << scalar << " scalar_increment=" << scalar_increment
370  << std::endl;
371  }
372  else if (scalar < min_permissible_scalar)
373  {
374  scalar_increment = (min_permissible_scalar - scalar_old) / 2.0;
375  scalar = scalar_old + scalar_increment;
376  if (iter_output)
377  *iter_output << "Scalar less than minimum (" << min_permissible_scalar
378  << ") adjusted scalar=" << scalar << " scalar_increment=" << scalar_increment
379  << std::endl;
380  }
381 }
382 
383 void
385  const Real residual,
386  const Real init_resid_sign,
387  Real & scalar_upper_bound,
388  Real & scalar_lower_bound,
389  std::stringstream * iter_output)
390 {
391  // Update upper/lower bounds as applicable
392  if (residual * init_resid_sign < 0.0 && scalar < scalar_upper_bound)
393  {
394  scalar_upper_bound = scalar;
395  if (scalar_upper_bound < scalar_lower_bound)
396  {
397  scalar_upper_bound = scalar_lower_bound;
398  scalar_lower_bound = 0.0;
399  if (iter_output)
400  *iter_output << " Corrected for scalar_upper_bound < scalar_lower_bound" << std::endl;
401  }
402  }
403  // Don't permit setting scalar_lower_bound > scalar_upper_bound (but do permit the reverse).
404  // This ensures that if we encounter multiple roots, we pick the lowest one.
405  else if (residual * init_resid_sign > 0.0 && scalar > scalar_lower_bound &&
406  scalar < scalar_upper_bound)
407  scalar_lower_bound = scalar;
408 }
SingleVariableReturnMappingSolution::maximumPermissibleValue
virtual Real maximumPermissibleValue(const Real effective_trial_stress) const
Compute the maximum permissible value of the scalar.
Definition: SingleVariableReturnMappingSolution.C:89
SingleVariableReturnMappingSolution::_check_range
bool _check_range
Whether to check to see whether iterative solution is within admissible range, and set within that ra...
Definition: SingleVariableReturnMappingSolution.h:120
SingleVariableReturnMappingSolution::_initial_residual
Real _initial_residual
Residual values, kept as members to retain solver state for summary outputting.
Definition: SingleVariableReturnMappingSolution.h:170
SingleVariableReturnMappingSolution::_bracket_solution
bool _bracket_solution
Whether to save upper and lower bounds of root for scalar, and set solution to the midpoint between t...
Definition: SingleVariableReturnMappingSolution.h:127
SingleVariableReturnMappingSolution::validParams
static InputParameters validParams()
Definition: SingleVariableReturnMappingSolution.C:28
SingleVariableReturnMappingSolution::SolveState::NAN_INF
SingleVariableReturnMappingSolution::_acceptable_multiplier
Real _acceptable_multiplier
Multiplier applied to relative and absolute tolerances for acceptable convergence.
Definition: SingleVariableReturnMappingSolution.h:158
SingleVariableReturnMappingSolution::minimumPermissibleValue
virtual Real minimumPermissibleValue(const Real effective_trial_stress) const
Compute the minimum permissible value of the scalar.
Definition: SingleVariableReturnMappingSolution.C:82
SingleVariableReturnMappingSolution::outputIterationSummary
virtual void outputIterationSummary(std::stringstream *iter_output, const unsigned int total_it)
Output summary information for the convergence history of the model.
Definition: SingleVariableReturnMappingSolution.C:347
SingleVariableReturnMappingSolution::SolveState::SUCCESS
SingleVariableReturnMappingSolution::_iteration
unsigned int _iteration
iteration number
Definition: SingleVariableReturnMappingSolution.h:167
SingleVariableReturnMappingSolution::_max_its
const unsigned int _max_its
Maximum number of return mapping iterations.
Definition: SingleVariableReturnMappingSolution.h:146
SingleVariableReturnMappingSolution::updateBounds
void updateBounds(const Real scalar, const Real residual, const Real init_resid_sign, Real &scalar_upper_bound, Real &scalar_lower_bound, std::stringstream *iter_output)
Update the upper and lower bounds of the root for the effective inelastic strain.
Definition: SingleVariableReturnMappingSolution.C:384
SingleVariableReturnMappingSolution::converged
bool converged(const Real residual, const Real reference)
Check to see whether the residual is within the convergence limits.
Definition: SingleVariableReturnMappingSolution.C:298
SingleVariableReturnMappingSolution::initialGuess
virtual Real initialGuess(const Real)
Compute an initial guess for the value of the scalar.
Definition: SingleVariableReturnMappingSolution.h:64
SingleVariableReturnMappingSolution::InternalSolveOutput::ALWAYS
defineLegacyParams
defineLegacyParams(SingleVariableReturnMappingSolution)
SingleVariableReturnMappingSolution::internalSolve
SolveState internalSolve(const Real effective_trial_stress, Real &scalar, std::stringstream *iter_output=nullptr)
Method called from within this class to perform the actual return mappping iterations.
Definition: SingleVariableReturnMappingSolution.C:157
SingleVariableReturnMappingSolution::InternalSolveOutput::NEVER
SingleVariableReturnMappingSolution::iterationFinalize
virtual void iterationFinalize(Real)
Finalize internal state variables for a model for a given iteration.
Definition: SingleVariableReturnMappingSolution.h:94
SingleVariableReturnMappingSolution::_internal_solve_output_on
enum SingleVariableReturnMappingSolution::InternalSolveOutput _internal_solve_output_on
SingleVariableReturnMappingSolution::_residual
Real _residual
Definition: SingleVariableReturnMappingSolution.h:171
SingleVariableReturnMappingSolution.h
SingleVariableReturnMappingSolution::outputIterationStep
virtual void outputIterationStep(std::stringstream *iter_output, const unsigned int it, const Real effective_trial_stress, const Real scalar, const Real residual, const Real reference_residual)
Output information for a single iteration step to build the convergence history of the model.
Definition: SingleVariableReturnMappingSolution.C:328
SingleVariableReturnMappingSolution::computeDerivative
virtual Real computeDerivative(const Real effective_trial_stress, const Real scalar)=0
Compute the derivative of the residual as a function of the scalar variable.
SingleVariableReturnMappingSolution::_line_search
bool _line_search
Whether to use line searches to improve convergence.
Definition: SingleVariableReturnMappingSolution.h:123
SingleVariableReturnMappingSolution::checkPermissibleRange
void checkPermissibleRange(Real &scalar, Real &scalar_increment, const Real scalar_old, const Real min_permissible_scalar, const Real max_permissible_scalar, std::stringstream *iter_output)
Check to see whether solution is within admissible range, and set it within that range if it is not.
Definition: SingleVariableReturnMappingSolution.C:356
SingleVariableReturnMappingSolution::returnMappingSolve
void returnMappingSolve(const Real effective_trial_stress, Real &scalar, const ConsoleStream &console)
Perform the return mapping iterations.
Definition: SingleVariableReturnMappingSolution.C:96
SingleVariableReturnMappingSolution::_svrms_name
const std::string _svrms_name
MOOSE input name of the object performing the solve.
Definition: SingleVariableReturnMappingSolution.h:175
SingleVariableReturnMappingSolution::computeResidual
virtual Real computeResidual(const Real effective_trial_stress, const Real scalar)=0
Compute the residual for a predicted value of the scalar.
SingleVariableReturnMappingSolution::_internal_solve_full_iteration_history
const bool _internal_solve_full_iteration_history
Whether to output iteration information all the time (regardless of whether iterations converge)
Definition: SingleVariableReturnMappingSolution.h:149
SingleVariableReturnMappingSolution::SolveState::EXCEEDED_ITERATIONS
SingleVariableReturnMappingSolution::_residual_history
std::vector< Real > _residual_history
History of residuals used to check whether progress is still being made on decreasing the residual.
Definition: SingleVariableReturnMappingSolution.h:164
SingleVariableReturnMappingSolution
Base class that provides capability for Newton return mapping iterations on a single variable.
Definition: SingleVariableReturnMappingSolution.h:24
SingleVariableReturnMappingSolution::convergedAcceptable
bool convergedAcceptable(const unsigned int it, const Real residual, const Real reference)
Check to see whether the residual is within acceptable convergence limits.
Definition: SingleVariableReturnMappingSolution.C:305
SingleVariableReturnMappingSolution::_num_resids
const std::size_t _num_resids
Number of residuals to be stored in history.
Definition: SingleVariableReturnMappingSolution.h:161
SingleVariableReturnMappingSolution::computeReferenceResidual
virtual Real computeReferenceResidual(const Real effective_trial_stress, const Real scalar)=0
Compute a reference quantity to be used for checking relative convergence.
SingleVariableReturnMappingSolution::SolveState
SolveState
Definition: SingleVariableReturnMappingSolution.h:137
SingleVariableReturnMappingSolution::_relative_tolerance
Real _relative_tolerance
Relative convergence tolerance.
Definition: SingleVariableReturnMappingSolution.h:152
SingleVariableReturnMappingSolution::_absolute_tolerance
Real _absolute_tolerance
Absolute convergence tolerance.
Definition: SingleVariableReturnMappingSolution.h:155
SingleVariableReturnMappingSolution::SingleVariableReturnMappingSolution
SingleVariableReturnMappingSolution(const InputParameters &parameters)
Definition: SingleVariableReturnMappingSolution.C:59
SingleVariableReturnMappingSolution::InternalSolveOutput
InternalSolveOutput
Definition: SingleVariableReturnMappingSolution.h:130