https://mooseframework.inl.gov
Loading...
Searching...
No Matches
StressDivergenceTensors.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
12// MOOSE includes
14#include "Material.h"
15#include "MooseMesh.h"
16#include "MooseVariable.h"
17#include "SystemBase.h"
18
19#include "libmesh/quadrature.h"
20
22
25{
27 params.addClassDescription("Stress divergence kernel for the Cartesian coordinate system");
28 params.addRequiredRangeCheckedParam<unsigned int>("component",
29 "component < 3",
30 "An integer corresponding to the direction "
31 "the variable this kernel acts in. (0 for x, "
32 "1 for y, 2 for z)");
33 params.addRequiredCoupledVar("displacements",
34 "The string of displacements suitable for the problem statement");
35
36 // maybe this should be deprecated in favor of args
37 params.addCoupledVar("temperature",
38 "The name of the temperature variable used in the "
39 "ComputeThermalExpansionEigenstrain. (Not required for "
40 "simulations without temperature coupling.)");
41
42 params.addParam<std::vector<MaterialPropertyName>>(
43 "eigenstrain_names",
44 {},
45 "List of eigenstrains used in the strain calculation. Used for computing their derivatives "
46 "for off-diagonal Jacobian terms.");
47 params.addCoupledVar("out_of_plane_strain",
48 "The name of the out_of_plane_strain variable used in the "
49 "WeakPlaneStress kernel.");
50 MooseEnum out_of_plane_direction("x y z", "z");
51 params.addParam<MooseEnum>(
52 "out_of_plane_direction",
53 out_of_plane_direction,
54 "The direction of the out_of_plane_strain variable used in the WeakPlaneStress kernel.");
55 params.addParam<std::string>("base_name", "Material property base name");
56 params.set<bool>("use_displaced_mesh") = false;
57 params.addParam<bool>(
58 "use_finite_deform_jacobian", false, "Jacobian for corotational finite strain");
59 params.addParam<bool>("volumetric_locking_correction",
60 false,
61 "Set to false to turn off volumetric locking correction");
62 return params;
63}
64
66 : JvarMapKernelInterface<ALEKernel>(parameters),
67 _base_name(isParamValid("base_name") ? getParam<std::string>("base_name") + "_" : ""),
68 _use_finite_deform_jacobian(getParam<bool>("use_finite_deform_jacobian")),
69 _stress(getMaterialPropertyByName<RankTwoTensor>(_base_name + "stress")),
70 _Jacobian_mult(getMaterialPropertyByName<RankFourTensor>(_base_name + "Jacobian_mult")),
71 _component(getParam<unsigned int>("component")),
72 _ndisp(coupledComponents("displacements")),
73 _disp_var(_ndisp),
74 _out_of_plane_strain_coupled(isCoupled("out_of_plane_strain")),
75 _out_of_plane_strain(_out_of_plane_strain_coupled ? &coupledValue("out_of_plane_strain")
76 : nullptr),
77 _out_of_plane_strain_var(_out_of_plane_strain_coupled ? coupled("out_of_plane_strain") : 0),
78 _out_of_plane_direction(getParam<MooseEnum>("out_of_plane_direction")),
79 _use_displaced_mesh(getParam<bool>("use_displaced_mesh")),
80 _avg_grad_test(_test.size(), std::vector<Real>(3, 0.0)),
81 _avg_grad_phi(_phi.size(), std::vector<Real>(3, 0.0)),
82 _volumetric_locking_correction(getParam<bool>("volumetric_locking_correction"))
83{
84 // get coupled displacements
85 for (unsigned int i = 0; i < _ndisp; ++i)
86 _disp_var[i] = coupled("displacements", i);
87
88 // fetch eigenstrain derivatives
89 const auto nvar = _coupled_moose_vars.size();
90 _deigenstrain_dargs.resize(nvar);
91 for (std::size_t i = 0; i < nvar; ++i)
92 for (auto eigenstrain_name : getParam<std::vector<MaterialPropertyName>>("eigenstrain_names"))
93 _deigenstrain_dargs[i].push_back(&getMaterialPropertyDerivative<RankTwoTensor>(
94 eigenstrain_name, _coupled_moose_vars[i]->name()));
95
96 // Checking for consistency between mesh size and length of the provided displacements vector
97 if (_out_of_plane_direction != 2 && _ndisp != 3)
98 mooseError("For 2D simulations where the out-of-plane direction is x or y coordinate "
99 "directions the number of supplied displacements must be three.");
100 else if (_out_of_plane_direction == 2 && _ndisp != _mesh.dimension())
101 mooseError("The number of displacement variables supplied must match the mesh dimension");
102
104 {
106 &getMaterialProperty<RankTwoTensor>(_base_name + "deformation_gradient");
108 &getMaterialPropertyOld<RankTwoTensor>(_base_name + "deformation_gradient");
109 _rotation_increment = &getMaterialProperty<RankTwoTensor>(_base_name + "rotation_increment");
110 }
111
112 // Error if volumetric locking correction is turned on for 1D problems
114 mooseError("Volumetric locking correction should be set to false for 1-D problems.");
115
116 // Generate warning when volumetric locking correction is used with second order elements
117 if (_mesh.hasSecondOrderElements() && _volumetric_locking_correction)
118 mooseWarning("Volumteric locking correction is not required for second order elements. Using "
119 "volumetric locking with second order elements could cause zigzag patterns in "
120 "stresses and strains.");
121}
122
123void
125{
126 // check if any of the eigenstrains provide derivatives wrt variables that are not coupled
127 for (auto eigenstrain_name : getParam<std::vector<MaterialPropertyName>>("eigenstrain_names"))
128 validateNonlinearCoupling<RankTwoTensor>(eigenstrain_name);
129
130 // make sure the coordinate system is cartesioan
131 if (getBlockCoordSystem() != Moose::COORD_XYZ)
132 mooseError("The coordinate system in the Problem block must be set to XYZ for cartesian "
133 "geometries.");
134}
135
136void
138{
139 prepareVectorTag(_assembly, _var.number());
140
143
144 precalculateResidual();
145 for (_i = 0; _i < _test.size(); ++_i)
146 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
147 _local_re(_i) += _JxW[_qp] * _coord[_qp] * computeQpResidual();
148
149 accumulateTaggedLocalResidual();
150
151 if (_has_save_in)
152 {
153 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
154 for (const auto & var : _save_in)
155 var->sys().solution().add_vector(_local_re, var->dofIndices());
156 }
157}
158
159Real
161{
162 Real residual = _stress[_qp].row(_component) * _grad_test[_i][_qp];
163 // volumetric locking correction
165 residual += _stress[_qp].trace() / 3.0 *
166 (_avg_grad_test[_i][_component] - _grad_test[_i][_qp](_component));
167
169 {
170 const Real out_of_plane_thickness = std::exp((*_out_of_plane_strain)[_qp]);
171 residual *= out_of_plane_thickness;
172 }
173
174 return residual;
175}
176
177void
179{
181 {
184 }
185
187 {
188 _finite_deform_Jacobian_mult.resize(_qrule->n_points());
189
190 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
192
194 }
195 else
197}
198
199void
201{
203 {
206 }
207
209 {
210 _finite_deform_Jacobian_mult.resize(_qrule->n_points());
211
212 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
214
216 }
217 else
219}
220
221Real
223{
228 _grad_test[_i][_qp],
229 _grad_phi_undisplaced[_j][_qp]);
230
231 Real sum_C3x3 = _Jacobian_mult[_qp].sum3x3();
232 RealGradient sum_C3x1 = _Jacobian_mult[_qp].sum3x1();
233
234 Real jacobian = 0.0;
235 // B^T_i * C * B_j
237 _Jacobian_mult[_qp], _component, _component, _grad_test[_i][_qp], _grad_phi[_j][_qp]);
238
240 {
241 // jacobian = Bbar^T_i * C * Bbar_j where Bbar = B + Bvol
242 // jacobian = B^T_i * C * B_j + Bvol^T_i * C * Bvol_j + Bvol^T_i * C * B_j + B^T_i * C *
243 // Bvol_j
244
245 // Bvol^T_i * C * Bvol_j
246 jacobian += sum_C3x3 * (_avg_grad_test[_i][_component] - _grad_test[_i][_qp](_component)) *
247 (_avg_grad_phi[_j][_component] - _grad_phi[_j][_qp](_component)) / 9.0;
248
249 // B^T_i * C * Bvol_j
250 jacobian += sum_C3x1(_component) * _grad_test[_i][_qp](_component) *
251 (_avg_grad_phi[_j][_component] - _grad_phi[_j][_qp](_component)) / 3.0;
252
253 // Bvol^T_i * C * B_j
254 RankTwoTensor phi;
255 switch (_component)
256 {
257 case 0:
258 phi(0, 0) = _grad_phi[_j][_qp](0);
259 phi(0, 1) = phi(1, 0) = _grad_phi[_j][_qp](1);
260 phi(0, 2) = phi(2, 0) = _grad_phi[_j][_qp](2);
261 break;
262
263 case 1:
264 phi(1, 1) = _grad_phi[_j][_qp](1);
265 phi(0, 1) = phi(1, 0) = _grad_phi[_j][_qp](0);
266 phi(1, 2) = phi(2, 1) = _grad_phi[_j][_qp](2);
267 break;
268
269 case 2:
270 phi(2, 2) = _grad_phi[_j][_qp](2);
271 phi(0, 2) = phi(2, 0) = _grad_phi[_j][_qp](0);
272 phi(1, 2) = phi(2, 1) = _grad_phi[_j][_qp](1);
273 break;
274 }
275
276 jacobian += (_Jacobian_mult[_qp] * phi).trace() *
277 (_avg_grad_test[_i][_component] - _grad_test[_i][_qp](_component)) / 3.0;
278 }
279
281 {
282 const Real out_of_plane_thickness = std::exp((*_out_of_plane_strain)[_qp]);
283 jacobian *= out_of_plane_thickness;
284 }
285
286 return jacobian;
287}
288
289Real
291{
292 // off-diagonal Jacobian with respect to a coupled displacement component
293 for (unsigned int coupled_component = 0; coupled_component < _ndisp; ++coupled_component)
294 if (jvar == _disp_var[coupled_component])
295 {
297 {
298 if (coupled_component == _out_of_plane_direction)
299 continue;
300 }
301
305 coupled_component,
306 _grad_test[_i][_qp],
307 _grad_phi_undisplaced[_j][_qp]);
308
309 const Real sum_C3x3 = _Jacobian_mult[_qp].sum3x3();
310 const RealGradient sum_C3x1 = _Jacobian_mult[_qp].sum3x1();
311 Real jacobian = 0.0;
312
313 // B^T_i * C * B_j
316 coupled_component,
317 _grad_test[_i][_qp],
318 _grad_phi[_j][_qp]);
319
321 {
322 // jacobian = Bbar^T_i * C * Bbar_j where Bbar = B + Bvol
323 // jacobian = B^T_i * C * B_j + Bvol^T_i * C * Bvol_j + Bvol^T_i * C * B_j + B^T_i * C *
324 // Bvol_j
325
326 // Bvol^T_i * C * Bvol_j
327 jacobian += sum_C3x3 * (_avg_grad_test[_i][_component] - _grad_test[_i][_qp](_component)) *
328 (_avg_grad_phi[_j][coupled_component] - _grad_phi[_j][_qp](coupled_component)) /
329 9.0;
330
331 // B^T_i * C * Bvol_j
332 jacobian += sum_C3x1(_component) * _grad_test[_i][_qp](_component) *
333 (_avg_grad_phi[_j][coupled_component] - _grad_phi[_j][_qp](coupled_component)) /
334 3.0;
335
336 // Bvol^T_i * C * B_i
337 RankTwoTensor phi;
338 for (unsigned int i = 0; i < 3; ++i)
339 phi(coupled_component, i) = _grad_phi[_j][_qp](i);
340
341 jacobian += (_Jacobian_mult[_qp] * phi).trace() *
342 (_avg_grad_test[_i][_component] - _grad_test[_i][_qp](_component)) / 3.0;
343 }
344
345 return jacobian;
346 }
347
348 // off-diagonal Jacobian with respect to a coupled out_of_plane_strain variable
350 return _Jacobian_mult[_qp](
352 _grad_test[_i][_qp](_component) * _phi[_j][_qp];
353
354 // bail out if jvar is not coupled
355 if (getJvarMap()[jvar] < 0)
356 return 0.0;
357
358 // off-diagonal Jacobian with respect to any other coupled variable
359 const unsigned int cvar = mapJvarToCvar(jvar);
360 RankTwoTensor total_deigenstrain;
361 for (const auto deigenstrain_darg : _deigenstrain_dargs[cvar])
362 total_deigenstrain += (*deigenstrain_darg)[_qp];
363
364 return -((_Jacobian_mult[_qp] * total_deigenstrain) *
365 _grad_test[_i][_qp])(_component)*_phi[_j][_qp];
366}
367
368void
370{
371 usingTensorIndices(i_, j_, k_, l_);
372 const auto I = RankTwoTensor::Identity();
373 const RankFourTensor I2 = I.times<i_, k_, j_, l_>(I);
374
375 // Bring back to unrotated config
376 const RankTwoTensor unrotated_stress =
377 (*_rotation_increment)[_qp].transpose() * _stress[_qp] * (*_rotation_increment)[_qp];
378
379 // Incremental deformation gradient Fhat
380 const RankTwoTensor Fhat =
381 (*_deformation_gradient)[_qp] * (*_deformation_gradient_old)[_qp].inverse();
382 const RankTwoTensor Fhatinv = Fhat.inverse();
383
384 const RankTwoTensor rot_times_stress = (*_rotation_increment)[_qp] * unrotated_stress;
385 const RankFourTensor dstress_drot =
386 I.times<i_, k_, j_, l_>(rot_times_stress) + I.times<j_, k_, i_, l_>(rot_times_stress);
387 const RankFourTensor rot_rank_four =
388 (*_rotation_increment)[_qp].times<i_, k_, j_, l_>((*_rotation_increment)[_qp]);
389 const RankFourTensor drot_dUhatinv = Fhat.times<i_, k_, j_, l_>(I);
390
391 const RankTwoTensor A = I - Fhatinv;
392
393 // Ctilde = Chat^-1 - I
394 const RankTwoTensor Ctilde = A * A.transpose() - A - A.transpose();
395 const RankFourTensor dCtilde_dFhatinv =
396 -I.times<i_, k_, j_, l_>(A) - I.times<j_, k_, i_, l_>(A) + I2 + I.times<j_, k_, i_, l_>(I);
397
398 // Second order approximation of Uhat - consistent with strain increment definition
399 // const RankTwoTensor Uhat = I - 0.5 * Ctilde - 3.0/8.0 * Ctilde * Ctilde;
400
401 RankFourTensor dUhatinv_dCtilde =
402 0.5 * I2 - 1.0 / 8.0 * (I.times<i_, k_, j_, l_>(Ctilde) + Ctilde.times<i_, k_, j_, l_>(I));
403 RankFourTensor drot_dFhatinv = drot_dUhatinv * dUhatinv_dCtilde * dCtilde_dFhatinv;
404
405 drot_dFhatinv -= Fhat.times<i_, k_, j_, l_>((*_rotation_increment)[_qp].transpose());
406 _finite_deform_Jacobian_mult[_qp] = dstress_drot * drot_dFhatinv;
407
408 const RankFourTensor dstrain_increment_dCtilde =
409 -0.5 * I2 + 0.25 * (I.times<i_, k_, j_, l_>(Ctilde) + Ctilde.times<i_, k_, j_, l_>(I));
411 rot_rank_four * _Jacobian_mult[_qp] * dstrain_increment_dCtilde * dCtilde_dFhatinv;
412 _finite_deform_Jacobian_mult[_qp] += Fhat.times<j_, k_, i_, l_>(_stress[_qp]);
413
414 const RankFourTensor dFhat_dFhatinv = -Fhat.times<i_, k_, j_, l_>(Fhat.transpose());
415 const RankTwoTensor dJ_dFhatinv = dFhat_dFhatinv.innerProductTranspose(Fhat.ddet());
416
417 // Component from Jacobian derivative
418 _finite_deform_Jacobian_mult[_qp] += _stress[_qp].times<i_, j_, k_, l_>(dJ_dFhatinv);
419
420 // Derivative of Fhatinv w.r.t. undisplaced coordinates
421 const RankTwoTensor Finv = (*_deformation_gradient)[_qp].inverse();
422 const RankFourTensor dFhatinv_dGradu = -Fhatinv.times<i_, k_, j_, l_>(Finv.transpose());
424}
425
426void
428{
429 // Calculate volume averaged value of shape function derivative
430 _avg_grad_test.resize(_test.size());
431 for (_i = 0; _i < _test.size(); ++_i)
432 {
433 _avg_grad_test[_i].resize(3);
434 _avg_grad_test[_i][_component] = 0.0;
435 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
436 _avg_grad_test[_i][_component] += _grad_test[_i][_qp](_component) * _JxW[_qp] * _coord[_qp];
437
438 _avg_grad_test[_i][_component] /= _current_elem_volume;
439 }
440}
441
442void
444{
445 // Calculate volume average derivatives for phi
446 _avg_grad_phi.resize(_phi.size());
447 for (_i = 0; _i < _phi.size(); ++_i)
448 {
449 _avg_grad_phi[_i].resize(3);
450 for (unsigned int component = 0; component < _mesh.dimension(); ++component)
451 {
452 _avg_grad_phi[_i][component] = 0.0;
453 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
454 _avg_grad_phi[_i][component] += _grad_phi[_i][_qp](component) * _JxW[_qp] * _coord[_qp];
455
456 _avg_grad_phi[_i][component] /= _current_elem_volume;
457 }
458 }
459}
void mooseWarning(Args &&... args)
void mooseError(Args &&... args)
const std::string name
Definition Setup.h:21
registerMooseObject("SolidMechanicsApp", StressDivergenceTensors)
void ErrorVector unsigned int
virtual void computeOffDiagJacobian(unsigned int jvar) override
Definition ALEKernel.C:41
virtual void computeJacobian() override
Definition ALEKernel.C:34
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
void addRequiredCoupledVar(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)
T & set(const std::string &name, bool quiet_mode=false)
void addCoupledVar(const std::string &name, const std::string &doc_string)
static InputParameters validParams()
unsigned int mapJvarToCvar(unsigned int jvar)
virtual void computeOffDiagJacobian(unsigned int jvar) override
virtual void computeJacobian() override
RankTwoTensorTempl< T > ddet() const
RankFourTensorTempl< T > times(const RankTwoTensorTempl< T > &b) const
RankTwoTensorTempl< T > inverse() const
RankTwoTensorTempl< T > transpose() const
static RankTwoTensorTempl Identity()
StressDivergenceTensors mostly copies from StressDivergence.
const std::string _base_name
Base name of the material system that this kernel applies to.
std::vector< unsigned int > _disp_var
Displacement variables IDs.
const unsigned int _out_of_plane_direction
const unsigned int _component
An integer corresponding to the direction this kernel acts in.
const MaterialProperty< RankTwoTensor > & _stress
The stress tensor that the divergence operator operates on.
virtual Real computeQpOffDiagJacobian(unsigned int jvar) override
const MaterialProperty< RankFourTensor > & _Jacobian_mult
bool _volumetric_locking_correction
Flag for volumetric locking correction.
StressDivergenceTensors(const InputParameters &parameters)
static InputParameters validParams()
unsigned int _ndisp
Coupled displacement variables.
const bool _use_displaced_mesh
Whether this object is acting on the displaced mesh.
const MaterialProperty< RankTwoTensor > * _rotation_increment
std::vector< std::vector< Real > > _avg_grad_phi
Gradient of phi function averaged over the element. Used in volumetric locking correction calculation...
const MaterialProperty< RankTwoTensor > * _deformation_gradient_old
const VariableValue *const _out_of_plane_strain
std::vector< RankFourTensor > _finite_deform_Jacobian_mult
virtual void computeResidual() override
const unsigned int _out_of_plane_strain_var
virtual Real computeQpResidual() override
std::vector< std::vector< Real > > _avg_grad_test
Gradient of test function averaged over the element. Used in volumetric locking correction calculatio...
virtual Real computeQpJacobian() override
virtual void computeOffDiagJacobian(unsigned int jvar) override
const MaterialProperty< RankTwoTensor > * _deformation_gradient
std::vector< std::vector< const MaterialProperty< RankTwoTensor > * > > _deigenstrain_dargs
eigen strain derivatives wrt coupled variables
virtual void computeJacobian() override
virtual void initialSetup() override
Real elasticJacobian(const RankFourTensor &r4t, unsigned int i, unsigned int k, const RealGradient &grad_test, const RealGradient &grad_phi)
This is used for the standard kernel stress_ij*d(test)/dx_j, when varied wrt u_k Jacobian entry: d(st...