https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
19
22
23template <bool is_ad>
26{
27 return MooseEnum("Geometry Topology", "Geometry");
28}
29
30template <bool is_ad>
33{
34 return MooseEnum("KI KII KIII T", "KI");
35}
36
37template <bool is_ad>
40{
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).");
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
115template <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;
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)
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
243template <bool is_ad>
244void
246{
247 _treat_as_2d = _crack_front_definition->treatAs2D();
248 _using_mesh_cutter = _crack_front_definition->usingMeshCutter();
249}
250
251template <bool is_ad>
252void
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
274template <bool is_ad>
275Real
276InteractionIntegralTempl<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
514template <bool is_ad>
515void
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
570template <bool is_ad>
571void
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
599template <bool is_ad>
600void
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
609template <bool is_ad>
610void
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
697template <bool is_ad>
698void
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
728template class InteractionIntegralTempl<true>;
const std::vector< double > y
registerMooseObject("SolidMechanicsApp", InteractionIntegral)
void mooseError(Args &&... args)
Moose::GenericType< RankThreeTensor, is_ad > GenericRankThreeTensor
unsigned int dim
void ErrorVector unsigned int
const VariableGradient & _grad_zero
virtual const VariableGradient & coupledGradient(const std::string &var_name, unsigned int comp=0) const
Class used in fracture integrals to define geometric characteristics of the crack front.
static InputParameters validParams()
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
void addRequiredParam(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)
This vectorpostprocessor computes the Interaction Integral, which is used to compute various fracture...
VectorPostprocessorValue & _interaction_integral
Real _kappa
Kappa Lame constant.
const VariableGradient * _additional_eigenstrain_gradient_12
Gradient used to add contribution to the interaction integral (YZ)
virtual void initialize() override
const VariableGradient * _additional_eigenstrain_gradient_22
Gradient used to add contribution to the interaction integral (ZZ)
const GenericMaterialProperty< RankTwoTensor, is_ad > *const _total_deigenstrain_dT
Derivative of the total eigenstrain with respect to temperature.
const MaterialProperty< Real > * _functionally_graded_youngs_modulus_crack_dir_gradient
Spatial derivative of the youngs modulus in the crack direction.
virtual void threadJoin(const UserObject &y) override
const MaterialProperty< Real > * _functionally_graded_youngs_modulus
Spatial elasticity modulus variable for FGM.
Real _poissons_ratio
Poisson's ratio of the material.
const VariableGradient * _additional_eigenstrain_gradient_01
Gradient used to add contribution to the interaction integral (XY)
virtual void finalize() override
QMethod
Enum used to select the method used to compute the q function used in the fracture integrals.
Real _youngs_modulus
Young's modulus of the material.
bool _has_additional_eigenstrain
Whether the user chooses to add other eigenstrain influence (e.g. irradiation-induced)
std::size_t _ndisp
Number of displacement components.
static MooseEnum qFunctionType()
Get the MooseEnum defining the options for how the q function is defined.
static MooseEnum sifModeType()
Get the MooseEnum defining the options for the integral to be computed.
virtual void execute() override
InteractionIntegralTempl(const InputParameters &parameters)
PositionType
Enum used to define how the distance along the crack front is measured (angle or distance)
Real _shear_modulus
Shear modulus.
void computeTFields(RankTwoTensor &aux_stress, RankTwoTensor &grad_disp)
Compute the auxiliary fields, including the auxiliary stress and the gradient of the auxiliary displa...
SifMethod
Enum used to select the type of integral to be performed.
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 displa...
const VariableGradient * _additional_eigenstrain_gradient_11
Gradient used to add contribution to the interaction integral (YY)
static InputParameters validParams()
const MaterialProperty< RealVectorValue > * _body_force
std::vector< const VariableGradient * > _grad_disp
Gradient of displacements.
virtual void initialSetup() override
const GenericMaterialProperty< RankThreeTensor, is_ad > * _eigenstrain_gradient
Pointers to optionally-used eigenstrain gradient and body force.
const bool _has_temp
Whether the temperature variable is coupled.
const VariableGradient * _additional_eigenstrain_gradient_02
Gradient used to add contribution to the interaction integral (XZ)
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...
const VariableGradient * _additional_eigenstrain_gradient_00
Gradient used to add contribution to the interaction integral (XX)
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
void mooseInfo(Args &&... args) const
bool isParamValid(const std::string &name) const
std::string getRawNames() const
virtual unsigned int dimension() const
RankFourTensorTempl< T > invSymm() const
void fillSymmetricIsotropicEandNu(const T &E, const T &nu)
static RankTwoTensorTempl initializeFromRows(const libMesh::TypeVector< T > &row0, const libMesh::TypeVector< T > &row1, const libMesh::TypeVector< T > &row2)
RankThreeTensorTempl< T > mixedProductJkI(const libMesh::VectorValue< T > &b) const
T doubleContraction(const RankTwoTensorTempl< T > &a) const
auto raw_value(const Eigen::Map< T > &in)
const Real pi