https://mooseframework.inl.gov
ComputeMultipleInelasticStressBase.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 "StressUpdateBase.h"
13 #include "MooseException.h"
14 #include "DamageBase.h"
15 #include "libmesh/int_range.h"
16 
19 {
21  params.addClassDescription("Compute state (stress and internal parameters such as plastic "
22  "strains and internal parameters) using an iterative process. "
23  "Combinations of creep models and plastic models may be used.");
24  params.addParam<unsigned int>("max_iterations",
25  30,
26  "Maximum number of the stress update "
27  "iterations over the stress change after all "
28  "update materials are called");
29  params.addParam<Real>("relative_tolerance",
30  1e-5,
31  "Relative convergence tolerance for the stress "
32  "update iterations over the stress change "
33  "after all update materials are called");
34  params.addParam<Real>("absolute_tolerance",
35  1e-5,
36  "Absolute convergence tolerance for the stress "
37  "update iterations over the stress change "
38  "after all update materials are called");
39  params.addParam<bool>(
40  "internal_solve_full_iteration_history",
41  false,
42  "Set to true to output stress update iteration information over the stress change");
43  params.addParam<bool>("perform_finite_strain_rotations",
44  true,
45  "Tensors are correctly rotated in "
46  "finite-strain simulations. For "
47  "optimal performance you can set "
48  "this to 'false' if you are only "
49  "ever using small strains");
50  MooseEnum tangent_operator("elastic nonlinear", "nonlinear");
51  params.addParam<MooseEnum>(
52  "tangent_operator",
53  tangent_operator,
54  "Type of tangent operator to return. 'elastic': return the "
55  "elasticity tensor. 'nonlinear': return the full, general consistent tangent "
56  "operator.");
57  params.addParam<std::vector<Real>>("combined_inelastic_strain_weights",
58  "The combined_inelastic_strain Material Property is a "
59  "weighted sum of the model inelastic strains. This parameter "
60  "is a vector of weights, of the same length as "
61  "inelastic_models. Default = '1 1 ... 1'. This "
62  "parameter is set to 1 if the number of models = 1");
63  params.addParam<bool>(
64  "cycle_models", false, "At timestep N use only inelastic model N % num_models.");
65  params.addParam<MaterialName>("damage_model", "Name of the damage model");
66 
67  return params;
68 }
69 
71  const InputParameters & parameters)
73  _max_iterations(parameters.get<unsigned int>("max_iterations")),
74  _relative_tolerance(parameters.get<Real>("relative_tolerance")),
75  _absolute_tolerance(parameters.get<Real>("absolute_tolerance")),
76  _internal_solve_full_iteration_history(getParam<bool>("internal_solve_full_iteration_history")),
77  _perform_finite_strain_rotations(getParam<bool>("perform_finite_strain_rotations")),
78  _elastic_strain_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "elastic_strain")),
79  _strain_increment(getMaterialProperty<RankTwoTensor>(_base_name + "strain_increment")),
80  _inelastic_strain(declareProperty<RankTwoTensor>(_base_name + "combined_inelastic_strain")),
81  _inelastic_strain_old(
82  getMaterialPropertyOld<RankTwoTensor>(_base_name + "combined_inelastic_strain")),
83  _tangent_operator_type(getParam<MooseEnum>("tangent_operator").getEnum<TangentOperatorEnum>()),
84  _tangent_calculation_method(TangentCalculationMethod::ELASTIC),
85  _cycle_models(getParam<bool>("cycle_models")),
86  _material_timestep_limit(declareProperty<Real>(_base_name + "material_timestep_limit")),
87  _identity_symmetric_four(RankFourTensor::initIdentitySymmetricFour),
88  _all_models_isotropic(true)
89 {
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<false> *>(&getMaterial("damage_model"))
104  : nullptr;
105 
108 
109  std::vector<MaterialName> models = getInelasticModelNames();
110 
111  _num_models = models.size();
112  _tangent_computation_flag.resize(_num_models, false);
114 
115  _inelastic_weights = isParamValid("combined_inelastic_strain_weights")
116  ? getParam<std::vector<Real>>("combined_inelastic_strain_weights")
117  : std::vector<Real>(_num_models, 1.0);
118 
119  if (_inelastic_weights.size() != _num_models)
120  mooseError("ComputeMultipleInelasticStressBase: combined_inelastic_strain_weights must contain "
121  "the same "
122  "number of entries as inelastic_models ",
123  _inelastic_weights.size(),
124  " ",
125  _num_models);
126 
127  for (const auto i : make_range(_num_models))
128  {
129  StressUpdateBase * rrr = dynamic_cast<StressUpdateBase *>(&getMaterialByName(models[i]));
130 
131  if (rrr)
132  {
133  _models.push_back(rrr);
136  mooseError("Model " + models[i] +
137  " requires an isotropic elasticity tensor, but the one supplied is not "
138  "guaranteed isotropic");
139  }
140  else
141  mooseError("Model " + models[i] +
142  " is not compatible with ComputeMultipleInelasticStressBase");
143  }
144 
145  // Check if tangent calculation methods are consistent. If all models have
146  // TangentOperatorEnum::ELASTIC or tangent_operator is set by the user as elasic, then the tangent
147  // is never calculated: J_tot = C. If PARTIAL and NONE models are present, utilize PARTIAL
148  // formulation: J_tot = (I + J_1 + ... J_N)^-1 C. If FULL and NONE models are present, utilize
149  // FULL formulation: J_tot = J_1 * C^-1 * J_2 * C^-1 * ... J_N * C. If PARTIAL and FULL models are
150  // present, error out.
151 
153  {
154  bool full_present = false;
155  bool partial_present = false;
156  for (const auto i : make_range(_num_models))
157  {
158  if (_models[i]->getTangentCalculationMethod() == TangentCalculationMethod::FULL)
159  {
160  full_present = true;
161  _tangent_computation_flag[i] = true;
163  }
164  else if (_models[i]->getTangentCalculationMethod() == TangentCalculationMethod::PARTIAL)
165  {
166  partial_present = true;
167  _tangent_computation_flag[i] = true;
169  }
170  }
171  if (full_present && partial_present)
172  mooseError("In ",
173  _name,
174  ": Models that calculate the full tangent operator and the partial tangent "
175  "operator are being combined. Either set tangent_operator to elastic, implement "
176  "the corrent tangent formulations, or use different models.");
177  }
178 
179  if (isParamValid("damage_model") && !_damage_model)
180  paramError("damage_model",
181  "Damage Model " + _damage_model->name() +
182  " is not compatible with ComputeMultipleInelasticStressBase");
183 
184  // This check prevents the hierarchy from silently skipping substepping without informing the user
185  for (const auto model_number : index_range(_models))
186  {
187  const bool use_substep = _models[model_number]->substeppingCapabilityRequested();
188  if (use_substep && !_models[model_number]->substeppingCapabilityEnabled())
189  {
190  std::stringstream error_message;
191  error_message << "Usage of substepping has been requested, but the inelastic model "
192  << _models[model_number]->name() << " does not implement substepping yet.";
193  mooseError(error_message.str());
194  }
195  }
196 }
197 
198 void
200 {
201  if (_damage_model)
202  {
206  }
208 
209  if (_damage_model)
210  {
216 
217  const Real damage_timestep_limit = _damage_model->computeTimeStepLimit();
218  if (_material_timestep_limit[_qp] > damage_timestep_limit)
219  _material_timestep_limit[_qp] = damage_timestep_limit;
220  }
221 
224 }
225 
226 void
228 {
229  RankTwoTensor elastic_strain_increment;
230  RankTwoTensor combined_inelastic_strain_increment;
231 
232  if (_num_models == 0)
233  {
235 
236  // If the elasticity tensor values have changed and the tensor is isotropic,
237  // use the old strain to calculate the old stress
240  else
241  {
242  if (_damage_model)
244  else
246  }
249 
250  _material_timestep_limit[_qp] = std::numeric_limits<Real>::max();
251  }
252  else
253  {
254  if (_num_models == 1 || _cycle_models)
256  elastic_strain_increment,
257  combined_inelastic_strain_increment);
258  else
259  updateQpState(elastic_strain_increment, combined_inelastic_strain_increment);
260 
261  _elastic_strain[_qp] = _elastic_strain_old[_qp] + elastic_strain_increment;
262  _inelastic_strain[_qp] = _inelastic_strain_old[_qp] + combined_inelastic_strain_increment;
263  }
264 }
265 
266 void
267 ComputeMultipleInelasticStressBase::finiteStrainRotation(const bool force_elasticity_rotation)
268 {
274 
275  if (force_elasticity_rotation ||
280 }
281 
282 void
284 {
288  {
290  for (const auto i_rmm : make_range(_num_models))
292  mooseAssert(A.isSymmetric(), "Tangent operator isn't symmetric");
293  _Jacobian_mult[_qp] = A.invSymm() * _elasticity_tensor[_qp];
294  }
295  else
296  {
297  const RankFourTensor E_inv = _elasticity_tensor[_qp].invSymm();
299  for (const auto i_rmm : make_range(1u, _num_models))
301  }
302 }
303 
304 void
306  unsigned model_number,
307  RankTwoTensor & elastic_strain_increment,
308  RankTwoTensor & combined_inelastic_strain_increment)
309 {
310  for (auto model : _models)
311  model->setQp(_qp);
312 
313  elastic_strain_increment = _strain_increment[_qp];
314 
315  // If the elasticity tensor values have changed and the tensor is isotropic,
316  // use the old strain to calculate the old stress
318  _stress[_qp] = _elasticity_tensor[_qp] * (_elastic_strain_old[_qp] + elastic_strain_increment);
319  else
320  {
321  if (_damage_model)
322  _stress[_qp] = _undamaged_stress_old + _elasticity_tensor[_qp] * elastic_strain_increment;
323  else
324  _stress[_qp] = _stress_old[_qp] + _elasticity_tensor[_qp] * elastic_strain_increment;
325  }
326 
327  computeAdmissibleState(model_number,
328  elastic_strain_increment,
329  combined_inelastic_strain_increment,
331 
333  {
337  {
339  mooseAssert(A.isSymmetric(), "Tangent operator isn't symmetric");
340  _Jacobian_mult[_qp] = A.invSymm() * _elasticity_tensor[_qp];
341  }
342  else
344  }
345 
346  _material_timestep_limit[_qp] = _models[0]->computeTimeStepLimit();
347 
348  /* propagate internal variables, etc, to this timestep for those inelastic models where
349  * "updateState" is not called */
350  for (const auto i_rmm : make_range(_num_models))
351  if (i_rmm != model_number)
352  _models[i_rmm]->propagateQpStatefulProperties();
353 }
354 
355 void
357  unsigned model_number,
358  RankTwoTensor & elastic_strain_increment,
359  RankTwoTensor & inelastic_strain_increment,
360  RankFourTensor & consistent_tangent_operator)
361 {
362  // Reset properties to the beginning of the time step (necessary if substepping is employed).
363  _models[model_number]->resetIncrementalMaterialProperties();
364 
365  const bool jac = _fe_problem.currentlyComputingJacobian();
366  if (_damage_model)
367  _models[model_number]->updateState(elastic_strain_increment,
368  inelastic_strain_increment,
370  _stress[_qp],
374  (jac && _tangent_computation_flag[model_number]),
375  consistent_tangent_operator);
376  else if (_models[model_number]->substeppingCapabilityEnabled() &&
378  _models[model_number]->updateStateSubstep(elastic_strain_increment,
379  inelastic_strain_increment,
381  _stress[_qp],
382  _stress_old[_qp],
385  (jac && _tangent_computation_flag[model_number]),
386  consistent_tangent_operator);
387  else
388  _models[model_number]->updateState(elastic_strain_increment,
389  inelastic_strain_increment,
391  _stress[_qp],
392  _stress_old[_qp],
395  (jac && _tangent_computation_flag[model_number]),
396  consistent_tangent_operator);
397 
398  if (jac && !_tangent_computation_flag[model_number])
399  {
401  consistent_tangent_operator.zero();
402  else
403  consistent_tangent_operator = _elasticity_tensor[_qp];
404  }
405 }
const bool _cycle_models
whether to cycle through the models, using only one model per timestep
MaterialProperty< RankFourTensor > & _Jacobian_mult
derivative of stress w.r.t. strain (_dstress_dstrain)
bool _is_elasticity_tensor_guaranteed_isotropic
is the elasticity tensor guaranteed to be isotropic?
const RankFourTensor _identity_symmetric_four
Rank four symmetric identity tensor.
virtual void computeQpJacobianMult()
Using _elasticity_tensor[_qp] and the consistent tangent operators, _consistent_tangent_operator[...] computed by the inelastic models, compute _Jacobian_mult[_qp].
virtual bool requiresIsotropicTensor()=0
Does the model require the elasticity tensor to be isotropic?
const MaterialProperty< RankTwoTensor > & _rotation_increment
Rotation increment material property.
virtual std::vector< MaterialName > getInelasticModelNames()=0
virtual void updateDamage()
Update the internal variable(s) that evolve the damage.
Definition: DamageBase.C:48
virtual void updateJacobianMultForDamage(RankFourTensor &jacobian_mult)=0
Update the material constitutive matrix.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual void finiteStrainRotation(const bool force_elasticity_rotation=false)
Rotate _elastic_strain, _stress, _inelastic_strain, and _Jacobian_mult to the new configuration...
ComputeMultipleInelasticStressBase(const InputParameters &parameters)
virtual void computeUndamagedOldStress(RankTwoTensor &stress_old)=0
virtual void updateQpStateSingleModel(unsigned model_number, RankTwoTensor &elastic_strain_increment, RankTwoTensor &combined_inelastic_strain_increment)
An optimised version of updateQpState that gets used when the number of plastic models is unity...
const MaterialProperty< RankFourTensor > & _elasticity_tensor
Elasticity tensor material property.
const MaterialProperty< RankTwoTensor > & _strain_increment
virtual void updateQpState(RankTwoTensor &elastic_strain_increment, RankTwoTensor &combined_inelastic_strain_increment)=0
Given the _strain_increment[_qp], iterate over all of the user-specified recompute materials in order...
std::vector< StressUpdateBase * > _models
The user supplied list of inelastic models to use in the simulation.
void setQp(unsigned int qp)
Sets the value of the member variable _qp for use in inheriting classes.
Definition: DamageBase.C:41
virtual const std::string & name() const
const std::string _elasticity_tensor_name
Name of the elasticity tensor material property.
bool _all_models_isotropic
are all inelastic models inherently isotropic? (not the case for e.g. weak plane plasticity models) ...
virtual void computeAdmissibleState(unsigned model_number, RankTwoTensor &elastic_strain_increment, RankTwoTensor &inelastic_strain_increment, RankFourTensor &consistent_tangent_operator)
Given a trial stress (_stress[_qp]) and a strain increment (elastic_strain_increment) let the model_n...
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
std::vector< RankFourTensor > _consistent_tangent_operator
the consistent tangent operators computed by each plastic model
virtual void initQpStatefulProperties() override
MaterialBase & getMaterial(const std::string &name)
TangentCalculationMethod _tangent_calculation_method
Calculation method for the tangent modulus.
DamageBaseTempl< false > * _damage_model
Pointer to the damage model.
std::vector< bool > _tangent_computation_flag
Flags to compute tangent during updateState call.
virtual bool isIsotropic()
Is the implmented model isotropic? The safe default is &#39;false&#39;.
TangentOperatorEnum
what sort of Tangent operator to calculate
void paramError(const std::string &param, Args... args) const
MaterialProperty< RankTwoTensor > & _inelastic_strain
The sum of the inelastic strains that come from the plastic models.
StressUpdateBase is a material that is not called by MOOSE because of the compute=false flag set in t...
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-")
ComputeFiniteStrainElasticStress computes the stress following elasticity theory for finite strains...
MaterialBase & getMaterialByName(const std::string &name, bool no_warn=false, bool no_dep=false)
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
std::vector< Real > _inelastic_weights
_inelastic_strain = sum_i (_inelastic_weights_i * inelastic_strain_from_model_i)
const MaterialProperty< RankTwoTensor > & _stress_old
Old state of the stress tensor material property.
virtual void computeQpStress() override
Compute the stress and store it in the _stress material property for the current quadrature point...
MaterialProperty< RankTwoTensor > & _elastic_strain
Elastic strain material property.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
const bool _perform_finite_strain_rotations
after updateQpState, rotate the stress, elastic_strain, inelastic_strain and Jacobian_mult using _rot...
MaterialProperty< RankTwoTensor > & _stress
Stress material property.
bool hasGuaranteedMaterialProperty(const MaterialPropertyName &prop, Guarantee guarantee)
const bool & currentlyComputingJacobian() const
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
TangentCalculationMethod
TangentCalculationMethod is an enum that determines the calculation method for the tangent operator...
enum ComputeMultipleInelasticStressBase::TangentOperatorEnum _tangent_operator_type
virtual Real computeTimeStepLimit()
Compute the limiting value of the time step for this material.
Definition: DamageBase.C:54
const MaterialProperty< RankTwoTensor > & _elastic_strain_old
Strain tensors.
void ErrorVector unsigned int
auto index_range(const T &sizable)
const Elem & get(const ElemType type_in)