www.mooseframework.org
Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes | Static Protected Attributes | List of all members
CrackFrontDefinition Class Reference

Works on top of NodalNormalsPreprocessor. More...

#include <CrackFrontDefinition.h>

Inheritance diagram for CrackFrontDefinition:
[legend]

Public Member Functions

 CrackFrontDefinition (const InputParameters &parameters)
 
virtual ~CrackFrontDefinition ()
 
virtual void initialSetup ()
 
virtual void initialize ()
 
virtual void finalize ()
 
virtual void execute ()
 
const Node * getCrackFrontNodePtr (const unsigned int node_index) const
 
const Point * getCrackFrontPoint (const unsigned int point_index) const
 
const RealVectorValue & getCrackFrontTangent (const unsigned int point_index) const
 
Real getCrackFrontForwardSegmentLength (const unsigned int point_index) const
 
Real getCrackFrontBackwardSegmentLength (const unsigned int point_index) const
 
const RealVectorValue & getCrackDirection (const unsigned int point_index) const
 
Real getDistanceAlongFront (const unsigned int point_index) const
 
bool hasAngleAlongFront () const
 
Real getAngleAlongFront (const unsigned int point_index) const
 
unsigned int getNumCrackFrontPoints () const
 
bool treatAs2D () const
 
RealVectorValue rotateToCrackFrontCoords (const RealVectorValue vector, const unsigned int point_index) const
 
RankTwoTensor rotateToCrackFrontCoords (const RankTwoTensor tensor, const unsigned int point_index) const
 
RealVectorValue rotateFromCrackFrontCoordsToGlobal (const RealVectorValue vector, const unsigned int point_index) const
 rotate a vector from crack front cartesian coordinate to global cartesian coordinate More...
 
void calculateRThetaToCrackFront (const Point qp, const unsigned int point_index, Real &r, Real &theta) const
 calculate r and theta in the crack front polar cooridnate More...
 
unsigned int calculateRThetaToCrackFront (const Point qp, Real &r, Real &theta) const
 calculate r and theta in the crack front polar cooridnate relatively to the closest crack front point. More...
 
bool isNodeOnIntersectingBoundary (const Node *const node) const
 
bool isPointWithIndexOnIntersectingBoundary (const unsigned int point_index) const
 
Real getCrackFrontTangentialStrain (const unsigned int node_index) const
 
bool hasCrackFrontNodes () const
 
bool isNodeInRing (const unsigned int ring_index, const dof_id_type connected_node_id, const unsigned int node_index) const
 
Real DomainIntegralQFunction (unsigned int crack_front_point_index, unsigned int ring_index, const Node *const current_node) const
 
Real DomainIntegralTopologicalQFunction (unsigned int crack_front_point_index, unsigned int ring_index, const Node *const current_node) const
 

Protected Types

enum  DIRECTION_METHOD { CRACK_DIRECTION_VECTOR, CRACK_MOUTH, CURVED_CRACK_FRONT }
 
enum  END_DIRECTION_METHOD { NO_SPECIAL_TREATMENT, END_CRACK_DIRECTION_VECTOR }
 
enum  CRACK_NODE_TYPE { MIDDLE_NODE, END_1_NODE, END_2_NODE }
 
enum  CRACK_GEOM_DEFINITION { CRACK_FRONT_NODES, CRACK_FRONT_POINTS }
 

Protected Member Functions

void getCrackFrontNodes (std::set< dof_id_type > &nodes)
 
void orderCrackFrontNodes (std::set< dof_id_type > &nodes)
 
void orderEndNodes (std::vector< dof_id_type > &end_nodes)
 
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)
 
unsigned int maxNodeCoor (std::vector< Node *> &nodes, unsigned int dir0=0)
 
void updateCrackFrontGeometry ()
 
void updateDataForCrackDirection ()
 
RealVectorValue calculateCrackFrontDirection (const Point &crack_front_point, const RealVectorValue &tangent_direction, const CRACK_NODE_TYPE ntype) const
 
void calculateTangentialStrainAlongFront ()
 
void createQFunctionRings ()
 
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)
 
void projectToFrontAtPoint (Real &dist_to_front, Real &dist_along_tangent, unsigned int crack_front_point_index, const Node *const current_node) const
 

Protected Attributes

AuxiliarySystem & _aux
 
MooseMesh & _mesh
 
std::vector< unsigned int > _ordered_crack_front_nodes
 
CRACK_GEOM_DEFINITION _geom_definition_method
 
std::vector< Point > _crack_front_points
 
std::vector< RealVectorValue > _tangent_directions
 
std::vector< RealVectorValue > _crack_directions
 
std::vector< std::pair< Real, Real > > _segment_lengths
 
std::vector< Real > _distances_along_front
 
std::vector< Real > _angles_along_front
 
std::vector< Real > _strain_along_front
 
std::vector< RankTwoTensor > _rot_matrix
 
Real _overall_length
 
DIRECTION_METHOD _direction_method
 
END_DIRECTION_METHOD _end_direction_method
 
RealVectorValue _crack_direction_vector
 
RealVectorValue _crack_direction_vector_end_1
 
RealVectorValue _crack_direction_vector_end_2
 
std::vector< BoundaryName > _crack_mouth_boundary_names
 
std::vector< BoundaryID > _crack_mouth_boundary_ids
 
std::vector< BoundaryName > _intersecting_boundary_names
 
std::vector< BoundaryID > _intersecting_boundary_ids
 
RealVectorValue _crack_mouth_coordinates
 
RealVectorValue _crack_plane_normal
 
bool _treat_as_2d
 
bool _closed_loop
 
unsigned int _axis_2d
 
bool _has_symmetry_plane
 
unsigned int _symmetry_plane
 
std::string _disp_x_var_name
 
std::string _disp_y_var_name
 
std::string _disp_z_var_name
 
bool _t_stress
 
bool _q_function_rings
 
unsigned int _last_ring
 
unsigned int _first_ring
 
std::map< std::pair< dof_id_type, unsigned int >, std::set< dof_id_type > > _crack_front_node_to_node_map
 
MooseEnum _q_function_type
 
std::vector< bool > _is_point_on_intersecting_boundary
 
std::vector< Real > _j_integral_radius_inner
 
std::vector< Real > _j_integral_radius_outer
 
const CrackFrontPointsProvider_crack_front_points_provider
 
unsigned int _num_points_from_provider
 

Static Protected Attributes

static const Real _tol = 1e-10
 

Detailed Description

Works on top of NodalNormalsPreprocessor.

Definition at line 35 of file CrackFrontDefinition.h.

Member Enumeration Documentation

◆ CRACK_GEOM_DEFINITION

Enumerator
CRACK_FRONT_NODES 
CRACK_FRONT_POINTS 

Definition at line 119 of file CrackFrontDefinition.h.

◆ CRACK_NODE_TYPE

Enumerator
MIDDLE_NODE 
END_1_NODE 
END_2_NODE 

Definition at line 112 of file CrackFrontDefinition.h.

◆ DIRECTION_METHOD

◆ END_DIRECTION_METHOD

Enumerator
NO_SPECIAL_TREATMENT 
END_CRACK_DIRECTION_VECTOR 

Definition at line 106 of file CrackFrontDefinition.h.

Constructor & Destructor Documentation

◆ CrackFrontDefinition()

CrackFrontDefinition::CrackFrontDefinition ( const InputParameters &  parameters)

Definition at line 99 of file CrackFrontDefinition.C.

100  : GeneralUserObject(parameters),
101  BoundaryRestrictable(this, true), // false means nodesets
102  _aux(_fe_problem.getAuxiliarySystem()),
103  _mesh(_subproblem.mesh()),
104  _treat_as_2d(getParam<bool>("2d")),
105  _closed_loop(getParam<bool>("closed_loop")),
106  _axis_2d(getParam<unsigned int>("axis_2d")),
107  _has_symmetry_plane(isParamValid("symmetry_plane")),
108  _symmetry_plane(_has_symmetry_plane ? getParam<unsigned int>("symmetry_plane")
109  : std::numeric_limits<unsigned int>::max()),
110  _t_stress(getParam<bool>("t_stress")),
111  _q_function_rings(getParam<bool>("q_function_rings")),
112  _q_function_type(getParam<MooseEnum>("q_function_type")),
114 {
115  if (isParamValid("crack_front_points"))
116  {
117  if (isParamValid("boundary"))
118  mooseError("CrackFrontDefinition error: since boundary is defined, crack_front_points should "
119  "not be added.");
120  if (isParamValid("crack_front_points_provider"))
121  mooseError("As crack_front_points have been provided, the crack_front_points_provider will "
122  "not be used and needs to be removed.");
123  _crack_front_points = getParam<std::vector<Point>>("crack_front_points");
125  if (_t_stress)
126  mooseError("t_stress not yet supported with crack_front_points");
127  if (_q_function_rings)
128  mooseError("q_function_rings not supported with crack_front_points");
129  }
130  else if (isParamValid("crack_front_points_provider"))
131  {
132  if (isParamValid("boundary"))
133  mooseError("CrackFrontDefinition error: since boundary is defined, "
134  "crack_front_points_provider should not be added.");
135  if (!isParamValid("number_points_from_provider"))
136  mooseError("CrackFrontDefinition error: When crack_front_points_provider is used, the "
137  "number_points_from_provider must be "
138  "provided.");
139  _crack_front_points_provider = &getUserObjectByName<CrackFrontPointsProvider>(
140  getParam<UserObjectName>("crack_front_points_provider"));
141  _num_points_from_provider = getParam<unsigned int>("number_points_from_provider");
143  }
144  else if (isParamValid("number_points_from_provider"))
145  mooseError("CrackFrontDefinition error: number_points_from_provider is provided but "
146  "crack_front_points_provider cannot "
147  "be found.");
148  else if (isParamValid("boundary"))
149  {
151  if (parameters.isParamSetByUser("closed_loop"))
152  mooseError("In CrackFrontDefinition, if 'boundary' is defined, 'closed_loop' should not be "
153  "set by user!");
154  }
155  else
156  mooseError("In CrackFrontDefinition, must define one of 'boundary', 'crack_front_points' "
157  "and 'crack_front_points_provider'");
158 
159  if (isParamValid("crack_mouth_boundary"))
160  _crack_mouth_boundary_names = getParam<std::vector<BoundaryName>>("crack_mouth_boundary");
161 
163  if (_symmetry_plane > 2)
164  mooseError("symmetry_plane out of bounds: ", _symmetry_plane, " Must be >=0 and <=2.");
165 
166  MooseEnum direction_method_moose_enum = getParam<MooseEnum>("crack_direction_method");
167  _direction_method = DIRECTION_METHOD(int(direction_method_moose_enum));
168  switch (_direction_method)
169  {
171  if (!isParamValid("crack_direction_vector"))
172  mooseError("crack_direction_vector must be specified if crack_direction_method = "
173  "CrackDirectionVector");
174  _crack_direction_vector = getParam<RealVectorValue>("crack_direction_vector");
175  break;
176  case CRACK_MOUTH:
177  if (isParamValid("crack_direction_vector"))
178  mooseError("crack_direction_vector must not be specified if crack_direction_method = "
179  "CrackMouthNodes");
180  if (_crack_mouth_boundary_names.size() == 0)
181  mooseError(
182  "crack_mouth_boundary must be specified if crack_direction_method = CrackMouthNodes");
183  break;
184  case CURVED_CRACK_FRONT:
185  if (isParamValid("crack_direction_vector"))
186  mooseError("crack_direction_vector must not be specified if crack_direction_method = "
187  "CurvedCrackFront");
188  break;
189  default:
190  mooseError("Invalid direction_method");
191  }
192 
193  if (isParamValid("intersecting_boundary"))
194  _intersecting_boundary_names = getParam<std::vector<BoundaryName>>("intersecting_boundary");
195 
196  MooseEnum end_direction_method_moose_enum = getParam<MooseEnum>("crack_end_direction_method");
197  if (end_direction_method_moose_enum.isValid())
198  {
199  _end_direction_method = END_DIRECTION_METHOD(int(end_direction_method_moose_enum));
201  {
202  if (!isParamValid("crack_direction_vector_end_1"))
203  mooseError("crack_direction_vector_end_1 must be specified if crack_end_direction_method = "
204  "CrackDirectionVector");
205  if (!isParamValid("crack_direction_vector_end_2"))
206  mooseError("crack_direction_vector_end_2 must be specified if crack_end_direction_method = "
207  "CrackDirectionVector");
208  _crack_direction_vector_end_1 = getParam<RealVectorValue>("crack_direction_vector_end_1");
209  _crack_direction_vector_end_2 = getParam<RealVectorValue>("crack_direction_vector_end_2");
210  }
211  }
212 
213  if (isParamValid("disp_x") && isParamValid("disp_y") && isParamValid("disp_z"))
214  {
215  _disp_x_var_name = getParam<VariableName>("disp_x");
216  _disp_y_var_name = getParam<VariableName>("disp_y");
217  _disp_z_var_name = getParam<VariableName>("disp_z");
218  }
219  else if (_t_stress == true && _treat_as_2d == false)
220  mooseError("Displacement variables must be provided for T-stress calculation");
221 
222  if (_q_function_rings)
223  {
224  if (!isParamValid("last_ring"))
225  mooseError("The max number of rings of nodes to generate must be provided if "
226  "q_function_rings = true");
227  _last_ring = getParam<unsigned int>("last_ring");
228  _first_ring = getParam<unsigned int>("first_ring");
229  }
230  else
231  {
232  _j_integral_radius_inner = getParam<std::vector<Real>>("j_integral_radius_inner");
233  _j_integral_radius_outer = getParam<std::vector<Real>>("j_integral_radius_outer");
234  }
235 }
std::vector< Point > _crack_front_points
END_DIRECTION_METHOD _end_direction_method
RealVectorValue _crack_direction_vector_end_2
const CrackFrontPointsProvider * _crack_front_points_provider
DIRECTION_METHOD _direction_method
CRACK_GEOM_DEFINITION _geom_definition_method
RealVectorValue _crack_direction_vector
unsigned int _num_points_from_provider
std::vector< BoundaryName > _crack_mouth_boundary_names
std::vector< Real > _j_integral_radius_outer
std::vector< BoundaryName > _intersecting_boundary_names
RealVectorValue _crack_direction_vector_end_1
std::vector< Real > _j_integral_radius_inner

◆ ~CrackFrontDefinition()

CrackFrontDefinition::~CrackFrontDefinition ( )
virtual

Definition at line 237 of file CrackFrontDefinition.C.

237 {}

Member Function Documentation

◆ addNodesToQFunctionRing()

void CrackFrontDefinition::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 
)
protected

Definition at line 1631 of file CrackFrontDefinition.C.

Referenced by createQFunctionRings().

1638 {
1639  for (std::set<dof_id_type>::const_iterator nit = nodes_old_ring.begin();
1640  nit != nodes_old_ring.end();
1641  ++nit)
1642  {
1643  std::vector<const Node *> neighbors;
1644  MeshTools::find_nodal_neighbors(
1645  _mesh.getMesh(), _mesh.nodeRef(*nit), nodes_to_elem_map, neighbors);
1646  for (unsigned int inei = 0; inei < neighbors.size(); ++inei)
1647  {
1648  std::set<dof_id_type>::const_iterator previt = nodes_all_rings.find(neighbors[inei]->id());
1649  std::set<dof_id_type>::const_iterator thisit = nodes_neighbor1.find(neighbors[inei]->id());
1650  std::set<dof_id_type>::const_iterator nextit = nodes_neighbor2.find(neighbors[inei]->id());
1651 
1652  // Add only nodes that are not already present in any of the three sets of nodes
1653  if (previt == nodes_all_rings.end() && thisit == nodes_neighbor1.end() &&
1654  nextit == nodes_neighbor2.end())
1655  nodes_new_ring.insert(neighbors[inei]->id());
1656  }
1657  }
1658 }

◆ calculateCrackFrontDirection()

RealVectorValue CrackFrontDefinition::calculateCrackFrontDirection ( const Point &  crack_front_point,
const RealVectorValue &  tangent_direction,
const CRACK_NODE_TYPE  ntype 
) const
protected

Definition at line 984 of file CrackFrontDefinition.C.

Referenced by updateCrackFrontGeometry().

987 {
988  RealVectorValue crack_dir;
989  RealVectorValue zero_vec(0.0);
990 
991  bool calc_dir = true;
993  {
994  if (ntype == END_1_NODE)
995  {
996  crack_dir = _crack_direction_vector_end_1;
997  calc_dir = false;
998  }
999  else if (ntype == END_2_NODE)
1000  {
1001  crack_dir = _crack_direction_vector_end_2;
1002  calc_dir = false;
1003  }
1004  }
1005 
1006  if (calc_dir)
1007  {
1009  {
1010  crack_dir = _crack_direction_vector;
1011  }
1012  else if (_direction_method == CRACK_MOUTH)
1013  {
1014  if (_crack_mouth_coordinates.absolute_fuzzy_equals(crack_front_point, _tol))
1015  {
1016  mooseError("Crack mouth too close to crack front node");
1017  }
1018  RealVectorValue mouth_to_front = crack_front_point - _crack_mouth_coordinates;
1019 
1020  RealVectorValue crack_plane_normal = mouth_to_front.cross(tangent_direction);
1021  if (crack_plane_normal.absolute_fuzzy_equals(zero_vec, _tol))
1022  {
1023  mooseError(
1024  "Vector from crack mouth to crack front node is collinear with crack front segment");
1025  }
1026 
1027  crack_dir = tangent_direction.cross(crack_plane_normal);
1028  Real dotprod = crack_dir * mouth_to_front;
1029  if (dotprod < 0)
1030  {
1031  crack_dir = -crack_dir;
1032  }
1033  }
1035  {
1036  crack_dir = tangent_direction.cross(_crack_plane_normal);
1037  }
1038  }
1039  crack_dir = crack_dir.unit();
1040 
1041  return crack_dir;
1042 }
END_DIRECTION_METHOD _end_direction_method
RealVectorValue _crack_direction_vector_end_2
DIRECTION_METHOD _direction_method
RealVectorValue _crack_direction_vector
RealVectorValue _crack_plane_normal
RealVectorValue _crack_direction_vector_end_1
RealVectorValue _crack_mouth_coordinates

◆ calculateRThetaToCrackFront() [1/2]

void CrackFrontDefinition::calculateRThetaToCrackFront ( const Point  qp,
const unsigned int  point_index,
Real &  r,
Real &  theta 
) const

calculate r and theta in the crack front polar cooridnate

Parameters
qpthe point cooridnate
point_indexthe crack front point index

Definition at line 1147 of file CrackFrontDefinition.C.

Referenced by calculateRThetaToCrackFront(), InteractionIntegral::computeQpIntegral(), InteractionIntegralSM::computeQpIntegral(), InteractionIntegralBenchmarkBC::computeQpValue(), EnrichmentFunctionCalculation::crackTipEnrichementFunctionAtPoint(), EnrichmentFunctionCalculation::crackTipEnrichementFunctionDerivativeAtPoint(), and CrackTipEnrichmentCutOffBC::shouldApply().

1151 {
1152  unsigned int num_points = getNumCrackFrontPoints();
1153  Point closest_point(0.0);
1154  RealVectorValue closest_point_to_p;
1155 
1156  const Point * crack_front_point = getCrackFrontPoint(point_index);
1157  RealVectorValue crack_front_point_rot = rotateToCrackFrontCoords(*crack_front_point, point_index);
1158 
1159  RealVectorValue crack_front_edge =
1160  rotateToCrackFrontCoords(_tangent_directions[point_index], point_index);
1161 
1162  Point p_rot = rotateToCrackFrontCoords(qp, point_index);
1163  p_rot = p_rot - crack_front_point_rot;
1164 
1165  if (_treat_as_2d)
1166  {
1167  // In 2D, the closest node is the crack tip node and the position of the crack tip node is
1168  // (0,0,0) in the crack front coordinate system
1169  // In case this is a 3D mesh treated as 2D, project point onto same plane as crack front node.
1170  // Note: In the crack front coordinate system, z is always in the tangent direction to the crack
1171  // front
1172  p_rot(2) = closest_point(2);
1173  closest_point_to_p = p_rot;
1174 
1175  // Find r, the distance between the qp and the crack front
1176  RealVectorValue r_vec = p_rot;
1177  r = r_vec.norm();
1178  }
1179  else
1180  {
1181  // Loop over crack front points to find the one closest to the point qp
1182  Real min_dist = std::numeric_limits<Real>::max();
1183  for (unsigned int pit = 0; pit != num_points; ++pit)
1184  {
1185  const Point * crack_front_point = getCrackFrontPoint(pit);
1186  RealVectorValue crack_point_to_current_point = qp - *crack_front_point;
1187  Real dist = crack_point_to_current_point.norm();
1188 
1189  if (dist < min_dist)
1190  {
1191  min_dist = dist;
1192  closest_point = *crack_front_point;
1193  }
1194  }
1195 
1196  // Rotate coordinates to crack front coordinate system
1197  closest_point = rotateToCrackFrontCoords(closest_point, point_index);
1198  closest_point = closest_point - crack_front_point_rot;
1199 
1200  // Find r, the distance between the qp and the crack front
1201  Real edge_length_sq = crack_front_edge.norm_sq();
1202  closest_point_to_p = p_rot - closest_point;
1203  Real perp = crack_front_edge * closest_point_to_p;
1204  Real dist_along_edge = perp / edge_length_sq;
1205  RealVectorValue point_on_edge = closest_point + crack_front_edge * dist_along_edge;
1206  RealVectorValue r_vec = p_rot - point_on_edge;
1207  r = r_vec.norm();
1208  }
1209 
1210  // Find theta, the angle between r and the crack front plane
1211  RealVectorValue crack_plane_normal = rotateToCrackFrontCoords(_crack_plane_normal, point_index);
1212  Real p_to_plane_dist = std::abs(closest_point_to_p * crack_plane_normal);
1213 
1214  // Determine if qp is above or below the crack plane
1215  Real y_local = p_rot(1) - closest_point(1);
1216 
1217  // Determine if qp is in front of or behind the crack front
1218  RealVectorValue p2(p_rot);
1219  p2(1) = 0;
1220  RealVectorValue p2_vec = p2 - closest_point;
1221  Real ahead = crack_front_edge(2) * p2_vec(0) - crack_front_edge(0) * p2_vec(2);
1222 
1223  Real x_local(0);
1224  if (ahead >= 0)
1225  x_local = 1;
1226  else
1227  x_local = -1;
1228 
1229  // Calculate theta based on in which quadrant in the crack front coordinate
1230  // system the qp is located
1231  if (r > 0)
1232  {
1233  Real theta_quadrant1(0.0);
1234  if (MooseUtils::absoluteFuzzyEqual(r, p_to_plane_dist, _tol))
1235  theta_quadrant1 = 0.5 * libMesh::pi;
1236  else if (p_to_plane_dist > r)
1237  mooseError(
1238  "Invalid distance p_to_plane_dist in CrackFrontDefinition::calculateRThetaToCrackFront");
1239  else
1240  theta_quadrant1 = std::asin(p_to_plane_dist / r);
1241 
1242  if (x_local >= 0 && y_local >= 0)
1243  theta = theta_quadrant1;
1244 
1245  else if (x_local < 0 && y_local >= 0)
1246  theta = libMesh::pi - 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 = -theta_quadrant1;
1253  }
1254  else if (r == 0)
1255  theta = 0;
1256  else
1257  mooseError("Invalid distance r in CrackFrontDefinition::calculateRThetaToCrackFront");
1258 }
unsigned int getNumCrackFrontPoints() const
RealVectorValue _crack_plane_normal
RealVectorValue rotateToCrackFrontCoords(const RealVectorValue vector, const unsigned int point_index) const
std::vector< RealVectorValue > _tangent_directions
const Point * getCrackFrontPoint(const unsigned int point_index) const

◆ calculateRThetaToCrackFront() [2/2]

unsigned int CrackFrontDefinition::calculateRThetaToCrackFront ( const Point  qp,
Real &  r,
Real &  theta 
) const

calculate r and theta in the crack front polar cooridnate relatively to the closest crack front point.

It does additional loop over all crack front points to find the one closest to the point qp.

Returns
The closest crack front point index

Definition at line 1261 of file CrackFrontDefinition.C.

1262 {
1263  unsigned int num_points = getNumCrackFrontPoints();
1264 
1265  // Loop over crack front points to find the one closest to the point qp
1266  Real min_dist = std::numeric_limits<Real>::max();
1267  unsigned int point_index = 0;
1268  for (unsigned int pit = 0; pit != num_points; ++pit)
1269  {
1270  const Point * crack_front_point = getCrackFrontPoint(pit);
1271  RealVectorValue crack_point_to_current_point = qp - *crack_front_point;
1272  Real dist = crack_point_to_current_point.norm();
1273 
1274  if (dist < min_dist)
1275  {
1276  min_dist = dist;
1277  point_index = pit;
1278  }
1279  }
1280 
1281  calculateRThetaToCrackFront(qp, point_index, r, theta);
1282 
1283  return point_index;
1284 }
void calculateRThetaToCrackFront(const Point qp, const unsigned int point_index, Real &r, Real &theta) const
calculate r and theta in the crack front polar cooridnate
unsigned int getNumCrackFrontPoints() const
const Point * getCrackFrontPoint(const unsigned int point_index) const

◆ calculateTangentialStrainAlongFront()

void CrackFrontDefinition::calculateTangentialStrainAlongFront ( )
protected

Definition at line 1324 of file CrackFrontDefinition.C.

Referenced by execute().

1325 {
1326  RealVectorValue disp_current_node;
1327  RealVectorValue disp_previous_node;
1328  RealVectorValue disp_next_node;
1329 
1330  RealVectorValue forward_segment0;
1331  RealVectorValue forward_segment1;
1332  Real forward_segment0_len;
1333  Real forward_segment1_len;
1334  RealVectorValue back_segment0;
1335  RealVectorValue back_segment1;
1336  Real back_segment0_len;
1337  Real back_segment1_len;
1338 
1339  unsigned int num_crack_front_nodes = _ordered_crack_front_nodes.size();
1340  const Node * current_node;
1341  const Node * previous_node;
1342  const Node * next_node;
1343 
1344  // In finalize(), gatherMax builds and distributes the complete strain vector on all processors
1345  // -> reset the vector every time
1346  for (unsigned int i = 0; i < num_crack_front_nodes; ++i)
1347  _strain_along_front[i] = -std::numeric_limits<Real>::max();
1348 
1349  MooseVariableFEBase & disp_x_var =
1350  _subproblem.getVariable(_tid,
1352  Moose::VarKindType::VAR_NONLINEAR,
1353  Moose::VarFieldType::VAR_FIELD_STANDARD);
1354  MooseVariableFEBase & disp_y_var =
1355  _subproblem.getVariable(_tid,
1357  Moose::VarKindType::VAR_NONLINEAR,
1358  Moose::VarFieldType::VAR_FIELD_STANDARD);
1359 
1360  MooseVariableFEBase & disp_z_var =
1361  _subproblem.getVariable(_tid,
1363  Moose::VarKindType::VAR_NONLINEAR,
1364  Moose::VarFieldType::VAR_FIELD_STANDARD);
1365 
1366  current_node = getCrackFrontNodePtr(0);
1367  if (current_node->processor_id() == processor_id())
1368  {
1369  disp_current_node(0) = disp_x_var.getNodalValue(*current_node);
1370  disp_current_node(1) = disp_y_var.getNodalValue(*current_node);
1371  disp_current_node(2) = disp_z_var.getNodalValue(*current_node);
1372 
1373  next_node = getCrackFrontNodePtr(1);
1374  disp_next_node(0) = disp_x_var.getNodalValue(*next_node);
1375  disp_next_node(1) = disp_y_var.getNodalValue(*next_node);
1376  disp_next_node(2) = disp_z_var.getNodalValue(*next_node);
1377 
1378  forward_segment0 = *next_node - *current_node;
1379  forward_segment0 = (forward_segment0 * _tangent_directions[0]) * _tangent_directions[0];
1380  forward_segment0_len = forward_segment0.norm();
1381 
1382  forward_segment1 = (*next_node + disp_next_node) - (*current_node + disp_current_node);
1383  forward_segment1 = (forward_segment1 * _tangent_directions[0]) * _tangent_directions[0];
1384  forward_segment1_len = forward_segment1.norm();
1385 
1386  _strain_along_front[0] = (forward_segment1_len - forward_segment0_len) / forward_segment0_len;
1387  }
1388 
1389  for (unsigned int i = 1; i < num_crack_front_nodes - 1; ++i)
1390  {
1391  current_node = getCrackFrontNodePtr(i);
1392  if (current_node->processor_id() == processor_id())
1393  {
1394  disp_current_node(0) = disp_x_var.getNodalValue(*current_node);
1395  disp_current_node(1) = disp_y_var.getNodalValue(*current_node);
1396  disp_current_node(2) = disp_z_var.getNodalValue(*current_node);
1397 
1398  previous_node = getCrackFrontNodePtr(i - 1);
1399  disp_previous_node(0) = disp_x_var.getNodalValue(*previous_node);
1400  disp_previous_node(1) = disp_y_var.getNodalValue(*previous_node);
1401  disp_previous_node(2) = disp_z_var.getNodalValue(*previous_node);
1402 
1403  next_node = getCrackFrontNodePtr(i + 1);
1404  disp_next_node(0) = disp_x_var.getNodalValue(*next_node);
1405  disp_next_node(1) = disp_y_var.getNodalValue(*next_node);
1406  disp_next_node(2) = disp_z_var.getNodalValue(*next_node);
1407 
1408  back_segment0 = *current_node - *previous_node;
1409  back_segment0 = (back_segment0 * _tangent_directions[i]) * _tangent_directions[i];
1410  back_segment0_len = back_segment0.norm();
1411 
1412  back_segment1 = (*current_node + disp_current_node) - (*previous_node + disp_previous_node);
1413  back_segment1 = (back_segment1 * _tangent_directions[i]) * _tangent_directions[i];
1414  back_segment1_len = back_segment1.norm();
1415 
1416  forward_segment0 = *next_node - *current_node;
1417  forward_segment0 = (forward_segment0 * _tangent_directions[i]) * _tangent_directions[i];
1418  forward_segment0_len = forward_segment0.norm();
1419 
1420  forward_segment1 = (*next_node + disp_next_node) - (*current_node + disp_current_node);
1421  forward_segment1 = (forward_segment1 * _tangent_directions[i]) * _tangent_directions[i];
1422  forward_segment1_len = forward_segment1.norm();
1423 
1424  _strain_along_front[i] =
1425  0.5 * ((back_segment1_len - back_segment0_len) / back_segment0_len +
1426  (forward_segment1_len - forward_segment0_len) / forward_segment0_len);
1427  }
1428  }
1429 
1430  current_node = getCrackFrontNodePtr(num_crack_front_nodes - 1);
1431  if (current_node->processor_id() == processor_id())
1432  {
1433  disp_current_node(0) = disp_x_var.getNodalValue(*current_node);
1434  disp_current_node(1) = disp_y_var.getNodalValue(*current_node);
1435  disp_current_node(2) = disp_z_var.getNodalValue(*current_node);
1436 
1437  previous_node = getCrackFrontNodePtr(num_crack_front_nodes - 2);
1438  disp_previous_node(0) = disp_x_var.getNodalValue(*previous_node);
1439  disp_previous_node(1) = disp_y_var.getNodalValue(*previous_node);
1440  disp_previous_node(2) = disp_z_var.getNodalValue(*previous_node);
1441 
1442  back_segment0 = *current_node - *previous_node;
1443  back_segment0 = (back_segment0 * _tangent_directions[num_crack_front_nodes - 1]) *
1444  _tangent_directions[num_crack_front_nodes - 1];
1445  back_segment0_len = back_segment0.norm();
1446 
1447  back_segment1 = (*current_node + disp_current_node) - (*previous_node + disp_previous_node);
1448  back_segment1 = (back_segment1 * _tangent_directions[num_crack_front_nodes - 1]) *
1449  _tangent_directions[num_crack_front_nodes - 1];
1450  back_segment1_len = back_segment1.norm();
1451 
1452  _strain_along_front[num_crack_front_nodes - 1] =
1453  (back_segment1_len - back_segment0_len) / back_segment0_len;
1454  }
1455 }
std::vector< Real > _strain_along_front
std::vector< RealVectorValue > _tangent_directions
const Node * getCrackFrontNodePtr(const unsigned int node_index) const
std::vector< unsigned int > _ordered_crack_front_nodes

◆ createQFunctionRings()

void CrackFrontDefinition::createQFunctionRings ( )
protected

Definition at line 1470 of file CrackFrontDefinition.C.

Referenced by initialSetup().

1471 {
1472  // In the variable names, "cfn" = crack front node
1473 
1474  if (_treat_as_2d) // 2D: the q-function defines an integral domain that is constant along the
1475  // crack front
1476  {
1477  std::vector<std::vector<const Elem *>> nodes_to_elem_map;
1478  MeshTools::build_nodes_to_elem_map(_mesh.getMesh(), nodes_to_elem_map);
1479 
1480  std::set<dof_id_type> nodes_prev_ring;
1481  nodes_prev_ring.insert(_ordered_crack_front_nodes.begin(), _ordered_crack_front_nodes.end());
1482 
1483  std::set<dof_id_type> connected_nodes_this_cfn;
1484  connected_nodes_this_cfn.insert(_ordered_crack_front_nodes.begin(),
1486 
1487  std::set<dof_id_type> old_ring_nodes_this_cfn = connected_nodes_this_cfn;
1488 
1489  // The first ring contains only the crack front node(s)
1490  std::pair<dof_id_type, unsigned int> node_ring_index =
1491  std::make_pair(_ordered_crack_front_nodes[0], 1);
1492  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1493  connected_nodes_this_cfn.end());
1494 
1495  // Build rings of nodes around the crack front node
1496  for (unsigned int ring = 2; ring <= _last_ring; ++ring)
1497  {
1498 
1499  // Find nodes connected to the nodes of the previous ring
1500  std::set<dof_id_type> new_ring_nodes_this_cfn;
1501  for (std::set<dof_id_type>::iterator nit = old_ring_nodes_this_cfn.begin();
1502  nit != old_ring_nodes_this_cfn.end();
1503  ++nit)
1504  {
1505  std::vector<const Node *> neighbors;
1506  MeshTools::find_nodal_neighbors(
1507  _mesh.getMesh(), _mesh.nodeRef(*nit), nodes_to_elem_map, neighbors);
1508  for (unsigned int inei = 0; inei < neighbors.size(); ++inei)
1509  {
1510  std::set<dof_id_type>::iterator thisit =
1511  connected_nodes_this_cfn.find(neighbors[inei]->id());
1512 
1513  // Add only nodes that are not already present in any of the rings
1514  if (thisit == connected_nodes_this_cfn.end())
1515  new_ring_nodes_this_cfn.insert(neighbors[inei]->id());
1516  }
1517  }
1518 
1519  // Add new nodes to rings
1520  connected_nodes_this_cfn.insert(new_ring_nodes_this_cfn.begin(),
1521  new_ring_nodes_this_cfn.end());
1522  old_ring_nodes_this_cfn = new_ring_nodes_this_cfn;
1523 
1524  std::pair<dof_id_type, unsigned int> node_ring_index =
1525  std::make_pair(_ordered_crack_front_nodes[0], ring);
1526  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1527  connected_nodes_this_cfn.end());
1528  }
1529  }
1530  else // 3D: The q-function defines one integral domain around each crack front node
1531  {
1532  unsigned int num_crack_front_points = _ordered_crack_front_nodes.size();
1533  std::vector<std::vector<const Elem *>> nodes_to_elem_map;
1534  MeshTools::build_nodes_to_elem_map(_mesh.getMesh(), nodes_to_elem_map);
1535  for (unsigned int icfn = 0; icfn < num_crack_front_points; ++icfn)
1536  {
1537  std::set<dof_id_type> nodes_prev_ring;
1538  nodes_prev_ring.insert(_ordered_crack_front_nodes[icfn]);
1539 
1540  std::set<dof_id_type> connected_nodes_prev_cfn;
1541  std::set<dof_id_type> connected_nodes_this_cfn;
1542  std::set<dof_id_type> connected_nodes_next_cfn;
1543 
1544  connected_nodes_this_cfn.insert(_ordered_crack_front_nodes[icfn]);
1545 
1546  if (_closed_loop && icfn == 0)
1547  {
1548  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[num_crack_front_points - 1]);
1549  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[icfn + 1]);
1550  }
1551  else if (_closed_loop && icfn == num_crack_front_points - 1)
1552  {
1553  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[icfn - 1]);
1554  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[0]);
1555  }
1556  else if (icfn == 0)
1557  {
1558  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[icfn + 1]);
1559  }
1560  else if (icfn == num_crack_front_points - 1)
1561  {
1562  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[icfn - 1]);
1563  }
1564  else
1565  {
1566  connected_nodes_prev_cfn.insert(_ordered_crack_front_nodes[icfn - 1]);
1567  connected_nodes_next_cfn.insert(_ordered_crack_front_nodes[icfn + 1]);
1568  }
1569 
1570  std::set<dof_id_type> old_ring_nodes_prev_cfn = connected_nodes_prev_cfn;
1571  std::set<dof_id_type> old_ring_nodes_this_cfn = connected_nodes_this_cfn;
1572  std::set<dof_id_type> old_ring_nodes_next_cfn = connected_nodes_next_cfn;
1573 
1574  // The first ring contains only the crack front node
1575  std::pair<dof_id_type, unsigned int> node_ring_index =
1576  std::make_pair(_ordered_crack_front_nodes[icfn], 1);
1577  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1578  connected_nodes_this_cfn.end());
1579 
1580  // Build rings of nodes around the crack front node
1581  for (unsigned int ring = 2; ring <= _last_ring; ++ring)
1582  {
1583 
1584  // Find nodes connected to the nodes of the previous ring, but exclude nodes in rings of
1585  // neighboring crack front nodes
1586  std::set<dof_id_type> new_ring_nodes_this_cfn;
1587  addNodesToQFunctionRing(new_ring_nodes_this_cfn,
1588  old_ring_nodes_this_cfn,
1589  connected_nodes_this_cfn,
1590  connected_nodes_prev_cfn,
1591  connected_nodes_next_cfn,
1592  nodes_to_elem_map);
1593 
1594  std::set<dof_id_type> new_ring_nodes_prev_cfn;
1595  addNodesToQFunctionRing(new_ring_nodes_prev_cfn,
1596  old_ring_nodes_prev_cfn,
1597  connected_nodes_prev_cfn,
1598  connected_nodes_this_cfn,
1599  connected_nodes_next_cfn,
1600  nodes_to_elem_map);
1601 
1602  std::set<dof_id_type> new_ring_nodes_next_cfn;
1603  addNodesToQFunctionRing(new_ring_nodes_next_cfn,
1604  old_ring_nodes_next_cfn,
1605  connected_nodes_next_cfn,
1606  connected_nodes_prev_cfn,
1607  connected_nodes_this_cfn,
1608  nodes_to_elem_map);
1609 
1610  // Add new nodes to the three sets of nodes
1611  connected_nodes_prev_cfn.insert(new_ring_nodes_prev_cfn.begin(),
1612  new_ring_nodes_prev_cfn.end());
1613  connected_nodes_this_cfn.insert(new_ring_nodes_this_cfn.begin(),
1614  new_ring_nodes_this_cfn.end());
1615  connected_nodes_next_cfn.insert(new_ring_nodes_next_cfn.begin(),
1616  new_ring_nodes_next_cfn.end());
1617  old_ring_nodes_prev_cfn = new_ring_nodes_prev_cfn;
1618  old_ring_nodes_this_cfn = new_ring_nodes_this_cfn;
1619  old_ring_nodes_next_cfn = new_ring_nodes_next_cfn;
1620 
1621  std::pair<dof_id_type, unsigned int> node_ring_index =
1622  std::make_pair(_ordered_crack_front_nodes[icfn], ring);
1623  _crack_front_node_to_node_map[node_ring_index].insert(connected_nodes_this_cfn.begin(),
1624  connected_nodes_this_cfn.end());
1625  }
1626  }
1627  }
1628 }
std::map< std::pair< dof_id_type, unsigned int >, std::set< dof_id_type > > _crack_front_node_to_node_map
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)
std::vector< unsigned int > _ordered_crack_front_nodes

◆ DomainIntegralQFunction()

Real CrackFrontDefinition::DomainIntegralQFunction ( unsigned int  crack_front_point_index,
unsigned int  ring_index,
const Node *const  current_node 
) const

Definition at line 1685 of file CrackFrontDefinition.C.

Referenced by JIntegral::computeIntegral(), InteractionIntegral::computeIntegral(), and InteractionIntegralSM::computeIntegral().

1688 {
1689  Real dist_to_crack_front;
1690  Real dist_along_tangent;
1692  dist_to_crack_front, dist_along_tangent, crack_front_point_index, current_node);
1693 
1694  Real q = 1.0;
1695  if (dist_to_crack_front > _j_integral_radius_inner[ring_index] &&
1696  dist_to_crack_front < _j_integral_radius_outer[ring_index])
1697  q = (_j_integral_radius_outer[ring_index] - dist_to_crack_front) /
1698  (_j_integral_radius_outer[ring_index] - _j_integral_radius_inner[ring_index]);
1699  else if (dist_to_crack_front >= _j_integral_radius_outer[ring_index])
1700  q = 0.0;
1701 
1702  if (q > 0.0)
1703  {
1704  Real tangent_multiplier = 1.0;
1705  if (!_treat_as_2d)
1706  {
1707  const Real forward_segment_length =
1708  getCrackFrontForwardSegmentLength(crack_front_point_index);
1709  const Real backward_segment_length =
1710  getCrackFrontBackwardSegmentLength(crack_front_point_index);
1711 
1712  if (dist_along_tangent >= 0.0)
1713  {
1714  if (forward_segment_length > 0.0)
1715  tangent_multiplier = 1.0 - dist_along_tangent / forward_segment_length;
1716  }
1717  else
1718  {
1719  if (backward_segment_length > 0.0)
1720  tangent_multiplier = 1.0 + dist_along_tangent / backward_segment_length;
1721  }
1722  }
1723 
1724  tangent_multiplier = std::max(tangent_multiplier, 0.0);
1725  tangent_multiplier = std::min(tangent_multiplier, 1.0);
1726 
1727  // Set to zero if a node is on a designated free surface and its crack front node is not.
1728  if (isNodeOnIntersectingBoundary(current_node) &&
1729  !_is_point_on_intersecting_boundary[crack_front_point_index])
1730  tangent_multiplier = 0.0;
1731 
1732  q *= tangent_multiplier;
1733  }
1734 
1735  return q;
1736 }
bool isNodeOnIntersectingBoundary(const Node *const node) const
Real getCrackFrontBackwardSegmentLength(const unsigned int point_index) const
std::vector< bool > _is_point_on_intersecting_boundary
std::vector< Real > _j_integral_radius_outer
Real getCrackFrontForwardSegmentLength(const unsigned int point_index) const
void projectToFrontAtPoint(Real &dist_to_front, Real &dist_along_tangent, unsigned int crack_front_point_index, const Node *const current_node) const
std::vector< Real > _j_integral_radius_inner

◆ DomainIntegralTopologicalQFunction()

Real CrackFrontDefinition::DomainIntegralTopologicalQFunction ( unsigned int  crack_front_point_index,
unsigned int  ring_index,
const Node *const  current_node 
) const

Definition at line 1739 of file CrackFrontDefinition.C.

Referenced by JIntegral::computeIntegral(), InteractionIntegral::computeIntegral(), and InteractionIntegralSM::computeIntegral().

1742 {
1743  Real q = 0;
1744  bool is_node_in_ring = isNodeInRing(ring_index, current_node->id(), crack_front_point_index);
1745  if (is_node_in_ring)
1746  q = 1;
1747 
1748  return q;
1749 }
bool isNodeInRing(const unsigned int ring_index, const dof_id_type connected_node_id, const unsigned int node_index) const

◆ execute()

void CrackFrontDefinition::execute ( )
virtual

Definition at line 240 of file CrackFrontDefinition.C.

241 {
242  // Because J-Integral is based on original geometry, the crack front geometry
243  // is never updated, so everything that needs to happen is done in initialSetup()
244  if (_t_stress == true && _treat_as_2d == false)
246 }

◆ finalize()

void CrackFrontDefinition::finalize ( )
virtual

Definition at line 300 of file CrackFrontDefinition.C.

301 {
302  if (_t_stress)
303  _communicator.max(_strain_along_front);
304 }
std::vector< Real > _strain_along_front

◆ getAngleAlongFront()

Real CrackFrontDefinition::getAngleAlongFront ( const unsigned int  point_index) const

Definition at line 1105 of file CrackFrontDefinition.C.

Referenced by CrackDataSampler::execute().

1106 {
1107  if (!hasAngleAlongFront())
1108  mooseError("In CrackFrontDefinition, Requested angle along crack front, but not available. "
1109  "Must specify crack_mouth_boundary.");
1110  return _angles_along_front[point_index];
1111 }
std::vector< Real > _angles_along_front

◆ getCrackDirection()

const RealVectorValue & CrackFrontDefinition::getCrackDirection ( const unsigned int  point_index) const

Definition at line 1087 of file CrackFrontDefinition.C.

Referenced by JIntegral::computeQpIntegral().

1088 {
1089  return _crack_directions[point_index];
1090 }
std::vector< RealVectorValue > _crack_directions

◆ getCrackFrontBackwardSegmentLength()

Real CrackFrontDefinition::getCrackFrontBackwardSegmentLength ( const unsigned int  point_index) const

◆ getCrackFrontForwardSegmentLength()

Real CrackFrontDefinition::getCrackFrontForwardSegmentLength ( const unsigned int  point_index) const

◆ getCrackFrontNodePtr()

const Node * CrackFrontDefinition::getCrackFrontNodePtr ( const unsigned int  node_index) const

Definition at line 1045 of file CrackFrontDefinition.C.

Referenced by calculateTangentialStrainAlongFront(), getCrackFrontPoint(), CrackFrontData::initialize(), and isPointWithIndexOnIntersectingBoundary().

1046 {
1047  mooseAssert(node_index < _ordered_crack_front_nodes.size(), "node_index out of range");
1048  const Node * crack_front_node = _mesh.nodePtr(_ordered_crack_front_nodes[node_index]);
1049  mooseAssert(crack_front_node != NULL, "invalid crack front node");
1050  return crack_front_node;
1051 }
std::vector< unsigned int > _ordered_crack_front_nodes

◆ getCrackFrontNodes()

void CrackFrontDefinition::getCrackFrontNodes ( std::set< dof_id_type > &  nodes)
protected

Definition at line 307 of file CrackFrontDefinition.C.

Referenced by initialSetup().

308 {
309  ConstBndNodeRange & bnd_nodes = *_mesh.getBoundaryNodeRange();
310  for (ConstBndNodeRange::const_iterator nd = bnd_nodes.begin(); nd != bnd_nodes.end(); ++nd)
311  {
312  const BndNode * bnode = *nd;
313  BoundaryID boundary_id = bnode->_bnd_id;
314 
315  if (hasBoundary(boundary_id))
316  nodes.insert(bnode->_node->id());
317  }
318 
319  if (_treat_as_2d)
320  {
321  if (nodes.size() > 1)
322  {
323  // Check that the nodes are collinear in the axis normal to the 2d plane
324  unsigned int axis0;
325  unsigned int axis1;
326 
327  switch (_axis_2d)
328  {
329  case 0:
330  axis0 = 1;
331  axis1 = 2;
332  break;
333  case 1:
334  axis0 = 0;
335  axis1 = 2;
336  break;
337  case 2:
338  axis0 = 0;
339  axis1 = 1;
340  break;
341  default:
342  mooseError("Invalid axis.");
343  }
344 
345  Real node0coor0;
346  Real node0coor1;
347 
348  for (std::set<dof_id_type>::iterator sit = nodes.begin(); sit != nodes.end(); ++sit)
349  {
350  Node & curr_node = _mesh.nodeRef(*sit);
351  if (sit == nodes.begin())
352  {
353  node0coor0 = curr_node(axis0);
354  node0coor1 = curr_node(axis1);
355  }
356  else
357  {
358  if (!MooseUtils::absoluteFuzzyEqual(curr_node(axis0), node0coor0, _tol) ||
359  !MooseUtils::absoluteFuzzyEqual(curr_node(axis1), node0coor1, _tol))
360  mooseError("Boundary provided in CrackFrontDefinition contains ",
361  nodes.size(),
362  " nodes, which are not collinear in the ",
363  _axis_2d,
364  " axis. Must contain either 1 node or collinear nodes to treat as 2D.");
365  }
366  }
367  }
368  }
369 }

◆ getCrackFrontPoint()

const Point * CrackFrontDefinition::getCrackFrontPoint ( const unsigned int  point_index) const

Definition at line 1054 of file CrackFrontDefinition.C.

Referenced by calculateRThetaToCrackFront(), CrackDataSampler::execute(), DomainIntegralQFunction::projectToFrontAtPoint(), projectToFrontAtPoint(), updateCrackFrontGeometry(), and updateDataForCrackDirection().

1055 {
1057  {
1058  return getCrackFrontNodePtr(point_index);
1059  }
1060  else
1061  {
1062  mooseAssert(point_index < _crack_front_points.size(), "point_index out of range");
1063  return &_crack_front_points[point_index];
1064  }
1065 }
std::vector< Point > _crack_front_points
CRACK_GEOM_DEFINITION _geom_definition_method
const Node * getCrackFrontNodePtr(const unsigned int node_index) const

◆ getCrackFrontTangent()

const RealVectorValue & CrackFrontDefinition::getCrackFrontTangent ( const unsigned int  point_index) const

Definition at line 1068 of file CrackFrontDefinition.C.

Referenced by DomainIntegralQFunction::projectToFrontAtPoint(), and projectToFrontAtPoint().

1069 {
1070  mooseAssert(point_index < _tangent_directions.size(), "point_index out of range");
1071  return _tangent_directions[point_index];
1072 }
std::vector< RealVectorValue > _tangent_directions

◆ getCrackFrontTangentialStrain()

Real CrackFrontDefinition::getCrackFrontTangentialStrain ( const unsigned int  node_index) const

Definition at line 1458 of file CrackFrontDefinition.C.

Referenced by InteractionIntegral::getValue(), and InteractionIntegralSM::getValue().

1459 {
1460  Real strain;
1461  if (_t_stress)
1462  strain = _strain_along_front[node_index];
1463  else
1464  mooseError("In CrackFrontDefinition, tangential strain not available");
1465 
1466  return strain;
1467 }
std::vector< Real > _strain_along_front

◆ getDistanceAlongFront()

Real CrackFrontDefinition::getDistanceAlongFront ( const unsigned int  point_index) const

Definition at line 1093 of file CrackFrontDefinition.C.

Referenced by CrackDataSampler::execute().

1094 {
1095  return _distances_along_front[point_index];
1096 }
std::vector< Real > _distances_along_front

◆ getNumCrackFrontPoints()

unsigned int CrackFrontDefinition::getNumCrackFrontPoints ( ) const

◆ hasAngleAlongFront()

bool CrackFrontDefinition::hasAngleAlongFront ( ) const

Definition at line 1099 of file CrackFrontDefinition.C.

Referenced by getAngleAlongFront(), CrackDataSampler::initialize(), and updateCrackFrontGeometry().

1100 {
1101  return (_crack_mouth_boundary_names.size() > 0);
1102 }
std::vector< BoundaryName > _crack_mouth_boundary_names

◆ hasCrackFrontNodes()

bool CrackFrontDefinition::hasCrackFrontNodes ( ) const
inline

◆ initialize()

void CrackFrontDefinition::initialize ( )
virtual

Definition at line 295 of file CrackFrontDefinition.C.

296 {
297 }

◆ initialSetup()

void CrackFrontDefinition::initialSetup ( )
virtual

Definition at line 249 of file CrackFrontDefinition.C.

250 {
251  if (_crack_front_points_provider != nullptr)
254 
257 
259  {
260  std::set<dof_id_type> nodes;
261  getCrackFrontNodes(nodes);
262  orderCrackFrontNodes(nodes);
263  }
264 
265  if (_closed_loop && _intersecting_boundary_names.size() > 0)
266  mooseError("Cannot use intersecting_boundary with closed-loop cracks");
267 
269 
270  if (_q_function_rings)
272 
273  if (_t_stress)
274  {
275  unsigned int num_crack_front_nodes = _ordered_crack_front_nodes.size();
276  for (unsigned int i = 0; i < num_crack_front_nodes; ++i)
277  _strain_along_front.push_back(-std::numeric_limits<Real>::max());
278  }
279 
280  unsigned int num_crack_front_points = getNumCrackFrontPoints();
281  if (_q_function_type == "GEOMETRY")
282  {
283  if (!_treat_as_2d)
284  if (num_crack_front_points < 1)
285  mooseError("num_crack_front_points is not > 0");
286  for (unsigned int i = 0; i < num_crack_front_points; ++i)
287  {
288  bool is_point_on_intersecting_boundary = isPointWithIndexOnIntersectingBoundary(i);
289  _is_point_on_intersecting_boundary.push_back(is_point_on_intersecting_boundary);
290  }
291  }
292 }
void getCrackFrontNodes(std::set< dof_id_type > &nodes)
std::vector< BoundaryID > _intersecting_boundary_ids
std::vector< Point > _crack_front_points
unsigned int getNumCrackFrontPoints() const
bool isPointWithIndexOnIntersectingBoundary(const unsigned int point_index) const
const CrackFrontPointsProvider * _crack_front_points_provider
std::vector< BoundaryID > _crack_mouth_boundary_ids
void orderCrackFrontNodes(std::set< dof_id_type > &nodes)
CRACK_GEOM_DEFINITION _geom_definition_method
virtual const std::vector< Point > getCrackFrontPoints(unsigned int) const =0
get a set of points along a crack front from a XFEM GeometricCutUserObject
std::vector< Real > _strain_along_front
std::vector< bool > _is_point_on_intersecting_boundary
unsigned int _num_points_from_provider
std::vector< BoundaryName > _crack_mouth_boundary_names
std::vector< BoundaryName > _intersecting_boundary_names
std::vector< unsigned int > _ordered_crack_front_nodes

◆ isNodeInRing()

bool CrackFrontDefinition::isNodeInRing ( const unsigned int  ring_index,
const dof_id_type  connected_node_id,
const unsigned int  node_index 
) const

Definition at line 1661 of file CrackFrontDefinition.C.

Referenced by DomainIntegralTopologicalQFunction::computeValue(), and DomainIntegralTopologicalQFunction().

1664 {
1665  bool is_node_in_ring = false;
1666  std::pair<dof_id_type, unsigned int> node_ring_key =
1667  std::make_pair(_ordered_crack_front_nodes[node_index], ring_index);
1668  std::map<std::pair<dof_id_type, unsigned int>, std::set<dof_id_type>>::const_iterator nnmit =
1669  _crack_front_node_to_node_map.find(node_ring_key);
1670 
1671  if (nnmit == _crack_front_node_to_node_map.end())
1672  mooseError("Could not find crack front node ",
1673  _ordered_crack_front_nodes[node_index],
1674  "in the crack front node to q-function ring-node map for ring ",
1675  ring_index);
1676 
1677  std::set<dof_id_type> q_func_nodes = nnmit->second;
1678  if (q_func_nodes.find(connected_node_id) != q_func_nodes.end())
1679  is_node_in_ring = true;
1680 
1681  return is_node_in_ring;
1682 }
std::map< std::pair< dof_id_type, unsigned int >, std::set< dof_id_type > > _crack_front_node_to_node_map
std::vector< unsigned int > _ordered_crack_front_nodes

◆ isNodeOnIntersectingBoundary()

bool CrackFrontDefinition::isNodeOnIntersectingBoundary ( const Node *const  node) const

Definition at line 1287 of file CrackFrontDefinition.C.

Referenced by DomainIntegralQFunction::computeValue(), DomainIntegralQFunction(), and isPointWithIndexOnIntersectingBoundary().

1288 {
1289  bool is_on_boundary = false;
1290  mooseAssert(node, "Invalid node");
1291  dof_id_type node_id = node->id();
1292  for (unsigned int i = 0; i < _intersecting_boundary_ids.size(); ++i)
1293  {
1294  if (_mesh.isBoundaryNode(node_id, _intersecting_boundary_ids[i]))
1295  {
1296  is_on_boundary = true;
1297  break;
1298  }
1299  }
1300  return is_on_boundary;
1301 }
std::vector< BoundaryID > _intersecting_boundary_ids

◆ isPointWithIndexOnIntersectingBoundary()

bool CrackFrontDefinition::isPointWithIndexOnIntersectingBoundary ( const unsigned int  point_index) const

Definition at line 1304 of file CrackFrontDefinition.C.

Referenced by DomainIntegralQFunction::initialSetup(), and initialSetup().

1305 {
1306  bool is_on_boundary = false;
1308  {
1309  const Node * crack_front_node = getCrackFrontNodePtr(point_index);
1310  is_on_boundary = isNodeOnIntersectingBoundary(crack_front_node);
1311  }
1312  else
1313  {
1314  // If the intersecting boundary option is used with crack front points, the
1315  // first and last points are assumed to be on the intersecting boundaries.
1316  unsigned int num_crack_front_points = getNumCrackFrontPoints();
1317  if (point_index == 0 || point_index == num_crack_front_points - 1)
1318  is_on_boundary = true;
1319  }
1320  return is_on_boundary;
1321 }
bool isNodeOnIntersectingBoundary(const Node *const node) const
unsigned int getNumCrackFrontPoints() const
CRACK_GEOM_DEFINITION _geom_definition_method
const Node * getCrackFrontNodePtr(const unsigned int node_index) const

◆ maxNodeCoor()

unsigned int CrackFrontDefinition::maxNodeCoor ( std::vector< Node *> &  nodes,
unsigned int  dir0 = 0 
)
protected

Definition at line 624 of file CrackFrontDefinition.C.

Referenced by pickLoopCrackEndNodes().

625 {
626  Real dirs[3];
627  if (dir0 == 0)
628  {
629  dirs[0] = 0;
630  dirs[1] = 1;
631  dirs[2] = 2;
632  }
633  else if (dir0 == 1)
634  {
635  dirs[0] = 1;
636  dirs[1] = 2;
637  dirs[2] = 0;
638  }
639  else if (dir0 == 2)
640  {
641  dirs[0] = 2;
642  dirs[1] = 0;
643  dirs[2] = 1;
644  }
645  else
646  mooseError("Invalid dir0 in CrackFrontDefinition::maxNodeCoor()");
647 
648  Real max_coor0 = -std::numeric_limits<Real>::max();
649  std::vector<Node *> max_coor0_nodes;
650  for (unsigned int i = 0; i < nodes.size(); ++i)
651  {
652  Real coor0 = (*nodes[i])(dirs[0]);
653  if (coor0 > max_coor0)
654  max_coor0 = coor0;
655  }
656  for (unsigned int i = 0; i < nodes.size(); ++i)
657  {
658  Real coor0 = (*nodes[i])(dirs[0]);
659  if (MooseUtils::absoluteFuzzyEqual(coor0, max_coor0, _tol))
660  max_coor0_nodes.push_back(nodes[i]);
661  }
662  if (max_coor0_nodes.size() > 1)
663  {
664  Real max_coor1 = -std::numeric_limits<Real>::max();
665  std::vector<Node *> max_coor1_nodes;
666  for (unsigned int i = 0; i < nodes.size(); ++i)
667  {
668  Real coor1 = (*nodes[i])(dirs[1]);
669  if (coor1 > max_coor1)
670  max_coor1 = coor1;
671  }
672  for (unsigned int i = 0; i < nodes.size(); ++i)
673  {
674  Real coor1 = (*nodes[i])(dirs[1]);
675  if (MooseUtils::absoluteFuzzyEqual(coor1, max_coor1, _tol))
676  max_coor1_nodes.push_back(nodes[i]);
677  }
678  if (max_coor1_nodes.size() > 1)
679  {
680  Real max_coor2 = -std::numeric_limits<Real>::max();
681  std::vector<Node *> max_coor2_nodes;
682  for (unsigned int i = 0; i < nodes.size(); ++i)
683  {
684  Real coor2 = (*nodes[i])(dirs[2]);
685  if (coor2 > max_coor2)
686  max_coor2 = coor2;
687  }
688  for (unsigned int i = 0; i < nodes.size(); ++i)
689  {
690  Real coor2 = (*nodes[i])(dirs[2]);
691  if (MooseUtils::absoluteFuzzyEqual(coor2, max_coor2, _tol))
692  max_coor2_nodes.push_back(nodes[i]);
693  }
694  if (max_coor2_nodes.size() > 1)
695  mooseError("Multiple nodes with same x,y,z coordinates within tolerance");
696  else
697  return max_coor2_nodes[0]->id();
698  }
699  else
700  return max_coor1_nodes[0]->id();
701  }
702  else
703  return max_coor0_nodes[0]->id();
704 }

◆ orderCrackFrontNodes()

void CrackFrontDefinition::orderCrackFrontNodes ( std::set< dof_id_type > &  nodes)
protected

Definition at line 372 of file CrackFrontDefinition.C.

Referenced by initialSetup().

373 {
375  if (nodes.size() < 1)
376  mooseError("No crack front nodes");
377  else if (nodes.size() == 1)
378  {
379  _ordered_crack_front_nodes.push_back(*nodes.begin());
380  if (!_treat_as_2d)
381  mooseError("Boundary provided in CrackFrontDefinition contains 1 node, but model is not "
382  "treated as 2d");
383  }
384  else // nodes.size() > 1
385  {
386  // Loop through the set of crack front nodes, and create a node to element map for just the
387  // crack front nodes
388  // The main reason for creating a second map is that we need to do a sort prior to the
389  // set_intersection.
390  // The original map contains vectors, and we can't sort them, so we create sets in the local
391  // map.
392  const std::map<dof_id_type, std::vector<dof_id_type>> & node_to_elem_map =
393  _mesh.nodeToElemMap();
394  std::map<dof_id_type, std::set<dof_id_type>> crack_front_node_to_elem_map;
395 
396  for (const auto & node_id : nodes)
397  {
398  const auto & node_to_elem_pair = node_to_elem_map.find(node_id);
399  mooseAssert(node_to_elem_pair != node_to_elem_map.end(),
400  "Could not find crack front node " << node_id << "in the node to elem map");
401 
402  const std::vector<dof_id_type> & connected_elems = node_to_elem_pair->second;
403  for (unsigned int i = 0; i < connected_elems.size(); ++i)
404  crack_front_node_to_elem_map[node_id].insert(connected_elems[i]);
405  }
406 
407  // Determine which nodes are connected to each other via elements, and construct line elements
408  // to represent
409  // those connections
410  std::vector<std::vector<dof_id_type>> line_elems;
411  std::map<dof_id_type, std::vector<dof_id_type>> node_to_line_elem_map;
412 
413  for (std::map<dof_id_type, std::set<dof_id_type>>::iterator cfnemit =
414  crack_front_node_to_elem_map.begin();
415  cfnemit != crack_front_node_to_elem_map.end();
416  ++cfnemit)
417  {
418  std::map<dof_id_type, std::set<dof_id_type>>::iterator cfnemit2 = cfnemit;
419  for (++cfnemit2; cfnemit2 != crack_front_node_to_elem_map.end(); ++cfnemit2)
420  {
421 
422  std::vector<dof_id_type> common_elements;
423  std::set<dof_id_type> & elements_connected_to_node1 = cfnemit->second;
424  std::set<dof_id_type> & elements_connected_to_node2 = cfnemit2->second;
425  std::set_intersection(elements_connected_to_node1.begin(),
426  elements_connected_to_node1.end(),
427  elements_connected_to_node2.begin(),
428  elements_connected_to_node2.end(),
429  std::inserter(common_elements, common_elements.end()));
430 
431  if (common_elements.size() > 0)
432  {
433  std::vector<dof_id_type> my_line_elem;
434  my_line_elem.push_back(cfnemit->first);
435  my_line_elem.push_back(cfnemit2->first);
436  node_to_line_elem_map[cfnemit->first].push_back(line_elems.size());
437  node_to_line_elem_map[cfnemit2->first].push_back(line_elems.size());
438  line_elems.push_back(my_line_elem);
439  }
440  }
441  }
442 
443  // Find nodes on ends of line (those connected to only one line element)
444  std::vector<dof_id_type> end_nodes;
445  for (std::map<dof_id_type, std::vector<dof_id_type>>::iterator nlemit =
446  node_to_line_elem_map.begin();
447  nlemit != node_to_line_elem_map.end();
448  ++nlemit)
449  {
450  unsigned int num_connected_elems = nlemit->second.size();
451  if (num_connected_elems == 1)
452  end_nodes.push_back(nlemit->first);
453  else if (num_connected_elems != 2)
454  mooseError(
455  "Node ", nlemit->first, " is connected to >2 line segments in CrackFrontDefinition");
456  }
457 
458  // For embedded crack with closed loop of crack front nodes, must pick the end nodes
459  if (end_nodes.size() == 0) // Crack front is a loop. Pick nodes to be end nodes.
460  {
461  pickLoopCrackEndNodes(end_nodes, nodes, node_to_line_elem_map, line_elems);
462  _closed_loop = true;
464  mooseError("In CrackFrontDefinition, end_direction_method cannot be CrackDirectionVector "
465  "for a closed-loop crack");
466  if (_intersecting_boundary_names.size() > 0)
467  mooseError("In CrackFrontDefinition, intersecting_boundary cannot be specified for a "
468  "closed-loop crack");
469  }
470  else if (end_nodes.size() == 2) // Rearrange the order of the end nodes if needed
471  orderEndNodes(end_nodes);
472  else
473  mooseError("In CrackFrontDefinition wrong number of end nodes. Number end nodes = ",
474  end_nodes.size());
475 
476  // Create an ordered list of the nodes going along the line of the crack front
477  _ordered_crack_front_nodes.push_back(end_nodes[0]);
478 
479  dof_id_type last_node = end_nodes[0];
480  dof_id_type second_last_node = last_node;
481  while (last_node != end_nodes[1])
482  {
483  std::vector<dof_id_type> & curr_node_line_elems = node_to_line_elem_map[last_node];
484  bool found_new_node = false;
485  for (unsigned int i = 0; i < curr_node_line_elems.size(); ++i)
486  {
487  std::vector<dof_id_type> curr_line_elem = line_elems[curr_node_line_elems[i]];
488  for (unsigned int j = 0; j < curr_line_elem.size(); ++j)
489  {
490  dof_id_type line_elem_node = curr_line_elem[j];
491  if (_closed_loop &&
492  (last_node == end_nodes[0] &&
493  line_elem_node == end_nodes[1])) // wrong direction around closed loop
494  continue;
495  if (line_elem_node != last_node && line_elem_node != second_last_node)
496  {
497  _ordered_crack_front_nodes.push_back(line_elem_node);
498  found_new_node = true;
499  break;
500  }
501  }
502  if (found_new_node)
503  break;
504  }
505  second_last_node = last_node;
506  last_node = _ordered_crack_front_nodes.back();
507  }
508  }
509 }
END_DIRECTION_METHOD _end_direction_method
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)
void orderEndNodes(std::vector< dof_id_type > &end_nodes)
std::vector< BoundaryName > _intersecting_boundary_names
std::vector< unsigned int > _ordered_crack_front_nodes

◆ orderEndNodes()

void CrackFrontDefinition::orderEndNodes ( std::vector< dof_id_type > &  end_nodes)
protected

Definition at line 512 of file CrackFrontDefinition.C.

Referenced by orderCrackFrontNodes().

513 {
514  // Choose the node to be the first node. Do that based on undeformed coordinates for
515  // repeatability.
516  Node & node0 = _mesh.nodeRef(end_nodes[0]);
517  Node & node1 = _mesh.nodeRef(end_nodes[1]);
518 
519  unsigned int num_positive_coor0 = 0;
520  unsigned int num_positive_coor1 = 0;
521  Real dist_from_origin0 = 0.0;
522  Real dist_from_origin1 = 0.0;
523  for (unsigned int i = 0; i < 3; ++i)
524  {
525  dist_from_origin0 += node0(i) * node0(i);
526  dist_from_origin1 += node1(i) * node1(i);
527  if (MooseUtils::absoluteFuzzyGreaterThan(node0(i), 0.0, _tol))
528  ++num_positive_coor0;
529  if (MooseUtils::absoluteFuzzyGreaterThan(node1(i), 0.0, _tol))
530  ++num_positive_coor1;
531  }
532  dist_from_origin0 = std::sqrt(dist_from_origin0);
533  dist_from_origin1 = std::sqrt(dist_from_origin1);
534 
535  bool switch_ends = false;
536  if (num_positive_coor1 > num_positive_coor0)
537  {
538  switch_ends = true;
539  }
540  else
541  {
542  if (!MooseUtils::absoluteFuzzyEqual(dist_from_origin1, dist_from_origin0, _tol))
543  {
544  if (dist_from_origin1 < dist_from_origin0)
545  switch_ends = true;
546  }
547  else
548  {
549  if (end_nodes[1] < end_nodes[0])
550  switch_ends = true;
551  }
552  }
553  if (switch_ends)
554  {
555  unsigned int tmp_node = end_nodes[1];
556  end_nodes[1] = end_nodes[0];
557  end_nodes[0] = tmp_node;
558  }
559 }

◆ pickLoopCrackEndNodes()

void CrackFrontDefinition::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 
)
protected

Definition at line 562 of file CrackFrontDefinition.C.

Referenced by orderCrackFrontNodes().

567 {
568  unsigned int max_dist_node = 0;
569  Real min_dist = std::numeric_limits<Real>::max();
570  Real max_dist = -std::numeric_limits<Real>::max();
571  // Pick the node farthest from the origin as the end node, or the one with
572  // the greatest x coordinate if the nodes are equidistant from the origin
573  for (std::set<dof_id_type>::iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
574  {
575  Node & node = _mesh.nodeRef(*nit);
576  Real dist = node.norm();
577  if (dist > max_dist)
578  {
579  max_dist = dist;
580  max_dist_node = *nit;
581  }
582  else if (dist < min_dist)
583  min_dist = dist;
584  }
585 
586  unsigned int end_node;
587  if (MooseUtils::absoluteFuzzyGreaterThan(max_dist, min_dist, _tol))
588  end_node = max_dist_node;
589  else
590  {
591  std::vector<Node *> node_vec;
592  for (std::set<dof_id_type>::iterator nit = nodes.begin(); nit != nodes.end(); ++nit)
593  node_vec.push_back(_mesh.nodePtr(*nit));
594  end_node = maxNodeCoor(node_vec);
595  }
596 
597  end_nodes.push_back(end_node);
598 
599  // Find the two nodes connected to the node identified as the end node, and pick one of those to
600  // be the other end node
601  std::vector<dof_id_type> end_node_line_elems = node_to_line_elem_map[end_node];
602  if (end_node_line_elems.size() != 2)
603  mooseError(
604  "Crack front nodes are in a loop, but crack end node is only connected to one other node");
605  std::vector<Node *> candidate_other_end_nodes;
606 
607  for (unsigned int i = 0; i < 2; ++i)
608  {
609  std::vector<dof_id_type> end_line_elem = line_elems[end_node_line_elems[i]];
610  for (unsigned int j = 0; j < end_line_elem.size(); ++j)
611  {
612  unsigned int line_elem_node = end_line_elem[j];
613  if (line_elem_node != end_node)
614  candidate_other_end_nodes.push_back(_mesh.nodePtr(line_elem_node));
615  }
616  }
617  if (candidate_other_end_nodes.size() != 2)
618  mooseError(
619  "Crack front nodes are in a loop, but crack end node is not connected to two other nodes");
620  end_nodes.push_back(maxNodeCoor(candidate_other_end_nodes, 1));
621 }
unsigned int maxNodeCoor(std::vector< Node *> &nodes, unsigned int dir0=0)

◆ projectToFrontAtPoint()

void CrackFrontDefinition::projectToFrontAtPoint ( Real &  dist_to_front,
Real &  dist_along_tangent,
unsigned int  crack_front_point_index,
const Node *const  current_node 
) const
protected

Definition at line 1752 of file CrackFrontDefinition.C.

Referenced by DomainIntegralQFunction().

1756 {
1757  const Point * crack_front_point = getCrackFrontPoint(crack_front_point_index);
1758 
1759  Point p = *current_node;
1760  const RealVectorValue & crack_front_tangent = getCrackFrontTangent(crack_front_point_index);
1761 
1762  RealVectorValue crack_node_to_current_node = p - *crack_front_point;
1763  dist_along_tangent = crack_node_to_current_node * crack_front_tangent;
1764  RealVectorValue projection_point = *crack_front_point + dist_along_tangent * crack_front_tangent;
1765  RealVectorValue axis_to_current_node = p - projection_point;
1766  dist_to_front = axis_to_current_node.norm();
1767 }
const RealVectorValue & getCrackFrontTangent(const unsigned int point_index) const
const Point * getCrackFrontPoint(const unsigned int point_index) const

◆ rotateFromCrackFrontCoordsToGlobal()

RealVectorValue CrackFrontDefinition::rotateFromCrackFrontCoordsToGlobal ( const RealVectorValue  vector,
const unsigned int  point_index 
) const

rotate a vector from crack front cartesian coordinate to global cartesian coordinate

Parameters
point_indexthe crack front point index

Definition at line 1130 of file CrackFrontDefinition.C.

Referenced by EnrichmentFunctionCalculation::rotateFromCrackFrontCoordsToGlobal().

1132 {
1133  RealVectorValue vec = _rot_matrix[point_index].transpose() * vector;
1134  return vec;
1135 }
std::vector< RankTwoTensor > _rot_matrix

◆ rotateToCrackFrontCoords() [1/2]

RealVectorValue CrackFrontDefinition::rotateToCrackFrontCoords ( const RealVectorValue  vector,
const unsigned int  point_index 
) const

Definition at line 1123 of file CrackFrontDefinition.C.

Referenced by calculateRThetaToCrackFront(), InteractionIntegral::computeQpIntegral(), and InteractionIntegralSM::computeQpIntegral().

1125 {
1126  return _rot_matrix[point_index] * vector;
1127 }
std::vector< RankTwoTensor > _rot_matrix

◆ rotateToCrackFrontCoords() [2/2]

RankTwoTensor CrackFrontDefinition::rotateToCrackFrontCoords ( const RankTwoTensor  tensor,
const unsigned int  point_index 
) const

Definition at line 1138 of file CrackFrontDefinition.C.

1140 {
1141  RankTwoTensor tmp_tensor(tensor);
1142  tmp_tensor.rotate(_rot_matrix[point_index]);
1143  return tmp_tensor;
1144 }
std::vector< RankTwoTensor > _rot_matrix

◆ treatAs2D()

bool CrackFrontDefinition::treatAs2D ( ) const
inline

◆ updateCrackFrontGeometry()

void CrackFrontDefinition::updateCrackFrontGeometry ( )
protected

Definition at line 707 of file CrackFrontDefinition.C.

Referenced by initialSetup().

708 {
710 
711  _segment_lengths.clear();
712  _distances_along_front.clear();
713  _angles_along_front.clear();
714  _tangent_directions.clear();
715  _crack_directions.clear();
716  _rot_matrix.clear();
717 
718  if (_treat_as_2d)
719  {
720  RealVectorValue tangent_direction;
721  RealVectorValue crack_direction;
722  tangent_direction(_axis_2d) = 1.0;
723  _tangent_directions.push_back(tangent_direction);
724  const Point * crack_front_point = getCrackFrontPoint(0);
725  crack_direction =
726  calculateCrackFrontDirection(*crack_front_point, tangent_direction, MIDDLE_NODE);
727  _crack_directions.push_back(crack_direction);
728  _crack_plane_normal = tangent_direction.cross(crack_direction);
729  RankTwoTensor rot_mat;
730  rot_mat.fillRow(0, crack_direction);
731  rot_mat.fillRow(1, _crack_plane_normal);
732  rot_mat(2, _axis_2d) = 1.0;
733  _rot_matrix.push_back(rot_mat);
734 
735  _segment_lengths.push_back(std::make_pair(0.0, 0.0));
736  _distances_along_front.push_back(0.0);
737  _angles_along_front.push_back(0.0);
738  _overall_length = 0.0;
739  }
740  else
741  {
742  unsigned int num_crack_front_points = getNumCrackFrontPoints();
743  _segment_lengths.reserve(num_crack_front_points);
744  _tangent_directions.reserve(num_crack_front_points);
745  _crack_directions.reserve(num_crack_front_points);
746  _overall_length = 0.0;
747 
748  RealVectorValue back_segment;
749  Real back_segment_len = 0.0;
750  if (_closed_loop)
751  {
752  back_segment = *getCrackFrontPoint(0) - *getCrackFrontPoint(num_crack_front_points - 1);
753  back_segment_len = back_segment.norm();
754  }
755 
756  for (unsigned int i = 0; i < num_crack_front_points; ++i)
757  {
758  CRACK_NODE_TYPE ntype;
759  if (_closed_loop)
760  ntype = MIDDLE_NODE;
761  else if (i == 0)
762  ntype = END_1_NODE;
763  else if (i == num_crack_front_points - 1)
764  ntype = END_2_NODE;
765  else
766  ntype = MIDDLE_NODE;
767 
768  RealVectorValue forward_segment;
769  Real forward_segment_len;
770  if (ntype == END_2_NODE)
771  forward_segment_len = 0.0;
772  else if (_closed_loop && i == num_crack_front_points - 1)
773  {
774  forward_segment = *getCrackFrontPoint(0) - *getCrackFrontPoint(i);
775  forward_segment_len = forward_segment.norm();
776  }
777  else
778  {
779  forward_segment = *getCrackFrontPoint(i + 1) - *getCrackFrontPoint(i);
780  forward_segment_len = forward_segment.norm();
781  _overall_length += forward_segment_len;
782  }
783 
784  _segment_lengths.push_back(std::make_pair(back_segment_len, forward_segment_len));
785  if (i == 0)
786  _distances_along_front.push_back(0.0);
787  else
788  _distances_along_front.push_back(back_segment_len + _distances_along_front[i - 1]);
789 
790  RealVectorValue tangent_direction = back_segment + forward_segment;
791  tangent_direction = tangent_direction / tangent_direction.norm();
792  _tangent_directions.push_back(tangent_direction);
793  _crack_directions.push_back(
794  calculateCrackFrontDirection(*getCrackFrontPoint(i), tangent_direction, ntype));
795 
796  // If the end directions are given by the user, correct also the tangent at the end nodes
799  (ntype == END_1_NODE || ntype == END_2_NODE))
801 
802  back_segment = forward_segment;
803  back_segment_len = forward_segment_len;
804  }
805 
806  // For CURVED_CRACK_FRONT, _crack_plane_normal gets computed in updateDataForCrackDirection
808  {
809  unsigned int mid_id = (num_crack_front_points - 1) / 2;
811 
812  // Make sure the normal vector is non-zero
813  RealVectorValue zero_vec(0.0);
814  if (_crack_plane_normal.absolute_fuzzy_equals(zero_vec, _tol))
815  mooseError("Crack plane normal vector evaluates to zero");
816  }
817 
818  // Calculate angles of each point along the crack front for an elliptical crack projected
819  // to a circle.
820  if (hasAngleAlongFront())
821  {
822  RealVectorValue origin_to_first_node = *getCrackFrontPoint(0) - _crack_mouth_coordinates;
823  Real hyp = origin_to_first_node.norm();
824  RealVectorValue norm_origin_to_first_node = origin_to_first_node / hyp;
825  RealVectorValue tangent_to_first_node = -norm_origin_to_first_node.cross(_crack_plane_normal);
826  tangent_to_first_node /= tangent_to_first_node.norm();
827 
828  for (unsigned int i = 0; i < num_crack_front_points; ++i)
829  {
830  RealVectorValue origin_to_curr_node = *getCrackFrontPoint(i) - _crack_mouth_coordinates;
831 
832  Real adj = origin_to_curr_node * norm_origin_to_first_node;
833  Real opp = origin_to_curr_node * tangent_to_first_node;
834 
835  Real angle = acos(adj / hyp) * 180.0 / libMesh::pi;
836  if (opp < 0.0)
837  angle = 360.0 - angle;
838  _angles_along_front.push_back(angle);
839  }
840 
841  // Correct angle on end nodes if they are 0 or 360 to be consistent with neighboring node
842  if (num_crack_front_points > 1)
843  {
844  if (MooseUtils::absoluteFuzzyEqual(_angles_along_front[0], 0.0, _tol) &&
845  _angles_along_front[1] > 180.0)
846  _angles_along_front[0] = 360.0;
847  else if (MooseUtils::absoluteFuzzyEqual(_angles_along_front[0], 360.0, _tol) &&
848  _angles_along_front[1] < 180.0)
849  _angles_along_front[0] = 0.0;
850 
851  if (MooseUtils::absoluteFuzzyEqual(
852  _angles_along_front[num_crack_front_points - 1], 0.0, _tol) &&
853  _angles_along_front[num_crack_front_points - 2] > 180.0)
854  _angles_along_front[num_crack_front_points - 1] = 360.0;
855  else if (MooseUtils::absoluteFuzzyEqual(
856  _angles_along_front[num_crack_front_points - 1], 360.0, _tol) &&
857  _angles_along_front[num_crack_front_points - 2] < 180.0)
858  _angles_along_front[num_crack_front_points - 1] = 0.0;
859  }
860  }
861  else
862  _angles_along_front.resize(num_crack_front_points, 0.0);
863 
864  // Create rotation matrix
865  for (unsigned int i = 0; i < num_crack_front_points; ++i)
866  {
867  RankTwoTensor rot_mat;
868  rot_mat.fillRow(0, _crack_directions[i]);
869  rot_mat.fillRow(1, _crack_plane_normal);
870  rot_mat.fillRow(2, _tangent_directions[i]);
871  _rot_matrix.push_back(rot_mat);
872  }
873 
874  _console << "Summary of J-Integral crack front geometry:" << std::endl;
875  _console << "index node id x coord y coord z coord x dir y dir "
876  " z dir angle position seg length"
877  << std::endl;
878  for (unsigned int i = 0; i < num_crack_front_points; ++i)
879  {
880  unsigned int point_id;
882  point_id = _ordered_crack_front_nodes[i];
883  else
884  point_id = i;
885  _console << std::left << std::setw(8) << i + 1 << std::setw(10) << point_id << std::setw(14)
886  << (*getCrackFrontPoint(i))(0) << std::setw(14) << (*getCrackFrontPoint(i))(1)
887  << std::setw(14) << (*getCrackFrontPoint(i))(2) << std::setw(14)
888  << _crack_directions[i](0) << std::setw(14) << _crack_directions[i](1)
889  << std::setw(14) << _crack_directions[i](2);
890  if (hasAngleAlongFront())
891  _console << std::left << std::setw(14) << _angles_along_front[i];
892  else
893  _console << std::left << std::setw(14) << "--";
894  _console << std::left << std::setw(14) << _distances_along_front[i] << std::setw(14)
895  << (_segment_lengths[i].first + _segment_lengths[i].second) / 2.0 << std::endl;
896  }
897  _console << "overall length: " << _overall_length << std::endl;
898  }
899 }
unsigned int getNumCrackFrontPoints() const
std::vector< Real > _distances_along_front
END_DIRECTION_METHOD _end_direction_method
RealVectorValue calculateCrackFrontDirection(const Point &crack_front_point, const RealVectorValue &tangent_direction, const CRACK_NODE_TYPE ntype) const
DIRECTION_METHOD _direction_method
std::vector< RankTwoTensor > _rot_matrix
CRACK_GEOM_DEFINITION _geom_definition_method
std::vector< RealVectorValue > _crack_directions
RealVectorValue _crack_plane_normal
std::vector< RealVectorValue > _tangent_directions
const Point * getCrackFrontPoint(const unsigned int point_index) const
std::vector< Real > _angles_along_front
std::vector< std::pair< Real, Real > > _segment_lengths
std::vector< unsigned int > _ordered_crack_front_nodes
RealVectorValue _crack_mouth_coordinates

◆ updateDataForCrackDirection()

void CrackFrontDefinition::updateDataForCrackDirection ( )
protected

Definition at line 902 of file CrackFrontDefinition.C.

Referenced by updateCrackFrontGeometry().

903 {
904  if (_crack_mouth_boundary_ids.size() > 0)
905  {
907 
908  std::set<Node *> crack_mouth_nodes;
909  ConstBndNodeRange & bnd_nodes = *_mesh.getBoundaryNodeRange();
910  for (ConstBndNodeRange::const_iterator nd = bnd_nodes.begin(); nd != bnd_nodes.end(); ++nd)
911  {
912  const BndNode * bnode = *nd;
913  BoundaryID boundary_id = bnode->_bnd_id;
914 
915  for (unsigned int ibid = 0; ibid < _crack_mouth_boundary_ids.size(); ++ibid)
916  {
917  if (boundary_id == _crack_mouth_boundary_ids[ibid])
918  {
919  crack_mouth_nodes.insert(bnode->_node);
920  break;
921  }
922  }
923  }
924 
925  for (std::set<Node *>::iterator nit = crack_mouth_nodes.begin(); nit != crack_mouth_nodes.end();
926  ++nit)
927  {
928  _crack_mouth_coordinates += **nit;
929  }
930  _crack_mouth_coordinates /= static_cast<Real>(crack_mouth_nodes.size());
931 
934  }
935 
937  {
938  _crack_plane_normal.zero();
939 
940  // Get 3 nodes on crack front
941  unsigned int num_points = getNumCrackFrontPoints();
942  if (num_points < 3)
943  {
944  mooseError("Crack front must contain at least 3 nodes to use CurvedCrackFront option");
945  }
946  unsigned int start_id;
947  unsigned int mid_id;
948  unsigned int end_id;
949 
950  if (_closed_loop)
951  {
952  start_id = 0;
953  mid_id = (num_points - 1) / 3;
954  end_id = 2 * mid_id;
955  }
956  else
957  {
958  start_id = 0;
959  mid_id = (num_points - 1) / 2;
960  end_id = num_points - 1;
961  }
962  const Point * start = getCrackFrontPoint(start_id);
963  const Point * mid = getCrackFrontPoint(mid_id);
964  const Point * end = getCrackFrontPoint(end_id);
965 
966  // Create two vectors connecting them
967  RealVectorValue v1 = *mid - *start;
968  RealVectorValue v2 = *end - *mid;
969 
970  // Take cross product to get normal
971  _crack_plane_normal = v1.cross(v2);
973 
974  // Make sure they're not collinear
975  RealVectorValue zero_vec(0.0);
976  if (_crack_plane_normal.absolute_fuzzy_equals(zero_vec, _tol))
977  {
978  mooseError("Nodes on crack front are too close to being collinear");
979  }
980  }
981 }
unsigned int getNumCrackFrontPoints() const
DIRECTION_METHOD _direction_method
std::vector< BoundaryID > _crack_mouth_boundary_ids
RealVectorValue _crack_plane_normal
const Point * getCrackFrontPoint(const unsigned int point_index) const
RealVectorValue _crack_mouth_coordinates

Member Data Documentation

◆ _angles_along_front

std::vector<Real> CrackFrontDefinition::_angles_along_front
protected

Definition at line 136 of file CrackFrontDefinition.h.

Referenced by getAngleAlongFront(), and updateCrackFrontGeometry().

◆ _aux

AuxiliarySystem& CrackFrontDefinition::_aux
protected

Definition at line 125 of file CrackFrontDefinition.h.

◆ _axis_2d

unsigned int CrackFrontDefinition::_axis_2d
protected

Definition at line 153 of file CrackFrontDefinition.h.

Referenced by getCrackFrontNodes(), and updateCrackFrontGeometry().

◆ _closed_loop

bool CrackFrontDefinition::_closed_loop
protected

◆ _crack_direction_vector

RealVectorValue CrackFrontDefinition::_crack_direction_vector
protected

Definition at line 142 of file CrackFrontDefinition.h.

Referenced by calculateCrackFrontDirection(), and CrackFrontDefinition().

◆ _crack_direction_vector_end_1

RealVectorValue CrackFrontDefinition::_crack_direction_vector_end_1
protected

Definition at line 143 of file CrackFrontDefinition.h.

Referenced by calculateCrackFrontDirection(), and CrackFrontDefinition().

◆ _crack_direction_vector_end_2

RealVectorValue CrackFrontDefinition::_crack_direction_vector_end_2
protected

Definition at line 144 of file CrackFrontDefinition.h.

Referenced by calculateCrackFrontDirection(), and CrackFrontDefinition().

◆ _crack_directions

std::vector<RealVectorValue> CrackFrontDefinition::_crack_directions
protected

Definition at line 133 of file CrackFrontDefinition.h.

Referenced by getCrackDirection(), and updateCrackFrontGeometry().

◆ _crack_front_node_to_node_map

std::map<std::pair<dof_id_type, unsigned int>, std::set<dof_id_type> > CrackFrontDefinition::_crack_front_node_to_node_map
protected

Definition at line 164 of file CrackFrontDefinition.h.

Referenced by createQFunctionRings(), and isNodeInRing().

◆ _crack_front_points

std::vector<Point> CrackFrontDefinition::_crack_front_points
protected

◆ _crack_front_points_provider

const CrackFrontPointsProvider* CrackFrontDefinition::_crack_front_points_provider
protected

Definition at line 169 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and initialSetup().

◆ _crack_mouth_boundary_ids

std::vector<BoundaryID> CrackFrontDefinition::_crack_mouth_boundary_ids
protected

Definition at line 146 of file CrackFrontDefinition.h.

Referenced by initialSetup(), and updateDataForCrackDirection().

◆ _crack_mouth_boundary_names

std::vector<BoundaryName> CrackFrontDefinition::_crack_mouth_boundary_names
protected

Definition at line 145 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), hasAngleAlongFront(), and initialSetup().

◆ _crack_mouth_coordinates

RealVectorValue CrackFrontDefinition::_crack_mouth_coordinates
protected

◆ _crack_plane_normal

RealVectorValue CrackFrontDefinition::_crack_plane_normal
protected

◆ _direction_method

DIRECTION_METHOD CrackFrontDefinition::_direction_method
protected

◆ _disp_x_var_name

std::string CrackFrontDefinition::_disp_x_var_name
protected

◆ _disp_y_var_name

std::string CrackFrontDefinition::_disp_y_var_name
protected

◆ _disp_z_var_name

std::string CrackFrontDefinition::_disp_z_var_name
protected

◆ _distances_along_front

std::vector<Real> CrackFrontDefinition::_distances_along_front
protected

Definition at line 135 of file CrackFrontDefinition.h.

Referenced by getDistanceAlongFront(), and updateCrackFrontGeometry().

◆ _end_direction_method

END_DIRECTION_METHOD CrackFrontDefinition::_end_direction_method
protected

◆ _first_ring

unsigned int CrackFrontDefinition::_first_ring
protected

Definition at line 162 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition().

◆ _geom_definition_method

CRACK_GEOM_DEFINITION CrackFrontDefinition::_geom_definition_method
protected

◆ _has_symmetry_plane

bool CrackFrontDefinition::_has_symmetry_plane
protected

Definition at line 154 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and updateDataForCrackDirection().

◆ _intersecting_boundary_ids

std::vector<BoundaryID> CrackFrontDefinition::_intersecting_boundary_ids
protected

Definition at line 148 of file CrackFrontDefinition.h.

Referenced by initialSetup(), and isNodeOnIntersectingBoundary().

◆ _intersecting_boundary_names

std::vector<BoundaryName> CrackFrontDefinition::_intersecting_boundary_names
protected

◆ _is_point_on_intersecting_boundary

std::vector<bool> CrackFrontDefinition::_is_point_on_intersecting_boundary
protected

Definition at line 166 of file CrackFrontDefinition.h.

Referenced by DomainIntegralQFunction(), and initialSetup().

◆ _j_integral_radius_inner

std::vector<Real> CrackFrontDefinition::_j_integral_radius_inner
protected

Definition at line 167 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and DomainIntegralQFunction().

◆ _j_integral_radius_outer

std::vector<Real> CrackFrontDefinition::_j_integral_radius_outer
protected

Definition at line 168 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and DomainIntegralQFunction().

◆ _last_ring

unsigned int CrackFrontDefinition::_last_ring
protected

Definition at line 161 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and createQFunctionRings().

◆ _mesh

MooseMesh& CrackFrontDefinition::_mesh
protected

◆ _num_points_from_provider

unsigned int CrackFrontDefinition::_num_points_from_provider
protected

Definition at line 170 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and initialSetup().

◆ _ordered_crack_front_nodes

std::vector<unsigned int> CrackFrontDefinition::_ordered_crack_front_nodes
protected

◆ _overall_length

Real CrackFrontDefinition::_overall_length
protected

Definition at line 139 of file CrackFrontDefinition.h.

Referenced by updateCrackFrontGeometry().

◆ _q_function_rings

bool CrackFrontDefinition::_q_function_rings
protected

Definition at line 160 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and initialSetup().

◆ _q_function_type

MooseEnum CrackFrontDefinition::_q_function_type
protected

Definition at line 165 of file CrackFrontDefinition.h.

Referenced by initialSetup().

◆ _rot_matrix

std::vector<RankTwoTensor> CrackFrontDefinition::_rot_matrix
protected

◆ _segment_lengths

std::vector<std::pair<Real, Real> > CrackFrontDefinition::_segment_lengths
protected

◆ _strain_along_front

std::vector<Real> CrackFrontDefinition::_strain_along_front
protected

◆ _symmetry_plane

unsigned int CrackFrontDefinition::_symmetry_plane
protected

Definition at line 155 of file CrackFrontDefinition.h.

Referenced by CrackFrontDefinition(), and updateDataForCrackDirection().

◆ _t_stress

bool CrackFrontDefinition::_t_stress
protected

◆ _tangent_directions

std::vector<RealVectorValue> CrackFrontDefinition::_tangent_directions
protected

◆ _tol

const Real CrackFrontDefinition::_tol = 1e-10
staticprotected

◆ _treat_as_2d

bool CrackFrontDefinition::_treat_as_2d
protected

The documentation for this class was generated from the following files: