70 mooseError(
"SBMInterfaceManager requires surfaces for at least two subdomains.");
72 for (
auto first_it = sets.begin(); first_it != sets.end(); ++first_it)
73 for (
auto second_it = std::next(first_it); second_it != sets.end(); ++second_it)
75 const auto first_id = first_it->first;
76 const auto second_id = second_it->first;
77 const auto key = std::minmax(first_id, second_id);
78 const auto & source_set = key.first == first_id ? first_it->second : second_it->second;
79 const auto & target_set = key.first == first_id ? second_it->second : first_it->second;
81 Real target_max_radius = 0.0;
82 for (
const auto & element : target_set.elements())
83 target_max_radius = std::max(target_max_radius, element->computeBoundingBall().radius());
86 auto &
interface =
_interfaces[{key.first, key.second}];
87 std::vector<nanoflann::ResultItem<std::size_t, Real>> candidates;
89 for (
const auto & source : source_set.elements())
91 const Point centroid = source->elem().vertex_average();
92 const Real search_radius =
95 target_tree.
radiusSearch(centroid, search_radius, candidates);
97 const auto matched = std::find_if(
100 [&](
const auto & candidate)
102 const auto & target = *target_set.elements()[candidate.first];
103 if (std::abs(std::abs(source->normal() * target.normal()) - 1.0) > _normal_tolerance)
106 const auto all_vertices_on = [&](const Elem & element, const SurfaceElement & surface)
108 for (const auto & node : element.node_ref_range())
109 if (SBMUtils::distanceFrom(surface, node).norm() > _distance_tolerance)
113 return all_vertices_on(source->elem(), target) &&
114 all_vertices_on(target.elem(), *source);
117 if (matched != candidates.end())
119 interface.elements.push_back(source.get());
120 interface.centroids.push_back(centroid);
121 interface.max_element_radius =
122 std::max(interface.max_element_radius, source->computeBoundingBall().radius());
126 if (interface.elements.empty())
129 interface.kd_tree = std::make_unique<KDTree>(interface.centroids,
_leaf_max_size);
143 const Point & point)
const
145 const auto ordered = std::minmax(first, second);
146 const auto interface_it =
_interfaces.find({ordered.first, ordered.second});
148 mooseError(
"SBMInterfaceManager: interface (", first,
", ", second,
") was not detected.");
150 const auto &
interface = interface_it->second;
151 std::vector<std::size_t> indices;
152 interface.kd_tree->neighborSearch(point, 1, indices);
153 std::size_t closest = indices.front();
156 std::vector<nanoflann::ResultItem<std::size_t, Real>> candidates;
157 interface.kd_tree->radiusSearch(
158 point,
distance.norm() + interface.max_element_radius, candidates);
159 for (
const auto & candidate : candidates)
161 const Point candidate_distance =
163 if (candidate_distance.norm() <
distance.norm())
165 closest = candidate.first;
170 Point normal = interface.elements[closest]->normal();
BoundaryMeshBuilder specialization that groups the surface elements by subdomain, building one Surfac...
static InputParameters validParams()
const std::unordered_map< subdomain_id_type, SurfaceElementSet > & getSurfaceElementSetsBySubdomain() const
Per-subdomain SurfaceElementSets. Valid after initialSetup().
virtual void initialSetup() override
libMesh::Point distanceFrom(const SurfaceElement &surface_elem, const libMesh::Point &pt)
Returns the vector from pt to the nearest point on the surface element: the normal projection if it f...
Real distance(const Point &p)