https://mooseframework.inl.gov
InteractionIntegral.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 "InteractionIntegral.h"
11 #include "MooseMesh.h"
12 #include "RankTwoTensor.h"
13 #include "Conversion.h"
14 #include "libmesh/string_to_enum.h"
15 #include "libmesh/quadrature.h"
17 #include "libmesh/utility.h"
18 #include "CrackFrontDefinition.h"
19 
20 registerMooseObject("SolidMechanicsApp", InteractionIntegral);
21 registerMooseObject("SolidMechanicsApp", ADInteractionIntegral);
22 
23 template <bool is_ad>
26 {
27  return MooseEnum("Geometry Topology", "Geometry");
28 }
29 
30 template <bool is_ad>
33 {
34  return MooseEnum("KI KII KIII T", "KI");
35 }
36 
37 template <bool is_ad>
40 {
42  params.addRequiredCoupledVar(
43  "displacements",
44  "The displacements appropriate for the simulation geometry and coordinate system");
45  params.addCoupledVar("temperature",
46  "The temperature (optional). Must be provided to correctly compute "
47  "stress intensity factors in models with thermal strain gradients.");
48  params.addParam<MaterialPropertyName>(
49  "functionally_graded_youngs_modulus",
50  "Spatially varying elasticity modulus variable. This input is required when "
51  "using the functionally graded material capability.");
52  params.addParam<MaterialPropertyName>(
53  "functionally_graded_youngs_modulus_crack_dir_gradient",
54  "Gradient of the spatially varying Young's modulus provided in "
55  "'functionally_graded_youngs_modulus' in the direction of crack extension.");
56  params.addRequiredParam<UserObjectName>("crack_front_definition",
57  "The CrackFrontDefinition user object name");
58  MooseEnum position_type("Angle Distance", "Distance");
59  params.addParam<MooseEnum>(
60  "position_type",
61  position_type,
62  "The method used to calculate position along crack front. Options are: " +
63  position_type.getRawNames());
64  params.addRequiredParam<Real>(
65  "K_factor", "Conversion factor between interaction integral and stress intensity factor K");
66  params.addParam<unsigned int>("symmetry_plane",
67  "Account for a symmetry plane passing through "
68  "the plane of the crack, normal to the specified "
69  "axis (0=x, 1=y, 2=z)");
70  params.addRequiredParam<Real>("poissons_ratio", "Poisson's ratio for the material.");
71  params.addRequiredParam<Real>("youngs_modulus", "Young's modulus of the material.");
72  params.set<bool>("use_displaced_mesh") = false;
73  params.addRequiredParam<unsigned int>("ring_index", "Ring ID");
74  params.addParam<MooseEnum>("q_function_type",
76  "The method used to define the integration domain. Options are: " +
79  "sif_mode",
81  "Stress intensity factor to calculate. Choices are: " +
83  params.addParam<MaterialPropertyName>("eigenstrain_gradient",
84  "Material defining gradient of eigenstrain tensor");
85  params.addParam<MaterialPropertyName>("body_force", "Material defining body force");
86  params.addCoupledVar("additional_eigenstrain_00",
87  "Optional additional eigenstrain variable that will be accounted for in the "
88  "interaction integral (component 00 or XX).");
89  params.addCoupledVar("additional_eigenstrain_01",
90  "Optional additional eigenstrain variable that will be accounted for in the "
91  "interaction integral (component 01 or XY).");
92  params.addCoupledVar("additional_eigenstrain_11",
93  "Optional additional eigenstrain variable that will be accounted for in the "
94  "interaction integral (component 11 or YY).");
95  params.addCoupledVar("additional_eigenstrain_22",
96  "Optional additional eigenstrain variable that will be accounted for in the "
97  "interaction integral (component 22 or ZZ).");
98  params.addCoupledVar("additional_eigenstrain_02",
99  "Optional additional eigenstrain variable that will be accounted for in the "
100  "interaction integral (component 02 or XZ).");
101  params.addCoupledVar("additional_eigenstrain_12",
102  "Optional additional eigenstrain variable that will be accounted for in the "
103  "interaction integral (component 12 or XZ).");
104  params.addParamNamesToGroup(
105  "additional_eigenstrain_00 additional_eigenstrain_01 additional_eigenstrain_11 "
106  "additional_eigenstrain_22 additional_eigenstrain_02 additional_eigenstrain_12",
107  "Generic eigenstrains for the computation of the interaction integral.");
108  params.addClassDescription(
109  "Computes the interaction integral, which is used to compute various "
110  "fracture mechanics parameters at a crack tip, including KI, KII, KIII, "
111  "and the T stress.");
112  return params;
113 }
114 
115 template <bool is_ad>
117  : ElementVectorPostprocessor(parameters),
118  _ndisp(coupledComponents("displacements")),
119  _crack_front_definition(&getUserObject<CrackFrontDefinition>("crack_front_definition")),
120  _treat_as_2d(false),
121  _stress(getGenericMaterialPropertyByName<RankTwoTensor, is_ad>("stress")),
122  _strain(getGenericMaterialPropertyByName<RankTwoTensor, is_ad>("elastic_strain")),
123  _fe_vars(getCoupledMooseVars()),
124  _fe_type(_fe_vars[0]->feType()),
125  _disp(coupledValues("displacements")),
126  _grad_disp(3),
127  _has_temp(isCoupled("temperature")),
128  _grad_temp(_has_temp ? coupledGradient("temperature") : _grad_zero),
129  _functionally_graded_youngs_modulus_crack_dir_gradient(
130  isParamSetByUser("functionally_graded_youngs_modulus_crack_dir_gradient")
131  ? &getMaterialProperty<Real>("functionally_graded_youngs_modulus_crack_dir_gradient")
132  : nullptr),
133  _functionally_graded_youngs_modulus(
134  isParamSetByUser("functionally_graded_youngs_modulus")
135  ? &getMaterialProperty<Real>("functionally_graded_youngs_modulus")
136  : nullptr),
137  _K_factor(getParam<Real>("K_factor")),
138  _has_symmetry_plane(isParamValid("symmetry_plane")),
139  _poissons_ratio(getParam<Real>("poissons_ratio")),
140  _youngs_modulus(getParam<Real>("youngs_modulus")),
141  _fgm_crack(isParamSetByUser("functionally_graded_youngs_modulus_crack_dir_gradient") &&
142  isParamSetByUser("functionally_graded_youngs_modulus")),
143  _ring_index(getParam<unsigned int>("ring_index")),
144  _total_deigenstrain_dT(
145  hasMaterialProperty<RankTwoTensor>("total_deigenstrain_dT")
146  ? &getGenericMaterialProperty<RankTwoTensor, is_ad>("total_deigenstrain_dT")
147  : nullptr),
148  _has_additional_eigenstrain(false),
149  _additional_eigenstrain_gradient_00(isCoupled("additional_eigenstrain_00")
150  ? &coupledGradient("additional_eigenstrain_00")
151  : nullptr),
152  _additional_eigenstrain_gradient_01(isCoupled("additional_eigenstrain_01")
153  ? &coupledGradient("additional_eigenstrain_01")
154  : nullptr),
155  _additional_eigenstrain_gradient_11(isCoupled("additional_eigenstrain_11")
156  ? &coupledGradient("additional_eigenstrain_11")
157  : nullptr),
158  _additional_eigenstrain_gradient_22(isCoupled("additional_eigenstrain_22")
159  ? &coupledGradient("additional_eigenstrain_22")
160  : nullptr),
161  _additional_eigenstrain_gradient_02(isCoupled("additional_eigenstrain_02")
162  ? &coupledGradient("additional_eigenstrain_02")
163  : nullptr),
164  _additional_eigenstrain_gradient_12(isCoupled("additional_eigenstrain_12")
165  ? &coupledGradient("additional_eigenstrain_12")
166  : nullptr),
167  _q_function_type(getParam<MooseEnum>("q_function_type").template getEnum<QMethod>()),
168  _position_type(getParam<MooseEnum>("position_type").template getEnum<PositionType>()),
169  _sif_mode(getParam<MooseEnum>("sif_mode").template getEnum<SifMethod>()),
170  _x(declareVector("x")),
171  _y(declareVector("y")),
172  _z(declareVector("z")),
173  _position(declareVector("id")),
174  _interaction_integral(declareVector("II_" + Moose::stringify(getParam<MooseEnum>("sif_mode")) +
175  "_" + Moose::stringify(_ring_index))),
176  _eigenstrain_gradient(nullptr),
177  _body_force(nullptr)
178 {
180  mooseError("InteractionIntegral Error: To include thermal strain term in interaction integral, "
181  "must both couple temperature in DomainIntegral block and compute "
182  "total_deigenstrain_dT using ThermalFractureIntegral material model.");
183 
188  paramError("functionally_graded_youngs_modulus_crack_dir_gradient",
189  "You have selected to compute the interaction integral for a crack in FGM. That "
190  "selection requires the user to provide a spatially varying elasticity modulus "
191  "that "
192  "defines the transition of material properties (i.e. "
193  "'functionally_graded_youngs_modulus') and its "
194  "spatial derivative in the crack direction (i.e. "
195  "'functionally_graded_youngs_modulus_crack_dir_gradient').");
196 
197  // plane strain
198  _kappa = 3.0 - 4.0 * _poissons_ratio;
199  _shear_modulus = _youngs_modulus / (2.0 * (1.0 + _poissons_ratio));
200 
201  // Checking for consistency between mesh size and length of the provided displacements vector
202  if (_ndisp != _mesh.dimension())
203  paramError("displacements",
204  "InteractionIntegral Error: number of variables supplied in 'displacements' must "
205  "match the mesh dimension.");
206 
207  // fetch gradients of coupled variables
208  for (std::size_t i = 0; i < _ndisp; ++i)
209  _grad_disp[i] = &coupledGradient("displacements", i);
210 
211  // set unused dimensions to zero
212  for (std::size_t i = _ndisp; i < 3; ++i)
213  _grad_disp[i] = &_grad_zero;
214 
215  if (isParamValid("eigenstrain_gradient"))
216  {
218  &getGenericMaterialProperty<RankThreeTensor, is_ad>("eigenstrain_gradient");
220  paramError("eigenstrain_gradient",
221  "eigenstrain_gradient cannot be specified for materials that provide the "
222  "total_deigenstrain_dT material property");
223  }
224  if (isParamValid("body_force"))
225  _body_force = &getMaterialProperty<RealVectorValue>("body_force");
226 
230 
234  paramError("additional_eigenstrain_gradient_12",
235  "If additional eigenstrains are provided for the computation of the interaction "
236  "integral in three dimensions, make sure the six components are provided.");
237 
239  mooseInfo("A generic eigenstrain provided by the user will be considered in the interaction "
240  "integral (via domain integral action).");
241 }
242 
243 template <bool is_ad>
244 void
246 {
247  _treat_as_2d = _crack_front_definition->treatAs2D();
248  _using_mesh_cutter = _crack_front_definition->usingMeshCutter();
249 }
250 
251 template <bool is_ad>
252 void
254 {
255  std::size_t num_pts;
256  if (_treat_as_2d && _using_mesh_cutter == false)
257  num_pts = 1;
258  else
259  num_pts = _crack_front_definition->getNumCrackFrontPoints();
260 
261  _x.assign(num_pts, 0.0);
262  _y.assign(num_pts, 0.0);
263  _z.assign(num_pts, 0.0);
264  _position.assign(num_pts, 0.0);
265  _interaction_integral.assign(num_pts, 0.0);
266 
267  for (const auto * fe_var : _fe_vars)
268  {
269  if (fe_var->feType() != _fe_type)
270  mooseError("All coupled displacements must have the same type");
271  }
272 }
273 
274 template <bool is_ad>
275 Real
276 InteractionIntegralTempl<is_ad>::computeQpIntegral(const std::size_t crack_front_point_index,
277  const Real scalar_q,
278  const RealVectorValue & grad_of_scalar_q)
279 {
280  // If q is zero, then dq is also zero, so all terms in the interaction integral would
281  // return zero. As such, let us avoid unnecessary, frequent computations
282  if (scalar_q < TOLERANCE * TOLERANCE * TOLERANCE)
283  return 0.0;
284 
285  // In the crack front coordinate system, the crack direction is (1,0,0)
286  RealVectorValue crack_direction(1.0, 0.0, 0.0);
287 
288  // Calculate (r,theta) position of qp relative to crack front
289  _crack_front_definition->calculateRThetaToCrackFront(
290  _q_point[_qp], crack_front_point_index, _r, _theta);
291 
292  RankTwoTensor aux_stress;
293  RankTwoTensor aux_du;
294  RankTwoTensor aux_strain;
295  RankTwoTensor aux_disp;
296 
297  if (_sif_mode == SifMethod::KI || _sif_mode == SifMethod::KII || _sif_mode == SifMethod::KIII)
298  computeAuxFields(aux_stress, aux_du, aux_strain, aux_disp);
299  else if (_sif_mode == SifMethod::T)
300  computeTFields(aux_stress, aux_du);
301 
302  auto grad_disp = RankTwoTensor::initializeFromRows(
303  (*_grad_disp[0])[_qp], (*_grad_disp[1])[_qp], (*_grad_disp[2])[_qp]);
304 
305  // Rotate stress, strain, displacement and temperature to crack front coordinate system
306  RealVectorValue grad_q_cf =
307  _crack_front_definition->rotateToCrackFrontCoords(grad_of_scalar_q, crack_front_point_index);
308  RankTwoTensor grad_disp_cf =
309  _crack_front_definition->rotateToCrackFrontCoords(grad_disp, crack_front_point_index);
310  RankTwoTensor stress_cf = _crack_front_definition->rotateToCrackFrontCoords(
311  MetaPhysicL::raw_value((_stress)[_qp]), crack_front_point_index);
312  RankTwoTensor strain_cf = _crack_front_definition->rotateToCrackFrontCoords(
313  MetaPhysicL::raw_value((_strain)[_qp]), crack_front_point_index);
314  RealVectorValue grad_temp_cf =
315  _crack_front_definition->rotateToCrackFrontCoords(_grad_temp[_qp], crack_front_point_index);
316 
317  if (getBlockCoordSystem() == Moose::COORD_RZ)
318  strain_cf(2, 2) = 0.0;
319 
320  RankTwoTensor dq;
321  dq(0, 0) = crack_direction(0) * grad_q_cf(0);
322  dq(0, 1) = crack_direction(0) * grad_q_cf(1);
323  dq(0, 2) = crack_direction(0) * grad_q_cf(2);
324 
325  // Calculate interaction integral terms
326 
327  // Term1 = stress * x1-derivative of aux disp * dq
328  RankTwoTensor tmp1 = dq * stress_cf;
329  Real term1 = aux_du.doubleContraction(tmp1);
330 
331  // Term2 = aux stress * x1-derivative of disp * dq
332  RankTwoTensor tmp2 = dq * aux_stress;
333  Real term2 = grad_disp_cf(0, 0) * tmp2(0, 0) + grad_disp_cf(1, 0) * tmp2(0, 1) +
334  grad_disp_cf(2, 0) * tmp2(0, 2);
335 
336  // Term3 = aux stress * strain * dq_x (= stress * aux strain * dq_x)
337  Real term3 = -dq(0, 0) * aux_stress.doubleContraction(strain_cf);
338 
339  // Term4 (thermal strain term) = q * aux_stress * alpha * dtheta_x
340  // - the term including the derivative of alpha is not implemented
341  Real term4 = 0.0;
342  if (_has_temp)
343  {
344  Real sigma_alpha =
345  aux_stress.doubleContraction(MetaPhysicL::raw_value((*_total_deigenstrain_dT)[_qp]));
346  term4 = scalar_q * sigma_alpha * grad_temp_cf(0);
347  }
348 
349  Real term4a = 0.0; // Gradient of arbitrary eigenstrain material contribution
350  if (_eigenstrain_gradient)
351  {
352  // Thermal strain gradient term in Nakamura and Parks, IJSS, 1992:
353  // alpha * dT/dx_k*aux_stress*scalar_q
354  // Generalization to the gradient of an arbitrary eigenstrain:
355  // d_eigenstrain/dx_k*aux_stress*scalar_q
356  const RealVectorValue & crack_dir =
357  _crack_front_definition->getCrackDirection(crack_front_point_index);
358  RankTwoTensor eigenstrain_grad_in_crack_dir =
359  crack_dir * MetaPhysicL::raw_value((*_eigenstrain_gradient)[_qp]);
360  term4a = scalar_q * aux_stress.doubleContraction(eigenstrain_grad_in_crack_dir);
361  }
362 
363  // Gradient of arbitrary eigenstrain variable contribution.
364  // Note that, unlike approaches 4 and 4a, approach 4b can integrate any type of eigenstrain, i.e.
365  // it does not have to be thermal or volumetric.
366  Real term4b = 0.0;
367  // Term4b (eigen strain term) = q * aux_stress * d{eigen_strain}_x
368  if (_has_additional_eigenstrain)
369  {
371  I_x(0, 0) = 1.0;
373  I_xy(0, 1) = 1.0;
374  I_xy(1, 0) = 1.0;
376  I_y(1, 1) = 1.0;
378  I_z(2, 2) = 1.0;
379 
380  const RealVectorValue & crack_dir =
381  _crack_front_definition->getCrackDirection(crack_front_point_index);
382 
383  const auto eigenstrain_gradient_x =
384  I_x.mixedProductJkI((*_additional_eigenstrain_gradient_00)[_qp]);
385  const auto eigenstrain_gradient_xy =
386  I_xy.mixedProductJkI((*_additional_eigenstrain_gradient_01)[_qp]);
387  const auto eigenstrain_gradient_y =
388  I_y.mixedProductJkI((*_additional_eigenstrain_gradient_11)[_qp]);
389 
390  GenericRankThreeTensor<is_ad> eigenstrain_gradient_z;
391  if (_additional_eigenstrain_gradient_22)
392  eigenstrain_gradient_z = I_z.mixedProductJkI((*_additional_eigenstrain_gradient_22)[_qp]);
393 
394  RankTwoTensor eigenstrain_grad_in_crack_dir =
395  crack_dir * (MetaPhysicL::raw_value(eigenstrain_gradient_x) +
396  MetaPhysicL::raw_value(eigenstrain_gradient_xy) +
397  MetaPhysicL::raw_value(eigenstrain_gradient_y) +
398  MetaPhysicL::raw_value(eigenstrain_gradient_z));
399 
400  GenericRankThreeTensor<is_ad> eigenstrain_gradient_xz;
401  GenericRankThreeTensor<is_ad> eigenstrain_gradient_yz;
402  // Add terms for three dimensions
403  if (_mesh.dimension() == 3)
404  {
405  // Add influence of xz and yz.
407  I_xz(0, 2) = I_xz(2, 0) = 1.0;
408  eigenstrain_gradient_xz = I_xz.mixedProductJkI((*_additional_eigenstrain_gradient_02)[_qp]);
410  I_yz(1, 2) = I_yz(2, 1) = 1.0;
411  eigenstrain_gradient_yz = I_yz.mixedProductJkI((*_additional_eigenstrain_gradient_12)[_qp]);
412 
413  eigenstrain_grad_in_crack_dir = crack_dir * (MetaPhysicL::raw_value(eigenstrain_gradient_xz) +
414  MetaPhysicL::raw_value(eigenstrain_gradient_yz) +
415  MetaPhysicL::raw_value(eigenstrain_gradient_x) +
416  MetaPhysicL::raw_value(eigenstrain_gradient_xy) +
417  MetaPhysicL::raw_value(eigenstrain_gradient_y) +
418  MetaPhysicL::raw_value(eigenstrain_gradient_z));
419  }
420 
421  term4b = scalar_q * aux_stress.doubleContraction(eigenstrain_grad_in_crack_dir);
422  }
423 
424  Real term5 = 0.0; // Body force
425  if (_body_force)
426  {
427  // Body force term in Nakamura and Parks, IJSS, 1992:
428  // b_i*aux_du*crack_dir*scalar_q
429  const RealVectorValue & crack_dir =
430  _crack_front_definition->getCrackDirection(crack_front_point_index);
431  term5 = -scalar_q * MetaPhysicL::raw_value((*_body_force)[_qp]) * aux_du * crack_dir;
432  }
433 
434  Real term6 = 0.0;
435  if (_fgm_crack && scalar_q != 0)
436  {
437  // See Equation 49 of J.-H. Kim and G. H. Paulino. Consistent formulations of the interaction
438  // integral method for fracture of functionally graded materials. Journal of Applied Mechanics,
439  // 72(3) 351-364 2004.
440 
441  // Term 6_1 = Cijkl,j(x) epsilon_{kl}^{aux} disp_{i,1}
442  RankTwoTensor cijklj_epsilonkl_aux; // Temporary second order tensor.
443  RankFourTensor cijklj;
444  cijklj.fillSymmetricIsotropicEandNu(1.0, _poissons_ratio);
445  cijklj *= (*_functionally_graded_youngs_modulus_crack_dir_gradient)[_qp];
446  cijklj_epsilonkl_aux = cijklj * aux_strain;
447 
448  const Real term6_a = grad_disp_cf(0, 0) * cijklj_epsilonkl_aux(0, 0) +
449  grad_disp_cf(1, 0) * cijklj_epsilonkl_aux(0, 1) +
450  grad_disp_cf(2, 0) * cijklj_epsilonkl_aux(0, 2);
451 
452  // Term 6_2 = -Cijkl,1(x) epsilon_{kl} epsilon_{ij}^{aux}
453  RankTwoTensor cijkl1_epsilonkl;
454  cijkl1_epsilonkl = -cijklj * strain_cf;
455  const Real term6_b = cijkl1_epsilonkl.doubleContraction(aux_strain);
456 
457  term6 = (term6_a + term6_b) * scalar_q;
458  }
459 
460  // Add terms for possibly RZ (axisymmetric problem).
461  // See Nahta and Moran, 1993, Domain integrals for axisymmetric interface crack problems, 30(15)
462  // Note: Sign problem in Eq. (26). Also Kolosov constant is wrong in Eq. (13)
463  Real term7 = 0.0;
464  if (getBlockCoordSystem() == Moose::COORD_RZ)
465  {
466  const Real u_r = (*_disp[0])[_qp];
467  const Real radius_qp = _q_point[_qp](0);
468 
469  const Real term7a =
470  (u_r / radius_qp * aux_stress(2, 2) + aux_disp(0, 0) / radius_qp * stress_cf(2, 2) -
471  aux_stress.doubleContraction(strain_cf)) /
472  radius_qp;
473 
474  // term7b1: sigma_aux_ralpha * u_alpha,r
475  const Real term7b1 = aux_stress(0, 0) * grad_disp_cf(0, 0) +
476  aux_stress(0, 1) * grad_disp_cf(1, 0) +
477  aux_stress(0, 2) * grad_disp_cf(2, 0);
478 
479  const Real term7b = 1.0 / radius_qp *
480  (term7b1 - aux_stress(2, 2) * grad_disp_cf(0, 0) +
481  stress_cf(2, 2) * (aux_du(0, 0) - aux_disp(0, 0) / radius_qp));
482 
483  term7 = (term7a + term7b) * scalar_q;
484  }
485 
486  Real q_avg_seg = 1.0;
487  if (!_crack_front_definition->treatAs2D())
488  {
489  q_avg_seg =
490  (_crack_front_definition->getCrackFrontForwardSegmentLength(crack_front_point_index) +
491  _crack_front_definition->getCrackFrontBackwardSegmentLength(crack_front_point_index)) /
492  2.0;
493  }
494 
495  Real eq = term1 + term2 + term3 + term4 + term4a + term4b + term5 + term6 + term7;
496 
497  if (getBlockCoordSystem() == Moose::COORD_RZ)
498  {
499  const Real radius_qp = _q_point[_qp](0);
500  eq *= radius_qp;
501 
502  std::size_t num_crack_front_points = _crack_front_definition->getNumCrackFrontPoints();
503  if (num_crack_front_points != 1)
504  mooseError("Crack front has more than one point, but this is a 2D-RZ problem. Please revise "
505  "your input file.");
506 
507  const Point * crack_front_point = _crack_front_definition->getCrackFrontPoint(0);
508  eq = eq / (*crack_front_point)(0);
509  }
510 
511  return eq / q_avg_seg;
512 }
513 
514 template <bool is_ad>
515 void
517 {
518  // calculate phi and dphi for this element
519  const std::size_t dim = _current_elem->dim();
520  std::unique_ptr<FEBase> fe(FEBase::build(dim, _fe_type));
521  fe->attach_quadrature_rule(const_cast<QBase *>(_qrule));
522  _phi_curr_elem = &fe->get_phi();
523  _dphi_curr_elem = &fe->get_dphi();
524  fe->reinit(_current_elem);
525 
526  // calculate q for all nodes in this element
527  std::size_t ring_base = (_q_function_type == QMethod::Topology) ? 0 : 1;
528 
529  for (auto icfp = beginIndex(_interaction_integral); icfp < _interaction_integral.size(); icfp++)
530  {
531  _q_curr_elem.clear();
532  for (std::size_t i = 0; i < _current_elem->n_nodes(); ++i)
533  {
534  const Node * this_node = _current_elem->node_ptr(i);
535  Real q_this_node;
536 
537  if (_q_function_type == QMethod::Geometry)
538  q_this_node = _crack_front_definition->DomainIntegralQFunction(
539  icfp, _ring_index - ring_base, this_node);
540  else // QMethod::Topology
541  q_this_node = _crack_front_definition->DomainIntegralTopologicalQFunction(
542  icfp, _ring_index - ring_base, this_node);
543 
544  _q_curr_elem.push_back(q_this_node);
545  }
546 
547  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
548  {
549  Real scalar_q = 0.0;
550  RealVectorValue grad_of_scalar_q(0.0, 0.0, 0.0);
551 
552  for (std::size_t i = 0; i < _current_elem->n_nodes(); ++i)
553  {
554  scalar_q += (*_phi_curr_elem)[i][_qp] * _q_curr_elem[i];
555 
556  for (std::size_t j = 0; j < _current_elem->dim(); ++j)
557  grad_of_scalar_q(j) += (*_dphi_curr_elem)[i][_qp](j) * _q_curr_elem[i];
558  }
559 
560  if (getBlockCoordSystem() != Moose::COORD_RZ)
561  _interaction_integral[icfp] +=
562  _JxW[_qp] * _coord[_qp] * computeQpIntegral(icfp, scalar_q, grad_of_scalar_q);
563  else
564  _interaction_integral[icfp] +=
565  _JxW[_qp] * computeQpIntegral(icfp, scalar_q, grad_of_scalar_q);
566  }
567  }
568 }
569 
570 template <bool is_ad>
571 void
573 {
574  gatherSum(_interaction_integral);
575 
576  for (auto i = beginIndex(_interaction_integral); i < _interaction_integral.size(); ++i)
577  {
578  if (_has_symmetry_plane)
579  _interaction_integral[i] *= 2.0;
580 
581  const auto cfp = _crack_front_definition->getCrackFrontPoint(i);
582  _x[i] = (*cfp)(0);
583  _y[i] = (*cfp)(1);
584  _z[i] = (*cfp)(2);
585 
586  if (_position_type == PositionType::Angle)
587  _position[i] = _crack_front_definition->getAngleAlongFront(i);
588  else
589  _position[i] = _crack_front_definition->getDistanceAlongFront(i);
590 
591  if (_sif_mode == SifMethod::T && !_treat_as_2d)
592  _interaction_integral[i] +=
593  _poissons_ratio * _crack_front_definition->getCrackFrontTangentialStrain(i);
594 
595  _interaction_integral[i] *= _K_factor;
596  }
597 }
598 
599 template <bool is_ad>
600 void
602 {
603  const auto & uo = static_cast<const InteractionIntegralTempl<is_ad> &>(y);
604 
605  for (auto i = beginIndex(_interaction_integral); i < _interaction_integral.size(); ++i)
606  _interaction_integral[i] += uo._interaction_integral[i];
607 }
608 
609 template <bool is_ad>
610 void
612  RankTwoTensor & grad_disp,
613  RankTwoTensor & aux_strain,
614  RankTwoTensor & aux_disp)
615 {
616  RealVectorValue k(0.0);
617  if (_sif_mode == SifMethod::KI)
618  k(0) = 1.0;
619  else if (_sif_mode == SifMethod::KII)
620  k(1) = 1.0;
621  else if (_sif_mode == SifMethod::KIII)
622  k(2) = 1.0;
623 
624  Real t = _theta;
625  Real t2 = _theta / 2.0;
626  Real tt2 = 3.0 * _theta / 2.0;
627  Real st = std::sin(t);
628  Real ct = std::cos(t);
629  Real st2 = std::sin(t2);
630  Real ct2 = std::cos(t2);
631  Real stt2 = std::sin(tt2);
632  Real ctt2 = std::cos(tt2);
633  Real ct2sq = Utility::pow<2>(ct2);
634  Real st2sq = Utility::pow<2>(st2);
635  Real ct2cu = Utility::pow<3>(ct2);
636  Real sqrt2PiR = std::sqrt(2.0 * libMesh::pi * _r);
637 
638  // Calculate auxiliary stress tensor
639  aux_stress.zero();
640 
641  aux_stress(0, 0) =
642  1.0 / sqrt2PiR * (k(0) * ct2 * (1.0 - st2 * stt2) - k(1) * st2 * (2.0 + ct2 * ctt2));
643  aux_stress(1, 1) = 1.0 / sqrt2PiR * (k(0) * ct2 * (1.0 + st2 * stt2) + k(1) * st2 * ct2 * ctt2);
644  aux_stress(0, 1) = 1.0 / sqrt2PiR * (k(0) * ct2 * st2 * ctt2 + k(1) * ct2 * (1.0 - st2 * stt2));
645  aux_stress(0, 2) = -1.0 / sqrt2PiR * k(2) * st2;
646  aux_stress(1, 2) = 1.0 / sqrt2PiR * k(2) * ct2;
647  // plane stress
648  // Real s33 = 0;
649  // plane strain
650  aux_stress(2, 2) = _poissons_ratio * (aux_stress(0, 0) + aux_stress(1, 1));
651 
652  aux_stress(1, 0) = aux_stress(0, 1);
653  aux_stress(2, 0) = aux_stress(0, 2);
654  aux_stress(2, 1) = aux_stress(1, 2);
655 
656  // Calculate auxiliary strain tensor (only needed to FGM)
657  if (_fgm_crack)
658  {
659  aux_strain.zero();
660  RankFourTensor spatial_elasticity_tensor;
661  spatial_elasticity_tensor.fillSymmetricIsotropicEandNu(
662  (*_functionally_graded_youngs_modulus)[_qp], _poissons_ratio);
663  aux_strain = spatial_elasticity_tensor.invSymm() * aux_stress;
664  }
665 
666  // Calculate x1 derivative of auxiliary displacements
667  grad_disp.zero();
668  grad_disp(0, 0) = k(0) / (4.0 * _shear_modulus * sqrt2PiR) *
669  (ct * ct2 * _kappa + ct * ct2 - 2.0 * ct * ct2cu + st * st2 * _kappa +
670  st * st2 - 6.0 * st * st2 * ct2sq) +
671  k(1) / (4.0 * _shear_modulus * sqrt2PiR) *
672  (ct * st2 * _kappa + ct * st2 + 2.0 * ct * st2 * ct2sq - st * ct2 * _kappa +
673  3.0 * st * ct2 - 6.0 * st * ct2cu);
674 
675  grad_disp(0, 1) = k(0) / (4.0 * _shear_modulus * sqrt2PiR) *
676  (ct * st2 * _kappa + ct * st2 - 2.0 * ct * st2 * ct2sq - st * ct2 * _kappa -
677  5.0 * st * ct2 + 6.0 * st * ct2cu) +
678  k(1) / (4.0 * _shear_modulus * sqrt2PiR) *
679  (-ct * ct2 * _kappa + 3.0 * ct * ct2 - 2.0 * ct * ct2cu -
680  st * st2 * _kappa + 3.0 * st * st2 - 6.0 * st * st2 * ct2sq);
681 
682  grad_disp(0, 2) = k(2) / (_shear_modulus * sqrt2PiR) * (st2 * ct - ct2 * st);
683 
684  // Calculate aux displacement field (used in RZ calculations) - Warp3D manual
685  aux_disp.zero();
686  if (getBlockCoordSystem() == Moose::COORD_RZ)
687  {
688  const Real prefactor_rz = std::sqrt(_r / 2.0 / libMesh::pi) / 2.0 / _shear_modulus;
689  aux_disp(0, 0) = prefactor_rz * ((k(0) * ct2 * (_kappa - 1.0 + 2.0 * st2sq)) +
690  (k(1) * st2 * (_kappa + 1.0 + 2.0 * ct2sq)));
691  aux_disp(0, 1) = prefactor_rz * ((k(0) * st2 * (_kappa + 1.0 - 2.0 * ct2sq)) -
692  (k(1) * ct2 * (_kappa - 1.0 - 2.0 * st2sq)));
693  aux_disp(0, 2) = prefactor_rz * k(2) * 4.0 * st2;
694  }
695 }
696 
697 template <bool is_ad>
698 void
700  RankTwoTensor & grad_disp)
701 {
702 
703  Real t = _theta;
704  Real st = std::sin(t);
705  Real ct = std::cos(t);
706  Real stsq = Utility::pow<2>(st);
707  Real ctsq = Utility::pow<2>(ct);
708  Real ctcu = Utility::pow<3>(ct);
709  Real oneOverPiR = 1.0 / (libMesh::pi * _r);
710 
711  aux_stress.zero();
712  aux_stress(0, 0) = -oneOverPiR * ctcu;
713  aux_stress(0, 1) = -oneOverPiR * st * ctsq;
714  aux_stress(1, 0) = -oneOverPiR * st * ctsq;
715  aux_stress(1, 1) = -oneOverPiR * ct * stsq;
716  aux_stress(2, 2) = -oneOverPiR * _poissons_ratio * (ctcu + ct * stsq);
717 
718  grad_disp.zero();
719  grad_disp(0, 0) = oneOverPiR / (4.0 * _youngs_modulus) *
720  (ct * (4.0 * Utility::pow<2>(_poissons_ratio) - 3.0 + _poissons_ratio) -
721  std::cos(3.0 * t) * (1.0 + _poissons_ratio));
722  grad_disp(0, 1) = -oneOverPiR / (4.0 * _youngs_modulus) *
723  (st * (4.0 * Utility::pow<2>(_poissons_ratio) - 3.0 + _poissons_ratio) +
724  std::sin(3.0 * t) * (1.0 + _poissons_ratio));
725 }
726 
727 template class InteractionIntegralTempl<false>;
728 template class InteractionIntegralTempl<true>;
const VariableGradient * _additional_eigenstrain_gradient_02
Gradient used to add contribution to the interaction integral (XZ)
const GenericMaterialProperty< RankTwoTensor, is_ad > *const _total_deigenstrain_dT
Derivative of the total eigenstrain with respect to temperature.
bool _has_additional_eigenstrain
Whether the user chooses to add other eigenstrain influence (e.g. irradiation-induced) ...
const MaterialProperty< Real > * _functionally_graded_youngs_modulus
Spatial elasticity modulus variable for FGM.
const MaterialProperty< Real > * _functionally_graded_youngs_modulus_crack_dir_gradient
Spatial derivative of the youngs modulus in the crack direction.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void computeAuxFields(RankTwoTensor &aux_stress, RankTwoTensor &grad_disp, RankTwoTensor &aux_strain, RankTwoTensor &aux_disp)
Compute the auxiliary fields, including the auxiliary stress and the gradient of the auxiliary disp...
const VariableGradient & _grad_zero
void mooseError(Args &&... args)
virtual void initialize() override
unsigned int dim
void mooseInfo(Args &&... args) const
Real _kappa
Kappa Lame constant.
std::vector< const VariableGradient * > _grad_disp
Gradient of displacements.
T & set(const std::string &name, bool quiet_mode=false)
const VariableGradient * _additional_eigenstrain_gradient_01
Gradient used to add contribution to the interaction integral (XY)
auto raw_value(const Eigen::Map< T > &in)
Real _poissons_ratio
Poisson&#39;s ratio of the material.
const VariableGradient * _additional_eigenstrain_gradient_11
Gradient used to add contribution to the interaction integral (YY)
const std::vector< double > y
virtual void execute() override
std::string getRawNames() const
virtual const VariableGradient & coupledGradient(const std::string &var_name, unsigned int comp=0) const
void addRequiredParam(const std::string &name, const std::string &doc_string)
static InputParameters validParams()
bool isParamValid(const std::string &name) const
static RankTwoTensorTempl initializeFromRows(const libMesh::TypeVector< Real > &row0, const libMesh::TypeVector< Real > &row1, const libMesh::TypeVector< Real > &row2)
QMethod
Enum used to select the method used to compute the q function used in the fracture integrals...
Class used in fracture integrals to define geometric characteristics of the crack front...
Real computeQpIntegral(const std::size_t crack_front_point_index, const Real scalar_q, const RealVectorValue &grad_of_scalar_q)
Compute the contribution of a specific quadrature point to a fracture integral for a point on the cra...
static MooseEnum qFunctionType()
Get the MooseEnum defining the options for how the q function is defined.
virtual unsigned int dimension() const
const MaterialProperty< RealVectorValue > * _body_force
void fillSymmetricIsotropicEandNu(const T &E, const T &nu)
virtual void finalize() override
Real doubleContraction(const RankTwoTensorTempl< Real > &a) const
void paramError(const std::string &param, Args... args) const
This vectorpostprocessor computes the Interaction Integral, which is used to compute various fracture...
registerMooseObject("SolidMechanicsApp", InteractionIntegral)
std::string stringify(const T &t)
InteractionIntegralTempl(const InputParameters &parameters)
void addCoupledVar(const std::string &name, const std::string &doc_string)
const bool _has_temp
Whether the temperature variable is coupled.
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
static MooseEnum sifModeType()
Get the MooseEnum defining the options for the integral to be computed.
const VariableGradient * _additional_eigenstrain_gradient_12
Gradient used to add contribution to the interaction integral (YZ)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void initialSetup() override
RankThreeTensorTempl< Real > mixedProductJkI(const libMesh::VectorValue< Real > &b) const
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
SifMethod
Enum used to select the type of integral to be performed.
Moose::GenericType< RankThreeTensor, is_ad > GenericRankThreeTensor
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
static InputParameters validParams()
const GenericMaterialProperty< RankThreeTensor, is_ad > * _eigenstrain_gradient
Pointers to optionally-used eigenstrain gradient and body force.
RankFourTensorTempl< T > invSymm() const
void computeTFields(RankTwoTensor &aux_stress, RankTwoTensor &grad_disp)
Compute the auxiliary fields, including the auxiliary stress and the gradient of the auxiliary displa...
static const std::string k
Definition: NS.h:130
Real _shear_modulus
Shear modulus.
void ErrorVector unsigned int
virtual void threadJoin(const UserObject &y) override
std::size_t _ndisp
Number of displacement components.
const VariableGradient * _additional_eigenstrain_gradient_22
Gradient used to add contribution to the interaction integral (ZZ)
PositionType
Enum used to define how the distance along the crack front is measured (angle or distance) ...
VectorPostprocessorValue & _interaction_integral
Real _youngs_modulus
Young&#39;s modulus of the material.
const Real pi
const VariableGradient * _additional_eigenstrain_gradient_00
Gradient used to add contribution to the interaction integral (XX)
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)