https://mooseframework.inl.gov
XYDelaunayGenerator.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 
10 #include "XYDelaunayGenerator.h"
11 
12 #include "CastUniquePointer.h"
13 #include "MooseMeshUtils.h"
14 #include "MooseUtils.h"
15 
16 #include "libmesh/elem.h"
17 #include "libmesh/enum_to_string.h"
18 #include "libmesh/int_range.h"
19 #include "libmesh/mesh_modification.h"
20 #include "libmesh/mesh_serializer.h"
21 #include "libmesh/mesh_triangle_holes.h"
22 #include "libmesh/parsed_function.h"
23 #include "libmesh/poly2tri_triangulator.h"
24 #include "libmesh/unstructured_mesh.h"
25 #include "DelimitedFileReader.h"
26 
28 
31 {
33 
34  MooseEnum algorithm("BINARY EXHAUSTIVE", "BINARY");
35  MooseEnum tri_elem_type("TRI3 TRI6 TRI7 DEFAULT", "DEFAULT");
36 
37  params.addRequiredParam<MeshGeneratorName>(
38  "boundary",
39  "The input MeshGenerator defining the output outer boundary and required Steiner points.");
40  params.addParam<std::vector<BoundaryName>>(
41  "input_boundary_names", "2D-input-mesh boundaries defining the output mesh outer boundary");
42  params.addParam<std::vector<SubdomainName>>(
43  "input_subdomain_names", "1D-input-mesh subdomains defining the output mesh outer boundary");
44  params.addParam<unsigned int>("add_nodes_per_boundary_segment",
45  0,
46  "How many more nodes to add in each outer boundary segment.");
47  params.addParam<bool>(
48  "refine_boundary", true, "Whether to allow automatically refining the outer boundary.");
49 
50  params.addParam<SubdomainName>("output_subdomain_name",
51  "Subdomain name to set on new triangles.");
52  params.addParam<SubdomainID>("output_subdomain_id", "Subdomain id to set on new triangles.");
53 
54  params.addParam<BoundaryName>(
55  "output_boundary",
56  "Boundary name to set on new outer boundary. Default ID: 0 if no hole meshes are stitched; "
57  "or maximum boundary ID of all the stitched hole meshes + 1.");
58  params.addParam<std::vector<BoundaryName>>(
59  "hole_boundaries",
60  "Boundary names to set on holes. Default IDs are numbered up from 1 if no hole meshes are "
61  "stitched; or from maximum boundary ID of all the stitched hole meshes + 2.");
62 
63  params.addParam<bool>(
64  "verify_holes",
65  true,
66  "Verify holes do not intersect boundary or each other. Asymptotically costly.");
67 
68  params.addParam<bool>("smooth_triangulation",
69  false,
70  "Whether to do Laplacian mesh smoothing on the generated triangles.");
71  params.addParam<std::vector<MeshGeneratorName>>(
72  "holes", std::vector<MeshGeneratorName>(), "The MeshGenerators that define mesh holes.");
73  params.addParam<std::vector<bool>>(
74  "stitch_holes", std::vector<bool>(), "Whether to stitch to the mesh defining each hole.");
75  params.addParam<std::vector<bool>>("refine_holes",
76  std::vector<bool>(),
77  "Whether to allow automatically refining each hole boundary.");
78  params.addRangeCheckedParam<Real>(
79  "desired_area",
80  0,
81  "desired_area>=0",
82  "Desired (maximum) triangle area, or 0 to skip uniform refinement");
83  params.addParam<std::string>(
84  "desired_area_func",
85  std::string(),
86  "Desired area as a function of x,y; omit to skip non-uniform refinement");
87 
88  params.addParam<bool>("use_auto_area_func",
89  false,
90  "Use the automatic area function for the triangle meshing region.");
91  params.addParam<Real>(
92  "auto_area_func_default_size",
93  0,
94  "Background size for automatic area function, or 0 to use non background size");
95  params.addParam<Real>("auto_area_func_default_size_dist",
96  -1.0,
97  "Effective distance of background size for automatic area "
98  "function, or negative to use non background size");
99  params.addParam<unsigned int>("auto_area_function_num_points",
100  10,
101  "Maximum number of nearest points used for the inverse distance "
102  "interpolation algorithm for automatic area function calculation.");
103  params.addRangeCheckedParam<Real>(
104  "auto_area_function_power",
105  1.0,
106  "auto_area_function_power>0",
107  "Polynomial power of the inverse distance interpolation algorithm for automatic area "
108  "function calculation.");
109 
110  params.addParam<MooseEnum>(
111  "algorithm",
112  algorithm,
113  "Control the use of binary search for the nodes of the stitched surfaces.");
114  params.addParam<MooseEnum>(
115  "tri_element_type", tri_elem_type, "Type of the triangular elements to be generated.");
116  params.addParam<bool>(
117  "verbose_stitching", false, "Whether mesh stitching should have verbose output.");
118  params.addParam<std::vector<Point>>("interior_points",
119  {},
120  "Interior node locations, if no smoothing is used. Any point "
121  "outside the surface will not be meshed.");
122  params.addParam<std::vector<FileName>>(
123  "interior_point_files", {}, "Text file(s) with the interior points, one per line");
124  params.addClassDescription("Triangulates meshes within boundaries defined by input meshes.");
125 
126  params.addParamNamesToGroup(
127  "use_auto_area_func auto_area_func_default_size auto_area_func_default_size_dist",
128  "Automatic triangle meshing area control");
129  params.addParamNamesToGroup("interior_points interior_point_files",
130  "Mandatory mesh interior nodes");
131 
132  return params;
133 }
134 
136  : MeshGenerator(parameters),
137  _bdy_ptr(getMesh("boundary")),
138  _add_nodes_per_boundary_segment(getParam<unsigned int>("add_nodes_per_boundary_segment")),
139  _refine_bdy(getParam<bool>("refine_boundary")),
140  _output_subdomain_id(0),
141  _smooth_tri(getParam<bool>("smooth_triangulation")),
142  _verify_holes(getParam<bool>("verify_holes")),
143  _hole_ptrs(getMeshes("holes")),
144  _stitch_holes(getParam<std::vector<bool>>("stitch_holes")),
145  _refine_holes(getParam<std::vector<bool>>("refine_holes")),
146  _desired_area(getParam<Real>("desired_area")),
147  _desired_area_func(getParam<std::string>("desired_area_func")),
148  _use_auto_area_func(getParam<bool>("use_auto_area_func")),
149  _auto_area_func_default_size(getParam<Real>("auto_area_func_default_size")),
150  _auto_area_func_default_size_dist(getParam<Real>("auto_area_func_default_size_dist")),
151  _auto_area_function_num_points(getParam<unsigned int>("auto_area_function_num_points")),
152  _auto_area_function_power(getParam<Real>("auto_area_function_power")),
153  _algorithm(parameters.get<MooseEnum>("algorithm")),
154  _tri_elem_type(parameters.get<MooseEnum>("tri_element_type")),
155  _verbose_stitching(parameters.get<bool>("verbose_stitching")),
156  _interior_points(getParam<std::vector<Point>>("interior_points"))
157 {
158  if ((_desired_area > 0.0 && !_desired_area_func.empty()) ||
159  (_desired_area > 0.0 && _use_auto_area_func) ||
161  paramError("desired_area_func",
162  "Only one of the three methods ('desired_area', 'desired_area_func', and "
163  "'_use_auto_area_func') to set element area limit should be used.");
164 
165  if (!_use_auto_area_func)
166  if (isParamSetByUser("auto_area_func_default_size") ||
167  isParamSetByUser("auto_area_func_default_size_dist") ||
168  isParamSetByUser("auto_area_function_num_points") ||
169  isParamSetByUser("auto_area_function_power"))
170  paramError("use_auto_area_func",
171  "If this parameter is set to false, the following parameters should not be set: "
172  "'auto_area_func_default_size', 'auto_area_func_default_size_dist', "
173  "'auto_area_function_num_points', 'auto_area_function_power'.");
174 
175  if (!_stitch_holes.empty() && _stitch_holes.size() != _hole_ptrs.size())
176  paramError("stitch_holes", "Need one stitch_holes entry per hole, if specified.");
177 
178  for (auto hole_i : index_range(_stitch_holes))
179  if (_stitch_holes[hole_i] && (hole_i >= _refine_holes.size() || _refine_holes[hole_i]))
180  paramError("refine_holes", "Disable auto refine of any hole boundary to be stitched.");
181 
182  if (isParamValid("hole_boundaries"))
183  {
184  auto & hole_boundaries = getParam<std::vector<BoundaryName>>("hole_boundaries");
185  if (hole_boundaries.size() != _hole_ptrs.size())
186  paramError("hole_boundaries", "Need one hole_boundaries entry per hole, if specified.");
187  }
188  // Copied from MultiApp.C
189  const auto & positions_files = getParam<std::vector<FileName>>("interior_point_files");
190  for (const auto p_file_it : index_range(positions_files))
191  {
192  const std::string positions_file = positions_files[p_file_it];
193  MooseUtils::DelimitedFileReader file(positions_file, &_communicator);
195  file.read();
196 
197  const std::vector<Point> & data = file.getDataAsPoints();
198  for (const auto & d : data)
199  _interior_points.push_back(d);
200  }
201  bool has_duplicates =
202  std::any_of(_interior_points.begin(),
203  _interior_points.end(),
204  [&](const Point & p)
205  { return std::count(_interior_points.begin(), _interior_points.end(), p) > 1; });
206  if (has_duplicates)
207  paramError("interior_points", "Duplicate points were found in the provided interior points.");
208 }
209 
210 std::unique_ptr<MeshBase>
212 {
213  // Put the boundary mesh in a local pointer
214  std::unique_ptr<UnstructuredMesh> mesh =
215  dynamic_pointer_cast<UnstructuredMesh>(std::move(_bdy_ptr));
216 
217  // Get ready to triangulate the line segments we extract from it
219  poly2tri.triangulation_type() = libMesh::TriangulatorInterface::PSLG;
220 
221  // If we're using a user-requested subset of boundaries on that
222  // mesh, get their ids.
223  std::set<std::size_t> bdy_ids;
224 
225  if (isParamValid("input_boundary_names"))
226  {
227  if (isParamValid("input_subdomain_names"))
228  paramError(
229  "input_subdomain_names",
230  "input_boundary_names and input_subdomain_names cannot both specify an outer boundary.");
231 
232  const auto & boundary_names = getParam<std::vector<BoundaryName>>("input_boundary_names");
233  for (const auto & name : boundary_names)
234  {
235  auto bcid = MooseMeshUtils::getBoundaryID(name, *mesh);
236  if (bcid == BoundaryInfo::invalid_id)
237  paramError("input_boundary_names", name, " is not a boundary name in the input mesh");
238 
239  bdy_ids.insert(bcid);
240  }
241  }
242 
243  if (isParamValid("input_subdomain_names"))
244  {
245  const auto & subdomain_names = getParam<std::vector<SubdomainName>>("input_subdomain_names");
246 
247  const auto subdomain_ids = MooseMeshUtils::getSubdomainIDs(*mesh, subdomain_names);
248 
249  // Check that the requested subdomains exist in the mesh
250  std::set<SubdomainID> subdomains;
251  mesh->subdomain_ids(subdomains);
252 
253  for (auto i : index_range(subdomain_ids))
254  {
255  if (subdomain_ids[i] == Moose::INVALID_BLOCK_ID || !subdomains.count(subdomain_ids[i]))
256  paramError(
257  "input_subdomain_names", subdomain_names[i], " was not found in the boundary mesh");
258 
259  bdy_ids.insert(subdomain_ids[i]);
260  }
261  }
262 
263  if (!bdy_ids.empty())
264  poly2tri.set_outer_boundary_ids(bdy_ids);
265 
266  poly2tri.set_interpolate_boundary_points(_add_nodes_per_boundary_segment);
267  poly2tri.set_refine_boundary_allowed(_refine_bdy);
268  poly2tri.set_verify_hole_boundaries(_verify_holes);
269 
270  poly2tri.desired_area() = _desired_area;
271  poly2tri.minimum_angle() = 0; // Not yet supported
272  poly2tri.smooth_after_generating() = _smooth_tri;
273 
274  std::vector<libMesh::TriangulatorInterface::MeshedHole> meshed_holes;
275  std::vector<libMesh::TriangulatorInterface::Hole *> triangulator_hole_ptrs(_hole_ptrs.size());
276  std::vector<std::unique_ptr<MeshBase>> hole_ptrs(_hole_ptrs.size());
277  // This tells us the element orders of the hole meshes
278  // For the boundary meshes, it can be access through poly2tri.segment_midpoints.
279  std::vector<bool> holes_with_midpoints(_hole_ptrs.size());
280  bool stitch_second_order_holes(false);
281 
282  // Make sure pointers here aren't invalidated by a resize
283  meshed_holes.reserve(_hole_ptrs.size());
284  for (auto hole_i : index_range(_hole_ptrs))
285  {
286  hole_ptrs[hole_i] = std::move(*_hole_ptrs[hole_i]);
287  if (!hole_ptrs[hole_i]->is_prepared())
288  hole_ptrs[hole_i]->prepare_for_use();
289  meshed_holes.emplace_back(*hole_ptrs[hole_i]);
290  holes_with_midpoints[hole_i] = meshed_holes.back().n_midpoints();
291  stitch_second_order_holes = _stitch_holes.empty()
292  ? false
293  : ((holes_with_midpoints[hole_i] && _stitch_holes[hole_i]) ||
294  stitch_second_order_holes);
295  if (hole_i < _refine_holes.size())
296  meshed_holes.back().set_refine_boundary_allowed(_refine_holes[hole_i]);
297 
298  triangulator_hole_ptrs[hole_i] = &meshed_holes.back();
299  }
300  if (stitch_second_order_holes && (_tri_elem_type == "TRI3" || _tri_elem_type == "DEFAULT"))
301  paramError(
302  "tri_element_type",
303  "Cannot use first order elements with stitched quadratic element holes. Please try "
304  "to specify a higher-order tri_element_type or reduce the order of the hole inputs.");
305 
306  if (!triangulator_hole_ptrs.empty())
307  poly2tri.attach_hole_list(&triangulator_hole_ptrs);
308 
309  if (_desired_area_func != "")
310  {
311  // poly2tri will clone this so it's fine going out of scope
313  poly2tri.set_desired_area_function(&area_func);
314  }
315  else if (_use_auto_area_func)
316  {
317  poly2tri.set_auto_area_function(
318  this->comm(),
323  }
324 
325  if (_tri_elem_type == "TRI6")
326  poly2tri.elem_type() = libMesh::ElemType::TRI6;
327  else if (_tri_elem_type == "TRI7")
328  poly2tri.elem_type() = libMesh::ElemType::TRI7;
329  // Add interior points before triangulating. Only points inside the boundaries
330  // will be meshed.
331  for (auto & point : _interior_points)
332  mesh->add_point(point);
333 
334  poly2tri.triangulate();
335 
336  if (isParamValid("output_subdomain_id"))
337  _output_subdomain_id = getParam<SubdomainID>("output_subdomain_id");
338 
339  if (isParamValid("output_subdomain_name"))
340  {
341  auto output_subdomain_name = getParam<SubdomainName>("output_subdomain_name");
342  auto id = MooseMeshUtils::getSubdomainID(output_subdomain_name, *mesh);
343 
344  if (id == Elem::invalid_subdomain_id)
345  {
346  if (!isParamValid("output_subdomain_id"))
347  {
348  // We'll probably need to make a new ID, then
350 
351  // But check the hole meshes for our output subdomain name too
352  for (auto & hole_ptr : hole_ptrs)
353  {
354  auto possible_sbdid = MooseMeshUtils::getSubdomainID(output_subdomain_name, *hole_ptr);
355  // Huh, it was in one of them
356  if (possible_sbdid != Elem::invalid_subdomain_id)
357  {
358  _output_subdomain_id = possible_sbdid;
359  break;
360  }
363  }
364  }
365  }
366  else
367  {
368  if (isParamValid("output_subdomain_id"))
369  {
370  if (id != _output_subdomain_id)
371  paramError("output_subdomain_name",
372  "name has been used by the input meshes and the corresponding id is not equal "
373  "to 'output_subdomain_id'");
374  }
375  else
377  }
378  // We do not want to set an empty subdomain name
379  if (output_subdomain_name.size())
380  mesh->subdomain_name(_output_subdomain_id) = output_subdomain_name;
381  }
382 
384  for (auto elem : mesh->element_ptr_range())
385  {
386  mooseAssert(elem->type() ==
387  (_tri_elem_type == "TRI6" ? TRI6 : (_tri_elem_type == "TRI7" ? TRI7 : TRI3)),
388  "Unexpected element type " << libMesh::Utility::enum_to_string(elem->type())
389  << " found in triangulation");
390 
391  elem->subdomain_id() = _output_subdomain_id;
392 
393  // I do not trust Laplacian mesh smoothing not to invert
394  // elements near reentrant corners. Eventually we'll add better
395  // smoothing options, but even those might have failure cases.
396  // Better to always do extra tests here than to ever let users
397  // try to run on a degenerate mesh.
398  if (_smooth_tri)
399  {
400  auto cross_prod = (elem->point(1) - elem->point(0)).cross(elem->point(2) - elem->point(0));
401 
402  if (cross_prod(2) <= 0)
403  mooseError("Inverted element found in triangulation.\n"
404  "Laplacian smoothing can create these at reentrant corners; disable it?");
405  }
406  }
407 
408  const bool use_binary_search = (_algorithm == "BINARY");
409 
410  // The hole meshes are specified by the user, so they could have any
411  // BCID or no BCID or any combination of BCIDs on their outer
412  // boundary, so we'll have to set our own BCID to use for stitching
413  // there. We'll need to check all the holes for used BCIDs, if we
414  // want to pick a new ID on hole N that doesn't conflict with any
415  // IDs on hole M < N (or with the IDs on the new triangulation)
416 
417  // The new triangulation by default assigns BCID i+1 to hole i ...
418  // but we can't even use this for mesh stitching, because we can't
419  // be sure it isn't also already in use on the hole's mesh and so we
420  // won't be able to safely clear it afterwards.
421  const boundary_id_type end_bcid = hole_ptrs.size() + 1;
422 
423  // For the hole meshes that need to be stitched, we would like to make sure the hole boundary ids
424  // and output boundary id are not conflicting with the existing boundary ids of the hole meshes to
425  // be stitched.
426  BoundaryID free_boundary_id = 0;
427  if (_stitch_holes.size())
428  {
429  for (auto hole_i : index_range(hole_ptrs))
430  {
431  if (_stitch_holes[hole_i])
432  {
433  free_boundary_id =
434  std::max(free_boundary_id, MooseMeshUtils::getNextFreeBoundaryID(*hole_ptrs[hole_i]));
435  hole_ptrs[hole_i]->comm().max(free_boundary_id);
436  }
437  }
438  for (auto h : index_range(hole_ptrs))
439  libMesh::MeshTools::Modification::change_boundary_id(*mesh, h + 1, h + 1 + free_boundary_id);
440  }
441  boundary_id_type new_hole_bcid = end_bcid + free_boundary_id;
442 
443  // We might be overriding the default bcid numbers. We have to be
444  // careful about how we renumber, though. We pick unused temporary
445  // numbers because e.g. "0->2, 2->0" is impossible to do
446  // sequentially, but "0->N, 2->N+2, N->2, N+2->0" works.
448  *mesh, 0, (isParamValid("output_boundary") ? end_bcid : 0) + free_boundary_id);
449 
450  if (isParamValid("hole_boundaries"))
451  {
452  auto hole_boundaries = getParam<std::vector<BoundaryName>>("hole_boundaries");
453  auto hole_boundary_ids = MooseMeshUtils::getBoundaryIDs(*mesh, hole_boundaries, true);
454 
455  for (auto h : index_range(hole_ptrs))
457  *mesh, h + 1 + free_boundary_id, h + 1 + free_boundary_id + end_bcid);
458 
459  for (auto h : index_range(hole_ptrs))
460  {
462  *mesh, h + 1 + free_boundary_id + end_bcid, hole_boundary_ids[h]);
463  mesh->get_boundary_info().sideset_name(hole_boundary_ids[h]) = hole_boundaries[h];
464  new_hole_bcid = std::max(new_hole_bcid, boundary_id_type(hole_boundary_ids[h] + 1));
465  }
466  }
467 
468  if (isParamValid("output_boundary"))
469  {
470  const BoundaryName output_boundary = getParam<BoundaryName>("output_boundary");
471  const std::vector<BoundaryID> output_boundary_id =
472  MooseMeshUtils::getBoundaryIDs(*mesh, {output_boundary}, true);
473 
475  *mesh, end_bcid + free_boundary_id, output_boundary_id[0]);
476  mesh->get_boundary_info().sideset_name(output_boundary_id[0]) = output_boundary;
477 
478  new_hole_bcid = std::max(new_hole_bcid, boundary_id_type(output_boundary_id[0] + 1));
479  }
480 
481  bool doing_stitching = false;
482 
483  for (auto hole_i : index_range(hole_ptrs))
484  {
485  const MeshBase & hole_mesh = *hole_ptrs[hole_i];
486  auto & hole_boundary_info = hole_mesh.get_boundary_info();
487  const std::set<boundary_id_type> & local_hole_bcids = hole_boundary_info.get_boundary_ids();
488 
489  if (!local_hole_bcids.empty())
490  new_hole_bcid = std::max(new_hole_bcid, boundary_id_type(*local_hole_bcids.rbegin() + 1));
491  hole_mesh.comm().max(new_hole_bcid);
492 
493  if (hole_i < _stitch_holes.size() && _stitch_holes[hole_i])
494  doing_stitching = true;
495  }
496 
497  const boundary_id_type inner_bcid = new_hole_bcid + 1;
498 
499  // libMesh mesh stitching still requires a serialized mesh, and it's
500  // cheaper to do that once than to do it once-per-hole
501  libMesh::MeshSerializer serial(*mesh, doing_stitching);
502 
503  // Define a reference map variable for subdomain map
504  auto & main_subdomain_map = mesh->set_subdomain_name_map();
505  for (auto hole_i : index_range(hole_ptrs))
506  {
507  if (hole_i < _stitch_holes.size() && _stitch_holes[hole_i])
508  {
509  UnstructuredMesh & hole_mesh = dynamic_cast<UnstructuredMesh &>(*hole_ptrs[hole_i]);
510  // increase hole mesh order if the triangulation mesh has higher order
511  if (!holes_with_midpoints[hole_i])
512  {
513  if (_tri_elem_type == "TRI6")
514  hole_mesh.all_second_order();
515  else if (_tri_elem_type == "TRI7")
516  hole_mesh.all_complete_order();
517  }
518  auto & hole_boundary_info = hole_mesh.get_boundary_info();
519 
520  // Our algorithm here requires a serialized Mesh. To avoid
521  // redundant serialization and deserialization (libMesh
522  // MeshedHole and stitch_meshes still also require
523  // serialization) we'll do the serialization up front.
524  libMesh::MeshSerializer serial_hole(hole_mesh);
525 
526  // It would have been nicer for MeshedHole to add the BCID
527  // itself, but we want MeshedHole to work with a const mesh.
528  // We'll still use MeshedHole, for its code distinguishing
529  // outer boundaries from inner boundaries on a
530  // hole-with-holes.
532 
533  // We have to translate from MeshedHole points to mesh
534  // sides.
535  std::unordered_map<Point, Point> next_hole_boundary_point;
536  const int np = mh.n_points();
537  for (auto pi : make_range(1, np))
538  next_hole_boundary_point[mh.point(pi - 1)] = mh.point(pi);
539  next_hole_boundary_point[mh.point(np - 1)] = mh.point(0);
540 
541 #ifndef NDEBUG
542  int found_hole_sides = 0;
543 #endif
544  for (auto elem : hole_mesh.element_ptr_range())
545  {
546  if (elem->dim() != 2)
547  mooseError("Non 2-D element found in hole; stitching is not supported.");
548 
549  auto ns = elem->n_sides();
550  for (auto s : make_range(ns))
551  {
552  auto it_s = next_hole_boundary_point.find(elem->point(s));
553  if (it_s != next_hole_boundary_point.end())
554  if (it_s->second == elem->point((s + 1) % ns))
555  {
556  hole_boundary_info.add_side(elem, s, new_hole_bcid);
557 #ifndef NDEBUG
558  ++found_hole_sides;
559 #endif
560  }
561  }
562  }
563  mooseAssert(found_hole_sides == np, "Failed to find full outer boundary of meshed hole");
564 
565  auto & mesh_boundary_info = mesh->get_boundary_info();
566 #ifndef NDEBUG
567  int found_inner_sides = 0;
568 #endif
569  for (auto elem : mesh->element_ptr_range())
570  {
571  auto ns = elem->n_sides();
572  for (auto s : make_range(ns))
573  {
574  auto it_s = next_hole_boundary_point.find(elem->point((s + 1) % ns));
575  if (it_s != next_hole_boundary_point.end())
576  if (it_s->second == elem->point(s))
577  {
578  mesh_boundary_info.add_side(elem, s, inner_bcid);
579 #ifndef NDEBUG
580  ++found_inner_sides;
581 #endif
582  }
583  }
584  }
585  mooseAssert(found_inner_sides == np, "Failed to find full boundary around meshed hole");
586 
587  // Retrieve subdomain name map from the mesh to be stitched and insert it into the main
588  // subdomain map
589  const auto & increment_subdomain_map = hole_mesh.get_subdomain_name_map();
590  main_subdomain_map.insert(increment_subdomain_map.begin(), increment_subdomain_map.end());
591 
592  mesh->stitch_meshes(hole_mesh,
593  inner_bcid,
594  new_hole_bcid,
595  TOLERANCE,
596  /*clear_stitched_bcids*/ true,
598  use_binary_search);
599  }
600  }
601  // Check if one SubdomainName is shared by more than one subdomain ids
602  std::set<SubdomainName> main_subdomain_map_name_list;
603  for (auto const & id_name_pair : main_subdomain_map)
604  main_subdomain_map_name_list.emplace(id_name_pair.second);
605  if (main_subdomain_map.size() != main_subdomain_map_name_list.size())
606  paramError("holes", "The hole meshes contain subdomain name maps with conflicts.");
607 
608  mesh->set_isnt_prepared();
609  return mesh;
610 }
const std::string _desired_area_func
Desired triangle area as a (fparser-compatible) function of x,y.
const bool _verbose_stitching
Whether mesh stitching should have verbose output.
virtual unsigned int n_points() const override
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 ...
Definition: MooseBase.h:435
const bool _verify_holes
Whether to verify holes do not intersect boundary or each other.
const std::vector< Point > getDataAsPoints() const
Get the data in Point format.
T * get(const std::unique_ptr< T > &u)
The MooseUtils::get() specializations are used to support making forwards-compatible code changes fro...
Definition: MooseUtils.h:1155
const std::vector< bool > _refine_holes
Whether to allow automatically refining each hole boundary.
registerMooseObject("MooseApp", XYDelaunayGenerator)
MeshBase & mesh
const Real _auto_area_func_default_size
Background size for automatic desired area function.
std::vector< Point > _interior_points
Desired interior node locations.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const bool _smooth_tri
Whether to do Laplacian mesh smoothing on the generated triangles.
const Parallel::Communicator & comm() const
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
const Parallel::Communicator & _communicator
std::vector< subdomain_id_type > getSubdomainIDs(const libMesh::MeshBase &mesh, const std::vector< SubdomainName > &subdomain_name)
Get the associated subdomainIDs for the subdomain names that are passed in.
std::unique_ptr< MeshBase > & _bdy_ptr
Input mesh defining the boundary to triangulate within.
const bool _refine_bdy
Whether to allow automatically refining the outer boundary.
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...
SubdomainID getSubdomainID(const SubdomainName &subdomain_name, const MeshBase &mesh)
Gets the subdomain ID associated with the given SubdomainName.
auto max(const L &left, const R &right)
TRI3
const SubdomainID INVALID_BLOCK_ID
Definition: MooseTypes.C:20
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
const std::vector< bool > _stitch_holes
Whether to stitch to the mesh defining each hole.
Generates a triangulation in the XY plane, based on an input mesh defining the outer boundary (as wel...
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:99
int8_t boundary_id_type
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
TRI6
boundary_id_type BoundaryID
void change_boundary_id(MeshBase &mesh, const boundary_id_type old_id, const boundary_id_type new_id)
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
void read()
Perform the actual data reading.
static InputParameters validParams()
Definition: MeshGenerator.C:23
XYDelaunayGenerator(const InputParameters &parameters)
const Real _auto_area_function_power
Power of the polynomial used in the inverse distance interpolation for automatic area function...
static InputParameters validParams()
const unsigned int _add_nodes_per_boundary_segment
How many more nodes to add in each outer boundary segment.
std::string enum_to_string(const T e)
const bool _use_auto_area_func
Whether to use automatic desired area function.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Utility class for reading delimited data (e.g., CSV data).
const MooseEnum _algorithm
Type of algorithm used to find matching nodes (binary or exhaustive)
const std::vector< std::unique_ptr< MeshBase > * > _hole_ptrs
Holds pointers to the pointers to input meshes defining holes.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:267
TRI7
const MooseEnum _tri_elem_type
Type of triangular elements to be generated.
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 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 addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
const Real _auto_area_func_default_size_dist
Background size&#39;s effective distance for automatic desired area function.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
const unsigned int _auto_area_function_num_points
Maximum number of points to use for the inverse distance interpolation for automatic area function...
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
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...
SubdomainID _output_subdomain_id
What subdomain_id to set on the generated triangles.
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition: MooseBase.h:201
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:32
void ErrorVector unsigned int
auto index_range(const T &sizable)
const Real _desired_area
Desired (maximum) triangle area.
const Real pi
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...