www.mooseframework.org
ADComputeMultipleInelasticStress.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 #include "ADStressUpdateBase.h"
12 #include "MooseException.h"
13 
15 
17 
18 template <ComputeStage compute_stage>
19 InputParameters
21 {
23  params.addClassDescription("Compute state (stress and internal parameters such as plastic "
24  "strains and internal parameters) using an iterative process. "
25  "Combinations of creep models and plastic models may be used.");
26  params.addParam<unsigned int>("max_iterations",
27  30,
28  "Maximum number of the stress update "
29  "iterations over the stress change after all "
30  "update materials are called");
31  params.addParam<Real>("relative_tolerance",
32  1e-5,
33  "Relative convergence tolerance for the stress "
34  "update iterations over the stress change "
35  "after all update materials are called");
36  params.addParam<Real>("absolute_tolerance",
37  1e-5,
38  "Absolute convergence tolerance for the stress "
39  "update iterations over the stress change "
40  "after all update materials are called");
41  params.addParam<bool>(
42  "internal_solve_full_iteration_history",
43  false,
44  "Set to true to output stress update iteration information over the stress change");
45  params.addParam<bool>("perform_finite_strain_rotations",
46  true,
47  "Tensors are correctly rotated in "
48  "finite-strain simulations. For "
49  "optimal performance you can set "
50  "this to 'false' if you are only "
51  "ever using small strains");
52  params.addRequiredParam<std::vector<MaterialName>>(
53  "inelastic_models",
54  "The material objects to use to calculate stress and inelastic strains. "
55  "Note: specify creep models first and plasticity models second.");
56  params.addParam<std::vector<Real>>("combined_inelastic_strain_weights",
57  "The combined_inelastic_strain Material Property is a "
58  "weighted sum of the model inelastic strains. This parameter "
59  "is a vector of weights, of the same length as "
60  "inelastic_models. Default = '1 1 ... 1'. This "
61  "parameter is set to 1 if the number of models = 1");
62  params.addParam<bool>(
63  "cycle_models", false, "At time step N use only inelastic model N % num_models.");
64  return params;
65 }
66 
67 template <ComputeStage compute_stage>
69  const InputParameters & parameters)
70  : ADComputeFiniteStrainElasticStress<compute_stage>(parameters),
71  _max_iterations(parameters.get<unsigned int>("max_iterations")),
72  _relative_tolerance(parameters.get<Real>("relative_tolerance")),
73  _absolute_tolerance(parameters.get<Real>("absolute_tolerance")),
74  _internal_solve_full_iteration_history(getParam<bool>("internal_solve_full_iteration_history")),
75  _perform_finite_strain_rotations(getParam<bool>("perform_finite_strain_rotations")),
76  _inelastic_strain(declareADProperty<RankTwoTensor>(_base_name + "combined_inelastic_strain")),
77  _inelastic_strain_old(
78  getMaterialPropertyOld<RankTwoTensor>(_base_name + "combined_inelastic_strain")),
79  _num_models(getParam<std::vector<MaterialName>>("inelastic_models").size()),
80  _inelastic_weights(isParamValid("combined_inelastic_strain_weights")
81  ? getParam<std::vector<Real>>("combined_inelastic_strain_weights")
82  : std::vector<Real>(_num_models, true)),
83  _cycle_models(getParam<bool>("cycle_models")),
84  _matl_timestep_limit(declareProperty<Real>("matl_timestep_limit"))
85 {
86  if (_inelastic_weights.size() != _num_models)
87  paramError("combined_inelastic_strain_weights",
88  "must contain the same number of entries as inelastic_models ",
89  _inelastic_weights.size(),
90  " vs. ",
91  _num_models);
92 }
93 
94 template <ComputeStage compute_stage>
95 void
97 {
99  _inelastic_strain[_qp].zero();
100 }
101 
102 template <ComputeStage compute_stage>
103 void
105 {
106  _is_elasticity_tensor_guaranteed_isotropic =
107  this->hasGuaranteedMaterialProperty(_elasticity_tensor_name, Guarantee::ISOTROPIC);
108 
109  std::vector<MaterialName> models = getParam<std::vector<MaterialName>>("inelastic_models");
110 
111  for (unsigned int i = 0; i < _num_models; ++i)
112  {
114  &this->template getMaterialByName<compute_stage>(models[i]));
115 
116  if (rrr)
117  {
118  _models.push_back(rrr);
119  if (rrr->requiresIsotropicTensor() && !_is_elasticity_tensor_guaranteed_isotropic)
120  mooseError("Model " + models[i] +
121  " requires an isotropic elasticity tensor, but the one supplied is not "
122  "guaranteed isotropic");
123  }
124  else
125  mooseError("Model " + models[i] + " is not compatible with ADComputeMultipleInelasticStress");
126  }
127 }
128 
129 template <ComputeStage compute_stage>
130 void
132 {
133  computeQpStressIntermediateConfiguration();
134  if (_perform_finite_strain_rotations)
135  finiteStrainRotation();
136 }
137 
138 template <ComputeStage compute_stage>
139 void
141 {
142  ADRankTwoTensor elastic_strain_increment;
143  ADRankTwoTensor combined_inelastic_strain_increment;
144 
145  if (_num_models == 0)
146  {
147  _elastic_strain[_qp] = _elastic_strain_old[_qp] + _strain_increment[_qp];
148 
149  // If the elasticity tensor values have changed and the tensor is isotropic,
150  // use the old strain to calculate the old stress
151  if (_is_elasticity_tensor_guaranteed_isotropic || !_perform_finite_strain_rotations)
152  _stress[_qp] = _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + _strain_increment[_qp]);
153  else
154  _stress[_qp] = _stress_old[_qp] + _elasticity_tensor[_qp] * _strain_increment[_qp];
155  }
156  else
157  {
158  if (_num_models == 1 || _cycle_models)
159  updateQpStateSingleModel((_t_step - 1) % _num_models,
160  elastic_strain_increment,
161  combined_inelastic_strain_increment);
162  else
163  updateQpState(elastic_strain_increment, combined_inelastic_strain_increment);
164 
165  _elastic_strain[_qp] = _elastic_strain_old[_qp] + elastic_strain_increment;
166  _inelastic_strain[_qp] = _inelastic_strain_old[_qp] + combined_inelastic_strain_increment;
167  }
168 }
169 
170 template <ComputeStage compute_stage>
171 void
173 {
174  _elastic_strain[_qp] =
175  _rotation_increment[_qp] * _elastic_strain[_qp] * _rotation_increment[_qp].transpose();
176  _stress[_qp] = _rotation_increment[_qp] * _stress[_qp] * _rotation_increment[_qp].transpose();
177  _inelastic_strain[_qp] =
178  _rotation_increment[_qp] * _inelastic_strain[_qp] * _rotation_increment[_qp].transpose();
179 }
180 
181 template <ComputeStage compute_stage>
182 void
184  ADRankTwoTensor & elastic_strain_increment,
185  ADRankTwoTensor & combined_inelastic_strain_increment)
186 {
187  if (_internal_solve_full_iteration_history == true)
188  {
189  _console << std::endl
190  << "iteration output for ADComputeMultipleInelasticStress solve:"
191  << " time=" << _t << " int_pt=" << _qp << std::endl;
192  }
193  Real l2norm_delta_stress;
194  Real first_l2norm_delta_stress = 1.0;
195  unsigned int counter = 0;
196 
197  std::vector<ADRankTwoTensor> inelastic_strain_increment;
198  inelastic_strain_increment.resize(_num_models);
199 
200  for (unsigned i_rmm = 0; i_rmm < _models.size(); ++i_rmm)
201  inelastic_strain_increment[i_rmm].zero();
202 
203  ADRankTwoTensor stress_max, stress_min;
204 
205  do
206  {
207  for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
208  {
209  _models[i_rmm]->setQp(_qp);
210 
211  // initially assume the strain is completely elastic
212  elastic_strain_increment = _strain_increment[_qp];
213  // and subtract off all inelastic strain increments calculated so far
214  // except the one that we're about to calculate
215  for (unsigned j_rmm = 0; j_rmm < _num_models; ++j_rmm)
216  if (i_rmm != j_rmm)
217  elastic_strain_increment -= inelastic_strain_increment[j_rmm];
218 
219  // form the trial stress, with the check for changed elasticity constants
220  if (_is_elasticity_tensor_guaranteed_isotropic || !_perform_finite_strain_rotations)
221  _stress[_qp] =
222  _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment);
223  else
224  _stress[_qp] = _stress_old[_qp] + _elasticity_tensor[_qp] * elastic_strain_increment;
225 
226  // given a trial stress (_stress[_qp]) and a strain increment (elastic_strain_increment)
227  // let the i^th model produce an admissible stress (as _stress[_qp]), and decompose
228  // the strain increment into an elastic part (elastic_strain_increment) and an
229  // inelastic part (inelastic_strain_increment[i_rmm])
230  computeAdmissibleState(i_rmm, elastic_strain_increment, inelastic_strain_increment[i_rmm]);
231 
232  if (i_rmm == 0)
233  {
234  stress_max = _stress[_qp];
235  stress_min = _stress[_qp];
236  }
237  else
238  {
239  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
240  {
241  for (unsigned int j = 0; j < LIBMESH_DIM; ++j)
242  {
243  if (_stress[_qp](i, j) > stress_max(i, j))
244  stress_max(i, j) = _stress[_qp](i, j);
245  else if (stress_min(i, j) > _stress[_qp](i, j))
246  stress_min(i, j) = _stress[_qp](i, j);
247  }
248  }
249  }
250  }
251 
252  // now check convergence in the stress:
253  // once the change in stress is within tolerance after each recompute material
254  // consider the stress to be converged
255  l2norm_delta_stress = MetaPhysicL::raw_value((stress_max - stress_min).L2norm());
256  if (counter == 0 && l2norm_delta_stress > 0.0)
257  first_l2norm_delta_stress = l2norm_delta_stress;
258 
259  if (_internal_solve_full_iteration_history == true)
260  {
261  _console << "stress iteration number = " << counter << "\n"
262  << " relative l2 norm delta stress = "
263  << (0 == first_l2norm_delta_stress ? 0
264  : l2norm_delta_stress / first_l2norm_delta_stress)
265  << "\n"
266  << " stress convergence relative tolerance = " << _relative_tolerance << "\n"
267  << " absolute l2 norm delta stress = " << l2norm_delta_stress << "\n"
268  << " stress convergence absolute tolerance = " << _absolute_tolerance << std::endl;
269  }
270  ++counter;
271  } while (counter < _max_iterations && l2norm_delta_stress > _absolute_tolerance &&
272  (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance &&
273  _num_models != 1);
274 
275  if (counter == _max_iterations && l2norm_delta_stress > _absolute_tolerance &&
276  (l2norm_delta_stress / first_l2norm_delta_stress) > _relative_tolerance)
277  mooseException(
278  "In ", _name, ": Max stress iteration hit during ADComputeMultipleInelasticStress solve!");
279 
280  combined_inelastic_strain_increment.zero();
281  for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
282  combined_inelastic_strain_increment +=
283  _inelastic_weights[i_rmm] * inelastic_strain_increment[i_rmm];
284 
285  _matl_timestep_limit[_qp] = 0.0;
286  for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
287  _matl_timestep_limit[_qp] += 1.0 / _models[i_rmm]->computeTimeStepLimit();
288 
289  if (MooseUtils::absoluteFuzzyEqual(_matl_timestep_limit[_qp], 0.0))
290  _matl_timestep_limit[_qp] = std::numeric_limits<Real>::max();
291  else
292  _matl_timestep_limit[_qp] = 1.0 / _matl_timestep_limit[_qp];
293 }
294 
295 template <ComputeStage compute_stage>
296 void
298  unsigned model_number,
299  ADRankTwoTensor & elastic_strain_increment,
300  ADRankTwoTensor & combined_inelastic_strain_increment)
301 {
302  for (auto model : _models)
303  model->setQp(_qp);
304 
305  elastic_strain_increment = _strain_increment[_qp];
306 
307  // If the elasticity tensor values have changed and the tensor is isotropic,
308  // use the old strain to calculate the old stress
309  if (_is_elasticity_tensor_guaranteed_isotropic || !_perform_finite_strain_rotations)
310  _stress[_qp] = _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment);
311  else
312  _stress[_qp] = _stress_old[_qp] + _elasticity_tensor[_qp] * elastic_strain_increment;
313 
314  computeAdmissibleState(
315  model_number, elastic_strain_increment, combined_inelastic_strain_increment);
316 
317  _matl_timestep_limit[_qp] = _models[0]->computeTimeStepLimit();
318 
319  /* propagate internal variables, etc, to this timestep for those inelastic models where
320  * "updateState" is not called */
321  for (unsigned i_rmm = 0; i_rmm < _num_models; ++i_rmm)
322  if (i_rmm != model_number)
323  _models[i_rmm]->propagateQpStatefulProperties();
324 }
325 
326 template <ComputeStage compute_stage>
327 void
329  unsigned model_number,
330  ADRankTwoTensor & elastic_strain_increment,
331  ADRankTwoTensor & inelastic_strain_increment)
332 {
333  _models[model_number]->updateState(elastic_strain_increment,
334  inelastic_strain_increment,
335  _rotation_increment[_qp],
336  _stress[_qp],
337  _stress_old[_qp],
338  _elasticity_tensor[_qp],
339  _elastic_strain_old[_qp]);
340 }
ADComputeMultipleInelasticStress::computeAdmissibleState
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...
Definition: ADComputeMultipleInelasticStress.C:328
ADComputeMultipleInelasticStress.h
defineADLegacyParams
defineADLegacyParams(ADComputeMultipleInelasticStress)
ADComputeMultipleInelasticStress::finiteStrainRotation
virtual void finiteStrainRotation()
Rotate _elastic_strain, _stress, and _inelastic_strain to the new configuration.
Definition: ADComputeMultipleInelasticStress.C:172
ADComputeStressBase::initQpStatefulProperties
virtual void initQpStatefulProperties() override
Definition: ADComputeStressBase.C:53
counter
static unsigned int counter
Definition: ContactPenetrationAuxAction.C:17
ADComputeMultipleInelasticStress::validParams
static InputParameters validParams()
Definition: ADComputeMultipleInelasticStress.C:20
registerADMooseObject
registerADMooseObject("TensorMechanicsApp", ADComputeMultipleInelasticStress)
ADComputeMultipleInelasticStress::_num_models
const unsigned _num_models
number of plastic models
Definition: ADComputeMultipleInelasticStress.h:142
ADComputeMultipleInelasticStress::updateQpState
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...
Definition: ADComputeMultipleInelasticStress.C:183
ADStressUpdateBase.h
ADComputeFiniteStrainElasticStress
ADComputeFiniteStrainElasticStress computes the stress following elasticity theory for finite strains...
Definition: ADComputeFiniteStrainElasticStress.h:25
ADStressUpdateBase
ADStressUpdateBase is a material that is not called by MOOSE because of the compute=false flag set in...
Definition: ADComputeMultipleInelasticStress.h:28
ADComputeMultipleInelasticStress
ADComputeMultipleInelasticStress computes the stress and a decomposition of the strain into elastic a...
Definition: ADComputeMultipleInelasticStress.h:26
ADComputeMultipleInelasticStress::ADComputeMultipleInelasticStress
ADComputeMultipleInelasticStress(const InputParameters &parameters)
Definition: ADComputeMultipleInelasticStress.C:68
ADComputeMultipleInelasticStress::initialSetup
virtual void initialSetup() override
Definition: ADComputeMultipleInelasticStress.C:104
ADComputeMultipleInelasticStress::initQpStatefulProperties
virtual void initQpStatefulProperties() override
Definition: ADComputeMultipleInelasticStress.C:96
ADStressUpdateBase::requiresIsotropicTensor
virtual bool requiresIsotropicTensor()=0
Does the model require the elasticity tensor to be isotropic?
ADComputeMultipleInelasticStress::_inelastic_weights
const std::vector< Real > _inelastic_weights
_inelastic_strain = sum_i (_inelastic_weights_i * inelastic_strain_from_model_i)
Definition: ADComputeMultipleInelasticStress.h:145
ADComputeMultipleInelasticStress::updateQpStateSingleModel
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,...
Definition: ADComputeMultipleInelasticStress.C:297
ADComputeMultipleInelasticStress::computeQpStressIntermediateConfiguration
virtual void computeQpStressIntermediateConfiguration()
Compute the stress for the current QP, but do not rotate tensors from the intermediate configuration ...
Definition: ADComputeMultipleInelasticStress.C:140
RankTwoTensorTempl
Definition: ACGrGrElasticDrivingForce.h:17
ADComputeMultipleInelasticStress::computeQpStress
virtual void computeQpStress() override
Definition: ADComputeMultipleInelasticStress.C:131
RankTwoScalarTools::L2norm
T L2norm(const RankTwoTensorTempl< T > &r2tensor)
Definition: RankTwoScalarTools.h:98
ADComputeFiniteStrainElasticStress::validParams
static InputParameters validParams()
Definition: ADComputeFiniteStrainElasticStress.C:18
Guarantee::ISOTROPIC