www.mooseframework.org
CrackFrontDefinition.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "CrackFrontDefinition.h"
11 
12 // MOOSE includes
13 #include "MooseMesh.h"
14 #include "MooseVariable.h"
15 #include "RankTwoTensor.h"
16 
17 #include "libmesh/mesh_tools.h"
18 #include "libmesh/string_to_enum.h"
19 #include "libmesh/quadrature.h"
20 
21 registerMooseObject("TensorMechanicsApp", CrackFrontDefinition);
22 
24 
25 InputParameters
27 {
28  InputParameters params = GeneralUserObject::validParams();
29  params.addClassDescription("Gathers information about nodes at the crack front; this object is "
30  "normally created by the DomainIntegralAction.");
33  params.set<bool>("use_displaced_mesh") = false;
34  return params;
35 }
36 
37 void
38 addCrackFrontDefinitionParams(InputParameters & params)
39 {
40  MooseEnum direction_method("CrackDirectionVector CrackMouth CurvedCrackFront");
41  MooseEnum end_direction_method("NoSpecialTreatment CrackDirectionVector", "NoSpecialTreatment");
42  params.addParam<std::vector<Point>>("crack_front_points", "Set of points to define crack front");
43  params.addParam<bool>("closed_loop", false, "Set of points forms forms a closed loop");
44  params.addRequiredParam<MooseEnum>(
45  "crack_direction_method",
46  direction_method,
47  "Method to determine direction of crack propagation. Choices are: " +
48  direction_method.getRawNames());
49  params.addParam<MooseEnum>(
50  "crack_end_direction_method",
51  end_direction_method,
52  "Method to determine direction of crack propagation at ends of crack. Choices are: " +
53  end_direction_method.getRawNames());
54  params.addParam<RealVectorValue>("crack_direction_vector", "Direction of crack propagation");
55  params.addParam<RealVectorValue>(
56  "crack_direction_vector_end_1",
57  "Direction of crack propagation for the node at end 1 of the crack");
58  params.addParam<RealVectorValue>(
59  "crack_direction_vector_end_2",
60  "Direction of crack propagation for the node at end 2 of the crack");
61  params.addParam<std::vector<BoundaryName>>(
62  "crack_mouth_boundary", "Boundaries whose average coordinate defines the crack mouth");
63  params.addParam<std::vector<BoundaryName>>("intersecting_boundary",
64  "Boundaries intersected by ends of crack");
65  params.addParam<bool>("2d", false, "Treat body as two-dimensional");
66  params.addRangeCheckedParam<unsigned int>(
67  "axis_2d",
68  2,
69  "axis_2d>=0 & axis_2d<=2",
70  "Out of plane axis for models treated as two-dimensional (0=x, 1=y, 2=z)");
71  params.addParam<unsigned int>("symmetry_plane",
72  "Account for a symmetry plane passing through "
73  "the plane of the crack, normal to the specified "
74  "axis (0=x, 1=y, 2=z)");
75  params.addParam<bool>("t_stress", false, "Calculate T-stress");
76  params.addParam<bool>("q_function_rings", false, "Generate rings of nodes for q-function");
77  params.addParam<unsigned int>("last_ring", "The number of rings of nodes to generate");
78  params.addParam<unsigned int>("first_ring", "The number of rings of nodes to generate");
79  params.addParam<unsigned int>("nrings", "The number of rings of nodes to generate");
80  params.addParam<VariableName>("disp_x", "Variable containing the x displacement");
81  params.addParam<VariableName>("disp_y", "Variable containing the y displacement");
82  params.addParam<VariableName>("disp_z", "Variable containing the z displacement");
83  params.addParam<std::vector<Real>>("j_integral_radius_inner",
84  "Radius for J-Integral calculation");
85  params.addParam<std::vector<Real>>("j_integral_radius_outer",
86  "Radius for J-Integral calculation");
87  MooseEnum q_function_type("Geometry Topology", "Geometry");
88  params.addParam<MooseEnum>("q_function_type",
89  q_function_type,
90  "The method used to define the integration domain. Options are: " +
91  q_function_type.getRawNames());
92  params.addParam<UserObjectName>(
93  "crack_front_points_provider",
94  "The UserObject provides the crack front points from XFEM GeometricCutObject");
95  params.addParam<unsigned int>(
96  "number_points_from_provider",
97  "The number of crack front points, only needed if crack_front_points_provider is used.");
98 }
99 
100 const Real CrackFrontDefinition::_tol = 1e-10;
101 
102 CrackFrontDefinition::CrackFrontDefinition(const InputParameters & parameters)
103  : GeneralUserObject(parameters),
104  BoundaryRestrictable(this, true), // false means nodesets
105  _aux(_fe_problem.getAuxiliarySystem()),
106  _mesh(_subproblem.mesh()),
107  _treat_as_2d(getParam<bool>("2d")),
108  _closed_loop(getParam<bool>("closed_loop")),
109  _axis_2d(getParam<unsigned int>("axis_2d")),
110  _has_symmetry_plane(isParamValid("symmetry_plane")),
111  _symmetry_plane(_has_symmetry_plane ? getParam<unsigned int>("symmetry_plane")
112  : std::numeric_limits<unsigned int>::max()),
113  _t_stress(getParam<bool>("t_stress")),
114  _q_function_rings(getParam<bool>("q_function_rings")),
115  _q_function_type(getParam<MooseEnum>("q_function_type")),
116  _crack_front_points_provider(nullptr)
117 {
118  if (isParamValid("crack_front_points"))
119  {
120  if (isParamValid("boundary"))
121  mooseError("CrackFrontDefinition error: since boundary is defined, crack_front_points should "
122  "not be added.");
123  if (isParamValid("crack_front_points_provider"))
124  mooseError("As crack_front_points have been provided, the crack_front_points_provider will "
125  "not be used and needs to be removed.");
126  _crack_front_points = getParam<std::vector<Point>>("crack_front_points");
128  if (_t_stress)
129  mooseError("t_stress not yet supported with crack_front_points");
130  if (_q_function_rings)
131  mooseError("q_function_rings not supported with crack_front_points");
132  }
133  else if (isParamValid("crack_front_points_provider"))
134  {
135  if (isParamValid("boundary"))
136  mooseError("CrackFrontDefinition error: since boundary is defined, "
137  "crack_front_points_provider should not be added.");
138  if (!isParamValid("number_points_from_provider"))
139  mooseError("CrackFrontDefinition error: When crack_front_points_provider is used, the "
140  "number_points_from_provider must be "
141  "provided.");
142  _crack_front_points_provider = &getUserObjectByName<CrackFrontPointsProvider>(
143  getParam<UserObjectName>("crack_front_points_provider"));
144  _num_points_from_provider = getParam<unsigned int>("number_points_from_provider");
146  }
147  else if (isParamValid("number_points_from_provider"))
148  mooseError("CrackFrontDefinition error: number_points_from_provider is provided but "
149  "crack_front_points_provider cannot "
150  "be found.");
151  else if (isParamValid("boundary"))
152  {
154  if (parameters.isParamSetByUser("closed_loop"))
155  mooseError("In CrackFrontDefinition, if 'boundary' is defined, 'closed_loop' should not be "
156  "set by user!");
157  }
158  else
159  mooseError("In CrackFrontDefinition, must define one of 'boundary', 'crack_front_points' "
160  "and 'crack_front_points_provider'");
161 
162  if (isParamValid("crack_mouth_boundary"))
163  _crack_mouth_boundary_names = getParam<std::vector<BoundaryName>>("crack_mouth_boundary");
164 
166  if (_symmetry_plane > 2)
167  mooseError("symmetry_plane out of bounds: ", _symmetry_plane, " Must be >=0 and <=2.");
168 
169  MooseEnum direction_method_moose_enum = getParam<MooseEnum>("crack_direction_method");
170  _direction_method = DIRECTION_METHOD(int(direction_method_moose_enum));
171  switch (_direction_method)
172  {
174  if (!isParamValid("crack_direction_vector"))
175  mooseError("crack_direction_vector must be specified if crack_direction_method = "
176  "CrackDirectionVector");
177  _crack_direction_vector = getParam<RealVectorValue>("crack_direction_vector");
178  break;
179  case CRACK_MOUTH:
180  if (isParamValid("crack_direction_vector"))
181  mooseError("crack_direction_vector must not be specified if crack_direction_method = "
182  "CrackMouthNodes");
183  if (_crack_mouth_boundary_names.size() == 0)
184  mooseError(
185  "crack_mouth_boundary must be specified if crack_direction_method = CrackMouthNodes");
186  break;
187  case CURVED_CRACK_FRONT:
188  if (isParamValid("crack_direction_vector"))
189  mooseError("crack_direction_vector must not be specified if crack_direction_method = "
190  "CurvedCrackFront");
191  break;
192  default:
193  mooseError("Invalid direction_method");
194  }
195 
196  if (isParamValid("intersecting_boundary"))
197  _intersecting_boundary_names = getParam<std::vector<BoundaryName>>("intersecting_boundary");
198 
199  MooseEnum end_direction_method_moose_enum = getParam<MooseEnum>("crack_end_direction_method");
200  if (end_direction_method_moose_enum.isValid())
201  {
202  _end_direction_method = END_DIRECTION_METHOD(int(end_direction_method_moose_enum));
204  {
205  if (!isParamValid("crack_direction_vector_end_1"))
206  mooseError("crack_direction_vector_end_1 must be specified if crack_end_direction_method = "
207  "CrackDirectionVector");
208  if (!isParamValid("crack_direction_vector_end_2"))
209  mooseError("crack_direction_vector_end_2 must be specified if crack_end_direction_method = "
210  "CrackDirectionVector");
211  _crack_direction_vector_end_1 = getParam<RealVectorValue>("crack_direction_vector_end_1");
212  _crack_direction_vector_end_2 = getParam<RealVectorValue>("crack_direction_vector_end_2");
213  }
214  }
215 
216  if (isParamValid("disp_x") && isParamValid("disp_y") && isParamValid("disp_z"))
217  {
218  _disp_x_var_name = getParam<VariableName>("disp_x");
219  _disp_y_var_name = getParam<VariableName>("disp_y");
220  _disp_z_var_name = getParam<VariableName>("disp_z");
221  }
222  else if (_t_stress == true && _treat_as_2d == false)
223  mooseError("Displacement variables must be provided for T-stress calculation");
224 
225  if (_q_function_rings)
226  {
227  if (!isParamValid("last_ring"))
228  mooseError("The max number of rings of nodes to generate must be provided if "
229  "q_function_rings = true");
230  _last_ring = getParam<unsigned int>("last_ring");
231  _first_ring = getParam<unsigned int>("first_ring");
232  }
233  else
234  {
235  _j_integral_radius_inner = getParam<std::vector<Real>>("j_integral_radius_inner");
236  _j_integral_radius_outer = getParam<std::vector<Real>>("j_integral_radius_outer");
237  }
238 }
239 
241 
242 void
244 {
245  // Because J-Integral is based on original geometry, the crack front geometry
246  // is never updated, so everything that needs to happen is done in initialSetup()
247  if (_t_stress == true && _treat_as_2d == false)
249 }
250 
251 void
253 {
254  if (_crack_front_points_provider != nullptr)
257 
260 
262  {
263  std::set<dof_id_type> nodes;
264  getCrackFrontNodes(nodes);
265  orderCrackFrontNodes(nodes);
266  }
267 
268  if (_closed_loop && _intersecting_boundary_names.size() > 0)
269  mooseError("Cannot use intersecting_boundary with closed-loop cracks");
270 
272 
273  if (_q_function_rings)
275 
276  if (_t_stress)
277  {
278  unsigned int num_crack_front_nodes = _ordered_crack_front_nodes.size();
279  for (unsigned int i = 0; i < num_crack_front_nodes; ++i)
280  _strain_along_front.push_back(-std::numeric_limits<Real>::max());
281  }
282 
283  unsigned int num_crack_front_points = getNumCrackFrontPoints();
284  if (_q_function_type == "GEOMETRY")
285  {
286  if (!_treat_as_2d)
287  if (num_crack_front_points < 1)
288  mooseError("num_crack_front_points is not > 0");
289  for (unsigned int i = 0; i < num_crack_front_points; ++i)
290  {
291  bool is_point_on_intersecting_boundary = isPointWithIndexOnIntersectingBoundary(i);
292  _is_point_on_intersecting_boundary.push_back(is_point_on_intersecting_boundary);
293  }
294  }
295 }
296 
297 void
299 {
300 }
301 
302 void
304 {
305  if (_t_stress)
306  _communicator.max(_strain_along_front);
307 }
308 
309 void
310 CrackFrontDefinition::getCrackFrontNodes(std::set<dof_id_type> & nodes)
311 {
312  ConstBndNodeRange & bnd_nodes = *_mesh.getBoundaryNodeRange();
313  for (ConstBndNodeRange::const_iterator nd = bnd_nodes.begin(); nd != bnd_nodes.end(); ++nd)
314  {
315  const BndNode * bnode = *nd;
316  BoundaryID boundary_id = bnode->_bnd_id;
317 
318  if (hasBoundary(boundary_id))
319  nodes.insert(bnode->_node->id());
320  }
321 
322  if (_treat_as_2d)
323  {
324  if (nodes.size() > 1)
325  {
326  // Check that the nodes are collinear in the axis normal to the 2d plane
327  unsigned int axis0;
328  unsigned int axis1;
329 
330  switch (_axis_2d)
331  {
332  case 0:
333  axis0 = 1;
334  axis1 = 2;
335  break;
336  case 1:
337  axis0 = 0;
338  axis1 = 2;
339  break;
340  case 2:
341  axis0 = 0;
342  axis1 = 1;
343  break;
344  default:
345  mooseError("Invalid axis.");
346  }
347 
348  Real node0coor0 = 0;
349  Real node0coor1 = 0;
350 
351  for (std::set<dof_id_type>::iterator sit = nodes.begin(); sit != nodes.end(); ++sit)
352  {
353  Node & curr_node = _mesh.nodeRef(*sit);
354  if (sit == nodes.begin())
355  {
356  node0coor0 = curr_node(axis0);
357  node0coor1 = curr_node(axis1);
358  }
359  else
360  {
361  if (!MooseUtils::absoluteFuzzyEqual(curr_node(axis0), node0coor0, _tol) ||
362  !MooseUtils::absoluteFuzzyEqual(curr_node(axis1), node0coor1, _tol))
363  mooseError("Boundary provided in CrackFrontDefinition contains ",
364  nodes.size(),
365  " nodes, which are not collinear in the ",
366  _axis_2d,
367  " axis. Must contain either 1 node or collinear nodes to treat as 2D.");
368  }
369  }
370  }
371  }
372 }
373 
374 void
375 CrackFrontDefinition::orderCrackFrontNodes(std::set<dof_id_type> & nodes)
376 {
378  if (nodes.size() < 1)
379  mooseError("No crack front nodes");
380  else if (nodes.size() == 1)
381  {
382  _ordered_crack_front_nodes.push_back(*nodes.begin());
383  if (!_treat_as_2d)
384  mooseError("Boundary provided in CrackFrontDefinition contains 1 node, but model is not "
385  "treated as 2d");
386  }
387  else // nodes.size() > 1
388  {
389  // Loop through the set of crack front nodes, and create a node to element map for just the
390  // crack front nodes
391  // The main reason for creating a second map is that we need to do a sort prior to the
392  // set_intersection.
393  // The original map contains vectors, and we can't sort them, so we create sets in the local
394  // map.
395  const std::map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map =
396  _mesh.nodeToElemMap();
397  std::map<dof_id_type, std::set<dof_id_type>> crack_front_node_to_elem_map;
398 
399  for (const auto & node_id : nodes)
400  {
401  const auto & node_to_elem_pair = node_to_elem_map.find(node_id);
402  mooseAssert(node_to_elem_pair != node_to_elem_map.end(),
403  "Could not find crack front node " << node_id << "in the node to elem map");
404 
405  const std::vector<dof_id_type> & connected_elems = node_to_elem_pair->second;
406  for (unsigned int i = 0; i < connected_elems.size(); ++i)
407  crack_front_node_to_elem_map[node_id].insert(connected_elems[i]);
408  }
409 
410  // Determine which nodes are connected to each other via elements, and construct line elements
411  // to represent
412  // those connections
413  std::vector<std::vector<dof_id_type>> line_elems;
414  std::map<dof_id_type, std::vector<dof_id_type>> node_to_line_elem_map;
415 
416  for (std::map<dof_id_type, std::set<dof_id_type>>::iterator cfnemit =
417  crack_front_node_to_elem_map.begin();
418  cfnemit != crack_front_node_to_elem_map.end();
419  ++cfnemit)
420  {
421  std::map<dof_id_type, std::set<dof_id_type>>::iterator cfnemit2 = cfnemit;
422  for (++cfnemit2; cfnemit2 != crack_front_node_to_elem_map.end(); ++cfnemit2)
423  {
424 
425  std::vector<dof_id_type> common_elements;
426  std::set<dof_id_type> & elements_connected_to_node1 = cfnemit->second;
427  std::set<dof_id_type> & elements_connected_to_node2 = cfnemit2->second;
428  std::set_intersection(elements_connected_to_node1.begin(),
429  elements_connected_to_node1.end(),
430  elements_connected_to_node2.begin(),
431  elements_connected_to_node2.end(),
432  std::inserter(common_elements, common_elements.end()));
433 
434  if (common_elements.size() > 0)
435  {
436  std::vector<dof_id_type> my_line_elem;
437  my_line_elem.push_back(cfnemit->first);
438  my_line_elem.push_back(cfnemit2->first);
439  node_to_line_elem_map[cfnemit->first].push_back(line_elems.size());
440  node_to_line_elem_map[cfnemit2->first].push_back(line_elems.size());
441  line_elems.push_back(my_line_elem);
442  }
443  }
444  }
445 
446  // Find nodes on ends of line (those connected to only one line element)
447  std::vector<dof_id_type> end_nodes;
448  for (std::map<dof_id_type, std::vector<dof_id_type>>::iterator nlemit =
449  node_to_line_elem_map.begin();
450  nlemit != node_to_line_elem_map.end();
451  ++nlemit)
452  {
453  unsigned int num_connected_elems = nlemit->second.size();
454  if (num_connected_elems == 1)
455  end_nodes.push_back(nlemit->first);
456  else if (num_connected_elems != 2)
457  mooseError(
458  "Node ", nlemit->first, " is connected to >2 line segments in CrackFrontDefinition");
459  }
460 
461  // For embedded crack with closed loop of crack front nodes, must pick the end nodes
462  if (end_nodes.size() == 0) // Crack front is a loop. Pick nodes to be end nodes.
463  {
464  pickLoopCrackEndNodes(end_nodes, nodes, node_to_line_elem_map, line_elems);
465  _closed_loop = true;
467  mooseError("In CrackFrontDefinition, end_direction_method cannot be CrackDirectionVector "
468  "for a closed-loop crack");
469  if (_intersecting_boundary_names.size() > 0)
470  mooseError("In CrackFrontDefinition, intersecting_boundary cannot be specified for a "
471  "closed-loop crack");
472  }
473  else if (end_nodes.size() == 2) // Rearrange the order of the end nodes if needed
474  orderEndNodes(end_nodes);
475  else
476  mooseError("In CrackFrontDefinition wrong number of end nodes. Number end nodes = ",
477  end_nodes.size());
478 
479  // Create an ordered list of the nodes going along the line of the crack front
480  _ordered_crack_front_nodes.push_back(end_nodes[0]);
481 
482  dof_id_type last_node = end_nodes[0];
483  dof_id_type second_last_node = last_node;
484  while (last_node != end_nodes[1])
485  {
486  std::vector<dof_id_type> & curr_node_line_elems = node_to_line_elem_map[last_node];
487  bool found_new_node = false;
488  for (unsigned int i = 0; i < curr_node_line_elems.size(); ++i)
489  {
490  std::vector<dof_id_type> curr_line_elem = line_elems[curr_node_line_elems[i]];
491  for (unsigned int j = 0; j < curr_line_elem.size(); ++j)
492  {
493  dof_id_type line_elem_node = curr_line_elem[j];
494  if (_closed_loop &&
495  (last_node == end_nodes[0] &&
496  line_elem_node == end_nodes[1])) // wrong direction around closed loop
497  continue;
498  if (line_elem_node != last_node && line_elem_node != second_last_node)
499  {
500  _ordered_crack_front_nodes.push_back(line_elem_node);
501  found_new_node = true;
502  break;
503  }
504  }
505  if (found_new_node)
506  break;
507  }
508  second_last_node = last_node;
509  last_node = _ordered_crack_front_nodes.back();
510  }
511  }
512 }
513 
514 void
515 CrackFrontDefinition::orderEndNodes(std::vector<dof_id_type> & end_nodes)
516 {
517  // Choose the node to be the first node. Do that based on undeformed coordinates for
518  // repeatability.
519  Node & node0 = _mesh.nodeRef(end_nodes[0]);
520  Node & node1 = _mesh.nodeRef(end_nodes[1]);
521 
522  unsigned int num_positive_coor0 = 0;
523  unsigned int num_positive_coor1 = 0;
524  Real dist_from_origin0 = 0.0;
525  Real dist_from_origin1 = 0.0;
526  for (unsigned int i = 0; i < 3; ++i)
527  {
528  dist_from_origin0 += node0(i) * node0(i);
529  dist_from_origin1 += node1(i) * node1(i);
530  if (MooseUtils::absoluteFuzzyGreaterThan(node0(i), 0.0, _tol))
531  ++num_positive_coor0;
532  if (MooseUtils::absoluteFuzzyGreaterThan(node1(i), 0.0, _tol))
533  ++num_positive_coor1;
534  }
535  dist_from_origin0 = std::sqrt(dist_from_origin0);
536  dist_from_origin1 = std::sqrt(dist_from_origin1);
537 
538  bool switch_ends = false;
539  if (num_positive_coor1 > num_positive_coor0)
540  {
541  switch_ends = true;
542  }
543  else
544  {
545  if (!MooseUtils::absoluteFuzzyEqual(dist_from_origin1, dist_from_origin0, _tol))
546  {
547  if (dist_from_origin1 < dist_from_origin0)
548  switch_ends = true;
549  }
550  else
551  {
552  if (end_nodes[1] < end_nodes[0])
553  switch_ends = true;
554  }
555  }
556  if (switch_ends)
557  {
558  unsigned int tmp_node = end_nodes[1];
559  end_nodes[1] = end_nodes[0];
560  end_nodes[0] = tmp_node;
561  }
562 }
563 
564 void
566  std::vector<dof_id_type> & end_nodes,
567  std::set<dof_id_type> & nodes,
568  std::map<dof_id_type, std::vector<dof_id_type>> & node_to_line_elem_map,
569  std::vector<std::vector<dof_id_type>> & line_elems)
570 {
571  unsigned int max_dist_node = 0;
572  Real min_dist = std::numeric_limits<Real>::max();
573  Real max_dist = -std::numeric_limits<Real>::max();
574  // Pick the node farthest from the origin as the end node, or the one with
575  // the greatest x coordinate if the nodes are equidistant from the origin
576  for (std::set<dof_id_type>::iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
577  {
578  Node & node = _mesh.nodeRef(*nit);
579  Real dist = node.norm();
580  if (dist > max_dist)
581  {
582  max_dist = dist;
583  max_dist_node = *nit;
584  }
585  else if (dist < min_dist)
586  min_dist = dist;
587  }
588 
589  unsigned int end_node;
590  if (MooseUtils::absoluteFuzzyGreaterThan(max_dist, min_dist, _tol))
591  end_node = max_dist_node;
592  else
593  {
594  std::vector<Node *> node_vec;
595  for (std::set<dof_id_type>::iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
596  node_vec.push_back(_mesh.nodePtr(*nit));
597  end_node = maxNodeCoor(node_vec);
598  }
599 
600  end_nodes.push_back(end_node);
601 
602  // Find the two nodes connected to the node identified as the end node, and pick one of those to
603  // be the other end node
604  std::vector<dof_id_type> end_node_line_elems = node_to_line_elem_map[end_node];
605  if (end_node_line_elems.size() != 2)
606  mooseError(
607  "Crack front nodes are in a loop, but crack end node is only connected to one other node");
608  std::vector<Node *> candidate_other_end_nodes;
609 
610  for (unsigned int i = 0; i < 2; ++i)
611  {
612  std::vector<dof_id_type> end_line_elem = line_elems[end_node_line_elems[i]];
613  for (unsigned int j = 0; j < end_line_elem.size(); ++j)
614  {
615  unsigned int line_elem_node = end_line_elem[j];
616  if (line_elem_node != end_node)
617  candidate_other_end_nodes.push_back(_mesh.nodePtr(line_elem_node));
618  }
619  }
620  if (candidate_other_end_nodes.size() != 2)
621  mooseError(
622  "Crack front nodes are in a loop, but crack end node is not connected to two other nodes");
623  end_nodes.push_back(maxNodeCoor(candidate_other_end_nodes, 1));
624 }
625 
626 unsigned int
627 CrackFrontDefinition::maxNodeCoor(std::vector<Node *> & nodes, unsigned int dir0)
628 {
629  Real dirs[3];
630  if (dir0 == 0)
631  {
632  dirs[0] = 0;
633  dirs[1] = 1;
634  dirs[2] = 2;
635  }
636  else if (dir0 == 1)
637  {
638  dirs[0] = 1;
639  dirs[1] = 2;
640  dirs[2] = 0;
641  }
642  else if (dir0 == 2)
643  {
644  dirs[0] = 2;
645  dirs[1] = 0;
646  dirs[2] = 1;
647  }
648  else
649  mooseError("Invalid dir0 in CrackFrontDefinition::maxNodeCoor()");
650 
651  Real max_coor0 = -std::numeric_limits<Real>::max();
652  std::vector<Node *> max_coor0_nodes;
653  for (unsigned int i = 0; i < nodes.size(); ++i)
654  {
655  Real coor0 = (*nodes[i])(dirs[0]);
656  if (coor0 > max_coor0)
657  max_coor0 = coor0;
658  }
659  for (unsigned int i = 0; i < nodes.size(); ++i)
660  {
661  Real coor0 = (*nodes[i])(dirs[0]);
662  if (MooseUtils::absoluteFuzzyEqual(coor0, max_coor0, _tol))
663  max_coor0_nodes.push_back(nodes[i]);
664  }
665  if (max_coor0_nodes.size() > 1)
666  {
667  Real max_coor1 = -std::numeric_limits<Real>::max();
668  std::vector<Node *> max_coor1_nodes;
669  for (unsigned int i = 0; i < nodes.size(); ++i)
670  {
671  Real coor1 = (*nodes[i])(dirs[1]);
672  if (coor1 > max_coor1)
673  max_coor1 = coor1;
674  }
675  for (unsigned int i = 0; i < nodes.size(); ++i)
676  {
677  Real coor1 = (*nodes[i])(dirs[1]);
678  if (MooseUtils::absoluteFuzzyEqual(coor1, max_coor1, _tol))
679  max_coor1_nodes.push_back(nodes[i]);
680  }
681  if (max_coor1_nodes.size() > 1)
682  {
683  Real max_coor2 = -std::numeric_limits<Real>::max();
684  std::vector<Node *> max_coor2_nodes;
685  for (unsigned int i = 0; i < nodes.size(); ++i)
686  {
687  Real coor2 = (*nodes[i])(dirs[2]);
688  if (coor2 > max_coor2)
689  max_coor2 = coor2;
690  }
691  for (unsigned int i = 0; i < nodes.size(); ++i)
692  {
693  Real coor2 = (*nodes[i])(dirs[2]);
694  if (MooseUtils::absoluteFuzzyEqual(coor2, max_coor2, _tol))
695  max_coor2_nodes.push_back(nodes[i]);
696  }
697  if (max_coor2_nodes.size() > 1)
698  mooseError("Multiple nodes with same x,y,z coordinates within tolerance");
699  else
700  return max_coor2_nodes[0]->id();
701  }
702  else
703  return max_coor1_nodes[0]->id();
704  }
705  else
706  return max_coor0_nodes[0]->id();
707 }
708 
709 void
711 {
713 
714  _segment_lengths.clear();
715  _distances_along_front.clear();
716  _angles_along_front.clear();
717  _tangent_directions.clear();
718  _crack_directions.clear();
719  _rot_matrix.clear();
720 
721  if (_treat_as_2d)
722  {
723  RealVectorValue tangent_direction;
724  RealVectorValue crack_direction;
725  tangent_direction(_axis_2d) = 1.0;
726  _tangent_directions.push_back(tangent_direction);
727  const Point * crack_front_point = getCrackFrontPoint(0);
728  crack_direction =
729  calculateCrackFrontDirection(*crack_front_point, tangent_direction, MIDDLE_NODE);
730  _crack_directions.push_back(crack_direction);
731  _crack_plane_normal = tangent_direction.cross(crack_direction);
732  RankTwoTensor rot_mat;
733  rot_mat.fillRow(0, crack_direction);
734  rot_mat.fillRow(1, _crack_plane_normal);
735  rot_mat(2, _axis_2d) = 1.0;
736  _rot_matrix.push_back(rot_mat);
737 
738  _segment_lengths.push_back(std::make_pair(0.0, 0.0));
739  _distances_along_front.push_back(0.0);
740  _angles_along_front.push_back(0.0);
741  _overall_length = 0.0;
742  }
743  else
744  {
745  unsigned int num_crack_front_points = getNumCrackFrontPoints();
746  _segment_lengths.reserve(num_crack_front_points);
747  _tangent_directions.reserve(num_crack_front_points);
748  _crack_directions.reserve(num_crack_front_points);
749  _overall_length = 0.0;
750 
751  RealVectorValue back_segment;
752  Real back_segment_len = 0.0;
753  if (_closed_loop)
754  {
755  back_segment = *getCrackFrontPoint(0) - *getCrackFrontPoint(num_crack_front_points - 1);
756  back_segment_len = back_segment.norm();
757  }
758 
759  for (unsigned int i = 0; i < num_crack_front_points; ++i)
760  {
761  CRACK_NODE_TYPE ntype;
762  if (_closed_loop)
763  ntype = MIDDLE_NODE;
764  else if (i == 0)
765  ntype = END_1_NODE;
766  else if (i == num_crack_front_points - 1)
767  ntype = END_2_NODE;
768  else
769  ntype = MIDDLE_NODE;
770 
771  RealVectorValue forward_segment;
772  Real forward_segment_len;
773  if (ntype == END_2_NODE)
774  forward_segment_len = 0.0;
775  else if (_closed_loop && i == num_crack_front_points - 1)
776  {
777  forward_segment = *getCrackFrontPoint(0) - *getCrackFrontPoint(i);
778  forward_segment_len = forward_segment.norm();
779  }
780  else
781  {
782  forward_segment = *getCrackFrontPoint(i + 1) - *getCrackFrontPoint(i);
783  forward_segment_len = forward_segment.norm();
784  _overall_length += forward_segment_len;
785  }
786 
787  _segment_lengths.push_back(std::make_pair(back_segment_len, forward_segment_len));
788  if (i == 0)
789  _distances_along_front.push_back(0.0);
790  else
791  _distances_along_front.push_back(back_segment_len + _distances_along_front[i - 1]);
792 
793  RealVectorValue tangent_direction = back_segment + forward_segment;
794  tangent_direction = tangent_direction / tangent_direction.norm();
795  _tangent_directions.push_back(tangent_direction);
796  _crack_directions.push_back(
797  calculateCrackFrontDirection(*getCrackFrontPoint(i), tangent_direction, ntype));
798 
799  // If the end directions are given by the user, correct also the tangent at the end nodes
802  (ntype == END_1_NODE || ntype == END_2_NODE))
804 
805  back_segment = forward_segment;
806  back_segment_len = forward_segment_len;
807  }
808 
809  // For CURVED_CRACK_FRONT, _crack_plane_normal gets computed in updateDataForCrackDirection
811  {
812  unsigned int mid_id = (num_crack_front_points - 1) / 2;
814 
815  // Make sure the normal vector is non-zero
816  RealVectorValue zero_vec(0.0);
817  if (_crack_plane_normal.absolute_fuzzy_equals(zero_vec, _tol))
818  mooseError("Crack plane normal vector evaluates to zero");
819  }
820 
821  // Calculate angles of each point along the crack front for an elliptical crack projected
822  // to a circle.
823  if (hasAngleAlongFront())
824  {
825  RealVectorValue origin_to_first_node = *getCrackFrontPoint(0) - _crack_mouth_coordinates;
826  Real hyp = origin_to_first_node.norm();
827  RealVectorValue norm_origin_to_first_node = origin_to_first_node / hyp;
828  RealVectorValue tangent_to_first_node = -norm_origin_to_first_node.cross(_crack_plane_normal);
829  tangent_to_first_node /= tangent_to_first_node.norm();
830 
831  for (unsigned int i = 0; i < num_crack_front_points; ++i)
832  {
833  RealVectorValue origin_to_curr_node = *getCrackFrontPoint(i) - _crack_mouth_coordinates;
834 
835  Real adj = origin_to_curr_node * norm_origin_to_first_node;
836  Real opp = origin_to_curr_node * tangent_to_first_node;
837 
838  Real angle = acos(adj / hyp) * 180.0 / libMesh::pi;
839  if (opp < 0.0)
840  angle = 360.0 - angle;
841  _angles_along_front.push_back(angle);
842  }
843 
844  // Correct angle on end nodes if they are 0 or 360 to be consistent with neighboring node
845  if (num_crack_front_points > 1)
846  {
847  if (MooseUtils::absoluteFuzzyEqual(_angles_along_front[0], 0.0, _tol) &&
848  _angles_along_front[1] > 180.0)
849  _angles_along_front[0] = 360.0;
850  else if (MooseUtils::absoluteFuzzyEqual(_angles_along_front[0], 360.0, _tol) &&
851  _angles_along_front[1] < 180.0)
852  _angles_along_front[0] = 0.0;
853 
854  if (MooseUtils::absoluteFuzzyEqual(
855  _angles_along_front[num_crack_front_points - 1], 0.0, _tol) &&
856  _angles_along_front[num_crack_front_points - 2] > 180.0)
857  _angles_along_front[num_crack_front_points - 1] = 360.0;
858  else if (MooseUtils::absoluteFuzzyEqual(
859  _angles_along_front[num_crack_front_points - 1], 360.0, _tol) &&
860  _angles_along_front[num_crack_front_points - 2] < 180.0)
861  _angles_along_front[num_crack_front_points - 1] = 0.0;
862  }
863  }
864  else
865  _angles_along_front.resize(num_crack_front_points, 0.0);
866 
867  // Create rotation matrix
868  for (unsigned int i = 0; i < num_crack_front_points; ++i)
869  {
870  RankTwoTensor rot_mat;
871  rot_mat.fillRow(0, _crack_directions[i]);
872  rot_mat.fillRow(1, _crack_plane_normal);
873  rot_mat.fillRow(2, _tangent_directions[i]);
874  _rot_matrix.push_back(rot_mat);
875  }
876 
877  _console << "Summary of J-Integral crack front geometry:" << std::endl;
878  _console << "index node id x coord y coord z coord x dir y dir "
879  " z dir angle position seg length"
880  << std::endl;
881  for (unsigned int i = 0; i < num_crack_front_points; ++i)
882  {
883  unsigned int point_id;
885  point_id = _ordered_crack_front_nodes[i];
886  else
887  point_id = i;
888  _console << std::left << std::setw(8) << i + 1 << std::setw(10) << point_id << std::setw(14)
889  << (*getCrackFrontPoint(i))(0) << std::setw(14) << (*getCrackFrontPoint(i))(1)
890  << std::setw(14) << (*getCrackFrontPoint(i))(2) << std::setw(14)
891  << _crack_directions[i](0) << std::setw(14) << _crack_directions[i](1)
892  << std::setw(14) << _crack_directions[i](2);
893  if (hasAngleAlongFront())
894  _console << std::left << std::setw(14) << _angles_along_front[i];
895  else
896  _console << std::left << std::setw(14) << "--";
897  _console << std::left << std::setw(14) << _distances_along_front[i] << std::setw(14)
898  << (_segment_lengths[i].first + _segment_lengths[i].second) / 2.0 << std::endl;
899  }
900  _console << "overall length: " << _overall_length << std::endl;
901  }
902 }
903 
904 void
906 {
907  if (_crack_mouth_boundary_ids.size() > 0)
908  {
910 
911  std::set<Node *> crack_mouth_nodes;
912  ConstBndNodeRange & bnd_nodes = *_mesh.getBoundaryNodeRange();
913  for (ConstBndNodeRange::const_iterator nd = bnd_nodes.begin(); nd != bnd_nodes.end(); ++nd)
914  {
915  const BndNode * bnode = *nd;
916  BoundaryID boundary_id = bnode->_bnd_id;
917 
918  for (unsigned int ibid = 0; ibid < _crack_mouth_boundary_ids.size(); ++ibid)
919  {
920  if (boundary_id == _crack_mouth_boundary_ids[ibid])
921  {
922  crack_mouth_nodes.insert(bnode->_node);
923  break;
924  }
925  }
926  }
927 
928  for (std::set<Node *>::iterator nit = crack_mouth_nodes.begin(); nit != crack_mouth_nodes.end();
929  ++nit)
930  {
931  _crack_mouth_coordinates += **nit;
932  }
933  _crack_mouth_coordinates /= static_cast<Real>(crack_mouth_nodes.size());
934 
937  }
938 
940  {
941  _crack_plane_normal.zero();
942 
943  // Get 3 nodes on crack front
944  unsigned int num_points = getNumCrackFrontPoints();
945  if (num_points < 3)
946  {
947  mooseError("Crack front must contain at least 3 nodes to use CurvedCrackFront option");
948  }
949  unsigned int start_id;
950  unsigned int mid_id;
951  unsigned int end_id;
952 
953  if (_closed_loop)
954  {
955  start_id = 0;
956  mid_id = (num_points - 1) / 3;
957  end_id = 2 * mid_id;
958  }
959  else
960  {
961  start_id = 0;
962  mid_id = (num_points - 1) / 2;
963  end_id = num_points - 1;
964  }
965  const Point * start = getCrackFrontPoint(start_id);
966  const Point * mid = getCrackFrontPoint(mid_id);
967  const Point * end = getCrackFrontPoint(end_id);
968 
969  // Create two vectors connecting them
970  RealVectorValue v1 = *mid - *start;
971  RealVectorValue v2 = *end - *mid;
972 
973  // Take cross product to get normal
974  _crack_plane_normal = v1.cross(v2);
976 
977  // Make sure they're not collinear
978  RealVectorValue zero_vec(0.0);
979  if (_crack_plane_normal.absolute_fuzzy_equals(zero_vec, _tol))
980  {
981  mooseError("Nodes on crack front are too close to being collinear");
982  }
983  }
984 }
985 
986 RealVectorValue
988  const RealVectorValue & tangent_direction,
989  const CRACK_NODE_TYPE ntype) const
990 {
991  RealVectorValue crack_dir;
992  RealVectorValue zero_vec(0.0);
993 
994  bool calc_dir = true;
996  {
997  if (ntype == END_1_NODE)
998  {
999  crack_dir = _crack_direction_vector_end_1;
1000  calc_dir = false;
1001  }
1002  else if (ntype == END_2_NODE)
1003  {
1004  crack_dir = _crack_direction_vector_end_2;
1005  calc_dir = false;
1006  }
1007  }
1008 
1009  if (calc_dir)
1010  {
1012  {
1013  crack_dir = _crack_direction_vector;
1014  }
1015  else if (_direction_method == CRACK_MOUTH)
1016  {
1017  if (_crack_mouth_coordinates.absolute_fuzzy_equals(crack_front_point, _tol))
1018  {
1019  mooseError("Crack mouth too close to crack front node");
1020  }
1021  RealVectorValue mouth_to_front = crack_front_point - _crack_mouth_coordinates;
1022 
1023  RealVectorValue crack_plane_normal = mouth_to_front.cross(tangent_direction);
1024  if (crack_plane_normal.absolute_fuzzy_equals(zero_vec, _tol))
1025  {
1026  mooseError(
1027  "Vector from crack mouth to crack front node is collinear with crack front segment");
1028  }
1029 
1030  crack_dir = tangent_direction.cross(crack_plane_normal);
1031  Real dotprod = crack_dir * mouth_to_front;
1032  if (dotprod < 0)
1033  {
1034  crack_dir = -crack_dir;
1035  }
1036  }
1038  {
1039  crack_dir = tangent_direction.cross(_crack_plane_normal);
1040  }
1041  }
1042  crack_dir = crack_dir.unit();
1043 
1044  return crack_dir;
1045 }
1046 
1047 const Node *
1048 CrackFrontDefinition::getCrackFrontNodePtr(const unsigned int node_index) const
1049 {
1050  mooseAssert(node_index < _ordered_crack_front_nodes.size(), "node_index out of range");
1051  const Node * crack_front_node = _mesh.nodePtr(_ordered_crack_front_nodes[node_index]);
1052  mooseAssert(crack_front_node != NULL, "invalid crack front node");
1053  return crack_front_node;
1054 }
1055 
1056 const Point *
1057 CrackFrontDefinition::getCrackFrontPoint(const unsigned int point_index) const
1058 {
1060  {
1061  return getCrackFrontNodePtr(point_index);
1062  }
1063  else
1064  {
1065  mooseAssert(point_index < _crack_front_points.size(), "point_index out of range");
1066  return &_crack_front_points[point_index];
1067  }
1068 }
1069 
1070 const RealVectorValue &
1071 CrackFrontDefinition::getCrackFrontTangent(const unsigned int point_index) const
1072 {
1073  mooseAssert(point_index < _tangent_directions.size(), "point_index out of range");
1074  return _tangent_directions[point_index];
1075 }
1076 
1077 Real
1078 CrackFrontDefinition::getCrackFrontForwardSegmentLength(const unsigned int point_index) const
1079 {
1080  return _segment_lengths[point_index].second;
1081 }
1082 
1083 Real
1085 {
1086  return _segment_lengths[point_index].first;
1087 }
1088 
1089 const RealVectorValue &
1090 CrackFrontDefinition::getCrackDirection(const unsigned int point_index) const
1091 {
1092  return _crack_directions[point_index];
1093 }
1094 
1095 Real
1096 CrackFrontDefinition::getDistanceAlongFront(const unsigned int point_index) const
1097 {
1098  return _distances_along_front[point_index];
1099 }
1100 
1101 bool
1103 {
1104  return (_crack_mouth_boundary_names.size() > 0);
1105 }
1106 
1107 Real
1108 CrackFrontDefinition::getAngleAlongFront(const unsigned int point_index) const
1109 {
1110  if (!hasAngleAlongFront())
1111  mooseError("In CrackFrontDefinition, Requested angle along crack front, but not available. "
1112  "Must specify crack_mouth_boundary.");
1113  return _angles_along_front[point_index];
1114 }
1115 
1116 unsigned int
1118 {
1120  return _ordered_crack_front_nodes.size();
1121  else
1122  return _crack_front_points.size();
1123 }
1124 
1125 RealVectorValue
1127  const unsigned int point_index) const
1128 {
1129  return _rot_matrix[point_index] * vector;
1130 }
1131 
1132 RealVectorValue
1134  const unsigned int point_index) const
1135 {
1136  RealVectorValue vec = _rot_matrix[point_index].transpose() * vector;
1137  return vec;
1138 }
1139 
1142  const unsigned int point_index) const
1143 {
1144  RankTwoTensor tmp_tensor(tensor);
1145  tmp_tensor.rotate(_rot_matrix[point_index]);
1146  return tmp_tensor;
1147 }
1148 
1149 void
1151  const unsigned int point_index,
1152  Real & r,
1153  Real & theta) const
1154 {
1155  unsigned int num_points = getNumCrackFrontPoints();
1156  Point closest_point(0.0);
1157  RealVectorValue closest_point_to_p;
1158 
1159  const Point * crack_front_point = getCrackFrontPoint(point_index);
1160  RealVectorValue crack_front_point_rot = rotateToCrackFrontCoords(*crack_front_point, point_index);
1161 
1162  RealVectorValue crack_front_edge =
1163  rotateToCrackFrontCoords(_tangent_directions[point_index], point_index);
1164 
1165  Point p_rot = rotateToCrackFrontCoords(qp, point_index);
1166  p_rot = p_rot - crack_front_point_rot;
1167 
1168  if (_treat_as_2d)
1169  {
1170  // In 2D, the closest node is the crack tip node and the position of the crack tip node is
1171  // (0,0,0) in the crack front coordinate system
1172  // In case this is a 3D mesh treated as 2D, project point onto same plane as crack front node.
1173  // Note: In the crack front coordinate system, z is always in the tangent direction to the crack
1174  // front
1175  p_rot(2) = closest_point(2);
1176  closest_point_to_p = p_rot;
1177 
1178  // Find r, the distance between the qp and the crack front
1179  RealVectorValue r_vec = p_rot;
1180  r = r_vec.norm();
1181  }
1182  else
1183  {
1184  // Loop over crack front points to find the one closest to the point qp
1185  Real min_dist = std::numeric_limits<Real>::max();
1186  for (unsigned int pit = 0; pit != num_points; ++pit)
1187  {
1188  const Point * crack_front_point = getCrackFrontPoint(pit);
1189  RealVectorValue crack_point_to_current_point = qp - *crack_front_point;
1190  Real dist = crack_point_to_current_point.norm();
1191 
1192  if (dist < min_dist)
1193  {
1194  min_dist = dist;
1195  closest_point = *crack_front_point;
1196  }
1197  }
1198 
1199  // Rotate coordinates to crack front coordinate system
1200  closest_point = rotateToCrackFrontCoords(closest_point, point_index);
1201  closest_point = closest_point - crack_front_point_rot;
1202 
1203  // Find r, the distance between the qp and the crack front
1204  Real edge_length_sq = crack_front_edge.norm_sq();
1205  closest_point_to_p = p_rot - closest_point;
1206  Real perp = crack_front_edge * closest_point_to_p;
1207  Real dist_along_edge = perp / edge_length_sq;
1208  RealVectorValue point_on_edge = closest_point + crack_front_edge * dist_along_edge;
1209  RealVectorValue r_vec = p_rot - point_on_edge;
1210  r = r_vec.norm();
1211  }
1212 
1213  // Find theta, the angle between r and the crack front plane
1214  RealVectorValue crack_plane_normal = rotateToCrackFrontCoords(_crack_plane_normal, point_index);
1215  Real p_to_plane_dist = std::abs(closest_point_to_p * crack_plane_normal);
1216 
1217  // Determine if qp is above or below the crack plane
1218  Real y_local = p_rot(1) - closest_point(1);
1219 
1220  // Determine if qp is in front of or behind the crack front
1221  RealVectorValue p2(p_rot);
1222  p2(1) = 0;
1223  RealVectorValue p2_vec = p2 - closest_point;
1224  Real ahead = crack_front_edge(2) * p2_vec(0) - crack_front_edge(0) * p2_vec(2);
1225 
1226  Real x_local(0);
1227  if (ahead >= 0)
1228  x_local = 1;
1229  else
1230  x_local = -1;
1231 
1232  // Calculate theta based on in which quadrant in the crack front coordinate
1233  // system the qp is located
1234  if (r > 0)
1235  {
1236  Real theta_quadrant1(0.0);
1237  if (MooseUtils::absoluteFuzzyEqual(r, p_to_plane_dist, _tol))
1238  theta_quadrant1 = 0.5 * libMesh::pi;
1239  else if (p_to_plane_dist > r)
1240  mooseError(
1241  "Invalid distance p_to_plane_dist in CrackFrontDefinition::calculateRThetaToCrackFront");
1242  else
1243  theta_quadrant1 = std::asin(p_to_plane_dist / r);
1244 
1245  if (x_local >= 0 && y_local >= 0)
1246  theta = theta_quadrant1;
1247 
1248  else if (x_local < 0 && y_local >= 0)
1249  theta = libMesh::pi - theta_quadrant1;
1250 
1251  else if (x_local < 0 && y_local < 0)
1252  theta = -(libMesh::pi - theta_quadrant1);
1253 
1254  else if (x_local >= 0 && y_local < 0)
1255  theta = -theta_quadrant1;
1256  }
1257  else if (r == 0)
1258  theta = 0;
1259  else
1260  mooseError("Invalid distance r in CrackFrontDefinition::calculateRThetaToCrackFront");
1261 }
1262 
1263 unsigned int
1264 CrackFrontDefinition::calculateRThetaToCrackFront(const Point qp, Real & r, Real & theta) const
1265 {
1266  unsigned int num_points = getNumCrackFrontPoints();
1267 
1268  // Loop over crack front points to find the one closest to the point qp
1269  Real min_dist = std::numeric_limits<Real>::max();
1270  unsigned int point_index = 0;
1271  for (unsigned int pit = 0; pit != num_points; ++pit)
1272  {
1273  const Point * crack_front_point = getCrackFrontPoint(pit);
1274  RealVectorValue crack_point_to_current_point = qp - *crack_front_point;
1275  Real dist = crack_point_to_current_point.norm();
1276 
1277  if (dist < min_dist)
1278  {
1279  min_dist = dist;
1280  point_index = pit;
1281  }
1282  }
1283 
1284  calculateRThetaToCrackFront(qp, point_index, r, theta);
1285 
1286  return point_index;
1287 }
1288 
1289 bool
1291 {
1292  bool is_on_boundary = false;
1293  mooseAssert(node, "Invalid node");
1294  dof_id_type node_id = node->id();
1295  for (unsigned int i = 0; i < _intersecting_boundary_ids.size(); ++i)
1296  {
1297  if (_mesh.isBoundaryNode(node_id, _intersecting_boundary_ids[i]))
1298  {
1299  is_on_boundary = true;
1300  break;
1301  }
1302  }
1303  return is_on_boundary;
1304 }
1305 
1306 bool
1308 {
1309  bool is_on_boundary = false;
1311  {
1312  const Node * crack_front_node = getCrackFrontNodePtr(point_index);
1313  is_on_boundary = isNodeOnIntersectingBoundary(crack_front_node);
1314  }
1315  else
1316  {
1317  // If the intersecting boundary option is used with crack front points, the
1318  // first and last points are assumed to be on the intersecting boundaries.
1319  unsigned int num_crack_front_points = getNumCrackFrontPoints();
1320  if (point_index == 0 || point_index == num_crack_front_points - 1)
1321  is_on_boundary = true;
1322  }
1323  return is_on_boundary;
1324 }
1325 
1326 void
1328 {
1329  RealVectorValue disp_current_node;
1330  RealVectorValue disp_previous_node;
1331  RealVectorValue disp_next_node;
1332 
1333  RealVectorValue forward_segment0;
1334  RealVectorValue forward_segment1;
1335  Real forward_segment0_len;
1336  Real forward_segment1_len;
1337  RealVectorValue back_segment0;
1338  RealVectorValue back_segment1;
1339  Real back_segment0_len;
1340  Real back_segment1_len;
1341 
1342  unsigned int num_crack_front_nodes = _ordered_crack_front_nodes.size();
1343  const Node * current_node;
1344  const Node * previous_node;
1345  const Node * next_node;
1346 
1347  // In finalize(), gatherMax builds and distributes the complete strain vector on all processors
1348  // -> reset the vector every time
1349  for (unsigned int i = 0; i < num_crack_front_nodes; ++i)
1350  _strain_along_front[i] = -std::numeric_limits<Real>::max();
1351 
1352  MooseVariable & disp_x_var = _subproblem.getStandardVariable(_tid, _disp_x_var_name);
1353  MooseVariable & disp_y_var = _subproblem.getStandardVariable(_tid, _disp_y_var_name);
1354  MooseVariable & disp_z_var = _subproblem.getStandardVariable(_tid, _disp_z_var_name);
1355 
1356  current_node = getCrackFrontNodePtr(0);
1357  if (current_node->processor_id() == processor_id())
1358  {
1359  disp_current_node(0) = disp_x_var.getNodalValue(*current_node);
1360  disp_current_node(1) = disp_y_var.getNodalValue(*current_node);
1361  disp_current_node(2) = disp_z_var.getNodalValue(*current_node);
1362 
1363  next_node = getCrackFrontNodePtr(1);
1364  disp_next_node(0) = disp_x_var.getNodalValue(*next_node);
1365  disp_next_node(1) = disp_y_var.getNodalValue(*next_node);
1366  disp_next_node(2) = disp_z_var.getNodalValue(*next_node);
1367 
1368  forward_segment0 = *next_node - *current_node;
1369  forward_segment0 = (forward_segment0 * _tangent_directions[0]) * _tangent_directions[0];
1370  forward_segment0_len = forward_segment0.norm();
1371 
1372  forward_segment1 = (*next_node + disp_next_node) - (*current_node + disp_current_node);
1373  forward_segment1 = (forward_segment1 * _tangent_directions[0]) * _tangent_directions[0];
1374  forward_segment1_len = forward_segment1.norm();
1375 
1376  _strain_along_front[0] = (forward_segment1_len - forward_segment0_len) / forward_segment0_len;
1377  }
1378 
1379  for (unsigned int i = 1; i < num_crack_front_nodes - 1; ++i)
1380  {
1381  current_node = getCrackFrontNodePtr(i);
1382  if (current_node->processor_id() == processor_id())
1383  {
1384  disp_current_node(0) = disp_x_var.getNodalValue(*current_node);
1385  disp_current_node(1) = disp_y_var.getNodalValue(*current_node);
1386  disp_current_node(2) = disp_z_var.getNodalValue(*current_node);
1387 
1388  previous_node = getCrackFrontNodePtr(i - 1);
1389  disp_previous_node(0) = disp_x_var.getNodalValue(*previous_node);
1390  disp_previous_node(1) = disp_y_var.getNodalValue(*previous_node);
1391  disp_previous_node(2) = disp_z_var.getNodalValue(*previous_node);
1392 
1393  next_node = getCrackFrontNodePtr(i + 1);
1394  disp_next_node(0) = disp_x_var.getNodalValue(*next_node);
1395  disp_next_node(1) = disp_y_var.getNodalValue(*next_node);
1396  disp_next_node(2) = disp_z_var.getNodalValue(*next_node);
1397 
1398  back_segment0 = *current_node - *previous_node;
1399  back_segment0 = (back_segment0 * _tangent_directions[i]) * _tangent_directions[i];
1400  back_segment0_len = back_segment0.norm();
1401 
1402  back_segment1 = (*current_node + disp_current_node) - (*previous_node + disp_previous_node);
1403  back_segment1 = (back_segment1 * _tangent_directions[i]) * _tangent_directions[i];
1404  back_segment1_len = back_segment1.norm();
1405 
1406  forward_segment0 = *next_node - *current_node;
1407  forward_segment0 = (forward_segment0 * _tangent_directions[i]) * _tangent_directions[i];
1408  forward_segment0_len = forward_segment0.norm();
1409 
1410  forward_segment1 = (*next_node + disp_next_node) - (*current_node + disp_current_node);
1411  forward_segment1 = (forward_segment1 * _tangent_directions[i]) * _tangent_directions[i];
1412  forward_segment1_len = forward_segment1.norm();
1413 
1414  _strain_along_front[i] =
1415  0.5 * ((back_segment1_len - back_segment0_len) / back_segment0_len +
1416  (forward_segment1_len - forward_segment0_len) / forward_segment0_len);
1417  }
1418  }
1419 
1420  current_node = getCrackFrontNodePtr(num_crack_front_nodes - 1);
1421  if (current_node->processor_id() == processor_id())
1422  {
1423  disp_current_node(0) = disp_x_var.getNodalValue(*current_node);
1424  disp_current_node(1) = disp_y_var.getNodalValue(*current_node);
1425  disp_current_node(2) = disp_z_var.getNodalValue(*current_node);
1426 
1427  previous_node = getCrackFrontNodePtr(num_crack_front_nodes - 2);
1428  disp_previous_node(0) = disp_x_var.getNodalValue(*previous_node);
1429  disp_previous_node(1) = disp_y_var.getNodalValue(*previous_node);
1430  disp_previous_node(2) = disp_z_var.getNodalValue(*previous_node);
1431 
1432  back_segment0 = *current_node - *previous_node;
1433  back_segment0 = (back_segment0 * _tangent_directions[num_crack_front_nodes - 1]) *
1434  _tangent_directions[num_crack_front_nodes - 1];
1435  back_segment0_len = back_segment0.norm();
1436 
1437  back_segment1 = (*current_node + disp_current_node) - (*previous_node + disp_previous_node);
1438  back_segment1 = (back_segment1 * _tangent_directions[num_crack_front_nodes - 1]) *
1439  _tangent_directions[num_crack_front_nodes - 1];
1440  back_segment1_len = back_segment1.norm();
1441 
1442  _strain_along_front[num_crack_front_nodes - 1] =
1443  (back_segment1_len - back_segment0_len) / back_segment0_len;
1444  }
1445 }
1446 
1447 Real
1448 CrackFrontDefinition::getCrackFrontTangentialStrain(const unsigned int node_index) const
1449 {
1450  Real strain;
1451  if (_t_stress)
1452  strain = _strain_along_front[node_index];
1453  else
1454  mooseError("In CrackFrontDefinition, tangential strain not available");
1455 
1456  return strain;
1457 }
1458 
1459 void
1461 {
1462  // In the variable names, "cfn" = crack front node
1463 
1464  if (_treat_as_2d) // 2D: the q-function defines an integral domain that is constant along the
1465  // crack front
1466  {
1467  std::vector<std::vector<const Elem *>> nodes_to_elem_map;
1468  MeshTools::build_nodes_to_elem_map(_mesh.getMesh(), nodes_to_elem_map);
1469 
1470  std::set<dof_id_type> nodes_prev_ring;
1471  nodes_prev_ring.insert(_ordered_crack_front_nodes.begin(), _ordered_crack_front_nodes.end());
1472 
1473  std::set<dof_id_type> connected_nodes_this_cfn;
1474  connected_nodes_this_cfn.insert(_ordered_crack_front_nodes.begin(),
1476 
1477  std::set<dof_id_type> old_ring_nodes_this_cfn = connected_nodes_this_cfn;
1478 
1479  // The first ring contains only the crack front node(s)
1480  std::pair<dof_id_type, unsigned int> node_ring_index =
1481  std::make_pair(_ordered_crack_front_nodes[0], 1);
1482  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1483  connected_nodes_this_cfn.end());
1484 
1485  // Build rings of nodes around the crack front node
1486  for (unsigned int ring = 2; ring <= _last_ring; ++ring)
1487  {
1488 
1489  // Find nodes connected to the nodes of the previous ring
1490  std::set<dof_id_type> new_ring_nodes_this_cfn;
1491  for (std::set<dof_id_type>::iterator nit = old_ring_nodes_this_cfn.begin();
1492  nit != old_ring_nodes_this_cfn.end();
1493  ++nit)
1494  {
1495  std::vector<const Node *> neighbors;
1496  MeshTools::find_nodal_neighbors(
1497  _mesh.getMesh(), _mesh.nodeRef(*nit), nodes_to_elem_map, neighbors);
1498  for (unsigned int inei = 0; inei < neighbors.size(); ++inei)
1499  {
1500  std::set<dof_id_type>::iterator thisit =
1501  connected_nodes_this_cfn.find(neighbors[inei]->id());
1502 
1503  // Add only nodes that are not already present in any of the rings
1504  if (thisit == connected_nodes_this_cfn.end())
1505  new_ring_nodes_this_cfn.insert(neighbors[inei]->id());
1506  }
1507  }
1508 
1509  // Add new nodes to rings
1510  connected_nodes_this_cfn.insert(new_ring_nodes_this_cfn.begin(),
1511  new_ring_nodes_this_cfn.end());
1512  old_ring_nodes_this_cfn = new_ring_nodes_this_cfn;
1513 
1514  std::pair<dof_id_type, unsigned int> node_ring_index =
1515  std::make_pair(_ordered_crack_front_nodes[0], ring);
1516  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1517  connected_nodes_this_cfn.end());
1518  }
1519  }
1520  else // 3D: The q-function defines one integral domain around each crack front node
1521  {
1522  unsigned int num_crack_front_points = _ordered_crack_front_nodes.size();
1523  std::vector<std::vector<const Elem *>> nodes_to_elem_map;
1524  MeshTools::build_nodes_to_elem_map(_mesh.getMesh(), nodes_to_elem_map);
1525  for (unsigned int icfn = 0; icfn < num_crack_front_points; ++icfn)
1526  {
1527  std::set<dof_id_type> nodes_prev_ring;
1528  nodes_prev_ring.insert(_ordered_crack_front_nodes[icfn]);
1529 
1530  std::set<dof_id_type> connected_nodes_prev_cfn;
1531  std::set<dof_id_type> connected_nodes_this_cfn;
1532  std::set<dof_id_type> connected_nodes_next_cfn;
1533 
1534  connected_nodes_this_cfn.insert(_ordered_crack_front_nodes[icfn]);
1535 
1536  if (_closed_loop && icfn == 0)
1537  {
1538  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[num_crack_front_points - 1]);
1539  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[icfn + 1]);
1540  }
1541  else if (_closed_loop && icfn == num_crack_front_points - 1)
1542  {
1543  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[icfn - 1]);
1544  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[0]);
1545  }
1546  else if (icfn == 0)
1547  {
1548  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[icfn + 1]);
1549  }
1550  else if (icfn == num_crack_front_points - 1)
1551  {
1552  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[icfn - 1]);
1553  }
1554  else
1555  {
1556  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[icfn - 1]);
1557  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[icfn + 1]);
1558  }
1559 
1560  std::set<dof_id_type> old_ring_nodes_prev_cfn = connected_nodes_prev_cfn;
1561  std::set<dof_id_type> old_ring_nodes_this_cfn = connected_nodes_this_cfn;
1562  std::set<dof_id_type> old_ring_nodes_next_cfn = connected_nodes_next_cfn;
1563 
1564  // The first ring contains only the crack front node
1565  std::pair<dof_id_type, unsigned int> node_ring_index =
1566  std::make_pair(_ordered_crack_front_nodes[icfn], 1);
1567  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1568  connected_nodes_this_cfn.end());
1569 
1570  // Build rings of nodes around the crack front node
1571  for (unsigned int ring = 2; ring <= _last_ring; ++ring)
1572  {
1573 
1574  // Find nodes connected to the nodes of the previous ring, but exclude nodes in rings of
1575  // neighboring crack front nodes
1576  std::set<dof_id_type> new_ring_nodes_this_cfn;
1577  addNodesToQFunctionRing(new_ring_nodes_this_cfn,
1578  old_ring_nodes_this_cfn,
1579  connected_nodes_this_cfn,
1580  connected_nodes_prev_cfn,
1581  connected_nodes_next_cfn,
1582  nodes_to_elem_map);
1583 
1584  std::set<dof_id_type> new_ring_nodes_prev_cfn;
1585  addNodesToQFunctionRing(new_ring_nodes_prev_cfn,
1586  old_ring_nodes_prev_cfn,
1587  connected_nodes_prev_cfn,
1588  connected_nodes_this_cfn,
1589  connected_nodes_next_cfn,
1590  nodes_to_elem_map);
1591 
1592  std::set<dof_id_type> new_ring_nodes_next_cfn;
1593  addNodesToQFunctionRing(new_ring_nodes_next_cfn,
1594  old_ring_nodes_next_cfn,
1595  connected_nodes_next_cfn,
1596  connected_nodes_prev_cfn,
1597  connected_nodes_this_cfn,
1598  nodes_to_elem_map);
1599 
1600  // Add new nodes to the three sets of nodes
1601  connected_nodes_prev_cfn.insert(new_ring_nodes_prev_cfn.begin(),
1602  new_ring_nodes_prev_cfn.end());
1603  connected_nodes_this_cfn.insert(new_ring_nodes_this_cfn.begin(),
1604  new_ring_nodes_this_cfn.end());
1605  connected_nodes_next_cfn.insert(new_ring_nodes_next_cfn.begin(),
1606  new_ring_nodes_next_cfn.end());
1607  old_ring_nodes_prev_cfn = new_ring_nodes_prev_cfn;
1608  old_ring_nodes_this_cfn = new_ring_nodes_this_cfn;
1609  old_ring_nodes_next_cfn = new_ring_nodes_next_cfn;
1610 
1611  std::pair<dof_id_type, unsigned int> node_ring_index =
1612  std::make_pair(_ordered_crack_front_nodes[icfn], ring);
1613  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1614  connected_nodes_this_cfn.end());
1615  }
1616  }
1617  }
1618 }
1619 
1620 void
1622  std::set<dof_id_type> & nodes_new_ring,
1623  const std::set<dof_id_type> & nodes_old_ring,
1624  const std::set<dof_id_type> & nodes_all_rings,
1625  const std::set<dof_id_type> & nodes_neighbor1,
1626  const std::set<dof_id_type> & nodes_neighbor2,
1627  std::vector<std::vector<const Elem *>> & nodes_to_elem_map)
1628 {
1629  for (std::set<dof_id_type>::const_iterator nit = nodes_old_ring.begin();
1630  nit != nodes_old_ring.end();
1631  ++nit)
1632  {
1633  std::vector<const Node *> neighbors;
1634  MeshTools::find_nodal_neighbors(
1635  _mesh.getMesh(), _mesh.nodeRef(*nit), nodes_to_elem_map, neighbors);
1636  for (unsigned int inei = 0; inei < neighbors.size(); ++inei)
1637  {
1638  std::set<dof_id_type>::const_iterator previt = nodes_all_rings.find(neighbors[inei]->id());
1639  std::set<dof_id_type>::const_iterator thisit = nodes_neighbor1.find(neighbors[inei]->id());
1640  std::set<dof_id_type>::const_iterator nextit = nodes_neighbor2.find(neighbors[inei]->id());
1641 
1642  // Add only nodes that are not already present in any of the three sets of nodes
1643  if (previt == nodes_all_rings.end() && thisit == nodes_neighbor1.end() &&
1644  nextit == nodes_neighbor2.end())
1645  nodes_new_ring.insert(neighbors[inei]->id());
1646  }
1647  }
1648 }
1649 
1650 bool
1651 CrackFrontDefinition::isNodeInRing(const unsigned int ring_index,
1652  const dof_id_type connected_node_id,
1653  const unsigned int node_index) const
1654 {
1655  bool is_node_in_ring = false;
1656  std::pair<dof_id_type, unsigned int> node_ring_key =
1657  std::make_pair(_ordered_crack_front_nodes[node_index], ring_index);
1658  std::map<std::pair<dof_id_type, unsigned int>, std::set<dof_id_type>>::const_iterator nnmit =
1659  _crack_front_node_to_node_map.find(node_ring_key);
1660 
1661  if (nnmit == _crack_front_node_to_node_map.end())
1662  mooseError("Could not find crack front node ",
1663  _ordered_crack_front_nodes[node_index],
1664  "in the crack front node to q-function ring-node map for ring ",
1665  ring_index);
1666 
1667  std::set<dof_id_type> q_func_nodes = nnmit->second;
1668  if (q_func_nodes.find(connected_node_id) != q_func_nodes.end())
1669  is_node_in_ring = true;
1670 
1671  return is_node_in_ring;
1672 }
1673 
1674 Real
1675 CrackFrontDefinition::DomainIntegralQFunction(unsigned int crack_front_point_index,
1676  unsigned int ring_index,
1677  const Node * const current_node) const
1678 {
1679  Real dist_to_crack_front;
1680  Real dist_along_tangent;
1682  dist_to_crack_front, dist_along_tangent, crack_front_point_index, current_node);
1683 
1684  Real q = 1.0;
1685  if (dist_to_crack_front > _j_integral_radius_inner[ring_index] &&
1686  dist_to_crack_front < _j_integral_radius_outer[ring_index])
1687  q = (_j_integral_radius_outer[ring_index] - dist_to_crack_front) /
1688  (_j_integral_radius_outer[ring_index] - _j_integral_radius_inner[ring_index]);
1689  else if (dist_to_crack_front >= _j_integral_radius_outer[ring_index])
1690  q = 0.0;
1691 
1692  if (q > 0.0)
1693  {
1694  Real tangent_multiplier = 1.0;
1695  if (!_treat_as_2d)
1696  {
1697  const Real forward_segment_length =
1698  getCrackFrontForwardSegmentLength(crack_front_point_index);
1699  const Real backward_segment_length =
1700  getCrackFrontBackwardSegmentLength(crack_front_point_index);
1701 
1702  if (dist_along_tangent >= 0.0)
1703  {
1704  if (forward_segment_length > 0.0)
1705  tangent_multiplier = 1.0 - dist_along_tangent / forward_segment_length;
1706  }
1707  else
1708  {
1709  if (backward_segment_length > 0.0)
1710  tangent_multiplier = 1.0 + dist_along_tangent / backward_segment_length;
1711  }
1712  }
1713 
1714  tangent_multiplier = std::max(tangent_multiplier, 0.0);
1715  tangent_multiplier = std::min(tangent_multiplier, 1.0);
1716 
1717  // Set to zero if a node is on a designated free surface and its crack front node is not.
1718  if (isNodeOnIntersectingBoundary(current_node) &&
1719  !_is_point_on_intersecting_boundary[crack_front_point_index])
1720  tangent_multiplier = 0.0;
1721 
1722  q *= tangent_multiplier;
1723  }
1724 
1725  return q;
1726 }
1727 
1728 Real
1730  unsigned int ring_index,
1731  const Node * const current_node) const
1732 {
1733  Real q = 0;
1734  bool is_node_in_ring = isNodeInRing(ring_index, current_node->id(), crack_front_point_index);
1735  if (is_node_in_ring)
1736  q = 1;
1737 
1738  return q;
1739 }
1740 
1741 void
1743  Real & dist_along_tangent,
1744  unsigned int crack_front_point_index,
1745  const Node * const current_node) const
1746 {
1747  const Point * crack_front_point = getCrackFrontPoint(crack_front_point_index);
1748 
1749  Point p = *current_node;
1750  const RealVectorValue & crack_front_tangent = getCrackFrontTangent(crack_front_point_index);
1751 
1752  RealVectorValue crack_node_to_current_node = p - *crack_front_point;
1753  dist_along_tangent = crack_node_to_current_node * crack_front_tangent;
1754  RealVectorValue projection_point = *crack_front_point + dist_along_tangent * crack_front_tangent;
1755  RealVectorValue axis_to_current_node = p - projection_point;
1756  dist_to_front = axis_to_current_node.norm();
1757 }
CrackFrontDefinition::_mesh
MooseMesh & _mesh
Definition: CrackFrontDefinition.h:129
CrackFrontDefinition::createQFunctionRings
void createQFunctionRings()
Definition: CrackFrontDefinition.C:1460
CrackFrontDefinition::END_1_NODE
Definition: CrackFrontDefinition.h:118
CrackFrontDefinition::pickLoopCrackEndNodes
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)
Definition: CrackFrontDefinition.C:565
CrackFrontDefinition::_axis_2d
unsigned int _axis_2d
Definition: CrackFrontDefinition.h:156
CrackFrontDefinition::_last_ring
unsigned int _last_ring
Definition: CrackFrontDefinition.h:164
CrackFrontDefinition::_ordered_crack_front_nodes
std::vector< unsigned int > _ordered_crack_front_nodes
Definition: CrackFrontDefinition.h:132
CrackFrontDefinition::_j_integral_radius_outer
std::vector< Real > _j_integral_radius_outer
Definition: CrackFrontDefinition.h:171
CrackFrontDefinition::_angles_along_front
std::vector< Real > _angles_along_front
Definition: CrackFrontDefinition.h:139
CrackFrontDefinition::getCrackFrontNodePtr
const Node * getCrackFrontNodePtr(const unsigned int node_index) const
Definition: CrackFrontDefinition.C:1048
CrackFrontDefinition::getCrackFrontTangent
const RealVectorValue & getCrackFrontTangent(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1071
CrackFrontDefinition::calculateCrackFrontDirection
RealVectorValue calculateCrackFrontDirection(const Point &crack_front_point, const RealVectorValue &tangent_direction, const CRACK_NODE_TYPE ntype) const
Definition: CrackFrontDefinition.C:987
CrackFrontDefinition::initialize
virtual void initialize()
Definition: CrackFrontDefinition.C:298
CrackFrontDefinition::_crack_mouth_boundary_names
std::vector< BoundaryName > _crack_mouth_boundary_names
Definition: CrackFrontDefinition.h:148
CrackFrontDefinition::addNodesToQFunctionRing
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)
Definition: CrackFrontDefinition.C:1621
CrackFrontDefinition::_intersecting_boundary_names
std::vector< BoundaryName > _intersecting_boundary_names
Definition: CrackFrontDefinition.h:150
CrackFrontDefinition::maxNodeCoor
unsigned int maxNodeCoor(std::vector< Node * > &nodes, unsigned int dir0=0)
Definition: CrackFrontDefinition.C:627
CrackFrontDefinition::DomainIntegralQFunction
Real DomainIntegralQFunction(unsigned int crack_front_point_index, unsigned int ring_index, const Node *const current_node) const
Definition: CrackFrontDefinition.C:1675
CrackFrontDefinition::calculateTangentialStrainAlongFront
void calculateTangentialStrainAlongFront()
Definition: CrackFrontDefinition.C:1327
CrackFrontDefinition::_tol
static const Real _tol
Definition: CrackFrontDefinition.h:130
CrackFrontDefinition::validParams
static InputParameters validParams()
Definition: CrackFrontDefinition.C:26
CrackFrontDefinition::CURVED_CRACK_FRONT
Definition: CrackFrontDefinition.h:106
CrackFrontDefinition::_crack_direction_vector_end_2
RealVectorValue _crack_direction_vector_end_2
Definition: CrackFrontDefinition.h:147
CrackFrontDefinition::_crack_front_points
std::vector< Point > _crack_front_points
Definition: CrackFrontDefinition.h:134
CrackFrontDefinition::isNodeOnIntersectingBoundary
bool isNodeOnIntersectingBoundary(const Node *const node) const
Definition: CrackFrontDefinition.C:1290
CrackFrontDefinition::isNodeInRing
bool isNodeInRing(const unsigned int ring_index, const dof_id_type connected_node_id, const unsigned int node_index) const
Definition: CrackFrontDefinition.C:1651
CrackFrontDefinition::CRACK_NODE_TYPE
CRACK_NODE_TYPE
Definition: CrackFrontDefinition.h:115
CrackFrontDefinition
Works on top of NodalNormalsPreprocessor.
Definition: CrackFrontDefinition.h:36
CrackFrontDefinition::_q_function_rings
bool _q_function_rings
Definition: CrackFrontDefinition.h:163
CrackFrontDefinition::_strain_along_front
std::vector< Real > _strain_along_front
Definition: CrackFrontDefinition.h:140
CrackFrontDefinition::getCrackFrontTangentialStrain
Real getCrackFrontTangentialStrain(const unsigned int node_index) const
Definition: CrackFrontDefinition.C:1448
CrackFrontDefinition::DIRECTION_METHOD
DIRECTION_METHOD
Definition: CrackFrontDefinition.h:102
CrackFrontDefinition::_first_ring
unsigned int _first_ring
Definition: CrackFrontDefinition.h:165
CrackFrontDefinition::_distances_along_front
std::vector< Real > _distances_along_front
Definition: CrackFrontDefinition.h:138
CrackFrontDefinition::execute
virtual void execute()
Definition: CrackFrontDefinition.C:243
CrackFrontDefinition::orderEndNodes
void orderEndNodes(std::vector< dof_id_type > &end_nodes)
Definition: CrackFrontDefinition.C:515
CrackFrontDefinition.h
CrackFrontDefinition::CRACK_FRONT_POINTS
Definition: CrackFrontDefinition.h:125
CrackFrontDefinition::_j_integral_radius_inner
std::vector< Real > _j_integral_radius_inner
Definition: CrackFrontDefinition.h:170
CrackFrontDefinition::~CrackFrontDefinition
virtual ~CrackFrontDefinition()
Definition: CrackFrontDefinition.C:240
CrackFrontDefinition::isPointWithIndexOnIntersectingBoundary
bool isPointWithIndexOnIntersectingBoundary(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1307
CrackFrontDefinition::END_CRACK_DIRECTION_VECTOR
Definition: CrackFrontDefinition.h:112
CrackFrontDefinition::hasAngleAlongFront
bool hasAngleAlongFront() const
Definition: CrackFrontDefinition.C:1102
CrackFrontDefinition::updateCrackFrontGeometry
void updateCrackFrontGeometry()
Definition: CrackFrontDefinition.C:710
CrackFrontDefinition::_crack_mouth_boundary_ids
std::vector< BoundaryID > _crack_mouth_boundary_ids
Definition: CrackFrontDefinition.h:149
CrackFrontDefinition::_disp_y_var_name
std::string _disp_y_var_name
Definition: CrackFrontDefinition.h:160
CrackFrontDefinition::_t_stress
bool _t_stress
Definition: CrackFrontDefinition.h:162
addCrackFrontDefinitionParams
void addCrackFrontDefinitionParams(InputParameters &params)
Definition: CrackFrontDefinition.C:38
CrackFrontDefinition::getCrackFrontPoint
const Point * getCrackFrontPoint(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1057
CrackFrontPointsProvider::getCrackFrontPoints
virtual const std::vector< Point > getCrackFrontPoints(unsigned int) const =0
get a set of points along a crack front from a XFEM GeometricCutUserObject
CrackFrontDefinition::updateDataForCrackDirection
void updateDataForCrackDirection()
Definition: CrackFrontDefinition.C:905
CrackFrontDefinition::DomainIntegralTopologicalQFunction
Real DomainIntegralTopologicalQFunction(unsigned int crack_front_point_index, unsigned int ring_index, const Node *const current_node) const
Definition: CrackFrontDefinition.C:1729
CrackFrontDefinition::rotateFromCrackFrontCoordsToGlobal
RealVectorValue rotateFromCrackFrontCoordsToGlobal(const RealVectorValue vector, const unsigned int point_index) const
rotate a vector from crack front cartesian coordinate to global cartesian coordinate
Definition: CrackFrontDefinition.C:1133
CrackFrontDefinition::_crack_front_node_to_node_map
std::map< std::pair< dof_id_type, unsigned int >, std::set< dof_id_type > > _crack_front_node_to_node_map
Definition: CrackFrontDefinition.h:167
CrackFrontDefinition::_num_points_from_provider
unsigned int _num_points_from_provider
Definition: CrackFrontDefinition.h:173
defineLegacyParams
defineLegacyParams(CrackFrontDefinition)
CrackFrontDefinition::_crack_mouth_coordinates
RealVectorValue _crack_mouth_coordinates
Definition: CrackFrontDefinition.h:152
CrackFrontDefinition::_intersecting_boundary_ids
std::vector< BoundaryID > _intersecting_boundary_ids
Definition: CrackFrontDefinition.h:151
CrackFrontDefinition::_crack_directions
std::vector< RealVectorValue > _crack_directions
Definition: CrackFrontDefinition.h:136
CrackFrontDefinition::calculateRThetaToCrackFront
void calculateRThetaToCrackFront(const Point qp, const unsigned int point_index, Real &r, Real &theta) const
calculate r and theta in the crack front polar coordinates
Definition: CrackFrontDefinition.C:1150
CrackFrontDefinition::getNumCrackFrontPoints
unsigned int getNumCrackFrontPoints() const
Definition: CrackFrontDefinition.C:1117
validParams
InputParameters validParams()
CrackFrontDefinition::getCrackDirection
const RealVectorValue & getCrackDirection(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1090
registerMooseObject
registerMooseObject("TensorMechanicsApp", CrackFrontDefinition)
CrackFrontDefinition::_end_direction_method
END_DIRECTION_METHOD _end_direction_method
Definition: CrackFrontDefinition.h:144
CrackFrontDefinition::CRACK_DIRECTION_VECTOR
Definition: CrackFrontDefinition.h:104
CrackFrontDefinition::_disp_z_var_name
std::string _disp_z_var_name
Definition: CrackFrontDefinition.h:161
CrackFrontDefinition::getCrackFrontNodes
void getCrackFrontNodes(std::set< dof_id_type > &nodes)
Definition: CrackFrontDefinition.C:310
CrackFrontDefinition::_q_function_type
MooseEnum _q_function_type
Definition: CrackFrontDefinition.h:168
CrackFrontDefinition::_crack_direction_vector
RealVectorValue _crack_direction_vector
Definition: CrackFrontDefinition.h:145
CrackFrontDefinition::initialSetup
virtual void initialSetup()
Definition: CrackFrontDefinition.C:252
CrackFrontDefinition::_rot_matrix
std::vector< RankTwoTensor > _rot_matrix
Definition: CrackFrontDefinition.h:141
CrackFrontDefinition::rotateToCrackFrontCoords
RealVectorValue rotateToCrackFrontCoords(const RealVectorValue vector, const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1126
CrackFrontDefinition::getDistanceAlongFront
Real getDistanceAlongFront(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1096
CrackFrontDefinition::END_DIRECTION_METHOD
END_DIRECTION_METHOD
Definition: CrackFrontDefinition.h:109
CrackFrontDefinition::CRACK_FRONT_NODES
Definition: CrackFrontDefinition.h:124
CrackFrontDefinition::_overall_length
Real _overall_length
Definition: CrackFrontDefinition.h:142
CrackFrontDefinition::CRACK_MOUTH
Definition: CrackFrontDefinition.h:105
CrackFrontDefinition::projectToFrontAtPoint
void projectToFrontAtPoint(Real &dist_to_front, Real &dist_along_tangent, unsigned int crack_front_point_index, const Node *const current_node) const
Definition: CrackFrontDefinition.C:1742
CrackFrontDefinition::orderCrackFrontNodes
void orderCrackFrontNodes(std::set< dof_id_type > &nodes)
Definition: CrackFrontDefinition.C:375
CrackFrontDefinition::_geom_definition_method
CRACK_GEOM_DEFINITION _geom_definition_method
Definition: CrackFrontDefinition.h:133
CrackFrontDefinition::_crack_front_points_provider
const CrackFrontPointsProvider * _crack_front_points_provider
Definition: CrackFrontDefinition.h:172
CrackFrontDefinition::_tangent_directions
std::vector< RealVectorValue > _tangent_directions
Definition: CrackFrontDefinition.h:135
CrackFrontDefinition::_crack_plane_normal
RealVectorValue _crack_plane_normal
Definition: CrackFrontDefinition.h:153
RankTwoTensorTempl< Real >
CrackFrontDefinition::MIDDLE_NODE
Definition: CrackFrontDefinition.h:117
CrackFrontDefinition::getAngleAlongFront
Real getAngleAlongFront(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1108
CrackFrontDefinition::getCrackFrontBackwardSegmentLength
Real getCrackFrontBackwardSegmentLength(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1084
CrackFrontDefinition::_is_point_on_intersecting_boundary
std::vector< bool > _is_point_on_intersecting_boundary
Definition: CrackFrontDefinition.h:169
CrackFrontDefinition::finalize
virtual void finalize()
Definition: CrackFrontDefinition.C:303
CrackFrontDefinition::END_2_NODE
Definition: CrackFrontDefinition.h:119
CrackFrontDefinition::_closed_loop
bool _closed_loop
Definition: CrackFrontDefinition.h:155
CrackFrontDefinition::_treat_as_2d
bool _treat_as_2d
Definition: CrackFrontDefinition.h:154
CrackFrontDefinition::_segment_lengths
std::vector< std::pair< Real, Real > > _segment_lengths
Definition: CrackFrontDefinition.h:137
CrackFrontDefinition::_direction_method
DIRECTION_METHOD _direction_method
Definition: CrackFrontDefinition.h:143
CrackFrontDefinition::getCrackFrontForwardSegmentLength
Real getCrackFrontForwardSegmentLength(const unsigned int point_index) const
Definition: CrackFrontDefinition.C:1078
CrackFrontDefinition::_has_symmetry_plane
bool _has_symmetry_plane
Definition: CrackFrontDefinition.h:157
CrackFrontDefinition::_disp_x_var_name
std::string _disp_x_var_name
Definition: CrackFrontDefinition.h:159
CrackFrontDefinition::_crack_direction_vector_end_1
RealVectorValue _crack_direction_vector_end_1
Definition: CrackFrontDefinition.h:146
CrackFrontDefinition::_symmetry_plane
unsigned int _symmetry_plane
Definition: CrackFrontDefinition.h:158
CrackFrontDefinition::CrackFrontDefinition
CrackFrontDefinition(const InputParameters &parameters)
Definition: CrackFrontDefinition.C:102