458 std::set<std::size_t> ids)
459 : _center(
std::numeric_limits<
Real>::max())
471 std::string error_reported;
473 auto report_error = [&
mesh, &error_reported](std::string er) {
474 error_reported = std::move(er);
476 libmesh_error_msg(error_reported);
483 libmesh_error_msg_if(!error_reported.empty(), error_reported);
497 std::multimap<
const Node *,
498 std::pair<const Node *, int>> hole_edge_map;
503 std::map<std::pair<const Node *, const Node *>,
504 std::vector<const Node *>> hole_midpoint_map;
506 std::vector<boundary_id_type> bcids;
510 for (
const auto & elem :
mesh.active_element_ptr_range())
512 if (elem->dim() == 1)
514 if (ids.empty() || ids.count(elem->subdomain_id()))
516 hole_edge_map.emplace(elem->node_ptr(0),
517 std::make_pair(elem->node_ptr(1),
519 hole_edge_map.emplace(elem->node_ptr(1),
520 std::make_pair(elem->node_ptr(0),
522 if (elem->type() ==
EDGE3)
524 hole_midpoint_map.emplace(std::make_pair(elem->node_ptr(0),
526 std::vector<const Node *>{elem->node_ptr(2)});
527 hole_midpoint_map.emplace(std::make_pair(elem->node_ptr(1),
529 std::vector<const Node *>{elem->node_ptr(2)});
531 else if (elem->type() ==
EDGE4)
533 hole_midpoint_map.emplace(std::make_pair(elem->node_ptr(0),
535 std::vector<const Node *>{elem->node_ptr(2),
537 hole_midpoint_map.emplace(std::make_pair(elem->node_ptr(1),
539 std::vector<const Node *>{elem->node_ptr(3),
543 libmesh_assert_equal_to(elem->default_side_order(), 1);
548 if (elem->dim() == 2)
550 const auto ns = elem->n_sides();
555 bool add_edge =
false;
556 if (!elem->neighbor_ptr(s) && ids.empty())
566 hole_edge_map.emplace(elem->node_ptr(s),
567 std::make_pair(elem->node_ptr((s+1)%ns),
570 hole_edge_map.emplace(elem->node_ptr((s+1)%ns),
571 std::make_pair(elem->node_ptr(s),
574 if (elem->default_side_order() == 2)
576 hole_midpoint_map.emplace(std::make_pair(elem->node_ptr(s),
577 elem->node_ptr((s+1)%ns)),
578 std::vector<const Node *>{elem->node_ptr(s+ns)});
579 hole_midpoint_map.emplace(std::make_pair(elem->node_ptr((s+1)%ns),
581 std::vector<const Node *>{elem->node_ptr(s+ns)});
584 libmesh_assert_equal_to(elem->default_side_order(), 1);
592 if (hole_edge_map.empty())
593 report_error(
"No valid hole edges found in mesh!");
601 auto extract_edge_vector =
602 [&report_error, &hole_edge_map, &hole_midpoint_map]() {
603 std::tuple<std::vector<const Node *>, std::vector<const Node *>,
int>
604 hole_points_and_edge_type
605 {{hole_edge_map.begin()->first, hole_edge_map.begin()->second.first},
606 {}, hole_edge_map.begin()->second.second};
608 auto & hole_points = std::get<0>(hole_points_and_edge_type);
609 auto & midpoint_points = std::get<1>(hole_points_and_edge_type);
610 int & edge_type = std::get<2>(hole_points_and_edge_type);
613 hole_edge_map.erase(hole_points.front());
616 for (
const Node * last = hole_points.front(),
617 * n = hole_points.back();
618 n != hole_points.front();
620 n = hole_points.back())
622 auto [next_it_begin, next_it_end] = hole_edge_map.equal_range(n);
624 if (std::distance(next_it_begin, next_it_end) != 2)
625 report_error(
"Bad edge topology found by MeshedHole");
627 const Node * next =
nullptr;
628 for (
const auto & [key, val] :
as_range(next_it_begin, next_it_end))
630 libmesh_assert_equal_to(key, n);
632 libmesh_assert_not_equal_to(val.first, n);
635 if (val.first == last)
640 if (val.second != edge_type &&
644 edge_type = val.second;
646 report_error(
"MeshedHole sees inconsistent triangle orientations on boundary");
652 hole_edge_map.erase(next_it_begin, next_it_end);
654 hole_points.push_back(next);
657 for (
auto i :
make_range(hole_points.size()-1))
659 const auto & midpoints = hole_midpoint_map[{hole_points[i],hole_points[i+1]}];
660 midpoint_points.insert(midpoint_points.end(),
661 midpoints.begin(), midpoints.end());
664 hole_points.pop_back();
666 return hole_points_and_edge_type;
673 int n_negative_areas = 0,
674 n_positive_areas = 0,
675 n_edgeelem_loops = 0;
677 std::vector<const Node *> outer_hole_points, outer_mid_points;
678 int outer_edge_type = -1;
679 Real twice_outer_area = 0,
680 abs_twice_outer_area = 0;
684 std::vector<std::pair<Real, int>> areas;
687 while (!hole_edge_map.empty()) {
688 auto [hole_points, mid_points, edge_type] = extract_edge_vector();
693 if (n_edgeelem_loops > 1)
694 report_error(
"MeshedHole is confused by multiple loops of Edge elements");
695 if (n_positive_areas || n_negative_areas)
696 report_error(
"MeshedHole is confused by meshes with both Edge and 2D-side boundaries");
699 const std::size_t n_hole_points = hole_points.size();
700 if (n_hole_points < 3)
701 report_error(
"Loop with only " + std::to_string(n_hole_points) +
702 " hole edges found in mesh!");
704 Real twice_this_area = 0;
705 const Point p0 = *hole_points[0];
706 for (
unsigned int i=2; i != n_hole_points; ++i)
708 const Point e_0im = *hole_points[i-1] - p0,
709 e_0i = *hole_points[i] - p0;
711 twice_this_area += e_0i.
cross(e_0im)(2);
714 auto abs_twice_this_area = std::abs(twice_this_area);
716 if (((twice_this_area > 0) && edge_type == 2) ||
717 ((twice_this_area < 0) && edge_type == 1))
719 else if (edge_type != 0)
723 areas.push_back({twice_this_area/2,edge_type});
726 if (abs_twice_this_area > abs_twice_outer_area)
728 twice_outer_area = twice_this_area;
729 abs_twice_outer_area = abs_twice_this_area;
730 outer_hole_points = std::move(hole_points);
731 outer_mid_points = std::move(mid_points);
732 outer_edge_type = edge_type;
736 _points.resize(outer_hole_points.size());
737 std::transform(outer_hole_points.begin(),
738 outer_hole_points.end(),
740 [](
const Node * n){ return Point(*n); });
742 std::transform(outer_mid_points.begin(),
743 outer_mid_points.end(),
745 [](
const Node * n){ return Point(*n); });
747 if (!twice_outer_area)
748 report_error(
"Zero-area MeshedHoles are not currently supported");
752 if (twice_outer_area > 0)
767 auto print_areas = [areas](){
769 static const std::vector<std::string> edgenames {
"E",
"CW",
"CCW"};
770 for (
auto area : areas)
776 auto print_areas = [](){};
779 if (((twice_outer_area > 0) && outer_edge_type == 2) ||
780 ((twice_outer_area < 0) && outer_edge_type == 1))
782 if (n_positive_areas > 1)
785 report_error(
"MeshedHole found " +
786 std::to_string(n_positive_areas) +
787 " counter-clockwise boundaries and cannot choose one!");
791 else if (outer_edge_type != 0)
793 if (n_negative_areas > 1)
796 report_error(
"MeshedHole found " +
797 std::to_string(n_negative_areas) +
798 " clockwise boundaries and cannot choose one!");