9#include "BoundingBoxTree.h"
16#include <dolfinx/fem/CoordinateElement.h>
17#include <dolfinx/fem/ElementDofLayout.h>
18#include <dolfinx/graph/AdjacencyList.h>
19#include <dolfinx/mesh/Mesh.h>
33template <std::
floating_po
int T>
41 std::vector<std::int32_t>
56template <std::
floating_po
int T>
58 std::span<const std::int32_t> entities,
59 std::span<const T> points)
61 const int tdim =
mesh.topology()->dim();
64 std::span<const T> geom_dofs =
geometry.x();
65 auto x_dofmap =
geometry.dofmaps().front();
66 std::vector<T> shortest_vectors;
67 shortest_vectors.reserve(3 * entities.size());
70 for (std::size_t e = 0; e < entities.size(); e++)
74 assert(entities[e] >= 0);
75 auto dofs = md::submdspan(x_dofmap, entities[e], md::full_extent);
76 std::vector<T> nodes(3 * dofs.size());
77 for (std::size_t i = 0; i < dofs.size(); ++i)
79 const std::int32_t pos = 3 * dofs[i];
80 for (std::size_t j = 0; j < 3; ++j)
81 nodes[3 * i + j] = geom_dofs[pos + j];
86 shortest_vectors.insert(shortest_vectors.end(), d.begin(), d.end());
91 mesh.topology_mutable()->create_connectivity(dim, tdim);
92 mesh.topology_mutable()->create_connectivity(tdim, dim);
93 auto e_to_c =
mesh.topology()->connectivity(dim, tdim);
95 auto c_to_e =
mesh.topology_mutable()->connectivity(tdim, dim);
97 for (std::size_t e = 0; e < entities.size(); e++)
99 const std::int32_t index = entities[e];
102 assert(e_to_c->num_links(index) > 0);
103 const std::int32_t c = e_to_c->links(index)[0];
106 auto cell_entities = c_to_e->links(c);
107 auto it0 = std::find(cell_entities.begin(), cell_entities.end(), index);
108 assert(it0 != cell_entities.end());
109 const int local_cell_entity
110 = std::ranges::distance(cell_entities.begin(), it0);
113 auto dofs = md::submdspan(x_dofmap, c, md::full_extent);
114 const std::vector<int> entity_dofs
115 =
geometry.cmaps().front().create_dof_layout().entity_closure_dofs(
116 dim, local_cell_entity);
117 std::vector<T> nodes(3 * entity_dofs.size());
118 for (std::size_t i = 0; i < entity_dofs.size(); i++)
120 const std::int32_t pos = 3 * dofs[entity_dofs[i]];
121 for (std::size_t j = 0; j < 3; ++j)
122 nodes[3 * i + j] = geom_dofs[pos + j];
127 shortest_vectors.insert(shortest_vectors.end(), d.begin(), d.end());
131 return shortest_vectors;
140template <std::
floating_po
int T>
142 std::span<const T, 3> x)
144 auto b0 = b.template subspan<0, 3>();
145 auto b1 = b.template subspan<3, 3>();
146 return std::transform_reduce(x.begin(), x.end(), b0.begin(), 0.0,
151 return dx > 0 ? 0 : dx * dx;
153 + std::transform_reduce(x.begin(), x.end(), b1.begin(), 0.0,
158 return dx < 0 ? 0 : dx * dx;
177template <std::
floating_po
int T>
179 std::span<const std::int32_t> entities,
180 std::span<const T> points)
183 std::vector<T> d(v.size() / 3, 0);
184 for (std::size_t i = 0; i < d.size(); ++i)
185 for (std::size_t j = 0; j < 3; ++j)
186 d[i] += v[3 * i + j] * v[3 * i + j];
193constexpr bool is_leaf(std::array<std::int32_t, 2> bbox)
196 return bbox[0] == bbox[1];
203template <std::
floating_po
int T>
204constexpr bool point_in_bbox(std::span<const T, 6> b, std::span<const T, 3> x)
206 constexpr T rtol = 1e-14;
208 for (std::size_t i = 0; i < 3; i++)
210 T eps = rtol * (b[i + 3] - b[i]);
211 in &= (x[i] >= (b[i] - eps)) && (x[i] <= (b[i + 3] + eps));
222template <std::
floating_po
int T>
223constexpr bool bbox_in_bbox(std::span<const T, 6> a, std::span<const T, 6> b)
225 constexpr T rtol = 1e-14;
226 auto a0 = a.template subspan<0, 3>();
227 auto a1 = a.template subspan<3, 3>();
228 auto b0 = b.template subspan<0, 3>();
229 auto b1 = b.template subspan<3, 3>();
232 for (std::size_t i = 0; i < 3; i++)
234 T eps = rtol * (b1[i] - b0[i]);
235 in &= a1[i] >= (b0[i] - eps);
236 in &= a0[i] <= (b1[i] + eps);
244template <std::
floating_po
int T>
264template <std::
floating_po
int T>
266 std::int32_t entity, std::span<const T, 3> point,
269 const int tdim =
mesh.topology()->dim();
271 std::span<const T> geom_dofs =
geometry.x();
272 auto x_dofmap =
geometry.dofmaps().front();
278 auto dofs = md::submdspan(x_dofmap, entity, md::full_extent);
279 assert(3 * dofs.size() <= scratch.
nodes.size());
280 for (std::size_t i = 0; i < dofs.size(); ++i)
282 const std::int32_t pos = 3 * dofs[i];
283 for (std::size_t j = 0; j < 3; ++j)
284 scratch.
nodes[3 * i + j] = geom_dofs[pos + j];
288 point, std::span<const T>(scratch.
nodes.data(), 3 * dofs.size()));
292 mesh.topology_mutable()->create_connectivity(dim, tdim);
293 mesh.topology_mutable()->create_connectivity(tdim, dim);
294 auto e_to_c =
mesh.topology()->connectivity(dim, tdim);
296 auto c_to_e =
mesh.topology_mutable()->connectivity(tdim, dim);
300 assert(e_to_c->num_links(entity) > 0);
301 const std::int32_t c = e_to_c->links(entity)[0];
304 auto cell_entities = c_to_e->links(c);
305 auto it0 = std::find(cell_entities.begin(), cell_entities.end(), entity);
306 assert(it0 != cell_entities.end());
307 const int local_cell_entity
308 = std::ranges::distance(cell_entities.begin(), it0);
311 auto dofs = md::submdspan(x_dofmap, c, md::full_extent);
312 const std::vector<int>& entity_dofs
314 assert(3 * entity_dofs.size() <= scratch.
nodes.size());
315 for (std::size_t i = 0; i < entity_dofs.size(); i++)
317 const std::int32_t pos = 3 * dofs[entity_dofs[i]];
318 for (std::size_t j = 0; j < 3; ++j)
319 scratch.
nodes[3 * i + j] = geom_dofs[pos + j];
324 std::span<const T>(scratch.
nodes.data(), 3 * entity_dofs.size()));
327 return d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
331template <std::
floating_po
int T>
332std::pair<std::int32_t, T>
333_compute_closest_entity(
const geometry::BoundingBoxTree<T>& tree,
334 std::span<const T, 3> point, std::int32_t node,
335 const mesh::Mesh<T>& mesh, std::int32_t closest_entity,
340 const std::array<std::int32_t, 2> bbox = tree.bbox(node);
345 if (tree.tdim() == 0)
347 std::array<T, 6> diff = tree.get_bbox(node);
348 for (std::size_t k = 0; k < 3; ++k)
350 r2 = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
359 r2 = squared_distance_entity(mesh, tree.tdim(), bbox.back(), point,
366 closest_entity = bbox.back();
370 return {closest_entity, R2};
377 return {closest_entity, R2};
381 std::pair<std::int32_t, T> p0 = _compute_closest_entity(
382 tree, point, bbox.front(), mesh, closest_entity, R2, scratch);
383 std::pair<std::int32_t, T> p1 = _compute_closest_entity(
384 tree, point, bbox.back(), mesh, p0.first, p0.second, scratch);
395template <std::
floating_po
int T>
396void _compute_collisions_point(
const geometry::BoundingBoxTree<T>& tree,
397 std::span<const T, 3> p,
398 std::vector<std::int32_t>& entities,
399 std::vector<std::int32_t>& stack)
401 assert(stack.empty());
402 std::int32_t next = tree.num_bboxes() - 1;
403 std::span<const T> coords = tree.bbox_coordinates();
404 auto view_bbox = [&coords](std::int32_t node)
405 {
return std::span<const T, 6>(coords.data() + 6 * node, 6); };
408 if (std::array bbox = tree.bbox(next);
409 is_leaf(bbox) and point_in_bbox(view_bbox(next), p))
413 entities.push_back(bbox[1]);
420 bool left = point_in_bbox(view_bbox(bbox[0]), p);
421 bool right = point_in_bbox(view_bbox(bbox[1]), p);
427 stack.push_back(bbox[1]);
446 if (next == -1 and !stack.empty())
455template <std::
floating_po
int T>
456void _compute_collisions_tree(
const geometry::BoundingBoxTree<T>& A,
457 const geometry::BoundingBoxTree<T>& B,
458 std::int32_t node_A, std::int32_t node_B,
459 std::vector<std::int32_t>& entities)
462 if (!bbox_in_bbox<T>(A.get_bbox(node_A), B.get_bbox(node_B)))
466 const std::array<std::int32_t, 2> bbox_A = A.bbox(node_A);
467 const std::array<std::int32_t, 2> bbox_B = B.bbox(node_B);
470 const bool is_leaf_A = is_leaf(bbox_A);
471 const bool is_leaf_B = is_leaf(bbox_B);
472 if (is_leaf_A and is_leaf_B)
476 entities.push_back(bbox_A[1]);
477 entities.push_back(bbox_B[1]);
482 _compute_collisions_tree(A, B, node_A, bbox_B[0], entities);
483 _compute_collisions_tree(A, B, node_A, bbox_B[1], entities);
488 _compute_collisions_tree(A, B, bbox_A[0], node_B, entities);
489 _compute_collisions_tree(A, B, bbox_A[1], node_B, entities);
491 else if (node_A > node_B)
497 _compute_collisions_tree(A, B, bbox_A[0], node_B, entities);
498 _compute_collisions_tree(A, B, bbox_A[1], node_B, entities);
502 _compute_collisions_tree(A, B, node_A, bbox_B[0], entities);
503 _compute_collisions_tree(A, B, node_A, bbox_B[1], entities);
518template <std::
floating_po
int T>
520 std::span<const std::int32_t> entities)
522 spdlog::info(
"Building point search tree to accelerate distance queries for "
523 "a given topological dimension and subset of entities.");
525 const std::vector<T> midpoints
527 std::vector<std::pair<std::array<T, 3>, std::int32_t>> points(
529 for (std::size_t i = 0; i < points.size(); ++i)
531 for (std::size_t j = 0; j < 3; ++j)
532 points[i].first[j] = midpoints[3 * i + j];
533 points[i].second = entities[i];
545template <std::
floating_po
int T>
550 std::vector<std::int32_t> entities;
553 impl::_compute_collisions_tree(tree0, tree1, tree0.
num_bboxes() - 1,
570template <std::
floating_po
int T>
576 std::vector<std::int32_t> entities, offsets(points.size() / 3 + 1, 0);
577 entities.reserve(points.size() / 3);
580 std::vector<std::int32_t> stack;
581 for (std::size_t p = 0; p < points.size() / 3; ++p)
583 impl::_compute_collisions_point(
584 tree, std::span<const T, 3>(points.data() + 3 * p, 3), entities,
586 offsets[p + 1] = entities.size();
594 std::vector<std::int32_t>(),
595 std::vector<std::int32_t>(points.size() / 3 + 1, 0));
624template <std::
floating_po
int T>
626 std::span<const std::int32_t> cells,
627 std::array<T, 3> point, T tol,
628 std::span<T> coordinate_dofs)
634 std::span<const T> geom_dofs =
geometry.x();
635 auto x_dofmap =
geometry.dofmaps().front();
636 const std::size_t num_nodes = x_dofmap.extent(1);
637 assert(coordinate_dofs.size() >= num_nodes * 3);
638 std::span<T> cell_dofs = coordinate_dofs.first(num_nodes * 3);
639 for (
auto cell : cells)
641 auto dofs = md::submdspan(x_dofmap, cell, md::full_extent);
642 for (std::size_t i = 0; i < num_nodes; ++i)
644 std::copy_n(std::next(geom_dofs.begin(), 3 * dofs[i]), 3,
645 std::next(cell_dofs.begin(), 3 * i));
651 [](
auto d,
auto e) {
return d + e * e; });
671template <std::
floating_po
int T>
672std::vector<std::int32_t>
678 return std::vector<std::int32_t>(points.size() / 3, -1);
680 std::vector<std::int32_t> entities;
681 entities.reserve(points.size() / 3);
684 =
mesh.geometry().cmaps().front().create_dof_layout();
689 std::size_t max_nodes = 0;
691 max_nodes = std::max(max_nodes,
static_cast<std::size_t
>(cmap.dim()));
692 impl::ClosestEntityScratch<T> scratch{std::vector<T>(3 * max_nodes),
694 for (std::size_t i = 0; i < points.size() / 3; ++i)
699 std::array<std::int32_t, 2> leaf0 = midpoint_tree.
bbox(0);
700 assert(impl::is_leaf(leaf0));
701 std::array<T, 6> diff = midpoint_tree.
get_bbox(0);
702 for (std::size_t k = 0; k < 3; ++k)
703 diff[k] -= points[3 * i + k];
704 T R2 = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
710 const auto [m_index, m_distance2] = impl::_compute_closest_entity(
711 midpoint_tree, std::span<const T, 3>(points.data() + 3 * i, 3),
719 const auto [index, distance2] = impl::_compute_closest_entity(
720 tree, std::span<const T, 3>(points.data() + 3 * i, 3),
723 entities.push_back(index);
744template <std::
floating_po
int T>
748 std::span<const T> points)
750 std::vector<std::int32_t> offsets = {0};
751 offsets.reserve(candidate_cells.
num_nodes() + 1);
752 std::vector<std::int32_t> colliding_cells;
753 constexpr T eps2 = 1e-12;
754 const int tdim =
mesh.topology()->dim();
755 for (std::int32_t i = 0; i < candidate_cells.
num_nodes(); i++)
757 auto cells = candidate_cells.
links(i);
758 std::vector<T> _point(3 * cells.size());
759 for (std::size_t j = 0; j < cells.size(); ++j)
760 for (std::size_t k = 0; k < 3; ++k)
761 _point[3 * j + k] = points[3 * i + k];
764 for (std::size_t j = 0; j < cells.size(); j++)
765 if (distances_sq[j] < eps2)
766 colliding_cells.push_back(cells[j]);
768 offsets.push_back(colliding_cells.size());
815template <std::
floating_po
int T>
819 std::optional<std::span<const std::int32_t>> cells,
820 bool find_closest_cell =
true)
822 MPI_Comm comm =
mesh.comm();
824 const int tdim =
mesh.topology()->dim();
826 std::vector<std::int32_t> local_cells;
827 if (not(cells.has_value()))
829 auto cell_map =
mesh.topology()->index_map(tdim);
830 local_cells.resize(cell_map->size_local());
831 std::iota(local_cells.begin(), local_cells.end(), 0);
833 = std::span<const std::int32_t>(local_cells.data(), local_cells.size());
845 std::vector<std::int32_t> out_ranks = collisions.
array();
846 std::ranges::sort(out_ranks);
847 auto [unique_end, range_end] = std::ranges::unique(out_ranks);
848 out_ranks.erase(unique_end, range_end);
852 std::ranges::sort(in_ranks);
855 MPI_Comm forward_comm;
856 MPI_Dist_graph_create_adjacent(
857 comm, in_ranks.size(), in_ranks.data(), MPI_UNWEIGHTED, out_ranks.size(),
858 out_ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &forward_comm);
862 std::map<std::int32_t, std::int32_t> rank_to_neighbor;
863 for (std::size_t i = 0; i < out_ranks.size(); i++)
864 rank_to_neighbor[out_ranks[i]] = i;
867 std::vector<std::int32_t> send_sizes(out_ranks.size());
868 for (std::size_t i = 0; i < points.size() / 3; ++i)
869 for (std::int32_t p : collisions.
links(i))
870 send_sizes[rank_to_neighbor[p]] += 3;
873 std::vector<std::int32_t> recv_sizes(in_ranks.size());
874 send_sizes.reserve(1);
875 recv_sizes.reserve(1);
876 MPI_Request sizes_request;
877 MPI_Ineighbor_alltoall(send_sizes.data(), 1, MPI_INT, recv_sizes.data(), 1,
878 MPI_INT, forward_comm, &sizes_request);
881 std::vector<std::int32_t> send_offsets(send_sizes.size() + 1, 0);
882 std::partial_sum(send_sizes.begin(), send_sizes.end(),
883 std::next(send_offsets.begin(), 1));
886 std::vector<T> send_data(send_offsets.back());
887 std::vector<std::int32_t> counter(send_sizes.size(), 0);
889 std::vector<std::int32_t> unpack_map(send_offsets.back() / 3);
890 for (std::size_t i = 0; i < points.size(); i += 3)
892 for (std::int32_t p : collisions.
links(i / 3))
894 std::int32_t neighbor = rank_to_neighbor[p];
895 std::int32_t pos = send_offsets[neighbor] + counter[neighbor];
896 auto it = std::next(send_data.begin(), pos);
897 std::copy_n(std::next(points.begin(), i), 3, it);
898 unpack_map[pos / 3] = i / 3;
899 counter[neighbor] += 3;
903 MPI_Wait(&sizes_request, MPI_STATUS_IGNORE);
904 std::vector<std::int32_t> recv_offsets(in_ranks.size() + 1, 0);
905 std::partial_sum(recv_sizes.begin(), recv_sizes.end(),
906 std::next(recv_offsets.begin(), 1));
908 std::vector<T> received_points((std::size_t)recv_offsets.back());
909 MPI_Neighbor_alltoallv(
910 send_data.data(), send_sizes.data(), send_offsets.data(),
916 std::span<const T> geom_dofs =
geometry.x();
917 auto x_dofmap =
geometry.dofmaps().front();
922 received_points.size()));
927 std::vector<T> coordinate_dofs(3 * x_dofmap.extent(1));
931 std::vector<std::int32_t> cell_indicator(received_points.size() / 3);
932 std::vector<std::int32_t> closest_cells(received_points.size() / 3);
933 for (std::size_t p = 0; p < received_points.size(); p += 3)
935 std::array<T, 3> point;
936 std::copy_n(std::next(received_points.begin(), p), 3, point.begin());
939 mesh, candidate_collisions.
links(p / 3), point,
940 10 * std::numeric_limits<T>::epsilon(), std::span<T>(coordinate_dofs));
943 cell_indicator[p / 3] = (colliding_cell >= 0) ? rank : -1;
946 closest_cells[p / 3] = colliding_cell;
951 MPI_Comm reverse_comm;
952 MPI_Dist_graph_create_adjacent(
953 comm, out_ranks.size(), out_ranks.data(), MPI_UNWEIGHTED, in_ranks.size(),
954 in_ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &reverse_comm);
959 auto rescale = [](
auto& x)
960 { std::ranges::transform(x, x.begin(), [](
auto e) { return (e / 3); }); };
962 rescale(recv_offsets);
964 rescale(send_offsets);
967 std::swap(recv_sizes, send_sizes);
968 std::swap(recv_offsets, send_offsets);
971 std::vector<std::int32_t> recv_ranks(recv_offsets.back());
972 MPI_Neighbor_alltoallv(cell_indicator.data(), send_sizes.data(),
973 send_offsets.data(), MPI_INT32_T, recv_ranks.data(),
974 recv_sizes.data(), recv_offsets.data(), MPI_INT32_T,
977 std::vector<int> point_owners(points.size() / 3, -1);
978 for (std::size_t i = 0; i < unpack_map.size(); i++)
980 const std::int32_t pos = unpack_map[i];
982 if (recv_ranks[i] >= 0 && point_owners[pos] == -1)
983 point_owners[pos] = recv_ranks[i];
986 if (find_closest_cell)
990 std::vector<std::uint8_t> send_needs_closest_cell(recv_offsets.back());
991 for (std::int32_t i = 0; i < recv_offsets.back(); i++)
993 const std::int32_t pos = unpack_map[i];
994 send_needs_closest_cell[i] = point_owners[pos] == -1;
998 std::swap(send_sizes, recv_sizes);
999 std::swap(send_offsets, recv_offsets);
1000 std::vector<std::uint8_t> dest_needs_closest_cell(recv_offsets.back());
1001 MPI_Neighbor_alltoallv(send_needs_closest_cell.data(), send_sizes.data(),
1002 send_offsets.data(), MPI_UINT8_T,
1003 dest_needs_closest_cell.data(), recv_sizes.data(),
1004 recv_offsets.data(), MPI_UINT8_T, forward_comm);
1006 std::vector<T> squared_distances(received_points.size() / 3, -1);
1008 for (std::size_t i = 0; i < dest_needs_closest_cell.size(); i++)
1010 if (dest_needs_closest_cell[i] == 1)
1012 assert(closest_cells[i] == -1);
1013 std::array<T, 3> point;
1014 std::copy_n(std::next(received_points.begin(), 3 * i), 3,
1018 T shortest_distance = std::numeric_limits<T>::max();
1019 std::int32_t closest_cell = -1;
1020 for (
auto cell : candidate_collisions.
links(i))
1022 auto dofs = md::submdspan(x_dofmap, cell, md::full_extent);
1023 for (std::size_t j = 0; j < dofs.size(); ++j)
1025 const int pos = 3 * dofs[j];
1026 for (std::size_t k = 0; k < 3; ++k)
1027 coordinate_dofs[3 * j + k] = geom_dofs[pos + k];
1030 std::span<const T>(point.data(), point.size()),
1031 std::span<const T>(coordinate_dofs.data(), 3 * dofs.size()));
1032 if (T current_distance = d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
1033 current_distance < shortest_distance)
1035 shortest_distance = current_distance;
1036 closest_cell = cell;
1039 closest_cells[i] = closest_cell;
1040 squared_distances[i] = shortest_distance;
1044 std::swap(recv_sizes, send_sizes);
1045 std::swap(recv_offsets, send_offsets);
1049 std::vector<T> recv_distances(recv_offsets.back());
1050 MPI_Neighbor_alltoallv(
1051 squared_distances.data(), send_sizes.data(), send_offsets.data(),
1056 std::vector<T> closest_distance(point_owners.size(),
1057 std::numeric_limits<T>::max());
1058 for (std::size_t i = 0; i < out_ranks.size(); i++)
1060 for (std::int32_t j = recv_offsets[i]; j < recv_offsets[i + 1]; j++)
1062 const std::int32_t pos = unpack_map[j];
1063 T current_dist = recv_distances[j];
1067 if (T d = closest_distance[pos];
1068 (current_dist >= 0) and (current_dist < d))
1070 point_owners[pos] = out_ranks[i];
1071 closest_distance[pos] = current_dist;
1078 std::swap(send_sizes, recv_sizes);
1079 std::swap(send_offsets, recv_offsets);
1082 std::vector<std::int32_t> send_owners(send_offsets.back());
1083 std::ranges::fill(counter, 0);
1084 for (std::size_t i = 0; i < points.size() / 3; ++i)
1086 for (std::int32_t p : collisions.
links(i))
1088 std::int32_t neighbor = rank_to_neighbor[p];
1089 send_owners[send_offsets[neighbor] + counter[neighbor]++]
1095 std::vector<std::int32_t> dest_ranks(recv_offsets.back());
1096 MPI_Neighbor_alltoallv(send_owners.data(), send_sizes.data(),
1097 send_offsets.data(), MPI_INT32_T, dest_ranks.data(),
1098 recv_sizes.data(), recv_offsets.data(), MPI_INT32_T,
1102 std::vector<int> owned_recv_ranks;
1103 owned_recv_ranks.reserve(recv_offsets.back());
1104 std::vector<T> owned_recv_points;
1105 std::vector<std::int32_t> owned_recv_cells;
1106 for (std::size_t i = 0; i < in_ranks.size(); i++)
1108 for (std::int32_t j = recv_offsets[i]; j < recv_offsets[i + 1]; j++)
1110 if (rank == dest_ranks[j])
1112 owned_recv_ranks.push_back(in_ranks[i]);
1113 owned_recv_points.insert(
1114 owned_recv_points.end(), std::next(received_points.cbegin(), 3 * j),
1115 std::next(received_points.cbegin(), 3 * (j + 1)));
1116 owned_recv_cells.push_back(closest_cells[j]);
1121 MPI_Comm_free(&forward_comm);
1122 MPI_Comm_free(&reverse_comm);
1124 .dest_owners = std::move(owned_recv_ranks),
1125 .dest_points = std::move(owned_recv_points),
1126 .dest_cells = std::move(owned_recv_cells)};
Definition CoordinateElement.h:39
Definition ElementDofLayout.h:31
const std::vector< int > & entity_closure_dofs(int dim, int entity_index) const
Definition ElementDofLayout.cpp:65
Definition BoundingBoxTree.h:215
BoundingBoxTree create_global_tree(MPI_Comm comm) const
Definition BoundingBoxTree.h:350
std::int32_t num_bboxes() const
Return number of bounding boxes.
Definition BoundingBoxTree.h:386
std::array< T, 6 > get_bbox(std::size_t node) const
Return bounding box coordinates for a given node in the tree,.
Definition BoundingBoxTree.h:338
std::array< std::int32_t, 2 > bbox(std::size_t node) const
Definition BoundingBoxTree.h:420
This class provides a static adjacency list data structure.
Definition AdjacencyList.h:41
const std::vector< LinkData > & array() const
Return contiguous array of links for all nodes (const version).
Definition AdjacencyList.h:188
std::span< LinkData > links(std::size_t node)
Get the links (edges) for given node.
Definition AdjacencyList.h:169
std::int32_t num_nodes() const
Get the number of nodes.
Definition AdjacencyList.h:154
Geometry stores the geometry imposed on a mesh.
Definition Geometry.h:39
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:25
MPI_Datatype mpi_t
Retrieves the MPI data type associated to the provided type.
Definition MPI.h:326
std::vector< int > compute_graph_edges_nbx(MPI_Comm comm, std::span< const int > edges, int tag=static_cast< int >(tag::consensus_nbx))
Determine incoming graph edges using the NBX consensus algorithm.
Definition MPI.cpp:294
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:73
Geometry data structures and algorithms.
Definition BoundingBoxTree.h:24
std::vector< T > squared_distance(const mesh::Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities, std::span< const T > points)
Compute the squared distance between a point and a mesh entity.
Definition utils.h:178
std::vector< std::int32_t > compute_collisions(const BoundingBoxTree< T > &tree0, const BoundingBoxTree< T > &tree1)
Compute all collisions between two bounding box trees.
Definition utils.h:546
T compute_squared_distance_bbox(std::span< const T, 6 > b, std::span< const T, 3 > x)
Compute squared distance between point and bounding box.
Definition utils.h:141
graph::AdjacencyList< std::int32_t > compute_colliding_cells(const mesh::Mesh< T > &mesh, const graph::AdjacencyList< std::int32_t > &candidate_cells, std::span< const T > points)
Compute which cells collide with a point.
Definition utils.h:745
std::vector< T > shortest_vector(const mesh::Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities, std::span< const T > points)
Compute the shortest vector from a mesh entity to a point.
Definition utils.h:57
BoundingBoxTree< T > create_midpoint_tree(const mesh::Mesh< T > &mesh, int tdim, std::span< const std::int32_t > entities)
Create a bounding box tree for the midpoints of a subset of entities.
Definition utils.h:519
PointOwnershipData< T > determine_point_ownership(const mesh::Mesh< T > &mesh, std::span< const T > points, T padding, std::optional< std::span< const std::int32_t > > cells, bool find_closest_cell=true)
Determine, for a set of points, the owning process of the cell (if any) that contains each point.
Definition utils.h:817
std::vector< std::int32_t > compute_closest_entity(const BoundingBoxTree< T > &tree, const BoundingBoxTree< T > &midpoint_tree, const mesh::Mesh< T > &mesh, std::span< const T > points)
Compute closest mesh entity to a point.
Definition utils.h:673
std::array< T, 3 > compute_distance_gjk(std::span< const T > p0, std::span< const T > q0)
Compute the distance between two convex bodies p0 and q0, each defined by a set of points.
Definition gjk.h:371
std::int32_t compute_first_colliding_cell(const mesh::Mesh< T > &mesh, std::span< const std::int32_t > cells, std::array< T, 3 > point, T tol, std::span< T > coordinate_dofs)
Given a set of cells, find the first one that collides with a point.
Definition utils.h:625
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
std::vector< T > compute_midpoints(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Compute the midpoints for mesh entities of a given dimension.
Definition utils.h:474
Information on the ownership of points distributed across processes.
Definition utils.h:35
std::vector< T > dest_points
Points that are owned by current process.
Definition utils.h:40
std::vector< std::int32_t > dest_cells
Definition utils.h:42
std::vector< int > dest_owners
Ranks that sent dest_points to current process.
Definition utils.h:39
std::vector< int > src_owner
Definition utils.h:36
std::vector< T > nodes
Definition utils.h:247
const fem::ElementDofLayout & cmap_dof_layout
Coordinate-element dof layout.
Definition utils.h:252