32template <std::
floating_po
int T>
37 std::span<const T> xg =
mesh.geometry().x();
40 std::span<const std::int32_t> entity(&index, 1);
41 const std::vector<std::int32_t> vertex_indices
45 std::span<T, 3> b0(b.data(), 3);
46 std::span<T, 3> b1(b.data() + 3, 3);
48 std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b0.begin());
49 std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b1.begin());
52 for (std::int32_t local_vertex : vertex_indices)
54 for (std::size_t j = 0; j < 3; ++j)
56 b0[j] = std::min(b0[j], xg[3 * local_vertex + j]);
57 b1[j] = std::max(b1[j], xg[3 * local_vertex + j]);
67template <std::
floating_po
int T>
68std::array<T, 6> compute_bbox_of_bboxes(
69 std::span<
const std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes)
72 std::array<T, 6> b = leaf_bboxes.front().first;
73 for (
auto [box, _] : leaf_bboxes)
75 std::transform(box.cbegin(), std::next(box.cbegin(), 3), b.cbegin(),
76 b.begin(), [](
auto a,
auto b) { return std::min(a, b); });
77 std::transform(std::next(box.cbegin(), 3), box.cend(),
78 std::next(b.cbegin(), 3), std::next(b.begin(), 3),
79 [](
auto a,
auto b) { return std::max(a, b); });
85template <std::
floating_po
int T>
86std::int32_t _build_from_leaf(
87 std::span<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes,
88 std::vector<int>& bboxes, std::vector<T>& bbox_coordinates)
90 if (leaf_bboxes.size() == 1)
95 const auto [b, entity_index] = leaf_bboxes.front();
98 bboxes.push_back(entity_index);
99 bboxes.push_back(entity_index);
100 std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
101 return bboxes.size() / 2 - 1;
106 std::array b = compute_bbox_of_bboxes<T>(leaf_bboxes);
109 std::array<T, 3> b_diff;
110 std::transform(std::next(b.cbegin(), 3), b.cend(), b.cbegin(),
111 b_diff.begin(), std::minus<T>());
112 const std::size_t axis = std::ranges::distance(
113 b_diff.begin(), std::max_element(b_diff.begin(), b_diff.end()));
115 auto middle = std::next(leaf_bboxes.begin(), leaf_bboxes.size() / 2);
116 std::nth_element(leaf_bboxes.begin(), middle, leaf_bboxes.end(),
117 [axis](
auto& p0,
auto& p1) ->
bool
119 auto x0 = p0.first[axis] + p0.first[3 + axis];
120 auto x1 = p1.first[axis] + p1.first[3 + axis];
125 assert(!leaf_bboxes.empty());
126 std::size_t part = leaf_bboxes.size() / 2;
128 = _build_from_leaf(leaf_bboxes.first(part), bboxes, bbox_coordinates);
129 std::int32_t bbox1 = _build_from_leaf(
130 leaf_bboxes.last(leaf_bboxes.size() - part), bboxes, bbox_coordinates);
133 bboxes.push_back(bbox0);
134 bboxes.push_back(bbox1);
135 std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
136 return bboxes.size() / 2 - 1;
140template <std::
floating_po
int T>
141std::pair<std::vector<std::int32_t>, std::vector<T>> build_from_leaf(
142 std::vector<std::pair<std::array<T, 6>, std::int32_t>>& leaf_bboxes)
144 assert(!leaf_bboxes.empty());
145 std::vector<std::int32_t> bboxes;
146 std::vector<T> bbox_coordinates;
149 const std::size_t num_nodes = 2 * leaf_bboxes.size() - 1;
150 bboxes.reserve(2 * num_nodes);
151 bbox_coordinates.reserve(6 * num_nodes);
153 impl_bb::_build_from_leaf<T>(leaf_bboxes, bboxes, bbox_coordinates);
154 return {std::move(bboxes), std::move(bbox_coordinates)};
157template <std::
floating_po
int T>
159_build_from_point(std::span<std::pair<std::array<T, 3>, std::int32_t>> points,
160 std::vector<std::int32_t>& bboxes,
161 std::vector<T>& bbox_coordinates)
164 if (points.size() == 1)
169 const std::int32_t c1 = points[0].second;
170 bboxes.push_back(c1);
171 bboxes.push_back(c1);
172 bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
173 points[0].first.end());
174 bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
175 points[0].first.end());
176 return bboxes.size() / 2 - 1;
180 auto [min, max] = std::ranges::minmax_element(points);
181 std::array<T, 3> b0 = min->first;
182 std::array<T, 3> b1 = max->first;
185 std::array<T, 3> b_diff;
186 std::ranges::transform(b1, b0, b_diff.begin(), std::minus<T>());
187 const std::size_t axis
188 = std::ranges::distance(b_diff.begin(), std::ranges::max_element(b_diff));
190 auto middle = std::next(points.begin(), points.size() / 2);
191 std::nth_element(points.begin(), middle, points.end(),
192 [axis](
auto& p0,
auto&& p1) ->
bool
193 { return p0.first[axis] < p1.first[axis]; });
196 assert(!points.empty());
197 std::size_t part = points.size() / 2;
199 = _build_from_point(points.first(part), bboxes, bbox_coordinates);
200 std::int32_t bbox1 = _build_from_point(points.last(points.size() - part),
201 bboxes, bbox_coordinates);
204 bboxes.push_back(bbox0);
205 bboxes.push_back(bbox1);
206 bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
207 bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
208 return bboxes.size() / 2 - 1;
215template <std::
floating_po
int T>
229 const std::int32_t num_entities = map->size_local() + map->num_ghosts();
230 std::vector<std::int32_t> r(num_entities);
231 std::iota(r.begin(), r.end(), 0);
246 std::optional<std::span<const std::int32_t>> entities
251 mesh.topology_mutable()->create_entities(
tdim);
255 std::span<const std::int32_t> entities_span;
256 std::optional<std::vector<std::int32_t>> local_range(std::nullopt);
258 entities_span = entities.value();
261 local_range.emplace(range(*
mesh.topology_mutable(),
tdim));
262 entities_span = std::span<const std::int32_t>(local_range->data(),
263 local_range->size());
268 throw std::invalid_argument(
269 "Dimension must be non-negative and less than or "
270 "equal to the topological dimension of the mesh");
273 mesh.topology_mutable()->create_connectivity(
tdim,
mesh.topology()->dim());
276 std::vector<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes;
277 leaf_bboxes.reserve(entities_span.size());
278 for (std::int32_t e : entities_span)
280 std::array<T, 6> b = impl_bb::compute_bbox_of_entity(
mesh,
tdim, e);
281 std::transform(b.cbegin(), std::next(b.cbegin(), 3), b.begin(),
282 [padding](
auto x) { return x - padding; });
283 std::transform(std::next(b.begin(), 3), b.end(), std::next(b.begin(), 3),
284 [padding](
auto x) { return x + padding; });
285 leaf_bboxes.emplace_back(b, e);
289 if (!leaf_bboxes.empty())
291 std::tie(_bboxes, _bbox_coordinates)
292 = impl_bb::build_from_leaf(leaf_bboxes);
295 logger().info(
"Computed bounding box tree with {} nodes for {} entities",
311 const std::size_t num_nodes = 2 * points.size() - 1;
312 _bboxes.reserve(2 * num_nodes);
313 _bbox_coordinates.reserve(6 * num_nodes);
315 impl_bb::_build_from_point(std::span(points), _bboxes, _bbox_coordinates);
318 logger().info(
"Computed bounding box tree with {} nodes for {} points.",
345 std::copy_n(_bbox_coordinates.data() + 6 * node, 6, x.begin());
362 constexpr T max_val = std::numeric_limits<T>::max();
363 std::array<T, 6> send_bbox
364 = {max_val, max_val, max_val, max_val, max_val, max_val};
366 std::copy_n(std::prev(_bbox_coordinates.end(), 6), 6, send_bbox.begin());
367 std::vector<T> recv_bbox(mpi_size * 6);
371 std::vector<std::pair<std::array<T, 6>, std::int32_t>> _recv_bbox(mpi_size);
372 for (std::size_t i = 0; i < _recv_bbox.size(); ++i)
374 std::copy_n(std::next(recv_bbox.begin(), 6 * i), 6,
375 _recv_bbox[i].first.begin());
376 _recv_bbox[i].second = i;
379 auto [global_bboxes, global_coords] = impl_bb::build_from_leaf(_recv_bbox);
381 std::move(global_coords));
383 logger().info(
"Computed global bounding box tree with {} boxes.",
390 std::int32_t
num_bboxes()
const {
return _bboxes.size() / 2; }
407 int tdim()
const {
return _tdim; }
413 tree_print(s, _bboxes.size() / 2 - 1);
424 std::array<std::int32_t, 2>
bbox(std::size_t node)
const
426 assert(2 * node + 1 < _bboxes.size());
427 return {_bboxes[2 * node], _bboxes[2 * node + 1]};
433 std::vector<T>&& bbox_coords)
434 : _tdim(0), _bboxes(bboxes), _bbox_coordinates(bbox_coords)
443 void tree_print(std::string& s, std::int32_t i)
const
446 for (std::size_t j = 0; j < 2; ++j)
448 for (std::size_t k = 0; k < 3; ++k)
450 std::format_to(std::back_inserter(s),
"{:.6} ",
451 _bbox_coordinates[6 * i + j * 3 + k]);
458 if (_bboxes[2 * i] == _bboxes[2 * i + 1])
460 std::format_to(std::back_inserter(s),
"leaf containing entity ({})",
466 tree_print(s, _bboxes[2 * i]);
468 tree_print(s, _bboxes[2 * i + 1]);
474 std::vector<std::int32_t> _bboxes;
477 std::vector<T> _bbox_coordinates;