https://mooseframework.inl.gov
Loading...
Searching...
No Matches
TensileStressUpdate.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
10#include "TensileStressUpdate.h"
11#include "libmesh/utility.h"
12
14
17{
19 params.addRequiredParam<UserObjectName>(
20 "tensile_strength",
21 "A SolidMechanicsHardening UserObject that defines hardening of the tensile strength");
22 params.addParam<bool>("perfect_guess",
23 true,
24 "Provide a guess to the Newton-Raphson procedure "
25 "that is the result from perfect plasticity. With "
26 "severe hardening/softening this may be "
27 "suboptimal.");
29 "Associative, smoothed, tensile (Rankine) plasticity with hardening/softening");
30 return params;
31}
32
34 : MultiParameterPlasticityStressUpdate(parameters, 3, 3, 1),
35 _strength(getUserObject<SolidMechanicsHardeningModel>("tensile_strength")),
36 _perfect_guess(getParam<bool>("perfect_guess")),
37 _eigvecs(RankTwoTensor()),
38 _dsp_trial_scratch(3),
39 _eigvals_scratch(_tensor_dimensionality)
40{
41}
42
43void
45 std::vector<Real> & stress_params) const
46{
47 // stress_params[0] = smallest eigenvalue, stress_params[2] = largest eigenvalue
48 stress.symmetricEigenvalues(stress_params);
49}
50
51void
53 std::vector<RankTwoTensor> & dsp) const
54{
55 mooseAssert(dsp.size() == 3,
56 "TensileStressUpdate: dsp incorrectly sized in dstressparam_dstress");
57 mooseAssert(_eigvals_scratch.size() == _tensor_dimensionality,
58 "_eigvals_scratch incorrectly sized in TensileStressUpdate:dstressparam_dstress");
60}
61
62void
64 std::vector<RankFourTensor> & d2sp) const
65{
66 /*
67 * This function is not used but is included here in case a derived class needs it.
68 * The reason it is unused is because consistentTangentOperatorV is optimised
69 */
70 mooseAssert(d2sp.size() == 3,
71 "TensileStressUpdate: d2sp incorrectly sized in d2stressparam_dstress");
72 stress.d2symmetricEigenvalues(d2sp);
73}
74
75void
76TensileStressUpdate::preReturnMapV(const std::vector<Real> & /*trial_stress_params*/,
77 const RankTwoTensor & stress_trial,
78 const std::vector<Real> & /*intnl_old*/,
79 const std::vector<Real> & /*yf*/,
80 const RankFourTensor & /*Eijkl*/)
81{
82 mooseAssert(_eigvals_scratch.size() == _tensor_dimensionality,
83 "_eigvals_scratch incorrectly sized in TensileStressUpdate:preReturnMapV");
85}
86
87void
89 const std::vector<Real> & stress_params,
90 Real /*gaE*/,
91 const std::vector<Real> & /*intnl*/,
92 const yieldAndFlow & /*smoothed_q*/,
93 const RankFourTensor & /*Eijkl*/,
94 RankTwoTensor & stress) const
95{
96 // form the diagonal stress
97 stress = RankTwoTensor(stress_params[0], stress_params[1], stress_params[2], 0.0, 0.0, 0.0);
98 // rotate to the original frame
99 stress = _eigvecs * stress * (_eigvecs.transpose());
100}
101
102void
103TensileStressUpdate::yieldFunctionValuesV(const std::vector<Real> & stress_params,
104 const std::vector<Real> & intnl,
105 std::vector<Real> & yf) const
106{
107 const Real ts = tensile_strength(intnl[0]);
108 // The smoothing strategy means that the last yield function
109 // gives the smallest value when returning to a line/point where,
110 // without smoothing, the yield functions are equal.
111 // Therefore, i use the smallest eigenvalue in this yield function
112 yf[0] = stress_params[2] - ts; // use largest eigenvalue
113 yf[1] = stress_params[1] - ts;
114 yf[2] = stress_params[0] - ts; // use smallest eigenvalue
115}
116
117void
118TensileStressUpdate::computeAllQV(const std::vector<Real> & stress_params,
119 const std::vector<Real> & intnl,
120 std::vector<yieldAndFlow> & all_q) const
121{
122 const Real ts = tensile_strength(intnl[0]);
123 const Real dts = dtensile_strength(intnl[0]);
124
125 // yield functions. See comment in yieldFunctionValuesV
126 all_q[0].f = stress_params[2] - ts;
127 all_q[1].f = stress_params[1] - ts;
128 all_q[2].f = stress_params[0] - ts;
129
130 // d(yield function)/d(stress_params)
131 for (unsigned yf = 0; yf < _num_yf; ++yf)
132 for (unsigned a = 0; a < _num_sp; ++a)
133 all_q[yf].df[a] = 0.0;
134 all_q[0].df[2] = 1.0;
135 all_q[1].df[1] = 1.0;
136 all_q[2].df[0] = 1.0;
137
138 // d(yield function)/d(intnl)
139 for (unsigned yf = 0; yf < _num_yf; ++yf)
140 all_q[yf].df_di[0] = -dts;
141
142 // the flow potential is just the yield function
143 // d(flow potential)/d(stress_params)
144 for (unsigned yf = 0; yf < _num_yf; ++yf)
145 for (unsigned a = 0; a < _num_sp; ++a)
146 all_q[yf].dg[a] = all_q[yf].df[a];
147
148 // d(flow potential)/d(stress_params)/d(intnl)
149 for (unsigned yf = 0; yf < _num_yf; ++yf)
150 for (unsigned a = 0; a < _num_sp; ++a)
151 all_q[yf].d2g_di[a][0] = 0.0;
152
153 // d(flow potential)/d(stress_params)/d(stress_params)
154 for (unsigned yf = 0; yf < _num_yf; ++yf)
155 for (unsigned a = 0; a < _num_sp; ++a)
156 for (unsigned b = 0; b < _num_sp; ++b)
157 all_q[yf].d2g[a][b] = 0.0;
158}
159
160void
162{
163 // Eijkl is required to be isotropic, so we can use the
164 // frame where stress is diagonal
165 for (unsigned a = 0; a < _num_sp; ++a)
166 for (unsigned b = 0; b < _num_sp; ++b)
167 _Eij[a][b] = Eijkl(a, a, b, b);
168 _En = _Eij[2][2];
169 const Real denom = _Eij[0][0] * (_Eij[0][0] + _Eij[0][1]) - 2 * Utility::pow<2>(_Eij[0][1]);
170 for (unsigned a = 0; a < _num_sp; ++a)
171 {
172 _Cij[a][a] = (_Eij[0][0] + _Eij[0][1]) / denom;
173 for (unsigned b = 0; b < a; ++b)
174 _Cij[a][b] = _Cij[b][a] = -_Eij[0][1] / denom;
175 }
176}
177
178void
179TensileStressUpdate::initializeVarsV(const std::vector<Real> & trial_stress_params,
180 const std::vector<Real> & intnl_old,
181 std::vector<Real> & stress_params,
182 Real & gaE,
183 std::vector<Real> & intnl) const
184{
185 if (!_perfect_guess)
186 {
187 for (unsigned i = 0; i < _num_sp; ++i)
188 stress_params[i] = trial_stress_params[i];
189 gaE = 0.0;
190 }
191 else
192 {
193 const Real ts = tensile_strength(intnl_old[0]);
194 stress_params[2] = ts; // largest eigenvalue
195 stress_params[1] = std::min(stress_params[1], ts);
196 stress_params[0] = std::min(stress_params[0], ts);
197 gaE = trial_stress_params[2] - stress_params[2];
198 }
199 setIntnlValuesV(trial_stress_params, stress_params, intnl_old, intnl);
200}
201
202void
203TensileStressUpdate::setIntnlValuesV(const std::vector<Real> & trial_stress_params,
204 const std::vector<Real> & current_stress_params,
205 const std::vector<Real> & intnl_old,
206 std::vector<Real> & intnl) const
207{
208 intnl[0] = intnl_old[0] + (trial_stress_params[2] - current_stress_params[2]) / _Eij[2][2];
209}
210
211void
212TensileStressUpdate::setIntnlDerivativesV(const std::vector<Real> & /*trial_stress_params*/,
213 const std::vector<Real> & /*current_stress_params*/,
214 const std::vector<Real> & /*intnl*/,
215 std::vector<std::vector<Real>> & dintnl) const
216{
217 dintnl[0][0] = 0.0;
218 dintnl[0][1] = 0.0;
219 dintnl[0][2] = -1.0 / _Eij[2][2];
220}
221
222Real
223TensileStressUpdate::tensile_strength(const Real internal_param) const
224{
225 return _strength.value(internal_param);
226}
227
228Real
229TensileStressUpdate::dtensile_strength(const Real internal_param) const
230{
231 return _strength.derivative(internal_param);
232}
233
234void
236 const std::vector<Real> & trial_stress_params,
237 const RankTwoTensor & /*stress*/,
238 const std::vector<Real> & stress_params,
239 Real /*gaE*/,
240 const yieldAndFlow & /*smoothed_q*/,
241 const RankFourTensor & elasticity_tensor,
242 bool compute_full_tangent_operator,
243 const std::vector<std::vector<Real>> & dvar_dtrial,
244 RankFourTensor & cto)
245{
246 cto = elasticity_tensor;
247 if (!compute_full_tangent_operator)
248 return;
249
250 // dvar_dtrial has been computed already, so
251 // d(stress)/d(trial_stress) = d(eigvecs * stress_params * eigvecs.transpose())/d(trial_stress)
252 // eigvecs is a rotation matrix, rot(i, j) = e_j(i) = i^th component of j^th eigenvector
253 // d(rot_ij)/d(stress_kl) = d(e_j(i))/d(stress_kl)
254 // = sum_a 0.5 * e_a(i) * (e_a(k)e_j(l) + e_a(l)e_j(k)) / (la_j - la_a)
255 // = sum_a 0.5 * rot(i,a) * (rot(k,a)rot(l,j) + rot(l,a)*rot(k,j)) / (la_j - la_a)
256 RankFourTensor drot_dstress;
257 for (unsigned i = 0; i < _tensor_dimensionality; ++i)
258 for (unsigned j = 0; j < _tensor_dimensionality; ++j)
259 for (unsigned k = 0; k < _tensor_dimensionality; ++k)
260 for (unsigned l = 0; l < _tensor_dimensionality; ++l)
261 for (unsigned a = 0; a < _num_sp; ++a)
262 {
263 if (trial_stress_params[a] == trial_stress_params[j])
264 continue;
265 drot_dstress(i, j, k, l) +=
266 0.5 * _eigvecs(i, a) *
267 (_eigvecs(k, a) * _eigvecs(l, j) + _eigvecs(l, a) * _eigvecs(k, j)) /
268 (trial_stress_params[j] - trial_stress_params[a]);
269 }
270
271 const RankTwoTensor eT = _eigvecs.transpose();
272
273 RankFourTensor dstress_dtrial;
274 for (unsigned i = 0; i < _tensor_dimensionality; ++i)
275 for (unsigned j = 0; j < _tensor_dimensionality; ++j)
276 for (unsigned k = 0; k < _tensor_dimensionality; ++k)
277 for (unsigned l = 0; l < _tensor_dimensionality; ++l)
278 for (unsigned a = 0; a < _num_sp; ++a)
279 dstress_dtrial(i, j, k, l) +=
280 drot_dstress(i, a, k, l) * stress_params[a] * eT(a, j) +
281 _eigvecs(i, a) * stress_params[a] * drot_dstress(j, a, k, l);
282
284 for (unsigned i = 0; i < _tensor_dimensionality; ++i)
285 for (unsigned j = 0; j < _tensor_dimensionality; ++j)
286 for (unsigned k = 0; k < _tensor_dimensionality; ++k)
287 for (unsigned l = 0; l < _tensor_dimensionality; ++l)
288 for (unsigned a = 0; a < _num_sp; ++a)
289 for (unsigned b = 0; b < _num_sp; ++b)
290 dstress_dtrial(i, j, k, l) +=
291 _eigvecs(i, a) * dvar_dtrial[a][b] * _dsp_trial_scratch[b](k, l) * eT(a, j);
292
293 cto = dstress_dtrial * elasticity_tensor;
294}
registerMooseObject("SolidMechanicsApp", TensileStressUpdate)
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)
MultiParameterPlasticityStressUpdate performs the return-map algorithm and associated stress updates ...
std::vector< std::vector< Real > > _Eij
E[i, j] in the system of equations to be solved.
std::vector< std::vector< Real > > _Cij
_Cij[i, j] * _Eij[j, k] = 1 iff j == k
const unsigned _num_sp
Number of stress parameters.
const unsigned _num_yf
Number of yield functions.
static constexpr unsigned _tensor_dimensionality
Internal dimensionality of tensors (currently this is 3 throughout solid mechanics)
void dsymmetricEigenvalues(std::vector< T > &eigvals, std::vector< RankTwoTensorTempl< T > > &deigvals) const
RankTwoTensorTempl< T > transpose() 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
virtual Real derivative(Real intnl) const
virtual Real value(Real intnl) const
TensileStressUpdate implements rate-independent associative tensile failure ("Rankine" plasticity) wi...
RankTwoTensor _eigvecs
Eigenvectors of the trial stress as a RankTwoTensor, in order to rotate the returned stress back to s...
void setEffectiveElasticity(const RankFourTensor &Eijkl) override
Sets _Eij and _En and _Cij.
virtual void consistentTangentOperatorV(const RankTwoTensor &stress_trial, const std::vector< Real > &trial_stress_params, const RankTwoTensor &stress, const std::vector< Real > &stress_params, Real gaE, const yieldAndFlow &smoothed_q, const RankFourTensor &Eijkl, bool compute_full_tangent_operator, const std::vector< std::vector< Real > > &dvar_dtrial, RankFourTensor &cto) override
Calculates the consistent tangent operator.
std::vector< Real > _eigvals_scratch
eigenvalues of the stress, used in dstressparam_dstress and preReturnMapV.
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
std::vector< RankTwoTensor > _dsp_trial_scratch
this is d(stress_param[:])/d(stress) which is calculated by dstressparam_dstress.
const SolidMechanicsHardeningModel & _strength
Hardening model for tensile strength.
void setIntnlDerivativesV(const std::vector< Real > &trial_stress_params, const std::vector< Real > &current_stress_params, const std::vector< Real > &intnl, std::vector< std::vector< Real > > &dintnl) const override
Sets the derivatives of internal parameters, based on the trial values of stress_params,...
static InputParameters validParams()
void computeAllQV(const std::vector< Real > &stress_params, const std::vector< Real > &intnl, std::vector< yieldAndFlow > &all_q) const override
Completely fills all_q with correct values.
virtual Real tensile_strength(const Real internal_param) const
tensile strength as a function of residual value, rate, and internal_param
TensileStressUpdate(const InputParameters &parameters)
virtual void setStressAfterReturnV(const RankTwoTensor &stress_trial, const std::vector< Real > &stress_params, Real gaE, const std::vector< Real > &intnl, const yieldAndFlow &smoothed_q, const RankFourTensor &Eijkl, RankTwoTensor &stress) const override
Sets stress from the admissible parameters.
virtual void preReturnMapV(const std::vector< Real > &trial_stress_params, const RankTwoTensor &stress_trial, const std::vector< Real > &intnl_old, const std::vector< Real > &yf, const RankFourTensor &Eijkl) override
Derived classes may employ this function to record stuff or do other computations prior to the return...
void d2stressparam_dstress(const RankTwoTensor &stress, std::vector< RankFourTensor > &d2sp) const override
d2(stress_param[i])/d(stress)/d(stress) at given stress.
void computeStressParams(const RankTwoTensor &stress, std::vector< Real > &stress_params) const override
Computes stress_params, given stress.
void setIntnlValuesV(const std::vector< Real > &trial_stress_params, const std::vector< Real > &current_stress_params, const std::vector< Real > &intnl_old, std::vector< Real > &intnl) const override
Sets the internal parameters based on the trial values of stress_params, their current values,...
void yieldFunctionValuesV(const std::vector< Real > &stress_params, const std::vector< Real > &intnl, std::vector< Real > &yf) const override
Computes the values of the yield functions, given stress_params and intnl parameters.
const bool _perfect_guess
Whether to provide an estimate of the returned stress, based on perfect plasticity.
void dstressparam_dstress(const RankTwoTensor &stress, std::vector< RankTwoTensor > &dsp) const override
d(stress_param[i])/d(stress) at given stress.
void initializeVarsV(const std::vector< Real > &trial_stress_params, const std::vector< Real > &intnl_old, std::vector< Real > &stress_params, Real &gaE, std::vector< Real > &intnl) const override
Sets (stress_params, intnl) at "good guesses" of the solution to the Return-Map algorithm.
Real elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l)
Struct designed to hold info about a single yield function and its derivatives, as well as the flow d...