18 const unsigned int component,
19 const RealVectorValue & grad,
37 grad_op(2, 2) =
value / point(0);
41 grad_op(0, 0) =
grad(0);
42 grad_op(1, 1) =
value / point(0);
43 grad_op(2, 2) =
value / point(0);
47 mooseError(
"Unsupported coordinate system for SCZMInterfaceKernelSmallStrain.");
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.");
68 params.
addParam<MaterialPropertyName>(
69 "tangent",
"Jacobian_mult",
"Name of the material Jacobian tensor property.");
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).");
78 "volumetric_locking_correction",
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.");
86 "Shifted CZM Interface kernel to use when using the Small Strain kinematic formulation.");
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)
106 if constexpr (!is_ad)
110 for (
const auto i : make_range(this->
_ndisp))
112 _disp_var[i] = this->coupled(
"displacements", i);
113 _vars[i] = this->getVar(
"displacements", i);
118 _Jacobian_mult = &this->
template getMaterialPropertyByName<RankFourTensor>(
119 this->
_base_name + parameters.
get<MaterialPropertyName>(
"tangent"));
121 this->
_base_name + parameters.
get<MaterialPropertyName>(
"tangent"));
124 const auto & tangent_name = parameters.
get<MaterialPropertyName>(
"tangent");
125 const auto & tangent_definition = parameters.
get<
MooseEnum>(
"tangent_definition");
126 if (tangent_definition ==
"auto")
128 if (tangent_name ==
"Jacobian_mult")
130 else if (tangent_name ==
"pk1_jacobian")
133 this->paramError(
"tangent_definition",
134 "Cannot infer the mathematical definition of custom tangent property '",
136 "'. Set 'tangent_definition' to 'stress_wrt_strain' or "
137 "'pk1_wrt_deformation_gradient'.");
151 const RealVectorValue true_normal(this->trueNormal());
152 const Real true_normal_dot_surrogate_normal = true_normal * this->_normals[this->_qp];
155 residual *= true_normal_dot_surrogate_normal;
157 if (_directional_correction)
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;
167 residual -= this->_test[this->_i][this->_qp] * (stress * normal_tangent);
171 residual += this->_test_neighbor[this->_i][this->_qp] * (stress_neighbor * normal_tangent);
195 const auto jacsd = (*_dtraction_djump_global)[this->_qp](this->_component, component_j);
203 jac *= _test[_i][_qp] * _vars[component_j]->phiFace()[_j][_qp];
206 jac *= -_test[_i][_qp] * _vars[component_j]->phiFaceNeighbor()[_j][_qp];
209 jac *= -_test_neighbor[_i][_qp] * _vars[component_j]->phiFace()[_j][_qp];
212 jac *= _test_neighbor[_i][_qp] * _vars[component_j]->phiFaceNeighbor()[_j][_qp];
218 const auto d = surrogateDistance();
219 const auto true_normal = RealVectorValue(trueNormal());
220 const auto true_normal_dot_surrogate_normal = true_normal * _normals[_qp];
226 jac *= _test[_i][_qp] * (_vars[component_j]->phiFace()[_j][_qp] +
227 _vars[component_j]->gradPhiFace()[_j][_qp] *
d);
230 jac *= -_test[_i][_qp] * (_vars[component_j]->phiFaceNeighbor()[_j][_qp] +
231 _vars[component_j]->gradPhiFaceNeighbor()[_j][_qp] *
d);
234 jac *= -_test_neighbor[_i][_qp] * (_vars[component_j]->phiFace()[_j][_qp] +
235 _vars[component_j]->gradPhiFace()[_j][_qp] *
d);
238 jac *= _test_neighbor[_i][_qp] * (_vars[component_j]->phiFaceNeighbor()[_j][_qp] +
239 _vars[component_j]->gradPhiFaceNeighbor()[_j][_qp] *
d);
243 jac *= true_normal_dot_surrogate_normal;
253 const auto true_normal =
254 _shifted ? RealVectorValue(trueNormal()) : RealVectorValue(_normals[_qp]);
257 const auto grad_phi = trial_on_element ? _grad_phi[_j][_qp] : _grad_phi_neighbor[_j][_qp];
259 const auto nt_tangent = _normals[_qp] - (true_normal * _normals[_qp]) * true_normal;
263 : _test_neighbor[_i][_qp];
266 ? (*_Jacobian_mult)[_qp]
267 : (*_Jacobian_mult_neighbor)[_qp];
270 r4t, ivar, jvar, nt_tangent * test , grad_phi );
272 const Real n0 = nt_tangent(0);
273 const Real n1 = nt_tangent(1);
274 const Real n2 = nt_tangent(2);
276 const Real gp0 = grad_phi(0);
277 const Real gp1 = grad_phi(1);
278 const Real gp2 = grad_phi(2);
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) *
291 Real jacobian = _tangent_is_dpk1_df ? origin_part : (origin_part + symmetric_part) * 0.5;
293 if (_volumetric_locking_correction)
295 const auto grad_op = gradOpForCoord(_coord_sys,
298 trial_on_element ? _phi[_j][_qp] : _phi_neighbor[_j][_qp],
301 [
this, k, trial_on_element](
unsigned int qp)
303 return gradOpForCoord(_coord_sys,
305 trial_on_element ? _grad_phi[_j][qp] : _grad_phi_neighbor[_j][qp],
306 trial_on_element ? _phi[_j][qp] : _phi_neighbor[_j][qp],
311 const Real volumetric_increment = (avg_grad_op.trace() - grad_op.
trace()) / 3.0;
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;
332 Real jacobian = computeDResidualDDisplacement(this->_component, type);
334 if (_shifted && _directional_correction)
338 jacobian -= calculateDirectionalCorrectionJacobian(_component, _component, type);
341 jacobian += calculateDirectionalCorrectionJacobian(_component, _component, type);
364 if (this->getJvarMap()[jvar] < 0)
368 for (
const auto coupled_component : make_range(this->_ndisp))
369 if (jvar == _disp_var[coupled_component])
370 jacobian = computeDResidualDDisplacement(coupled_component, type);
372 if (_shifted && _directional_correction)
373 for (
const auto coupled_component : make_range(_ndisp))
374 if (jvar == _disp_var[coupled_component])
378 jacobian -= calculateDirectionalCorrectionJacobian(_component, coupled_component, type);
381 jacobian += calculateDirectionalCorrectionJacobian(_component, coupled_component, type);
void mooseError(Args &&... args)
Moose::GenericType< Real, is_ad > GenericReal
registerMooseObject("ShiftedBoundaryMethodApp", SCZMInterfaceKernelSmallStrain)
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
static InputParameters validParams()
GenericReal< is_ad > computeQpResidual(Moose::DGResidualType type) override
SCZMInterfaceKernelSmallStrainTempl(const InputParameters ¶meters)
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
std::vector< MooseVariable * > _vars
Real computeQpOffDiagJacobian(Moose::DGJacobianType type, unsigned int jvar) override
std::string grad(const std::string &var)
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)