https://mooseframework.inl.gov
Loading...
Searching...
No Matches
FiniteStrainPlasticMaterial.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 "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
52void
59
60void
62{
63
64 // perform the return-mapping algorithm
70 _stress[_qp],
72 _plastic_strain[_qp]);
73
74 // Rotate the stress tensor to the current configuration
75 _stress[_qp] = _rotation_increment[_qp] * _stress[_qp] * _rotation_increment[_qp].transpose();
76
77 // Rotate plastic strain tensor to the current configuration
78 _plastic_strain[_qp] =
79 _rotation_increment[_qp] * _plastic_strain[_qp] * _rotation_increment[_qp].transpose();
80
81 // Calculate the elastic strain_increment
83
85}
86
148void
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
309Real
310FiniteStrainPlasticMaterial::yieldFunction(const RankTwoTensor & stress, const Real yield_stress)
311{
312 return getSigEqv(stress) - yield_stress;
313}
314
317{
318 RankTwoTensor deriv = sig.dsecondInvariant();
319 deriv *= std::sqrt(3.0 / sig.secondInvariant()) / 2.0;
320 return deriv;
321}
322
323Real
324FiniteStrainPlasticMaterial::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
335Real
340
341Real
343{
344 return std::sqrt(3 * stress.secondInvariant());
345}
346
347// Jacobian for stress update algorithm
348void
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)
377Real
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]) /
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
413Real
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]) /
433 }
434 else
435 return 0.0;
436
437 ind += 2;
438 }
439
440 return 0.0;
441}
Real f(Real x)
Test function for Brents method.
const double tol
registerMooseObject("SolidMechanicsApp", FiniteStrainPlasticMaterial)
void mooseError(Args &&... args)
const MaterialProperty< RankTwoTensor > & _mechanical_strain
Mechanical strain material property.
MaterialProperty< RankFourTensor > & _Jacobian_mult
derivative of stress w.r.t. strain (_dstress_dstrain)
virtual void initQpStatefulProperties() override
MaterialProperty< RankTwoTensor > & _elastic_strain
Elastic strain material property.
MaterialProperty< RankTwoTensor > & _stress
Stress material property.
ComputeStressBase is the base class for stress tensors computed from MOOSE's strain calculators.
static InputParameters validParams()
FiniteStrainPlasticMaterial implements rate-independent associative J2 plasticity with isotropic hard...
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.
const MaterialProperty< RankTwoTensor > & _plastic_strain_old
virtual Real yieldFunction(const RankTwoTensor &stress, const Real yield_stress)
Calculates the yield function.
const MaterialProperty< RankTwoTensor > & _strain_increment
virtual RankTwoTensor flowPotential(const RankTwoTensor &stress)
Flow potential, which in this case is just dyieldFunction_dstress because we are doing associative fl...
virtual void computeQpStress()
Compute the stress and store it in the _stress material property for the current quadrature point.
virtual Real internalPotential()
The internal potential.
virtual RankTwoTensor dyieldFunction_dstress(const RankTwoTensor &stress)
Derivative of yieldFunction with respect to the stress.
const MaterialProperty< RankFourTensor > & _elasticity_tensor
Elasticity tensor material property.
MaterialProperty< RankTwoTensor > & _plastic_strain
Real getYieldStress(const Real equivalent_plastic_strain)
yield stress as a function of equivalent plastic strain.
const MaterialProperty< RankTwoTensor > & _stress_old
The old stress tensor.
FiniteStrainPlasticMaterial(const InputParameters &parameters)
const MaterialProperty< Real > & _eqv_plastic_strain_old
MaterialProperty< Real > & _eqv_plastic_strain
Real getSigEqv(const RankTwoTensor &stress)
Equivalent stress.
const MaterialProperty< RankTwoTensor > & _rotation_increment
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}...
virtual Real dyieldFunction_dinternal(const Real equivalent_plastic_strain)
Derivative of yieldFunction with respect to the equivalent plastic strain.
Real getdYieldStressdPlasticStrain(const Real equivalent_plastic_strain)
d(yieldstress)/d(equivalent plastic strain)
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)
RankFourTensorTempl< T > invSymm() const
T doubleContraction(const RankTwoTensorTempl< T > &a) const
RankFourTensorTempl< T > outerProduct(const RankTwoTensorTempl< T > &b) const
T secondInvariant() const
RankTwoTensorTempl< T > dsecondInvariant() const
RankTwoTensorTempl< T > deviatoric() const