https://mooseframework.inl.gov
Loading...
Searching...
No Matches
RadialReturnStressUpdate.C
Go to the documentation of this file.
1
2//* This file is part of the MOOSE framework
3//* https://mooseframework.inl.gov
4//*
5//* All rights reserved, see COPYRIGHT for full restrictions
6//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
7//*
8//* Licensed under LGPL 2.1, please see LICENSE for details
9//* https://www.gnu.org/licenses/lgpl-2.1.html
10
12
13#include "MooseMesh.h"
15
16template <bool is_ad>
19{
21 params.addClassDescription("Calculates the effective inelastic strain increment required to "
22 "return the isotropic stress state to a J2 yield surface. This class "
23 "is intended to be a parent class for classes with specific "
24 "constitutive models.");
26 params.addParam<Real>("max_inelastic_increment",
27 1e-4,
28 "The maximum inelastic strain increment allowed in a time step");
29 params.addRequiredParam<std::string>(
30 "effective_inelastic_strain_name",
31 "Name of the material property that stores the effective inelastic strain");
32 params.addParam<bool>("use_substep", false, "Whether to use substepping");
33
34 MooseEnum substeppingType("NONE ERROR_BASED INCREMENT_BASED", "NONE");
35 substeppingType.addDocumentation("NONE", "Do not use substepping");
36 substeppingType.addDocumentation(
37 "ERROR_BASED",
38 "Use substepping with a substep size that will yield, at most, the creep numerical "
39 "integration error given by substep_strain_tolerance.");
40 substeppingType.addDocumentation(
41 "INCREMENT_BASED",
42 "Use substepping with a substep size that will keep each inelastic strain increment below "
43 "the maximum inelastic strain increment allowed in a time step.");
44 params.addParam<MooseEnum>(
45 "use_substepping", substeppingType, "Whether and how to use substepping");
46 params.addParam<bool>(
47 "adaptive_substepping",
48 false,
49 "Use adaptive substepping, where the number of substeps is successively doubled until the "
50 "return mapping model successfully converges or the maximum number of substeps is reached. ");
51
52 params.addDeprecatedParam<bool>(
53 "use_substep", false, "Whether to use substepping", "Use `use_substepping` instead");
54 params.addParam<Real>("substep_strain_tolerance",
55 0.1,
56 "Maximum ratio of the initial elastic strain increment at start of the "
57 "return mapping solve to the maximum inelastic strain allowable in a "
58 "single substep. Reduce this value to increase the number of substeps");
59 params.addParam<bool>("apply_strain", true, "Flag to apply strain. Used for testing.");
61 "effective_inelastic_strain_name substep_strain_tolerance apply_strain", "Advanced");
62 params.addParam<bool>("use_substep_integration_error",
63 false,
64 "If true, it establishes a substep size that will yield, at most,"
65 "the creep numerical integration error given by substep_strain_tolerance.");
66 params.addParam<unsigned>("maximum_number_substeps",
67 25,
68 "The maximum number of substeps allowed before cutting the time step.");
69 return params;
70}
71
72template <bool is_ad>
74 const InputParameters & parameters)
75 : StressUpdateBaseTempl<is_ad>(parameters),
77 _effective_inelastic_strain(this->template declareGenericProperty<Real, is_ad>(
78 this->_base_name +
79 this->template getParam<std::string>("effective_inelastic_strain_name"))),
80 _effective_inelastic_strain_old(this->template getMaterialPropertyOld<Real>(
81 this->_base_name +
82 this->template getParam<std::string>("effective_inelastic_strain_name"))),
83 _max_inelastic_increment(this->template getParam<Real>("max_inelastic_increment")),
84 _substep_tolerance(this->template getParam<Real>("substep_strain_tolerance")),
85 _identity_two(RankTwoTensor::initIdentity),
86 _identity_symmetric_four(RankFourTensor::initIdentitySymmetricFour),
87 _deviatoric_projection_four(_identity_symmetric_four -
88 _identity_two.outerProduct(_identity_two) / 3.0),
89 _apply_strain(this->template getParam<bool>("apply_strain")),
90 _use_substepping(
91 this->template getParam<MooseEnum>("use_substepping").template getEnum<SubsteppingType>()),
92 _adaptive_substepping(this->template getParam<bool>("adaptive_substepping")),
93 _maximum_number_substeps(this->template getParam<unsigned>("maximum_number_substeps"))
94{
95 if (this->_pars.isParamSetByUser("use_substep"))
96 {
97 if (this->_pars.isParamSetByUser("use_substepping"))
98 this->paramError("use_substep",
99 "Remove this parameter and just keep `use_substepping` in the input");
100
101 if (parameters.get<bool>("use_substep"))
102 {
103 if (parameters.get<bool>("use_substep_integration_error"))
105 else
107 }
108 }
109
110 if (this->_pars.isParamSetByUser("maximum_number_substeps") &&
112 this->paramError(
113 "maximum_number_substeps",
114 "The parameter maximum_number_substeps can only be used when the substepping option "
115 "(use_substepping) is not set to NONE");
116
118 this->paramError(
119 "adaptive_substepping",
120 "The parameter adaptive_substepping can only be used when the substepping option "
121 "(use_substepping) is not set to NONE");
122}
123
124template <bool is_ad>
125void
127{
128 _effective_inelastic_strain[_qp] = 0.0;
129}
130
131template <bool is_ad>
132void
134 const GenericReal<is_ad> & /*effective_trial_stress*/,
135 const GenericRankFourTensor<is_ad> & elasticity_tensor)
136{
137 // Set the value of 3 * shear modulus for use as a reference residual value
139}
140
141template <bool is_ad>
142void
144{
145 _effective_inelastic_strain[_qp] = _effective_inelastic_strain_old[_qp];
146}
147
148template <bool is_ad>
149int
151 const GenericRankTwoTensor<is_ad> & strain_increment)
152{
153 // compute an effective elastic strain measure
154 const GenericReal<is_ad> contracted_elastic_strain =
155 strain_increment.doubleContraction(strain_increment);
156 const Real effective_elastic_strain =
157 std::sqrt(3.0 / 2.0 * MetaPhysicL::raw_value(contracted_elastic_strain));
158
159 if (MooseUtils::absoluteFuzzyEqual(effective_elastic_strain, 0.0))
160 return 1;
161
162 if (_use_substepping == SubsteppingType::INCREMENT_BASED)
163 {
164 const Real ratio = effective_elastic_strain / _max_inelastic_increment;
165
166 if (ratio > _substep_tolerance)
167 return std::ceil(ratio / _substep_tolerance);
168 return 1;
169 }
170
171 if (_use_substepping == SubsteppingType::ERROR_BASED)
172 {
173 const Real accurate_time_step_ratio = _substep_tolerance / effective_elastic_strain;
174
175 if (accurate_time_step_ratio < 1.0)
176 return std::ceil(1.0 / accurate_time_step_ratio);
177 return 1;
178 }
179
180 mooseError("calculateNumberSubsteps should not have been called. Notify a developer.");
181}
182
183template <bool is_ad>
184void
186 const RankTwoTensor & /*stress_new*/,
187 RankFourTensor & /*tangent_operator*/)
188{
189 mooseError("computeTangentOperator called: no tangent computation is needed for AD");
190}
191
192template <>
193void
195 const RankTwoTensor & stress_new,
196 RankFourTensor & tangent_operator)
197{
198 if (getTangentCalculationMethod() == TangentCalculationMethod::PARTIAL)
199 {
200 if (MooseUtils::absoluteFuzzyEqual(_effective_inelastic_strain_increment, 0.0))
201 tangent_operator.zero();
202 else
203 {
204 // mu = _three_shear_modulus / 3.0;
205 // norm_dev_stress = ||s_n+1||
206 // effective_trial_stress = von mises trial stress = std::sqrt(3.0 / 2.0) * ||s_n+1^trial||
207 // scalar_effective_inelastic_strain = Delta epsilon^cr_n+1
208 // deriv = derivative of scalar_effective_inelastic_strain w.r.t. von mises stress
209 // deriv = std::sqrt(3.0 / 2.0) partial Delta epsilon^cr_n+1n over partial ||s_n+1^trial||
210
211 mooseAssert(_three_shear_modulus != 0.0, "Shear modulus is zero");
212
213 const RankTwoTensor deviatoric_stress = stress_new.deviatoric();
214 const Real norm_dev_stress_squared = deviatoric_stress.doubleContraction(deviatoric_stress);
215 if (MooseUtils::absoluteFuzzyEqual(norm_dev_stress_squared, 0.0))
216 {
217 tangent_operator.zero();
218 return;
219 }
220 const Real norm_dev_stress = std::sqrt(norm_dev_stress_squared);
221
222 const RankTwoTensor flow_direction = deviatoric_stress / norm_dev_stress;
223 const RankFourTensor flow_direction_dyad = flow_direction.outerProduct(flow_direction);
224 const Real deriv =
225 computeStressDerivative(effective_trial_stress, _effective_inelastic_strain_increment);
226 const Real scalar_one = _three_shear_modulus * _effective_inelastic_strain_increment /
227 std::sqrt(1.5) / norm_dev_stress;
228
229 tangent_operator = scalar_one * _deviatoric_projection_four +
230 (_three_shear_modulus * deriv - scalar_one) * flow_direction_dyad;
231 }
232 }
233}
234
235template <bool is_ad>
236void
238 GenericRankTwoTensor<is_ad> & strain_increment,
239 GenericRankTwoTensor<is_ad> & inelastic_strain_increment,
240 const GenericRankTwoTensor<is_ad> & /*rotation_increment*/,
241 GenericRankTwoTensor<is_ad> & stress_new,
242 const RankTwoTensor & /*stress_old*/,
243 const GenericRankFourTensor<is_ad> & elasticity_tensor,
244 const RankTwoTensor & elastic_strain_old,
245 bool compute_full_tangent_operator,
246 RankFourTensor & tangent_operator)
247{
248 using std::sqrt;
249
250 // compute the deviatoric trial stress and trial strain from the current intermediate
251 // configuration
252 GenericRankTwoTensor<is_ad> deviatoric_trial_stress = stress_new.deviatoric();
253
254 // compute the effective trial stress
255 GenericReal<is_ad> dev_trial_stress_squared =
256 deviatoric_trial_stress.doubleContraction(deviatoric_trial_stress);
257 GenericReal<is_ad> effective_trial_stress = MetaPhysicL::raw_value(dev_trial_stress_squared)
258 ? sqrt(3.0 / 2.0 * dev_trial_stress_squared)
259 : 0.0;
260
261 computeStressInitialize(effective_trial_stress, elasticity_tensor);
262
263 mooseAssert(
264 _three_shear_modulus != 0.0,
265 "Shear modulus is zero. Ensure that the base class computeStressInitialize() is called.");
266
267 // Use Newton iteration to determine the scalar effective inelastic strain increment
268 _effective_inelastic_strain_increment = 0.0;
269 if (!MooseUtils::absoluteFuzzyEqual(effective_trial_stress, 0.0))
270 {
271 this->returnMappingSolve(
272 effective_trial_stress, _effective_inelastic_strain_increment, this->_console);
273 if (_effective_inelastic_strain_increment != 0.0)
274 inelastic_strain_increment =
275 deviatoric_trial_stress *
276 (1.5 * _effective_inelastic_strain_increment / effective_trial_stress);
277 else
278 inelastic_strain_increment.zero();
279 }
280 else
281 inelastic_strain_increment.zero();
282
283 if (_apply_strain)
284 {
285 strain_increment -= inelastic_strain_increment;
286 updateEffectiveInelasticStrain(_effective_inelastic_strain_increment);
287
288 // Use the old elastic strain here because we require tensors used by this class
289 // to be isotropic and this method natively allows for changing in time
290 // elasticity tensors
291 stress_new = elasticity_tensor * (strain_increment + elastic_strain_old);
292 }
293
294 computeStressFinalize(inelastic_strain_increment);
295
296 if constexpr (!is_ad)
297 {
298 if (compute_full_tangent_operator)
299 computeTangentOperator(effective_trial_stress, stress_new, tangent_operator);
300 }
301 else
302 {
303 libmesh_ignore(compute_full_tangent_operator);
304 libmesh_ignore(tangent_operator);
305 }
306}
307
308template <bool is_ad>
309void
311 GenericRankTwoTensor<is_ad> & strain_increment,
312 GenericRankTwoTensor<is_ad> & inelastic_strain_increment,
313 const GenericRankTwoTensor<is_ad> & rotation_increment,
314 GenericRankTwoTensor<is_ad> & stress_new,
315 const RankTwoTensor & stress_old,
316 const GenericRankFourTensor<is_ad> & elasticity_tensor,
317 const RankTwoTensor & elastic_strain_old,
318 unsigned int total_number_substeps,
319 bool compute_full_tangent_operator,
320 RankFourTensor & tangent_operator)
321{
322 using std::sqrt;
323
324 // if only one substep is needed, then call the original update state method
325 if (total_number_substeps == 1)
326 {
327 updateState(strain_increment,
328 inelastic_strain_increment,
329 rotation_increment,
330 stress_new,
331 stress_old,
333 elastic_strain_old,
334 compute_full_tangent_operator,
335 tangent_operator);
336
337 this->storeIncrementalMaterialProperties(total_number_substeps);
338 return;
339 }
340
341 if (total_number_substeps > _maximum_number_substeps)
342 mooseException("The number of substeps computed exceeds 'maximum_number_substeps'.");
343
344 // cut the original timestep
345 _dt = _dt_original / total_number_substeps;
346
347 // initialize the inputs
348 const GenericRankTwoTensor<is_ad> strain_increment_per_step =
349 strain_increment / total_number_substeps;
350 GenericRankTwoTensor<is_ad> sub_stress_new = elasticity_tensor * elastic_strain_old;
351 GenericRankTwoTensor<is_ad> sub_elastic_strain_old = elastic_strain_old;
352
353 // clear the original inputs
354 MathUtils::mooseSetToZero(strain_increment);
355 MathUtils::mooseSetToZero(inelastic_strain_increment);
356 MathUtils::mooseSetToZero(stress_new);
357
358 GenericReal<is_ad> sub_effective_inelastic_strain_increment = 0.0;
359 GenericRankTwoTensor<is_ad> sub_inelastic_strain_increment = inelastic_strain_increment;
360
361 for (unsigned int step = 0; step < total_number_substeps; ++step)
362 {
363 // set up input for this substep
364 GenericRankTwoTensor<is_ad> sub_strain_increment = strain_increment_per_step;
365 sub_stress_new += elasticity_tensor * sub_strain_increment;
366
367 Real effective_sub_stress_new;
368 if constexpr (!is_ad)
369 {
370 // compute effective_sub_stress_new
371 const RankTwoTensor deviatoric_sub_stress_new = sub_stress_new.deviatoric();
372 const Real dev_sub_stress_new_squared =
373 deviatoric_sub_stress_new.doubleContraction(deviatoric_sub_stress_new);
374 effective_sub_stress_new = sqrt(3.0 / 2.0 * dev_sub_stress_new_squared);
375 }
376 else
377 libmesh_ignore(effective_sub_stress_new);
378
379 // update stress and strain based on the strain increment
380 updateState(sub_strain_increment,
381 sub_inelastic_strain_increment,
382 rotation_increment, // not used in updateState
383 sub_stress_new,
384 stress_old, // not used in updateState
386 elastic_strain_old,
387 false);
388 // do not compute tangent until the end of this substep (or not at all for is_ad == true)
389
390 // update strain and stress
391 strain_increment += sub_strain_increment;
392 inelastic_strain_increment += sub_inelastic_strain_increment;
393 sub_elastic_strain_old += sub_strain_increment;
394 sub_stress_new = elasticity_tensor * sub_elastic_strain_old;
395
396 // accumulate scalar_effective_inelastic_strain
397 sub_effective_inelastic_strain_increment += _effective_inelastic_strain_increment;
398
399 if constexpr (!is_ad)
400 computeTangentOperator(effective_sub_stress_new, sub_stress_new, tangent_operator);
401
402 // store incremental material properties for this step
403 this->storeIncrementalMaterialProperties(total_number_substeps);
404 }
405
406 // update stress
407 stress_new = sub_stress_new;
408
409 // update effective inelastic strain
410 updateEffectiveInelasticStrain(sub_effective_inelastic_strain_increment);
411}
412
413template <bool is_ad>
414void
416 GenericRankTwoTensor<is_ad> & strain_increment,
417 GenericRankTwoTensor<is_ad> & inelastic_strain_increment,
418 const GenericRankTwoTensor<is_ad> & rotation_increment,
419 GenericRankTwoTensor<is_ad> & stress_new,
420 const RankTwoTensor & stress_old,
421 const GenericRankFourTensor<is_ad> & elasticity_tensor,
422 const RankTwoTensor & elastic_strain_old,
423 bool compute_full_tangent_operator,
424 RankFourTensor & tangent_operator)
425{
426 unsigned int num_substeps = calculateNumberSubsteps(strain_increment);
427 _dt_original = _dt;
428 while (true)
429 {
430 try
431 {
432 updateStateSubstepInternal(strain_increment,
433 inelastic_strain_increment,
434 rotation_increment,
435 stress_new,
436 stress_old,
438 elastic_strain_old,
439 num_substeps,
440 compute_full_tangent_operator,
441 tangent_operator);
442 }
443 catch (MooseException & e)
444 {
445 // if we are not using adaptive substepping we just rethrow the exception
446 if (!_adaptive_substepping)
447 throw;
448
449 // otherwise we double the number of substeps and try again
450 num_substeps *= 2;
451 if (num_substeps <= _maximum_number_substeps)
452 continue;
453
454 // too meany substeps, break out of the loop
455 break;
456 }
457
458 // updateStateSubstepInternal was successful (didn't throw)
459 _dt = _dt_original;
460 return;
461 }
462
463 // recover the original timestep
464 _dt = _dt_original;
465
466 mooseException("Adaptive substepping failed. Maximum number of substeps exceeded.");
467}
468
469template <bool is_ad>
470Real
472 const GenericReal<is_ad> & effective_trial_stress,
473 const GenericReal<is_ad> & scalar_effective_inelastic_strain)
474{
475 return MetaPhysicL::raw_value(effective_trial_stress / _three_shear_modulus) -
476 MetaPhysicL::raw_value(scalar_effective_inelastic_strain);
477}
478
479template <bool is_ad>
482 const GenericReal<is_ad> & effective_trial_stress) const
483{
484 return effective_trial_stress / _three_shear_modulus;
485}
486
487template <bool is_ad>
488Real
490{
491 const Real scalar_inelastic_strain_incr =
492 std::abs(MetaPhysicL::raw_value(_effective_inelastic_strain[_qp]) -
493 _effective_inelastic_strain_old[_qp]);
494 if (!scalar_inelastic_strain_incr)
495 return std::numeric_limits<Real>::max();
496
497 return _dt * _max_inelastic_increment / scalar_inelastic_strain_incr;
498}
499
500template <bool is_ad>
501void
503 const unsigned int total_it)
504{
505 if (iter_output)
506 {
507 *iter_output << "At element " << _current_elem->id() << " _qp=" << _qp << " Coordinates "
508 << _q_point[_qp] << " block=" << _current_elem->subdomain_id() << '\n';
509 }
511}
512
void mooseError(Args &&... args)
Moose::GenericType< RankFourTensor, is_ad > GenericRankFourTensor
Moose::GenericType< Real, is_ad > GenericReal
Moose::GenericType< RankTwoTensor, is_ad > GenericRankTwoTensor
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
bool isParamSetByUser(const std::string &name) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
void addClassDescription(const std::string &doc_string)
const InputParameters & parameters() const
void paramError(const std::string &param, Args... args) const
const InputParameters & _pars
RadialReturnStressUpdate computes the radial return stress increment for an isotropic elastic-viscopl...
virtual void updateStateSubstepInternal(GenericRankTwoTensor< is_ad > &, GenericRankTwoTensor< is_ad > &, const GenericRankTwoTensor< is_ad > &, GenericRankTwoTensor< is_ad > &, const RankTwoTensor &, const GenericRankFourTensor< is_ad > &, const RankTwoTensor &, unsigned int total_number_substeps, bool compute_full_tangent_operator=false, RankFourTensor &tangent_operator=StressUpdateBaseTempl< is_ad >::_identityTensor)
void computeTangentOperator(Real effective_trial_stress, const RankTwoTensor &stress_new, RankFourTensor &tangent_operator)
Calculate the tangent_operator.
SubsteppingType _use_substepping
Whether user has requested the use of substepping technique to improve convergence [make const later]...
virtual void updateStateSubstep(GenericRankTwoTensor< is_ad > &, GenericRankTwoTensor< is_ad > &, const GenericRankTwoTensor< is_ad > &, GenericRankTwoTensor< is_ad > &, const RankTwoTensor &, const GenericRankFourTensor< is_ad > &, const RankTwoTensor &, bool compute_full_tangent_operator=false, RankFourTensor &tangent_operator=StressUpdateBaseTempl< is_ad >::_identityTensor) override
Similar to the updateState function, this method updates the strain and stress for one substep.
RadialReturnStressUpdateTempl(const InputParameters &parameters)
void propagateQpStatefulPropertiesRadialReturn()
Propagate the properties pertaining to this intermediate class.
virtual Real computeReferenceResidual(const GenericReal< is_ad > &effective_trial_stress, const GenericReal< is_ad > &scalar_effective_inelastic_strain) override
Compute a reference quantity to be used for checking relative convergence.
virtual void computeStressInitialize(const GenericReal< is_ad > &effective_trial_stress, const GenericRankFourTensor< is_ad > &elasticity_tensor)
Perform any necessary initialization before return mapping iterations.
virtual void initQpStatefulProperties() override
virtual GenericReal< is_ad > maximumPermissibleValue(const GenericReal< is_ad > &effective_trial_stress) const override
Compute the maximum permissible value of the scalar.
virtual int calculateNumberSubsteps(const GenericRankTwoTensor< is_ad > &strain_increment) override
If substepping is enabled, calculate the number of substeps as a function of the elastic strain incre...
virtual Real computeTimeStepLimit() override
Compute the limiting value of the time step for this material.
const bool _adaptive_substepping
Use adaptive substepping, cutting substep sizes until convergence is achieved.
void outputIterationSummary(std::stringstream *iter_output, const unsigned int total_it) override
Output summary information for the convergence history of the model.
virtual void updateState(GenericRankTwoTensor< is_ad > &strain_increment, GenericRankTwoTensor< is_ad > &inelastic_strain_increment, const GenericRankTwoTensor< is_ad > &rotation_increment, GenericRankTwoTensor< is_ad > &stress_new, const RankTwoTensor &stress_old, const GenericRankFourTensor< is_ad > &elasticity_tensor, const RankTwoTensor &elastic_strain_old, bool compute_full_tangent_operator=false, RankFourTensor &tangent_operator=StressUpdateBaseTempl< is_ad >::_identityTensor) override
A radial return (J2) mapping method is performed with return mapping iterations.
T doubleContraction(const RankTwoTensorTempl< T > &a) const
RankFourTensorTempl< T > outerProduct(const RankTwoTensorTempl< T > &b) const
RankTwoTensorTempl< T > deviatoric() const
Base class that provides capability for Newton return mapping iterations on a single variable.
virtual void outputIterationSummary(std::stringstream *iter_output, const unsigned int total_it)
Output summary information for the convergence history of the model.
StressUpdateBase is a material that is not called by MOOSE because of the compute=false flag set in t...
static InputParameters validParams()
T getIsotropicShearModulus(const RankFourTensorTempl< T > &elasticity_tensor)
Get the shear modulus for an isotropic elasticity tensor param elasticity_tensor the tensor (must be ...
void mooseSetToZero(T &v)
auto raw_value(const Eigen::Map< T > &in)
Real elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l)