17#include "libmesh/edge_edge2.h"
18#include "libmesh/serial_mesh.h"
19#include "libmesh/mesh_tools.h"
25 params.
addParam<UserObjectName>(
"nucleate_uo",
"The MeshCutNucleation UO for nucleating cracks.");
26 params.
addParam<UserObjectName>(
"crack_front_definition",
27 "crackFrontDefinition",
28 "The CrackFrontDefinition user object name");
29 params.
addClassDescription(
"Creates a UserObject base class for a mesh cutter in 2D problems");
35 _mesh(_subproblem.
mesh()),
36 _nucleate_uo(isParamValid(
"nucleate_uo")
39 _is_mesh_modified(false)
41 _depend_uo.insert(getParam<UserObjectName>(
"crack_front_definition"));
44 for (
const auto & cut_elem :
_cutter_mesh->element_ptr_range())
46 if (cut_elem->n_nodes() != 2)
47 mooseError(
"The input cut mesh should include EDGE2 elements only!");
48 if (cut_elem->dim() != 1)
49 mooseError(
"The input cut mesh should have 1D elements (in a 2D space) only!");
59 const auto uo_name = getParam<UserObjectName>(
"crack_front_definition");
65 std::vector<Xfem::CutEdge> & cut_edges,
66 std::vector<Xfem::CutNode> & cut_nodes)
const
70 mooseAssert(elem->dim() == 2,
"Dimension of element to be cut must be 2");
72 bool elem_cut =
false;
74 for (
const auto & cut_elem :
_cutter_mesh->element_ptr_range())
76 unsigned int n_sides = elem->n_sides();
78 for (
unsigned int i = 0; i < n_sides; ++i)
80 std::unique_ptr<const Elem> curr_side = elem->side_ptr(i);
82 mooseAssert(curr_side->type() == EDGE2,
"Element side type must be EDGE2.");
84 const Node * node1 = curr_side->node_ptr(0);
85 const Node * node2 = curr_side->node_ptr(1);
86 Real seg_int_frac = 0.0;
88 const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
96 mycut.
_id1 = node1->id();
97 mycut.
_id2 = node2->id();
100 cut_edges.push_back(mycut);
106 mycut.
_id = node1->id();
108 cut_nodes.push_back(mycut);
118 std::vector<Xfem::CutFace> & )
const
120 mooseError(
"Invalid method for 2D mesh cutting.");
126 std::vector<Xfem::CutEdge> & cut_edges)
const
128 bool cut_frag =
false;
130 for (
const auto & cut_elem :
_cutter_mesh->element_ptr_range())
132 const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
133 unsigned int n_sides = frag_edges.size();
134 for (
unsigned int i = 0; i < n_sides; ++i)
136 Real seg_int_frac = 0.0;
138 frag_edges[i][0], frag_edges[i][1], elem_endpoints, 1, seg_int_frac))
143 mycut.
_id2 = (i < (n_sides - 1) ? (i + 1) : 0);
146 cut_edges.push_back(mycut);
155 std::vector<Xfem::CutFace> & )
const
157 mooseError(
"Invalid method for 2D mesh fragment cutting.");
167const std::vector<Point>
170 std::vector<Point> crack_front_points(number_crack_front_points);
174 mooseError(
"Number of nodes in CrackFrontDefinition does not match the number of nodes in the "
175 "cutter_mesh.\nCrackFrontDefinition nodes = " +
179 for (
unsigned int i = 0; i < number_crack_front_points; ++i)
183 mooseAssert(this_node,
"Node is NULL");
184 Point & this_point = *this_node;
185 crack_front_points[i] = this_point;
187 return crack_front_points;
190const std::vector<RealVectorValue>
194 mooseError(
"MeshCut2DFractureUserObject::getCrackPlaneNormals: number_crack_front_points=" +
196 " does not match the number of nodes given in "
197 "_original_and_current_front_node_ids=" +
199 ". This will happen if a crack front exits the boundary because the number of "
200 "points in the CrackFrontDefinition is never updated.");
202 std::vector<std::pair<dof_id_type, RealVectorValue>> crack_plane_normals;
203 for (
const auto & elem :
_cutter_mesh->element_ptr_range())
205 dof_id_type id0 = elem->node_id(0);
206 dof_id_type id1 = elem->node_id(1);
211 [&id0](
const std::pair<dof_id_type, dof_id_type> & element)
212 { return element.second == id0; });
215 [&id1](
const std::pair<dof_id_type, dof_id_type> & element)
216 { return element.second == id1; });
225 Point end_pt, connecting_pt;
227 end_pt = elem->node_ref(0);
228 connecting_pt = elem->node_ref(1);
231 Point fracture_dir = end_pt - connecting_pt;
235 RealVectorValue normal_dir{fracture_dir(1), -fracture_dir(0), 0};
236 normal_dir /= normal_dir.
norm();
237 crack_plane_normals.push_back(std::make_pair(
id, normal_dir));
242 Point end_pt, connecting_pt;
244 end_pt = elem->node_ref(1);
245 connecting_pt = elem->node_ref(0);
248 Point fracture_dir = end_pt - connecting_pt;
252 RealVectorValue normal_dir{fracture_dir(1), -fracture_dir(0), 0};
253 normal_dir /= normal_dir.
norm();
254 crack_plane_normals.push_back(std::make_pair(
id, normal_dir));
259 "Boundary nodes are attached to more than one element. This should not happen for a 1D "
261 "\n Number of _original_and_current_front_node_ids=" +
263 "\n Number of crack_plane_normals=" +
Moose::stringify(crack_plane_normals.size()));
266 std::sort(crack_plane_normals.begin(), crack_plane_normals.end());
267 std::vector<RealVectorValue> sorted_crack_plane_normals;
268 for (
auto & crack : crack_plane_normals)
269 sorted_crack_plane_normals.push_back(crack.second);
271 return sorted_crack_plane_normals;
278 pl->enable_out_of_mesh_mode();
279 std::unordered_set boundary_nodes = MeshTools::find_boundary_nodes(*
_cutter_mesh);
280 for (
const auto & node : boundary_nodes)
284 mooseAssert(this_node,
"Node is NULL");
285 Point & this_point = *this_node;
287 const Elem * elem = (*pl)(this_point);
298 dof_id_type current_front_node_id;
303 auto direction_iter =
306 [¤t_front_node_id](
const std::pair<dof_id_type, Point> & element)
307 { return element.first == current_front_node_id; });
311 Node * this_node =
_cutter_mesh->node_ptr(current_front_node_id);
312 mooseAssert(this_node,
"Node is NULL");
313 Point & this_point = *this_node;
315 Point new_node_offset = direction_iter->second;
316 Point
x = this_point + new_node_offset;
329 this_node = Node::build(
x,
_cutter_mesh->n_nodes()).release();
331 dof_id_type new_front_node_id =
_cutter_mesh->n_nodes() - 1;
334 std::vector<dof_id_type> elem;
335 elem.push_back(current_front_node_id);
336 elem.push_back(new_front_node_id);
337 Elem * new_elem = Elem::build(EDGE2).release();
338 for (
unsigned int i = 0; i < new_elem->n_nodes(); ++i)
340 mooseAssert(
_cutter_mesh->node_ptr(elem[i]) !=
nullptr,
"Node is NULL");
358 std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> nucleated_elems_map =
366 pl->enable_out_of_mesh_mode();
367 for (
const auto & elem_nodes : nucleated_elems_map)
369 std::pair<RealVectorValue, RealVectorValue> nodes = elem_nodes.second;
371 Node * node_0 = Node::build(nodes.first,
_cutter_mesh->n_nodes()).release();
374 Node * node_1 = Node::build(nodes.second,
_cutter_mesh->n_nodes()).release();
378 std::vector<dof_id_type> elem;
379 elem.push_back(node_id_0);
380 elem.push_back(node_id_1);
381 Elem * new_elem = Elem::build(EDGE2).release();
382 for (
unsigned int i = 0; i < new_elem->n_nodes(); ++i)
384 mooseAssert(
_cutter_mesh->node_ptr(elem[i]) !=
nullptr,
"Node is NULL");
391 Point & point_0 = *node_0;
392 const Elem * crack_front_elem_0 = (*pl)(point_0);
393 if (crack_front_elem_0 != NULL)
396 Point & point_1 = *node_1;
397 const Elem * crack_front_elem_1 = (*pl)(point_1);
398 if (crack_front_elem_1 != NULL)
409 std::map<
unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
410 const Real nucleationRadius)
413 for (
auto it1 = nucleated_elems_map.begin(); it1 != nucleated_elems_map.end(); ++it1)
415 std::pair<RealVectorValue, RealVectorValue> nodes = it1->second;
416 Point p2 = nodes.first;
417 Point p1 = nodes.second;
418 Point
p = p1 + (p2 - p1) / 2;
419 for (
auto it2 = nucleated_elems_map.begin(); it2 != nucleated_elems_map.end();)
430 Point q = p1 + (p2 - p1) / 2;
432 if (pq.norm() <= nucleationRadius)
433 it2 = nucleated_elems_map.erase(it2);
442 std::map<
unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
443 const Real nucleationRadius)
445 for (
auto it = nucleated_elems_map.begin(); it != nucleated_elems_map.end();)
447 std::pair<RealVectorValue, RealVectorValue> nodes = it->second;
448 Point p2 = nodes.first;
449 Point p1 = nodes.second;
450 Point
p = p1 + (p2 - p1) / 2;
451 bool removeNucleatedElem =
false;
452 for (
const auto & cutter_elem :
455 const Node *
const * cutter_elem_nodes = cutter_elem->get_nodes();
456 Point m = *cutter_elem_nodes[1] - *cutter_elem_nodes[0];
457 Real t = m * (
p - *cutter_elem_nodes[0]) / m.norm_sq();
458 Real
d = std::numeric_limits<Real>::max();
461 Point j =
p - *cutter_elem_nodes[0];
466 Point j =
p - *cutter_elem_nodes[1];
471 Point j =
p - (*cutter_elem_nodes[0] + t * m);
474 if (
d <= nucleationRadius)
476 removeNucleatedElem =
true;
480 if (removeNucleatedElem)
481 it = nucleated_elems_map.erase(it);
const std::vector< double > x
Class used in fracture integrals to define geometric characteristics of the crack front.
T & getUserObject(const std::string &name, unsigned int tid=0) const
std::map< unsigned int, std::pair< RealVectorValue, RealVectorValue > > getNucleatedElemsMap() const
Provide getter to MeshCut2DUserObjectBase for a map of nucleated cracks.
Real getNucleationRadius() const
Provide getter to MeshCut2DUserObjectBase for member data set in input.
void addNucleatedCracksToMesh()
Calls into MeshCutNucleation UO to add cracks.
void growFront()
grow the cutter mesh
void findOriginalCrackFrontNodes()
Find the original crack front nodes in the cutter mesh and use to populate _original_and_current_fron...
virtual unsigned int getNumberOfCrackFrontPoints() const override
Get the current number of crack front points.
virtual const std::vector< Point > getCrackFrontPoints(unsigned int num_crack_front_points) const override
get a set of points along a crack front from a XFEM GeometricCutUserObject
virtual bool cutFragmentByGeometry(std::vector< std::vector< Point > > &frag_edges, std::vector< Xfem::CutEdge > &cut_edges) const override
static InputParameters validParams()
void removeNucleatedCracksTooCloseToExistingCracks(std::map< unsigned int, std::pair< RealVectorValue, RealVectorValue > > &nucleated_elems_map, Real nucleationRadius)
Remove nucleated cracks that are too close to a pre-existing crack in the mesh.
const MeshCut2DNucleationBase * _nucleate_uo
2D UO for nucleating cracks
std::vector< std::pair< dof_id_type, dof_id_type > > _original_and_current_front_node_ids
This vector of pairs orders crack tips to make the order used in this class the same as those for the...
std::vector< std::pair< dof_id_type, Point > > _active_front_node_growth_vectors
contains the active node ids and their growth vectors
virtual const std::vector< RealVectorValue > getCrackPlaneNormals(unsigned int num_crack_front_points) const override
get a set of normal vectors along a crack front from a XFEM GeometricCutUserObject CrackFrontDefiniti...
void removeNucleatedCracksTooCloseToEachOther(std::map< unsigned int, std::pair< RealVectorValue, RealVectorValue > > &nucleated_elems_map, Real nucleationRadius)
Remove nucleated cracks that are too close too each other.
virtual bool cutElementByGeometry(const Elem *elem, std::vector< Xfem::CutEdge > &cut_edges, std::vector< Xfem::CutNode > &cut_nodes) const override
bool _is_mesh_modified
Indicator that shows if the cutting mesh is modified or not in this calculation step.
virtual void initialSetup() override final
MeshCut2DUserObjectBase(const InputParameters ¶meters)
MooseMesh & _mesh
The FE solution mesh.
CrackFrontDefinition * _crack_front_definition
user object for communicating between solid_mechanics interaction integrals and xfem cutter mesh
Simple base class for XFEM cutting objects that use a mesh to cut.
static InputParameters validParams()
std::unique_ptr< MeshBase > _cutter_mesh
The xfem cutter mesh.
void mooseError(Args &&... args) const
virtual std::unique_ptr< libMesh::PointLocatorBase > getPointLocator() const
std::set< std::string > _depend_uo
FEProblemBase & _fe_problem
std::string stringify(const T &t)
bool intersectSegmentWithCutLine(const Point &segment_point1, const Point &segment_point2, const std::pair< Point, Point > &cutting_line_points, const Real &cutting_line_fraction, Real &segment_intersection_fraction)
Determine whether a line segment is intersected by a cutting line, and compute the fraction along tha...
Data structure defining a cut on an element edge.
unsigned int _id1
ID of the first node on the edge.
Real _distance
Fractional distance along the edge (from node 1 to 2) where the cut is located.
unsigned int _id2
ID of the second node on the edge.
unsigned int _host_side_id
Local ID of this side in the host element.
Data structure defining a cut through a node.
unsigned int _id
ID of the cut node.
unsigned int _host_id
Local ID of this node in the host element.