Line data Source code
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 "MeshCut2DFractureUserObject.h"
11 :
12 : #include "XFEMFuncs.h"
13 : #include "MooseError.h"
14 : #include "MooseMesh.h"
15 : #include "libmesh/edge_edge2.h"
16 : #include "libmesh/serial_mesh.h"
17 : #include "libmesh/mesh_tools.h"
18 : #include "algorithm"
19 :
20 : #include "CrackFrontDefinition.h"
21 :
22 : registerMooseObject("XFEMApp", MeshCut2DFractureUserObject);
23 :
24 : InputParameters
25 83 : MeshCut2DFractureUserObject::validParams()
26 : {
27 83 : InputParameters params = MeshCut2DUserObjectBase::validParams();
28 83 : params.addClassDescription("XFEM mesh cutter for 2D models that defines cuts with a"
29 : "mesh and uses fracture integrals to determine growth");
30 166 : params.addRequiredParam<Real>("growth_increment",
31 : "Length to grow crack if k>k_critical or stress>stress_threshold");
32 166 : params.addParam<Real>("k_critical", "Critical fracture toughness.");
33 166 : params.addParam<Real>("stress_threshold", "Stress threshold for growing crack");
34 166 : params.addParam<VectorPostprocessorName>(
35 : "ki_vectorpostprocessor", "II_KI_1", "The name of the vectorpostprocessor that contains KI");
36 166 : params.addParam<VectorPostprocessorName>("kii_vectorpostprocessor",
37 : "II_KII_1",
38 : "The name of the vectorpostprocessor that contains KII");
39 166 : params.addParam<VectorPostprocessorName>(
40 : "stress_vectorpostprocessor",
41 : "The name of the vectorpostprocessor that contains crack front stress");
42 166 : params.addParam<std::string>("stress_vector_name",
43 : "crack_tip_stress",
44 : "The name of the stress vector in the stress_vectorpostprocessor");
45 166 : params.addParam<VectorPostprocessorName>(
46 : "k_critical_vectorpostprocessor",
47 : "The name of the vectorpostprocessor that contains critical fracture toughness at crack tip");
48 166 : params.addParam<std::string>(
49 : "k_critical_vector_name",
50 : "The name of the k_critical vector in the k_critical_vectorpostprocessor");
51 83 : return params;
52 0 : }
53 :
54 42 : MeshCut2DFractureUserObject::MeshCut2DFractureUserObject(const InputParameters & parameters)
55 : : MeshCut2DUserObjectBase(parameters),
56 42 : _growth_increment(getParam<Real>("growth_increment")),
57 100 : _use_k(isParamValid("k_critical") || isParamValid("k_critical_vectorpostprocessor")),
58 84 : _use_stress(isParamValid("stress_threshold")),
59 152 : _k_critical(isParamValid("k_critical") ? getParam<Real>("k_critical")
60 : : std::numeric_limits<Real>::max()),
61 50 : _stress_threshold(_use_stress ? getParam<Real>("stress_threshold")
62 : : std::numeric_limits<Real>::max()),
63 80 : _ki_vpp(_use_k ? &getVectorPostprocessorValue(
64 : "ki_vectorpostprocessor",
65 80 : getParam<VectorPostprocessorName>("ki_vectorpostprocessor"))
66 : : nullptr),
67 80 : _kii_vpp(_use_k ? &getVectorPostprocessorValue(
68 : "kii_vectorpostprocessor",
69 80 : getParam<VectorPostprocessorName>("kii_vectorpostprocessor"))
70 : : nullptr),
71 84 : _stress_vpp(_use_stress
72 50 : ? &getVectorPostprocessorValue("stress_vectorpostprocessor",
73 50 : getParam<std::string>("stress_vector_name"))
74 : : nullptr),
75 42 : _k_critical_vpp(
76 42 : isParamValid("k_critical_vectorpostprocessor")
77 47 : ? &getVectorPostprocessorValue("k_critical_vectorpostprocessor",
78 52 : getParam<std::string>("k_critical_vector_name"))
79 42 : : nullptr)
80 : {
81 42 : if (!_use_k && !_use_stress)
82 0 : paramError("k_critical",
83 : "Must set crack extension criterion with k_critical, k_critical_vectorpostprocessor "
84 : "or stress_threshold.");
85 :
86 152 : if (isParamValid("k_critical") && isParamValid("k_critical_vectorpostprocessor"))
87 1 : paramError("k_critical",
88 : "Fracture toughness cannot be specified by both k_critical and "
89 : "k_critical_vectorpostprocessor.");
90 41 : }
91 :
92 : void
93 350 : MeshCut2DFractureUserObject::initialize()
94 : {
95 350 : _is_mesh_modified = false;
96 350 : findActiveBoundaryGrowth();
97 350 : growFront();
98 350 : addNucleatedCracksToMesh();
99 : // update _crack_front_definition with nucleated nodes
100 350 : _crack_front_definition->updateNumberOfCrackFrontPoints(
101 : _original_and_current_front_node_ids.size());
102 350 : _crack_front_definition->isCutterModified(_is_mesh_modified);
103 350 : }
104 :
105 : void
106 350 : MeshCut2DFractureUserObject::findActiveBoundaryGrowth()
107 : {
108 : // The k*_vpp & stress_vpp are empty (but not a nullptr) on the very first time step because this
109 : // UO is called before the InteractionIntegral or crackFrontStress vpp
110 350 : if ((!_ki_vpp || _ki_vpp->size() == 0) && (!_stress_vpp || _stress_vpp->size() == 0))
111 : return;
112 :
113 291 : if (_use_k && ((_ki_vpp->size() != _kii_vpp->size()) ||
114 : (_ki_vpp->size() != _original_and_current_front_node_ids.size())))
115 0 : mooseError("ki_vectorpostprocessor and kii_vectorpostprocessor should have the same number of "
116 : "crack tips as CrackFrontDefinition.",
117 : "\n ki size = ",
118 0 : _ki_vpp->size(),
119 : "\n kii size = ",
120 0 : _kii_vpp->size(),
121 : "\n cracktips in MeshCut2DFractureUserObject = ",
122 0 : _original_and_current_front_node_ids.size());
123 :
124 291 : if (_use_stress && ((_stress_vpp->size() != _original_and_current_front_node_ids.size())))
125 0 : mooseError("stress_vectorpostprocessor should have the same number of crack front points as "
126 : "CrackFrontDefinition.",
127 : "\n stress_vectorpostprocessor size = ",
128 0 : _stress_vpp->size(),
129 : "\n cracktips in MeshCut2DFractureUserObject = ",
130 0 : _original_and_current_front_node_ids.size());
131 :
132 291 : if (_k_critical_vpp && ((_k_critical_vpp->size() != _original_and_current_front_node_ids.size())))
133 0 : mooseError("k_critical_vectorpostprocessor must have the same number of crack front points as "
134 : "CrackFrontDefinition.",
135 : "\n k_critical_vectorpostprocessor size = ",
136 0 : _k_critical_vpp->size(),
137 : "\n cracktips in MeshCut2DFractureUserObject = ",
138 0 : _original_and_current_front_node_ids.size());
139 :
140 291 : _active_front_node_growth_vectors.clear();
141 1201 : for (unsigned int i = 0; i < _original_and_current_front_node_ids.size(); ++i)
142 : {
143 : // only extend crack with kcrit or nonlocal stress, never both.
144 : bool was_crack_extended_kcrit = false;
145 910 : if (_use_k)
146 : {
147 846 : Real k_crit = _k_critical;
148 846 : if (_k_critical_vpp)
149 132 : k_crit = std::min(_k_critical_vpp->at(i), _k_critical);
150 :
151 846 : Real k_squared = _ki_vpp->at(i) * _ki_vpp->at(i) + _kii_vpp->at(i) * _kii_vpp->at(i);
152 846 : if (k_squared > (k_crit * k_crit) && _ki_vpp->at(i) > 0)
153 : {
154 : // growth direction in crack front coord (cfc) system based on the max hoop stress criterion
155 : // Jiang, Wen, Benjamin W.Spencer, and John E.Dolbow.
156 : // "Ceramic nuclear fuel fracture modeling with the extended finite "
157 : // "element method." Engineering Fracture Mechanics 223(2020):106713.
158 : // https://doi.org/10.1016/j.engfracmech.2019.106713
159 : // Equation 6
160 212 : Real ki = _ki_vpp->at(i);
161 212 : Real kii = _kii_vpp->at(i);
162 212 : Real sqrt_k = std::sqrt(ki * ki + 8 * kii * kii);
163 :
164 : Real theta_m = 0;
165 : Real theta_p = 0;
166 212 : if (std::abs(kii) > libMesh::TOLERANCE)
167 : {
168 212 : theta_m = 2 * std::atan((ki - sqrt_k) / (4 * kii));
169 212 : theta_p = 2 * std::atan((ki + sqrt_k) / (4 * kii));
170 : }
171 :
172 : // Equation 5 check relative sigma_tt
173 212 : Real sigma_tt_m = ki * (3 * std::cos(theta_m / 2) + std::cos(3 * theta_m / 2)) +
174 212 : kii * (-3 * std::sin(theta_m / 2) - 3 * std::sin(3 * theta_m / 2));
175 212 : Real sigma_tt_p = ki * (3 * std::cos(theta_p / 2) + std::cos(3 * theta_p / 2)) +
176 212 : kii * (-3 * std::sin(theta_p / 2) - 3 * std::sin(3 * theta_p / 2));
177 : Real theta;
178 212 : if (sigma_tt_m > sigma_tt_p)
179 : theta = theta_m;
180 : else
181 : theta = theta_p;
182 :
183 : RealVectorValue dir_cfc;
184 212 : dir_cfc(0) = std::cos(theta);
185 212 : dir_cfc(1) = std::sin(theta);
186 : dir_cfc(2) = 0;
187 :
188 : // growth direction in global coord system based on the max hoop stress criterion
189 : RealVectorValue dir_global =
190 212 : _crack_front_definition->rotateFromCrackFrontCoordsToGlobal(dir_cfc, i);
191 212 : Point dir_global_pt(dir_global(0), dir_global(1), dir_global(2));
192 212 : Point nodal_offset = dir_global_pt * _growth_increment;
193 : _active_front_node_growth_vectors.push_back(
194 212 : std::make_pair(_original_and_current_front_node_ids[i].second, nodal_offset));
195 : }
196 : }
197 910 : if (_use_stress && !was_crack_extended_kcrit && _stress_vpp->at(i) > _stress_threshold)
198 : {
199 : // crack will only be extended if it was not already extended by kcrit
200 : // just extending the crack in the same direction it was going
201 : RealVectorValue dir_cfc(1.0, 0.0, 0.0);
202 : RealVectorValue dir_global =
203 48 : _crack_front_definition->rotateFromCrackFrontCoordsToGlobal(dir_cfc, i);
204 48 : Point dir_global_pt(dir_global(0), dir_global(1), dir_global(2));
205 48 : Point nodal_offset = dir_global_pt * _growth_increment;
206 : _active_front_node_growth_vectors.push_back(
207 48 : std::make_pair(_original_and_current_front_node_ids[i].second, nodal_offset));
208 : }
209 : }
210 : }
|