Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
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. ",
89  _num_models);
90 }
91 
92 void
94 {
96  _inelastic_strain[_qp].zero();
97 }
98 
99 void
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 
134 void
136 {
137  if (_damage_model)
138  {
142  }
143 
145 
146  if (_damage_model)
147  {
152 
153  const Real damage_timestep_limit = _damage_model->computeTimeStepLimit();
154  if (_material_timestep_limit[_qp] > damage_timestep_limit)
155  _material_timestep_limit[_qp] = damage_timestep_limit;
156  }
157 
160 }
161 
162 void
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)
179  paramError(
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 
207 void
209 {
215 }
216 
217 void
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 
339  _material_timestep_limit[_qp] = std::numeric_limits<Real>::max();
340  else
342 }
343 
344 void
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)
362  paramError(
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 
388 void
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],
412  _stress_old[_qp],
415  }
416  else
417  _models[model_number]->updateState(elastic_strain_increment,
418  inelastic_strain_increment,
420  _stress[_qp],
421  _stress_old[_qp],
424 }
const std::vector< Real > _inelastic_weights
_inelastic_strain = sum_i (_inelastic_weights_i * inelastic_strain_from_model_i)
virtual bool requiresIsotropicTensor()=0
Does the model require the elasticity tensor to be isotropic?
ADComputeMultipleInelasticStress(const InputParameters &parameters)
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
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...
ADMaterialProperty< RankTwoTensor > & _rotation_total
Rotation up to current step "n" to compute anisotropic elasticity tensor.
virtual void updateDamage()
Update the internal variable(s) that evolve the damage.
Definition: DamageBase.C:48
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
T L2norm(const RankTwoTensorTempl< T > &r2tensor)
const MaterialProperty< RankTwoTensor > & _inelastic_strain_old
old value of inelastic strain
ADMaterialProperty< RankTwoTensor > & _inelastic_strain
The sum of the inelastic strains that come from the plastic models.
ADMaterialProperty< R2 > & _stress
The stress tensor to be calculated.
virtual void computeQpStressIntermediateConfiguration()
Compute the stress for the current QP, but do not rotate tensors from the intermediate configuration ...
ADComputeMultipleInelasticStress computes the stress and a decomposition of the strain into elastic a...
virtual void computeUndamagedOldStress(RankTwoTensor &stress_old)=0
const bool _perform_finite_strain_rotations
after updateQpState, rotate the stress, elastic_strain, and inelastic_strain using _rotation_incremen...
auto raw_value(const Eigen::Map< T > &in)
static constexpr std::size_t dim
void setQp(unsigned int qp)
Sets the value of the member variable _qp for use in inheriting classes.
Definition: DamageBase.C:41
const Number zero
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual void updateStressForDamage(GenericRankTwoTensor< is_ad > &stress_new)=0
Update the current stress tensor for effects of damage.
bool isParamValid(const std::string &name) const
unsigned int _qp
const ADMaterialProperty< RankTwoTensor > & _rotation_increment
int & _t_step
MaterialBase & getMaterial(const std::string &name)
const ADMaterialProperty< R4 > & _elasticity_tensor
Elasticity tensor material property.
registerMooseObject("SolidMechanicsApp", ADComputeMultipleInelasticStress)
const MaterialProperty< RankTwoTensor > & _rotation_total_old
Rotation up to "n - 1" (previous) step to compute anisotropic elasticity tensor.
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 std::string _elasticity_tensor_name
Name of the elasticity tensor material property.
const unsigned int _max_iterations
Input parameters associated with the recompute iteration to return the stress state to the yield surf...
Real & _t
void paramError(const std::string &param, Args... args) const
ADComputeFiniteStrainElasticStress computes the stress following elasticity theory for finite strains...
StressUpdateBase is a material that is not called by MOOSE because of the compute=false flag set in t...
const std::string _name
void rotate(const TypeTensor< T > &R)
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-")
MaterialBase & getMaterialByName(const std::string &name, bool no_warn=false, bool no_dep=false)
std::vector< ADStressUpdateBase * > _models
The user supplied list of inelastic models to use in the simulation.
virtual void finiteStrainRotation(const GenericRankTwoTensor< is_ad > &rotation_increment)
Perform any necessary rotation of internal variables for finite strain.
Definition: DamageBase.C:61
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool _is_elasticity_tensor_guaranteed_isotropic
is the elasticity tensor guaranteed to be isotropic?
const unsigned _num_models
number of plastic models
IntRange< T > make_range(T beg, T end)
DamageBaseTempl< true > * _damage_model
Pointer to the damage model.
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
ADMaterialProperty< R2 > & _elastic_strain
const ConsoleStream _console
bool hasGuaranteedMaterialProperty(const MaterialPropertyName &prop, Guarantee guarantee)
const bool _cycle_models
whether to cycle through the models, using only one model per timestep
const MaterialProperty< R2 > & _stress_old
The old stress tensor.
const MaterialProperty< R2 > & _elastic_strain_old
The old elastic strain is used to calculate the old stress in the case of variable elasticity tensors...
virtual Real computeTimeStepLimit()
Compute the limiting value of the time step for this material.
Definition: DamageBase.C:54
void ErrorVector unsigned int
const Elem & get(const ElemType type_in)
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 finiteStrainRotation()
Rotate _elastic_strain, _stress, and _inelastic_strain to the new configuration.