27template <std::
floating_po
int T>
 
   28std::array<T, 6> compute_bbox_of_entity(
const mesh::Mesh<T>& mesh, 
int dim,
 
   32  std::span<const T> xg = mesh.geometry().x();
 
   35  std::span<const std::int32_t> entity(&index, 1);
 
   36  const std::vector<std::int32_t> vertex_indices
 
   40  auto b0 = std::span(b).template subspan<0, 3>();
 
   41  auto b1 = std::span(b).template subspan<3, 3>();
 
   42  std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b0.begin());
 
   43  std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b1.begin());
 
   46  for (std::int32_t local_vertex : vertex_indices)
 
   48    for (std::size_t j = 0; j < 3; ++j)
 
   50      b0[j] = std::min(b0[j], xg[3 * local_vertex + j]);
 
   51      b1[j] = std::max(b1[j], xg[3 * local_vertex + j]);
 
   61template <std::
floating_po
int T>
 
   62std::array<T, 6> compute_bbox_of_bboxes(
 
   63    std::span<
const std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes)
 
   66  std::array<T, 6> b = leaf_bboxes.front().first;
 
   67  for (
auto [box, _] : leaf_bboxes)
 
   69    std::transform(box.cbegin(), std::next(box.cbegin(), 3), b.cbegin(),
 
   70                   b.begin(), [](
auto a, 
auto b) { return std::min(a, b); });
 
   71    std::transform(std::next(box.cbegin(), 3), box.cend(),
 
   72                   std::next(b.cbegin(), 3), std::next(b.begin(), 3),
 
   73                   [](
auto a, 
auto b) { return std::max(a, b); });
 
   79template <std::
floating_po
int T>
 
   80std::int32_t _build_from_leaf(
 
   81    std::span<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes,
 
   82    std::vector<int>& bboxes, std::vector<T>& bbox_coordinates)
 
   84  if (leaf_bboxes.size() == 1)
 
   89    const auto [b, entity_index] = leaf_bboxes.front();
 
   92    bboxes.push_back(entity_index);
 
   93    bboxes.push_back(entity_index);
 
   94    std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
 
   95    return bboxes.size() / 2 - 1;
 
  100    std::array b = compute_bbox_of_bboxes<T>(leaf_bboxes);
 
  103    std::array<T, 3> b_diff;
 
  104    std::transform(std::next(b.cbegin(), 3), b.cend(), b.cbegin(),
 
  105                   b_diff.begin(), std::minus<T>());
 
  106    const std::size_t axis = std::distance(
 
  107        b_diff.begin(), std::max_element(b_diff.begin(), b_diff.end()));
 
  109    auto middle = std::next(leaf_bboxes.begin(), leaf_bboxes.size() / 2);
 
  110    std::nth_element(leaf_bboxes.begin(), middle, leaf_bboxes.end(),
 
  111                     [axis](
auto& p0, 
auto& p1) -> 
bool 
  113                       auto x0 = p0.first[axis] + p0.first[3 + axis];
 
  114                       auto x1 = p1.first[axis] + p1.first[3 + axis];
 
  119    assert(!leaf_bboxes.empty());
 
  120    std::size_t part = leaf_bboxes.size() / 2;
 
  122        = _build_from_leaf(leaf_bboxes.first(part), bboxes, bbox_coordinates);
 
  123    std::int32_t bbox1 = _build_from_leaf(
 
  124        leaf_bboxes.last(leaf_bboxes.size() - part), bboxes, bbox_coordinates);
 
  127    bboxes.push_back(bbox0);
 
  128    bboxes.push_back(bbox1);
 
  129    std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
 
  130    return bboxes.size() / 2 - 1;
 
  134template <std::
floating_po
int T>
 
  135std::pair<std::vector<std::int32_t>, std::vector<T>> build_from_leaf(
 
  136    std::vector<std::pair<std::array<T, 6>, std::int32_t>>& leaf_bboxes)
 
  138  std::vector<std::int32_t> bboxes;
 
  139  std::vector<T> bbox_coordinates;
 
  140  impl_bb::_build_from_leaf<T>(leaf_bboxes, bboxes, bbox_coordinates);
 
  141  return {std::move(bboxes), std::move(bbox_coordinates)};
 
  144template <std::
floating_po
int T>
 
  146_build_from_point(std::span<std::pair<std::array<T, 3>, std::int32_t>> points,
 
  147                  std::vector<std::int32_t>& bboxes,
 
  148                  std::vector<T>& bbox_coordinates)
 
  151  if (points.size() == 1)
 
  156    const std::int32_t c1 = points[0].second;
 
  157    bboxes.push_back(c1);
 
  158    bboxes.push_back(c1);
 
  159    bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
 
  160                            points[0].first.end());
 
  161    bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
 
  162                            points[0].first.end());
 
  163    return bboxes.size() / 2 - 1;
 
  167  auto [min, max] = std::ranges::minmax_element(points);
 
  168  std::array<T, 3> b0 = min->first;
 
  169  std::array<T, 3> b1 = max->first;
 
  172  std::array<T, 3> b_diff;
 
  173  std::ranges::transform(b1, b0, b_diff.begin(), std::minus<T>());
 
  174  const std::size_t axis
 
  175      = std::distance(b_diff.begin(), std::ranges::max_element(b_diff));
 
  177  auto middle = std::next(points.begin(), points.size() / 2);
 
  178  std::nth_element(points.begin(), middle, points.end(),
 
  179                   [axis](
auto& p0, 
auto&& p1) -> 
bool 
  180                   { return p0.first[axis] < p1.first[axis]; });
 
  183  assert(!points.empty());
 
  184  std::size_t part = points.size() / 2;
 
  186      = _build_from_point(points.first(part), bboxes, bbox_coordinates);
 
  187  std::int32_t bbox1 = _build_from_point(points.last(points.size() - part),
 
  188                                         bboxes, bbox_coordinates);
 
  191  bboxes.push_back(bbox0);
 
  192  bboxes.push_back(bbox1);
 
  193  bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
 
  194  bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
 
  195  return bboxes.size() / 2 - 1;
 
  202template <std::
floating_po
int T>
 
  211    const std::int32_t num_entities = map->size_local() + map->num_ghosts();
 
  212    std::vector<std::int32_t> r(num_entities);
 
  213    std::iota(r.begin(), r.end(), 0);
 
  227                  std::span<const std::int32_t> entities, 
double padding = 0)
 
  232      throw std::runtime_error(
 
  233          "Dimension must be non-negative and less than or " 
  234          "equal to the topological dimension of the mesh");
 
  238    mesh.topology_mutable()->create_entities(
tdim);
 
  239    mesh.topology_mutable()->create_connectivity(
tdim, mesh.topology()->dim());
 
  242    std::vector<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes;
 
  243    leaf_bboxes.reserve(entities.size());
 
  244    for (std::int32_t e : entities)
 
  246      std::array<T, 6> b = impl_bb::compute_bbox_of_entity(mesh, 
tdim, e);
 
  247      std::transform(b.cbegin(), std::next(b.cbegin(), 3), b.begin(),
 
  248                     [padding](
auto x) { return x - padding; });
 
  249      std::transform(std::next(b.begin(), 3), b.end(), std::next(b.begin(), 3),
 
  250                     [padding](
auto x) { return x + padding; });
 
  251      leaf_bboxes.emplace_back(b, e);
 
  255    if (!leaf_bboxes.empty())
 
  256      std::tie(_bboxes, _bbox_coordinates)
 
  257          = impl_bb::build_from_leaf(leaf_bboxes);
 
  259    spdlog::info(
"Computed bounding box tree with {} nodes for {} entities",
 
 
  271            mesh, 
tdim, range(mesh.topology_mutable(), 
tdim), padding)
 
 
  285      impl_bb::_build_from_point(std::span(points), _bboxes, _bbox_coordinates);
 
  288    spdlog::info(
"Computed bounding box tree with {} nodes for {} points.",
 
 
  315    std::copy_n(_bbox_coordinates.data() + 6 * node, 6, x.begin());
 
 
  332    constexpr T max_val = std::numeric_limits<T>::max();
 
  333    std::array<T, 6> send_bbox
 
  334        = {max_val, max_val, max_val, max_val, max_val, max_val};
 
  336      std::copy_n(std::prev(_bbox_coordinates.end(), 6), 6, send_bbox.begin());
 
  337    std::vector<T> recv_bbox(mpi_size * 6);
 
  341    std::vector<std::pair<std::array<T, 6>, std::int32_t>> _recv_bbox(mpi_size);
 
  342    for (std::size_t i = 0; i < _recv_bbox.size(); ++i)
 
  344      std::copy_n(std::next(recv_bbox.begin(), 6 * i), 6,
 
  345                  _recv_bbox[i].first.begin());
 
  346      _recv_bbox[i].second = i;
 
  349    auto [global_bboxes, global_coords] = impl_bb::build_from_leaf(_recv_bbox);
 
  351                                std::move(global_coords));
 
  353    spdlog::info(
"Computed global bounding box tree with {} boxes.",
 
 
  360  std::int32_t 
num_bboxes()
 const { 
return _bboxes.size() / 2; }
 
  363  int tdim()
 const { 
return _tdim; }
 
  369    tree_print(s, _bboxes.size() / 2 - 1);
 
 
  380  std::array<std::int32_t, 2> 
bbox(std::size_t node)
 const 
  382    assert(2 * node + 1 < _bboxes.size());
 
  383    return {_bboxes[2 * node], _bboxes[2 * node + 1]};
 
 
  389                  std::vector<T>&& bbox_coords)
 
  390      : _tdim(0), _bboxes(bboxes), _bbox_coordinates(bbox_coords)
 
  399  void tree_print(std::stringstream& s, std::int32_t i)
 const 
  402    for (std::size_t j = 0; j < 2; ++j)
 
  404      for (std::size_t k = 0; k < 3; ++k)
 
  405        s << _bbox_coordinates[6 * i + j * 3 + k] << 
" ";
 
  412    if (_bboxes[2 * i] == _bboxes[2 * i + 1])
 
  413      s << 
"leaf containing entity (" << _bboxes[2 * i + 1] << 
")";
 
  417      tree_print(s, _bboxes[2 * i]);
 
  419      tree_print(s, _bboxes[2 * i + 1]);
 
  425  std::vector<std::int32_t> _bboxes;
 
  428  std::vector<T> _bbox_coordinates;