37 std::span<const std::int32_t> entities,
38 std::span<const T> points)
40 const int tdim = mesh.
topology()->dim();
42 if (geometry.
cmaps().size() > 1)
43 throw std::runtime_error(
"Mixed topology not supported");
45 std::span<const T> geom_dofs = geometry.
x();
46 auto x_dofmap = geometry.
dofmap();
47 std::vector<T> shortest_vectors;
48 shortest_vectors.reserve(3 * entities.size());
51 for (std::size_t e = 0; e < entities.size(); e++)
55 assert(entities[e] >= 0);
57 = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
58 submdspan(x_dofmap, entities[e],
59 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
60 std::vector<T> nodes(3 * dofs.size());
61 for (std::size_t i = 0; i < dofs.size(); ++i)
63 const std::int32_t pos = 3 * dofs[i];
64 for (std::size_t j = 0; j < 3; ++j)
65 nodes[3 * i + j] = geom_dofs[pos + j];
69 = compute_distance_gjk<T>(points.subspan(3 * e, 3), nodes);
70 shortest_vectors.insert(shortest_vectors.end(), d.begin(), d.end());
77 auto e_to_c = mesh.
topology()->connectivity(dim, tdim);
81 for (std::size_t e = 0; e < entities.size(); e++)
83 const std::int32_t index = entities[e];
86 assert(e_to_c->num_links(index) > 0);
87 const std::int32_t c = e_to_c->links(index)[0];
90 auto cell_entities = c_to_e->links(c);
91 auto it0 = std::find(cell_entities.begin(), cell_entities.end(), index);
92 assert(it0 != cell_entities.end());
93 const int local_cell_entity = std::distance(cell_entities.begin(), it0);
96 auto dofs = MDSPAN_IMPL_STANDARD_NAMESPACE::
97 MDSPAN_IMPL_PROPOSED_NAMESPACE::submdspan(
98 x_dofmap, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
99 const std::vector<int> entity_dofs
100 = geometry.
cmaps()[0].create_dof_layout().entity_closure_dofs(
101 dim, local_cell_entity);
102 std::vector<T> nodes(3 * entity_dofs.size());
103 for (std::size_t i = 0; i < entity_dofs.size(); i++)
105 const std::int32_t pos = 3 * dofs[entity_dofs[i]];
106 for (std::size_t j = 0; j < 3; ++j)
107 nodes[3 * i + j] = geom_dofs[pos + j];
111 = compute_distance_gjk<T>(points.subspan(3 * e, 3), nodes);
112 shortest_vectors.insert(shortest_vectors.end(), d.begin(), d.end());
116 return shortest_vectors;
685 MPI_Comm comm = mesh.
comm();
689 const int tdim = mesh.
topology()->dim();
690 auto cell_map = mesh.
topology()->index_map(tdim);
691 const std::int32_t num_cells = cell_map->size_local();
693 std::vector<std::int32_t> cells(num_cells, 0);
694 std::iota(cells.begin(), cells.end(), 0);
703 std::vector<std::int32_t> out_ranks = collisions.
array();
704 std::sort(out_ranks.begin(), out_ranks.end());
705 out_ranks.erase(std::unique(out_ranks.begin(), out_ranks.end()),
709 std::sort(in_ranks.begin(), in_ranks.end());
712 MPI_Comm forward_comm;
713 MPI_Dist_graph_create_adjacent(
714 comm, in_ranks.size(), in_ranks.data(), MPI_UNWEIGHTED, out_ranks.size(),
715 out_ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &forward_comm);
719 std::map<std::int32_t, std::int32_t> rank_to_neighbor;
720 for (std::size_t i = 0; i < out_ranks.size(); i++)
721 rank_to_neighbor[out_ranks[i]] = i;
724 std::vector<std::int32_t> send_sizes(out_ranks.size());
725 for (std::size_t i = 0; i < points.size() / 3; ++i)
726 for (
auto p : collisions.
links(i))
727 send_sizes[rank_to_neighbor[p]] += 3;
730 std::vector<std::int32_t> recv_sizes(in_ranks.size());
731 send_sizes.reserve(1);
732 recv_sizes.reserve(1);
733 MPI_Request sizes_request;
734 MPI_Ineighbor_alltoall(send_sizes.data(), 1, MPI_INT, recv_sizes.data(), 1,
735 MPI_INT, forward_comm, &sizes_request);
738 std::vector<std::int32_t> send_offsets(send_sizes.size() + 1, 0);
739 std::partial_sum(send_sizes.begin(), send_sizes.end(),
740 std::next(send_offsets.begin(), 1));
743 std::vector<T> send_data(send_offsets.back());
744 std::vector<std::int32_t> counter(send_sizes.size(), 0);
746 std::vector<std::int32_t> unpack_map(send_offsets.back() / 3);
747 for (std::size_t i = 0; i < points.size(); i += 3)
749 for (
auto p : collisions.
links(i / 3))
751 int neighbor = rank_to_neighbor[p];
752 int pos = send_offsets[neighbor] + counter[neighbor];
753 auto it = std::next(send_data.begin(), pos);
754 std::copy_n(std::next(points.begin(), i), 3, it);
755 unpack_map[pos / 3] = i / 3;
756 counter[neighbor] += 3;
760 MPI_Wait(&sizes_request, MPI_STATUS_IGNORE);
761 std::vector<std::int32_t> recv_offsets(in_ranks.size() + 1, 0);
762 std::partial_sum(recv_sizes.begin(), recv_sizes.end(),
763 std::next(recv_offsets.begin(), 1));
765 std::vector<T> received_points((std::size_t)recv_offsets.back());
766 MPI_Neighbor_alltoallv(
767 send_data.data(), send_sizes.data(), send_offsets.data(),
768 dolfinx::MPI::mpi_type<T>(), received_points.data(), recv_sizes.data(),
769 recv_offsets.data(), dolfinx::MPI::mpi_type<T>(), forward_comm);
773 if (geometry.
cmaps().size() > 1)
774 throw std::runtime_error(
"Mixed topology not supported");
775 std::span<const T> geom_dofs = geometry.
x();
776 auto x_dofmap = geometry.
dofmap();
781 received_points.size()));
785 std::vector<std::int32_t> cell_indicator(received_points.size() / 3);
786 std::vector<std::int32_t> closest_cells(received_points.size() / 3);
787 for (std::size_t p = 0; p < received_points.size(); p += 3)
789 std::array<T, 3> point;
790 std::copy_n(std::next(received_points.begin(), p), 3, point.begin());
793 mesh, candidate_collisions.
links(p / 3), point,
794 10 * std::numeric_limits<T>::epsilon());
797 cell_indicator[p / 3] = (colliding_cell >= 0) ? rank : -1;
800 closest_cells[p / 3] = colliding_cell;
805 MPI_Comm reverse_comm;
806 MPI_Dist_graph_create_adjacent(
807 comm, out_ranks.size(), out_ranks.data(), MPI_UNWEIGHTED, in_ranks.size(),
808 in_ranks.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &reverse_comm);
813 auto rescale = [](
auto& x)
815 std::transform(x.cbegin(), x.cend(), x.begin(),
816 [](
auto e) { return (e / 3); });
819 rescale(recv_offsets);
821 rescale(send_offsets);
824 std::swap(recv_sizes, send_sizes);
825 std::swap(recv_offsets, send_offsets);
828 std::vector<std::int32_t> recv_ranks(recv_offsets.back());
829 MPI_Neighbor_alltoallv(cell_indicator.data(), send_sizes.data(),
830 send_offsets.data(), MPI_INT32_T, recv_ranks.data(),
831 recv_sizes.data(), recv_offsets.data(), MPI_INT32_T,
834 std::vector<std::int32_t> point_owners(points.size() / 3, -1);
835 for (std::size_t i = 0; i < unpack_map.size(); i++)
837 const std::int32_t pos = unpack_map[i];
839 if (recv_ranks[i] >= 0 && point_owners[pos] == -1)
840 point_owners[pos] = recv_ranks[i];
845 std::vector<std::uint8_t> send_extrapolate(recv_offsets.back());
846 for (std::int32_t i = 0; i < recv_offsets.back(); i++)
848 const std::int32_t pos = unpack_map[i];
849 send_extrapolate[i] = point_owners[pos] == -1;
854 std::swap(send_sizes, recv_sizes);
855 std::swap(send_offsets, recv_offsets);
856 std::vector<std::uint8_t> dest_extrapolate(recv_offsets.back());
857 MPI_Neighbor_alltoallv(send_extrapolate.data(), send_sizes.data(),
858 send_offsets.data(), MPI_UINT8_T,
859 dest_extrapolate.data(), recv_sizes.data(),
860 recv_offsets.data(), MPI_UINT8_T, forward_comm);
862 std::vector<T> squared_distances(received_points.size() / 3, -1);
864 for (std::size_t i = 0; i < dest_extrapolate.size(); i++)
866 if (dest_extrapolate[i] == 1)
868 assert(closest_cells[i] == -1);
869 std::array<T, 3> point;
870 std::copy_n(std::next(received_points.begin(), 3 * i), 3, point.begin());
873 T shortest_distance = std::numeric_limits<T>::max();
874 std::int32_t closest_cell = -1;
875 for (
auto cell : candidate_collisions.
links(i))
877 auto dofs = MDSPAN_IMPL_STANDARD_NAMESPACE::
878 MDSPAN_IMPL_PROPOSED_NAMESPACE::submdspan(
879 x_dofmap, cell, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
880 std::vector<T> nodes(3 * dofs.size());
881 for (std::size_t j = 0; j < dofs.size(); ++j)
883 const int pos = 3 * dofs[j];
884 for (std::size_t k = 0; k < 3; ++k)
885 nodes[3 * j + k] = geom_dofs[pos + k];
887 const std::array<T, 3> d = compute_distance_gjk<T>(
888 std::span<const T>(point.data(), point.size()), nodes);
889 if (T current_distance = d[0] * d[0] + d[1] * d[1] + d[2] * d[2];
890 current_distance < shortest_distance)
892 shortest_distance = current_distance;
896 closest_cells[i] = closest_cell;
897 squared_distances[i] = shortest_distance;
901 std::swap(recv_sizes, send_sizes);
902 std::swap(recv_offsets, send_offsets);
905 std::vector<T> recv_distances(recv_offsets.back());
906 MPI_Neighbor_alltoallv(
907 squared_distances.data(), send_sizes.data(), send_offsets.data(),
908 dolfinx::MPI::mpi_type<T>(), recv_distances.data(), recv_sizes.data(),
909 recv_offsets.data(), dolfinx::MPI::mpi_type<T>(), reverse_comm);
912 std::vector<T> closest_distance(unpack_map.size(),
913 std::numeric_limits<T>::max());
914 for (std::size_t i = 0; i < out_ranks.size(); i++)
916 for (std::int32_t j = recv_offsets[i]; j < recv_offsets[i + 1]; j++)
918 const std::int32_t pos = unpack_map[j];
919 auto current_dist = recv_distances[j];
921 if (
auto d = closest_distance[pos];
922 (current_dist > 0) and (current_dist < d))
924 point_owners[pos] = out_ranks[i];
925 closest_distance[pos] = current_dist;
931 std::swap(send_sizes, recv_sizes);
932 std::swap(send_offsets, recv_offsets);
935 std::vector<std::int32_t> send_owners(send_offsets.back());
936 std::fill(counter.begin(), counter.end(), 0);
937 for (std::size_t i = 0; i < points.size() / 3; ++i)
939 for (
auto p : collisions.
links(i))
941 int neighbor = rank_to_neighbor[p];
942 send_owners[send_offsets[neighbor] + counter[neighbor]++]
948 std::vector<std::int32_t> dest_ranks(recv_offsets.back());
949 MPI_Neighbor_alltoallv(send_owners.data(), send_sizes.data(),
950 send_offsets.data(), MPI_INT32_T, dest_ranks.data(),
951 recv_sizes.data(), recv_offsets.data(), MPI_INT32_T,
955 std::vector<std::int32_t> owned_recv_ranks;
956 owned_recv_ranks.reserve(recv_offsets.back());
957 std::vector<T> owned_recv_points;
958 std::vector<std::int32_t> owned_recv_cells;
959 for (std::size_t i = 0; i < in_ranks.size(); i++)
961 for (std::int32_t j = recv_offsets[i]; j < recv_offsets[i + 1]; j++)
963 if (rank == dest_ranks[j])
965 owned_recv_ranks.push_back(in_ranks[i]);
966 owned_recv_points.insert(
967 owned_recv_points.end(), std::next(received_points.cbegin(), 3 * j),
968 std::next(received_points.cbegin(), 3 * (j + 1)));
969 owned_recv_cells.push_back(closest_cells[j]);
974 MPI_Comm_free(&forward_comm);
975 MPI_Comm_free(&reverse_comm);
977 return std::make_tuple(point_owners, owned_recv_ranks, owned_recv_points,