32 std::unique_ptr<MeshBase> boundary_mesh,
33 std::vector<std::unique_ptr<MeshBase>> hole_meshes,
37 std::unique_ptr<UnstructuredMesh>
mesh =
38 dynamic_pointer_cast<UnstructuredMesh>(std::move(boundary_mesh));
46 std::set<std::size_t> bdy_ids;
52 "input_subdomain_names",
53 "input_boundary_names and input_subdomain_names cannot both specify an outer boundary.");
59 mg.
paramError(
"input_boundary_names", name,
" is not a boundary name in the input mesh");
71 const auto subdomain_ids =
75 std::set<SubdomainID> subdomains;
83 " was not found in the boundary mesh");
85 bdy_ids.insert(subdomain_ids[i]);
100 std::vector<libMesh::TriangulatorInterface::MeshedHole> meshed_holes;
101 std::vector<libMesh::TriangulatorInterface::Hole *> triangulator_hole_ptrs(hole_meshes.size());
104 std::vector<bool> holes_with_midpoints(hole_meshes.size());
105 bool stitch_second_order_holes(
false);
108 meshed_holes.reserve(hole_meshes.size());
111 if (!hole_meshes[hole_i]->is_prepared())
112 hole_meshes[hole_i]->prepare_for_use();
117 meshed_holes.emplace_back(*hole_meshes[hole_i]);
118 holes_with_midpoints[hole_i] = meshed_holes.back().n_midpoints();
119 stitch_second_order_holes =
122 : ((holes_with_midpoints[hole_i] && xyd_opts.
stitch_holes[hole_i]) ||
123 stitch_second_order_holes);
125 meshed_holes.back().set_refine_boundary_allowed(xyd_opts.
refine_holes[hole_i]);
127 triangulator_hole_ptrs[hole_i] = &meshed_holes.back();
129 if (stitch_second_order_holes &&
133 "Cannot use first order elements with stitched quadratic element holes. Please try "
134 "to specify a higher-order tri_element_type or reduce the order of the hole inputs.");
136 if (!triangulator_hole_ptrs.empty())
157 poly2tri.
elem_type() = libMesh::ElemType::TRI6;
159 poly2tri.
elem_type() = libMesh::ElemType::TRI7;
174 if (
id == Elem::invalid_subdomain_id)
182 for (
auto & hole_ptr : hole_meshes)
184 auto possible_sbdid =
187 if (possible_sbdid != Elem::invalid_subdomain_id)
189 output_subdomain_id = possible_sbdid;
192 output_subdomain_id =
201 if (
id != output_subdomain_id)
203 "name has been used by the input meshes and the corresponding id is not "
204 "equal to 'output_subdomain_id'");
207 output_subdomain_id = id;
214 if (xyd_opts.
smooth_tri || output_subdomain_id)
215 for (
auto elem :
mesh->element_ptr_range())
217 mooseAssert(elem->type() == (xyd_opts.
tri_elem_type ==
"TRI6"
221 <<
" found in triangulation");
223 elem->subdomain_id() = output_subdomain_id;
232 auto cross_prod = (elem->point(1) - elem->point(0)).cross(elem->point(2) - elem->point(0));
234 if (cross_prod(2) <= 0)
235 mooseError(
"Inverted element found in triangulation.\n"
236 "Laplacian smoothing can create these at reentrant corners; disable it?");
255 std::vector<BoundaryID> hole_boundary_rec(hole_meshes.size());
256 std::iota(hole_boundary_rec.begin(), hole_boundary_rec.end(), 1);
270 hole_meshes[hole_i]->comm().max(free_boundary_id);
276 hole_boundary_rec[h] = h + 1 + free_boundary_id;
294 *
mesh, h + 1 + free_boundary_id, h + 1 + free_boundary_id + end_bcid);
299 *
mesh, h + 1 + free_boundary_id + end_bcid, hole_boundary_ids[h]);
300 hole_boundary_rec[h] = hole_boundary_ids[h];
302 new_hole_bcid = std::max(new_hole_bcid,
boundary_id_type(hole_boundary_ids[h] + 1));
308 const std::vector<BoundaryID> output_boundary_id =
312 *
mesh, end_bcid + free_boundary_id, output_boundary_id[0]);
315 new_hole_bcid = std::max(new_hole_bcid,
boundary_id_type(output_boundary_id[0] + 1));
318 bool doing_stitching =
false;
322 const MeshBase & hole_mesh = *hole_meshes[hole_i];
324 const std::set<boundary_id_type> & local_hole_bcids = hole_boundary_info.
get_boundary_ids();
326 if (!local_hole_bcids.empty())
327 new_hole_bcid = std::max(new_hole_bcid,
boundary_id_type(*local_hole_bcids.rbegin() + 1));
328 hole_mesh.
comm().
max(new_hole_bcid);
331 doing_stitching =
true;
348 if (!holes_with_midpoints[hole_i])
370 : std::set<std::size_t>();
375 std::unordered_map<Point, Point> next_hole_boundary_point;
376 const int np = mh.n_points();
378 next_hole_boundary_point[mh.point(
pi - 1)] = mh.
point(
pi);
379 next_hole_boundary_point[mh.point(np - 1)] = mh.point(0);
382 int found_hole_sides = 0;
384 for (
auto elem : hole_mesh.element_ptr_range())
386 if (elem->dim() != 2)
387 mooseError(
"Non 2-D element found in hole; stitching is not supported.");
389 auto ns = elem->n_sides();
392 auto it_s = next_hole_boundary_point.find(elem->point(s));
393 if (it_s != next_hole_boundary_point.end())
394 if (it_s->second == elem->point((s + 1) % ns))
396 hole_boundary_info.add_side(elem, s, new_hole_bcid);
403 mooseAssert(found_hole_sides == np,
"Failed to find full outer boundary of meshed hole");
407 int found_inner_sides = 0;
409 for (
auto elem :
mesh->element_ptr_range())
411 auto ns = elem->n_sides();
414 auto it_s = next_hole_boundary_point.find(elem->point((s + 1) % ns));
415 if (it_s != next_hole_boundary_point.end())
416 if (it_s->second == elem->point(s))
418 mesh_boundary_info.
add_side(elem, s, inner_bcid);
425 mooseAssert(found_inner_sides == np,
"Failed to find full boundary around meshed hole");
430 main_subdomain_map.insert(increment_subdomain_map.begin(), increment_subdomain_map.end());
433 for (
const auto & bcid : hole_bdy_id_filter)
434 hole_boundary_info.remove_id(bcid);
436 if (hole_bdy_id_filter.size())
443 hole_boundary_rec[hole_i],
450 mesh->stitch_meshes(hole_mesh,
460 std::set<SubdomainName> main_subdomain_map_name_list;
461 for (
auto const & id_name_pair : main_subdomain_map)
462 main_subdomain_map_name_list.emplace(id_name_pair.second);
463 if (main_subdomain_map.size() != main_subdomain_map_name_list.size())
464 mg.
paramError(
"holes",
"The hole meshes contain subdomain name maps with conflicts.");