3.6-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
boundingboxtree.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*****************************************************************************
4 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
31#ifndef DUMUX_GEOMETRY_BOUNDINGBOXTREE_HH
32#define DUMUX_GEOMETRY_BOUNDINGBOXTREE_HH
33
34#include <vector>
35#include <array>
36#include <algorithm>
37#include <memory>
38#include <numeric>
39#include <type_traits>
40#include <iostream>
41
42#include <dune/common/promotiontraits.hh>
43#include <dune/common/timer.hh>
44#include <dune/common/fvector.hh>
45
46namespace Dumux {
47
66template <class GeometricEntitySet>
68{
69 enum { dimworld = GeometricEntitySet::dimensionworld };
70 using ctype = typename GeometricEntitySet::ctype;
71
77 struct BoundingBoxNode
78 {
79 std::size_t child0;
80 std::size_t child1;
81 };
82
83public:
85 using EntitySet = GeometricEntitySet;
86
88 BoundingBoxTree() = default;
89
91 BoundingBoxTree(std::shared_ptr<const GeometricEntitySet> set)
92 { build(set); }
93
95 void build(std::shared_ptr<const GeometricEntitySet> set)
96 {
97 // set the pointer to the entity set
98 entitySet_ = set;
99
100 // clear all internal data
101 boundingBoxNodes_.clear();
102 boundingBoxCoordinates_.clear();
103
104 // start the timer
105 Dune::Timer timer;
106
107 // Create bounding boxes for all elements
108 const auto numLeaves = set->size();
109
110 // reserve enough space for the nodes and the coordinates
111 const auto numNodes = 2*numLeaves - 1;
112 boundingBoxNodes_.reserve(numNodes);
113 boundingBoxCoordinates_.reserve(numNodes*2*dimworld);
114
115 // create a vector for leaf boxes (min and max for all dims)
116 std::vector<ctype> leafBoxes(2*dimworld*numLeaves);
117
118 for (const auto& geometricEntity : *set)
119 computeEntityBoundingBox_(leafBoxes.data() + 2*dimworld*set->index(geometricEntity), geometricEntity);
120
121 // create the leaf partition, the set of available indices (to be sorted)
122 std::vector<std::size_t> leafPartition(numLeaves);
123 std::iota(leafPartition.begin(), leafPartition.end(), 0);
124
125 // Recursively build the bounding box tree
126 build_(leafBoxes, leafPartition.begin(), leafPartition.end());
127
128 // We are done, log output
129 std::cout << "Computed bounding box tree with " << numBoundingBoxes()
130 << " nodes for " << numLeaves << " grid entities in "
131 << timer.stop() << " seconds." << std::endl;
132 }
133
135 const EntitySet& entitySet() const
136 { return *entitySet_; }
137
141
143 const BoundingBoxNode& getBoundingBoxNode(std::size_t nodeIdx) const
144 { return boundingBoxNodes_[nodeIdx]; }
145
147 const ctype* getBoundingBoxCoordinates(std::size_t nodeIdx) const
148 { return boundingBoxCoordinates_.data() + 2*dimworld*nodeIdx; }
149
151 std::size_t numBoundingBoxes() const
152 { return boundingBoxNodes_.size(); }
153
156 bool isLeaf(const BoundingBoxNode& node, std::size_t nodeIdx) const
157 { return node.child0 == nodeIdx; }
158
159private:
160
162 std::vector<BoundingBoxNode> boundingBoxNodes_;
163
165 std::vector<ctype> boundingBoxCoordinates_;
166
168 std::shared_ptr<const EntitySet> entitySet_;
169
171 template <class Entity>
172 void computeEntityBoundingBox_(ctype* b, const Entity& entity) const
173 {
174 // get the bounding box coordinates
175 ctype* xMin = b;
176 ctype* xMax = b + dimworld;
177
178 // get mesh entity data
179 auto geometry = entity.geometry();
180
181 // Get coordinates of first vertex
182 auto corner = geometry.corner(0);
183 for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
184 xMin[dimIdx] = xMax[dimIdx] = corner[dimIdx];
185
186 // Compute the min and max over the remaining vertices
187 for (std::size_t cornerIdx = 1; cornerIdx < geometry.corners(); ++cornerIdx)
188 {
189 corner = geometry.corner(cornerIdx);
190 for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
191 {
192 using std::max;
193 using std::min;
194 xMin[dimIdx] = min(xMin[dimIdx], corner[dimIdx]);
195 xMax[dimIdx] = max(xMax[dimIdx], corner[dimIdx]);
196 }
197 }
198 }
199
201 std::size_t build_(const std::vector<ctype>& leafBoxes,
202 const std::vector<std::size_t>::iterator& begin,
203 const std::vector<std::size_t>::iterator& end)
204 {
205 assert(begin < end);
206
207 // If we reached the end of the recursion, i.e. only a leaf box is left
208 if (end - begin == 1)
209 {
210 // Get the bounding box coordinates for the leaf
211 const std::size_t leafNodeIdx = *begin;
212 const auto beginCoords = leafBoxes.begin() + 2*dimworld*leafNodeIdx;
213 const auto endCoords = beginCoords + 2*dimworld;
214
215 // Store the data in the bounding box
216 // leaf nodes are indicated by setting child0 to
217 // the node itself and child1 to the index of the entity in the bounding box.
218 return addBoundingBox_(BoundingBoxNode{numBoundingBoxes(), leafNodeIdx}, beginCoords, endCoords);
219 }
220
221 // Compute the bounding box of all bounding boxes in the range [begin, end]
222 const auto bCoords = computeBBoxOfBBoxes_(leafBoxes, begin, end);
223
224 // sort bounding boxes along the longest axis
225 const auto axis = computeLongestAxis_(bCoords);
226
227 // nth_element sorts the range to make sure that middle points to the coordinate median in axis direction
228 // this is the most expensive part of the algorithm
229 auto middle = begin + (end - begin)/2;
230 std::nth_element(begin, middle, end, [&leafBoxes, axis](std::size_t i, std::size_t j)
231 {
232 const ctype* bi = leafBoxes.data() + 2*dimworld*i;
233 const ctype* bj = leafBoxes.data() + 2*dimworld*j;
234 return bi[axis] + bi[axis + dimworld] < bj[axis] + bj[axis + dimworld];
235 });
236
237 // split the bounding boxes into two at the middle iterator and call build recursively, each
238 // call resulting in a new node of this bounding box, i.e. the root will be added at the end of the process.
239 return addBoundingBox_(BoundingBoxNode{build_(leafBoxes, begin, middle), build_(leafBoxes, middle, end)},
240 bCoords.begin(), bCoords.end());
241 }
242
244 template <class Iterator>
245 std::size_t addBoundingBox_(BoundingBoxNode&& node,
246 const Iterator& coordBegin,
247 const Iterator& coordEnd)
248 {
249 // Add the bounding box
250 boundingBoxNodes_.emplace_back(node);
251
252 // Add the bounding box's coordinates
253 boundingBoxCoordinates_.insert(boundingBoxCoordinates_.end(), coordBegin, coordEnd);
254
255 // return the index of the new node
256 return boundingBoxNodes_.size() - 1;
257 }
258
260 std::array<ctype, 2*dimworld>
261 computeBBoxOfBBoxes_(const std::vector<ctype>& leafBoxes,
262 const std::vector<std::size_t>::iterator& begin,
263 const std::vector<std::size_t>::iterator& end)
264 {
265 std::array<ctype, 2*dimworld> bBoxCoords;
266
267 // copy the iterator and get coordinates of first box
268 auto it = begin;
269 const auto* bFirst = leafBoxes.data() + 2*dimworld*(*it);
270
271 for (int coordIdx = 0; coordIdx < 2*dimworld; ++coordIdx)
272 bBoxCoords[coordIdx] = bFirst[coordIdx];
273
274 // Compute min and max with the remaining boxes
275 for (; it != end; ++it)
276 {
277 const auto* b = leafBoxes.data() + 2*dimworld*(*it);
278 for (int coordIdx = 0; coordIdx < dimworld; ++coordIdx)
279 if (b[coordIdx] < bBoxCoords[coordIdx])
280 bBoxCoords[coordIdx] = b[coordIdx];
281 for (int coordIdx = dimworld; coordIdx < 2*dimworld; ++coordIdx)
282 if (b[coordIdx] > bBoxCoords[coordIdx])
283 bBoxCoords[coordIdx] = b[coordIdx];
284 }
285
286 return bBoxCoords;
287 }
288
290 std::size_t computeLongestAxis_(const std::array<ctype, 2*dimworld>& bCoords)
291 {
292 std::array<ctype, dimworld> axisLength;
293 for (int coordIdx = 0; coordIdx < dimworld; ++coordIdx)
294 axisLength[coordIdx] = bCoords[dimworld + coordIdx] - bCoords[coordIdx];
295
296 return std::distance(axisLength.begin(), std::max_element(axisLength.begin(), axisLength.end()));
297 }
298};
299
305template<class ctype, int dimworld, typename std::enable_if_t<dimworld == 3, int> = 0>
306inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
307{
308 static constexpr ctype eps_ = 1.0e-7;
309
310 using std::max;
311 const auto dx = b[3] - b[0];
312 const auto dy = b[4] - b[1];
313 const auto dz = b[5] - b[2];
314 const ctype eps = max({dx, dy, dz})*eps_;
315 return (b[0] - eps <= point[0] && point[0] <= b[3] + eps &&
316 b[1] - eps <= point[1] && point[1] <= b[4] + eps &&
317 b[2] - eps <= point[2] && point[2] <= b[5] + eps);
318}
319
325template<class ctype, int dimworld, typename std::enable_if_t<dimworld == 2, int> = 0>
326inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
327{
328 static constexpr ctype eps_ = 1.0e-7;
329
330 using std::max;
331 const auto dx = b[2] - b[0];
332 const auto dy = b[3] - b[1];
333 const ctype eps = max(dx, dy)*eps_;
334 return (b[0] - eps <= point[0] && point[0] <= b[2] + eps &&
335 b[1] - eps <= point[1] && point[1] <= b[3] + eps);
336}
337
343template<class ctype, int dimworld, typename std::enable_if_t<dimworld == 1, int> = 0>
344inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
345{
346 static constexpr ctype eps_ = 1.0e-7;
347 const ctype eps0 = eps_*(b[1] - b[0]);
348 return b[0] - eps0 <= point[0] && point[0] <= b[1] + eps0;
349}
350
356template<class ctype, int dimworld>
357inline bool intersectsPointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point,
358 const Dune::FieldVector<ctype, dimworld>& min,
359 const Dune::FieldVector<ctype, dimworld>& max)
360{
361 std::array<ctype, 2*dimworld> bBox;
362 std::copy(min.begin(), min.end(), bBox.begin());
363 std::copy(max.begin(), max.end(), bBox.begin()+dimworld);
364 return intersectsPointBoundingBox(point, bBox.data());
365}
366
372template<int dimworld, class ctypea, class ctypeb, typename std::enable_if_t<dimworld == 3, int> = 0>
373inline bool intersectsBoundingBoxBoundingBox(const ctypea* a, const ctypeb* b)
374{
375 using ctype = typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
376 static constexpr ctype eps_ = 1.0e-7;
377 const ctype eps0 = eps_*std::max(b[3]-b[0], a[3]-a[0]);
378 const ctype eps1 = eps_*std::max(b[4]-b[1], a[4]-a[1]);
379 const ctype eps2 = eps_*std::max(b[5]-b[2], a[5]-a[2]);
380 return (b[0] - eps0 <= a[3] && a[0] <= b[3] + eps0 &&
381 b[1] - eps1 <= a[4] && a[1] <= b[4] + eps1 &&
382 b[2] - eps2 <= a[5] && a[2] <= b[5] + eps2);
383
384}
385
391template<int dimworld, class ctypea, class ctypeb, typename std::enable_if_t<dimworld == 2, int> = 0>
392inline bool intersectsBoundingBoxBoundingBox(const ctypea* a, const ctypeb* b)
393{
394 using ctype = typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
395 static constexpr ctype eps_ = 1.0e-7;
396 const ctype eps0 = eps_*std::max(b[2]-b[0], a[2]-a[0]);
397 const ctype eps1 = eps_*std::max(b[3]-b[1], a[3]-a[1]);
398 return (b[0] - eps0 <= a[2] && a[0] <= b[2] + eps0 &&
399 b[1] - eps1 <= a[3] && a[1] <= b[3] + eps1);
400}
401
407template<int dimworld, class ctypea, class ctypeb, typename std::enable_if_t<dimworld == 1, int> = 0>
408inline bool intersectsBoundingBoxBoundingBox(const ctypea* a, const ctypeb* b)
409{
410 using ctype = typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
411 static constexpr ctype eps_ = 1.0e-7;
412 const ctype eps0 = eps_*std::max(b[1]-b[0], a[1]-a[0]);
413 return b[0] - eps0 <= a[1] && a[0] <= b[1] + eps0;
414}
415
421template<int dimworld, class ctype>
422inline ctype squaredDistancePointBoundingBox(const Dune::FieldVector<ctype, dimworld>& point, const ctype* b)
423{
424 ctype squaredDistance = 0.0;
425 for (int d = 0; d < dimworld; ++d)
426 {
427 if (point[d] < b[d])
428 squaredDistance += (point[d] - b[d])*(point[d] - b[d]);
429 if (point[d] > b[d+dimworld])
430 squaredDistance += (point[d] - b[d+dimworld])*(point[d] - b[d+dimworld]);
431 }
432 return squaredDistance;
433}
434
435} // end namespace Dumux
436
437#endif
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:294
static ctype squaredDistance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest squared distance between two points.
Definition: distance.hh:303
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
bool intersectsBoundingBoxBoundingBox(const ctypea *a, const ctypeb *b)
Check whether a bounding box is intersecting another bounding box (dimworld == 3)
Definition: boundingboxtree.hh:373
ctype squaredDistancePointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Compute squared distance between point and bounding box.
Definition: boundingboxtree.hh:422
bool intersectsPointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Check whether a point is intersectin a bounding box (dimworld == 3)
Definition: boundingboxtree.hh:306
An axis-aligned bounding box volume tree implementation.
Definition: boundingboxtree.hh:68
BoundingBoxTree()=default
Default Constructor.
const ctype * getBoundingBoxCoordinates(std::size_t nodeIdx) const
Get an existing bounding box for a given node.
Definition: boundingboxtree.hh:147
bool isLeaf(const BoundingBoxNode &node, std::size_t nodeIdx) const
Definition: boundingboxtree.hh:156
const EntitySet & entitySet() const
the entity set this tree was built with
Definition: boundingboxtree.hh:135
GeometricEntitySet EntitySet
the type of entity set this tree was built with
Definition: boundingboxtree.hh:85
void build(std::shared_ptr< const GeometricEntitySet > set)
Build up bounding box tree for a grid with leafGridView.
Definition: boundingboxtree.hh:95
BoundingBoxTree(std::shared_ptr< const GeometricEntitySet > set)
Constructor with gridView.
Definition: boundingboxtree.hh:91
std::size_t numBoundingBoxes() const
Get the number of bounding boxes currently in the tree.
Definition: boundingboxtree.hh:151
const BoundingBoxNode & getBoundingBoxNode(std::size_t nodeIdx) const
Interface to be used by other bounding box trees.
Definition: boundingboxtree.hh:143