www.mooseframework.org
CappedDruckerPragerStressUpdate.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 
12 #include "libmesh/utility.h"
13 
15 
18 {
20  params.addClassDescription("Capped Drucker-Prager plasticity stress calculator");
21  params.addRequiredParam<UserObjectName>(
22  "DP_model",
23  "A SolidMechanicsPlasticDruckerPrager UserObject that defines the "
24  "Drucker-Prager parameters (cohesion, friction angle and dilation angle)");
25  params.addRequiredParam<UserObjectName>(
26  "tensile_strength",
27  "A SolidMechanicsHardening UserObject that defines hardening of the "
28  "tensile strength. In physical situations this is positive (and always "
29  "must be greater than negative compressive-strength.");
30  params.addRequiredParam<UserObjectName>(
31  "compressive_strength",
32  "A SolidMechanicsHardening UserObject that defines hardening of the "
33  "compressive strength. In physical situations this is positive.");
35  "tip_smoother",
36  "tip_smoother>=0",
37  "The cone vertex at J2 = 0 will be smoothed by the given "
38  "amount. Typical value is 0.1*cohesion");
39  params.addParam<bool>("perfect_guess",
40  true,
41  "Provide a guess to the Newton-Raphson procedure "
42  "that is the result from perfect plasticity. With "
43  "severe hardening/softening this may be "
44  "suboptimal.");
45  params.addParam<bool>("small_dilation",
46  true,
47  "If true, and if the trial stress exceeds the "
48  "tensile strength, then the user guarantees that "
49  "the returned stress will be independent of the "
50  "compressive strength.");
51  return params;
52 }
53 
55  : TwoParameterPlasticityStressUpdate(parameters, 3, 2),
56  _dp(getUserObject<SolidMechanicsPlasticDruckerPrager>("DP_model")),
57  _tstrength(getUserObject<SolidMechanicsHardeningModel>("tensile_strength")),
58  _cstrength(getUserObject<SolidMechanicsHardeningModel>("compressive_strength")),
59  _small_smoother2(Utility::pow<2>(getParam<Real>("tip_smoother"))),
60  _perfect_guess(getParam<bool>("perfect_guess")),
61  _stress_return_type(StressReturnType::nothing_special),
62  _small_dilation(getParam<bool>("small_dilation")),
63  _in_q_trial(0.0)
64 {
65  // With arbitary UserObjects, it is impossible to check everything,
66  // but this will catch the common errors
68  mooseError("CappedDruckerPragerStressUpdate: Tensile strength plus compressive strength must "
69  "be greater than smoothing_tol");
70 }
71 
72 void
74 {
76 }
77 
78 void
80 {
82 }
83 
84 void
86  Real q_trial,
87  const RankTwoTensor & /*stress_trial*/,
88  const std::vector<Real> & /*intnl_old*/,
89  const std::vector<Real> & yf,
90  const RankFourTensor & /*Eijkl*/)
91 {
92  // If it's obvious, then simplify the return-type
93  if (yf[2] >= 0)
95  else if (_small_dilation && yf[1] >= 0)
97 
98  _in_q_trial = q_trial;
99 }
100 
101 void
102 CappedDruckerPragerStressUpdate::computePQ(const RankTwoTensor & stress, Real & p, Real & q) const
103 {
104  p = stress.trace();
105  q = std::sqrt(stress.secondInvariant());
106 }
107 
108 void
110  Real & Epp,
111  Real & Eqq) const
112 {
113  Epp = Eijkl.sum3x3();
114  Eqq = Eijkl(0, 1, 0, 1);
115 }
116 
117 void
119  Real q_trial,
120  Real /*p*/,
121  Real q,
122  const std::vector<Real> & intnl,
123  std::vector<std::vector<Real>> & dintnl) const
124 {
125  Real tanpsi;
126  _dp.onlyB(intnl[0], _dp.dilation, tanpsi);
127  Real dtanpsi;
128  _dp.donlyB(intnl[0], _dp.dilation, dtanpsi);
129  dintnl[0][0] = 0.0;
130  dintnl[0][1] = -1.0 / _Eqq;
131  dintnl[1][0] = -1.0 / _Epp;
132  dintnl[1][1] = tanpsi / _Eqq - (q_trial - q) * dtanpsi * dintnl[0][1] / _Eqq;
133 }
134 
135 void
137  Real q,
138  const std::vector<Real> & intnl,
139  std::vector<Real> & yf) const
140 {
141  Real aaa;
142  Real bbb;
143  _dp.bothAB(intnl[0], aaa, bbb);
144  yf[0] = std::sqrt(Utility::pow<2>(q) + _small_smoother2) + p * bbb - aaa;
145 
147  yf[1] = std::numeric_limits<Real>::lowest();
148  else
149  yf[1] = p - _tstrength.value(intnl[1]);
150 
152  yf[2] = std::numeric_limits<Real>::lowest();
153  else
154  yf[2] = -p - _cstrength.value(intnl[1]);
155 }
156 
157 void
159  Real q,
160  const std::vector<Real> & intnl,
161  std::vector<yieldAndFlow> & all_q) const
162 {
163  Real aaa;
164  Real bbb;
165  _dp.bothAB(intnl[0], aaa, bbb);
166  Real daaa;
167  Real dbbb;
168  _dp.dbothAB(intnl[0], daaa, dbbb);
169  Real tanpsi;
170  _dp.onlyB(intnl[0], _dp.dilation, tanpsi);
171  Real dtanpsi;
172  _dp.donlyB(intnl[0], _dp.dilation, dtanpsi);
173 
174  // yield function values
175  all_q[0].f = std::sqrt(Utility::pow<2>(q) + _small_smoother2) + p * bbb - aaa;
177  all_q[1].f = std::numeric_limits<Real>::lowest();
178  else
179  all_q[1].f = p - _tstrength.value(intnl[1]);
181  all_q[2].f = std::numeric_limits<Real>::lowest();
182  else
183  all_q[2].f = -p - _cstrength.value(intnl[1]);
184 
185  // d(yield Function)/d(p, q)
186  // derivatives wrt p
187  all_q[0].df[0] = bbb;
188  all_q[1].df[0] = 1.0;
189  all_q[2].df[0] = -1.0;
190 
191  // derivatives wrt q
192  if (_small_smoother2 == 0.0)
193  all_q[0].df[1] = 1.0;
194  else
195  all_q[0].df[1] = q / std::sqrt(Utility::pow<2>(q) + _small_smoother2);
196  all_q[1].df[1] = 0.0;
197  all_q[2].df[1] = 0.0;
198 
199  // d(yield Function)/d(intnl)
200  // derivatives wrt intnl[0] (shear plastic strain)
201  all_q[0].df_di[0] = p * dbbb - daaa;
202  all_q[1].df_di[0] = 0.0;
203  all_q[2].df_di[0] = 0.0;
204  // derivatives wrt intnl[q] (tensile plastic strain)
205  all_q[0].df_di[1] = 0.0;
206  all_q[1].df_di[1] = -_tstrength.derivative(intnl[1]);
207  all_q[2].df_di[1] = -_cstrength.derivative(intnl[1]);
208 
209  // d(flowPotential)/d(p, q)
210  // derivatives wrt p
211  all_q[0].dg[0] = tanpsi;
212  all_q[1].dg[0] = 1.0;
213  all_q[2].dg[0] = -1.0;
214  // derivatives wrt q
215  if (_small_smoother2 == 0.0)
216  all_q[0].dg[1] = 1.0;
217  else
218  all_q[0].dg[1] = q / std::sqrt(Utility::pow<2>(q) + _small_smoother2);
219  all_q[1].dg[1] = 0.0;
220  all_q[2].dg[1] = 0.0;
221 
222  // d2(flowPotential)/d(p, q)/d(intnl)
223  // d(dg/dp)/dintnl[0]
224  all_q[0].d2g_di[0][0] = dtanpsi;
225  all_q[1].d2g_di[0][0] = 0.0;
226  all_q[2].d2g_di[0][0] = 0.0;
227  // d(dg/dp)/dintnl[1]
228  all_q[0].d2g_di[0][1] = 0.0;
229  all_q[1].d2g_di[0][1] = 0.0;
230  all_q[2].d2g_di[0][1] = 0.0;
231  // d(dg/dq)/dintnl[0]
232  all_q[0].d2g_di[1][0] = 0.0;
233  all_q[1].d2g_di[1][0] = 0.0;
234  all_q[2].d2g_di[1][0] = 0.0;
235  // d(dg/dq)/dintnl[1]
236  all_q[0].d2g_di[1][1] = 0.0;
237  all_q[1].d2g_di[1][1] = 0.0;
238  all_q[2].d2g_di[1][1] = 0.0;
239 
240  // d2(flowPotential)/d(p, q)/d(p, q)
241  // d(dg/dp)/dp
242  all_q[0].d2g[0][0] = 0.0;
243  all_q[1].d2g[0][0] = 0.0;
244  all_q[2].d2g[0][0] = 0.0;
245  // d(dg/dp)/dq
246  all_q[0].d2g[0][1] = 0.0;
247  all_q[1].d2g[0][1] = 0.0;
248  all_q[2].d2g[0][1] = 0.0;
249  // d(dg/dq)/dp
250  all_q[0].d2g[1][0] = 0.0;
251  all_q[1].d2g[1][0] = 0.0;
252  all_q[2].d2g[1][0] = 0.0;
253  // d(dg/dq)/dq
254  if (_small_smoother2 == 0.0)
255  all_q[0].d2g[1][1] = 0.0;
256  else
257  all_q[0].d2g[1][1] = _small_smoother2 / std::pow(Utility::pow<2>(q) + _small_smoother2, 1.5);
258  all_q[1].d2g[1][1] = 0.0;
259  all_q[2].d2g[1][1] = 0.0;
260 }
261 
262 void
264  Real q_trial,
265  const std::vector<Real> & intnl_old,
266  Real & p,
267  Real & q,
268  Real & gaE,
269  std::vector<Real> & intnl) const
270 {
271  if (!_perfect_guess)
272  {
273  p = p_trial;
274  q = q_trial;
275  gaE = 0.0;
276  }
277  else
278  {
279  Real coh;
280  Real tanphi;
281  _dp.bothAB(intnl[0], coh, tanphi);
282  Real tanpsi;
283  _dp.onlyB(intnl_old[0], _dp.dilation, tanpsi);
284  const Real tens = _tstrength.value(intnl_old[1]);
285  const Real comp = _cstrength.value(intnl_old[1]);
286  const Real q_at_T = coh - tens * tanphi;
287  const Real q_at_C = coh + comp * tanphi;
288 
289  if ((p_trial >= tens) && (q_trial <= q_at_T))
290  {
291  // pure tensile failure
292  p = tens;
293  q = q_trial;
294  gaE = p_trial - p;
295  }
296  else if ((p_trial <= -comp) && (q_trial <= q_at_C))
297  {
298  // pure compressive failure
299  p = -comp;
300  q = q_trial;
301  gaE = p - p_trial;
302  }
303  else
304  {
305  // shear failure or a mixture
306  // Calculate ga assuming a pure shear failure
307  const Real ga = (q_trial + p_trial * tanphi - coh) / (_Eqq + _Epp * tanphi * tanpsi);
308  if (ga <= 0 && p_trial <= tens && p_trial >= -comp)
309  {
310  // very close to one of the rounded corners: there is no advantage to guessing the
311  // solution, so:
312  p = p_trial;
313  q = q_trial;
314  gaE = 0.0;
315  }
316  else
317  {
318  q = q_trial - _Eqq * ga;
319  if (q <= 0.0 && q_at_T <= 0.0)
320  {
321  // user has set tensile strength so large that it is irrelevant: return to the tip of the
322  // shear cone
323  q = 0.0;
324  p = coh / tanphi;
325  gaE = (p_trial - p) / tanpsi; // just a guess, based on the angle to the corner
326  }
327  else if (q <= q_at_T)
328  {
329  // pure shear is incorrect: mixture of tension and shear is correct
330  q = q_at_T;
331  p = tens;
332  gaE = (p_trial - p) / tanpsi; // just a guess, based on the angle to the corner
333  }
334  else if (q >= q_at_C)
335  {
336  // pure shear is incorrect: mixture of compression and shear is correct
337  q = q_at_C;
338  p = -comp;
339  if (p - p_trial < _Epp * tanpsi * (q_trial - q) / _Eqq)
340  // trial point is sitting almost directly above corner
341  gaE = (q_trial - q) * _Epp / _Eqq;
342  else
343  // trial point is sitting to the left of the corner
344  gaE = (p - p_trial) / tanpsi;
345  }
346  else
347  {
348  // pure shear was correct
349  p = p_trial - _Epp * ga * tanpsi;
350  gaE = ga * _Epp;
351  }
352  }
353  }
354  }
355  setIntnlValues(p_trial, q_trial, p, q, intnl_old, intnl);
356 }
357 
358 void
360  Real q_trial,
361  Real p,
362  Real q,
363  const std::vector<Real> & intnl_old,
364  std::vector<Real> & intnl) const
365 {
366  intnl[0] = intnl_old[0] + (q_trial - q) / _Eqq;
367  Real tanpsi;
368  _dp.onlyB(intnl[0], _dp.dilation, tanpsi);
369  intnl[1] = intnl_old[1] + (p_trial - p) / _Epp - (q_trial - q) * tanpsi / _Eqq;
370 }
371 
372 void
374  Real p_ok,
375  Real q_ok,
376  Real /*gaE*/,
377  const std::vector<Real> & /*intnl*/,
378  const yieldAndFlow & /*smoothed_q*/,
379  const RankFourTensor & /*Eijkl*/,
380  RankTwoTensor & stress) const
381 {
382  // stress = s_ij + de_ij tr(stress) / 3 = q / q_trial * s_ij^trial + de_ij p / 3 = q / q_trial *
383  // (stress_ij^trial - de_ij tr(stress^trial) / 3) + de_ij p / 3
384  const Real p_trial = stress_trial.trace();
386  (p_ok - (_in_q_trial == 0.0 ? 0.0 : p_trial * q_ok / _in_q_trial));
387  if (_in_q_trial > 0)
388  stress += q_ok / _in_q_trial * stress_trial;
389 }
390 
393 {
394  return stress.dtrace();
395 }
396 
399 {
400  return RankFourTensor();
401 }
402 
405 {
406  const Real j2 = stress.secondInvariant();
407  if (j2 == 0.0)
408  return RankTwoTensor();
409  return 0.5 * stress.dsecondInvariant() / std::sqrt(j2);
410 }
411 
414 {
415  const Real j2 = stress.secondInvariant();
416  if (j2 == 0.0)
417  return RankFourTensor();
418 
419  const RankTwoTensor dj2 = stress.dsecondInvariant();
420  return -0.25 * dj2.outerProduct(dj2) / std::pow(j2, 1.5) +
421  0.5 * stress.d2secondInvariant() / std::sqrt(j2);
422 }
423 
424 void
426  Real /*p_trial*/,
427  Real /*q_trial*/,
428  const RankTwoTensor & stress,
429  Real /*p*/,
430  Real q,
431  Real gaE,
432  const yieldAndFlow & smoothed_q,
433  const RankFourTensor & Eijkl,
434  bool compute_full_tangent_operator,
435  RankFourTensor & cto) const
436 {
437  cto = Eijkl;
438  if (!compute_full_tangent_operator)
439  return;
440 
441  const RankTwoTensor s_over_q =
442  (q == 0.0 ? RankTwoTensor()
443  : (stress - stress.trace() * RankTwoTensor(RankTwoTensor::initIdentity) / 3.0) / q);
444 
445  for (unsigned i = 0; i < _tensor_dimensionality; ++i)
446  for (unsigned j = 0; j < _tensor_dimensionality; ++j)
447  for (unsigned k = 0; k < _tensor_dimensionality; ++k)
448  for (unsigned l = 0; l < _tensor_dimensionality; ++l)
449  {
450  cto(i, j, k, l) -=
451  (i == j) * (1.0 / 3.0) *
452  (_Epp * (1.0 - _dp_dpt) / 3.0 * (k == l) + s_over_q(k, l) * _Eqq * (-_dp_dqt));
453  cto(i, j, k, l) -= s_over_q(i, j) * (_Epp * (-_dq_dpt) / 3.0 * (k == l) +
454  s_over_q(k, l) * _Eqq * (1.0 - _dq_dqt));
455  }
456 
457  if (smoothed_q.dg[1] != 0.0)
458  {
459  const RankFourTensor Tijab = Eijkl * (gaE / _Epp) * smoothed_q.dg[1] * d2qdstress2(stress);
461  try
462  {
463  inv = inv.transposeMajor().invSymm();
464  }
465  catch (const MooseException & e)
466  {
467  // Cannot form the inverse, so probably at some degenerate place in stress space.
468  // Just return with the "best estimate" of the cto.
469  mooseWarning("CappedDruckerPragerStressUpdate: Cannot invert 1+T in consistent tangent "
470  "operator computation at quadpoint ",
471  _qp,
472  " of element ",
473  _current_elem->id());
474  return;
475  }
476  cto = (cto.transposeMajor() * inv).transposeMajor();
477  }
478 }
RankFourTensorTempl< Real > outerProduct(const RankTwoTensorTempl< Real > &b) const
const SolidMechanicsPlasticDruckerPrager & _dp
Hardening model for cohesion, friction and dilation angles.
RankTwoTensorTempl< Real > dsecondInvariant() const
RankFourTensorTempl< Real > d2secondInvariant() const
const Real _small_smoother2
The cone vertex is smoothed by this amount.
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
virtual RankFourTensor d2qdstress2(const RankTwoTensor &stress) const override
d2(q)/d(stress)/d(stress) Derived classes must override this
virtual void initializeVars(Real p_trial, Real q_trial, const std::vector< Real > &intnl_old, Real &p, Real &q, Real &gaE, std::vector< Real > &intnl) const override
Sets (p, q, gaE, intnl) at "good guesses" of the solution to the Return-Map algorithm.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void donlyB(Real intnl, int fd, Real &dbbb) const
Calculate d(bbb)/d(intnl) or d(bbb_flow)/d(intnl)
Real _dp_dpt
derivative of Variable with respect to trial variable (used in consistent-tangent-operator calculatio...
Real _dq_dpt
derivative of Variable with respect to trial variable (used in consistent-tangent-operator calculatio...
void bothAB(Real intnl, Real &aaa, Real &bbb) const
Calculates aaa and bbb as a function of the internal parameter intnl.
Struct designed to hold info about a single yield function and its derivatives, as well as the flow d...
TwoParameterPlasticityStressUpdate performs the return-map algorithm and associated stress updates fo...
RankTwoTensorTempl< Real > dtrace() const
virtual void finalizeReturnProcess(const RankTwoTensor &rotation_increment) override
Derived classes may use this to perform calculations after the return-map process has completed succe...
virtual RankTwoTensor dqdstress(const RankTwoTensor &stress) const override
d(q)/d(stress) Derived classes must override this
ADRealEigenVector< T, D, asd > sqrt(const ADRealEigenVector< T, D, asd > &)
const bool _small_dilation
If true, and if the trial stress exceeds the tensile strength, then the user gaurantees that the retu...
virtual Real value(Real intnl) const
void mooseWarning(Args &&... args) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual RankFourTensor d2pdstress2(const RankTwoTensor &stress) const override
d2(p)/d(stress)/d(stress) Derived classes must override this
CappedDruckerPragerStressUpdate(const InputParameters &parameters)
void onlyB(Real intnl, int fd, Real &bbb) const
Calculate bbb or bbb_flow.
unsigned int _qp
Rate-independent non-associative Drucker Prager with hardening/softening.
Real _dq_dqt
derivative of Variable with respect to trial variable (used in consistent-tangent-operator calculatio...
virtual RankTwoTensor dpdstress(const RankTwoTensor &stress) const override
d(p)/d(stress) Derived classes must override this
RankFourTensorTempl< T > transposeMajor() const
Real _Epp
elasticity tensor in p direction
const Real _smoothing_tol
Smoothing tolerance: edges of the yield surface get smoothed by this amount.
void dbothAB(Real intnl, Real &daaa, Real &dbbb) const
Calculates d(aaa)/d(intnl) and d(bbb)/d(intnl) as a function of the internal parameter intnl...
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
virtual void setIntnlValues(Real p_trial, Real q_trial, Real p, Real q, const std::vector< Real > &intnl_old, std::vector< Real > &intnl) const override
Sets the internal parameters based on the trial values of p and q, their current values, and the old values of the internal parameters.
virtual Real derivative(Real intnl) const
const SolidMechanicsHardeningModel & _cstrength
Hardening model for compressive strength.
virtual void yieldFunctionValues(Real p, Real q, const std::vector< Real > &intnl, std::vector< Real > &yf) const override
Computes the values of the yield functions, given p, q and intnl parameters.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real _Eqq
elasticity tensor in q direction
virtual void consistentTangentOperator(const RankTwoTensor &stress_trial, Real p_trial, Real q_trial, const RankTwoTensor &stress, Real p, Real q, Real gaE, const yieldAndFlow &smoothed_q, const RankFourTensor &Eijkl, bool compute_full_tangent_operator, RankFourTensor &cto) const override
Calculates the consistent tangent operator.
const SolidMechanicsHardeningModel & _tstrength
Hardening model for tensile strength.
virtual void initializeReturnProcess() override
Derived classes may use this to perform calculations before any return-map process is performed...
StressReturnType
This allows some simplification in the return-map process.
void mooseError(Args &&... args) const
CappedDruckerPragerStressUpdate performs the return-map algorithm and associated stress updates for p...
void addClassDescription(const std::string &doc_string)
virtual void setIntnlDerivatives(Real p_trial, Real q_trial, Real p, Real q, const std::vector< Real > &intnl, std::vector< std::vector< Real >> &dintnl) const override
Sets the derivatives of internal parameters, based on the trial values of p and q, their current values, and the old values of the internal parameters.
enum CappedDruckerPragerStressUpdate::StressReturnType _stress_return_type
virtual void setEppEqq(const RankFourTensor &Eijkl, Real &Epp, Real &Eqq) const override
Set Epp and Eqq based on the elasticity tensor Derived classes must override this.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
virtual void computePQ(const RankTwoTensor &stress, Real &p, Real &q) const override
Computes p and q, given stress.
registerMooseObject("SolidMechanicsApp", CappedDruckerPragerStressUpdate)
virtual void setStressAfterReturn(const RankTwoTensor &stress_trial, Real p_ok, Real q_ok, Real gaE, const std::vector< Real > &intnl, const yieldAndFlow &smoothed_q, const RankFourTensor &Eijkl, RankTwoTensor &stress) const override
Sets stress from the admissible parameters.
const bool _perfect_guess
Initialize the NR proceedure from a guess coming from perfect plasticity.
Real _dp_dqt
derivative of Variable with respect to trial variable (used in consistent-tangent-operator calculatio...
virtual void preReturnMap(Real p_trial, Real q_trial, const RankTwoTensor &stress_trial, const std::vector< Real > &intnl_old, const std::vector< Real > &yf, const RankFourTensor &Eijkl) override
Derived classes may employ this function to record stuff or do other computations prior to the return...
RankFourTensorTempl< T > invSymm() const
MooseUnits pow(const MooseUnits &, int)
static constexpr unsigned _tensor_dimensionality
Internal dimensionality of tensors (currently this is 3 throughout tensor_mechanics) ...
static const std::string k
Definition: NS.h:124
const Elem *const & _current_elem
virtual void computeAllQ(Real p, Real q, const std::vector< Real > &intnl, std::vector< yieldAndFlow > &all_q) const override
Completely fills all_q with correct values.