https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ADComputeMultipleInelasticStress.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#include "MooseException.h"
12
14
17{
19 params.addClassDescription("Compute state (stress and internal parameters such as plastic "
20 "strains and internal parameters) using an iterative process. "
21 "Combinations of creep models and plastic models may be used.");
22 params.addParam<unsigned int>("max_iterations",
23 30,
24 "Maximum number of the stress update "
25 "iterations over the stress change after all "
26 "update materials are called");
27 params.addParam<Real>("relative_tolerance",
28 1e-5,
29 "Relative convergence tolerance for the stress "
30 "update iterations over the stress change "
31 "after all update materials are called");
32 params.addParam<Real>("absolute_tolerance",
33 1e-5,
34 "Absolute convergence tolerance for the stress "
35 "update iterations over the stress change "
36 "after all update materials are called");
37 params.addParam<bool>(
38 "internal_solve_full_iteration_history",
39 false,
40 "Set to true to output stress update iteration information over the stress change");
41 params.addParam<bool>("perform_finite_strain_rotations",
42 true,
43 "Tensors are correctly rotated in "
44 "finite-strain simulations. For "
45 "optimal performance you can set "
46 "this to 'false' if you are only "
47 "ever using small strains");
48 params.addRequiredParam<std::vector<MaterialName>>(
49 "inelastic_models",
50 "The material objects to use to calculate stress and inelastic strains. "
51 "Note: specify creep models first and plasticity models second.");
52 params.addParam<std::vector<Real>>("combined_inelastic_strain_weights",
53 "The combined_inelastic_strain Material Property is a "
54 "weighted sum of the model inelastic strains. This parameter "
55 "is a vector of weights, of the same length as "
56 "inelastic_models. Default = '1 1 ... 1'. This "
57 "parameter is set to 1 if the number of models = 1");
58 params.addParam<bool>(
59 "cycle_models", false, "At time step N use only inelastic model N % num_models.");
60 params.addParam<MaterialName>("damage_model", "Name of the damage model");
61
62 return params;
63}
64
66 const InputParameters & parameters)
68 _max_iterations(parameters.get<unsigned int>("max_iterations")),
69 _relative_tolerance(parameters.get<Real>("relative_tolerance")),
70 _absolute_tolerance(parameters.get<Real>("absolute_tolerance")),
71 _internal_solve_full_iteration_history(getParam<bool>("internal_solve_full_iteration_history")),
72 _perform_finite_strain_rotations(getParam<bool>("perform_finite_strain_rotations")),
73 _inelastic_strain(declareADProperty<RankTwoTensor>(_base_name + "combined_inelastic_strain")),
74 _inelastic_strain_old(
75 getMaterialPropertyOld<RankTwoTensor>(_base_name + "combined_inelastic_strain")),
76 _num_models(getParam<std::vector<MaterialName>>("inelastic_models").size()),
77 _inelastic_weights(isParamValid("combined_inelastic_strain_weights")
78 ? getParam<std::vector<Real>>("combined_inelastic_strain_weights")
79 : std::vector<Real>(_num_models, true)),
80 _cycle_models(getParam<bool>("cycle_models")),
81 _material_timestep_limit(declareProperty<Real>(_base_name + "material_timestep_limit")),
82 _is_elasticity_tensor_guaranteed_isotropic(false)
83{
84 if (_inelastic_weights.size() != _num_models)
85 paramError("combined_inelastic_strain_weights",
86 "must contain the same number of entries as inelastic_models ",
87 _inelastic_weights.size(),
88 " vs. ",
90}
91
92void
98
99void
101{
102 _damage_model = isParamValid("damage_model")
103 ? dynamic_cast<DamageBaseTempl<true> *>(&getMaterial("damage_model"))
104 : nullptr;
105
106 if (isParamValid("damage_model") && !_damage_model)
107 paramError("damage_model",
108 "Damage Model " + getMaterial("damage_model").name() +
109 " is not compatible with ADComputeMultipleInelasticStress");
110
113
114 std::vector<MaterialName> models = getParam<std::vector<MaterialName>>("inelastic_models");
115
116 for (unsigned int i = 0; i < _num_models; ++i)
117 {
118 ADStressUpdateBase * rrr =
119 dynamic_cast<ADStressUpdateBase *>(&this->getMaterialByName(models[i]));
120
121 if (rrr)
122 {
123 _models.push_back(rrr);
125 mooseError("Model " + models[i] +
126 " requires an isotropic elasticity tensor, but the one supplied is not "
127 "guaranteed isotropic");
128 }
129 else
130 mooseError("Model " + models[i] + " is not compatible with ADComputeMultipleInelasticStress");
131 }
132}
133
134void
161
162void
164{
165 ADRankTwoTensor elastic_strain_increment;
166 ADRankTwoTensor combined_inelastic_strain_increment;
167
168 if (_num_models == 0)
169 {
171
172 // If the elasticity tensor values have changed and the tensor is isotropic,
173 // use the old strain to calculate the old stress
176 else
177 {
178 if (_damage_model)
180 "damage_model",
181 "Damage models cannot be used with inelastic models and elastic anisotropic behavior");
182
183 ADRankFourTensor elasticity_tensor_rotated = _elasticity_tensor[_qp];
184 elasticity_tensor_rotated.rotate(_rotation_total_old[_qp]);
185
186 _stress[_qp] =
187 elasticity_tensor_rotated * (_elastic_strain_old[_qp] + _strain_increment[_qp]);
188
189 // Update current total rotation matrix to be used in next step
191 }
192 }
193 else
194 {
195 if (_num_models == 1 || _cycle_models)
197 elastic_strain_increment,
198 combined_inelastic_strain_increment);
199 else
200 updateQpState(elastic_strain_increment, combined_inelastic_strain_increment);
201
202 _elastic_strain[_qp] = _elastic_strain_old[_qp] + elastic_strain_increment;
203 _inelastic_strain[_qp] = _inelastic_strain_old[_qp] + combined_inelastic_strain_increment;
204 }
205}
206
207void
216
217void
219 ADRankTwoTensor & elastic_strain_increment,
220 ADRankTwoTensor & combined_inelastic_strain_increment)
221{
223 {
224 _console << std::endl
225 << "iteration output for ADComputeMultipleInelasticStress solve:"
226 << " time=" << _t << " int_pt=" << _qp << std::endl;
227 }
228 Real l2norm_delta_stress;
229 Real first_l2norm_delta_stress = 1.0;
230 unsigned int counter = 0;
231
232 std::vector<ADRankTwoTensor> inelastic_strain_increment;
233 inelastic_strain_increment.resize(_num_models);
234
235 for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
236 inelastic_strain_increment[i_rmm].zero();
237
238 ADRankTwoTensor stress_max, stress_min;
239
240 do
241 {
242 for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
243 {
244 _models[i_rmm]->setQp(_qp);
245
246 // initially assume the strain is completely elastic
247 elastic_strain_increment = _strain_increment[_qp];
248 // and subtract off all inelastic strain increments calculated so far
249 // except the one that we're about to calculate
250 for (unsigned j_rmm = 0; j_rmm < _num_models; ++j_rmm)
251 if (i_rmm != j_rmm)
252 elastic_strain_increment -= inelastic_strain_increment[j_rmm];
253
254 // form the trial stress, with the check for changed elasticity constants
256 _stress[_qp] =
257 _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment);
258 else
259 {
260 if (_damage_model)
261 paramError("damage_model",
262 "Damage models cannot be used with inelastic models and elastic anisotropic "
263 "behavior");
264
265 ADRankFourTensor elasticity_tensor_rotated = _elasticity_tensor[_qp];
266 elasticity_tensor_rotated.rotate(_rotation_total_old[_qp]);
267
268 _stress[_qp] =
269 elasticity_tensor_rotated * (_elastic_strain_old[_qp] + elastic_strain_increment);
270
271 // Update current total rotation matrix to be used in next step
273 }
274 // given a trial stress (_stress[_qp]) and a strain increment (elastic_strain_increment)
275 // let the i^th model produce an admissible stress (as _stress[_qp]), and decompose
276 // the strain increment into an elastic part (elastic_strain_increment) and an
277 // inelastic part (inelastic_strain_increment[i_rmm])
278 computeAdmissibleState(i_rmm, elastic_strain_increment, inelastic_strain_increment[i_rmm]);
279
280 if (i_rmm == 0)
281 {
282 stress_max = _stress[_qp];
283 stress_min = _stress[_qp];
284 }
285 else
286 {
287 for (const auto i : make_range(Moose::dim))
288 {
289 for (const auto j : make_range(Moose::dim))
290 {
291 if (_stress[_qp](i, j) > stress_max(i, j))
292 stress_max(i, j) = _stress[_qp](i, j);
293 else if (stress_min(i, j) > _stress[_qp](i, j))
294 stress_min(i, j) = _stress[_qp](i, j);
295 }
296 }
297 }
298 }
299
300 // now check convergence in the stress:
301 // once the change in stress is within tolerance after each recompute material
302 // consider the stress to be converged
303 l2norm_delta_stress = MetaPhysicL::raw_value((stress_max - stress_min).L2norm());
304 if (counter == 0 && l2norm_delta_stress > 0.0)
305 first_l2norm_delta_stress = l2norm_delta_stress;
306
308 {
309 _console << "stress iteration number = " << counter << "\n"
310 << " relative l2 norm delta stress = "
311 << (0 == first_l2norm_delta_stress ? 0
312 : l2norm_delta_stress / first_l2norm_delta_stress)
313 << "\n"
314 << " stress convergence relative tolerance = " << _relative_tolerance << "\n"
315 << " absolute l2 norm delta stress = " << l2norm_delta_stress << "\n"
316 << " stress convergence absolute tolerance = " << _absolute_tolerance << std::endl;
317 }
318 ++counter;
319
320 } while (counter < _max_iterations && l2norm_delta_stress > _absolute_tolerance &&
321 (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance &&
322 _num_models != 1);
323
324 if (counter == _max_iterations && l2norm_delta_stress > _absolute_tolerance &&
325 (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance)
326 mooseException(
327 "In ", _name, ": Max stress iteration hit during ADComputeMultipleInelasticStress solve!");
328
329 combined_inelastic_strain_increment.zero();
330 for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
331 combined_inelastic_strain_increment +=
332 _inelastic_weights[i_rmm] * inelastic_strain_increment[i_rmm];
333
335 for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
336 _material_timestep_limit[_qp] += 1.0 / _models[i_rmm]->computeTimeStepLimit();
337
338 if (MooseUtils::absoluteFuzzyEqual(_material_timestep_limit[_qp], 0.0))
339 _material_timestep_limit[_qp] = std::numeric_limits<Real>::max();
340 else
342}
343
344void
346 unsigned model_number,
347 ADRankTwoTensor & elastic_strain_increment,
348 ADRankTwoTensor & combined_inelastic_strain_increment)
349{
350 for (auto model : _models)
351 model->setQp(_qp);
352
353 elastic_strain_increment = _strain_increment[_qp];
354
355 // If the elasticity tensor values have changed and the tensor is isotropic,
356 // use the old strain to calculate the old stress
358 _stress[_qp] = _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment);
359 else
360 {
361 if (_damage_model)
363 "damage_model",
364 "Damage models cannot be used with inelastic models and elastic anisotropic behavior");
365
366 ADRankFourTensor elasticity_tensor_rotated = _elasticity_tensor[_qp];
367 elasticity_tensor_rotated.rotate(_rotation_total_old[_qp]);
368
369 _stress[_qp] =
370 elasticity_tensor_rotated * (_elastic_strain_old[_qp] + elastic_strain_increment);
371
372 // Update current total rotation matrix to be used in next step
374 }
375
377 model_number, elastic_strain_increment, combined_inelastic_strain_increment);
378
379 _material_timestep_limit[_qp] = _models[0]->computeTimeStepLimit();
380
381 /* propagate internal variables, etc, to this timestep for those inelastic models where
382 * "updateState" is not called */
383 for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
384 if (i_rmm != model_number)
385 _models[i_rmm]->propagateQpStatefulProperties();
386}
387
388void
390 unsigned model_number,
391 ADRankTwoTensor & elastic_strain_increment,
392 ADRankTwoTensor & inelastic_strain_increment)
393{
394 // Properly update material properties (necessary if substepping is employed).
395 _models[model_number]->resetIncrementalMaterialProperties();
396
397 if (_damage_model)
398 _models[model_number]->updateState(elastic_strain_increment,
399 inelastic_strain_increment,
401 _stress[_qp],
405 else if (_models[model_number]->substeppingCapabilityEnabled() &&
407 {
408 _models[model_number]->updateStateSubstep(elastic_strain_increment,
409 inelastic_strain_increment,
411 _stress[_qp],
415 }
416 else
417 _models[model_number]->updateState(elastic_strain_increment,
418 inelastic_strain_increment,
420 _stress[_qp],
424}
registerMooseObject("SolidMechanicsApp", ADComputeMultipleInelasticStress)
const PertinentGeochemicalSystem model(database, {"H2O", "H+", "HCO3-", "O2(aq)", "Ca++", ">(s)FeOH", "radius_neg1", "radius_neg1.5"}, {"Calcite"}, {}, {"Calcite_asdf"}, {"CH4(aq)"}, {">(s)FeOCa+"}, "O2(aq)", "e-")
void ErrorVector unsigned int
ADComputeFiniteStrainElasticStress computes the stress following elasticity theory for finite strains...
const MaterialProperty< R2 > & _elastic_strain_old
The old elastic strain is used to calculate the old stress in the case of variable elasticity tensors...
const ADMaterialProperty< R4 > & _elasticity_tensor
Elasticity tensor material property.
ADMaterialProperty< RankTwoTensor > & _rotation_total
Rotation up to current step "n" to compute anisotropic elasticity tensor.
const ADMaterialProperty< RankTwoTensor > & _rotation_increment
const MaterialProperty< R2 > & _stress_old
The old stress tensor.
const std::string _elasticity_tensor_name
Name of the elasticity tensor material property.
const MaterialProperty< RankTwoTensor > & _rotation_total_old
Rotation up to "n - 1" (previous) step to compute anisotropic elasticity tensor.
ADComputeMultipleInelasticStress computes the stress and a decomposition of the strain into elastic a...
virtual void finiteStrainRotation()
Rotate _elastic_strain, _stress, and _inelastic_strain to the new configuration.
DamageBaseTempl< true > * _damage_model
Pointer to the damage model.
virtual void updateQpState(ADRankTwoTensor &elastic_strain_increment, ADRankTwoTensor &combined_inelastic_strain_increment)
Given the _strain_increment[_qp], iterate over all of the user-specified recompute materials in order...
const unsigned _num_models
number of plastic models
ADMaterialProperty< RankTwoTensor > & _inelastic_strain
The sum of the inelastic strains that come from the plastic models.
const unsigned int _max_iterations
Input parameters associated with the recompute iteration to return the stress state to the yield surf...
const std::vector< Real > _inelastic_weights
_inelastic_strain = sum_i (_inelastic_weights_i * inelastic_strain_from_model_i)
virtual void updateQpStateSingleModel(unsigned model_number, ADRankTwoTensor &elastic_strain_increment, ADRankTwoTensor &combined_inelastic_strain_increment)
An optimised version of updateQpState that gets used when the number of plastic models is unity,...
std::vector< ADStressUpdateBase * > _models
The user supplied list of inelastic models to use in the simulation.
const bool _cycle_models
whether to cycle through the models, using only one model per timestep
virtual void computeAdmissibleState(unsigned model_number, ADRankTwoTensor &elastic_strain_increment, ADRankTwoTensor &inelastic_strain_increment)
Given a trial stress (_stress[_qp]) and a strain increment (elastic_strain_increment) let the model_n...
virtual void computeQpStressIntermediateConfiguration()
Compute the stress for the current QP, but do not rotate tensors from the intermediate configuration ...
const MaterialProperty< RankTwoTensor > & _inelastic_strain_old
old value of inelastic strain
ADComputeMultipleInelasticStress(const InputParameters &parameters)
const bool _perform_finite_strain_rotations
after updateQpState, rotate the stress, elastic_strain, and inelastic_strain using _rotation_incremen...
bool _is_elasticity_tensor_guaranteed_isotropic
is the elasticity tensor guaranteed to be isotropic?
ADMaterialProperty< R2 > & _stress
The stress tensor to be calculated.
ADMaterialProperty< R2 > & _elastic_strain
const ConsoleStream _console
DamageBase is a base class for damage models, which modify the stress tensor computed by another mode...
Definition DamageBase.h:26
virtual Real computeTimeStepLimit()
Compute the limiting value of the time step for this material.
Definition DamageBase.C:54
void setQp(unsigned int qp)
Sets the value of the member variable _qp for use in inheriting classes.
Definition DamageBase.C:41
virtual void finiteStrainRotation(const GenericRankTwoTensor< is_ad > &rotation_increment)
Perform any necessary rotation of internal variables for finite strain.
Definition DamageBase.C:61
virtual void updateStressForDamage(GenericRankTwoTensor< is_ad > &stress_new)=0
Update the current stress tensor for effects of damage.
virtual void updateDamage()
Update the internal variable(s) that evolve the damage.
Definition DamageBase.C:48
virtual void computeUndamagedOldStress(RankTwoTensor &stress_old)=0
bool hasGuaranteedMaterialProperty(const MaterialPropertyName &prop, Guarantee guarantee)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
unsigned int _qp
MaterialBase & getMaterialByName(const std::string &name, bool no_warn=false, bool no_dep=false)
MaterialBase & getMaterial(const std::string &name)
const std::string & name() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
const std::string & _name
bool isParamValid(const std::string &name) const
void rotate(const TypeTensor< T > &R)
StressUpdateBase is a material that is not called by MOOSE because of the compute=false flag set in t...
virtual bool requiresIsotropicTensor()=0
Does the model require the elasticity tensor to be isotropic?
Real & _t
int & _t_step
auto raw_value(const Eigen::Map< T > &in)
static constexpr std::size_t dim