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