https://mooseframework.inl.gov
Loading...
Searching...
No Matches
SCZMInterfaceKernelSmallStrain.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
12#include "StabilizationUtils.h"
13
14namespace
15{
17gradOpForCoord(const Moose::CoordinateSystemType coord_sys,
18 const unsigned int component,
19 const RealVectorValue & grad,
20 const Real value,
21 const Point & point)
22{
23 RankTwoTensor grad_op;
24
25 switch (coord_sys)
26 {
28 for (const auto j : make_range(3))
29 grad_op(component, j) = grad(j);
30 break;
31
32 case Moose::COORD_RZ:
33 for (const auto j : make_range(2))
34 grad_op(component, j) = grad(j);
35
36 if (component == 0)
37 grad_op(2, 2) = value / point(0);
38 break;
39
41 grad_op(0, 0) = grad(0);
42 grad_op(1, 1) = value / point(0);
43 grad_op(2, 2) = value / point(0);
44 break;
45
46 default:
47 mooseError("Unsupported coordinate system for SCZMInterfaceKernelSmallStrain.");
48 }
49
50 return grad_op;
51}
52}
53
56
57template <bool is_ad>
60{
62
63 params.addParam<bool>("directional_correction", true, "Add the directional correction terms.");
64 params.addParam<MaterialPropertyName>(
65 "stress", "stress", "Name of the stress tensor material property.");
66 if constexpr (!is_ad)
67 {
68 params.addParam<MaterialPropertyName>(
69 "tangent", "Jacobian_mult", "Name of the material Jacobian tensor property.");
70 params.addParam<MooseEnum>(
71 "tangent_definition",
72 MooseEnum("auto stress_wrt_strain pk1_wrt_deformation_gradient", "auto"),
73 "Mathematical definition of the tangent material property. 'auto' recognizes the standard "
74 "Jacobian_mult property as d(stress)/d(strain) and pk1_jacobian as d(PK1)/d(F). Select "
75 "'stress_wrt_strain' or 'pk1_wrt_deformation_gradient' explicitly for a custom tangent "
76 "property; use the latter only when the property is known to be d(PK1)/d(F).");
77 params.addParam<bool>(
78 "volumetric_locking_correction",
79 false,
80 "Whether to apply volumetric locking correction to the directional "
81 "correction Jacobian. This setting should be consistent with the volumetric "
82 "locking correction used in the bulk finite element formulation to ensure "
83 "the interface Jacobian is consistent with the bulk stress.");
84 }
86 "Shifted CZM Interface kernel to use when using the Small Strain kinematic formulation.");
87
88 return params;
89}
90
91template <bool is_ad>
93 const InputParameters & parameters)
94 : SCZMInterfaceKernelBaseTempl<is_ad>(parameters),
95 _stress(this->template getGenericMaterialPropertyByName<RankTwoTensor, is_ad>(
96 this->_base_name + parameters.get<MaterialPropertyName>("stress"))),
97 _stress_neighbor(this->template getGenericNeighborMaterialPropertyByName<RankTwoTensor, is_ad>(
98 this->_base_name + parameters.get<MaterialPropertyName>("stress"))),
99 _dtraction_djump_global(nullptr),
100 _Jacobian_mult(nullptr),
101 _Jacobian_mult_neighbor(nullptr),
102 _tangent_is_dpk1_df(false),
103 _directional_correction(parameters.get<bool>("directional_correction")),
104 _volumetric_locking_correction(false)
105{
106 if constexpr (!is_ad)
107 {
108 _disp_var.resize(this->_ndisp);
109 _vars.resize(this->_ndisp);
110 for (const auto i : make_range(this->_ndisp))
111 {
112 _disp_var[i] = this->coupled("displacements", i);
113 _vars[i] = this->getVar("displacements", i);
114 }
115
116 _dtraction_djump_global = &this->template getMaterialPropertyByName<RankTwoTensor>(
117 this->_base_name + "dtraction_djump_global");
118 _Jacobian_mult = &this->template getMaterialPropertyByName<RankFourTensor>(
119 this->_base_name + parameters.get<MaterialPropertyName>("tangent"));
120 _Jacobian_mult_neighbor = &this->template getNeighborMaterialPropertyByName<RankFourTensor>(
121 this->_base_name + parameters.get<MaterialPropertyName>("tangent"));
122 _volumetric_locking_correction = parameters.get<bool>("volumetric_locking_correction");
123
124 const auto & tangent_name = parameters.get<MaterialPropertyName>("tangent");
125 const auto & tangent_definition = parameters.get<MooseEnum>("tangent_definition");
126 if (tangent_definition == "auto")
127 {
128 if (tangent_name == "Jacobian_mult")
129 _tangent_is_dpk1_df = false;
130 else if (tangent_name == "pk1_jacobian")
131 _tangent_is_dpk1_df = true;
132 else
133 this->paramError("tangent_definition",
134 "Cannot infer the mathematical definition of custom tangent property '",
135 tangent_name,
136 "'. Set 'tangent_definition' to 'stress_wrt_strain' or "
137 "'pk1_wrt_deformation_gradient'.");
138 }
139 else
140 _tangent_is_dpk1_df = tangent_definition == "pk1_wrt_deformation_gradient";
141 }
142}
143
144template <bool is_ad>
147{
148 if (!this->_shifted)
150
151 const RealVectorValue true_normal(this->trueNormal());
152 const Real true_normal_dot_surrogate_normal = true_normal * this->_normals[this->_qp];
153
155 residual *= true_normal_dot_surrogate_normal;
156
157 if (_directional_correction)
158 {
159 const auto stress = _stress[this->_qp].row(this->_component);
160 const auto stress_neighbor = _stress_neighbor[this->_qp].row(this->_component);
161 const auto normal_tangent =
162 this->_normals[this->_qp] - true_normal_dot_surrogate_normal * true_normal;
163
164 switch (type)
165 {
166 case Moose::Element:
167 residual -= this->_test[this->_i][this->_qp] * (stress * normal_tangent);
168 break;
169
170 case Moose::Neighbor:
171 residual += this->_test_neighbor[this->_i][this->_qp] * (stress_neighbor * normal_tangent);
172 break;
173
174 default:
175 break;
176 }
177 }
178
179 return residual;
180}
181
182template <>
183Real
185 unsigned int /*component_j*/, Moose::DGJacobianType /*type*/) const
186{
187 return 0;
188}
189
190template <>
191Real
193 unsigned int component_j, Moose::DGJacobianType type) const
194{
195 const auto jacsd = (*_dtraction_djump_global)[this->_qp](this->_component, component_j);
196 Real jac = jacsd;
197
198 if (!_shifted)
199 {
200 switch (type)
201 {
202 case Moose::ElementElement: // Residual_sign -1 ddeltaU_ddisp sign -1;
203 jac *= _test[_i][_qp] * _vars[component_j]->phiFace()[_j][_qp];
204 break;
205 case Moose::ElementNeighbor: // Residual_sign -1 ddeltaU_ddisp sign 1;
206 jac *= -_test[_i][_qp] * _vars[component_j]->phiFaceNeighbor()[_j][_qp];
207 break;
208 case Moose::NeighborElement: // Residual_sign 1 ddeltaU_ddisp sign -1;
209 jac *= -_test_neighbor[_i][_qp] * _vars[component_j]->phiFace()[_j][_qp];
210 break;
211 case Moose::NeighborNeighbor: // Residual_sign 1 ddeltaU_ddisp sign 1;
212 jac *= _test_neighbor[_i][_qp] * _vars[component_j]->phiFaceNeighbor()[_j][_qp];
213 break;
214 }
215 return jac;
216 }
217
218 const auto d = surrogateDistance();
219 const auto true_normal = RealVectorValue(trueNormal());
220 const auto true_normal_dot_surrogate_normal = true_normal * _normals[_qp];
221
222 // Shifted derivative uses d(u + grad_u * d)/du = phiFace + gradPhiFace * d.
223 switch (type)
224 {
225 case Moose::ElementElement: // Residual_sign -1 ddeltaU_ddisp sign -1;
226 jac *= _test[_i][_qp] * (_vars[component_j]->phiFace()[_j][_qp] +
227 _vars[component_j]->gradPhiFace()[_j][_qp] * d);
228 break;
229 case Moose::ElementNeighbor: // Residual_sign -1 ddeltaU_ddisp sign 1;
230 jac *= -_test[_i][_qp] * (_vars[component_j]->phiFaceNeighbor()[_j][_qp] +
231 _vars[component_j]->gradPhiFaceNeighbor()[_j][_qp] * d);
232 break;
233 case Moose::NeighborElement: // Residual_sign 1 ddeltaU_ddisp sign -1;
234 jac *= -_test_neighbor[_i][_qp] * (_vars[component_j]->phiFace()[_j][_qp] +
235 _vars[component_j]->gradPhiFace()[_j][_qp] * d);
236 break;
237 case Moose::NeighborNeighbor: // Residual_sign 1 ddeltaU_ddisp sign 1;
238 jac *= _test_neighbor[_i][_qp] * (_vars[component_j]->phiFaceNeighbor()[_j][_qp] +
239 _vars[component_j]->gradPhiFaceNeighbor()[_j][_qp] * d);
240 break;
241 }
242
243 jac *= true_normal_dot_surrogate_normal; // Area correction
244
245 return jac;
246}
247
248template <>
249Real
251 unsigned int ivar, unsigned int jvar, Moose::DGJacobianType type) const
252{
253 const auto true_normal =
254 _shifted ? RealVectorValue(trueNormal()) : RealVectorValue(_normals[_qp]);
255
256 const bool trial_on_element = type == Moose::ElementElement || type == Moose::NeighborElement;
257 const auto grad_phi = trial_on_element ? _grad_phi[_j][_qp] : _grad_phi_neighbor[_j][_qp];
258
259 const auto nt_tangent = _normals[_qp] - (true_normal * _normals[_qp]) * true_normal;
260
261 const auto test = (type == Moose::ElementElement || type == Moose::ElementNeighbor)
262 ? _test[_i][_qp]
263 : _test_neighbor[_i][_qp];
264
265 const auto & r4t = (type == Moose::ElementElement || type == Moose::ElementNeighbor)
266 ? (*_Jacobian_mult)[_qp]
267 : (*_Jacobian_mult_neighbor)[_qp];
268
269 const Real origin_part = ElasticityTensorTools::elasticJacobian(
270 r4t, ivar, jvar, nt_tangent * test /*transpose later (w^T n^T)*/, grad_phi /*B*/);
271
272 const Real n0 = nt_tangent(0);
273 const Real n1 = nt_tangent(1);
274 const Real n2 = nt_tangent(2);
275
276 const Real gp0 = grad_phi(0);
277 const Real gp1 = grad_phi(1);
278 const Real gp2 = grad_phi(2);
279
280 const auto i = ivar;
281 const auto k = jvar;
282
283 const Real symmetric_part =
284 ((r4t(i, 0, 0, k) * gp0 + r4t(i, 0, 1, k) * gp1 + r4t(i, 0, 2, k) * gp2) * n0 +
285 (r4t(i, 1, 0, k) * gp0 + r4t(i, 1, 1, k) * gp1 + r4t(i, 1, 2, k) * gp2) * n1 +
286 (r4t(i, 2, 0, k) * gp0 + r4t(i, 2, 1, k) * gp1 + r4t(i, 2, 2, k) * gp2) * n2) *
287 test;
288
289 // dP/dF acts on the full displacement gradient. A strain-based tangent instead acts on the
290 // symmetric gradient, which contributes the transposed contraction as well.
291 Real jacobian = _tangent_is_dpk1_df ? origin_part : (origin_part + symmetric_part) * 0.5;
292
293 if (_volumetric_locking_correction)
294 {
295 const auto grad_op = gradOpForCoord(_coord_sys,
296 k,
297 grad_phi,
298 trial_on_element ? _phi[_j][_qp] : _phi_neighbor[_j][_qp],
299 _q_point[_qp]);
300 const auto avg_grad_op = StabilizationUtils::elementAverage(
301 [this, k, trial_on_element](unsigned int qp)
302 {
303 return gradOpForCoord(_coord_sys,
304 k,
305 trial_on_element ? _grad_phi[_j][qp] : _grad_phi_neighbor[_j][qp],
306 trial_on_element ? _phi[_j][qp] : _phi_neighbor[_j][qp],
307 _q_point[qp]);
308 },
309 _JxW,
310 _coord);
311 const Real volumetric_increment = (avg_grad_op.trace() - grad_op.trace()) / 3.0;
312
313 for (const auto m : make_range(3))
314 jacobian += (r4t(i, 0, m, m) * n0 + r4t(i, 1, m, m) * n1 + r4t(i, 2, m, m) * n2) * test *
315 volumetric_increment;
316 }
317
318 return jacobian;
319}
320
321template <>
322Real
327
328template <>
329Real
331{
332 Real jacobian = computeDResidualDDisplacement(this->_component, type);
333
334 if (_shifted && _directional_correction)
335 switch (type)
336 {
338 jacobian -= calculateDirectionalCorrectionJacobian(_component, _component, type);
339 break;
341 jacobian += calculateDirectionalCorrectionJacobian(_component, _component, type);
342 break;
345 break;
346 }
347
348 return jacobian;
349}
350
351template <>
352Real
354 unsigned int /*jvar*/)
355{
356 return 0;
357}
358
359template <>
360Real
362 unsigned int jvar)
363{
364 if (this->getJvarMap()[jvar] < 0)
365 return 0;
366
367 Real jacobian = 0;
368 for (const auto coupled_component : make_range(this->_ndisp))
369 if (jvar == _disp_var[coupled_component])
370 jacobian = computeDResidualDDisplacement(coupled_component, type);
371
372 if (_shifted && _directional_correction)
373 for (const auto coupled_component : make_range(_ndisp))
374 if (jvar == _disp_var[coupled_component])
375 switch (type)
376 {
378 jacobian -= calculateDirectionalCorrectionJacobian(_component, coupled_component, type);
379 break;
381 jacobian += calculateDirectionalCorrectionJacobian(_component, coupled_component, type);
382 break;
385 break;
386 }
387
388 return jacobian;
389}
390
391template <>
392Real
398
void mooseError(Args &&... args)
Moose::GenericType< Real, is_ad > GenericReal
registerMooseObject("ShiftedBoundaryMethodApp", SCZMInterfaceKernelSmallStrain)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
void addClassDescription(const std::string &doc_string)
Base class for AD and non-AD shifted cohesive zone interface kernels.
static InputParameters validParams()
const std::string _base_name
Base name of the material system that this kernel applies to.
GenericReal< is_ad > computeQpResidual(Moose::DGResidualType type) override
const unsigned int _ndisp
Number of displacement components.
AD and non-AD shifted cohesive zone interface kernel for the small-strain formulation.
const MaterialProperty< RankTwoTensor > * _dtraction_djump_global
const MaterialProperty< RankFourTensor > * _Jacobian_mult
Real calculateDirectionalCorrectionJacobian(unsigned int ivar, unsigned int jvar, Moose::DGJacobianType type) const
Real computeQpJacobian(Moose::DGJacobianType type) override
GenericReal< is_ad > computeQpResidual(Moose::DGResidualType type) override
SCZMInterfaceKernelSmallStrainTempl(const InputParameters &parameters)
Real computeDResidualDDisplacement(unsigned int component_j, Moose::DGJacobianType type) const
std::vector< unsigned int > _disp_var
Non-AD data used by the hand-coded Jacobian.
bool _volumetric_locking_correction
Whether to apply the volumetric locking correction to the directional correction term.
const MaterialProperty< RankFourTensor > * _Jacobian_mult_neighbor
Real computeQpOffDiagJacobian(Moose::DGJacobianType type, unsigned int jvar) 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...
DGResidualType
CoordinateSystemType
COORD_RSPHERICAL
DGJacobianType
NeighborNeighbor
ElementElement
NeighborElement
ElementNeighbor
std::string grad(const std::string &var)
Definition NS.h:92
T component(const RankTwoTensorTempl< T > &r2tensor, unsigned int i, unsigned int j)
auto elementAverage(const Functor &f, const MooseArray< Real > &JxW, const MooseArray< Real > &coord)
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
IntRange< T > make_range(T beg, T end)