https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
15registerMooseObjectRenamed("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.");
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
66Real
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
91Real
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
168Real
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
205Real
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
224Real
226{
227 return _strength.value(internal_param);
228}
229
230Real
232{
233 return _strength.derivative(internal_param);
234}
235
236Real
238{
239 return _c_strength.value(internal_param);
240}
241
242Real
244{
245 return _c_strength.derivative(internal_param);
246}
247
248void
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
298bool
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{
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
437bool
442
443bool
448
449std::string
451{
452 return "MeanCapTC";
453}
Real f(Real x)
Test function for Brents method.
registerMooseObject("SolidMechanicsApp", SolidMechanicsPlasticMeanCapTC)
registerMooseObjectRenamed("SolidMechanicsApp", TensorMechanicsPlasticMeanCapTC, "01/01/2025 00:00", SolidMechanicsPlasticMeanCapTC)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
void mooseError(Args &&... args) const
RankFourTensorTempl< T > outerProduct(const RankTwoTensorTempl< T > &b) const
RankTwoTensorTempl< T > dtrace() const
virtual Real derivative(Real intnl) const
virtual Real value(Real intnl) const
Rate-independent associative mean-cap tensile AND compressive failure with hardening/softening of the...
const bool _use_custom_returnMap
Whether to use the custom return-map algorithm.
RankFourTensor dflowPotential_dstress(const RankTwoTensor &stress, Real intnl) const override
The derivative of the flow potential with respect to stress.
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 compressive_strength(const Real internal_param) const
compressive strength as a function of residual value, rate, and internal_param
virtual bool useCustomCTO() const override
Returns false. You will want to override this in your derived class if you write a custom consistent ...
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 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.
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
Real hardPotential(const RankTwoTensor &stress, Real intnl) const override
The hardening potential.
const SolidMechanicsHardeningModel & _c_strength
the compressive strength
Real yieldFunction(const RankTwoTensor &stress, Real intnl) const override
The following functions are what you should override when building single-plasticity models.
RankTwoTensor flowPotential(const RankTwoTensor &stress, Real intnl) const override
The flow potential.
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
RankTwoTensor dyieldFunction_dstress(const RankTwoTensor &stress, Real intnl) const override
The derivative of yield function with respect to stress.
const bool _use_custom_cto
Whether to use the custom consistent tangent operator algorithm.
virtual Real dhardPotential_dintnl(const RankTwoTensor &stress, Real intnl) const override
The derivative of the hardening potential with respect to the internal parameter.
virtual RankTwoTensor dhardPotential_dstress(const RankTwoTensor &stress, Real intnl) const override
The derivative of the hardening potential with respect to stress.
SolidMechanicsPlasticMeanCapTC(const InputParameters &parameters)
const SolidMechanicsHardeningModel & _strength
the tensile strength
virtual std::string modelName() const override
const unsigned _max_iters
max iters for custom return map loop
RankTwoTensor dflowPotential_dintnl(const RankTwoTensor &stress, Real intnl) const override
The derivative of the flow potential with respect to the internal parameter.
virtual Real tensile_strength(const Real internal_param) const
tensile strength as a function of residual value, rate, and internal_param
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.
RankTwoTensor df_dsig(const RankTwoTensor &stress, Real intnl) const
Derivative of the yield function with respect to stress.
Real dyieldFunction_dintnl(const RankTwoTensor &stress, Real intnl) const override
The derivative of yield function with respect to the internal parameter.
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.
const Real _f_tol
Tolerance on yield function.
static InputParameters validParams()
const Real pi