www.mooseframework.org
TensorMechanicsPlasticMohrCoulombMulti.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 "RankFourTensor.h"
12 
13 // Following is for perturbing eigvenvalues. This looks really bodgy, but works quite well!
14 #include "MooseRandom.h"
15 #include "libmesh/utility.h"
16 
18 
20 
21 InputParameters
23 {
24  InputParameters params = TensorMechanicsPlasticModel::validParams();
25  params.addClassDescription("Non-associative Mohr-Coulomb plasticity with hardening/softening");
26  params.addRequiredParam<UserObjectName>(
27  "cohesion", "A TensorMechanicsHardening UserObject that defines hardening of the cohesion");
28  params.addRequiredParam<UserObjectName>("friction_angle",
29  "A TensorMechanicsHardening UserObject "
30  "that defines hardening of the "
31  "friction angle (in radians)");
32  params.addRequiredParam<UserObjectName>("dilation_angle",
33  "A TensorMechanicsHardening UserObject "
34  "that defines hardening of the "
35  "dilation angle (in radians)");
36  params.addParam<unsigned int>("max_iterations",
37  10,
38  "Maximum number of Newton-Raphson iterations "
39  "allowed in the custom return-map algorithm. "
40  " For highly nonlinear hardening this may "
41  "need to be higher than 10.");
42  params.addParam<Real>("shift",
43  "Yield surface is shifted by this amount to avoid problems with "
44  "defining derivatives when eigenvalues are equal. If this is "
45  "larger than f_tol, a warning will be issued. This may be set "
46  "very small when using the custom returnMap. Default = f_tol.");
47  params.addParam<bool>("use_custom_returnMap",
48  true,
49  "Use a custom return-map algorithm for this "
50  "plasticity model, which may speed up "
51  "computations considerably. Set to true "
52  "only for isotropic elasticity with no "
53  "hardening of the dilation angle. In this "
54  "case you may set 'shift' very small.");
55 
56  return params;
57 }
58 
60  const InputParameters & parameters)
61  : TensorMechanicsPlasticModel(parameters),
62  _cohesion(getUserObject<TensorMechanicsHardeningModel>("cohesion")),
63  _phi(getUserObject<TensorMechanicsHardeningModel>("friction_angle")),
64  _psi(getUserObject<TensorMechanicsHardeningModel>("dilation_angle")),
65  _max_iters(getParam<unsigned int>("max_iterations")),
66  _shift(parameters.isParamValid("shift") ? getParam<Real>("shift") : _f_tol),
67  _use_custom_returnMap(getParam<bool>("use_custom_returnMap"))
68 {
69  if (_shift < 0)
70  mooseError("Value of 'shift' in TensorMechanicsPlasticMohrCoulombMulti must not be negative\n");
71  if (_shift > _f_tol)
72  _console << "WARNING: value of 'shift' in TensorMechanicsPlasticMohrCoulombMulti is probably "
73  "set too high\n";
74  if (LIBMESH_DIM != 3)
75  mooseError("TensorMechanicsPlasticMohrCoulombMulti is only defined for LIBMESH_DIM=3");
76  MooseRandom::seed(0);
77 }
78 
79 unsigned int
81 {
82  return 6;
83 }
84 
85 void
87  Real intnl,
88  std::vector<Real> & f) const
89 {
90  std::vector<Real> eigvals;
91  stress.symmetricEigenvalues(eigvals);
92  eigvals[0] += _shift;
93  eigvals[2] -= _shift;
94 
95  const Real sinphi = std::sin(phi(intnl));
96  const Real cosphi = std::cos(phi(intnl));
97  const Real cohcos = cohesion(intnl) * cosphi;
98 
99  yieldFunctionEigvals(eigvals[0], eigvals[1], eigvals[2], sinphi, cohcos, f);
100 }
101 
102 void
104  Real e0, Real e1, Real e2, Real sinphi, Real cohcos, std::vector<Real> & f) const
105 {
106  // Naively it seems a shame to have 6 yield functions active instead of just
107  // 3. But 3 won't do. Eg, think of a loading with eigvals[0]=eigvals[1]=eigvals[2]
108  // Then to return to the yield surface would require 2 positive plastic multipliers
109  // and one negative one. Boo hoo.
110 
111  f.resize(6);
112  f[0] = 0.5 * (e0 - e1) + 0.5 * (e0 + e1) * sinphi - cohcos;
113  f[1] = 0.5 * (e1 - e0) + 0.5 * (e0 + e1) * sinphi - cohcos;
114  f[2] = 0.5 * (e0 - e2) + 0.5 * (e0 + e2) * sinphi - cohcos;
115  f[3] = 0.5 * (e2 - e0) + 0.5 * (e0 + e2) * sinphi - cohcos;
116  f[4] = 0.5 * (e1 - e2) + 0.5 * (e1 + e2) * sinphi - cohcos;
117  f[5] = 0.5 * (e2 - e1) + 0.5 * (e1 + e2) * sinphi - cohcos;
118 }
119 
120 void
122  std::vector<Real> & eigvals,
123  std::vector<RankTwoTensor> & deigvals) const
124 {
125  Real small_perturbation;
126  RankTwoTensor shifted_stress = stress;
127  while (eigvals[0] > eigvals[1] - 0.1 * _shift || eigvals[1] > eigvals[2] - 0.1 * _shift)
128  {
129  for (unsigned i = 0; i < 3; ++i)
130  for (unsigned j = 0; j <= i; ++j)
131  {
132  small_perturbation = 0.1 * _shift * 2 * (MooseRandom::rand() - 0.5);
133  shifted_stress(i, j) += small_perturbation;
134  shifted_stress(j, i) += small_perturbation;
135  }
136  shifted_stress.dsymmetricEigenvalues(eigvals, deigvals);
137  }
138 }
139 
140 void
142  Real sin_angle,
143  std::vector<RankTwoTensor> & df) const
144 {
145  std::vector<Real> eigvals;
146  std::vector<RankTwoTensor> deigvals;
147  stress.dsymmetricEigenvalues(eigvals, deigvals);
148 
149  if (eigvals[0] > eigvals[1] - 0.1 * _shift || eigvals[1] > eigvals[2] - 0.1 * _shift)
150  perturbStress(stress, eigvals, deigvals);
151 
152  df.resize(6);
153  df[0] = 0.5 * (deigvals[0] - deigvals[1]) + 0.5 * (deigvals[0] + deigvals[1]) * sin_angle;
154  df[1] = 0.5 * (deigvals[1] - deigvals[0]) + 0.5 * (deigvals[0] + deigvals[1]) * sin_angle;
155  df[2] = 0.5 * (deigvals[0] - deigvals[2]) + 0.5 * (deigvals[0] + deigvals[2]) * sin_angle;
156  df[3] = 0.5 * (deigvals[2] - deigvals[0]) + 0.5 * (deigvals[0] + deigvals[2]) * sin_angle;
157  df[4] = 0.5 * (deigvals[1] - deigvals[2]) + 0.5 * (deigvals[1] + deigvals[2]) * sin_angle;
158  df[5] = 0.5 * (deigvals[2] - deigvals[1]) + 0.5 * (deigvals[1] + deigvals[2]) * sin_angle;
159 }
160 
161 void
163  const RankTwoTensor & stress, Real intnl, std::vector<RankTwoTensor> & df_dstress) const
164 {
165  const Real sinphi = std::sin(phi(intnl));
166  df_dsig(stress, sinphi, df_dstress);
167 }
168 
169 void
171  Real intnl,
172  std::vector<Real> & df_dintnl) const
173 {
174  std::vector<Real> eigvals;
175  stress.symmetricEigenvalues(eigvals);
176  eigvals[0] += _shift;
177  eigvals[2] -= _shift;
178 
179  const Real sin_angle = std::sin(phi(intnl));
180  const Real cos_angle = std::cos(phi(intnl));
181  const Real dsin_angle = cos_angle * dphi(intnl);
182  const Real dcos_angle = -sin_angle * dphi(intnl);
183  const Real dcohcos = dcohesion(intnl) * cos_angle + cohesion(intnl) * dcos_angle;
184 
185  df_dintnl.resize(6);
186  df_dintnl[0] = df_dintnl[1] = 0.5 * (eigvals[0] + eigvals[1]) * dsin_angle - dcohcos;
187  df_dintnl[2] = df_dintnl[3] = 0.5 * (eigvals[0] + eigvals[2]) * dsin_angle - dcohcos;
188  df_dintnl[4] = df_dintnl[5] = 0.5 * (eigvals[1] + eigvals[2]) * dsin_angle - dcohcos;
189 }
190 
191 void
193  Real intnl,
194  std::vector<RankTwoTensor> & r) const
195 {
196  const Real sinpsi = std::sin(psi(intnl));
197  df_dsig(stress, sinpsi, r);
198 }
199 
200 void
202  const RankTwoTensor & stress, Real intnl, std::vector<RankFourTensor> & dr_dstress) const
203 {
204  std::vector<RankFourTensor> d2eigvals;
205  stress.d2symmetricEigenvalues(d2eigvals);
206 
207  const Real sinpsi = std::sin(psi(intnl));
208 
209  dr_dstress.resize(6);
210  dr_dstress[0] =
211  0.5 * (d2eigvals[0] - d2eigvals[1]) + 0.5 * (d2eigvals[0] + d2eigvals[1]) * sinpsi;
212  dr_dstress[1] =
213  0.5 * (d2eigvals[1] - d2eigvals[0]) + 0.5 * (d2eigvals[0] + d2eigvals[1]) * sinpsi;
214  dr_dstress[2] =
215  0.5 * (d2eigvals[0] - d2eigvals[2]) + 0.5 * (d2eigvals[0] + d2eigvals[2]) * sinpsi;
216  dr_dstress[3] =
217  0.5 * (d2eigvals[2] - d2eigvals[0]) + 0.5 * (d2eigvals[0] + d2eigvals[2]) * sinpsi;
218  dr_dstress[4] =
219  0.5 * (d2eigvals[1] - d2eigvals[2]) + 0.5 * (d2eigvals[1] + d2eigvals[2]) * sinpsi;
220  dr_dstress[5] =
221  0.5 * (d2eigvals[2] - d2eigvals[1]) + 0.5 * (d2eigvals[1] + d2eigvals[2]) * sinpsi;
222 }
223 
224 void
226  const RankTwoTensor & stress, Real intnl, std::vector<RankTwoTensor> & dr_dintnl) const
227 {
228  const Real cos_angle = std::cos(psi(intnl));
229  const Real dsin_angle = cos_angle * dpsi(intnl);
230 
231  std::vector<Real> eigvals;
232  std::vector<RankTwoTensor> deigvals;
233  stress.dsymmetricEigenvalues(eigvals, deigvals);
234 
235  if (eigvals[0] > eigvals[1] - 0.1 * _shift || eigvals[1] > eigvals[2] - 0.1 * _shift)
236  perturbStress(stress, eigvals, deigvals);
237 
238  dr_dintnl.resize(6);
239  dr_dintnl[0] = dr_dintnl[1] = 0.5 * (deigvals[0] + deigvals[1]) * dsin_angle;
240  dr_dintnl[2] = dr_dintnl[3] = 0.5 * (deigvals[0] + deigvals[2]) * dsin_angle;
241  dr_dintnl[4] = dr_dintnl[5] = 0.5 * (deigvals[1] + deigvals[2]) * dsin_angle;
242 }
243 
244 void
246  const RankTwoTensor & stress,
247  Real intnl,
248  const RankFourTensor & Eijkl,
249  std::vector<bool> & act,
250  RankTwoTensor & returned_stress) const
251 {
252  act.assign(6, false);
253 
254  if (f[0] <= _f_tol && f[1] <= _f_tol && f[2] <= _f_tol && f[3] <= _f_tol && f[4] <= _f_tol &&
255  f[5] <= _f_tol)
256  {
257  returned_stress = stress;
258  return;
259  }
260 
261  Real returned_intnl;
262  std::vector<Real> dpm(6);
263  RankTwoTensor delta_dp;
264  std::vector<Real> yf(6);
265  bool trial_stress_inadmissible;
266  doReturnMap(stress,
267  intnl,
268  Eijkl,
269  0.0,
270  returned_stress,
271  returned_intnl,
272  dpm,
273  delta_dp,
274  yf,
275  trial_stress_inadmissible);
276 
277  for (unsigned i = 0; i < 6; ++i)
278  act[i] = (dpm[i] > 0);
279 }
280 
281 Real
282 TensorMechanicsPlasticMohrCoulombMulti::cohesion(const Real internal_param) const
283 {
284  return _cohesion.value(internal_param);
285 }
286 
287 Real
289 {
290  return _cohesion.derivative(internal_param);
291 }
292 
293 Real
294 TensorMechanicsPlasticMohrCoulombMulti::phi(const Real internal_param) const
295 {
296  return _phi.value(internal_param);
297 }
298 
299 Real
300 TensorMechanicsPlasticMohrCoulombMulti::dphi(const Real internal_param) const
301 {
302  return _phi.derivative(internal_param);
303 }
304 
305 Real
306 TensorMechanicsPlasticMohrCoulombMulti::psi(const Real internal_param) const
307 {
308  return _psi.value(internal_param);
309 }
310 
311 Real
312 TensorMechanicsPlasticMohrCoulombMulti::dpsi(const Real internal_param) const
313 {
314  return _psi.derivative(internal_param);
315 }
316 
317 std::string
319 {
320  return "MohrCoulombMulti";
321 }
322 
323 bool
325  Real intnl_old,
326  const RankFourTensor & E_ijkl,
327  Real ep_plastic_tolerance,
328  RankTwoTensor & returned_stress,
329  Real & returned_intnl,
330  std::vector<Real> & dpm,
331  RankTwoTensor & delta_dp,
332  std::vector<Real> & yf,
333  bool & trial_stress_inadmissible) const
334 {
336  return TensorMechanicsPlasticModel::returnMap(trial_stress,
337  intnl_old,
338  E_ijkl,
339  ep_plastic_tolerance,
340  returned_stress,
341  returned_intnl,
342  dpm,
343  delta_dp,
344  yf,
345  trial_stress_inadmissible);
346 
347  return doReturnMap(trial_stress,
348  intnl_old,
349  E_ijkl,
350  ep_plastic_tolerance,
351  returned_stress,
352  returned_intnl,
353  dpm,
354  delta_dp,
355  yf,
356  trial_stress_inadmissible);
357 }
358 
359 bool
361  Real intnl_old,
362  const RankFourTensor & E_ijkl,
363  Real ep_plastic_tolerance,
364  RankTwoTensor & returned_stress,
365  Real & returned_intnl,
366  std::vector<Real> & dpm,
367  RankTwoTensor & delta_dp,
368  std::vector<Real> & yf,
369  bool & trial_stress_inadmissible) const
370 {
371  mooseAssert(dpm.size() == 6,
372  "TensorMechanicsPlasticMohrCoulombMulti size of dpm should be 6 but it is "
373  << dpm.size());
374 
375  std::vector<Real> eigvals;
376  RankTwoTensor eigvecs;
377  trial_stress.symmetricEigenvaluesEigenvectors(eigvals, eigvecs);
378  eigvals[0] += _shift;
379  eigvals[2] -= _shift;
380 
381  Real sinphi = std::sin(phi(intnl_old));
382  Real cosphi = std::cos(phi(intnl_old));
383  Real coh = cohesion(intnl_old);
384  Real cohcos = coh * cosphi;
385 
386  yieldFunctionEigvals(eigvals[0], eigvals[1], eigvals[2], sinphi, cohcos, yf);
387 
388  if (yf[0] <= _f_tol && yf[1] <= _f_tol && yf[2] <= _f_tol && yf[3] <= _f_tol && yf[4] <= _f_tol &&
389  yf[5] <= _f_tol)
390  {
391  // purely elastic (trial_stress, intnl_old)
392  trial_stress_inadmissible = false;
393  return true;
394  }
395 
396  trial_stress_inadmissible = true;
397  delta_dp.zero();
398  returned_stress = RankTwoTensor();
399 
400  // these are the normals to the 6 yield surfaces, which are const because of the assumption of no
401  // psi hardening
402  std::vector<RealVectorValue> norm(6);
403  const Real sinpsi = std::sin(psi(intnl_old));
404  const Real oneminus = 0.5 * (1 - sinpsi);
405  const Real oneplus = 0.5 * (1 + sinpsi);
406  norm[0](0) = oneplus;
407  norm[0](1) = -oneminus;
408  norm[0](2) = 0;
409  norm[1](0) = -oneminus;
410  norm[1](1) = oneplus;
411  norm[1](2) = 0;
412  norm[2](0) = oneplus;
413  norm[2](1) = 0;
414  norm[2](2) = -oneminus;
415  norm[3](0) = -oneminus;
416  norm[3](1) = 0;
417  norm[3](2) = oneplus;
418  norm[4](0) = 0;
419  norm[4](1) = oneplus;
420  norm[4](2) = -oneminus;
421  norm[5](0) = 0;
422  norm[5](1) = -oneminus;
423  norm[5](2) = oneplus;
424 
425  // the flow directions are these norm multiplied by Eijkl.
426  // I call the flow directions "n".
427  // In the following I assume that the Eijkl is
428  // for an isotropic situation. Then I don't have to
429  // rotate to the principal-stress frame, and i don't
430  // have to worry about strange off-diagonal things
431  std::vector<RealVectorValue> n(6);
432  for (unsigned ys = 0; ys < 6; ++ys)
433  for (unsigned i = 0; i < 3; ++i)
434  for (unsigned j = 0; j < 3; ++j)
435  n[ys](i) += E_ijkl(i, i, j, j) * norm[ys](j);
436  const Real mag_E = E_ijkl(0, 0, 0, 0);
437 
438  // With non-zero Poisson's ratio and hardening
439  // it is not computationally cheap to know whether
440  // the trial stress will return to the tip, edge,
441  // or plane. The following at least
442  // gives a not-completely-stupid guess
443  // trial_order[0] = type of return to try first
444  // trial_order[1] = type of return to try second
445  // trial_order[2] = type of return to try third
446  // trial_order[3] = type of return to try fourth
447  // trial_order[4] = type of return to try fifth
448  // In the following the "binary" stuff indicates the
449  // deactive (0) and active (1) surfaces, eg
450  // 110100 means that surfaces 0, 1 and 3 are active
451  // and 2, 4 and 5 are deactive
452  const unsigned int number_of_return_paths = 5;
453  std::vector<int> trial_order(number_of_return_paths);
454  if (yf[1] > _f_tol && yf[3] > _f_tol && yf[5] > _f_tol)
455  {
456  trial_order[0] = tip110100;
457  trial_order[1] = edge010100;
458  trial_order[2] = plane000100;
459  trial_order[3] = edge000101;
460  trial_order[4] = tip010101;
461  }
462  else if (yf[1] <= _f_tol && yf[3] > _f_tol && yf[5] > _f_tol)
463  {
464  trial_order[0] = edge000101;
465  trial_order[1] = plane000100;
466  trial_order[2] = tip110100;
467  trial_order[3] = tip010101;
468  trial_order[4] = edge010100;
469  }
470  else if (yf[1] <= _f_tol && yf[3] > _f_tol && yf[5] <= _f_tol)
471  {
472  trial_order[0] = plane000100;
473  trial_order[1] = edge000101;
474  trial_order[2] = edge010100;
475  trial_order[3] = tip110100;
476  trial_order[4] = tip010101;
477  }
478  else
479  {
480  trial_order[0] = edge010100;
481  trial_order[1] = plane000100;
482  trial_order[2] = edge000101;
483  trial_order[3] = tip110100;
484  trial_order[4] = tip010101;
485  }
486 
487  unsigned trial;
488  bool nr_converged = false;
489  bool kt_success = false;
490  std::vector<RealVectorValue> ntip(3);
491  std::vector<Real> dpmtip(3);
492 
493  for (trial = 0; trial < number_of_return_paths; ++trial)
494  {
495  switch (trial_order[trial])
496  {
497  case tip110100:
498  for (unsigned int i = 0; i < 3; ++i)
499  {
500  ntip[0](i) = n[0](i);
501  ntip[1](i) = n[1](i);
502  ntip[2](i) = n[3](i);
503  }
504  kt_success = returnTip(eigvals,
505  ntip,
506  dpmtip,
507  returned_stress,
508  intnl_old,
509  sinphi,
510  cohcos,
511  0,
512  nr_converged,
513  ep_plastic_tolerance,
514  yf);
515  if (nr_converged && kt_success)
516  {
517  dpm[0] = dpmtip[0];
518  dpm[1] = dpmtip[1];
519  dpm[3] = dpmtip[2];
520  dpm[2] = dpm[4] = dpm[5] = 0;
521  }
522  break;
523 
524  case tip010101:
525  for (unsigned int i = 0; i < 3; ++i)
526  {
527  ntip[0](i) = n[1](i);
528  ntip[1](i) = n[3](i);
529  ntip[2](i) = n[5](i);
530  }
531  kt_success = returnTip(eigvals,
532  ntip,
533  dpmtip,
534  returned_stress,
535  intnl_old,
536  sinphi,
537  cohcos,
538  0,
539  nr_converged,
540  ep_plastic_tolerance,
541  yf);
542  if (nr_converged && kt_success)
543  {
544  dpm[1] = dpmtip[0];
545  dpm[3] = dpmtip[1];
546  dpm[5] = dpmtip[2];
547  dpm[0] = dpm[2] = dpm[4] = 0;
548  }
549  break;
550 
551  case edge000101:
552  kt_success = returnEdge000101(eigvals,
553  n,
554  dpm,
555  returned_stress,
556  intnl_old,
557  sinphi,
558  cohcos,
559  0,
560  mag_E,
561  nr_converged,
562  ep_plastic_tolerance,
563  yf);
564  break;
565 
566  case edge010100:
567  kt_success = returnEdge010100(eigvals,
568  n,
569  dpm,
570  returned_stress,
571  intnl_old,
572  sinphi,
573  cohcos,
574  0,
575  mag_E,
576  nr_converged,
577  ep_plastic_tolerance,
578  yf);
579  break;
580 
581  case plane000100:
582  kt_success = returnPlane(eigvals,
583  n,
584  dpm,
585  returned_stress,
586  intnl_old,
587  sinphi,
588  cohcos,
589  0,
590  nr_converged,
591  ep_plastic_tolerance,
592  yf);
593  break;
594  }
595 
596  if (nr_converged && kt_success)
597  break;
598  }
599 
600  if (trial == number_of_return_paths)
601  {
602  sinphi = std::sin(phi(intnl_old));
603  cosphi = std::cos(phi(intnl_old));
604  coh = cohesion(intnl_old);
605  cohcos = coh * cosphi;
606  yieldFunctionEigvals(eigvals[0], eigvals[1], eigvals[2], sinphi, cohcos, yf);
607  Moose::err << "Trial stress = \n";
608  trial_stress.print(Moose::err);
609  Moose::err << "which has eigenvalues = " << eigvals[0] << " " << eigvals[1] << " " << eigvals[2]
610  << "\n";
611  Moose::err << "and yield functions = " << yf[0] << " " << yf[1] << " " << yf[2] << " " << yf[3]
612  << " " << yf[4] << " " << yf[5] << "\n";
613  Moose::err << "Internal parameter = " << intnl_old << "\n";
614  mooseError("TensorMechanicsPlasticMohrCoulombMulti: FAILURE! You probably need to implement a "
615  "line search if your hardening is too severe, or you need to tune your tolerances "
616  "(eg, yield_function_tolerance should be a little smaller than (young "
617  "modulus)*ep_plastic_tolerance).\n");
618  return false;
619  }
620 
621  // success
622 
623  returned_intnl = intnl_old;
624  for (unsigned i = 0; i < 6; ++i)
625  returned_intnl += dpm[i];
626  for (unsigned i = 0; i < 6; ++i)
627  for (unsigned j = 0; j < 3; ++j)
628  delta_dp(j, j) += dpm[i] * norm[i](j);
629  returned_stress = eigvecs * returned_stress * (eigvecs.transpose());
630  delta_dp = eigvecs * delta_dp * (eigvecs.transpose());
631  return true;
632 }
633 
634 bool
635 TensorMechanicsPlasticMohrCoulombMulti::returnTip(const std::vector<Real> & eigvals,
636  const std::vector<RealVectorValue> & n,
637  std::vector<Real> & dpm,
638  RankTwoTensor & returned_stress,
639  Real intnl_old,
640  Real & sinphi,
641  Real & cohcos,
642  Real initial_guess,
643  bool & nr_converged,
644  Real ep_plastic_tolerance,
645  std::vector<Real> & yf) const
646 {
647  // This returns to the Mohr-Coulomb tip using the THREE directions
648  // given in n, and yields the THREE dpm values. Note that you
649  // must supply THREE suitable n vectors out of the total of SIX
650  // flow directions, and then interpret the THREE dpm values appropriately.
651  //
652  // Eg1. You supply the flow directions n[0], n[1] and n[3] as
653  // the "n" vectors. This is return-to-the-tip via 110100.
654  // Then the three returned dpm values will be dpm[0], dpm[1] and dpm[3].
655 
656  // Eg2. You supply the flow directions n[1], n[3] and n[5] as
657  // the "n" vectors. This is return-to-the-tip via 010101.
658  // Then the three returned dpm values will be dpm[1], dpm[3] and dpm[5].
659 
660  // The returned point is defined by the three yield functions (corresonding
661  // to the three supplied flow directions) all being zero.
662  // that is, returned_stress = diag(cohcot, cohcot, cohcot), where
663  // cohcot = cohesion*cosphi/sinphi
664  // where intnl = intnl_old + dpm[0] + dpm[1] + dpm[2]
665  // The 3 plastic multipliers, dpm, are defiend by the normality condition
666  // eigvals - cohcot = dpm[0]*n[0] + dpm[1]*n[1] + dpm[2]*n[2]
667  // (Kuhn-Tucker demands that all dpm are non-negative, but we leave
668  // that checking for the end.)
669  // (Remember that these "n" vectors and "dpm" values must be interpreted
670  // differently depending on what you pass into this function.)
671  // This is a vector equation with solution (A):
672  // dpm[0] = triple(eigvals - cohcot, n[1], n[2])/trip;
673  // dpm[1] = triple(eigvals - cohcot, n[2], n[0])/trip;
674  // dpm[2] = triple(eigvals - cohcot, n[0], n[1])/trip;
675  // where trip = triple(n[0], n[1], n[2]).
676  // By adding the three components of that solution together
677  // we can get an equation for x = dpm[0] + dpm[1] + dpm[2],
678  // and then our Newton-Raphson only involves one variable (x).
679  // In the following, i specialise to the isotropic situation.
680 
681  mooseAssert(n.size() == 3,
682  "TensorMechanicsPlasticMohrCoulombMulti: Custom tip-return algorithm must be "
683  "supplied with n of size 3, whereas yours is "
684  << n.size());
685  mooseAssert(dpm.size() == 3,
686  "TensorMechanicsPlasticMohrCoulombMulti: Custom tip-return algorithm must be "
687  "supplied with dpm of size 3, whereas yours is "
688  << dpm.size());
689  mooseAssert(yf.size() == 6,
690  "TensorMechanicsPlasticMohrCoulombMulti: Custom tip-return algorithm must be "
691  "supplied with yf of size 6, whereas yours is "
692  << yf.size());
693 
694  Real x = initial_guess;
695  const Real trip = triple_product(n[0], n[1], n[2]);
696  sinphi = std::sin(phi(intnl_old + x));
697  Real cosphi = std::cos(phi(intnl_old + x));
698  Real coh = cohesion(intnl_old + x);
699  cohcos = coh * cosphi;
700  Real cohcot = cohcos / sinphi;
701 
702  if (_cohesion.modelName().compare("Constant") != 0 || _phi.modelName().compare("Constant") != 0)
703  {
704  // Finding x is expensive. Therefore
705  // although x!=0 for Constant Hardening, solution (A)
706  // demonstrates that we don't
707  // actually need to know x to find the dpm for
708  // Constant Hardening.
709  //
710  // However, for nontrivial Hardening, the following
711  // is necessary
712  // cohcot_coeff = [1,1,1].(Cross[n[1], n[2]] + Cross[n[2], n[0]] + Cross[n[0], n[1]])/trip
713  Real cohcot_coeff =
714  (n[0](0) * (n[1](1) - n[1](2) - n[2](1)) + (n[1](2) - n[1](1)) * n[2](0) +
715  (n[1](0) - n[1](2)) * n[2](1) + n[0](2) * (n[1](0) - n[1](1) - n[2](0) + n[2](1)) +
716  n[0](1) * (n[1](2) - n[1](0) + n[2](0) - n[2](2)) +
717  (n[0](0) - n[1](0) + n[1](1)) * n[2](2)) /
718  trip;
719  // eig_term = eigvals.(Cross[n[1], n[2]] + Cross[n[2], n[0]] + Cross[n[0], n[1]])/trip
720  Real eig_term = eigvals[0] *
721  (-n[0](2) * n[1](1) + n[0](1) * n[1](2) + n[0](2) * n[2](1) -
722  n[1](2) * n[2](1) - n[0](1) * n[2](2) + n[1](1) * n[2](2)) /
723  trip;
724  eig_term += eigvals[1] *
725  (n[0](2) * n[1](0) - n[0](0) * n[1](2) - n[0](2) * n[2](0) + n[1](2) * n[2](0) +
726  n[0](0) * n[2](2) - n[1](0) * n[2](2)) /
727  trip;
728  eig_term += eigvals[2] *
729  (n[0](0) * n[1](1) - n[1](1) * n[2](0) + n[0](1) * n[2](0) - n[0](1) * n[1](0) -
730  n[0](0) * n[2](1) + n[1](0) * n[2](1)) /
731  trip;
732  // and finally, the equation we want to solve is:
733  // x - eig_term + cohcot*cohcot_coeff = 0
734  // but i divide by cohcot_coeff so the result has the units of
735  // stress, so using _f_tol as a convergence check is reasonable
736  eig_term /= cohcot_coeff;
737  Real residual = x / cohcot_coeff - eig_term + cohcot;
738  Real jacobian;
739  Real deriv_phi;
740  Real deriv_coh;
741  unsigned int iter = 0;
742  do
743  {
744  deriv_phi = dphi(intnl_old + x);
745  deriv_coh = dcohesion(intnl_old + x);
746  jacobian = 1.0 / cohcot_coeff + deriv_coh * cosphi / sinphi -
747  coh * deriv_phi / Utility::pow<2>(sinphi);
748  x += -residual / jacobian;
749 
750  if (iter > _max_iters) // not converging
751  {
752  nr_converged = false;
753  return false;
754  }
755 
756  sinphi = std::sin(phi(intnl_old + x));
757  cosphi = std::cos(phi(intnl_old + x));
758  coh = cohesion(intnl_old + x);
759  cohcos = coh * cosphi;
760  cohcot = cohcos / sinphi;
761  residual = x / cohcot_coeff - eig_term + cohcot;
762  iter++;
763  } while (residual * residual > _f_tol * _f_tol / 100);
764  }
765 
766  // so the NR process converged, but we must
767  // calculate the individual dpm values and
768  // check Kuhn-Tucker
769  nr_converged = true;
770  if (x < -3 * ep_plastic_tolerance)
771  // obviously at least one of the dpm are < -ep_plastic_tolerance. No point in proceeding. This
772  // is a potential weak-point: if the user has set _f_tol quite large, and ep_plastic_tolerance
773  // quite small, the above NR process will quickly converge, but the solution may be wrong and
774  // violate Kuhn-Tucker.
775  return false;
776 
777  // The following is the solution (A) written above
778  // (dpm[0] = triple(eigvals - cohcot, n[1], n[2])/trip, etc)
779  // in the isotropic situation
780  RealVectorValue v;
781  v(0) = eigvals[0] - cohcot;
782  v(1) = eigvals[1] - cohcot;
783  v(2) = eigvals[2] - cohcot;
784  dpm[0] = triple_product(v, n[1], n[2]) / trip;
785  dpm[1] = triple_product(v, n[2], n[0]) / trip;
786  dpm[2] = triple_product(v, n[0], n[1]) / trip;
787 
788  if (dpm[0] < -ep_plastic_tolerance || dpm[1] < -ep_plastic_tolerance ||
789  dpm[2] < -ep_plastic_tolerance)
790  // Kuhn-Tucker failure. No point in proceeding
791  return false;
792 
793  // Kuhn-Tucker has succeeded: just need returned_stress and yf values
794  // I do not use the dpm to calculate returned_stress, because that
795  // might add error (and computational effort), simply:
796  returned_stress(0, 0) = returned_stress(1, 1) = returned_stress(2, 2) = cohcot;
797  // So by construction the yield functions are all zero
798  yf[0] = yf[1] = yf[2] = yf[3] = yf[4] = yf[5] = 0;
799  return true;
800 }
801 
802 bool
803 TensorMechanicsPlasticMohrCoulombMulti::returnPlane(const std::vector<Real> & eigvals,
804  const std::vector<RealVectorValue> & n,
805  std::vector<Real> & dpm,
806  RankTwoTensor & returned_stress,
807  Real intnl_old,
808  Real & sinphi,
809  Real & cohcos,
810  Real initial_guess,
811  bool & nr_converged,
812  Real ep_plastic_tolerance,
813  std::vector<Real> & yf) const
814 {
815  // This returns to the Mohr-Coulomb plane using n[3] (ie 000100)
816  //
817  // The returned point is defined by the f[3]=0 and
818  // a = eigvals - dpm[3]*n[3]
819  // where "a" is the returned point and dpm[3] is the plastic multiplier.
820  // This equation is a vector equation in principal stress space.
821  // (Kuhn-Tucker also demands that dpm[3]>=0, but we leave checking
822  // that condition for the end.)
823  // Since f[3]=0, we must have
824  // a[2]*(1+sinphi) + a[0]*(-1+sinphi) - 2*coh*cosphi = 0
825  // which gives dpm[3] as the solution of
826  // alpha*dpm[3] + eigvals[2] - eigvals[0] + beta*sinphi - 2*coh*cosphi = 0
827  // with alpha = n[3](0) - n[3](2) - (n[3](2) + n[3](0))*sinphi
828  // beta = eigvals[2] + eigvals[0]
829 
830  mooseAssert(n.size() == 6,
831  "TensorMechanicsPlasticMohrCoulombMulti: Custom plane-return algorithm must be "
832  "supplied with n of size 6, whereas yours is "
833  << n.size());
834  mooseAssert(dpm.size() == 6,
835  "TensorMechanicsPlasticMohrCoulombMulti: Custom plane-return algorithm must be "
836  "supplied with dpm of size 6, whereas yours is "
837  << dpm.size());
838  mooseAssert(yf.size() == 6,
839  "TensorMechanicsPlasticMohrCoulombMulti: Custom tip-return algorithm must be "
840  "supplied with yf of size 6, whereas yours is "
841  << yf.size());
842 
843  dpm[3] = initial_guess;
844  sinphi = std::sin(phi(intnl_old + dpm[3]));
845  Real cosphi = std::cos(phi(intnl_old + dpm[3]));
846  Real coh = cohesion(intnl_old + dpm[3]);
847  cohcos = coh * cosphi;
848 
849  Real alpha = n[3](0) - n[3](2) - (n[3](2) + n[3](0)) * sinphi;
850  Real deriv_phi;
851  Real dalpha;
852  const Real beta = eigvals[2] + eigvals[0];
853  Real deriv_coh;
854 
855  Real residual =
856  alpha * dpm[3] + eigvals[2] - eigvals[0] + beta * sinphi - 2.0 * cohcos; // this is 2*yf[3]
857  Real jacobian;
858 
859  const Real f_tol2 = Utility::pow<2>(_f_tol);
860  unsigned int iter = 0;
861  do
862  {
863  deriv_phi = dphi(intnl_old + dpm[3]);
864  dalpha = -(n[3](2) + n[3](0)) * cosphi * deriv_phi;
865  deriv_coh = dcohesion(intnl_old + dpm[3]);
866  jacobian = alpha + dalpha * dpm[3] + beta * cosphi * deriv_phi - 2.0 * deriv_coh * cosphi +
867  2.0 * coh * sinphi * deriv_phi;
868 
869  dpm[3] -= residual / jacobian;
870  if (iter > _max_iters) // not converging
871  {
872  nr_converged = false;
873  return false;
874  }
875 
876  sinphi = std::sin(phi(intnl_old + dpm[3]));
877  cosphi = std::cos(phi(intnl_old + dpm[3]));
878  coh = cohesion(intnl_old + dpm[3]);
879  cohcos = coh * cosphi;
880  alpha = n[3](0) - n[3](2) - (n[3](2) + n[3](0)) * sinphi;
881  residual = alpha * dpm[3] + eigvals[2] - eigvals[0] + beta * sinphi - 2.0 * cohcos;
882  iter++;
883  } while (residual * residual > f_tol2);
884 
885  // so the NR process converged, but we must
886  // check Kuhn-Tucker
887  nr_converged = true;
888  if (dpm[3] < -ep_plastic_tolerance)
889  // Kuhn-Tucker failure
890  return false;
891 
892  for (unsigned i = 0; i < 3; ++i)
893  returned_stress(i, i) = eigvals[i] - dpm[3] * n[3](i);
895  returned_stress(0, 0), returned_stress(1, 1), returned_stress(2, 2), sinphi, cohcos, yf);
896 
897  // by construction abs(yf[3]) = abs(residual/2) < _f_tol/2
898  if (yf[0] > _f_tol || yf[1] > _f_tol || yf[2] > _f_tol || yf[4] > _f_tol || yf[5] > _f_tol)
899  // Kuhn-Tucker failure
900  return false;
901 
902  // success!
903  dpm[0] = dpm[1] = dpm[2] = dpm[4] = dpm[5] = 0;
904  return true;
905 }
906 
907 bool
909  const std::vector<RealVectorValue> & n,
910  std::vector<Real> & dpm,
911  RankTwoTensor & returned_stress,
912  Real intnl_old,
913  Real & sinphi,
914  Real & cohcos,
915  Real initial_guess,
916  Real mag_E,
917  bool & nr_converged,
918  Real ep_plastic_tolerance,
919  std::vector<Real> & yf) const
920 {
921  // This returns to the Mohr-Coulomb edge
922  // with 000101 being active. This means that
923  // f3=f5=0. Denoting the returned stress by "a"
924  // (in principal stress space), this means that
925  // a0=a1 = (2Ccosphi + a2(1+sinphi))/(sinphi-1)
926  //
927  // Also, a = eigvals - dpm3*n3 - dpm5*n5,
928  // where the dpm are the plastic multipliers
929  // and the n are the flow directions.
930  //
931  // Hence we have 5 equations and 5 unknowns (a,
932  // dpm3 and dpm5). Eliminating all unknowns
933  // except for x = dpm3+dpm5 gives the residual below
934  // (I used mathematica)
935 
936  Real x = initial_guess;
937  sinphi = std::sin(phi(intnl_old + x));
938  Real cosphi = std::cos(phi(intnl_old + x));
939  Real coh = cohesion(intnl_old + x);
940  cohcos = coh * cosphi;
941 
942  const Real numer_const =
943  -n[3](2) * eigvals[0] - n[5](1) * eigvals[0] + n[5](2) * eigvals[0] + n[3](2) * eigvals[1] +
944  n[5](0) * eigvals[1] - n[5](2) * eigvals[1] - n[5](0) * eigvals[2] + n[5](1) * eigvals[2] +
945  n[3](0) * (-eigvals[1] + eigvals[2]) - n[3](1) * (-eigvals[0] + eigvals[2]);
946  const Real numer_coeff1 = 2 * (-n[3](0) + n[3](1) + n[5](0) - n[5](1));
947  const Real numer_coeff2 =
948  n[5](2) * (eigvals[0] - eigvals[1]) + n[3](2) * (-eigvals[0] + eigvals[1]) +
949  n[5](1) * (eigvals[0] + eigvals[2]) + (n[3](0) - n[5](0)) * (eigvals[1] + eigvals[2]) -
950  n[3](1) * (eigvals[0] + eigvals[2]);
951  Real numer = numer_const + numer_coeff1 * cohcos + numer_coeff2 * sinphi;
952  const Real denom_const = -n[3](2) * (n[5](0) - n[5](1)) - n[3](1) * (-n[5](0) + n[5](2)) +
953  n[3](0) * (-n[5](1) + n[5](2));
954  const Real denom_coeff = -n[3](2) * (n[5](0) - n[5](1)) - n[3](1) * (n[5](0) + n[5](2)) +
955  n[3](0) * (n[5](1) + n[5](2));
956  Real denom = denom_const + denom_coeff * sinphi;
957  Real residual = -x + numer / denom;
958 
959  Real deriv_phi;
960  Real deriv_coh;
961  Real jacobian;
962  const Real tol = Utility::pow<2>(_f_tol / (mag_E * 10.0));
963  unsigned int iter = 0;
964  do
965  {
966  do
967  {
968  deriv_phi = dphi(intnl_old + dpm[3]);
969  deriv_coh = dcohesion(intnl_old + dpm[3]);
970  jacobian = -1 +
971  (numer_coeff1 * deriv_coh * cosphi - numer_coeff1 * coh * sinphi * deriv_phi +
972  numer_coeff2 * cosphi * deriv_phi) /
973  denom -
974  numer * denom_coeff * cosphi * deriv_phi / denom / denom;
975  x -= residual / jacobian;
976  if (iter > _max_iters) // not converging
977  {
978  nr_converged = false;
979  return false;
980  }
981 
982  sinphi = std::sin(phi(intnl_old + x));
983  cosphi = std::cos(phi(intnl_old + x));
984  coh = cohesion(intnl_old + x);
985  cohcos = coh * cosphi;
986  numer = numer_const + numer_coeff1 * cohcos + numer_coeff2 * sinphi;
987  denom = denom_const + denom_coeff * sinphi;
988  residual = -x + numer / denom;
989  iter++;
990  } while (residual * residual > tol);
991 
992  // now must ensure that yf[3] and yf[5] are both "zero"
993  const Real dpm3minusdpm5 =
994  (2.0 * (eigvals[0] - eigvals[1]) + x * (n[3](1) - n[3](0) + n[5](1) - n[5](0))) /
995  (n[3](0) - n[3](1) + n[5](1) - n[5](0));
996  dpm[3] = (x + dpm3minusdpm5) / 2.0;
997  dpm[5] = (x - dpm3minusdpm5) / 2.0;
998 
999  for (unsigned i = 0; i < 3; ++i)
1000  returned_stress(i, i) = eigvals[i] - dpm[3] * n[3](i) - dpm[5] * n[5](i);
1002  returned_stress(0, 0), returned_stress(1, 1), returned_stress(2, 2), sinphi, cohcos, yf);
1003  } while (yf[3] * yf[3] > _f_tol * _f_tol && yf[5] * yf[5] > _f_tol * _f_tol);
1004 
1005  // so the NR process converged, but we must
1006  // check Kuhn-Tucker
1007  nr_converged = true;
1008 
1009  if (dpm[3] < -ep_plastic_tolerance || dpm[5] < -ep_plastic_tolerance)
1010  // Kuhn-Tucker failure. This is a potential weak-point: if the user has set _f_tol quite
1011  // large, and ep_plastic_tolerance quite small, the above NR process will quickly converge, but
1012  // the solution may be wrong and violate Kuhn-Tucker.
1013  return false;
1014 
1015  if (yf[0] > _f_tol || yf[1] > _f_tol || yf[2] > _f_tol || yf[4] > _f_tol)
1016  // Kuhn-Tucker failure
1017  return false;
1018 
1019  // success
1020  dpm[0] = dpm[1] = dpm[2] = dpm[4] = 0;
1021  return true;
1022 }
1023 
1024 bool
1026  const std::vector<RealVectorValue> & n,
1027  std::vector<Real> & dpm,
1028  RankTwoTensor & returned_stress,
1029  Real intnl_old,
1030  Real & sinphi,
1031  Real & cohcos,
1032  Real initial_guess,
1033  Real mag_E,
1034  bool & nr_converged,
1035  Real ep_plastic_tolerance,
1036  std::vector<Real> & yf) const
1037 {
1038  // This returns to the Mohr-Coulomb edge
1039  // with 010100 being active. This means that
1040  // f1=f3=0. Denoting the returned stress by "a"
1041  // (in principal stress space), this means that
1042  // a1=a2 = (2Ccosphi + a0(1-sinphi))/(sinphi+1)
1043  //
1044  // Also, a = eigvals - dpm1*n1 - dpm3*n3,
1045  // where the dpm are the plastic multipliers
1046  // and the n are the flow directions.
1047  //
1048  // Hence we have 5 equations and 5 unknowns (a,
1049  // dpm1 and dpm3). Eliminating all unknowns
1050  // except for x = dpm1+dpm3 gives the residual below
1051  // (I used mathematica)
1052 
1053  Real x = initial_guess;
1054  sinphi = std::sin(phi(intnl_old + x));
1055  Real cosphi = std::cos(phi(intnl_old + x));
1056  Real coh = cohesion(intnl_old + x);
1057  cohcos = coh * cosphi;
1058 
1059  const Real numer_const = -n[1](2) * eigvals[0] - n[3](1) * eigvals[0] + n[3](2) * eigvals[0] -
1060  n[1](0) * eigvals[1] + n[1](2) * eigvals[1] + n[3](0) * eigvals[1] -
1061  n[3](2) * eigvals[1] + n[1](0) * eigvals[2] - n[3](0) * eigvals[2] +
1062  n[3](1) * eigvals[2] - n[1](1) * (-eigvals[0] + eigvals[2]);
1063  const Real numer_coeff1 = 2 * (n[1](1) - n[1](2) - n[3](1) + n[3](2));
1064  const Real numer_coeff2 =
1065  n[3](2) * (-eigvals[0] - eigvals[1]) + n[1](2) * (eigvals[0] + eigvals[1]) +
1066  n[3](1) * (eigvals[0] + eigvals[2]) + (n[1](0) - n[3](0)) * (eigvals[1] - eigvals[2]) -
1067  n[1](1) * (eigvals[0] + eigvals[2]);
1068  Real numer = numer_const + numer_coeff1 * cohcos + numer_coeff2 * sinphi;
1069  const Real denom_const = -n[1](0) * (n[3](1) - n[3](2)) + n[1](2) * (-n[3](0) + n[3](1)) +
1070  n[1](1) * (-n[3](2) + n[3](0));
1071  const Real denom_coeff =
1072  n[1](0) * (n[3](1) - n[3](2)) + n[1](2) * (n[3](0) + n[3](1)) - n[1](1) * (n[3](0) + n[3](2));
1073  Real denom = denom_const + denom_coeff * sinphi;
1074  Real residual = -x + numer / denom;
1075 
1076  Real deriv_phi;
1077  Real deriv_coh;
1078  Real jacobian;
1079  const Real tol = Utility::pow<2>(_f_tol / (mag_E * 10.0));
1080  unsigned int iter = 0;
1081  do
1082  {
1083  do
1084  {
1085  deriv_phi = dphi(intnl_old + dpm[3]);
1086  deriv_coh = dcohesion(intnl_old + dpm[3]);
1087  jacobian = -1 +
1088  (numer_coeff1 * deriv_coh * cosphi - numer_coeff1 * coh * sinphi * deriv_phi +
1089  numer_coeff2 * cosphi * deriv_phi) /
1090  denom -
1091  numer * denom_coeff * cosphi * deriv_phi / denom / denom;
1092  x -= residual / jacobian;
1093  if (iter > _max_iters) // not converging
1094  {
1095  nr_converged = false;
1096  return false;
1097  }
1098 
1099  sinphi = std::sin(phi(intnl_old + x));
1100  cosphi = std::cos(phi(intnl_old + x));
1101  coh = cohesion(intnl_old + x);
1102  cohcos = coh * cosphi;
1103  numer = numer_const + numer_coeff1 * cohcos + numer_coeff2 * sinphi;
1104  denom = denom_const + denom_coeff * sinphi;
1105  residual = -x + numer / denom;
1106  iter++;
1107  } while (residual * residual > tol);
1108 
1109  // now must ensure that yf[1] and yf[3] are both "zero"
1110  Real dpm1minusdpm3 =
1111  (2 * (eigvals[1] - eigvals[2]) + x * (n[1](2) - n[1](1) + n[3](2) - n[3](1))) /
1112  (n[1](1) - n[1](2) + n[3](2) - n[3](1));
1113  dpm[1] = (x + dpm1minusdpm3) / 2.0;
1114  dpm[3] = (x - dpm1minusdpm3) / 2.0;
1115 
1116  for (unsigned i = 0; i < 3; ++i)
1117  returned_stress(i, i) = eigvals[i] - dpm[1] * n[1](i) - dpm[3] * n[3](i);
1119  returned_stress(0, 0), returned_stress(1, 1), returned_stress(2, 2), sinphi, cohcos, yf);
1120  } while (yf[1] * yf[1] > _f_tol * _f_tol && yf[3] * yf[3] > _f_tol * _f_tol);
1121 
1122  // so the NR process converged, but we must
1123  // check Kuhn-Tucker
1124  nr_converged = true;
1125 
1126  if (dpm[1] < -ep_plastic_tolerance || dpm[3] < -ep_plastic_tolerance)
1127  // Kuhn-Tucker failure. This is a potential weak-point: if the user has set _f_tol quite
1128  // large, and ep_plastic_tolerance quite small, the above NR process will quickly converge, but
1129  // the solution may be wrong and violate Kuhn-Tucker
1130  return false;
1131 
1132  if (yf[0] > _f_tol || yf[2] > _f_tol || yf[4] > _f_tol || yf[5] > _f_tol)
1133  // Kuhn-Tucker failure
1134  return false;
1135 
1136  // success
1137  dpm[0] = dpm[2] = dpm[4] = dpm[5] = 0;
1138  return true;
1139 }
1140 
1141 bool
1143  const std::vector<Real> & dpm,
1144  Real ep_plastic_tolerance) const
1145 {
1146  mooseAssert(
1147  yf.size() == 6,
1148  "TensorMechanicsPlasticMohrCoulomb::KuhnTuckerOK requires yf to be size 6, but your is "
1149  << yf.size());
1150  mooseAssert(
1151  dpm.size() == 6,
1152  "TensorMechanicsPlasticMohrCoulomb::KuhnTuckerOK requires dpm to be size 6, but your is "
1153  << dpm.size());
1154  for (unsigned i = 0; i < 6; ++i)
1155  if (!TensorMechanicsPlasticModel::KuhnTuckerSingleSurface(yf[i], dpm[i], ep_plastic_tolerance))
1156  return false;
1157  return true;
1158 }
1159 
1160 bool
1162 {
1163  return _use_custom_returnMap;
1164 }
TensorMechanicsPlasticMohrCoulombMulti::_max_iters
const unsigned int _max_iters
Maximum Newton-Raphison iterations in the custom returnMap algorithm.
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:109
TensorMechanicsPlasticMohrCoulombMulti
FiniteStrainMohrCoulombMulti implements rate-independent non-associative mohr-coulomb with hardening/...
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:24
TensorMechanicsPlasticMohrCoulombMulti::df_dsig
void df_dsig(const RankTwoTensor &stress, Real sin_angle, std::vector< RankTwoTensor > &df) const
this is exactly dyieldFunction_dstress, or flowPotential, depending on whether sin_angle = sin(phi),...
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:141
TensorMechanicsPlasticMohrCoulombMulti::dpsi
virtual Real dpsi(const Real internal_param) const
d(psi)/d(internal_param) as a function of residual value, rate, and internal_param
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:312
TensorMechanicsPlasticMohrCoulombMulti::modelName
virtual std::string modelName() const override
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:318
TensorMechanicsPlasticMohrCoulombMulti::flowPotentialV
virtual void flowPotentialV(const RankTwoTensor &stress, Real intnl, std::vector< RankTwoTensor > &r) const override
The flow potentials.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:192
TensorMechanicsPlasticModel::validParams
static InputParameters validParams()
Definition: TensorMechanicsPlasticModel.C:18
TensorMechanicsPlasticMohrCoulombMulti::edge000101
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:325
TensorMechanicsPlasticMohrCoulombMulti::tip110100
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:322
TensorMechanicsPlasticMohrCoulombMulti::returnEdge000101
bool returnEdge000101(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real &sinphi, Real &cohcos, Real initial_guess, Real mag_E, bool &nr_converged, Real ep_plastic_tolerance, std::vector< Real > &yf) const
Tries to return-map to the MC edge using the n[4] and n[6] directions The return value is true if the...
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:908
TensorMechanicsPlasticMohrCoulombMulti::returnPlane
bool returnPlane(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real &sinphi, Real &cohcos, Real initial_guess, bool &nr_converged, Real ep_plastic_tolerance, std::vector< Real > &yf) const
Tries to return-map to the MC plane using the n[3] direction The return value is true if the internal...
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:803
TensorMechanicsPlasticMohrCoulombMulti::KuhnTuckerOK
bool KuhnTuckerOK(const std::vector< Real > &yf, const std::vector< Real > &dpm, Real ep_plastic_tolerance) const
Returns true if the Kuhn-Tucker conditions are satisfied.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:1142
TensorMechanicsPlasticMohrCoulombMulti::dflowPotential_dintnlV
virtual void dflowPotential_dintnlV(const RankTwoTensor &stress, Real intnl, std::vector< RankTwoTensor > &dr_dintnl) const override
The derivative of the flow potential with respect to the internal parameter.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:225
defineLegacyParams
defineLegacyParams(TensorMechanicsPlasticMohrCoulombMulti)
TensorMechanicsPlasticMohrCoulombMulti::returnEdge010100
bool returnEdge010100(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real &sinphi, Real &cohcos, Real initial_guess, Real mag_E, bool &nr_converged, Real ep_plastic_tolerance, std::vector< Real > &yf) const
Tries to return-map to the MC edge using the n[1] and n[3] directions The return value is true if the...
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:1025
TensorMechanicsPlasticMohrCoulombMulti::dphi
virtual Real dphi(const Real internal_param) const
d(phi)/d(internal_param) as a function of residual value, rate, and internal_param
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:300
TensorMechanicsPlasticMohrCoulombMulti::validParams
static InputParameters validParams()
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:22
TensorMechanicsPlasticMohrCoulombMulti::cohesion
virtual Real cohesion(const Real internal_param) const
cohesion as a function of residual value, rate, and internal_param
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:282
TensorMechanicsPlasticMohrCoulombMulti::_cohesion
const TensorMechanicsHardeningModel & _cohesion
Hardening model for cohesion.
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:100
TensorMechanicsPlasticMohrCoulombMulti::_phi
const TensorMechanicsHardeningModel & _phi
Hardening model for phi.
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:103
TensorMechanicsPlasticModel::KuhnTuckerSingleSurface
bool KuhnTuckerSingleSurface(Real yf, Real dpm, Real dpm_tol) const
Returns true if the Kuhn-Tucker conditions for the single surface are satisfied.
Definition: TensorMechanicsPlasticModel.C:248
TensorMechanicsPlasticMohrCoulombMulti::edge010100
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:324
TensorMechanicsPlasticMohrCoulombMulti.h
TensorMechanicsPlasticMohrCoulombMulti::_shift
const Real _shift
yield function is shifted by this amount to avoid problems with stress-derivatives at equal eigenvalu...
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:112
TensorMechanicsPlasticMohrCoulombMulti::plane000100
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:326
TensorMechanicsPlasticMohrCoulombMulti::doReturnMap
bool doReturnMap(const RankTwoTensor &trial_stress, Real intnl_old, const RankFourTensor &E_ijkl, Real ep_plastic_tolerance, RankTwoTensor &returned_stress, Real &returned_intnl, std::vector< Real > &dpm, RankTwoTensor &delta_dp, std::vector< Real > &yf, bool &trial_stress_inadmissible) const
See doco for returnMap function.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:360
TensorMechanicsPlasticMohrCoulombMulti::dyieldFunction_dstressV
virtual void dyieldFunction_dstressV(const RankTwoTensor &stress, Real intnl, std::vector< RankTwoTensor > &df_dstress) const override
The derivative of yield functions with respect to stress.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:162
TensorMechanicsPlasticMohrCoulombMulti::_psi
const TensorMechanicsHardeningModel & _psi
Hardening model for psi.
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:106
TensorMechanicsPlasticMohrCoulombMulti::activeConstraints
virtual void activeConstraints(const std::vector< Real > &f, const RankTwoTensor &stress, Real intnl, const RankFourTensor &Eijkl, std::vector< bool > &act, RankTwoTensor &returned_stress) const override
The active yield surfaces, given a vector of yield functions.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:245
TensorMechanicsPlasticMohrCoulombMulti::dcohesion
virtual Real dcohesion(const Real internal_param) const
d(cohesion)/d(internal_param) as a function of residual value, rate, and internal_param
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:288
TensorMechanicsPlasticMohrCoulombMulti::dflowPotential_dstressV
virtual void dflowPotential_dstressV(const RankTwoTensor &stress, Real intnl, std::vector< RankFourTensor > &dr_dstress) const override
The derivative of the flow potential with respect to stress.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:201
TensorMechanicsPlasticModel::_f_tol
const Real _f_tol
Tolerance on yield function.
Definition: TensorMechanicsPlasticModel.h:175
TensorMechanicsPlasticMohrCoulombMulti::returnMap
virtual bool returnMap(const RankTwoTensor &trial_stress, Real intnl_old, const RankFourTensor &E_ijkl, Real ep_plastic_tolerance, RankTwoTensor &returned_stress, Real &returned_intnl, std::vector< Real > &dpm, RankTwoTensor &delta_dp, std::vector< Real > &yf, bool &trial_stress_inadmissible) const override
Performs a custom return-map.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:324
TensorMechanicsHardeningModel::modelName
virtual std::string modelName() const =0
TensorMechanicsPlasticMohrCoulombMulti::returnTip
bool returnTip(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real &sinphi, Real &cohcos, Real initial_guess, bool &nr_converged, Real ep_plastic_tolerance, std::vector< Real > &yf) const
Tries to return-map to the MC tip using the THREE directions given in n, and THREE dpm values are ret...
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:635
tol
const double tol
Definition: Setup.h:18
TensorMechanicsHardeningModel::derivative
virtual Real derivative(Real intnl) const
Definition: TensorMechanicsHardeningModel.C:47
TensorMechanicsPlasticMohrCoulombMulti::TensorMechanicsPlasticMohrCoulombMulti
TensorMechanicsPlasticMohrCoulombMulti(const InputParameters &parameters)
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:59
registerMooseObject
registerMooseObject("TensorMechanicsApp", TensorMechanicsPlasticMohrCoulombMulti)
TensorMechanicsPlasticModel::returnMap
virtual bool returnMap(const RankTwoTensor &trial_stress, Real intnl_old, const RankFourTensor &E_ijkl, Real ep_plastic_tolerance, RankTwoTensor &returned_stress, Real &returned_intnl, std::vector< Real > &dpm, RankTwoTensor &delta_dp, std::vector< Real > &yf, bool &trial_stress_inadmissible) const
Performs a custom return-map.
Definition: TensorMechanicsPlasticModel.C:221
TensorMechanicsHardeningModel::value
virtual Real value(Real intnl) const
Definition: TensorMechanicsHardeningModel.C:45
RankTwoTensor
RankTwoTensorTempl< Real > RankTwoTensor
Definition: ACGrGrElasticDrivingForce.h:17
TensorMechanicsPlasticMohrCoulombMulti::tip010101
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:323
RankFourTensorTempl< Real >
TensorMechanicsPlasticModel
Plastic Model base class The virtual functions written below must be over-ridden in derived classes t...
Definition: TensorMechanicsPlasticModel.h:42
TensorMechanicsPlasticMohrCoulombMulti::psi
virtual Real psi(const Real internal_param) const
psi as a function of residual value, rate, and internal_param
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:306
TensorMechanicsPlasticMohrCoulombMulti::dyieldFunction_dintnlV
virtual void dyieldFunction_dintnlV(const RankTwoTensor &stress, Real intnl, std::vector< Real > &df_dintnl) const override
The derivative of yield functions with respect to the internal parameter.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:170
RankTwoTensorTempl< Real >
TensorMechanicsPlasticMohrCoulombMulti::perturbStress
void perturbStress(const RankTwoTensor &stress, std::vector< Real > &eigvals, std::vector< RankTwoTensor > &deigvals) const
perturbs the stress tensor in the case of almost-equal eigenvalues.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:121
TensorMechanicsPlasticMohrCoulombMulti::numberSurfaces
virtual unsigned int numberSurfaces() const override
The number of yield surfaces for this plasticity model.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:80
TensorMechanicsPlasticMohrCoulombMulti::useCustomReturnMap
virtual bool useCustomReturnMap() const override
Returns false. You will want to override this in your derived class if you write a custom returnMap f...
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:1161
TensorMechanicsPlasticMohrCoulombMulti::yieldFunctionV
virtual void yieldFunctionV(const RankTwoTensor &stress, Real intnl, std::vector< Real > &f) const override
Calculates the yield functions.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:86
TensorMechanicsPlasticMohrCoulombMulti::yieldFunctionEigvals
void yieldFunctionEigvals(Real e0, Real e1, Real e2, Real sinphi, Real cohcos, std::vector< Real > &f) const
Calculates the yield functions given the eigenvalues of stress.
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:103
TensorMechanicsPlasticMohrCoulombMulti::_use_custom_returnMap
const bool _use_custom_returnMap
Whether to use the custom return-map algorithm.
Definition: TensorMechanicsPlasticMohrCoulombMulti.h:115
TensorMechanicsPlasticMohrCoulombMulti::phi
virtual Real phi(const Real internal_param) const
phi as a function of residual value, rate, and internal_param
Definition: TensorMechanicsPlasticMohrCoulombMulti.C:294
TensorMechanicsHardeningModel
Hardening Model base class.
Definition: TensorMechanicsHardeningModel.h:27