53 std::span<const std::int32_t> entities,
54 std::span<const T> points)
56 const int tdim =
mesh.topology()->dim();
59 std::span<const T> geom_dofs =
geometry.x();
60 auto x_dofmap =
geometry.dofmaps().front();
61 std::vector<T> shortest_vectors;
62 shortest_vectors.reserve(3 * entities.size());
65 for (std::size_t e = 0; e < entities.size(); e++)
69 assert(entities[e] >= 0);
70 auto dofs = md::submdspan(x_dofmap, entities[e], md::full_extent);
71 std::vector<T> nodes(3 * dofs.size());
72 for (std::size_t i = 0; i < dofs.size(); ++i)
74 const std::int32_t pos = 3 * dofs[i];
75 for (std::size_t j = 0; j < 3; ++j)
76 nodes[3 * i + j] = geom_dofs[pos + j];
81 shortest_vectors.insert(shortest_vectors.end(), d.begin(), d.end());
86 mesh.topology_mutable()->create_connectivity(dim, tdim);
87 mesh.topology_mutable()->create_connectivity(tdim, dim);
88 auto e_to_c =
mesh.topology()->connectivity(dim, tdim);
90 auto c_to_e =
mesh.topology_mutable()->connectivity(tdim, dim);
92 for (std::size_t e = 0; e < entities.size(); e++)
94 const std::int32_t index = entities[e];
97 assert(e_to_c->num_links(index) > 0);
98 const std::int32_t c = e_to_c->links(index)[0];
101 auto cell_entities = c_to_e->links(c);
102 auto it0 = std::find(cell_entities.begin(), cell_entities.end(), index);
103 assert(it0 != cell_entities.end());
104 const int local_cell_entity
105 = std::ranges::distance(cell_entities.begin(), it0);
108 auto dofs = md::submdspan(x_dofmap, c, md::full_extent);
109 const std::vector<int> entity_dofs
110 =
geometry.cmaps().front().create_dof_layout().entity_closure_dofs(
111 dim, local_cell_entity);
112 std::vector<T> nodes(3 * entity_dofs.size());
113 for (std::size_t i = 0; i < entity_dofs.size(); i++)
115 const std::int32_t pos = 3 * dofs[entity_dofs[i]];
116 for (std::size_t j = 0; j < 3; ++j)
117 nodes[3 * i + j] = geom_dofs[pos + j];
122 shortest_vectors.insert(shortest_vectors.end(), d.begin(), d.end());
126 return shortest_vectors;
686 std::optional<std::span<const std::int32_t>> cells)
688 MPI_Comm comm =
mesh.comm();
690 const int tdim =
mesh.topology()->dim();
692 std::vector<std::int32_t> local_cells;
693 if (not(cells.has_value()))
695 auto cell_map =
mesh.topology()->index_map(tdim);
696 local_cells.resize(cell_map->size_local());
697 std::iota(local_cells.begin(), local_cells.end(), 0);
699 = std::span<const std::int32_t>(local_cells.data(), local_cells.size());
711 std::vector<std::int32_t> out_ranks = collisions.
array();
712 std::ranges::sort(out_ranks);
713 auto [unique_end, range_end] = std::ranges::unique(out_ranks);
714 out_ranks.erase(unique_end, range_end);
718 std::ranges::sort(in_ranks);
721 MPI_Comm forward_comm;
722 MPI_Dist_graph_create_adjacent(
723 comm, in_ranks.size(), in_ranks.data(), MPI_UNWEIGHTED, out_ranks.size(),
724 out_ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &forward_comm);
728 std::map<std::int32_t, std::int32_t> rank_to_neighbor;
729 for (std::size_t i = 0; i < out_ranks.size(); i++)
730 rank_to_neighbor[out_ranks[i]] = i;
733 std::vector<std::int32_t> send_sizes(out_ranks.size());
734 for (std::size_t i = 0; i < points.size() / 3; ++i)
735 for (
auto p : collisions.
links(i))
736 send_sizes[rank_to_neighbor[p]] += 3;
739 std::vector<std::int32_t> recv_sizes(in_ranks.size());
740 send_sizes.reserve(1);
741 recv_sizes.reserve(1);
742 MPI_Request sizes_request;
743 MPI_Ineighbor_alltoall(send_sizes.data(), 1, MPI_INT, recv_sizes.data(), 1,
744 MPI_INT, forward_comm, &sizes_request);
747 std::vector<std::int32_t> send_offsets(send_sizes.size() + 1, 0);
748 std::partial_sum(send_sizes.begin(), send_sizes.end(),
749 std::next(send_offsets.begin(), 1));
752 std::vector<T> send_data(send_offsets.back());
753 std::vector<std::int32_t> counter(send_sizes.size(), 0);
755 std::vector<std::int32_t> unpack_map(send_offsets.back() / 3);
756 for (std::size_t i = 0; i < points.size(); i += 3)
758 for (
auto p : collisions.
links(i / 3))
760 int neighbor = rank_to_neighbor[p];
761 int pos = send_offsets[neighbor] + counter[neighbor];
762 auto it = std::next(send_data.begin(), pos);
763 std::copy_n(std::next(points.begin(), i), 3, it);
764 unpack_map[pos / 3] = i / 3;
765 counter[neighbor] += 3;
769 MPI_Wait(&sizes_request, MPI_STATUS_IGNORE);
770 std::vector<std::int32_t> recv_offsets(in_ranks.size() + 1, 0);
771 std::partial_sum(recv_sizes.begin(), recv_sizes.end(),
772 std::next(recv_offsets.begin(), 1));
774 std::vector<T> received_points((std::size_t)recv_offsets.back());
775 MPI_Neighbor_alltoallv(
776 send_data.data(), send_sizes.data(), send_offsets.data(),
782 std::span<const T> geom_dofs =
geometry.x();
783 auto x_dofmap =
geometry.dofmaps().front();
788 received_points.size()));
792 std::vector<std::int32_t> cell_indicator(received_points.size() / 3);
793 std::vector<std::int32_t> closest_cells(received_points.size() / 3);
794 for (std::size_t p = 0; p < received_points.size(); p += 3)
796 std::array<T, 3> point;
797 std::copy_n(std::next(received_points.begin(), p), 3, point.begin());
800 mesh, candidate_collisions.
links(p / 3), point,
801 10 * std::numeric_limits<T>::epsilon());
804 cell_indicator[p / 3] = (colliding_cell >= 0) ? rank : -1;
807 closest_cells[p / 3] = colliding_cell;
812 MPI_Comm reverse_comm;
813 MPI_Dist_graph_create_adjacent(
814 comm, out_ranks.size(), out_ranks.data(), MPI_UNWEIGHTED, in_ranks.size(),
815 in_ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &reverse_comm);
820 auto rescale = [](
auto& x)
821 { std::ranges::transform(x, x.begin(), [](
auto e) { return (e / 3); }); };
823 rescale(recv_offsets);
825 rescale(send_offsets);
828 std::swap(recv_sizes, send_sizes);
829 std::swap(recv_offsets, send_offsets);
832 std::vector<std::int32_t> recv_ranks(recv_offsets.back());
833 MPI_Neighbor_alltoallv(cell_indicator.data(), send_sizes.data(),
834 send_offsets.data(), MPI_INT32_T, recv_ranks.data(),
835 recv_sizes.data(), recv_offsets.data(), MPI_INT32_T,
838 std::vector<int> point_owners(points.size() / 3, -1);
839 for (std::size_t i = 0; i < unpack_map.size(); i++)
841 const std::int32_t pos = unpack_map[i];
843 if (recv_ranks[i] >= 0 && point_owners[pos] == -1)
844 point_owners[pos] = recv_ranks[i];
849 std::vector<std::uint8_t> send_extrapolate(recv_offsets.back());
850 for (std::int32_t i = 0; i < recv_offsets.back(); i++)
852 const std::int32_t pos = unpack_map[i];
853 send_extrapolate[i] = point_owners[pos] == -1;
858 std::swap(send_sizes, recv_sizes);
859 std::swap(send_offsets, recv_offsets);
860 std::vector<std::uint8_t> dest_extrapolate(recv_offsets.back());
861 MPI_Neighbor_alltoallv(send_extrapolate.data(), send_sizes.data(),
862 send_offsets.data(), MPI_UINT8_T,
863 dest_extrapolate.data(), recv_sizes.data(),
864 recv_offsets.data(), MPI_UINT8_T, forward_comm);
866 std::vector<T> squared_distances(received_points.size() / 3, -1);
868 for (std::size_t i = 0; i < dest_extrapolate.size(); i++)
870 if (dest_extrapolate[i] == 1)
872 assert(closest_cells[i] == -1);
873 std::array<T, 3> point;
874 std::copy_n(std::next(received_points.begin(), 3 * i), 3, point.begin());
877 T shortest_distance = std::numeric_limits<T>::max();
878 std::int32_t closest_cell = -1;
879 for (
auto cell : candidate_collisions.
links(i))
881 auto dofs = md::submdspan(x_dofmap, cell, md::full_extent);
882 std::vector<T> nodes(3 * dofs.size());
883 for (std::size_t j = 0; j < dofs.size(); ++j)
885 const int pos = 3 * dofs[j];
886 for (std::size_t k = 0; k < 3; ++k)
887 nodes[3 * j + k] = geom_dofs[pos + k];
890 std::span<const T>(point.data(), point.size()), nodes);
891 if (T current_distance = d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
892 current_distance < shortest_distance)
894 shortest_distance = current_distance;
898 closest_cells[i] = closest_cell;
899 squared_distances[i] = shortest_distance;
903 std::swap(recv_sizes, send_sizes);
904 std::swap(recv_offsets, send_offsets);
907 std::vector<T> recv_distances(recv_offsets.back());
908 MPI_Neighbor_alltoallv(
909 squared_distances.data(), send_sizes.data(), send_offsets.data(),
914 std::vector<T> closest_distance(point_owners.size(),
915 std::numeric_limits<T>::max());
916 for (std::size_t i = 0; i < out_ranks.size(); i++)
918 for (std::int32_t j = recv_offsets[i]; j < recv_offsets[i + 1]; j++)
920 const std::int32_t pos = unpack_map[j];
921 auto current_dist = recv_distances[j];
923 if (
auto d = closest_distance[pos];
924 (current_dist > 0) and (current_dist < d))
926 point_owners[pos] = out_ranks[i];
927 closest_distance[pos] = current_dist;
933 std::swap(send_sizes, recv_sizes);
934 std::swap(send_offsets, recv_offsets);
937 std::vector<std::int32_t> send_owners(send_offsets.back());
938 std::ranges::fill(counter, 0);
939 for (std::size_t i = 0; i < points.size() / 3; ++i)
941 for (
auto p : collisions.
links(i))
943 int neighbor = rank_to_neighbor[p];
944 send_owners[send_offsets[neighbor] + counter[neighbor]++]
950 std::vector<std::int32_t> dest_ranks(recv_offsets.back());
951 MPI_Neighbor_alltoallv(send_owners.data(), send_sizes.data(),
952 send_offsets.data(), MPI_INT32_T, dest_ranks.data(),
953 recv_sizes.data(), recv_offsets.data(), MPI_INT32_T,
957 std::vector<int> owned_recv_ranks;
958 owned_recv_ranks.reserve(recv_offsets.back());
959 std::vector<T> owned_recv_points;
960 std::vector<std::int32_t> owned_recv_cells;
961 for (std::size_t i = 0; i < in_ranks.size(); i++)
963 for (std::int32_t j = recv_offsets[i]; j < recv_offsets[i + 1]; j++)
965 if (rank == dest_ranks[j])
967 owned_recv_ranks.push_back(in_ranks[i]);
968 owned_recv_points.insert(
969 owned_recv_points.end(), std::next(received_points.cbegin(), 3 * j),
970 std::next(received_points.cbegin(), 3 * (j + 1)));
971 owned_recv_cells.push_back(closest_cells[j]);
976 MPI_Comm_free(&forward_comm);
977 MPI_Comm_free(&reverse_comm);
979 .dest_owners = std::move(owned_recv_ranks),
980 .dest_points = std::move(owned_recv_points),
981 .dest_cells = std::move(owned_recv_cells)};