https://mooseframework.inl.gov
Loading...
Searching...
No Matches
StressDivergenceRZTensors.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 "Assembly.h"
13#include "libmesh/quadrature.h"
14
16
19{
22 "Calculate stress divergence for an axisymmetric problem in cylindrical coordinates.");
23 params.addRequiredRangeCheckedParam<unsigned int>(
24 "component",
25 "component < 2",
26 "An integer corresponding to the direction the variable this kernel acts in. (0 "
27 "refers to the radial and 1 to the axial displacement.)");
28 params.set<bool>("use_displaced_mesh") = true;
29 return params;
30}
31
36
37void
39{
40 // check if any of the eigenstrains provide derivatives wrt variables that are not coupled
41 for (auto eigenstrain_name : getParam<std::vector<MaterialPropertyName>>("eigenstrain_names"))
42 validateNonlinearCoupling<RankTwoTensor>(eigenstrain_name);
43
44 if (getBlockCoordSystem() != Moose::COORD_RZ)
45 mooseError("The coordinate system in the Problem block must be set to RZ for axisymmetric "
46 "geometries.");
47
48 if (getBlockCoordSystem() == Moose::COORD_RZ && _fe_problem.getAxisymmetricRadialCoord() != 0)
49 mooseError("rz_coord_axis=Y is the only supported option for StressDivergenceRZTensors");
50}
51
52Real
54{
55 Real div = 0.0;
56 if (_component == 0)
57 {
58 div = _grad_test[_i][_qp](0) * _stress[_qp](0, 0) +
59 +(_test[_i][_qp] / _q_point[_qp](0)) * _stress[_qp](2, 2) +
60 +_grad_test[_i][_qp](1) * _stress[_qp](0, 1); // stress_{rz}
61
62 // volumetric locking correction
64 div += (_avg_grad_test[_i][0] - _grad_test[_i][_qp](0) - _test[_i][_qp] / _q_point[_qp](0)) *
65 (_stress[_qp].trace()) / 3.0;
66 }
67 else if (_component == 1)
68 {
69 div = _grad_test[_i][_qp](1) * _stress[_qp](1, 1) +
70 +_grad_test[_i][_qp](0) * _stress[_qp](1, 0); // stress_{zr}
71
72 // volumetric locking correction
74 div += (_avg_grad_test[_i][1] - _grad_test[_i][_qp](1)) * (_stress[_qp].trace()) / 3.0;
75 }
76 else
77 mooseError("Invalid component for this AxisymmetricRZ problem.");
78
79 return div;
80}
81
82Real
87
88Real
90{
91 for (unsigned int i = 0; i < _ndisp; ++i)
92 if (jvar == _disp_var[i])
94
95 // bail out if jvar is not coupled
96 if (getJvarMap()[jvar] < 0)
97 return 0.0;
98
99 // off-diagonal Jacobian with respect to any other coupled variable
100 const unsigned int cvar = mapJvarToCvar(jvar);
101 RankTwoTensor total_deigenstrain;
102 for (const auto deigenstrain_darg : _deigenstrain_dargs[cvar])
103 total_deigenstrain += (*deigenstrain_darg)[_qp];
104
105 Real jac = 0.0;
106 if (_component == 0)
107 {
108 for (unsigned k = 0; k < LIBMESH_DIM; ++k)
109 for (unsigned l = 0; l < LIBMESH_DIM; ++l)
110 jac -= (_grad_test[_i][_qp](0) * _Jacobian_mult[_qp](0, 0, k, l) +
111 _test[_i][_qp] / _q_point[_qp](0) * _Jacobian_mult[_qp](2, 2, k, l) +
112 _grad_test[_i][_qp](1) * _Jacobian_mult[_qp](0, 1, k, l)) *
113 total_deigenstrain(k, l);
114 return jac * _phi[_j][_qp];
115 }
116 else if (_component == 1)
117 {
118 for (unsigned k = 0; k < LIBMESH_DIM; ++k)
119 for (unsigned l = 0; l < LIBMESH_DIM; ++l)
120 jac -= (_grad_test[_i][_qp](1) * _Jacobian_mult[_qp](1, 1, k, l) +
121 _grad_test[_i][_qp](0) * _Jacobian_mult[_qp](1, 0, k, l)) *
122 total_deigenstrain(k, l);
123 return jac * _phi[_j][_qp];
124 }
125
126 return 0.0;
127}
128
129Real
130StressDivergenceRZTensors::calculateJacobian(unsigned int ivar, unsigned int jvar)
131{
132 // B^T_i * C * B_j
133 RealGradient test, test_z, phi, phi_z;
134 Real first_term = 0.0;
135 if (ivar == 0) // Case grad_test for x, requires contributions from stress_xx, stress_xy, and
136 // stress_zz
137 {
138 test(0) = _grad_test[_i][_qp](0);
139 test(1) = _grad_test[_i][_qp](1);
140 test_z(2) = _test[_i][_qp] / _q_point[_qp](0);
141 }
142 else // Case grad_test for y
143 {
144 test(0) = _grad_test[_i][_qp](0);
145 test(1) = _grad_test[_i][_qp](1);
146 }
147
148 if (jvar == 0)
149 {
150 phi(0) = _grad_phi[_j][_qp](0);
151 phi(1) = _grad_phi[_j][_qp](1);
152 phi_z(2) = _phi[_j][_qp] / _q_point[_qp](0);
153 }
154 else
155 {
156 phi(0) = _grad_phi[_j][_qp](0);
157 phi(1) = _grad_phi[_j][_qp](1);
158 }
159
160 if (ivar == 0 &&
161 jvar == 0) // Case when both phi and test are functions of x and z; requires four terms
162 {
163 const Real first_sum = ElasticityTensorTools::elasticJacobian(
164 _Jacobian_mult[_qp], ivar, jvar, test, phi); // test_x and phi_x
165 const Real second_sum = ElasticityTensorTools::elasticJacobian(
166 _Jacobian_mult[_qp], 2, 2, test_z, phi_z); // test_z and phi_z
167 const Real mixed_sum1 = ElasticityTensorTools::elasticJacobian(
168 _Jacobian_mult[_qp], ivar, 2, test, phi_z); // test_x and phi_z
169 const Real mixed_sum2 = ElasticityTensorTools::elasticJacobian(
170 _Jacobian_mult[_qp], 2, jvar, test_z, phi); // test_z and phi_x
171
172 first_term = first_sum + second_sum + mixed_sum1 + mixed_sum2;
173 }
174 else if (ivar == 0 && jvar == 1)
175 {
176 const Real first_sum = ElasticityTensorTools::elasticJacobian(
177 _Jacobian_mult[_qp], ivar, jvar, test, phi); // test_x and phi_y
178 const Real mixed_sum2 = ElasticityTensorTools::elasticJacobian(
179 _Jacobian_mult[_qp], 2, jvar, test_z, phi); // test_z and phi_y
180
181 first_term = first_sum + mixed_sum2;
182 }
183 else if (ivar == 1 && jvar == 0)
184 {
185 const Real second_sum = ElasticityTensorTools::elasticJacobian(
186 _Jacobian_mult[_qp], ivar, jvar, test, phi); // test_y and phi_x
187 const Real mixed_sum1 = ElasticityTensorTools::elasticJacobian(
188 _Jacobian_mult[_qp], ivar, 2, test, phi_z); // test_y and phi_z
189
190 first_term = second_sum + mixed_sum1;
191 }
192 else if (ivar == 1 && jvar == 1)
194 _Jacobian_mult[_qp], ivar, jvar, test, phi); // test_y and phi_y
195 else
196 mooseError("Invalid component in Jacobian Calculation");
197
198 Real val = 0.0;
199 // volumetric locking correction
200 // K = Bbar^T_i * C * Bbar^T_j where Bbar = B + Bvol
201 // K = B^T_i * C * B_j + Bvol^T_i * C * Bvol_j + B^T_i * C * Bvol_j + Bvol^T_i * C * B_j
203 {
204 RealGradient new_test(2, 0.0);
205 RealGradient new_phi(2, 0.0);
206
207 new_test(0) = _grad_test[_i][_qp](0) + _test[_i][_qp] / _q_point[_qp](0);
208 new_test(1) = _grad_test[_i][_qp](1);
209 new_phi(0) = _grad_phi[_j][_qp](0) + _phi[_j][_qp] / _q_point[_qp](0);
210 new_phi(1) = _grad_phi[_j][_qp](1);
211
212 // Bvol^T_i * C * Bvol_j
213 val += _Jacobian_mult[_qp].sum3x3() * (_avg_grad_test[_i][ivar] - new_test(ivar)) *
214 (_avg_grad_phi[_j][jvar] - new_phi(jvar)) / 3.0;
215
216 // B^T_i * C * Bvol_j
217 RealGradient sum_3x1 = _Jacobian_mult[_qp].sum3x1();
218 if (ivar == 0 && jvar == 0)
219 val += (sum_3x1(0) * test(0) + sum_3x1(2) * test_z(2)) * (_avg_grad_phi[_j][0] - new_phi(0));
220 else if (ivar == 0 && jvar == 1)
221 val += (sum_3x1(0) * test(0) + sum_3x1(2) * test_z(2)) * (_avg_grad_phi[_j][1] - new_phi(1));
222 else if (ivar == 1 && jvar == 0)
223 val += sum_3x1(1) * test(1) * (_avg_grad_phi[_j][0] - new_phi(0));
224 else
225 val += sum_3x1(1) * test(1) * (_avg_grad_phi[_j][1] - new_phi(1));
226
227 // Bvol^T_i * C * B_j
228 // val = trace (C * B_j) *(avg_grad_test[_i][ivar] - new_test(ivar))
229 if (jvar == 0)
230 for (unsigned int i = 0; i < 3; ++i)
231 val +=
232 (_Jacobian_mult[_qp](i, i, 0, 0) * phi(0) + _Jacobian_mult[_qp](i, i, 0, 1) * phi(1) +
233 _Jacobian_mult[_qp](i, i, 2, 2) * phi_z(2)) *
234 (_avg_grad_test[_i][ivar] - new_test(ivar));
235 else if (jvar == 1)
236 for (unsigned int i = 0; i < 3; ++i)
237 val +=
238 (_Jacobian_mult[_qp](i, i, 0, 1) * phi(0) + _Jacobian_mult[_qp](i, i, 1, 1) * phi(1)) *
239 (_avg_grad_test[_i][ivar] - new_test(ivar));
240 }
241
242 return val / 3.0 + first_term;
243}
244
245void
247{
248 // calculate volume averaged value of shape function derivative
249 _avg_grad_test.resize(_test.size());
250 for (_i = 0; _i < _test.size(); ++_i)
251 {
252 _avg_grad_test[_i].resize(2);
253 _avg_grad_test[_i][_component] = 0.0;
254 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
255 {
256 if (_component == 0)
258 (_grad_test[_i][_qp](_component) + _test[_i][_qp] / _q_point[_qp](0)) * _JxW[_qp] *
259 _coord[_qp];
260 else
261 _avg_grad_test[_i][_component] += _grad_test[_i][_qp](_component) * _JxW[_qp] * _coord[_qp];
262 }
263 _avg_grad_test[_i][_component] /= _current_elem_volume;
264 }
265}
266
267void
269{
270 _avg_grad_phi.resize(_phi.size());
271 for (_i = 0; _i < _phi.size(); ++_i)
272 {
273 _avg_grad_phi[_i].resize(2);
274 for (unsigned int component = 0; component < 2; ++component)
275 {
276 _avg_grad_phi[_i][component] = 0.0;
277 for (_qp = 0; _qp < _qrule->n_points(); ++_qp)
278 {
279 if (component == 0)
280 _avg_grad_phi[_i][component] +=
281 (_grad_phi[_i][_qp](component) + _phi[_i][_qp] / _q_point[_qp](0)) * _JxW[_qp] *
282 _coord[_qp];
283 else
284 _avg_grad_phi[_i][component] += _grad_phi[_i][_qp](component) * _JxW[_qp] * _coord[_qp];
285 }
286 _avg_grad_phi[_i][component] /= _current_elem_volume;
287 }
288 }
289}
void mooseError(Args &&... args)
registerMooseObject("SolidMechanicsApp", StressDivergenceRZTensors)
void addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
T & set(const std::string &name, bool quiet_mode=false)
unsigned int mapJvarToCvar(unsigned int jvar)
StressDivergenceRZTensors is a modification of StressDivergenceTensors to accommodate the Axisymmetri...
virtual Real computeQpResidual() override
virtual Real computeQpJacobian() override
virtual void initialSetup() override
virtual Real computeQpOffDiagJacobian(unsigned int jvar) override
virtual void computeAverageGradientPhi() override
static InputParameters validParams()
virtual void computeAverageGradientTest() override
Real calculateJacobian(unsigned int ivar, unsigned int jvar)
StressDivergenceRZTensors(const InputParameters &parameters)
StressDivergenceTensors mostly copies from StressDivergence.
std::vector< unsigned int > _disp_var
Displacement variables IDs.
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.
const MaterialProperty< RankFourTensor > & _Jacobian_mult
bool _volumetric_locking_correction
Flag for volumetric locking correction.
static InputParameters validParams()
unsigned int _ndisp
Coupled displacement variables.
std::vector< std::vector< Real > > _avg_grad_phi
Gradient of phi function averaged over the element. Used in volumetric locking correction calculation...
std::vector< std::vector< Real > > _avg_grad_test
Gradient of test function averaged over the element. Used in volumetric locking correction calculatio...
std::vector< std::vector< const MaterialProperty< RankTwoTensor > * > > _deigenstrain_dargs
eigen strain derivatives wrt coupled variables
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...