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 minmax = std::minmax_element(points.begin(), points.end());
168 std::array<T, 3> b0 = minmax.first->first;
169 std::array<T, 3> b1 = minmax.second->first;
172 std::array<T, 3> b_diff;
173 std::transform(b1.begin(), b1.end(), b0.begin(), b_diff.begin(),
175 const std::size_t axis = std::distance(
176 b_diff.begin(), std::max_element(b_diff.begin(), b_diff.end()));
178 auto middle = std::next(points.begin(), points.size() / 2);
179 std::nth_element(points.begin(), middle, points.end(),
180 [axis](
auto& p0,
auto&& p1) ->
bool
181 { return p0.first[axis] < p1.first[axis]; });
184 assert(!points.empty());
185 std::size_t part = points.size() / 2;
187 = _build_from_point(points.first(part), bboxes, bbox_coordinates);
188 std::int32_t bbox1 = _build_from_point(points.last(points.size() - part),
189 bboxes, bbox_coordinates);
192 bboxes.push_back(bbox0);
193 bboxes.push_back(bbox1);
194 bbox_coordinates.insert(bbox_coordinates.end(), b0.begin(), b0.end());
195 bbox_coordinates.insert(bbox_coordinates.end(), b1.begin(), b1.end());
196 return bboxes.size() / 2 - 1;
203template <std::
floating_po
int T>
212 const std::int32_t num_entities = map->size_local() + map->num_ghosts();
213 std::vector<std::int32_t> r(num_entities);
214 std::iota(r.begin(), r.end(), 0);
228 std::span<const std::int32_t> entities,
double padding = 0)
231 if (tdim < 0 or tdim > mesh.
topology()->dim())
233 throw std::runtime_error(
234 "Dimension must be non-negative and less than or "
235 "equal to the topological dimension of the mesh");
243 std::vector<std::pair<std::array<T, 6>, std::int32_t>> leaf_bboxes;
244 leaf_bboxes.reserve(entities.size());
245 for (std::int32_t e : entities)
247 std::array<T, 6> b = impl_bb::compute_bbox_of_entity(mesh,
tdim, e);
248 std::transform(b.cbegin(), std::next(b.cbegin(), 3), b.begin(),
249 [padding](
auto x) { return x - padding; });
250 std::transform(std::next(b.begin(), 3), b.end(), std::next(b.begin(), 3),
251 [padding](
auto x) { return x + padding; });
252 leaf_bboxes.emplace_back(b, e);
256 if (!leaf_bboxes.empty())
257 std::tie(_bboxes, _bbox_coordinates)
258 = impl_bb::build_from_leaf(leaf_bboxes);
260 LOG(INFO) <<
"Computed bounding box tree with " <<
num_bboxes()
261 <<
" nodes for " << entities.size() <<
" entities.";
272 mesh,
tdim, range(mesh.topology_mutable(),
tdim), padding)
286 impl_bb::_build_from_point(std::span(points), _bboxes, _bbox_coordinates);
289 LOG(INFO) <<
"Computed bounding box tree with " <<
num_bboxes()
290 <<
" nodes for " << points.size() <<
" points.";
316 std::copy_n(_bbox_coordinates.data() + 6 * node, 6, x.begin());
333 constexpr T max_val = std::numeric_limits<T>::max();
334 std::array<T, 6> send_bbox
335 = {max_val, max_val, max_val, max_val, max_val, max_val};
337 std::copy_n(std::prev(_bbox_coordinates.end(), 6), 6, send_bbox.begin());
338 std::vector<T> recv_bbox(mpi_size * 6);
339 MPI_Allgather(send_bbox.data(), 6, dolfinx::MPI::mpi_type<T>(),
340 recv_bbox.data(), 6, dolfinx::MPI::mpi_type<T>(), comm);
342 std::vector<std::pair<std::array<T, 6>, std::int32_t>> _recv_bbox(mpi_size);
343 for (std::size_t i = 0; i < _recv_bbox.size(); ++i)
345 std::copy_n(std::next(recv_bbox.begin(), 6 * i), 6,
346 _recv_bbox[i].first.begin());
347 _recv_bbox[i].second = i;
350 auto [global_bboxes, global_coords] = impl_bb::build_from_leaf(_recv_bbox);
352 std::move(global_coords));
354 LOG(INFO) <<
"Computed global bounding box tree with "
361 std::int32_t
num_bboxes()
const {
return _bboxes.size() / 2; }
364 int tdim()
const {
return _tdim; }
370 tree_print(s, _bboxes.size() / 2 - 1);
381 std::array<std::int32_t, 2>
bbox(std::size_t node)
const
383 assert(2 * node + 1 < _bboxes.size());
384 return {_bboxes[2 * node], _bboxes[2 * node + 1]};
390 std::vector<T>&& bbox_coords)
391 : _tdim(0), _bboxes(bboxes), _bbox_coordinates(bbox_coords)
400 void tree_print(std::stringstream& s, std::int32_t i)
const
403 for (std::size_t j = 0; j < 2; ++j)
405 for (std::size_t k = 0; k < 3; ++k)
406 s << _bbox_coordinates[6 * i + j * 3 + k] <<
" ";
413 if (_bboxes[2 * i] == _bboxes[2 * i + 1])
414 s <<
"leaf containing entity (" << _bboxes[2 * i + 1] <<
")";
418 tree_print(s, _bboxes[2 * i]);
420 tree_print(s, _bboxes[2 * i + 1]);
426 std::vector<std::int32_t> _bboxes;
429 std::vector<T> _bbox_coordinates;