https://mooseframework.inl.gov
CutMeshByLevelSetGeneratorBase.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
12 #include "MooseMeshUtils.h"
13 
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"
20 
21 // C++ includes
22 #include <cmath>
23 
26 {
29 
30  params.addRequiredParam<MeshGeneratorName>("input", "The input mesh that needs to be trimmed.");
31 
32  params.addParam<boundary_id_type>("cut_face_id",
33  "The boundary id of the face generated by the cut. An "
34  "id will be automatically assigned if not provided.");
35  params.addParam<BoundaryName>(
36  "cut_face_name", BoundaryName(), "The boundary name of the face generated by the cut.");
37 
38  params.addClassDescription(
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.");
42 
43  return params;
44 }
45 
47  : MeshGenerator(parameters),
48  FunctionParserUtils<false>(parameters),
49  _input_name(getParam<MeshGeneratorName>("input")),
50  _cut_face_name(getParam<BoundaryName>("cut_face_name")),
51  _input(getMeshByName(_input_name))
52 {
53  _cut_face_id = isParamValid("cut_face_id") ? getParam<boundary_id_type>("cut_face_id") : -1;
54 }
55 
56 std::unique_ptr<MeshBase>
58 {
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)
64  paramError(
65  "input",
66  "Only 3D meshes are supported. Use XYMeshLineCutter for 2D meshes if applicable. Mixed "
67  "dimensional meshes are not supported at the moment.");
68 
69  ReplicatedMesh & mesh = *replicated_mesh_ptr;
70 
71  if (!_cut_face_name.empty())
72  {
74  {
75  const boundary_id_type exist_cut_face_id =
77  if (_cut_face_id != -1 && _cut_face_id != exist_cut_face_id)
78  paramError("cut_face_id",
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.");
81  else
82  _cut_face_id = exist_cut_face_id;
83  }
84  else
85  {
86  if (_cut_face_id == -1)
88  mesh.get_boundary_info().sideset_name(_cut_face_id) = _cut_face_name;
89  }
90  }
91  else if (_cut_face_id == -1)
92  {
94  }
95 
96  // Subdomain ID for new utility blocks must be new
97  std::set<subdomain_id_type> subdomain_ids_set;
98  mesh.subdomain_ids(subdomain_ids_set);
99  const subdomain_id_type max_subdomain_id = *subdomain_ids_set.rbegin();
100  const subdomain_id_type block_id_to_remove = max_subdomain_id + 1;
101 
102  // For the boolean value in the pair, true means the element is crossed by the cutting plane
103  // false means the element is on the remaining side
104  std::vector<std::pair<dof_id_type, bool>> cross_and_remained_elems_pre_convert;
105 
106  for (auto elem_it = mesh.active_elements_begin(); elem_it != mesh.active_elements_end();
107  elem_it++)
108  {
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++)
112  {
113  // We define elem_vertices_counter in this way so that those elements with one face on the
114  // plane are also processed to have the cut face boundary assigned.
115  if (pointLevelSetRelation((*(*elem_it)->node_ptr(i))) !=
117  elem_vertices_counter++;
118  }
119  if (elem_vertices_counter == n_vertices)
120  (*elem_it)->subdomain_id() = block_id_to_remove;
121  else
122  {
123  // Check if any elements to be processed are not first order
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));
128  }
129  }
130 
131  std::vector<dof_id_type> converted_elems_ids_to_cut;
132  // Then convert these non-TET4 elements into TET4 elements
134  cross_and_remained_elems_pre_convert,
135  converted_elems_ids_to_cut,
136  block_id_to_remove,
137  false);
138 
139  std::vector<const Node *> new_on_plane_nodes;
140  // We build the sideset information now, as we only need the information of the elements before
141  // cutting
142  BoundaryInfo & boundary_info = mesh.get_boundary_info();
143  const auto bdry_side_list = boundary_info.build_side_list();
144  // Cut the TET4 Elements
145  for (const auto & converted_elems_id_to_cut : converted_elems_ids_to_cut)
146  {
148  mesh, bdry_side_list, converted_elems_id_to_cut, block_id_to_remove, new_on_plane_nodes);
149  }
150 
151  // Delete the block to remove
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);
154  elem_it++)
155  mesh.delete_elem(*elem_it);
156 
157  mesh.contract();
158  mesh.set_isnt_prepared();
159  return std::move(_input);
160 }
161 
164 {
165  const Real level_set_value = levelSetEvaluator(point);
166  if (MooseUtils::absoluteFuzzyLessThan(level_set_value, 0.0))
168  else if (MooseUtils::absoluteFuzzyGreaterThan(level_set_value, 0.0))
170  else
172 }
173 
174 Point
176  const Point & point2)
177 {
178  Real dist1 = levelSetEvaluator(point1);
179  Real dist2 = levelSetEvaluator(point2);
180 
181  if (MooseUtils::absoluteFuzzyEqual(dist1, 0.0) || MooseUtils::absoluteFuzzyEqual(dist2, 0.0))
182  mooseError("At least one of the two points are on the plane.");
183  if (MooseUtils::absoluteFuzzyGreaterThan(dist1 * dist2, 0.0))
184  mooseError("The two points are on the same side of the plane.");
185 
186  Point p1(point1);
187  Point p2(point2);
188  Real dist = abs(dist1) + abs(dist2);
189  Point mid_point;
190 
191  // Bisection method to find midpoint
192  while (MooseUtils::absoluteFuzzyGreaterThan(dist, 0.0))
193  {
194  mid_point = 0.5 * (p1 + p2);
195  const Real dist_mid = levelSetEvaluator(mid_point);
196  // We do not need Fuzzy here as it will be covered by the while loop
197  if (dist_mid == 0.0)
198  dist = 0.0;
199  else if (dist_mid * dist1 < 0.0)
200  {
201  p2 = mid_point;
202  dist2 = levelSetEvaluator(p2);
203  dist = abs(dist1) + abs(dist2);
204  }
205  else
206  {
207  p1 = mid_point;
208  dist1 = levelSetEvaluator(p1);
209  dist = abs(dist1) + abs(dist2);
210  }
211  }
212  return mid_point;
213 }
214 
215 const Node *
217  ReplicatedMesh & mesh,
218  std::vector<const Node *> & new_on_plane_nodes,
219  const Point & new_point) const
220 {
221  for (const auto & new_on_plane_node : new_on_plane_nodes)
222  {
223  if (MooseUtils::absoluteFuzzyEqual((*new_on_plane_node - new_point).norm(), 0.0))
224  return new_on_plane_node;
225  }
226  new_on_plane_nodes.push_back(mesh.add_point(new_point));
227  return new_on_plane_nodes.back();
228 }
229 
230 void
232  ReplicatedMesh & mesh,
233  const std::vector<libMesh::BoundaryInfo::BCTuple> & bdry_side_list,
234  const dof_id_type elem_id,
235  const subdomain_id_type & block_id_to_remove,
236  std::vector<const Node *> & new_on_plane_nodes)
237 {
238  // Retrieve boundary information for the mesh
239  BoundaryInfo & boundary_info = mesh.get_boundary_info();
240  // Create a list of sidesets involving the element to be split
241  // It might be complex to assign the boundary id to the new elements
242  // In TET4, none of the four faces have the same normal vector
243  // So we are using the normal vector to identify the faces that
244  // need to be assigned the same boundary id
245  std::vector<Point> elem_side_normal_list;
246  elem_side_normal_list.resize(4);
247  for (const auto i : make_range(4))
248  {
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))
252  .unit();
253  }
254 
255  std::vector<std::vector<boundary_id_type>> elem_side_list;
257  bdry_side_list, elem_id, 4, elem_side_list);
258 
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;
264  // Sort tetrahedral nodes based on their positioning wrt the plane
265  for (unsigned int i = 0; i < 4; i++)
266  {
267  tet4_nodes[i] = mesh.elem_ptr(elem_id)->node_ptr(i);
268  node_plane_relation[i] = pointLevelSetRelation(*tet4_nodes[i]);
269  if (node_plane_relation[i] == PointLevelSetRelationIndex::on_level_set)
270  tet4_nodes_on_plane.push_back(tet4_nodes[i]);
271  else if (node_plane_relation[i] == PointLevelSetRelationIndex::level_set_out_side)
272  tet4_nodes_outside_plane.push_back(tet4_nodes[i]);
273  else
274  tet4_nodes_inside_plane.push_back(tet4_nodes[i]);
275  }
276  std::vector<Elem *> elems_tet4;
277  bool new_elements_created(false);
278  // No cutting needed if no nodes are outside the plane
279  if (tet4_nodes_outside_plane.size() == 0)
280  {
281  if (tet4_nodes_on_plane.size() == 3)
282  {
283  // Record the element for future cross section boundary assignment
284  elems_tet4.push_back(mesh.elem_ptr(elem_id));
285  }
286  }
287  // Remove the element if all the nodes are outside the plane
288  else if (tet4_nodes_inside_plane.size() == 0)
289  {
290  mesh.elem_ptr(elem_id)->subdomain_id() = block_id_to_remove;
291  if (tet4_nodes_on_plane.size() == 3)
292  {
293  // I think the neighboring element will be handled,
294  // So we do not need to assign the cross section boundary here
295  }
296  }
297  // As we have nodes on both sides, six different scenarios are possible
298  else
299  {
300  new_elements_created = true;
301  if (tet4_nodes_inside_plane.size() == 1 && tet4_nodes_outside_plane.size() == 3)
302  {
303  std::vector<const Node *> new_plane_nodes;
304  // A smaller TET4 element is created, this solution is unique
305  for (const auto & tet4_node_outside_plane : tet4_nodes_outside_plane)
306  {
307  new_plane_nodes.push_back(nonDuplicateNodeCreator(
308  mesh,
309  new_on_plane_nodes,
310  pointPairLevelSetInterception(*tet4_node_outside_plane, *tet4_nodes_inside_plane[0])));
311  }
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)));
319  }
320  else if (tet4_nodes_inside_plane.size() == 2 && tet4_nodes_outside_plane.size() == 2)
321  {
322  std::vector<const Node *> new_plane_nodes;
323  // 3 smaller TET3 elements are created
324  for (const auto & tet4_node_outside_plane : tet4_nodes_outside_plane)
325  {
326  for (const auto & tet4_node_inside_plane : tet4_nodes_inside_plane)
327  {
328  new_plane_nodes.push_back(nonDuplicateNodeCreator(
329  mesh,
330  new_on_plane_nodes,
331  pointPairLevelSetInterception(*tet4_node_outside_plane, *tet4_node_inside_plane)));
332  }
333  }
334  std::vector<const Node *> new_elems_nodes = {tet4_nodes_inside_plane[1],
335  new_plane_nodes[3],
336  new_plane_nodes[1],
337  tet4_nodes_inside_plane[0],
338  new_plane_nodes[2],
339  new_plane_nodes[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);
344 
345  for (unsigned int i = 0; i < optimized_node_list.size(); i++)
346  {
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)));
354  }
355  }
356  else if (tet4_nodes_inside_plane.size() == 3 && tet4_nodes_outside_plane.size() == 1)
357  {
358  std::vector<const Node *> new_plane_nodes;
359  // 3 smaller Tet4 elements are created
360  for (const auto & tet4_node_inside_plane : tet4_nodes_inside_plane)
361  {
362  new_plane_nodes.push_back(nonDuplicateNodeCreator(
363  mesh,
364  new_on_plane_nodes,
365  pointPairLevelSetInterception(*tet4_node_inside_plane, *tet4_nodes_outside_plane[0])));
366  }
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],
370  new_plane_nodes[0],
371  new_plane_nodes[1],
372  new_plane_nodes[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);
377 
378  for (unsigned int i = 0; i < optimized_node_list.size(); i++)
379  {
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)));
387  }
388  }
389  else if (tet4_nodes_inside_plane.size() == 1 && tet4_nodes_outside_plane.size() == 1)
390  {
391  auto new_plane_node = nonDuplicateNodeCreator(
392  mesh,
393  new_on_plane_nodes,
394  pointPairLevelSetInterception(*tet4_nodes_inside_plane[0], *tet4_nodes_outside_plane[0]));
395  // A smaller Tet4 is created, this solution is unique
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)));
403  }
404  else if (tet4_nodes_inside_plane.size() == 1 && tet4_nodes_outside_plane.size() == 2)
405  {
406  std::vector<const Node *> new_plane_nodes;
407  // A smaller Tet4 element is created, this solution is unique
408  for (const auto & tet4_node_outside_plane : tet4_nodes_outside_plane)
409  {
410  new_plane_nodes.push_back(nonDuplicateNodeCreator(
411  mesh,
412  new_on_plane_nodes,
413  pointPairLevelSetInterception(*tet4_node_outside_plane, *tet4_nodes_inside_plane[0])));
414  }
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)));
422  }
423  else if (tet4_nodes_inside_plane.size() == 2 && tet4_nodes_outside_plane.size() == 1)
424  {
425  std::vector<const Node *> new_plane_nodes;
426  // 2 smaller TET4 elements are created
427  for (const auto & tet4_node_inside_plane : tet4_nodes_inside_plane)
428  {
429  new_plane_nodes.push_back(nonDuplicateNodeCreator(
430  mesh,
431  new_on_plane_nodes,
432  pointPairLevelSetInterception(*tet4_node_inside_plane, *tet4_nodes_outside_plane[0])));
433  }
434  std::vector<const Node *> new_elems_nodes = {tet4_nodes_inside_plane[0],
435  tet4_nodes_inside_plane[1],
436  new_plane_nodes[1],
437  new_plane_nodes[0],
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);
443 
444  for (unsigned int i = 0; i < optimized_node_list.size(); i++)
445  {
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)));
453  }
454  }
455  else
456  mooseError("Unexpected scenario.");
457 
458  mesh.elem_ptr(elem_id)->subdomain_id() = block_id_to_remove;
459  }
460 
461  for (auto & elem_tet4 : elems_tet4)
462  {
463  if (new_elements_created)
464  {
465  if (elem_tet4->volume() < 0.0)
466  {
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);
470  }
471  }
472  // Find the boundary id of the new element
473  for (unsigned int i = 0; i < 4; i++)
474  {
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);
478 
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++)
481  {
482  if (new_elements_created)
483  {
484  if (MooseUtils::absoluteFuzzyEqual(side_normal * elem_side_normal_list[j], 1.0))
485  {
486  for (const auto & side_info : elem_side_list[j])
487  {
488  boundary_info.add_side(elem_tet4, i, side_info);
489  }
490  }
491  }
492  }
493  if (MooseUtils::absoluteFuzzyEqual(levelSetEvaluator(side_pt_0), 0.0) &&
496  {
497 
498  boundary_info.add_side(elem_tet4, i, _cut_face_id);
499  }
500  }
501  }
502 }
503 
504 Real
506 {
507  _func_params[0] = point(0);
508  _func_params[1] = point(1);
509  _func_params[2] = point(2);
510  return evaluate(_func_level_set);
511 }
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)
Definition: EigenADReal.h:42
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.
Definition: MooseUtils.h:380
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
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
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.
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
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.
int8_t boundary_id_type
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...
Definition: MooseUtils.h:475
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
auto norm(const T &a) -> decltype(std::abs(a))
static InputParameters validParams()
Definition: MeshGenerator.C:23
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 &parameters)
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 addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
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()
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
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.
Definition: MeshGenerator.h:32
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...
Definition: MooseUtils.h:428
uint8_t dof_id_type