11 #include "RankFourTensor.h"
14 #include "MooseRandom.h"
24 params.addClassDescription(
"Associative tensile plasticity with hardening/softening");
25 params.addRequiredParam<UserObjectName>(
27 "A TensorMechanicsHardening UserObject that defines hardening of the tensile strength");
28 params.addParam<Real>(
"shift",
29 "Yield surface is shifted by this amount to avoid problems with "
30 "defining derivatives when eigenvalues are equal. If this is "
31 "larger than f_tol, a warning will be issued. Default = f_tol.");
32 params.addParam<
unsigned int>(
"max_iterations",
34 "Maximum number of Newton-Raphson iterations "
35 "allowed in the custom return-map algorithm. "
36 " For highly nonlinear hardening this may "
37 "need to be higher than 10.");
38 params.addParam<
bool>(
"use_custom_returnMap",
40 "Whether to use the custom returnMap "
41 "algorithm. Set to true if you are using "
42 "isotropic elasticity.");
43 params.addParam<
bool>(
"use_custom_cto",
45 "Whether to use the custom consistent tangent "
46 "operator computations. Set to true if you are "
47 "using isotropic elasticity.");
52 const InputParameters & parameters)
55 _max_iters(getParam<unsigned int>(
"max_iterations")),
56 _shift(parameters.isParamValid(
"shift") ? getParam<Real>(
"shift") : _f_tol),
57 _use_custom_returnMap(getParam<bool>(
"use_custom_returnMap")),
58 _use_custom_cto(getParam<bool>(
"use_custom_cto"))
61 mooseError(
"Value of 'shift' in TensorMechanicsPlasticTensileMulti must not be negative\n");
63 _console <<
"WARNING: value of 'shift' in TensorMechanicsPlasticTensileMulti is probably set "
66 mooseError(
"TensorMechanicsPlasticTensileMulti is only defined for LIBMESH_DIM=3");
79 std::vector<Real> & f)
const
81 std::vector<Real> eigvals;
82 stress.symmetricEigenvalues(eigvals);
86 f[0] = eigvals[0] +
_shift - str;
87 f[1] = eigvals[1] - str;
88 f[2] = eigvals[2] -
_shift - str;
93 const RankTwoTensor & stress, Real , std::vector<RankTwoTensor> & df_dstress)
const
95 std::vector<Real> eigvals;
96 stress.dsymmetricEigenvalues(eigvals, df_dstress);
98 if (eigvals[0] > eigvals[1] - 0.1 *
_shift || eigvals[1] > eigvals[2] - 0.1 *
_shift)
100 Real small_perturbation;
102 while (eigvals[0] > eigvals[1] - 0.1 *
_shift || eigvals[1] > eigvals[2] - 0.1 *
_shift)
104 for (
unsigned i = 0; i < 3; ++i)
105 for (
unsigned j = 0; j <= i; ++j)
107 small_perturbation = 0.1 *
_shift * 2 * (MooseRandom::rand() - 0.5);
108 shifted_stress(i, j) += small_perturbation;
109 shifted_stress(j, i) += small_perturbation;
111 shifted_stress.dsymmetricEigenvalues(eigvals, df_dstress);
119 std::vector<Real> & df_dintnl)
const
127 std::vector<RankTwoTensor> & r)
const
135 const RankTwoTensor & stress, Real , std::vector<RankFourTensor> & dr_dstress)
const
137 stress.d2symmetricEigenvalues(dr_dstress);
142 const RankTwoTensor & , Real , std::vector<RankTwoTensor> & dr_dintnl)
const
164 std::vector<bool> & act,
167 act.assign(3,
false);
171 returned_stress = stress;
176 std::vector<Real> dpm(3);
178 std::vector<Real> yf(3);
179 bool trial_stress_inadmissible;
189 trial_stress_inadmissible);
191 for (
unsigned i = 0; i < 3; ++i)
192 act[i] = (dpm[i] > 0);
197 const std::vector<Real> & b)
const
199 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
204 const std::vector<Real> & b,
205 const std::vector<Real> & c)
const
207 return a[0] * (b[1] * c[2] - b[2] * c[1]) - a[1] * (b[0] * c[2] - b[2] * c[0]) +
208 a[2] * (b[0] * c[1] - b[1] * c[0]);
214 return "TensileMulti";
221 Real ep_plastic_tolerance,
223 Real & returned_intnl,
224 std::vector<Real> & dpm,
226 std::vector<Real> & yf,
227 bool & trial_stress_inadmissible)
const
233 ep_plastic_tolerance,
239 trial_stress_inadmissible);
244 ep_plastic_tolerance,
250 trial_stress_inadmissible);
257 Real ep_plastic_tolerance,
259 Real & returned_intnl,
260 std::vector<Real> & dpm,
262 std::vector<Real> & yf,
263 bool & trial_stress_inadmissible)
const
265 mooseAssert(dpm.size() == 3,
266 "TensorMechanicsPlasticTensileMulti size of dpm should be 3 but it is "
269 std::vector<Real> eigvals;
271 trial_stress.symmetricEigenvaluesEigenvectors(eigvals, eigvecs);
278 yf[0] = eigvals[0] - str;
279 yf[1] = eigvals[1] - str;
280 yf[2] = eigvals[2] - str;
285 trial_stress_inadmissible =
false;
289 trial_stress_inadmissible =
true;
291 returned_stress.zero();
314 std::vector<RealVectorValue> n(3);
315 n[0](0) = E_ijkl(0, 0, 0, 0);
316 n[0](1) = E_ijkl(1, 1, 0, 0);
317 n[0](2) = E_ijkl(2, 2, 0, 0);
318 n[1](0) = E_ijkl(0, 0, 1, 1);
319 n[1](1) = E_ijkl(1, 1, 1, 1);
320 n[1](2) = E_ijkl(2, 2, 1, 1);
321 n[2](0) = E_ijkl(0, 0, 2, 2);
322 n[2](1) = E_ijkl(1, 1, 2, 2);
323 n[2](2) = E_ijkl(2, 2, 2, 2);
335 const unsigned int number_of_return_paths = 3;
336 std::vector<int> trial_order(number_of_return_paths);
340 trial_order[0] =
tip;
341 trial_order[1] =
edge;
342 trial_order[2] =
plane;
346 trial_order[0] =
edge;
347 trial_order[1] =
tip;
348 trial_order[2] =
plane;
352 trial_order[0] =
plane;
353 trial_order[1] =
edge;
354 trial_order[2] =
tip;
358 bool nr_converged =
false;
359 for (trial = 0; trial < number_of_return_paths; ++trial)
361 switch (trial_order[trial])
364 nr_converged =
returnTip(eigvals, n, dpm, returned_stress, intnl_old, 0);
367 nr_converged =
returnEdge(eigvals, n, dpm, returned_stress, intnl_old, 0);
370 nr_converged =
returnPlane(eigvals, n, dpm, returned_stress, intnl_old, 0);
376 if (nr_converged &&
KuhnTuckerOK(returned_stress, dpm, str, ep_plastic_tolerance))
380 if (trial == number_of_return_paths)
382 Moose::err <<
"Trial stress = \n";
383 trial_stress.print(Moose::err);
384 Moose::err <<
"Internal parameter = " << intnl_old <<
"\n";
385 mooseError(
"TensorMechanicsPlasticTensileMulti: FAILURE! You probably need to implement a "
389 yf[0] = eigvals[0] - str;
390 yf[1] = eigvals[1] - str;
391 yf[2] = eigvals[2] - str;
397 returned_intnl = intnl_old;
398 for (
unsigned i = 0; i < 3; ++i)
400 yf[i] = returned_stress(i, i) - str;
401 delta_dp(i, i) = dpm[i];
402 returned_intnl += dpm[i];
404 returned_stress = eigvecs * returned_stress * (eigvecs.transpose());
405 delta_dp = eigvecs * delta_dp * (eigvecs.transpose());
411 const std::vector<RealVectorValue> & n,
412 std::vector<Real> & dpm,
415 Real initial_guess)
const
435 Real x = initial_guess;
436 const Real denom = (n[0](0) - n[0](1)) * (n[0](0) + 2 * n[0](1));
449 const Real eig = eigvals[0] + eigvals[1] + eigvals[2];
450 const Real bul = (n[0](0) + 2 * n[0](1));
458 Real residual = bul * x - eig + 3 * str;
460 unsigned int iter = 0;
464 x += -residual / jacobian;
468 residual = bul * x - eig + 3 * str;
476 dpm[0] = (n[0](0) * (eigvals[0] - str) + n[0](1) * (eigvals[0] - eigvals[1] - eigvals[2] + str)) /
478 dpm[1] = (n[0](0) * (eigvals[1] - str) + n[0](1) * (eigvals[1] - eigvals[2] - eigvals[0] + str)) /
480 dpm[2] = (n[0](0) * (eigvals[2] - str) + n[0](1) * (eigvals[2] - eigvals[0] - eigvals[1] + str)) /
482 returned_stress(0, 0) = returned_stress(1, 1) = returned_stress(2, 2) = str;
488 const std::vector<RealVectorValue> & n,
489 std::vector<Real> & dpm,
492 Real initial_guess)
const
516 Real x = initial_guess;
517 const Real denom = n[0](0) + n[0](1);
530 const Real eig = eigvals[1] + eigvals[2];
531 Real residual = denom * x - eig + 2 * str;
533 unsigned int iter = 0;
537 x += -residual / jacobian;
541 residual = denom * x - eig + 2 * str;
547 dpm[1] = ((eigvals[1] * n[0](0) - eigvals[2] * n[0](1)) / (n[0](0) - n[0](1)) - str) / denom;
548 dpm[2] = ((eigvals[2] * n[0](0) - eigvals[1] * n[0](1)) / (n[0](0) - n[0](1)) - str) / denom;
550 returned_stress(0, 0) = eigvals[0] - n[0](1) * (dpm[1] + dpm[2]);
551 returned_stress(1, 1) = returned_stress(2, 2) = str;
557 const std::vector<RealVectorValue> & n,
558 std::vector<Real> & dpm,
561 Real initial_guess)
const
579 dpm[2] = initial_guess;
580 Real residual = n[2](2) * dpm[2] - eigvals[2] +
tensile_strength(intnl_old + dpm[2]);
582 unsigned int iter = 0;
586 dpm[2] += -residual / jacobian;
589 residual = n[2](2) * dpm[2] - eigvals[2] +
tensile_strength(intnl_old + dpm[2]);
595 returned_stress(0, 0) = eigvals[0] - dpm[2] * n[2](0);
596 returned_stress(1, 1) = eigvals[1] - dpm[2] * n[2](1);
597 returned_stress(2, 2) = eigvals[2] - dpm[2] * n[2](2);
603 const std::vector<Real> & dpm,
605 Real ep_plastic_tolerance)
const
607 for (
unsigned i = 0; i < 3; ++i)
609 returned_diagonal_stress(i, i) - str, dpm[i], ep_plastic_tolerance))
621 const std::vector<Real> & cumulative_pm)
const
625 trial_stress, intnl_old, stress, intnl, E_ijkl, cumulative_pm);
627 mooseAssert(cumulative_pm.size() == 3,
628 "TensorMechanicsPlasticTensileMulti size of cumulative_pm should be 3 but it is "
629 << cumulative_pm.size());
631 if (cumulative_pm[2] <= 0)
635 std::vector<Real> eigvals;
636 stress.symmetricEigenvalues(eigvals);
641 std::vector<Real> trial_eigvals;
643 trial_stress.symmetricEigenvaluesEigenvectors(trial_eigvals, trial_eigvecs);
675 const Real la = E_ijkl(0, 0, 1, 1);
676 const Real mu = 0.5 * (E_ijkl(0, 0, 0, 0) - la);
678 if (cumulative_pm[1] <= 0)
681 const Real denom = hard + la + 2 * mu;
682 const Real al = la * la / denom;
683 const Real be = la * (la + 2 * mu) / denom;
684 const Real ga = hard * (la + 2 * mu) / denom;
685 std::vector<Real> comps(9);
686 comps[0] = comps[4] = la + 2 * mu - al;
687 comps[1] = comps[3] = la - al;
688 comps[2] = comps[5] = comps[6] = comps[7] = la - be;
690 cto.fillFromInputVector(comps, RankFourTensor::principal);
692 else if (cumulative_pm[0] <= 0)
695 const Real denom = 2 * hard + 2 * la + 2 * mu;
696 const Real al = hard * 2 * la / denom;
697 const Real be = hard * (2 * la + 2 * mu) / denom;
698 std::vector<Real> comps(9);
699 comps[0] = la + 2 * mu - 2 * la * la / denom;
700 comps[1] = comps[2] = al;
701 comps[3] = comps[6] = al;
702 comps[4] = comps[5] = comps[7] = comps[8] = be;
703 cto.fillFromInputVector(comps, RankFourTensor::principal);
708 const Real denom = 3 * hard + 3 * la + 2 * mu;
709 std::vector<Real> comps(2);
710 comps[0] = hard * (3 * la + 2 * mu) / denom;
712 cto.fillFromInputVector(comps, RankFourTensor::symmetric_isotropic);
715 cto.rotate(trial_eigvecs);
734 for (
unsigned k = 0; k < 3; ++k)
735 for (
unsigned b = 0; b < 3; ++b)
739 for (
unsigned m = 0; m < 3; ++m)
740 for (
unsigned n = 0; n < 3; ++n)
741 for (
unsigned i = 0; i < 3; ++i)
742 drdsig(i, k, m, n) += trial_eigvecs(m, b) * trial_eigvecs(n, k) * trial_eigvecs(i, b) /
743 (trial_eigvals[k] - trial_eigvals[b]);
753 for (
unsigned i = 0; i < 3; ++i)
754 for (
unsigned j = 0; j < 3; ++j)
755 for (
unsigned a = 0; a < 3; ++a)
756 for (
unsigned k = 0; k < 3; ++k)
757 for (
unsigned m = 0; m < 3; ++m)
758 ans(i, j, a, a) += (drdsig(i, k, m, m) * trial_eigvecs(j, k) +
759 trial_eigvecs(i, k) * drdsig(j, k, m, m)) *
762 for (
unsigned i = 0; i < 3; ++i)
763 for (
unsigned j = 0; j < 3; ++j)
764 for (
unsigned a = 0; a < 3; ++a)
765 for (
unsigned b = 0; b < 3; ++b)
766 for (
unsigned k = 0; k < 3; ++k)
768 ans(i, j, a, b) += (drdsig(i, k, a, b) * trial_eigvecs(j, k) +
769 trial_eigvecs(i, k) * drdsig(j, k, a, b)) *
771 ans(i, j, a, b) += (drdsig(i, k, b, a) * trial_eigvecs(j, k) +
772 trial_eigvecs(i, k) * drdsig(j, k, b, a)) *