30template <std::
floating_po
int T>
35 std::span<const T> xg =
mesh.geometry().x();
38 std::span<const std::int32_t> entity(&index, 1);
39 const std::vector<std::int32_t> vertex_indices
43 std::span<T, 3> b0(b.data(), 3);
44 std::span<T, 3> b1(b.data() + 3, 3);
46 std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b0.begin());
47 std::copy_n(std::next(xg.begin(), 3 * vertex_indices.front()), 3, b1.begin());
50 for (std::int32_t local_vertex : vertex_indices)
52 for (std::size_t j = 0; j < 3; ++j)
54 b0[j] = std::min(b0[j], xg[3 * local_vertex + j]);
55 b1[j] = std::max(b1[j], xg[3 * local_vertex + j]);
65template <std::
floating_po
int T>
66std::array<T, 6> compute_bbox_of_bboxes(
67 std::span<
const std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes)
70 std::array<T, 6> b = leaf_bboxes.front().first;
71 for (
auto [box, _] : leaf_bboxes)
73 std::transform(box.cbegin(), std::next(box.cbegin(), 3), b.cbegin(),
74 b.begin(), [](
auto a,
auto b) { return std::min(a, b); });
75 std::transform(std::next(box.cbegin(), 3), box.cend(),
76 std::next(b.cbegin(), 3), std::next(b.begin(), 3),
77 [](
auto a,
auto b) { return std::max(a, b); });
83template <std::
floating_po
int T>
84std::int32_t _build_from_leaf(
85 std::span<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes,
86 std::vector<int>& bboxes, std::vector<T>& bbox_coordinates)
88 if (leaf_bboxes.size() == 1)
93 const auto [b, entity_index] = leaf_bboxes.front();
96 bboxes.push_back(entity_index);
97 bboxes.push_back(entity_index);
98 std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
99 return bboxes.size() / 2 - 1;
104 std::array b = compute_bbox_of_bboxes<T>(leaf_bboxes);
107 std::array<T, 3> b_diff;
108 std::transform(std::next(b.cbegin(), 3), b.cend(), b.cbegin(),
109 b_diff.begin(), std::minus<T>());
110 const std::size_t axis = std::distance(
111 b_diff.begin(), std::max_element(b_diff.begin(), b_diff.end()));
113 auto middle = std::next(leaf_bboxes.begin(), leaf_bboxes.size() / 2);
114 std::nth_element(leaf_bboxes.begin(), middle, leaf_bboxes.end(),
115 [axis](
auto& p0,
auto& p1) ->
bool
117 auto x0 = p0.first[axis] + p0.first[3 + axis];
118 auto x1 = p1.first[axis] + p1.first[3 + axis];
123 assert(!leaf_bboxes.empty());
124 std::size_t part = leaf_bboxes.size() / 2;
126 = _build_from_leaf(leaf_bboxes.first(part), bboxes, bbox_coordinates);
127 std::int32_t bbox1 = _build_from_leaf(
128 leaf_bboxes.last(leaf_bboxes.size() - part), bboxes, bbox_coordinates);
131 bboxes.push_back(bbox0);
132 bboxes.push_back(bbox1);
133 std::copy_n(b.begin(), 6, std::back_inserter(bbox_coordinates));
134 return bboxes.size() / 2 - 1;
138template <std::
floating_po
int T>
139std::pair<std::vector<std::int32_t>, std::vector<T>> build_from_leaf(
140 std::vector<std::pair<std::array<T, 6>, std::int32_t>>& leaf_bboxes)
142 std::vector<std::int32_t> bboxes;
143 std::vector<T> bbox_coordinates;
144 impl_bb::_build_from_leaf<T>(leaf_bboxes, bboxes, bbox_coordinates);
145 return {std::move(bboxes), std::move(bbox_coordinates)};
148template <std::
floating_po
int T>
150_build_from_point(std::span<std::pair<std::array<T, 3>, std::int32_t>> points,
151 std::vector<std::int32_t>& bboxes,
152 std::vector<T>& bbox_coordinates)
155 if (points.size() == 1)
160 const std::int32_t c1 = points[0].second;
161 bboxes.push_back(c1);
162 bboxes.push_back(c1);
163 bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
164 points[0].first.end());
165 bbox_coordinates.insert(bbox_coordinates.end(), points[0].first.begin(),
166 points[0].first.end());
167 return bboxes.size() / 2 - 1;
171 auto [min, max] = std::ranges::minmax_element(points);
172 std::array<T, 3> b0 = min->first;
173 std::array<T, 3> b1 = max->first;
176 std::array<T, 3> b_diff;
177 std::ranges::transform(b1, b0, b_diff.begin(), std::minus<T>());
178 const std::size_t axis
179 = std::distance(b_diff.begin(), std::ranges::max_element(b_diff));
181 auto middle = std::next(points.begin(), points.size() / 2);
182 std::nth_element(points.begin(), middle, points.end(),
183 [axis](
auto& p0,
auto&& p1) ->
bool
184 { return p0.first[axis] < p1.first[axis]; });
187 assert(!points.empty());
188 std::size_t part = points.size() / 2;
190 = _build_from_point(points.first(part), bboxes, bbox_coordinates);
191 std::int32_t bbox1 = _build_from_point(points.last(points.size() - part),
192 bboxes, bbox_coordinates);
195 bboxes.push_back(bbox0);
196 bboxes.push_back(bbox1);
197 bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
198 bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
199 return bboxes.size() / 2 - 1;
206template <std::
floating_po
int T>
220 const std::int32_t num_entities = map->size_local() + map->num_ghosts();
221 std::vector<std::int32_t> r(num_entities);
222 std::iota(r.begin(), r.end(), 0);
237 std::optional<std::span<const std::int32_t>> entities
242 mesh.topology_mutable()->create_entities(
tdim);
246 std::span<const std::int32_t> entities_span;
247 std::optional<std::vector<std::int32_t>> local_range(std::nullopt);
249 entities_span = entities.value();
252 local_range.emplace(range(*
mesh.topology_mutable(),
tdim));
253 entities_span = std::span<const std::int32_t>(local_range->data(),
254 local_range->size());
259 throw std::runtime_error(
260 "Dimension must be non-negative and less than or "
261 "equal to the topological dimension of the mesh");
264 mesh.topology_mutable()->create_connectivity(
tdim,
mesh.topology()->dim());
267 std::vector<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes;
268 leaf_bboxes.reserve(entities_span.size());
269 for (std::int32_t e : entities_span)
271 std::array<T, 6> b = impl_bb::compute_bbox_of_entity(
mesh,
tdim, e);
272 std::transform(b.cbegin(), std::next(b.cbegin(), 3), b.begin(),
273 [padding](
auto x) { return x - padding; });
274 std::transform(std::next(b.begin(), 3), b.end(), std::next(b.begin(), 3),
275 [padding](
auto x) { return x + padding; });
276 leaf_bboxes.emplace_back(b, e);
280 if (!leaf_bboxes.empty())
281 std::tie(_bboxes, _bbox_coordinates)
282 = impl_bb::build_from_leaf(leaf_bboxes);
284 spdlog::info(
"Computed bounding box tree with {} nodes for {} entities",
298 impl_bb::_build_from_point(std::span(points), _bboxes, _bbox_coordinates);
301 spdlog::info(
"Computed bounding box tree with {} nodes for {} points.",
328 std::copy_n(_bbox_coordinates.data() + 6 * node, 6, x.begin());
345 constexpr T max_val = std::numeric_limits<T>::max();
346 std::array<T, 6> send_bbox
347 = {max_val, max_val, max_val, max_val, max_val, max_val};
349 std::copy_n(std::prev(_bbox_coordinates.end(), 6), 6, send_bbox.begin());
350 std::vector<T> recv_bbox(mpi_size * 6);
354 std::vector<std::pair<std::array<T, 6>, std::int32_t>> _recv_bbox(mpi_size);
355 for (std::size_t i = 0; i < _recv_bbox.size(); ++i)
357 std::copy_n(std::next(recv_bbox.begin(), 6 * i), 6,
358 _recv_bbox[i].first.begin());
359 _recv_bbox[i].second = i;
362 auto [global_bboxes, global_coords] = impl_bb::build_from_leaf(_recv_bbox);
364 std::move(global_coords));
366 spdlog::info(
"Computed global bounding box tree with {} boxes.",
373 std::int32_t
num_bboxes()
const {
return _bboxes.size() / 2; }
390 int tdim()
const {
return _tdim; }
396 tree_print(s, _bboxes.size() / 2 - 1);
407 std::array<std::int32_t, 2>
bbox(std::size_t node)
const
409 assert(2 * node + 1 < _bboxes.size());
410 return {_bboxes[2 * node], _bboxes[2 * node + 1]};
416 std::vector<T>&& bbox_coords)
417 : _tdim(0), _bboxes(bboxes), _bbox_coordinates(bbox_coords)
426 void tree_print(std::string& s, std::int32_t i)
const
429 for (std::size_t j = 0; j < 2; ++j)
431 for (std::size_t k = 0; k < 3; ++k)
433 std::format_to(std::back_inserter(s),
"{:.6} ",
434 _bbox_coordinates[6 * i + j * 3 + k]);
441 if (_bboxes[2 * i] == _bboxes[2 * i + 1])
443 std::format_to(std::back_inserter(s),
"leaf containing entity ({})",
449 tree_print(s, _bboxes[2 * i]);
451 tree_print(s, _bboxes[2 * i + 1]);
457 std::vector<std::int32_t> _bboxes;
460 std::vector<T> _bbox_coordinates;