14 #include "libmesh/elem.h" 15 #include "libmesh/boundary_info.h" 16 #include "libmesh/mesh_base.h" 17 #include "libmesh/parallel.h" 18 #include "libmesh/parallel_algebra.h" 19 #include "libmesh/cell_tet4.h" 30 params.
addRequiredParam<MeshGeneratorName>(
"input",
"The input mesh that needs to be trimmed.");
33 "The boundary id of the face generated by the cut. An " 34 "id will be automatically assigned if not provided.");
36 "cut_face_name", BoundaryName(),
"The boundary name of the face generated by the cut.");
39 "This CutMeshByLevelSetGeneratorBase object is designed to be the base class of mesh " 40 "generator that cuts a 3D mesh based on an analytic level set function. The level set " 41 "function could be provided explicitly or indirectly.");
49 _input_name(getParam<MeshGeneratorName>(
"input")),
50 _cut_face_name(getParam<BoundaryName>(
"cut_face_name")),
51 _input(getMeshByName(_input_name))
56 std::unique_ptr<MeshBase>
59 auto replicated_mesh_ptr =
dynamic_cast<ReplicatedMesh *
>(
_input.get());
60 if (!replicated_mesh_ptr)
61 paramError(
"input",
"Input is not a replicated mesh, which is required");
62 if (*(replicated_mesh_ptr->elem_dimensions().begin()) != 3 ||
63 *(replicated_mesh_ptr->elem_dimensions().rbegin()) != 3)
66 "Only 3D meshes are supported. Use XYMeshLineCutter for 2D meshes if applicable. Mixed " 67 "dimensional meshes are not supported at the moment.");
69 ReplicatedMesh &
mesh = *replicated_mesh_ptr;
79 "The cut face boundary name and id are both provided, but they are inconsistent " 80 "with an existing boundary name which has a different id.");
97 std::set<subdomain_id_type> subdomain_ids_set;
98 mesh.subdomain_ids(subdomain_ids_set);
104 std::vector<std::pair<dof_id_type, bool>> cross_and_remained_elems_pre_convert;
106 for (
auto elem_it =
mesh.active_elements_begin(); elem_it !=
mesh.active_elements_end();
109 const unsigned int & n_vertices = (*elem_it)->n_vertices();
110 unsigned short elem_vertices_counter(0);
111 for (
unsigned int i = 0; i < n_vertices; i++)
117 elem_vertices_counter++;
119 if (elem_vertices_counter == n_vertices)
120 (*elem_it)->subdomain_id() = block_id_to_remove;
124 if ((*elem_it)->default_order() != Order::FIRST)
125 mooseError(
"Only first order elements are supported for cutting.");
126 cross_and_remained_elems_pre_convert.push_back(
127 std::make_pair((*elem_it)->id(), elem_vertices_counter > 0));
131 std::vector<dof_id_type> converted_elems_ids_to_cut;
134 cross_and_remained_elems_pre_convert,
135 converted_elems_ids_to_cut,
139 std::vector<const Node *> new_on_plane_nodes;
142 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
143 const auto bdry_side_list = boundary_info.build_side_list();
145 for (
const auto & converted_elems_id_to_cut : converted_elems_ids_to_cut)
148 mesh, bdry_side_list, converted_elems_id_to_cut, block_id_to_remove, new_on_plane_nodes);
152 for (
auto elem_it =
mesh.active_subdomain_elements_begin(block_id_to_remove);
153 elem_it !=
mesh.active_subdomain_elements_end(block_id_to_remove);
155 mesh.delete_elem(*elem_it);
158 mesh.set_isnt_prepared();
176 const Point & point2)
182 mooseError(
"At least one of the two points are on the plane.");
184 mooseError(
"The two points are on the same side of the plane.");
194 mid_point = 0.5 * (p1 + p2);
199 else if (dist_mid * dist1 < 0.0)
203 dist =
abs(dist1) +
abs(dist2);
209 dist =
abs(dist1) +
abs(dist2);
217 ReplicatedMesh & mesh,
218 std::vector<const Node *> & new_on_plane_nodes,
219 const Point & new_point)
const 221 for (
const auto & new_on_plane_node : new_on_plane_nodes)
224 return new_on_plane_node;
226 new_on_plane_nodes.push_back(
mesh.add_point(new_point));
227 return new_on_plane_nodes.back();
232 ReplicatedMesh & mesh,
233 const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
236 std::vector<const Node *> & new_on_plane_nodes)
239 BoundaryInfo & boundary_info =
mesh.get_boundary_info();
245 std::vector<Point> elem_side_normal_list;
246 elem_side_normal_list.resize(4);
249 auto elem_side =
mesh.elem_ptr(elem_id)->side_ptr(i);
250 elem_side_normal_list[i] = (*elem_side->node_ptr(1) - *elem_side->node_ptr(0))
251 .cross(*elem_side->node_ptr(2) - *elem_side->node_ptr(1))
255 std::vector<std::vector<boundary_id_type>> elem_side_list;
257 bdry_side_list, elem_id, 4, elem_side_list);
259 std::vector<PointLevelSetRelationIndex> node_plane_relation(4);
260 std::vector<const Node *> tet4_nodes(4);
261 std::vector<const Node *> tet4_nodes_on_plane;
262 std::vector<const Node *> tet4_nodes_outside_plane;
263 std::vector<const Node *> tet4_nodes_inside_plane;
265 for (
unsigned int i = 0; i < 4; i++)
267 tet4_nodes[i] =
mesh.elem_ptr(elem_id)->node_ptr(i);
270 tet4_nodes_on_plane.push_back(tet4_nodes[i]);
272 tet4_nodes_outside_plane.push_back(tet4_nodes[i]);
274 tet4_nodes_inside_plane.push_back(tet4_nodes[i]);
276 std::vector<Elem *> elems_tet4;
277 bool new_elements_created(
false);
279 if (tet4_nodes_outside_plane.size() == 0)
281 if (tet4_nodes_on_plane.size() == 3)
284 elems_tet4.push_back(
mesh.elem_ptr(elem_id));
288 else if (tet4_nodes_inside_plane.size() == 0)
290 mesh.elem_ptr(elem_id)->subdomain_id() = block_id_to_remove;
291 if (tet4_nodes_on_plane.size() == 3)
300 new_elements_created =
true;
301 if (tet4_nodes_inside_plane.size() == 1 && tet4_nodes_outside_plane.size() == 3)
303 std::vector<const Node *> new_plane_nodes;
305 for (
const auto & tet4_node_outside_plane : tet4_nodes_outside_plane)
312 auto new_elem_tet4 = std::make_unique<Tet4>();
313 new_elem_tet4->set_node(0, const_cast<Node *>(tet4_nodes_inside_plane[0]));
314 new_elem_tet4->set_node(1, const_cast<Node *>(new_plane_nodes[0]));
315 new_elem_tet4->set_node(2, const_cast<Node *>(new_plane_nodes[1]));
316 new_elem_tet4->set_node(3, const_cast<Node *>(new_plane_nodes[2]));
317 new_elem_tet4->subdomain_id() =
mesh.elem_ptr(elem_id)->subdomain_id();
318 elems_tet4.push_back(
mesh.add_elem(std::move(new_elem_tet4)));
320 else if (tet4_nodes_inside_plane.size() == 2 && tet4_nodes_outside_plane.size() == 2)
322 std::vector<const Node *> new_plane_nodes;
324 for (
const auto & tet4_node_outside_plane : tet4_nodes_outside_plane)
326 for (
const auto & tet4_node_inside_plane : tet4_nodes_inside_plane)
334 std::vector<const Node *> new_elems_nodes = {tet4_nodes_inside_plane[1],
337 tet4_nodes_inside_plane[0],
340 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
341 std::vector<std::vector<const Node *>> optimized_node_list;
343 new_elems_nodes, rotated_tet_face_indices, optimized_node_list);
345 for (
unsigned int i = 0; i < optimized_node_list.size(); i++)
347 auto new_elem_tet4 = std::make_unique<Tet4>();
348 new_elem_tet4->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
349 new_elem_tet4->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
350 new_elem_tet4->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
351 new_elem_tet4->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
352 new_elem_tet4->subdomain_id() =
mesh.elem_ptr(elem_id)->subdomain_id();
353 elems_tet4.push_back(
mesh.add_elem(std::move(new_elem_tet4)));
356 else if (tet4_nodes_inside_plane.size() == 3 && tet4_nodes_outside_plane.size() == 1)
358 std::vector<const Node *> new_plane_nodes;
360 for (
const auto & tet4_node_inside_plane : tet4_nodes_inside_plane)
367 std::vector<const Node *> new_elems_nodes = {tet4_nodes_inside_plane[0],
368 tet4_nodes_inside_plane[1],
369 tet4_nodes_inside_plane[2],
373 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
374 std::vector<std::vector<const Node *>> optimized_node_list;
376 new_elems_nodes, rotated_tet_face_indices, optimized_node_list);
378 for (
unsigned int i = 0; i < optimized_node_list.size(); i++)
380 auto new_elem_tet4 = std::make_unique<Tet4>();
381 new_elem_tet4->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
382 new_elem_tet4->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
383 new_elem_tet4->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
384 new_elem_tet4->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
385 new_elem_tet4->subdomain_id() =
mesh.elem_ptr(elem_id)->subdomain_id();
386 elems_tet4.push_back(
mesh.add_elem(std::move(new_elem_tet4)));
389 else if (tet4_nodes_inside_plane.size() == 1 && tet4_nodes_outside_plane.size() == 1)
396 auto new_elem_tet4 = std::make_unique<Tet4>();
397 new_elem_tet4->set_node(0, const_cast<Node *>(new_plane_node));
398 new_elem_tet4->set_node(1, const_cast<Node *>(tet4_nodes_on_plane[0]));
399 new_elem_tet4->set_node(2, const_cast<Node *>(tet4_nodes_on_plane[1]));
400 new_elem_tet4->set_node(3, const_cast<Node *>(tet4_nodes_inside_plane[0]));
401 new_elem_tet4->subdomain_id() =
mesh.elem_ptr(elem_id)->subdomain_id();
402 elems_tet4.push_back(
mesh.add_elem(std::move(new_elem_tet4)));
404 else if (tet4_nodes_inside_plane.size() == 1 && tet4_nodes_outside_plane.size() == 2)
406 std::vector<const Node *> new_plane_nodes;
408 for (
const auto & tet4_node_outside_plane : tet4_nodes_outside_plane)
415 auto new_elem_tet4 = std::make_unique<Tet4>();
416 new_elem_tet4->set_node(0, const_cast<Node *>(new_plane_nodes[0]));
417 new_elem_tet4->set_node(1, const_cast<Node *>(new_plane_nodes[1]));
418 new_elem_tet4->set_node(2, const_cast<Node *>(tet4_nodes_on_plane[0]));
419 new_elem_tet4->set_node(3, const_cast<Node *>(tet4_nodes_inside_plane[0]));
420 new_elem_tet4->subdomain_id() =
mesh.elem_ptr(elem_id)->subdomain_id();
421 elems_tet4.push_back(
mesh.add_elem(std::move(new_elem_tet4)));
423 else if (tet4_nodes_inside_plane.size() == 2 && tet4_nodes_outside_plane.size() == 1)
425 std::vector<const Node *> new_plane_nodes;
427 for (
const auto & tet4_node_inside_plane : tet4_nodes_inside_plane)
434 std::vector<const Node *> new_elems_nodes = {tet4_nodes_inside_plane[0],
435 tet4_nodes_inside_plane[1],
438 tet4_nodes_on_plane[0]};
439 std::vector<std::vector<unsigned int>> rotated_tet_face_indices;
440 std::vector<std::vector<const Node *>> optimized_node_list;
442 new_elems_nodes, rotated_tet_face_indices, optimized_node_list);
444 for (
unsigned int i = 0; i < optimized_node_list.size(); i++)
446 auto new_elem_tet4 = std::make_unique<Tet4>();
447 new_elem_tet4->set_node(0, const_cast<Node *>(optimized_node_list[i][0]));
448 new_elem_tet4->set_node(1, const_cast<Node *>(optimized_node_list[i][1]));
449 new_elem_tet4->set_node(2, const_cast<Node *>(optimized_node_list[i][2]));
450 new_elem_tet4->set_node(3, const_cast<Node *>(optimized_node_list[i][3]));
451 new_elem_tet4->subdomain_id() =
mesh.elem_ptr(elem_id)->subdomain_id();
452 elems_tet4.push_back(
mesh.add_elem(std::move(new_elem_tet4)));
458 mesh.elem_ptr(elem_id)->subdomain_id() = block_id_to_remove;
461 for (
auto & elem_tet4 : elems_tet4)
463 if (new_elements_created)
465 if (elem_tet4->volume() < 0.0)
467 Node * temp = elem_tet4->node_ptr(0);
468 elem_tet4->set_node(0, elem_tet4->node_ptr(1));
469 elem_tet4->set_node(1, temp);
473 for (
unsigned int i = 0; i < 4; i++)
475 const Point & side_pt_0 = *elem_tet4->side_ptr(i)->node_ptr(0);
476 const Point & side_pt_1 = *elem_tet4->side_ptr(i)->node_ptr(1);
477 const Point & side_pt_2 = *elem_tet4->side_ptr(i)->node_ptr(2);
479 const Point side_normal = (side_pt_1 - side_pt_0).cross(side_pt_2 - side_pt_1).unit();
480 for (
unsigned int j = 0; j < 4; j++)
482 if (new_elements_created)
486 for (
const auto & side_info : elem_side_list[j])
488 boundary_info.add_side(elem_tet4, i, side_info);
std::unique_ptr< MeshBase > & _input
Reference to input mesh pointer.
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the mesh.
SymFunctionPtr _func_level_set
function parser object describing the level set
void elementBoundaryInfoCollector(const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const unsigned short n_elem_sides, std::vector< std::vector< boundary_id_type >> &elem_side_list)
Collect the boundary information of the given element in a mesh.
PointLevelSetRelationIndex pointLevelSetRelation(const Point &point)
Evaluate whether a point is on the level set, inside or outside the level set.
const BoundaryName _cut_face_name
The boundary name of the surface generated by the cut.
Real levelSetEvaluator(const Point &point)
Evaluate the level set function at a given point.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
PointLevelSetRelationIndex
An enum class for style of input polygon size.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
Point pointPairLevelSetInterception(const Point &point1, const Point &point2)
Calculate the intersection point of a level set and a line segment defined by two points separated by...
bool absoluteFuzzyLessThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is less than another variable within an absolute tolerance...
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
static InputParameters validParams()
void convert3DMeshToAllTet4(ReplicatedMesh &mesh, const std::vector< std::pair< dof_id_type, bool >> &elems_to_process, std::vector< dof_id_type > &converted_elems_ids_to_track, const subdomain_id_type block_id_to_remove, const bool delete_block_to_remove)
Convert all the elements in a 3D mesh, consisting of only linear elements, into TET4 elements...
const Node * nonDuplicateNodeCreator(ReplicatedMesh &mesh, std::vector< const Node *> &new_on_plane_nodes, const Point &new_point) const
Check if a position on a plane has already been used as a node in the mesh.
CutMeshByLevelSetGeneratorBase(const InputParameters ¶meters)
boundary_id_type _cut_face_id
The boundary id of the surface generated by the cut.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void pyramidNodesToTetNodesDeterminer(std::vector< const Node *> &pyramid_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
For a rotated nodes that can form a PYRAMID5 element, create a series of four-node set that can form ...
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
void tet4ElemCutter(ReplicatedMesh &mesh, const std::vector< libMesh::BoundaryInfo::BCTuple > &bdry_side_list, const dof_id_type elem_id, const subdomain_id_type &block_id_to_remove, std::vector< const Node *> &new_on_plane_nodes)
For a TET4 elements crossed by the level set, keep the part of the element on the retaining side of t...
static InputParameters validParams()
static InputParameters validParams()
void prismNodesToTetNodesDeterminer(std::vector< const Node *> &prism_nodes, std::vector< std::vector< unsigned int >> &rotated_tet_face_indices, std::vector< std::vector< const Node *>> &tet_nodes_list)
For a rotated nodes that can form a PRISM6 element, create a series of four-node set that can form TE...
BoundaryID getNextFreeBoundaryID(MeshBase &input_mesh)
Checks input mesh and returns the largest boundary ID in the mesh plus one, which is a boundary ID in...
MeshGenerators are objects that can modify or add to an existing mesh.
bool absoluteFuzzyGreaterThan(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether a variable is greater than another variable within an absolute tolerance...