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,