18 TensorMechanicsPlasticTensileMulti,
29 "A SolidMechanicsHardening UserObject that defines hardening of the tensile strength");
31 "Yield surface is shifted by this amount to avoid problems with "
32 "defining derivatives when eigenvalues are equal. If this is "
33 "larger than f_tol, a warning will be issued. Default = f_tol.");
34 params.
addParam<
unsigned int>(
"max_iterations",
36 "Maximum number of Newton-Raphson iterations "
37 "allowed in the custom return-map algorithm. "
38 " For highly nonlinear hardening this may "
39 "need to be higher than 10.");
40 params.
addParam<
bool>(
"use_custom_returnMap",
42 "Whether to use the custom returnMap "
43 "algorithm. Set to true if you are using "
44 "isotropic elasticity.");
45 params.
addParam<
bool>(
"use_custom_cto",
47 "Whether to use the custom consistent tangent "
48 "operator computations. Set to true if you are "
49 "using isotropic elasticity.");
57 _max_iters(getParam<unsigned
int>(
"max_iterations")),
58 _shift(parameters.isParamValid(
"shift") ? getParam<Real>(
"shift") : _f_tol),
59 _use_custom_returnMap(getParam<bool>(
"use_custom_returnMap")),
60 _use_custom_cto(getParam<bool>(
"use_custom_cto"))
63 mooseError(
"Value of 'shift' in SolidMechanicsPlasticTensileMulti must not be negative\n");
65 _console <<
"WARNING: value of 'shift' in SolidMechanicsPlasticTensileMulti is probably set "
69 mooseError(
"SolidMechanicsPlasticTensileMulti is only defined for LIBMESH_DIM=3");
82 std::vector<Real> &
f)
const
84 std::vector<Real> eigvals;
89 f[0] = eigvals[0] +
_shift - str;
90 f[1] = eigvals[1] - str;
91 f[2] = eigvals[2] -
_shift - str;
96 const RankTwoTensor & stress, Real , std::vector<RankTwoTensor> & df_dstress)
const
98 std::vector<Real> eigvals;
101 if (eigvals[0] > eigvals[1] - 0.1 *
_shift || eigvals[1] > eigvals[2] - 0.1 *
_shift)
103 Real small_perturbation;
105 while (eigvals[0] > eigvals[1] - 0.1 *
_shift || eigvals[1] > eigvals[2] - 0.1 *
_shift)
107 for (
unsigned i = 0; i < 3; ++i)
108 for (
unsigned j = 0; j <= i; ++j)
111 shifted_stress(i, j) += small_perturbation;
112 shifted_stress(j, i) += small_perturbation;
122 std::vector<Real> & df_dintnl)
const
130 std::vector<RankTwoTensor> & r)
const
138 const RankTwoTensor & stress, Real , std::vector<RankFourTensor> & dr_dstress)
const
145 const RankTwoTensor & , Real , std::vector<RankTwoTensor> & dr_dintnl)
const
167 std::vector<bool> & act,
170 act.assign(3,
false);
174 returned_stress = stress;
179 std::vector<Real> dpm(3);
181 std::vector<Real> yf(3);
182 bool trial_stress_inadmissible;
192 trial_stress_inadmissible);
194 for (
unsigned i = 0; i < 3; ++i)
195 act[i] = (dpm[i] > 0);
200 const std::vector<Real> & b)
const
202 return a[0] *
b[0] +
a[1] *
b[1] +
a[2] *
b[2];
207 const std::vector<Real> & b,
208 const std::vector<Real> &
c)
const
210 return a[0] * (
b[1] *
c[2] -
b[2] *
c[1]) -
a[1] * (
b[0] *
c[2] -
b[2] *
c[0]) +
211 a[2] * (
b[0] *
c[1] -
b[1] *
c[0]);
217 return "TensileMulti";
224 Real ep_plastic_tolerance,
226 Real & returned_intnl,
227 std::vector<Real> & dpm,
229 std::vector<Real> & yf,
230 bool & trial_stress_inadmissible)
const
236 ep_plastic_tolerance,
242 trial_stress_inadmissible);
247 ep_plastic_tolerance,
253 trial_stress_inadmissible);
260 Real ep_plastic_tolerance,
262 Real & returned_intnl,
263 std::vector<Real> & dpm,
265 std::vector<Real> & yf,
266 bool & trial_stress_inadmissible)
const
268 mooseAssert(dpm.size() == 3,
269 "SolidMechanicsPlasticTensileMulti size of dpm should be 3 but it is " << dpm.size());
271 std::vector<Real> eigvals;
280 yf[0] = eigvals[0] - str;
281 yf[1] = eigvals[1] - str;
282 yf[2] = eigvals[2] - str;
287 trial_stress_inadmissible =
false;
291 trial_stress_inadmissible =
true;
293 returned_stress.zero();
316 std::vector<RealVectorValue> n(3);
317 n[0](0) = E_ijkl(0, 0, 0, 0);
318 n[0](1) = E_ijkl(1, 1, 0, 0);
319 n[0](2) = E_ijkl(2, 2, 0, 0);
320 n[1](0) = E_ijkl(0, 0, 1, 1);
321 n[1](1) = E_ijkl(1, 1, 1, 1);
322 n[1](2) = E_ijkl(2, 2, 1, 1);
323 n[2](0) = E_ijkl(0, 0, 2, 2);
324 n[2](1) = E_ijkl(1, 1, 2, 2);
325 n[2](2) = E_ijkl(2, 2, 2, 2);
337 const unsigned int number_of_return_paths = 3;
338 std::vector<int> trial_order(number_of_return_paths);
342 trial_order[0] =
tip;
343 trial_order[1] =
edge;
344 trial_order[2] =
plane;
348 trial_order[0] =
edge;
349 trial_order[1] =
tip;
350 trial_order[2] =
plane;
354 trial_order[0] =
plane;
355 trial_order[1] =
edge;
356 trial_order[2] =
tip;
360 bool nr_converged =
false;
361 for (trial = 0; trial < number_of_return_paths; ++trial)
363 switch (trial_order[trial])
366 nr_converged =
returnTip(eigvals, n, dpm, returned_stress, intnl_old, 0);
369 nr_converged =
returnEdge(eigvals, n, dpm, returned_stress, intnl_old, 0);
372 nr_converged =
returnPlane(eigvals, n, dpm, returned_stress, intnl_old, 0);
378 if (nr_converged &&
KuhnTuckerOK(returned_stress, dpm, str, ep_plastic_tolerance))
382 if (trial == number_of_return_paths)
384 Moose::err <<
"Trial stress = \n";
385 trial_stress.
print(Moose::err);
386 Moose::err <<
"Internal parameter = " << intnl_old << std::endl;
387 mooseError(
"SolidMechanicsPlasticTensileMulti: FAILURE! You probably need to implement a "
391 yf[0] = eigvals[0] - str;
392 yf[1] = eigvals[1] - str;
393 yf[2] = eigvals[2] - str;
399 returned_intnl = intnl_old;
400 for (
unsigned i = 0; i < 3; ++i)
402 yf[i] = returned_stress(i, i) - str;
403 delta_dp(i, i) = dpm[i];
404 returned_intnl += dpm[i];
406 returned_stress = eigvecs * returned_stress * (eigvecs.
transpose());
407 delta_dp = eigvecs * delta_dp * (eigvecs.
transpose());
413 const std::vector<RealVectorValue> & n,
414 std::vector<Real> & dpm,
417 Real initial_guess)
const
437 Real
x = initial_guess;
438 const Real denom = (n[0](0) - n[0](1)) * (n[0](0) + 2 * n[0](1));
451 const Real eig = eigvals[0] + eigvals[1] + eigvals[2];
452 const Real bul = (n[0](0) + 2 * n[0](1));
460 Real residual = bul *
x - eig + 3 * str;
462 unsigned int iter = 0;
466 x += -residual / jacobian;
470 residual = bul *
x - eig + 3 * str;
478 dpm[0] = (n[0](0) * (eigvals[0] - str) + n[0](1) * (eigvals[0] - eigvals[1] - eigvals[2] + str)) /
480 dpm[1] = (n[0](0) * (eigvals[1] - str) + n[0](1) * (eigvals[1] - eigvals[2] - eigvals[0] + str)) /
482 dpm[2] = (n[0](0) * (eigvals[2] - str) + n[0](1) * (eigvals[2] - eigvals[0] - eigvals[1] + str)) /
484 returned_stress(0, 0) = returned_stress(1, 1) = returned_stress(2, 2) = str;
490 const std::vector<RealVectorValue> & n,
491 std::vector<Real> & dpm,
494 Real initial_guess)
const
518 Real
x = initial_guess;
519 const Real denom = n[0](0) + n[0](1);
532 const Real eig = eigvals[1] + eigvals[2];
533 Real residual = denom *
x - eig + 2 * str;
535 unsigned int iter = 0;
539 x += -residual / jacobian;
543 residual = denom *
x - eig + 2 * str;
549 dpm[1] = ((eigvals[1] * n[0](0) - eigvals[2] * n[0](1)) / (n[0](0) - n[0](1)) - str) / denom;
550 dpm[2] = ((eigvals[2] * n[0](0) - eigvals[1] * n[0](1)) / (n[0](0) - n[0](1)) - str) / denom;
552 returned_stress(0, 0) = eigvals[0] - n[0](1) * (dpm[1] + dpm[2]);
553 returned_stress(1, 1) = returned_stress(2, 2) = str;
559 const std::vector<RealVectorValue> & n,
560 std::vector<Real> & dpm,
563 Real initial_guess)
const
581 dpm[2] = initial_guess;
582 Real residual = n[2](2) * dpm[2] - eigvals[2] +
tensile_strength(intnl_old + dpm[2]);
584 unsigned int iter = 0;
588 dpm[2] += -residual / jacobian;
591 residual = n[2](2) * dpm[2] - eigvals[2] +
tensile_strength(intnl_old + dpm[2]);
597 returned_stress(0, 0) = eigvals[0] - dpm[2] * n[2](0);
598 returned_stress(1, 1) = eigvals[1] - dpm[2] * n[2](1);
599 returned_stress(2, 2) = eigvals[2] - dpm[2] * n[2](2);
605 const std::vector<Real> & dpm,
607 Real ep_plastic_tolerance)
const
609 for (
unsigned i = 0; i < 3; ++i)
611 returned_diagonal_stress(i, i) - str, dpm[i], ep_plastic_tolerance))
623 const std::vector<Real> & cumulative_pm)
const
627 trial_stress, intnl_old, stress, intnl, E_ijkl, cumulative_pm);
629 mooseAssert(cumulative_pm.size() == 3,
630 "SolidMechanicsPlasticTensileMulti size of cumulative_pm should be 3 but it is "
631 << cumulative_pm.size());
633 if (cumulative_pm[2] <= 0)
637 std::vector<Real> eigvals;
643 std::vector<Real> trial_eigvals;
677 const Real la = E_ijkl(0, 0, 1, 1);
678 const Real
mu = 0.5 * (E_ijkl(0, 0, 0, 0) - la);
680 if (cumulative_pm[1] <= 0)
683 const Real denom = hard + la + 2 *
mu;
684 const Real al = la * la / denom;
685 const Real be = la * (la + 2 *
mu) / denom;
686 const Real ga = hard * (la + 2 *
mu) / denom;
687 std::vector<Real> comps(9);
688 comps[0] = comps[4] = la + 2 *
mu - al;
689 comps[1] = comps[3] = la - al;
690 comps[2] = comps[5] = comps[6] = comps[7] = la - be;
694 else if (cumulative_pm[0] <= 0)
697 const Real denom = 2 * hard + 2 * la + 2 *
mu;
698 const Real al = hard * 2 * la / denom;
699 const Real be = hard * (2 * la + 2 *
mu) / denom;
700 std::vector<Real> comps(9);
701 comps[0] = la + 2 *
mu - 2 * la * la / denom;
702 comps[1] = comps[2] = al;
703 comps[3] = comps[6] = al;
704 comps[4] = comps[5] = comps[7] = comps[8] = be;
710 const Real denom = 3 * hard + 3 * la + 2 *
mu;
711 std::vector<Real> comps(2);
712 comps[0] = hard * (3 * la + 2 *
mu) / denom;
717 cto.
rotate(trial_eigvecs);
736 for (
unsigned k = 0; k < 3; ++k)
737 for (
unsigned b = 0;
b < 3; ++
b)
741 for (
unsigned m = 0; m < 3; ++m)
742 for (
unsigned n = 0; n < 3; ++n)
743 for (
unsigned i = 0; i < 3; ++i)
744 drdsig(i, k, m, n) += trial_eigvecs(m,
b) * trial_eigvecs(n, k) * trial_eigvecs(i,
b) /
745 (trial_eigvals[k] - trial_eigvals[
b]);
755 for (
unsigned i = 0; i < 3; ++i)
756 for (
unsigned j = 0; j < 3; ++j)
757 for (
unsigned a = 0;
a < 3; ++
a)
758 for (
unsigned k = 0; k < 3; ++k)
759 for (
unsigned m = 0; m < 3; ++m)
760 ans(i, j,
a,
a) += (drdsig(i, k, m, m) * trial_eigvecs(j, k) +
761 trial_eigvecs(i, k) * drdsig(j, k, m, m)) *
764 for (
unsigned i = 0; i < 3; ++i)
765 for (
unsigned j = 0; j < 3; ++j)
766 for (
unsigned a = 0;
a < 3; ++
a)
767 for (
unsigned b = 0;
b < 3; ++
b)
768 for (
unsigned k = 0; k < 3; ++k)
770 ans(i, j,
a,
b) += (drdsig(i, k,
a,
b) * trial_eigvecs(j, k) +
771 trial_eigvecs(i, k) * drdsig(j, k,
a,
b)) *
773 ans(i, j,
a,
b) += (drdsig(i, k,
b,
a) * trial_eigvecs(j, k) +
774 trial_eigvecs(i, k) * drdsig(j, k,
b,
a)) *
Real f(Real x)
Test function for Brents method.
const std::vector< double > x
registerMooseObject("SolidMechanicsApp", SolidMechanicsPlasticTensileMulti)
registerMooseObjectRenamed("SolidMechanicsApp", TensorMechanicsPlasticTensileMulti, "01/01/2025 00:00", SolidMechanicsPlasticTensileMulti)
void ErrorVector unsigned int
const ConsoleStream _console
void mooseError(Args &&... args) const
void seed(std::size_t i, unsigned int seed)
void fillFromInputVector(const std::vector< T > &input, FillMethod fill_method)
void rotate(const TypeTensor< T > &R)
void dsymmetricEigenvalues(std::vector< T > &eigvals, std::vector< RankTwoTensorTempl< T > > &deigvals) const
RankTwoTensorTempl< T > transpose() const
void print(std::ostream &stm=Moose::out) const
void d2symmetricEigenvalues(std::vector< RankFourTensorTempl< T > > &deriv) const
void symmetricEigenvalues(std::vector< T > &eigvals) const
void symmetricEigenvaluesEigenvectors(std::vector< T > &eigvals, RankTwoTensorTempl< T > &eigvecs) const
Hardening Model base class.
virtual Real derivative(Real intnl) const
virtual std::string modelName() const =0
virtual Real value(Real intnl) const
Plastic Model base class The virtual functions written below must be over-ridden in derived classes t...
virtual RankFourTensor consistentTangentOperator(const RankTwoTensor &trial_stress, Real intnl_old, const RankTwoTensor &stress, Real intnl, const RankFourTensor &E_ijkl, const std::vector< Real > &cumulative_pm) const
Calculates a custom consistent tangent operator.
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.
bool KuhnTuckerSingleSurface(Real yf, Real dpm, Real dpm_tol) const
Returns true if the Kuhn-Tucker conditions for the single surface are satisfied.
const Real _f_tol
Tolerance on yield function.
static InputParameters validParams()
FiniteStrainTensileMulti implements rate-independent associative tensile failure with hardening/softe...
bool returnPlane(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real initial_guess) const
Tries to return-map to the Tensile plane The return value is true if the internal Newton-Raphson proc...
static InputParameters validParams()
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.
virtual bool useCustomCTO() const override
Returns false. You will want to override this in your derived class if you write a custom consistent ...
Real dot(const std::vector< Real > &a, const std::vector< Real > &b) const
dot product of two 3-dimensional vectors
const SolidMechanicsHardeningModel & _strength
const unsigned int _max_iters
maximum iterations allowed in the custom return-map algorithm
virtual void flowPotentialV(const RankTwoTensor &stress, Real intnl, std::vector< RankTwoTensor > &r) const override
The flow potentials.
virtual RankFourTensor consistentTangentOperator(const RankTwoTensor &trial_stress, Real intnl_old, const RankTwoTensor &stress, Real intnl, const RankFourTensor &E_ijkl, const std::vector< Real > &cumulative_pm) const override
Calculates a custom consistent tangent operator.
virtual Real tensile_strength(const Real internal_param) const
tensile strength as a function of residual value, rate, and internal_param
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.
virtual 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
Just like returnMap, but a protected interface that definitely uses the algorithm,...
const bool _use_custom_cto
Whether to use the custom consistent tangent operator calculation.
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.
bool returnEdge(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real initial_guess) const
Tries to return-map to the Tensile edge.
SolidMechanicsPlasticTensileMulti(const InputParameters ¶meters)
Real triple(const std::vector< Real > &a, const std::vector< Real > &b, const std::vector< Real > &c) const
triple product of three 3-dimensional vectors
bool KuhnTuckerOK(const RankTwoTensor &returned_diagonal_stress, const std::vector< Real > &dpm, Real str, Real ep_plastic_tolerance) const
Returns true if the Kuhn-Tucker conditions are satisfied.
virtual void yieldFunctionV(const RankTwoTensor &stress, Real intnl, std::vector< Real > &f) const override
Calculates the yield functions.
const Real _shift
yield function is shifted by this amount to avoid problems with stress-derivatives at equal eigenvalu...
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.
const bool _use_custom_returnMap
Whether to use the custom return-map algorithm.
bool returnTip(const std::vector< Real > &eigvals, const std::vector< RealVectorValue > &n, std::vector< Real > &dpm, RankTwoTensor &returned_stress, Real intnl_old, Real initial_guess) const
Tries to return-map to the Tensile tip.
virtual unsigned int numberSurfaces() const override
The number of yield surfaces for this plasticity model.
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.
virtual std::string modelName() const override
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.
virtual bool useCustomReturnMap() const override
Returns false. You will want to override this in your derived class if you write a custom returnMap f...
virtual Real dtensile_strength(const Real internal_param) const
d(tensile strength)/d(internal_param) as a function of residual value, rate, and internal_param