17 #include "libmesh/edge_edge2.h" 18 #include "libmesh/serial_mesh.h" 19 #include "libmesh/mesh_tools.h" 27 "Mesh file for the XFEM geometric cut; currently only the Exodus type is supported");
28 params.
addParam<UserObjectName>(
"nucleate_uo",
"The MeshCutNucleation UO for nucleating cracks.");
29 params.
addParam<UserObjectName>(
"crack_front_definition",
30 "crackFrontDefinition",
31 "The CrackFrontDefinition user object name");
32 params.
addClassDescription(
"Creates a UserObject base class for a mesh cutter in 2D problems");
38 _mesh(_subproblem.
mesh()),
39 _nucleate_uo(isParamValid(
"nucleate_uo")
42 _is_mesh_modified(false)
44 _depend_uo.insert(getParam<UserObjectName>(
"crack_front_definition"));
47 MeshFileName cutterMeshFileName = getParam<MeshFileName>(
"mesh_file");
51 for (
const auto & cut_elem :
_cutter_mesh->element_ptr_range())
53 if (cut_elem->n_nodes() != 2)
54 mooseError(
"The input cut mesh should include EDGE2 elements only!");
55 if (cut_elem->dim() != 1)
56 mooseError(
"The input cut mesh should have 1D elements (in a 2D space) only!");
66 const auto uo_name = getParam<UserObjectName>(
"crack_front_definition");
72 std::vector<Xfem::CutEdge> & cut_edges,
73 std::vector<Xfem::CutNode> & cut_nodes)
const 77 mooseAssert(elem->dim() == 2,
"Dimension of element to be cut must be 2");
79 bool elem_cut =
false;
81 for (
const auto & cut_elem :
_cutter_mesh->element_ptr_range())
83 unsigned int n_sides = elem->n_sides();
85 for (
unsigned int i = 0; i < n_sides; ++i)
87 std::unique_ptr<const Elem> curr_side = elem->side_ptr(i);
89 mooseAssert(curr_side->type() ==
EDGE2,
"Element side type must be EDGE2.");
91 const Node * node1 = curr_side->node_ptr(0);
92 const Node * node2 = curr_side->node_ptr(1);
93 Real seg_int_frac = 0.0;
95 const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
103 mycut.
_id1 = node1->id();
104 mycut.
_id2 = node2->id();
107 cut_edges.push_back(mycut);
113 mycut.
_id = node1->id();
115 cut_nodes.push_back(mycut);
125 std::vector<Xfem::CutFace> & )
const 127 mooseError(
"Invalid method for 2D mesh cutting.");
133 std::vector<Xfem::CutEdge> & cut_edges)
const 135 bool cut_frag =
false;
137 for (
const auto & cut_elem :
_cutter_mesh->element_ptr_range())
139 const std::pair<Point, Point> elem_endpoints(cut_elem->node_ref(0), cut_elem->node_ref(1));
140 unsigned int n_sides = frag_edges.size();
141 for (
unsigned int i = 0; i < n_sides; ++i)
143 Real seg_int_frac = 0.0;
145 frag_edges[i][0], frag_edges[i][1], elem_endpoints, 1, seg_int_frac))
150 mycut.
_id2 = (i < (n_sides - 1) ? (i + 1) : 0);
153 cut_edges.push_back(mycut);
162 std::vector<Xfem::CutFace> & )
const 164 mooseError(
"Invalid method for 2D mesh fragment cutting.");
171 mooseAssert(
_cutter_mesh,
"MeshCut2DUserObjectBase::getCutterMesh _cutter_mesh is nullptr");
175 const std::vector<Point>
178 std::vector<Point> crack_front_points(number_crack_front_points);
182 mooseError(
"MeshCut2DFractureUserObject::getCrackFrontPoints: number_crack_front_points=" +
184 " does not match the number of nodes given in " 185 "_original_and_current_front_node_ids=" +
188 for (
unsigned int i = 0; i < number_crack_front_points; ++i)
192 mooseAssert(this_node,
"Node is NULL");
193 Point & this_point = *this_node;
194 crack_front_points[i] = this_point;
196 return crack_front_points;
199 const std::vector<RealVectorValue>
203 mooseError(
"MeshCut2DFractureUserObject::getCrackPlaneNormals: number_crack_front_points=" +
205 " does not match the number of nodes given in " 206 "_original_and_current_front_node_ids=" +
208 ". This will happen if a crack front exits the boundary because the number of " 209 "points in the CrackFrontDefinition is never updated.");
211 std::vector<std::pair<dof_id_type, RealVectorValue>> crack_plane_normals;
212 for (
const auto & elem :
_cutter_mesh->element_ptr_range())
220 [&id0](
const std::pair<dof_id_type, dof_id_type> & element)
221 {
return element.second == id0; });
224 [&id1](
const std::pair<dof_id_type, dof_id_type> & element)
225 {
return element.second == id1; });
234 Point end_pt, connecting_pt;
236 end_pt = elem->node_ref(0);
237 connecting_pt = elem->node_ref(1);
240 Point fracture_dir = end_pt - connecting_pt;
245 normal_dir /= normal_dir.
norm();
246 crack_plane_normals.push_back(std::make_pair(
id, normal_dir));
251 Point end_pt, connecting_pt;
253 end_pt = elem->node_ref(1);
254 connecting_pt = elem->node_ref(0);
257 Point fracture_dir = end_pt - connecting_pt;
262 normal_dir /= normal_dir.
norm();
263 crack_plane_normals.push_back(std::make_pair(
id, normal_dir));
268 "Boundary nodes are attached to more than one element. This should not happen for a 1D " 270 "\n Number of _original_and_current_front_node_ids=" +
272 "\n Number of crack_plane_normals=" +
Moose::stringify(crack_plane_normals.size()));
275 std::sort(crack_plane_normals.begin(), crack_plane_normals.end());
276 std::vector<RealVectorValue> sorted_crack_plane_normals;
277 for (
auto & crack : crack_plane_normals)
278 sorted_crack_plane_normals.push_back(crack.second);
280 return sorted_crack_plane_normals;
287 pl->enable_out_of_mesh_mode();
288 std::unordered_set boundary_nodes = MeshTools::find_boundary_nodes(*
_cutter_mesh);
289 for (
const auto & node : boundary_nodes)
293 mooseAssert(this_node,
"Node is NULL");
294 Point & this_point = *this_node;
296 const Elem * elem = (*pl)(this_point);
312 auto direction_iter =
315 [¤t_front_node_id](
const std::pair<dof_id_type, Point> & element)
316 {
return element.first == current_front_node_id; });
320 Node * this_node =
_cutter_mesh->node_ptr(current_front_node_id);
321 mooseAssert(this_node,
"Node is NULL");
322 Point & this_point = *this_node;
324 Point new_node_offset = direction_iter->second;
325 Point
x = this_point + new_node_offset;
338 this_node = Node::build(
x,
_cutter_mesh->n_nodes()).release();
343 std::vector<dof_id_type> elem;
344 elem.push_back(current_front_node_id);
345 elem.push_back(new_front_node_id);
346 Elem * new_elem = Elem::build(
EDGE2).release();
347 for (
unsigned int i = 0; i < new_elem->n_nodes(); ++i)
349 mooseAssert(
_cutter_mesh->node_ptr(elem[i]) !=
nullptr,
"Node is NULL");
367 std::map<unsigned int, std::pair<RealVectorValue, RealVectorValue>> nucleated_elems_map =
375 pl->enable_out_of_mesh_mode();
376 for (
const auto & elem_nodes : nucleated_elems_map)
378 std::pair<RealVectorValue, RealVectorValue> nodes = elem_nodes.second;
380 Node * node_0 = Node::build(nodes.first,
_cutter_mesh->n_nodes()).release();
383 Node * node_1 = Node::build(nodes.second,
_cutter_mesh->n_nodes()).release();
387 std::vector<dof_id_type> elem;
388 elem.push_back(node_id_0);
389 elem.push_back(node_id_1);
390 Elem * new_elem = Elem::build(
EDGE2).release();
391 for (
unsigned int i = 0; i < new_elem->n_nodes(); ++i)
393 mooseAssert(
_cutter_mesh->node_ptr(elem[i]) !=
nullptr,
"Node is NULL");
400 Point & point_0 = *node_0;
401 const Elem * crack_front_elem_0 = (*pl)(point_0);
402 if (crack_front_elem_0 != NULL)
405 Point & point_1 = *node_1;
406 const Elem * crack_front_elem_1 = (*pl)(point_1);
407 if (crack_front_elem_1 != NULL)
418 std::map<
unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
419 const Real nucleationRadius)
422 for (
auto it1 = nucleated_elems_map.begin(); it1 != nucleated_elems_map.end(); ++it1)
424 std::pair<RealVectorValue, RealVectorValue> nodes = it1->second;
425 Point p2 = nodes.first;
426 Point p1 = nodes.second;
427 Point p = p1 + (p2 - p1) / 2;
428 for (
auto it2 = nucleated_elems_map.begin(); it2 != nucleated_elems_map.end();)
439 Point q = p1 + (p2 - p1) / 2;
441 if (pq.norm() <= nucleationRadius)
442 it2 = nucleated_elems_map.erase(it2);
451 std::map<
unsigned int, std::pair<RealVectorValue, RealVectorValue>> & nucleated_elems_map,
452 const Real nucleationRadius)
454 for (
auto it = nucleated_elems_map.begin(); it != nucleated_elems_map.end();)
456 std::pair<RealVectorValue, RealVectorValue> nodes = it->second;
457 Point p2 = nodes.first;
458 Point p1 = nodes.second;
459 Point p = p1 + (p2 - p1) / 2;
460 bool removeNucleatedElem =
false;
461 for (
const auto & cutter_elem :
464 const Node *
const * cutter_elem_nodes = cutter_elem->get_nodes();
465 Point m = *cutter_elem_nodes[1] - *cutter_elem_nodes[0];
466 Real t = m * (p - *cutter_elem_nodes[0]) / m.norm_sq();
467 Real d = std::numeric_limits<Real>::max();
470 Point
j = p - *cutter_elem_nodes[0];
475 Point
j = p - *cutter_elem_nodes[1];
480 Point
j = p - (*cutter_elem_nodes[0] + t * m);
483 if (
d <= nucleationRadius)
485 removeNucleatedElem =
true;
489 if (removeNucleatedElem)
490 it = nucleated_elems_map.erase(it);
Data structure defining a cut through a node.
static InputParameters validParams()
Factory constructor, takes parameters so that all derived classes can be built using the same constru...
auto norm() const -> decltype(std::norm(Real()))
virtual bool cutElementByGeometry(const Elem *elem, std::vector< Xfem::CutEdge > &cut_edges, std::vector< Xfem::CutNode > &cut_nodes) const override
T & getUserObject(const std::string &name, unsigned int tid=0) const
static InputParameters validParams()
void findOriginalCrackFrontNodes()
Find the original crack front nodes in the cutter mesh and use to populate _original_and_current_fron...
MeshCut2DUserObjectBase(const InputParameters ¶meters)
unsigned int _host_id
Local ID of this node in the host element.
std::unique_ptr< MeshBase > _cutter_mesh
The xfem cutter mesh.
const Parallel::Communicator & _communicator
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...
virtual bool cutFragmentByGeometry(std::vector< std::vector< Point >> &frag_edges, std::vector< Xfem::CutEdge > &cut_edges) const override
Data structure defining a cut on an element edge.
Class used in fracture integrals to define geometric characteristics of the crack front...
Real getNucleationRadius() const
Provide getter to MeshCut2DUserObjectBase for member data set in input.
unsigned int _id1
ID of the first node on the edge.
const std::vector< double > x
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
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...
MooseMesh & _mesh
The FE solution mesh.
std::map< unsigned int, std::pair< RealVectorValue, RealVectorValue > > getNucleatedElemsMap() const
Provide getter to MeshCut2DUserObjectBase for a map of nucleated cracks.
void addNucleatedCracksToMesh()
Calls into MeshCutNucleation UO to add cracks.
const MeshCut2DNucleationBase * _nucleate_uo
2D UO for nucleating cracks
virtual void initialSetup() override final
MeshBase & getCutterMesh() const
std::set< std::string > _depend_uo
Real _distance
Fractional distance along the edge (from node 1 to 2) where the cut is located.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _id2
ID of the second node on the edge.
FEProblemBase & _fe_problem
bool _is_mesh_modified
Indicator that shows if the cutting mesh is modified or not in this calculation step.
void mooseError(Args &&... args) const
unsigned int _host_side_id
Local ID of this side in the host element.
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
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
virtual std::unique_ptr< libMesh::PointLocatorBase > getPointLocator() const
void growFront()
grow the cutter mesh
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.
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.
std::vector< std::pair< dof_id_type, Point > > _active_front_node_growth_vectors
contains the active node ids and their growth vectors
unsigned int _id
ID of the cut node.
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...
CrackFrontDefinition * _crack_front_definition
user object for communicating between solid_mechanics interaction integrals and xfem cutter mesh ...