www.mooseframework.org
FiniteStrainPlasticMaterial.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 "libmesh/utility.h"
12 
14 
17 {
19 
20  params.addRequiredParam<std::vector<Real>>(
21  "yield_stress",
22  "Input data as pairs of equivalent plastic strain and yield stress: Should "
23  "start with equivalent plastic strain 0");
24  params.addParam<Real>("rtol", 1e-8, "Plastic strain NR tolerance");
25  params.addParam<Real>("ftol", 1e-4, "Consistency condition NR tolerance");
26  params.addParam<Real>("eptol", 1e-7, "Equivalent plastic strain NR tolerance");
27  params.addClassDescription("Associative J2 plasticity with isotropic hardening.");
28 
29  return params;
30 }
31 
33  : ComputeStressBase(parameters),
34  _yield_stress_vector(getParam<std::vector<Real>>("yield_stress")), // Read from input file
35  _plastic_strain(declareProperty<RankTwoTensor>(_base_name + "plastic_strain")),
36  _plastic_strain_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "plastic_strain")),
37  _eqv_plastic_strain(declareProperty<Real>(_base_name + "eqv_plastic_strain")),
38  _eqv_plastic_strain_old(getMaterialPropertyOld<Real>(_base_name + "eqv_plastic_strain")),
39  _stress_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "stress")),
40  _strain_increment(getMaterialProperty<RankTwoTensor>(_base_name + "strain_increment")),
41  _rotation_increment(getMaterialProperty<RankTwoTensor>(_base_name + "rotation_increment")),
42  _elasticity_tensor_name(_base_name + "elasticity_tensor"),
43  _elasticity_tensor(getMaterialPropertyByName<RankFourTensor>(_elasticity_tensor_name)),
44  _rtol(getParam<Real>("rtol")),
45  _ftol(getParam<Real>("ftol")),
46  _eptol(getParam<Real>("eptol")),
47  _deltaOuter(RankTwoTensor::Identity().times<i_, j_, k_, l_>(RankTwoTensor::Identity())),
48  _deltaMixed(RankTwoTensor::Identity().times<i_, k_, j_, l_>(RankTwoTensor::Identity()))
49 {
50 }
51 
52 void
54 {
56  _plastic_strain[_qp].zero();
57  _eqv_plastic_strain[_qp] = 0.0;
58 }
59 
60 void
62 {
63 
64  // perform the return-mapping algorithm
70  _stress[_qp],
73 
74  // Rotate the stress tensor to the current configuration
76 
77  // Rotate plastic strain tensor to the current configuration
80 
81  // Calculate the elastic strain_increment
83 
85 }
86 
148 void
150  const Real eqvpstrain_old,
151  const RankTwoTensor & plastic_strain_old,
152  const RankTwoTensor & delta_d,
153  const RankFourTensor & E_ijkl,
154  RankTwoTensor & sig,
155  Real & eqvpstrain,
156  RankTwoTensor & plastic_strain)
157 {
158  // the yield function, must be non-positive
159  // Newton-Raphson sets this to zero if trial stress enters inadmissible region
160  Real f;
161 
162  // the consistency parameter, must be non-negative
163  // change in plastic strain in this timestep = flow_incr*flow_potential
164  Real flow_incr = 0.0;
165 
166  // direction of flow defined by the potential
167  RankTwoTensor flow_dirn;
168 
169  // Newton-Raphson sets this zero
170  // resid_ij = flow_incr*flow_dirn_ij - (plastic_strain - plastic_strain_old)
171  RankTwoTensor resid;
172 
173  // Newton-Raphson sets this zero
174  // rep = -flow_incr*internalPotential - (eqvpstrain - eqvpstrain_old)
175  Real rep;
176 
177  // change in the stress (sig) in a Newton-Raphson iteration
178  RankTwoTensor ddsig;
179 
180  // change in the consistency parameter in a Newton-Raphson iteration
181  Real dflow_incr = 0.0;
182 
183  // change in equivalent plastic strain in one Newton-Raphson iteration
184  Real deqvpstrain = 0.0;
185 
186  // convenience variable that holds the change in plastic strain incurred during the return
187  // delta_dp = plastic_strain - plastic_strain_old
188  // delta_dp = E^{-1}*(trial_stress - sig), where trial_stress = E*(strain - plastic_strain_old)
189  RankTwoTensor delta_dp;
190 
191  // d(yieldFunction)/d(stress)
192  RankTwoTensor df_dsig;
193 
194  // d(resid_ij)/d(sigma_kl)
195  RankFourTensor dr_dsig;
196 
197  // dr_dsig_inv_ijkl*dr_dsig_klmn = 0.5*(de_ij de_jn + de_ij + de_jm), where de_ij = 1 if i=j, but
198  // zero otherwise
199  RankFourTensor dr_dsig_inv;
200 
201  // d(yieldFunction)/d(eqvpstrain)
202  Real fq;
203 
204  // yield stress at the start of this "time step" (ie, evaluated with
205  // eqvpstrain_old). It is held fixed during the Newton-Raphson return,
206  // even if eqvpstrain != eqvpstrain_old.
207  Real yield_stress;
208 
209  // measures of whether the Newton-Raphson process has converged
210  Real err1, err2, err3;
211 
212  // number of Newton-Raphson iterations performed
213  unsigned int iter = 0;
214 
215  // maximum number of Newton-Raphson iterations allowed
216  unsigned int maxiter = 100;
217 
218  // plastic loading occurs if yieldFunction > toly
219  Real toly = 1.0e-8;
220 
221  // Assume this strain increment does not induce any plasticity
222  // This is the elastic-predictor
223  sig = sig_old + E_ijkl * delta_d; // the trial stress
224  eqvpstrain = eqvpstrain_old;
225  plastic_strain = plastic_strain_old;
226 
227  yield_stress = getYieldStress(eqvpstrain); // yield stress at this equivalent plastic strain
228  if (yieldFunction(sig, yield_stress) > toly)
229  {
230  // the sig just calculated is inadmissable. We must return to the yield surface.
231  // This is done iteratively, using a Newton-Raphson process.
232 
233  delta_dp.zero();
234 
235  sig = sig_old + E_ijkl * delta_d; // this is the elastic predictor
236 
237  flow_dirn = flowPotential(sig);
238 
239  resid = flow_dirn * flow_incr - delta_dp; // Residual 1 - refer Hughes Simo
240  f = yieldFunction(sig, yield_stress);
241  rep = -eqvpstrain + eqvpstrain_old - flow_incr * internalPotential(); // Residual 3 rep=0
242 
243  err1 = resid.L2norm();
244  err2 = std::abs(f);
245  err3 = std::abs(rep);
246 
247  while ((err1 > _rtol || err2 > _ftol || err3 > _eptol) &&
248  iter < maxiter) // Stress update iteration (hardness fixed)
249  {
250  iter++;
251 
252  df_dsig = dyieldFunction_dstress(sig);
253  getJac(sig, E_ijkl, flow_incr, dr_dsig); // gets dr_dsig = d(resid_ij)/d(sig_kl)
254  fq = dyieldFunction_dinternal(eqvpstrain); // d(f)/d(eqvpstrain)
255 
267  dr_dsig_inv = dr_dsig.invSymm();
268 
276  dflow_incr = (f - df_dsig.doubleContraction(dr_dsig_inv * resid) + fq * rep) /
277  (df_dsig.doubleContraction(dr_dsig_inv * flow_dirn) - fq);
278  ddsig =
279  dr_dsig_inv *
280  (-resid -
281  flow_dirn * dflow_incr); // from solving the top row of linear system, given dflow_incr
282  deqvpstrain =
283  rep + dflow_incr; // from solving the bottom row of linear system, given dflow_incr
284 
285  // update the variables
286  flow_incr += dflow_incr;
287  delta_dp -= E_ijkl.invSymm() * ddsig;
288  sig += ddsig;
289  eqvpstrain += deqvpstrain;
290 
291  // evaluate the RHS equations ready for next Newton-Raphson iteration
292  flow_dirn = flowPotential(sig);
293  resid = flow_dirn * flow_incr - delta_dp;
294  f = yieldFunction(sig, yield_stress);
295  rep = -eqvpstrain + eqvpstrain_old - flow_incr * internalPotential();
296 
297  err1 = resid.L2norm();
298  err2 = std::abs(f);
299  err3 = std::abs(rep);
300  }
301 
302  if (iter >= maxiter)
303  mooseError("Constitutive failure");
304 
305  plastic_strain += delta_dp;
306  }
307 }
308 
309 Real
310 FiniteStrainPlasticMaterial::yieldFunction(const RankTwoTensor & stress, const Real yield_stress)
311 {
312  return getSigEqv(stress) - yield_stress;
313 }
314 
317 {
319  deriv *= std::sqrt(3.0 / sig.secondInvariant()) / 2.0;
320  return deriv;
321 }
322 
323 Real
324 FiniteStrainPlasticMaterial::dyieldFunction_dinternal(const Real equivalent_plastic_strain)
325 {
326  return -getdYieldStressdPlasticStrain(equivalent_plastic_strain);
327 }
328 
331 {
332  return dyieldFunction_dstress(sig); // this plasticity model assumes associative flow
333 }
334 
335 Real
337 {
338  return -1;
339 }
340 
341 Real
343 {
344  return std::sqrt(3 * stress.secondInvariant());
345 }
346 
347 // Jacobian for stress update algorithm
348 void
350  const RankFourTensor & E_ijkl,
351  Real flow_incr,
352  RankFourTensor & dresid_dsig)
353 {
354  RankTwoTensor sig_dev, df_dsig, flow_dirn;
355  RankTwoTensor dfi_dft, dfi_dsig;
356  RankFourTensor dft_dsig, dfd_dft, dfd_dsig;
357  Real sig_eqv;
358  Real f1, f2, f3;
359  RankFourTensor temp;
360 
361  sig_dev = sig.deviatoric();
362  sig_eqv = getSigEqv(sig);
363  df_dsig = dyieldFunction_dstress(sig);
364  flow_dirn = flowPotential(sig);
365 
366  f1 = 3.0 / (2.0 * sig_eqv);
367  f2 = f1 / 3.0;
368  f3 = 9.0 / (4.0 * Utility::pow<3>(sig_eqv));
369 
370  dft_dsig = f1 * _deltaMixed - f2 * _deltaOuter - f3 * sig_dev.outerProduct(sig_dev);
371 
372  dfd_dsig = dft_dsig;
373  dresid_dsig = E_ijkl.invSymm() + dfd_dsig * flow_incr;
374 }
375 
376 // Obtain yield stress for a given equivalent plastic strain (input)
377 Real
379 {
380  unsigned nsize;
381 
382  nsize = _yield_stress_vector.size();
383 
384  if (_yield_stress_vector[0] > 0.0 || nsize % 2 > 0) // Error check for input inconsitency
385  mooseError("Error in yield stress input: Should be a vector with eqv plastic strain and yield "
386  "stress pair values.\n");
387 
388  unsigned int ind = 0;
389  Real tol = 1e-8;
390 
391  while (ind < nsize)
392  {
393  if (std::abs(eqpe - _yield_stress_vector[ind]) < tol)
394  return _yield_stress_vector[ind + 1];
395 
396  if (ind + 2 < nsize)
397  {
398  if (eqpe > _yield_stress_vector[ind] && eqpe < _yield_stress_vector[ind + 2])
399  return _yield_stress_vector[ind + 1] +
400  (eqpe - _yield_stress_vector[ind]) /
401  (_yield_stress_vector[ind + 2] - _yield_stress_vector[ind]) *
402  (_yield_stress_vector[ind + 3] - _yield_stress_vector[ind + 1]);
403  }
404  else
405  return _yield_stress_vector[nsize - 1];
406 
407  ind += 2;
408  }
409 
410  return 0.0;
411 }
412 
413 Real
415 {
416  unsigned nsize;
417 
418  nsize = _yield_stress_vector.size();
419 
420  if (_yield_stress_vector[0] > 0.0 || nsize % 2 > 0) // Error check for input inconsitency
421  mooseError("Error in yield stress input: Should be a vector with eqv plastic strain and yield "
422  "stress pair values.\n");
423 
424  unsigned int ind = 0;
425 
426  while (ind < nsize)
427  {
428  if (ind + 2 < nsize)
429  {
430  if (eqpe >= _yield_stress_vector[ind] && eqpe < _yield_stress_vector[ind + 2])
431  return (_yield_stress_vector[ind + 3] - _yield_stress_vector[ind + 1]) /
432  (_yield_stress_vector[ind + 2] - _yield_stress_vector[ind]);
433  }
434  else
435  return 0.0;
436 
437  ind += 2;
438  }
439 
440  return 0.0;
441 }
RankFourTensorTempl< Real > outerProduct(const RankTwoTensorTempl< Real > &b) const
MaterialProperty< RankFourTensor > & _Jacobian_mult
derivative of stress w.r.t. strain (_dstress_dstrain)
RankTwoTensorTempl< Real > dsecondInvariant() const
virtual void computeQpStress()
Compute the stress and store it in the _stress material property for the current quadrature point...
FiniteStrainPlasticMaterial implements rate-independent associative J2 plasticity with isotropic hard...
ComputeStressBase is the base class for stress tensors computed from MOOSE&#39;s strain calculators...
const MaterialProperty< RankTwoTensor > & _strain_increment
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const MaterialProperty< RankTwoTensor > & _mechanical_strain
Mechanical strain material property.
static InputParameters validParams()
const double tol
MaterialProperty< Real > & _eqv_plastic_strain
virtual Real dyieldFunction_dinternal(const Real equivalent_plastic_strain)
Derivative of yieldFunction with respect to the equivalent plastic strain.
virtual void returnMap(const RankTwoTensor &sig_old, const Real eqvpstrain_old, const RankTwoTensor &plastic_strain_old, const RankTwoTensor &delta_d, const RankFourTensor &E_ijkl, RankTwoTensor &sig, Real &eqvpstrain, RankTwoTensor &plastic_strain)
Implements the return map.
virtual RankTwoTensor flowPotential(const RankTwoTensor &stress)
Flow potential, which in this case is just dyieldFunction_dstress because we are doing associative fl...
const MaterialProperty< RankFourTensor > & _elasticity_tensor
Elasticity tensor material property.
ADRealEigenVector< T, D, asd > sqrt(const ADRealEigenVector< T, D, asd > &)
void addRequiredParam(const std::string &name, const std::string &doc_string)
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
RankTwoTensorTempl< Real > deviatoric() const
const MaterialProperty< Real > & _eqv_plastic_strain_old
virtual void initQpStatefulProperties() override
Real deriv(unsigned n, unsigned alpha, unsigned beta, Real x)
Real f(Real x)
Test function for Brents method.
virtual Real yieldFunction(const RankTwoTensor &stress, const Real yield_stress)
Calculates the yield function.
Real getYieldStress(const Real equivalent_plastic_strain)
yield stress as a function of equivalent plastic strain.
Real doubleContraction(const RankTwoTensorTempl< Real > &a) const
FiniteStrainPlasticMaterial(const InputParameters &parameters)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
registerMooseObject("SolidMechanicsApp", FiniteStrainPlasticMaterial)
MaterialProperty< RankTwoTensor > & _elastic_strain
Elastic strain material property.
const MaterialProperty< RankTwoTensor > & _plastic_strain_old
Real getSigEqv(const RankTwoTensor &stress)
Equivalent stress.
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
MaterialProperty< RankTwoTensor > & _stress
Stress material property.
virtual RankTwoTensor dyieldFunction_dstress(const RankTwoTensor &stress)
Derivative of yieldFunction with respect to the stress.
virtual Real internalPotential()
The internal potential.
const MaterialProperty< RankTwoTensor > & _rotation_increment
RankFourTensorTempl< T > invSymm() const
Real getdYieldStressdPlasticStrain(const Real equivalent_plastic_strain)
d(yieldstress)/d(equivalent plastic strain)
MaterialProperty< RankTwoTensor > & _plastic_strain
virtual void getJac(const RankTwoTensor &sig, const RankFourTensor &E_ijkl, Real flow_incr, RankFourTensor &dresid_dsig)
Evaluates the derivative d(resid_ij)/d(sig_kl), where resid_ij = flow_incr*flowPotential_ij - (E^{-1}...
static InputParameters validParams()
const MaterialProperty< RankTwoTensor > & _stress_old
The old stress tensor.