79 std::unique_ptr<MeshBase> boundary_mesh,
80 std::vector<std::unique_ptr<MeshBase>> hole_meshes,
84 std::unique_ptr<UnstructuredMesh>
mesh =
85 dynamic_pointer_cast<UnstructuredMesh>(std::move(boundary_mesh));
106 std::vector<libMesh::TriangulatorInterface::MeshedHole> meshed_holes;
107 std::vector<libMesh::TriangulatorInterface::Hole *> triangulator_hole_ptrs(hole_meshes.size());
110 std::vector<bool> holes_with_midpoints(hole_meshes.size());
111 bool stitch_second_order_holes(
false);
114 meshed_holes.reserve(hole_meshes.size());
115 for (
auto hole_i : index_range(hole_meshes))
117 if (!hole_meshes[hole_i]->is_prepared())
118 hole_meshes[hole_i]->prepare_for_use();
123 meshed_holes.emplace_back(*hole_meshes[hole_i]);
124 holes_with_midpoints[hole_i] = meshed_holes.back().n_midpoints();
125 stitch_second_order_holes =
128 : ((holes_with_midpoints[hole_i] && xyd_opts.
stitch_holes[hole_i]) ||
129 stitch_second_order_holes);
131 meshed_holes.back().set_refine_boundary_allowed(xyd_opts.
refine_holes[hole_i]);
133 triangulator_hole_ptrs[hole_i] = &meshed_holes.back();
135 if (stitch_second_order_holes &&
139 "Cannot use first order elements with stitched quadratic element holes. Please try "
140 "to specify a higher-order tri_element_type or reduce the order of the hole inputs.");
142 if (!triangulator_hole_ptrs.empty())
163 poly2tri.
elem_type() = libMesh::ElemType::TRI6;
166 poly2tri.
elem_type() = libMesh::ElemType::TRI7;
176 mesh->add_point(point);
187 UnstructuredMesh & mesh,
188 std::vector<std::unique_ptr<MeshBase>> & holes,
189 const std::vector<bool> & holes_with_midpoints,
198 if (
id == Elem::invalid_subdomain_id)
206 for (
auto & hole_ptr : holes)
208 auto possible_sbdid =
211 if (possible_sbdid != Elem::invalid_subdomain_id)
213 output_subdomain_id = possible_sbdid;
216 output_subdomain_id =
225 if (
id != output_subdomain_id)
227 "name has been used by the input meshes and the corresponding id is not "
228 "equal to 'output_subdomain_id'");
231 output_subdomain_id = id;
239 for (
auto elem :
mesh.element_ptr_range())
245 <<
" found in triangulation");
247 elem->subdomain_id() = output_subdomain_id;
256 auto cross_prod = (elem->point(1) - elem->point(0)).cross(elem->point(2) - elem->point(0));
258 if (cross_prod(2) <= 0)
259 mooseError(
"Inverted element found in triangulation.\n"
260 "Laplacian smoothing can create these at reentrant corners; disable it?");
275 const boundary_id_type end_bcid = holes.size() + 1;
279 std::vector<BoundaryID> hole_boundary_rec(holes.size());
280 std::iota(hole_boundary_rec.begin(), hole_boundary_rec.end(), 1);
288 for (
auto hole_i : index_range(holes))
294 holes[hole_i]->comm().max(free_boundary_id);
297 for (
auto h : index_range(holes))
300 hole_boundary_rec[h] = h + 1 + free_boundary_id;
303 boundary_id_type new_hole_bcid = end_bcid + free_boundary_id;
316 for (
auto h : index_range(holes))
318 mesh, h + 1 + free_boundary_id, h + 1 + free_boundary_id + end_bcid);
320 for (
auto h : index_range(holes))
323 mesh, h + 1 + free_boundary_id + end_bcid, hole_boundary_ids[h]);
324 hole_boundary_rec[h] = hole_boundary_ids[h];
326 new_hole_bcid = std::max(new_hole_bcid, boundary_id_type(hole_boundary_ids[h] + 1));
332 const std::vector<BoundaryID> output_boundary_id =
336 mesh, end_bcid + free_boundary_id, output_boundary_id[0]);
339 new_hole_bcid = std::max(new_hole_bcid, boundary_id_type(output_boundary_id[0] + 1));
342 bool doing_stitching =
false;
344 for (
auto hole_i : index_range(holes))
346 const MeshBase & hole_mesh = *holes[hole_i];
347 auto & hole_boundary_info = hole_mesh.get_boundary_info();
348 const std::set<boundary_id_type> & local_hole_bcids = hole_boundary_info.get_boundary_ids();
350 if (!local_hole_bcids.empty())
351 new_hole_bcid = std::max(new_hole_bcid, boundary_id_type(*local_hole_bcids.rbegin() + 1));
352 hole_mesh.comm().max(new_hole_bcid);
355 doing_stitching =
true;
358 const boundary_id_type inner_bcid = new_hole_bcid + 1;
365 auto & main_subdomain_map =
mesh.set_subdomain_name_map();
366 for (
auto hole_i : index_range(holes))
370 UnstructuredMesh & hole_mesh =
dynamic_cast<UnstructuredMesh &
>(*holes[hole_i]);
372 if (!holes_with_midpoints[hole_i])
375 hole_mesh.all_second_order();
377 hole_mesh.all_complete_order();
379 auto & hole_boundary_info = hole_mesh.get_boundary_info();
394 : std::set<std::size_t>();
399 std::unordered_map<Point, Point> next_hole_boundary_point;
401 for (
auto pi : make_range(1, np))
402 next_hole_boundary_point[mh.point(pi - 1)] = mh.point(pi);
403 next_hole_boundary_point[mh.point(np - 1)] = mh.point(0);
406 int found_hole_sides = 0;
408 for (
auto elem : hole_mesh.element_ptr_range())
410 if (elem->dim() != 2)
411 mooseError(
"Non 2-D element found in hole; stitching is not supported.");
413 auto ns = elem->n_sides();
414 for (
auto s : make_range(ns))
416 auto it_s = next_hole_boundary_point.find(elem->point(s));
417 if (it_s != next_hole_boundary_point.end())
418 if (it_s->second == elem->point((s + 1) % ns))
420 hole_boundary_info.add_side(elem, s, new_hole_bcid);
427 mooseAssert(found_hole_sides == np,
"Failed to find full outer boundary of meshed hole");
429 auto & mesh_boundary_info =
mesh.get_boundary_info();
431 int found_inner_sides = 0;
433 for (
auto elem :
mesh.element_ptr_range())
435 auto ns = elem->n_sides();
436 for (
auto s : make_range(ns))
438 auto it_s = next_hole_boundary_point.find(elem->point((s + 1) % ns));
439 if (it_s != next_hole_boundary_point.end())
440 if (it_s->second == elem->point(s))
442 mesh_boundary_info.add_side(elem, s, inner_bcid);
449 mooseAssert(found_inner_sides == np,
"Failed to find full boundary around meshed hole");
453 const auto & increment_subdomain_map = hole_mesh.get_subdomain_name_map();
454 main_subdomain_map.insert(increment_subdomain_map.begin(), increment_subdomain_map.end());
457 for (
const auto & bcid : hole_bdy_id_filter)
458 hole_boundary_info.remove_id(bcid);
460 if (hole_bdy_id_filter.size())
467 hole_boundary_rec[hole_i],
469 hole_mesh.get_boundary_info().sideset_name(hole_boundary_rec[hole_i]) =
470 mesh.get_boundary_info().sideset_name(hole_boundary_rec[hole_i]);
471 mesh.get_boundary_info().remove_id(hole_boundary_rec[hole_i]);
474 mesh.stitch_meshes(hole_mesh,
484 std::set<SubdomainName> main_subdomain_map_name_list;
485 for (
auto const & id_name_pair : main_subdomain_map)
486 main_subdomain_map_name_list.emplace(id_name_pair.second);
487 if (main_subdomain_map.size() != main_subdomain_map_name_list.size())
488 mg.
paramError(
"holes",
"The hole meshes contain subdomain name maps with conflicts.");
490 mesh.unset_is_prepared();