18 #include "libmesh/mesh_tools.h" 19 #include "libmesh/string_to_enum.h" 20 #include "libmesh/quadrature.h" 28 params.
addClassDescription(
"Used to describe geometric characteristics of the crack front for " 29 "fracture integral calculations");
32 params.
set<
bool>(
"use_displaced_mesh") =
false;
37 { rm_params.
set<
unsigned short>(
"layers") = 2; });
44 MooseEnum direction_method(
"CrackDirectionVector CrackMouth CurvedCrackFront");
45 MooseEnum end_direction_method(
"NoSpecialTreatment CrackDirectionVector CrackTangentVector",
46 "NoSpecialTreatment");
47 params.
addParam<std::vector<Point>>(
"crack_front_points",
"Set of points to define crack front");
48 params.
addParam<
bool>(
"closed_loop",
false,
"Set of points forms forms a closed loop");
50 "crack_direction_method",
52 "Method to determine direction of crack propagation. Choices are: " +
55 "crack_end_direction_method",
57 "Method to determine direction of crack propagation at ends of crack. Choices are: " +
61 "crack_direction_vector_end_1",
62 "Direction of crack propagation for the node at end 1 of the crack");
64 "crack_direction_vector_end_2",
65 "Direction of crack propagation for the node at end 2 of the crack");
67 "Direction of crack tangent for the node at end 1 of the crack");
69 "Direction of crack tangent for the node at end 2 of the crack");
70 params.
addParam<std::vector<BoundaryName>>(
71 "crack_mouth_boundary",
"Boundaries whose average coordinate defines the crack mouth");
72 params.
addParam<std::vector<BoundaryName>>(
"intersecting_boundary",
73 "Boundaries intersected by ends of crack");
74 params.
addParam<
bool>(
"2d",
false,
"Treat body as two-dimensional");
78 "axis_2d>=0 & axis_2d<=2",
79 "Out of plane axis for models treated as two-dimensional (0=x, 1=y, 2=z)");
80 params.
addParam<
unsigned int>(
"symmetry_plane",
81 "Account for a symmetry plane passing through " 82 "the plane of the crack, normal to the specified " 83 "axis (0=x, 1=y, 2=z)");
84 params.
addParam<
bool>(
"t_stress",
false,
"Calculate T-stress");
85 params.
addParam<
bool>(
"q_function_rings",
false,
"Generate rings of nodes for q-function");
86 params.
addParam<
unsigned int>(
"last_ring",
"The number of rings of nodes to generate");
87 params.
addParam<
unsigned int>(
"first_ring",
"The number of rings of nodes to generate");
88 params.
addParam<
unsigned int>(
"nrings",
"The number of rings of nodes to generate");
89 params.
addParam<VariableName>(
"disp_x",
"Variable containing the x displacement");
90 params.
addParam<VariableName>(
"disp_y",
"Variable containing the y displacement");
91 params.
addParam<VariableName>(
"disp_z",
"Variable containing the z displacement");
93 "j_integral_radius_inner", {},
"Radius for J-Integral calculation");
95 "j_integral_radius_outer", {},
"Radius for J-Integral calculation");
96 MooseEnum q_function_type(
"Geometry Topology",
"Geometry");
99 "The method used to define the integration domain. Options are: " +
102 "crack_front_points_provider",
103 "The UserObject provides the crack front points from XFEM GeometricCutObject");
105 params.
addParam<
unsigned int>(
"number_points_from_provider",
106 "The number of crack front points, only needed for " 107 "crack_front_points_provider that do not use a cut mesh.");
109 "crack_front_node_tolerance",
111 "General tolerance for locating nodes on the crack front based on xyz coordinates.");
118 _end_direction_method(
120 _aux(_fe_problem.getAuxiliarySystem()),
121 _mesh(_subproblem.
mesh()),
122 _treat_as_2d(getParam<bool>(
"2d")),
123 _use_mesh_cutter(false),
124 _is_cutter_modified(false),
125 _closed_loop(getParam<bool>(
"closed_loop")),
126 _axis_2d(getParam<unsigned
int>(
"axis_2d")),
127 _has_symmetry_plane(isParamValid(
"symmetry_plane")),
128 _symmetry_plane(_has_symmetry_plane ? getParam<unsigned
int>(
"symmetry_plane")
129 :
std::numeric_limits<unsigned
int>::
max()),
130 _t_stress(getParam<bool>(
"t_stress")),
131 _q_function_rings(getParam<bool>(
"q_function_rings")),
132 _q_function_type(getParam<
MooseEnum>(
"q_function_type")),
133 _crack_front_points_provider(nullptr),
134 _tol(getParam<
Real>(
"crack_front_node_tolerance"))
136 auto boundary =
isParamValid(
"boundary") ? getParam<std::vector<BoundaryName>>(
"boundary")
137 : std::vector<BoundaryName>{};
142 "CrackFrontDefinition error: since boundary is defined, crack_front_points should " 146 "As crack_front_points have been provided, the crack_front_points_provider will " 147 "not be used and needs to be removed.");
151 paramError(
"t_stress",
"t_stress not yet supported with crack_front_points");
153 paramError(
"q_function_rings",
"q_function_rings not supported with crack_front_points");
159 "CrackFrontDefinition error: since boundary is defined, " 160 "crack_front_points_provider should not be added.");
166 "CrackFrontDefinition error: number_points_from_provider is provided but " 167 "crack_front_points_provider cannot be found.");
168 else if (boundary.size())
173 "In CrackFrontDefinition, if 'boundary' is defined, 'closed_loop' should not be " 174 "set by user because closed loops are detected automatically");
177 mooseError(
"In CrackFrontDefinition, must define one of 'boundary', 'crack_front_points' " 178 "and 'crack_front_points_provider'");
186 "symmetry_plane out of bounds: ",
188 " Must be >=0 and <=2.");
195 "crack_direction_vector must be specified if crack_direction_method = " 196 "CrackDirectionVector");
202 "crack_direction_vector must not be specified if crack_direction_method = " 206 "crack_mouth_boundary",
207 "crack_mouth_boundary must be specified if crack_direction_method = CrackMouthNodes");
212 "crack_direction_vector must not be specified if crack_direction_method = " 216 paramError(
"crack_direction_method",
"Invalid direction_method");
226 "crack_direction_vector_end_1 must be specified if crack_end_direction_method = " 227 "CrackDirectionVector");
230 "crack_direction_vector_end_2 must be specified if crack_end_direction_method = " 231 "CrackDirectionVector");
240 "crack_tangent_vector_end_1 must be specified if crack_end_tangent_method = " 241 "CrackTangentVector");
244 "crack_tangent_vector_end_2 must be specified if crack_end_tangent_method = " 245 "CrackTangentVector");
257 paramError(
"displacements",
"Displacement variables must be provided for T-stress calculation");
263 "The max number of rings of nodes to generate must be provided if " 264 "q_function_rings = true");
265 _last_ring = getParam<unsigned int>(
"last_ring");
266 _first_ring = getParam<unsigned int>(
"first_ring");
290 getParam<UserObjectName>(
"crack_front_points_provider"));
297 mooseInfo(
"CrackFrontDefinition: Automatically detected ",
299 " crack front points from mesh-based provider");
303 "Using a `crack_front_points_provider` that uses an XFEM cutter mesh also " 304 "requires setting 'crack_direction_method = CurvedCrackFront'");
307 "'crack_mouth_boundary' cannot be set when using a " 308 "'crack_front_points_provider' that uses an XFEM cutter mesh");
317 "number_points_from_provider",
318 "CrackFrontDefinition error: When using a non-mesh-based crack_front_points_provider, " 319 "the number_points_from_provider parameter must be provided.");
333 std::set<dof_id_type> nodes;
339 paramError(
"intersecting_boundary",
"Cannot use intersecting_boundary with closed-loop cracks");
349 for (std::size_t i = 0; i < num_crack_front_nodes; ++i)
357 if (num_crack_front_points < 1)
358 mooseError(
"num_crack_front_points is not > 0");
359 for (std::size_t i = 0; i < num_crack_front_points; ++i)
383 for (std::size_t i = 0; i < num_crack_front_points; ++i)
402 for (
auto nd = bnd_nodes.
begin(); nd != bnd_nodes.
end(); ++nd)
408 nodes.insert(bnode->
_node->
id());
413 if (nodes.size() > 1)
440 for (
auto sit = nodes.begin(); sit != nodes.end(); ++sit)
443 if (sit == nodes.begin())
445 node0coor0 = curr_node(axis0);
446 node0coor1 = curr_node(axis1);
450 if (!MooseUtils::absoluteFuzzyEqual(curr_node(axis0), node0coor0,
_tol) ||
451 !MooseUtils::absoluteFuzzyEqual(curr_node(axis1), node0coor1,
_tol))
452 mooseError(
"Boundary provided in CrackFrontDefinition contains ",
454 " nodes, which are not collinear in the ",
456 " axis. Must contain either 1 node or collinear nodes to treat as 2D.");
467 if (nodes.size() < 1)
469 else if (nodes.size() == 1)
473 mooseError(
"Boundary provided in CrackFrontDefinition contains 1 node, but model is not " 491 const std::map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map =
493 std::map<dof_id_type, std::set<dof_id_type>> crack_front_node_to_elem_map;
495 for (
const auto & node_id : nodes)
497 const auto & node_to_elem_pair = node_to_elem_map.find(node_id);
498 mooseAssert(node_to_elem_pair != node_to_elem_map.end(),
499 "Could not find crack front node " << node_id <<
" in the node to elem map");
501 const std::vector<dof_id_type> & connected_elems = node_to_elem_pair->second;
502 for (std::size_t i = 0; i < connected_elems.size(); ++i)
503 crack_front_node_to_elem_map[node_id].insert(connected_elems[i]);
509 std::vector<std::vector<dof_id_type>> line_elems;
510 std::map<dof_id_type, std::vector<dof_id_type>> node_to_line_elem_map;
512 for (
auto cfnemit = crack_front_node_to_elem_map.begin();
513 cfnemit != crack_front_node_to_elem_map.end();
516 auto cfnemit2 = cfnemit;
517 for (++cfnemit2; cfnemit2 != crack_front_node_to_elem_map.end(); ++cfnemit2)
520 std::vector<dof_id_type> common_elements;
521 std::set<dof_id_type> & elements_connected_to_node1 = cfnemit->second;
522 std::set<dof_id_type> & elements_connected_to_node2 = cfnemit2->second;
523 std::set_intersection(elements_connected_to_node1.begin(),
524 elements_connected_to_node1.end(),
525 elements_connected_to_node2.begin(),
526 elements_connected_to_node2.end(),
527 std::inserter(common_elements, common_elements.end()));
529 if (common_elements.size() > 0)
531 std::vector<dof_id_type> my_line_elem;
532 my_line_elem.push_back(cfnemit->first);
533 my_line_elem.push_back(cfnemit2->first);
534 node_to_line_elem_map[cfnemit->first].push_back(line_elems.size());
535 node_to_line_elem_map[cfnemit2->first].push_back(line_elems.size());
536 line_elems.push_back(my_line_elem);
542 std::vector<dof_id_type> end_nodes;
543 for (
auto nlemit = node_to_line_elem_map.begin(); nlemit != node_to_line_elem_map.end();
546 std::size_t num_connected_elems = nlemit->second.size();
547 if (num_connected_elems == 1)
548 end_nodes.push_back(nlemit->first);
549 else if (num_connected_elems != 2)
551 "Node ", nlemit->first,
" is connected to >2 line segments in CrackFrontDefinition");
555 if (end_nodes.size() == 0)
562 "In CrackFrontDefinition, end_direction_method cannot be CrackDirectionVector " 563 "or CrackTangentVector for a closed-loop crack");
566 "In CrackFrontDefinition, intersecting_boundary cannot be specified for a " 567 "closed-loop crack");
569 else if (end_nodes.size() == 2)
572 mooseError(
"In CrackFrontDefinition wrong number of end nodes. Number end nodes = ",
580 while (last_node != end_nodes[1])
582 std::vector<dof_id_type> & curr_node_line_elems = node_to_line_elem_map[last_node];
583 bool found_new_node =
false;
584 for (std::size_t i = 0; i < curr_node_line_elems.size(); ++i)
586 std::vector<dof_id_type> curr_line_elem = line_elems[curr_node_line_elems[i]];
587 for (std::size_t
j = 0;
j < curr_line_elem.size(); ++
j)
591 (last_node == end_nodes[0] &&
592 line_elem_node == end_nodes[1]))
594 if (line_elem_node != last_node && line_elem_node != second_last_node)
597 found_new_node =
true;
604 second_last_node = last_node;
618 std::size_t num_positive_coor0 = 0;
619 std::size_t num_positive_coor1 = 0;
620 Real dist_from_origin0 = 0.0;
621 Real dist_from_origin1 = 0.0;
622 for (std::size_t i = 0; i < 3; ++i)
624 dist_from_origin0 += node0(i) * node0(i);
625 dist_from_origin1 += node1(i) * node1(i);
626 if (MooseUtils::absoluteFuzzyGreaterThan(node0(i), 0.0,
_tol))
627 ++num_positive_coor0;
628 if (MooseUtils::absoluteFuzzyGreaterThan(node1(i), 0.0,
_tol))
629 ++num_positive_coor1;
631 dist_from_origin0 = std::sqrt(dist_from_origin0);
632 dist_from_origin1 = std::sqrt(dist_from_origin1);
634 bool switch_ends =
false;
635 if (num_positive_coor1 > num_positive_coor0)
641 if (!MooseUtils::absoluteFuzzyEqual(dist_from_origin1, dist_from_origin0,
_tol))
643 if (dist_from_origin1 < dist_from_origin0)
648 if (end_nodes[1] < end_nodes[0])
654 std::size_t tmp_node = end_nodes[1];
655 end_nodes[1] = end_nodes[0];
656 end_nodes[0] = tmp_node;
662 std::vector<dof_id_type> & end_nodes,
663 std::set<dof_id_type> & nodes,
664 std::map<
dof_id_type, std::vector<dof_id_type>> & node_to_line_elem_map,
665 std::vector<std::vector<dof_id_type>> & line_elems)
668 Real min_dist = std::numeric_limits<Real>::max();
669 Real max_dist = -std::numeric_limits<Real>::max();
672 for (
auto nit = nodes.begin(); nit != nodes.end(); ++nit)
675 Real dist = node.norm();
679 max_dist_node = *nit;
681 else if (dist < min_dist)
686 if (MooseUtils::absoluteFuzzyGreaterThan(max_dist, min_dist,
_tol))
687 end_node = max_dist_node;
690 std::vector<Node *> node_vec;
691 for (
auto nit = nodes.begin(); nit != nodes.end(); ++nit)
696 end_nodes.push_back(end_node);
700 auto end_node_line_elems = node_to_line_elem_map[end_node];
701 if (end_node_line_elems.size() != 2)
703 "Crack front nodes are in a loop, but crack end node is only connected to one other node");
704 std::vector<Node *> candidate_other_end_nodes;
706 for (std::size_t i = 0; i < 2; ++i)
708 auto end_line_elem = line_elems[end_node_line_elems[i]];
709 for (std::size_t
j = 0;
j < end_line_elem.size(); ++
j)
711 auto line_elem_node = end_line_elem[
j];
712 if (line_elem_node != end_node)
713 candidate_other_end_nodes.push_back(
_mesh.
nodePtr(line_elem_node));
716 if (candidate_other_end_nodes.size() != 2)
718 "Crack front nodes are in a loop, but crack end node is not connected to two other nodes");
719 end_nodes.push_back(
maxNodeCoor(candidate_other_end_nodes, 1));
745 mooseError(
"Invalid dir0 in CrackFrontDefinition::maxNodeCoor()");
747 Real max_coor0 = -std::numeric_limits<Real>::max();
748 std::vector<Node *> max_coor0_nodes;
749 for (std::size_t i = 0; i < nodes.size(); ++i)
751 Real coor0 = (*nodes[i])(dirs[0]);
752 if (coor0 > max_coor0)
755 for (std::size_t i = 0; i < nodes.size(); ++i)
757 Real coor0 = (*nodes[i])(dirs[0]);
758 if (MooseUtils::absoluteFuzzyEqual(coor0, max_coor0,
_tol))
759 max_coor0_nodes.push_back(nodes[i]);
761 if (max_coor0_nodes.size() > 1)
763 Real max_coor1 = -std::numeric_limits<Real>::max();
764 std::vector<Node *> max_coor1_nodes;
765 for (std::size_t i = 0; i < nodes.size(); ++i)
767 Real coor1 = (*nodes[i])(dirs[1]);
768 if (coor1 > max_coor1)
771 for (std::size_t i = 0; i < nodes.size(); ++i)
773 Real coor1 = (*nodes[i])(dirs[1]);
774 if (MooseUtils::absoluteFuzzyEqual(coor1, max_coor1,
_tol))
775 max_coor1_nodes.push_back(nodes[i]);
777 if (max_coor1_nodes.size() > 1)
779 Real max_coor2 = -std::numeric_limits<Real>::max();
780 std::vector<Node *> max_coor2_nodes;
781 for (std::size_t i = 0; i < nodes.size(); ++i)
783 Real coor2 = (*nodes[i])(dirs[2]);
784 if (coor2 > max_coor2)
787 for (std::size_t i = 0; i < nodes.size(); ++i)
789 Real coor2 = (*nodes[i])(dirs[2]);
790 if (MooseUtils::absoluteFuzzyEqual(coor2, max_coor2,
_tol))
791 max_coor2_nodes.push_back(nodes[i]);
793 if (max_coor2_nodes.size() > 1)
794 mooseError(
"Multiple nodes with same x,y,z coordinates within tolerance");
796 return max_coor2_nodes[0]->id();
799 return max_coor1_nodes[0]->id();
802 return max_coor0_nodes[0]->id();
829 for (std::size_t i = 0; i < num_crack_front_points; ++i)
842 rot_mat.
fillRow(0, crack_direction);
872 Real back_segment_len = 0.0;
876 back_segment_len = back_segment.
norm();
879 for (std::size_t i = 0; i < num_crack_front_points; ++i)
886 else if (i == num_crack_front_points - 1)
892 Real forward_segment_len;
894 forward_segment_len = 0.0;
895 else if (
_closed_loop && i == num_crack_front_points - 1)
898 forward_segment_len = forward_segment.
norm();
903 forward_segment_len = forward_segment.
norm();
907 _segment_lengths.push_back(std::make_pair(back_segment_len, forward_segment_len));
914 tangent_direction = tangent_direction / tangent_direction.
norm();
942 back_segment = forward_segment;
943 back_segment_len = forward_segment_len;
950 std::size_t mid_id = (num_crack_front_points - 1) / 2;
957 mooseError(
"Crack plane normal vector evaluates to zero");
965 Real hyp = origin_to_first_node.
norm();
966 RealVectorValue norm_origin_to_first_node = origin_to_first_node / hyp;
969 tangent_to_first_node /= tangent_to_first_node.
norm();
971 for (std::size_t i = 0; i < num_crack_front_points; ++i)
975 Real adj = origin_to_curr_node * norm_origin_to_first_node;
976 Real opp = origin_to_curr_node * tangent_to_first_node;
980 angle = 360.0 - angle;
985 if (num_crack_front_points > 1)
994 if (MooseUtils::absoluteFuzzyEqual(
998 else if (MooseUtils::absoluteFuzzyEqual(
1008 for (std::size_t i = 0; i < num_crack_front_points; ++i)
1017 _console <<
"Summary of crack front geometry (used for fracture integrals):" << std::endl;
1018 _console <<
"index node id x coord y coord z coord x dir y dir " 1019 " z dir angle position seg length" 1021 for (std::size_t i = 0; i < num_crack_front_points; ++i)
1023 std::size_t point_id;
1028 _console << std::left << std::setw(8) << i + 1 << std::setw(10) << point_id << std::setw(14)
1036 _console << std::left << std::setw(14) <<
"--";
1051 std::set<Node *> crack_mouth_nodes;
1053 for (
auto nd = bnd_nodes.
begin(); nd != bnd_nodes.
end(); ++nd)
1062 crack_mouth_nodes.insert(bnode->
_node);
1068 for (
auto nit = crack_mouth_nodes.begin(); nit != crack_mouth_nodes.end(); ++nit)
1090 mooseError(
"Crack front must contain at least 3 nodes to use CurvedCrackFront option");
1092 std::size_t start_id;
1099 mid_id = (num_points - 1) / 3;
1100 end_id = 2 * mid_id;
1105 mid_id = (num_points - 1) / 2;
1106 end_id = num_points - 1;
1117 Point crack_plane_normal = v1.
cross(v2);
1118 crack_plane_normal = crack_plane_normal.unit();
1125 mooseError(
"Nodes on crack front are too close to being collinear");
1134 const std::size_t crack_front_point_index)
const 1139 bool calc_dir =
true;
1164 mooseError(
"Crack mouth too close to crack front node");
1172 "Vector from crack mouth to crack front node is collinear with crack front segment");
1175 crack_dir = tangent_direction.
cross(crack_plane_normal);
1176 Real dotprod = crack_dir * mouth_to_front;
1179 crack_dir = -crack_dir;
1187 crack_dir = crack_dir.
unit();
1203 mooseAssert(crack_front_node !=
nullptr,
"invalid crack front node");
1204 return crack_front_node;
1270 "crack_mouth_boundary",
1271 "In CrackFrontDefinition, Requested angle along crack front, but definition of crack mouth " 1272 "boundary using 'crack_mouth_boundary' parameter is necessary to do that.");
1287 const std::size_t point_index)
const 1294 const std::size_t point_index)
const 1302 const std::size_t point_index)
const 1311 const std::size_t point_index,
1316 Point closest_point(0.0);
1326 p_rot = p_rot - crack_front_point_rot;
1335 p_rot(2) = closest_point(2);
1336 closest_point_to_p = p_rot;
1345 Real min_dist = std::numeric_limits<Real>::max();
1346 for (std::size_t pit = 0; pit != num_points; ++pit)
1349 RealVectorValue crack_point_to_current_point = qp - *crack_front_point;
1350 Real dist = crack_point_to_current_point.
norm();
1352 if (dist < min_dist)
1355 closest_point = *crack_front_point;
1361 closest_point = closest_point - crack_front_point_rot;
1365 closest_point_to_p = p_rot - closest_point;
1366 Real perp = crack_front_edge * closest_point_to_p;
1367 Real dist_along_edge = perp / edge_length_sq;
1368 RealVectorValue point_on_edge = closest_point + crack_front_edge * dist_along_edge;
1376 Real p_to_plane_dist = std::abs(closest_point_to_p * crack_plane_normal);
1379 Real y_local = p_rot(1) - closest_point(1);
1385 Real ahead = crack_front_edge(2) * p2_vec(0) - crack_front_edge(0) * p2_vec(2);
1397 Real theta_quadrant1(0.0);
1398 if (MooseUtils::absoluteFuzzyEqual(r, p_to_plane_dist,
_tol))
1400 else if (p_to_plane_dist > r)
1402 "Invalid distance p_to_plane_dist in CrackFrontDefinition::calculateRThetaToCrackFront");
1404 theta_quadrant1 = std::asin(p_to_plane_dist / r);
1406 if (x_local >= 0 && y_local >= 0)
1407 theta = theta_quadrant1;
1409 else if (x_local < 0 && y_local >= 0)
1412 else if (x_local < 0 && y_local < 0)
1415 else if (x_local >= 0 && y_local < 0)
1416 theta = -theta_quadrant1;
1421 mooseError(
"Invalid distance r in CrackFrontDefinition::calculateRThetaToCrackFront");
1430 Real min_dist = std::numeric_limits<Real>::max();
1431 std::size_t point_index = 0;
1432 for (std::size_t pit = 0; pit != num_points; ++pit)
1435 RealVectorValue crack_point_to_current_point = qp - *crack_front_point;
1436 Real dist = crack_point_to_current_point.
norm();
1438 if (dist < min_dist)
1453 bool is_on_boundary =
false;
1454 mooseAssert(node,
"Invalid node");
1460 is_on_boundary =
true;
1464 return is_on_boundary;
1470 bool is_on_boundary =
false;
1481 if (point_index == 0 || point_index == num_crack_front_points - 1)
1482 is_on_boundary =
true;
1484 return is_on_boundary;
1496 Real forward_segment0_len;
1497 Real forward_segment1_len;
1500 Real back_segment0_len;
1501 Real back_segment1_len;
1504 const Node * current_node;
1505 const Node * previous_node;
1506 const Node * next_node;
1512 for (std::size_t i = 0; i < num_crack_front_nodes; ++i)
1522 disp_current_node(0) = disp_x_var.
getNodalValue(*current_node);
1523 disp_current_node(1) = disp_y_var.
getNodalValue(*current_node);
1524 disp_current_node(2) = disp_z_var.
getNodalValue(*current_node);
1531 forward_segment0 = *next_node - *current_node;
1533 forward_segment0_len = forward_segment0.
norm();
1535 forward_segment1 = (*next_node + disp_next_node) - (*current_node + disp_current_node);
1537 forward_segment1_len = forward_segment1.
norm();
1539 _strain_along_front[0] = (forward_segment1_len - forward_segment0_len) / forward_segment0_len;
1542 for (std::size_t i = 1; i < num_crack_front_nodes - 1; ++i)
1547 disp_current_node(0) = disp_x_var.
getNodalValue(*current_node);
1548 disp_current_node(1) = disp_y_var.
getNodalValue(*current_node);
1549 disp_current_node(2) = disp_z_var.
getNodalValue(*current_node);
1552 disp_previous_node(0) = disp_x_var.
getNodalValue(*previous_node);
1553 disp_previous_node(1) = disp_y_var.
getNodalValue(*previous_node);
1554 disp_previous_node(2) = disp_z_var.
getNodalValue(*previous_node);
1561 back_segment0 = *current_node - *previous_node;
1563 back_segment0_len = back_segment0.
norm();
1565 back_segment1 = (*current_node + disp_current_node) - (*previous_node + disp_previous_node);
1567 back_segment1_len = back_segment1.
norm();
1569 forward_segment0 = *next_node - *current_node;
1571 forward_segment0_len = forward_segment0.
norm();
1573 forward_segment1 = (*next_node + disp_next_node) - (*current_node + disp_current_node);
1575 forward_segment1_len = forward_segment1.
norm();
1578 0.5 * ((back_segment1_len - back_segment0_len) / back_segment0_len +
1579 (forward_segment1_len - forward_segment0_len) / forward_segment0_len);
1586 disp_current_node(0) = disp_x_var.
getNodalValue(*current_node);
1587 disp_current_node(1) = disp_y_var.
getNodalValue(*current_node);
1588 disp_current_node(2) = disp_z_var.
getNodalValue(*current_node);
1591 disp_previous_node(0) = disp_x_var.
getNodalValue(*previous_node);
1592 disp_previous_node(1) = disp_y_var.
getNodalValue(*previous_node);
1593 disp_previous_node(2) = disp_z_var.
getNodalValue(*previous_node);
1595 back_segment0 = *current_node - *previous_node;
1598 back_segment0_len = back_segment0.
norm();
1600 back_segment1 = (*current_node + disp_current_node) - (*previous_node + disp_previous_node);
1603 back_segment1_len = back_segment1.
norm();
1606 (back_segment1_len - back_segment0_len) / back_segment0_len;
1617 mooseAssert(strain > -std::numeric_limits<Real>::max(),
1618 "Failure in parallel communication of crack tangential strain");
1621 mooseError(
"In CrackFrontDefinition, tangential strain not available");
1633 std::vector<std::vector<const Elem *>> nodes_to_elem_map;
1634 MeshTools::build_nodes_to_elem_map(
_mesh.
getMesh(), nodes_to_elem_map);
1636 std::set<dof_id_type> nodes_prev_ring;
1639 std::set<dof_id_type> connected_nodes_this_cfn;
1643 std::set<dof_id_type> old_ring_nodes_this_cfn = connected_nodes_this_cfn;
1646 std::pair<dof_id_type, std::size_t> node_ring_index =
1649 connected_nodes_this_cfn.end());
1652 for (std::size_t ring = 2; ring <=
_last_ring; ++ring)
1656 std::set<dof_id_type> new_ring_nodes_this_cfn;
1657 for (
auto nit = old_ring_nodes_this_cfn.begin(); nit != old_ring_nodes_this_cfn.end(); ++nit)
1659 std::vector<const Node *> neighbors;
1660 MeshTools::find_nodal_neighbors(
1662 for (std::size_t inei = 0; inei < neighbors.size(); ++inei)
1664 auto thisit = connected_nodes_this_cfn.find(neighbors[inei]->
id());
1667 if (thisit == connected_nodes_this_cfn.end())
1668 new_ring_nodes_this_cfn.insert(neighbors[inei]->id());
1673 connected_nodes_this_cfn.insert(new_ring_nodes_this_cfn.begin(),
1674 new_ring_nodes_this_cfn.end());
1675 old_ring_nodes_this_cfn = new_ring_nodes_this_cfn;
1677 std::pair<dof_id_type, std::size_t> node_ring_index =
1680 connected_nodes_this_cfn.end());
1686 std::vector<std::vector<const Elem *>> nodes_to_elem_map;
1687 MeshTools::build_nodes_to_elem_map(
_mesh.
getMesh(), nodes_to_elem_map);
1688 for (std::size_t icfn = 0; icfn < num_crack_front_points; ++icfn)
1690 std::set<dof_id_type> nodes_prev_ring;
1693 std::set<dof_id_type> connected_nodes_prev_cfn;
1694 std::set<dof_id_type> connected_nodes_this_cfn;
1695 std::set<dof_id_type> connected_nodes_next_cfn;
1704 else if (
_closed_loop && icfn == num_crack_front_points - 1)
1713 else if (icfn == num_crack_front_points - 1)
1723 std::set<dof_id_type> old_ring_nodes_prev_cfn = connected_nodes_prev_cfn;
1724 std::set<dof_id_type> old_ring_nodes_this_cfn = connected_nodes_this_cfn;
1725 std::set<dof_id_type> old_ring_nodes_next_cfn = connected_nodes_next_cfn;
1728 std::pair<dof_id_type, std::size_t> node_ring_index =
1731 connected_nodes_this_cfn.end());
1734 for (std::size_t ring = 2; ring <=
_last_ring; ++ring)
1739 std::set<dof_id_type> new_ring_nodes_this_cfn;
1741 old_ring_nodes_this_cfn,
1742 connected_nodes_this_cfn,
1743 connected_nodes_prev_cfn,
1744 connected_nodes_next_cfn,
1747 std::set<dof_id_type> new_ring_nodes_prev_cfn;
1749 old_ring_nodes_prev_cfn,
1750 connected_nodes_prev_cfn,
1751 connected_nodes_this_cfn,
1752 connected_nodes_next_cfn,
1755 std::set<dof_id_type> new_ring_nodes_next_cfn;
1757 old_ring_nodes_next_cfn,
1758 connected_nodes_next_cfn,
1759 connected_nodes_prev_cfn,
1760 connected_nodes_this_cfn,
1764 connected_nodes_prev_cfn.insert(new_ring_nodes_prev_cfn.begin(),
1765 new_ring_nodes_prev_cfn.end());
1766 connected_nodes_this_cfn.insert(new_ring_nodes_this_cfn.begin(),
1767 new_ring_nodes_this_cfn.end());
1768 connected_nodes_next_cfn.insert(new_ring_nodes_next_cfn.begin(),
1769 new_ring_nodes_next_cfn.end());
1770 old_ring_nodes_prev_cfn = new_ring_nodes_prev_cfn;
1771 old_ring_nodes_this_cfn = new_ring_nodes_this_cfn;
1772 old_ring_nodes_next_cfn = new_ring_nodes_next_cfn;
1774 std::pair<dof_id_type, std::size_t> node_ring_index =
1777 connected_nodes_this_cfn.end());
1785 std::set<dof_id_type> & nodes_new_ring,
1786 const std::set<dof_id_type> & nodes_old_ring,
1787 const std::set<dof_id_type> & nodes_all_rings,
1788 const std::set<dof_id_type> & nodes_neighbor1,
1789 const std::set<dof_id_type> & nodes_neighbor2,
1790 std::vector<std::vector<const Elem *>> & nodes_to_elem_map)
1792 for (
auto nit = nodes_old_ring.begin(); nit != nodes_old_ring.end(); ++nit)
1794 std::vector<const Node *> neighbors;
1795 MeshTools::find_nodal_neighbors(
1797 for (std::size_t inei = 0; inei < neighbors.size(); ++inei)
1799 auto previt = nodes_all_rings.find(neighbors[inei]->
id());
1800 auto thisit = nodes_neighbor1.find(neighbors[inei]->
id());
1801 auto nextit = nodes_neighbor2.find(neighbors[inei]->
id());
1804 if (previt == nodes_all_rings.end() && thisit == nodes_neighbor1.end() &&
1805 nextit == nodes_neighbor2.end())
1806 nodes_new_ring.insert(neighbors[inei]->id());
1814 const std::size_t node_index)
const 1816 bool is_node_in_ring =
false;
1817 std::pair<dof_id_type, std::size_t> node_ring_key =
1822 mooseError(
"Could not find crack front node ",
1824 " in the crack front node to q-function ring-node map for ring ",
1827 std::set<dof_id_type> q_func_nodes = nnmit->second;
1828 if (q_func_nodes.find(connected_node_id) != q_func_nodes.end())
1829 is_node_in_ring =
true;
1831 return is_node_in_ring;
1836 std::size_t ring_index,
1837 const Node *
const current_node)
const 1839 Real dist_to_crack_front;
1840 Real dist_along_tangent;
1842 dist_to_crack_front, dist_along_tangent, crack_front_point_index, current_node);
1854 Real tangent_multiplier = 1.0;
1857 const Real forward_segment_length =
1859 const Real backward_segment_length =
1862 if (dist_along_tangent >= 0.0)
1864 if (forward_segment_length > 0.0)
1865 tangent_multiplier = 1.0 - dist_along_tangent / forward_segment_length;
1869 if (backward_segment_length > 0.0)
1870 tangent_multiplier = 1.0 + dist_along_tangent / backward_segment_length;
1874 tangent_multiplier = std::max(tangent_multiplier, 0.0);
1875 tangent_multiplier = std::min(tangent_multiplier, 1.0);
1880 tangent_multiplier = 0.0;
1882 q *= tangent_multiplier;
1890 std::size_t ring_index,
1891 const Node *
const current_node)
const 1894 bool is_node_in_ring =
isNodeInRing(ring_index, current_node->id(), crack_front_point_index);
1895 if (is_node_in_ring)
1903 Real & dist_along_tangent,
1904 std::size_t crack_front_point_index,
1905 const Node *
const current_node)
const 1909 Point
p = *current_node;
1913 dist_along_tangent = crack_node_to_current_node * crack_front_tangent;
1914 RealVectorValue projection_point = *crack_front_point + dist_along_tangent * crack_front_tangent;
1916 dist_to_front = axis_to_current_node.
norm();
void calculateTangentialStrainAlongFront()
Compute the strain in the direction tangent to the crack at all points on the crack front...
void isCutterModified(const bool is_cutter_modified)
Set the value of _is_cutter_modified.
unsigned int _axis_2d
Out of plane axis when crack is treated as 2D.
void getCrackFrontNodes(std::set< dof_id_type > &nodes)
Get the set of all crack front nodes.
std::vector< BoundaryID > _intersecting_boundary_ids
IDs of boundaries that intersect crack at its ends.
void mooseInfo(Args &&... args) const
bool isNodeOnIntersectingBoundary(const Node *const node) const
Determine whether a given node is on one of the boundaries that intersects an end of the crack front...
RealVectorValue calculateCrackFrontDirection(const Point &crack_front_point, const RealVectorValue &tangent_direction, const CRACK_NODE_TYPE ntype, const std::size_t crack_front_point_index=0) const
Compute the direction of crack extension for a given point on the crack front.
Real _overall_length
Overall length of the crack.
void fillRow(unsigned int r, const libMesh::TypeVector< Real > &v)
const RealVectorValue & getCrackFrontTangent(const std::size_t point_index) const
Get the vector tangent to the crack front at a specified position.
CrackFrontDefinition(const InputParameters ¶meters)
std::vector< Point > _crack_front_points
Vector of points along the crack front.
bool _has_symmetry_plane
Whether the crack plane is also a symmetry plane in the model.
virtual void execute() override
const Node * getCrackFrontNodePtr(const std::size_t node_index) const
Get the node pointer for a specified node on the crack front.
void paramError(const std::string ¶m, Args... args) const
static InputParameters validParams()
std::size_t _first_ring
Numer of elements from crack tip to first topological ring.
void updateCrackFrontGeometry()
Update the data structures defining the crack front geometry such as the ordered crack front nodes/po...
Real getCrackFrontBackwardSegmentLength(const std::size_t point_index) const
Get the length of the line segment on the crack front behind the specified position.
enum CrackFrontDefinition::END_DIRECTION_METHOD _end_direction_method
bool isBoundaryNode(dof_id_type node_id) const
std::vector< Real > _distances_along_front
Vector of distances along the crack front.
RealVectorValue _crack_direction_vector_end_2
Fixed vector optionally used to define crack extension direction at end 2 of crack front...
bool _use_mesh_cutter
Whether to describe the crack as a mesh cutter.
const InputParameters & parameters() const
std::map< std::pair< dof_id_type, std::size_t >, std::set< dof_id_type > > _crack_front_node_to_node_map
Data structure used to store information about topological rings Key is a pair of the crack front nod...
RealVectorValue rotateToCrackFrontCoords(const RealVectorValue vector, const std::size_t point_index) const
Rotate a vector in the global coordinate coordinate system to the crack front local coordinate system...
bool isNodeInRing(const std::size_t ring_index, const dof_id_type connected_node_id, const std::size_t node_index) const
Determine whether a node is contained within a specified volume integral element ring for a given nod...
void addNodesToQFunctionRing(std::set< dof_id_type > &nodes_new_ring, const std::set< dof_id_type > &nodes_old_ring, const std::set< dof_id_type > &nodes_all_rings, const std::set< dof_id_type > &nodes_neighbor1, const std::set< dof_id_type > &nodes_neighbor2, std::vector< std::vector< const Elem *>> &nodes_to_elem_map)
Find nodes that are connected through elements to the nodes in the previous node ring.
bool _q_function_rings
Whether topological rings are used to define the q functions.
const CrackFrontPointsProvider * _crack_front_points_provider
Pointer to a CrackFrontPointsProvider object optionally used to define the crack front points...
registerMooseObject("SolidMechanicsApp", CrackFrontDefinition)
const Parallel::Communicator & _communicator
bool hasAngleAlongFront() const
Whether the distance along the crack front is available as an angle.
Real DomainIntegralQFunction(std::size_t crack_front_point_index, std::size_t ring_index, const Node *const current_node) const
Compute the q function for the case where it is defined geometrically.
static void includeCrackFrontDefinitionParams(InputParameters ¶ms)
used by Actions to add CrackFrontDefinitionParams
std::string getRawNames() const
std::string _disp_y_var_name
std::vector< BoundaryID > _crack_mouth_boundary_ids
IDs of boundaries used to define location of crack mouth.
Real DomainIntegralTopologicalQFunction(std::size_t crack_front_point_index, std::size_t ring_index, const Node *const current_node) const
Compute the q function for the case where it is defined through element connectivity.
virtual const Node & nodeRef(const dof_id_type i) const
bool isPointWithIndexOnIntersectingBoundary(const std::size_t point_index) const
Determine whether a given crack front point is on one of the boundaries that intersects an end of the...
void computeCurvedCrackFrontCrackPlaneNormals()
Compute crack plane face normals for cracks that have a curved crack front but do not use a mesh cutt...
std::vector< RealVectorValue > _crack_plane_normals
Vector normals to a nonplanar crack.
void updateNumberOfCrackFrontPoints(const std::size_t num_points)
Change the number of crack front nodes.
auto max(const L &left, const R &right)
void rotate(const RankTwoTensorTempl< Real > &R)
void pickLoopCrackEndNodes(std::vector< dof_id_type > &end_nodes, std::set< dof_id_type > &nodes, std::map< dof_id_type, std::vector< dof_id_type >> &node_to_line_elem_map, std::vector< std::vector< dof_id_type >> &line_elems)
For the case of a crack that is a complete loop, determine which of the nodes should be the start and...
const Real _tol
tolerance for matching nodes at crack front
std::vector< RankTwoTensor > _rot_matrix
Vector of rotation matrices along the crack front.
RealVectorValue rotateFromCrackFrontCoordsToGlobal(const RealVectorValue vector, const std::size_t point_index) const
Rotate a vector from crack front cartesian coordinate to global cartesian coordinate.
enum CrackFrontDefinition::CRACK_GEOM_DEFINITION _geom_definition_method
Class used in fracture integrals to define geometric characteristics of the crack front...
std::size_t getNumCrackFrontPoints() const
Get the number of points defining the crack front as a set of line segments.
TypeVector< Real > unit() const
void orderCrackFrontNodes(std::set< dof_id_type > &nodes)
Arrange the crack front nodes by their position along the crack front, and put them in the _ordered_c...
dof_id_type maxNodeCoor(std::vector< Node *> &nodes, unsigned int dir0=0)
Find the node with the maximum value of its coordinate.
CRACK_NODE_TYPE
Enum used to define the type of the nodes on the crack front (end or middle)
const RealVectorValue & getCrackFrontNormal(const std::size_t point_index) const
Get the vector normal to the crack front at a specified position.
bool _closed_loop
Whether the crack forms a closed loop.
const Point * getCrackFrontPoint(const std::size_t point_index) const
Get a Point object for a specified point on the crack front.
void calculateRThetaToCrackFront(const Point qp, const std::size_t point_index, Real &r, Real &theta) const
Calculate r and theta of a point in the crack front polar coordinates for a given crack point index...
bool _is_cutter_modified
Indicator that shows if the cutter mesh is modified or not in the calculation step.
virtual const std::vector< Point > getCrackFrontPoints(unsigned int) const =0
get a set of points along a crack front from a XFEM GeometricCutUserObject
Real getDistanceAlongFront(const std::size_t point_index) const
Get the distance along the crack front from the beginning of the crack to the specified position...
boundary_id_type BoundaryID
virtual unsigned int getNumberOfCrackFrontPoints() const =0
Get the current number of crack front points.
virtual const Node * nodePtr(const dof_id_type i) const
virtual void initialSetup() override
bool usesMesh() const
Getter for if a cutter mesh is used in a derived class.
std::vector< Real > _strain_along_front
Vector of tangential strain along the crack front.
std::vector< RealVectorValue > _crack_directions
Vector of crack extension directions along the crack front.
std::vector< bool > _is_point_on_intersecting_boundary
Vector of bools indicating whether individual crack front points are on an intersecting boundary...
const RealVectorValue & getCrackDirection(const std::size_t point_index) const
Get the unit vector of the crack extension direction at the specified position.
RealVectorValue _crack_direction_vector
Fixed vector optionally used to define crack extension direction.
DIRECTION_METHOD
Enum used to define the method for computing the crack extension direction.
virtual MooseVariable & getStandardVariable(const THREAD_ID tid, const std::string &var_name)=0
TypeVector< typename CompareTypes< Real, T2 >::supertype > cross(const TypeVector< T2 > &v) const
std::vector< BoundaryName > _crack_mouth_boundary_names
Names of boundaries used to define location of crack mouth.
bool absolute_fuzzy_equals(const TypeVector< Real > &rhs, Real tol=TOLERANCE) const
MooseMesh & _mesh
Reference to the mesh.
std::string _disp_z_var_name
void orderEndNodes(std::vector< dof_id_type > &end_nodes)
Determine which of the end nodes should be the starting point of the crack front. ...
void projectToFrontAtPoint(Real &dist_to_front, Real &dist_along_tangent, std::size_t crack_front_point_index, const Node *const current_node) const
Project a point to a specified point along the crack front and compute the projected normal and tange...
static InputParameters validParams()
void createQFunctionRings()
Create the data defining the rings used to define the q function when the topological option is used ...
std::vector< Real > _j_integral_radius_outer
Vector of outer radii of the rings used for geometric q functions.
bool hasBoundary(const BoundaryName &name) const
unsigned int _symmetry_plane
Which plane is the symmetry plane.
virtual const std::vector< RealVectorValue > getCrackPlaneNormals(unsigned int) const =0
get a set of normal vectors along a crack front from a XFEM GeometricCutUserObject ...
const_iterator end() const
END_DIRECTION_METHOD
Enum used to define the method for computing the crack extension direction at the ends of the crack...
std::string _disp_x_var_name
Names of the x, y, and z displacement variables.
std::size_t _num_points_from_provider
Number of points coming from the CrackFrontPointsProvider.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void computeCrackMouthNodes()
compute node and coordinate data for crack fronts defined by crack_mouth_boundary_ids sidesets ...
std::vector< RealVectorValue > _tangent_directions
Vector of tangent directions along the crack front.
void max(const T &r, T &o, Request &req) const
static InputParameters validParams()
DofValue getNodalValue(const Node &node) const
Real getAngleAlongFront(const std::size_t point_index) const
Get the angle along the crack front from the beginning of the crack to the specified position...
const_iterator begin() const
std::vector< dof_id_type > _ordered_crack_front_nodes
Crack front nodes ordered from the start to end of the crack front.
std::vector< BoundaryName > _intersecting_boundary_names
Names of boundaries that intersect crack at its ends.
Real getCrackFrontTangentialStrain(const std::size_t node_index) const
Get the strain in the direction tangent to the crack front at a given point.
void mooseError(Args &&... args) const
Real getCrackFrontForwardSegmentLength(const std::size_t point_index) const
Get the length of the line segment on the crack front ahead of the specified position.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
MooseEnum _q_function_type
Method used to define the q function.
bool isParamValid(const std::string &name) const
bool _t_stress
Whether the T-stress is being computed.
const ConsoleStream _console
std::vector< BoundaryID > getBoundaryIDs(const Elem *const elem, const unsigned short int side) const
virtual void initialize() override
RealVectorValue _crack_tangent_vector_end_2
Fixed vector optionally used to define crack tangent direction at end 2 of crack front.
std::size_t _last_ring
Numer of elements from crack tip to last topological ring.
std::vector< Real > _angles_along_front
Vector of angles along the crack front.
processor_id_type processor_id() const
std::vector< std::pair< Real, Real > > _segment_lengths
Vector of segment lengths along the crack front.
virtual void finalize() override
RealVectorValue _crack_tangent_vector_end_1
Fixed vector optionally used to define crack tangent direction at end 1 of crack front.
bool _treat_as_2d
Whether to treat the model as 2D for computation of fracture integrals.
RealVectorValue _crack_direction_vector_end_1
Fixed vector optionally used to define crack extension direction at end 1 of crack front...
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode *> * getBoundaryNodeRange()
void ErrorVector unsigned int
std::vector< Real > _j_integral_radius_inner
Vector of inner radii of the rings used for geometric q functions.
const std::map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
RealVectorValue _crack_mouth_coordinates
Coordinates of crack mouth.
enum CrackFrontDefinition::DIRECTION_METHOD _direction_method