https://mooseframework.inl.gov
SolidMechanicsPlasticMeanCapTC.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 #include "RankFourTensor.h"
12 #include "libmesh/utility.h"
13 
15 registerMooseObjectRenamed("SolidMechanicsApp",
16  TensorMechanicsPlasticMeanCapTC,
17  "01/01/2025 00:00",
19 
22 {
24  params.addRangeCheckedParam<unsigned>("max_iterations",
25  10,
26  "max_iterations>0",
27  "Maximum iterations for custom MeanCapTC return map");
28  params.addParam<bool>(
29  "use_custom_returnMap", true, "Whether to use the custom MeanCapTC returnMap algorithm.");
30  params.addParam<bool>("use_custom_cto",
31  true,
32  "Whether to use the custom consistent tangent operator computations.");
33  params.addRequiredParam<UserObjectName>("tensile_strength",
34  "A SolidMechanicsHardening UserObject that defines "
35  "hardening of the mean-cap tensile strength (it will "
36  "typically be positive). Yield function = trace(stress) "
37  "- tensile_strength for trace(stress)>tensile_strength.");
38  params.addRequiredParam<UserObjectName>(
39  "compressive_strength",
40  "A SolidMechanicsHardening UserObject that defines hardening of the "
41  "mean-cap compressive strength. This should always be less than "
42  "tensile_strength (it will typically be negative). Yield function = "
43  "- (trace(stress) - compressive_strength) for "
44  "trace(stress)<compressive_strength.");
45  params.addClassDescription(
46  "Associative mean-cap tensile and compressive plasticity with hardening/softening");
47 
48  return params;
49 }
50 
52  : SolidMechanicsPlasticModel(parameters),
53  _max_iters(getParam<unsigned>("max_iterations")),
54  _use_custom_returnMap(getParam<bool>("use_custom_returnMap")),
55  _use_custom_cto(getParam<bool>("use_custom_cto")),
56  _strength(getUserObject<SolidMechanicsHardeningModel>("tensile_strength")),
57  _c_strength(getUserObject<SolidMechanicsHardeningModel>("compressive_strength"))
58 {
59  // cannot check the following for all values of the internal parameter, but this will catch most
60  // errors
61  if (_strength.value(0) <= _c_strength.value(0))
62  mooseError("MeanCapTC: tensile strength (which is usually positive) must not be less than "
63  "compressive strength (which is usually negative)");
64 }
65 
66 Real
68 {
69  const Real tr = stress.trace();
70  const Real t_str = tensile_strength(intnl);
71  if (tr >= t_str)
72  return tr - t_str;
73 
74  const Real c_str = compressive_strength(intnl);
75  if (tr <= c_str)
76  return -(tr - c_str);
77  // the following is zero at tr = t_str, and at tr = c_str
78  // it also has derivative = 1 at tr = t_str, and derivative = -1 at tr = c_str
79  // it also has second derivative = 0, at these points.
80  // This makes the complete yield function C2 continuous.
81  return (c_str - t_str) / libMesh::pi * std::sin(libMesh::pi * (tr - c_str) / (t_str - c_str));
82 }
83 
86  Real intnl) const
87 {
88  return df_dsig(stress, intnl);
89 }
90 
91 Real
93  Real intnl) const
94 {
95  const Real tr = stress.trace();
96  const Real t_str = tensile_strength(intnl);
97  if (tr >= t_str)
98  return -dtensile_strength(intnl);
99 
100  const Real c_str = compressive_strength(intnl);
101  if (tr <= c_str)
102  return dcompressive_strength(intnl);
103 
104  const Real dt = dtensile_strength(intnl);
105  const Real dc = dcompressive_strength(intnl);
106  return (dc - dt) / libMesh::pi * std::sin(libMesh::pi * (tr - c_str) / (t_str - c_str)) +
107  1.0 / (t_str - c_str) * std::cos(libMesh::pi * (tr - c_str) / (t_str - c_str)) *
108  ((tr - c_str) * dt - (tr - t_str) * dc);
109 }
110 
113 {
114  const Real tr = stress.trace();
115  const Real t_str = tensile_strength(intnl);
116  if (tr >= t_str)
117  return stress.dtrace();
118 
119  const Real c_str = compressive_strength(intnl);
120  if (tr <= c_str)
121  return -stress.dtrace();
122 
123  return -std::cos(libMesh::pi * (tr - c_str) / (t_str - c_str)) * stress.dtrace();
124 }
125 
128 {
129  return df_dsig(stress, intnl);
130 }
131 
134  Real intnl) const
135 {
136  const Real tr = stress.trace();
137  const Real t_str = tensile_strength(intnl);
138  if (tr >= t_str)
139  return RankFourTensor();
140 
141  const Real c_str = compressive_strength(intnl);
142  if (tr <= c_str)
143  return RankFourTensor();
144 
145  return libMesh::pi / (t_str - c_str) * std::sin(libMesh::pi * (tr - c_str) / (t_str - c_str)) *
146  stress.dtrace().outerProduct(stress.dtrace());
147 }
148 
151  Real intnl) const
152 {
153  const Real tr = stress.trace();
154  const Real t_str = tensile_strength(intnl);
155  if (tr >= t_str)
156  return RankTwoTensor();
157 
158  const Real c_str = compressive_strength(intnl);
159  if (tr <= c_str)
160  return RankTwoTensor();
161 
162  const Real dt = dtensile_strength(intnl);
163  const Real dc = dcompressive_strength(intnl);
164  return std::sin(libMesh::pi * (tr - c_str) / (t_str - c_str)) * stress.dtrace() * libMesh::pi /
165  Utility::pow<2>(t_str - c_str) * ((tr - t_str) * dc - (tr - c_str) * dt);
166 }
167 
168 Real
170 {
171  // This is the key for this whole class!
172  const Real tr = stress.trace();
173  const Real t_str = tensile_strength(intnl);
174 
175  if (tr >= t_str)
176  return -1.0; // this will serve to *increase* the internal parameter (so internal parameter will
177  // be a measure of volumetric strain)
178 
179  const Real c_str = compressive_strength(intnl);
180  if (tr <= c_str)
181  return 1.0; // this will serve to *decrease* the internal parameter (so internal parameter will
182  // be a measure of volumetric strain)
183 
184  return std::cos(libMesh::pi * (tr - c_str) /
185  (t_str - c_str)); // this interpolates C2 smoothly between 1 and -1
186 }
187 
190  Real intnl) const
191 {
192  const Real tr = stress.trace();
193  const Real t_str = tensile_strength(intnl);
194  if (tr >= t_str)
195  return RankTwoTensor();
196 
197  const Real c_str = compressive_strength(intnl);
198  if (tr <= c_str)
199  return RankTwoTensor();
200 
201  return -std::sin(libMesh::pi * (tr - c_str) / (t_str - c_str)) * libMesh::pi / (t_str - c_str) *
202  stress.dtrace();
203 }
204 
205 Real
207  Real intnl) const
208 {
209  const Real tr = stress.trace();
210  const Real t_str = tensile_strength(intnl);
211  if (tr >= t_str)
212  return 0.0;
213 
214  const Real c_str = compressive_strength(intnl);
215  if (tr <= c_str)
216  return 0.0;
217 
218  const Real dt = dtensile_strength(intnl);
219  const Real dc = dcompressive_strength(intnl);
220  return -std::sin(libMesh::pi * (tr - c_str) / (t_str - c_str)) * libMesh::pi /
221  Utility::pow<2>(t_str - c_str) * ((tr - t_str) * dc - (tr - c_str) * dt);
222 }
223 
224 Real
225 SolidMechanicsPlasticMeanCapTC::tensile_strength(const Real internal_param) const
226 {
227  return _strength.value(internal_param);
228 }
229 
230 Real
232 {
233  return _strength.derivative(internal_param);
234 }
235 
236 Real
238 {
239  return _c_strength.value(internal_param);
240 }
241 
242 Real
244 {
245  return _c_strength.derivative(internal_param);
246 }
247 
248 void
250  const RankTwoTensor & stress,
251  Real intnl,
252  const RankFourTensor & Eijkl,
253  std::vector<bool> & act,
254  RankTwoTensor & returned_stress) const
255 {
256  act.assign(1, false);
257 
258  if (f[0] <= _f_tol)
259  {
260  returned_stress = stress;
261  return;
262  }
263 
264  const Real tr = stress.trace();
265  const Real t_str = tensile_strength(intnl);
266  Real str;
267  Real dirn;
268  if (tr >= t_str)
269  {
270  str = t_str;
271  dirn = 1.0;
272  }
273  else
274  {
275  str = compressive_strength(intnl);
276  dirn = -1.0;
277  }
278 
279  RankTwoTensor n; // flow direction
280  for (unsigned i = 0; i < 3; ++i)
281  for (unsigned j = 0; j < 3; ++j)
282  for (unsigned k = 0; k < 3; ++k)
283  n(i, j) += dirn * Eijkl(i, j, k, k);
284 
285  // returned_stress = stress - gamma*n
286  // and taking the trace of this and using
287  // Tr(returned_stress) = str, gives
288  // gamma = (Tr(stress) - str)/Tr(n)
289  Real gamma = (stress.trace() - str) / n.trace();
290 
291  for (unsigned i = 0; i < 3; ++i)
292  for (unsigned j = 0; j < 3; ++j)
293  returned_stress(i, j) = stress(i, j) - gamma * n(i, j);
294 
295  act[0] = true;
296 }
297 
298 bool
300  Real intnl_old,
301  const RankFourTensor & E_ijkl,
302  Real ep_plastic_tolerance,
303  RankTwoTensor & returned_stress,
304  Real & returned_intnl,
305  std::vector<Real> & dpm,
306  RankTwoTensor & delta_dp,
307  std::vector<Real> & yf,
308  bool & trial_stress_inadmissible) const
309 {
310  if (!(_use_custom_returnMap))
311  return SolidMechanicsPlasticModel::returnMap(trial_stress,
312  intnl_old,
313  E_ijkl,
314  ep_plastic_tolerance,
315  returned_stress,
316  returned_intnl,
317  dpm,
318  delta_dp,
319  yf,
320  trial_stress_inadmissible);
321 
322  yf.resize(1);
323 
324  Real yf_orig = yieldFunction(trial_stress, intnl_old);
325 
326  yf[0] = yf_orig;
327 
328  if (yf_orig < _f_tol)
329  {
330  // the trial_stress is admissible
331  trial_stress_inadmissible = false;
332  return true;
333  }
334 
335  trial_stress_inadmissible = true;
336 
337  // In the following we want to solve
338  // trial_stress - stress = E_ijkl * dpm * r ...... (1)
339  // and either
340  // stress.trace() = tensile_strength(intnl) ...... (2a)
341  // intnl = intnl_old + dpm ...... (3a)
342  // or
343  // stress.trace() = compressive_strength(intnl) ... (2b)
344  // intnl = intnl_old - dpm ...... (3b)
345  // The former (2a and 3a) are chosen if
346  // trial_stress.trace() > tensile_strength(intnl_old)
347  // while the latter (2b and 3b) are chosen if
348  // trial_stress.trace() < compressive_strength(intnl_old)
349  // The variables we want to solve for are stress, dpm
350  // and intnl. We do this using a Newton approach, starting
351  // with stress=trial_stress and intnl=intnl_old and dpm=0
352  const bool tensile_failure = (trial_stress.trace() >= tensile_strength(intnl_old));
353  const Real dirn = (tensile_failure ? 1.0 : -1.0);
354 
355  RankTwoTensor n; // flow direction, which is E_ijkl * r
356  for (unsigned i = 0; i < 3; ++i)
357  for (unsigned j = 0; j < 3; ++j)
358  for (unsigned k = 0; k < 3; ++k)
359  n(i, j) += dirn * E_ijkl(i, j, k, k);
360  const Real n_trace = n.trace();
361 
362  // Perform a Newton-Raphson to find dpm when
363  // residual = trial_stress.trace() - tensile_strength(intnl) - dpm * n.trace() [for
364  // tensile_failure=true]
365  // or
366  // residual = trial_stress.trace() - compressive_strength(intnl) - dpm * n.trace() [for
367  // tensile_failure=false]
368  Real trial_trace = trial_stress.trace();
369  Real residual;
370  Real jac;
371  dpm[0] = 0;
372  unsigned int iter = 0;
373  do
374  {
375  if (tensile_failure)
376  {
377  residual = trial_trace - tensile_strength(intnl_old + dpm[0]) - dpm[0] * n_trace;
378  jac = -dtensile_strength(intnl_old + dpm[0]) - n_trace;
379  }
380  else
381  {
382  residual = trial_trace - compressive_strength(intnl_old - dpm[0]) - dpm[0] * n_trace;
383  jac = -dcompressive_strength(intnl_old - dpm[0]) - n_trace;
384  }
385  dpm[0] += -residual / jac;
386  if (iter > _max_iters) // not converging
387  return false;
388  iter++;
389  } while (residual * residual > _f_tol * _f_tol);
390 
391  // set the returned values
392  yf[0] = 0;
393  returned_intnl = intnl_old + dirn * dpm[0];
394  returned_stress = trial_stress - dpm[0] * n;
395  delta_dp = dpm[0] * dirn * returned_stress.dtrace();
396 
397  return true;
398 }
399 
402  const RankTwoTensor & trial_stress,
403  Real intnl_old,
404  const RankTwoTensor & stress,
405  Real intnl,
406  const RankFourTensor & E_ijkl,
407  const std::vector<Real> & cumulative_pm) const
408 {
409  if (!_use_custom_cto)
411  trial_stress, intnl_old, stress, intnl, E_ijkl, cumulative_pm);
412 
413  Real df_dq;
414  Real alpha;
415  if (trial_stress.trace() >= tensile_strength(intnl_old))
416  {
417  df_dq = -dtensile_strength(intnl);
418  alpha = 1.0;
419  }
420  else
421  {
422  df_dq = dcompressive_strength(intnl);
423  alpha = -1.0;
424  }
425 
426  RankTwoTensor elas;
427  for (unsigned int i = 0; i < 3; ++i)
428  for (unsigned int j = 0; j < 3; ++j)
429  for (unsigned int k = 0; k < 3; ++k)
430  elas(i, j) += E_ijkl(i, j, k, k);
431 
432  const Real hw = -df_dq + alpha * elas.trace();
433 
434  return E_ijkl - alpha / hw * elas.outerProduct(elas);
435 }
436 
437 bool
439 {
440  return _use_custom_returnMap;
441 }
442 
443 bool
445 {
446  return _use_custom_cto;
447 }
448 
449 std::string
451 {
452  return "MeanCapTC";
453 }
RankFourTensorTempl< Real > outerProduct(const RankTwoTensorTempl< Real > &b) const
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.
Real hardPotential(const RankTwoTensor &stress, Real intnl) const override
The hardening potential.
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 ...
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
virtual bool useCustomCTO() const override
Returns false. You will want to override this in your derived class if you write a custom consistent ...
virtual Real dhardPotential_dintnl(const RankTwoTensor &stress, Real intnl) const override
The derivative of the hardening potential with respect to the internal parameter. ...
const SolidMechanicsHardeningModel & _c_strength
the compressive strength
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 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.
RankTwoTensorTempl< Real > dtrace() const
Real yieldFunction(const RankTwoTensor &stress, Real intnl) const override
The following functions are what you should override when building single-plasticity models...
virtual std::string modelName() const override
virtual Real value(Real intnl) const
RankFourTensor dflowPotential_dstress(const RankTwoTensor &stress, Real intnl) const override
The derivative of the flow potential with respect to stress.
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual RankTwoTensor dhardPotential_dstress(const RankTwoTensor &stress, Real intnl) const override
The derivative of the hardening potential with respect to stress.
virtual Real tensile_strength(const Real internal_param) const
tensile strength as a function of residual value, rate, and internal_param
virtual Real dcompressive_strength(const Real internal_param) const
d(compressive strength)/d(internal_param) as a function of residual value, rate, and internal_param ...
static InputParameters validParams()
const unsigned _max_iters
max iters for custom return map loop
Real dyieldFunction_dintnl(const RankTwoTensor &stress, Real intnl) const override
The derivative of yield function with respect to the internal parameter.
Real f(Real x)
Test function for Brents method.
registerMooseObject("SolidMechanicsApp", SolidMechanicsPlasticMeanCapTC)
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.
RankTwoTensor flowPotential(const RankTwoTensor &stress, Real intnl) const override
The flow potential.
SolidMechanicsPlasticMeanCapTC(const InputParameters &parameters)
virtual bool useCustomReturnMap() const override
Returns false. You will want to override this in your derived class if you write a custom returnMap f...
const Real _f_tol
Tolerance on yield function.
RankTwoTensor dyieldFunction_dstress(const RankTwoTensor &stress, Real intnl) const override
The derivative of yield function with respect to stress.
virtual Real derivative(Real intnl) const
const bool _use_custom_cto
Whether to use the custom consistent tangent operator algorithm.
const bool _use_custom_returnMap
Whether to use the custom return-map algorithm.
RankTwoTensor df_dsig(const RankTwoTensor &stress, Real intnl) const
Derivative of the yield function with respect to stress.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
RankTwoTensor dflowPotential_dintnl(const RankTwoTensor &stress, Real intnl) const override
The derivative of the flow potential with respect to the internal parameter.
static const std::string alpha
Definition: NS.h:134
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.
void mooseError(Args &&... args) const
const SolidMechanicsHardeningModel & _strength
the tensile strength
void addClassDescription(const std::string &doc_string)
registerMooseObjectRenamed("SolidMechanicsApp", TensorMechanicsPlasticMeanCapTC, "01/01/2025 00:00", SolidMechanicsPlasticMeanCapTC)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
virtual Real compressive_strength(const Real internal_param) const
compressive strength as a function of residual value, rate, and internal_param
Plastic Model base class The virtual functions written below must be over-ridden in derived classes t...
Rate-independent associative mean-cap tensile AND compressive failure with hardening/softening of the...
static const std::string k
Definition: NS.h:130
const Real pi