19#ifndef DUMUX_GEOMETRY_BOUNDINGBOXTREE_HH 
   20#define DUMUX_GEOMETRY_BOUNDINGBOXTREE_HH 
   31#include <dune/common/promotiontraits.hh> 
   32#include <dune/common/timer.hh> 
   33#include <dune/common/fvector.hh> 
   41template<
typename ctype>
 
   42inline constexpr ctype minimumBaseEpsilon = 10.0*std::numeric_limits<ctype>::epsilon();
 
   65template <
class GeometricEntitySet>
 
   68    enum { dimworld = GeometricEntitySet::dimensionworld };
 
   69    using ctype = 
typename GeometricEntitySet::ctype;
 
   76    struct BoundingBoxNode
 
   94    void build(std::shared_ptr<const GeometricEntitySet> set)
 
  100        boundingBoxNodes_.clear();
 
  101        boundingBoxCoordinates_.clear();
 
  107        const auto numLeaves = set->size();
 
  110        const auto numNodes = 2*numLeaves - 1;
 
  111        boundingBoxNodes_.reserve(numNodes);
 
  112        boundingBoxCoordinates_.reserve(numNodes*2*dimworld);
 
  115        std::vector<ctype> leafBoxes(2*dimworld*numLeaves);
 
  117        for (
const auto& geometricEntity : *set)
 
  118            computeEntityBoundingBox_(leafBoxes.data() + 2*dimworld*set->index(geometricEntity), geometricEntity);
 
  121        std::vector<std::size_t> leafPartition(numLeaves);
 
  122        std::iota(leafPartition.begin(), leafPartition.end(), 0);
 
  125        build_(leafBoxes, leafPartition.begin(), leafPartition.end());
 
  129                  << 
" nodes for " << numLeaves << 
" grid entities in " 
  130                  << timer.stop() << 
" seconds." << std::endl;
 
 
  135    { 
return *entitySet_; }
 
 
  143    { 
return boundingBoxNodes_[nodeIdx]; }
 
 
  147    { 
return boundingBoxCoordinates_.data() + 2*dimworld*nodeIdx; }
 
 
  151    { 
return boundingBoxNodes_.size(); }
 
 
  155    bool isLeaf(
const BoundingBoxNode& node, std::size_t nodeIdx)
 const 
  156    { 
return node.child0 == nodeIdx; }
 
 
  161    std::vector<BoundingBoxNode> boundingBoxNodes_;
 
  164    std::vector<ctype> boundingBoxCoordinates_;
 
  167    std::shared_ptr<const EntitySet> entitySet_;
 
  170    template <
class Entity>
 
  171    void computeEntityBoundingBox_(ctype* b, 
const Entity& entity)
 const 
  175        ctype* xMax = b + dimworld;
 
  178        auto geometry = entity.geometry();
 
  181        auto corner = geometry.corner(0);
 
  182        for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
 
  183            xMin[dimIdx] = xMax[dimIdx] = corner[dimIdx];
 
  186        for (std::size_t cornerIdx = 1; cornerIdx < geometry.corners(); ++cornerIdx)
 
  188            corner = geometry.corner(cornerIdx);
 
  189            for (std::size_t dimIdx = 0; dimIdx < dimworld; ++dimIdx)
 
  193                xMin[dimIdx] = min(xMin[dimIdx], corner[dimIdx]);
 
  194                xMax[dimIdx] = max(xMax[dimIdx], corner[dimIdx]);
 
  200    std::size_t build_(
const std::vector<ctype>& leafBoxes,
 
  201                       const std::vector<std::size_t>::iterator& begin,
 
  202                       const std::vector<std::size_t>::iterator& end)
 
  207        if (end - begin == 1)
 
  210            const std::size_t leafNodeIdx = *begin;
 
  211            const auto beginCoords = leafBoxes.begin() + 2*dimworld*leafNodeIdx;
 
  212            const auto endCoords = beginCoords + 2*dimworld;
 
  217            return addBoundingBox_(BoundingBoxNode{
numBoundingBoxes(), leafNodeIdx}, beginCoords, endCoords);
 
  221        const auto bCoords = computeBBoxOfBBoxes_(leafBoxes, begin, end);
 
  224        const auto axis = computeLongestAxis_(bCoords);
 
  228        auto middle = begin + (end - begin)/2;
 
  229        std::nth_element(begin, middle, end, [&leafBoxes, axis](std::size_t i, std::size_t j)
 
  231                             const ctype* bi = leafBoxes.data() + 2*dimworld*i;
 
  232                             const ctype* 
bj = leafBoxes.data() + 2*dimworld*j;
 
  233                             return bi[axis] + bi[axis + dimworld] < 
bj[axis] + 
bj[axis + dimworld];
 
  238        return addBoundingBox_(BoundingBoxNode{build_(leafBoxes, begin, middle), build_(leafBoxes, middle, end)},
 
  239                               bCoords.begin(), bCoords.end());
 
  243    template <
class Iterator>
 
  244    std::size_t addBoundingBox_(BoundingBoxNode&& node,
 
  245                                const Iterator& coordBegin,
 
  246                                const Iterator& coordEnd)
 
  249        boundingBoxNodes_.emplace_back(node);
 
  252        boundingBoxCoordinates_.insert(boundingBoxCoordinates_.end(), coordBegin, coordEnd);
 
  255        return boundingBoxNodes_.size() - 1;
 
  259    std::array<ctype, 2*dimworld>
 
  260    computeBBoxOfBBoxes_(
const std::vector<ctype>& leafBoxes,
 
  261                         const std::vector<std::size_t>::iterator& begin,
 
  262                         const std::vector<std::size_t>::iterator& end)
 
  264        std::array<ctype, 2*dimworld> bBoxCoords;
 
  268        const auto* bFirst = leafBoxes.data() + 2*dimworld*(*it);
 
  270        for (
int coordIdx = 0; coordIdx < 2*dimworld; ++coordIdx)
 
  271            bBoxCoords[coordIdx] = bFirst[coordIdx];
 
  274        for (; it != end; ++it)
 
  276            const auto* b = leafBoxes.data() + 2*dimworld*(*it);
 
  277            for (
int coordIdx = 0; coordIdx < dimworld; ++coordIdx)
 
  278                if (b[coordIdx] < bBoxCoords[coordIdx])
 
  279                    bBoxCoords[coordIdx] = b[coordIdx];
 
  280            for (
int coordIdx = dimworld; coordIdx < 2*dimworld; ++coordIdx)
 
  281                if (b[coordIdx] > bBoxCoords[coordIdx])
 
  282                    bBoxCoords[coordIdx] = b[coordIdx];
 
  289    std::size_t computeLongestAxis_(
const std::array<ctype, 2*dimworld>& bCoords)
 
  291        std::array<ctype, dimworld> axisLength;
 
  292        for (
int coordIdx = 0; coordIdx < dimworld; ++coordIdx)
 
  293            axisLength[coordIdx] = bCoords[dimworld + coordIdx] - bCoords[coordIdx];
 
  295        return std::distance(axisLength.begin(), std::max_element(axisLength.begin(), axisLength.end()));
 
 
  304template<
class ctype, 
int dimworld, 
typename std::enable_if_t<dimworld == 3, 
int> = 0>
 
  307    static constexpr ctype eps_ = 1.0e-7;
 
  310    const auto dx = b[3] - b[0];
 
  311    const auto dy = b[4] - b[1];
 
  312    const auto dz = b[5] - b[2];
 
  313    const ctype eps = max({dx, dy, dz})*eps_;
 
  314    return (b[0] - eps <= point[0] && point[0] <= b[3] + eps &&
 
  315            b[1] - eps <= point[1] && point[1] <= b[4] + eps &&
 
  316            b[2] - eps <= point[2] && point[2] <= b[5] + eps);
 
 
  324template<
class ctype, 
int dimworld, 
typename std::enable_if_t<dimworld == 2, 
int> = 0>
 
  327    static constexpr ctype eps_ = 1.0e-7;
 
  330    const auto dx = b[2] - b[0];
 
  331    const auto dy = b[3] - b[1];
 
  332    const ctype eps = max(dx, dy)*eps_;
 
  333    return (b[0] - eps <= point[0] && point[0] <= b[2] + eps &&
 
  334            b[1] - eps <= point[1] && point[1] <= b[3] + eps);
 
  342template<
class ctype, 
int dimworld, 
typename std::enable_if_t<dimworld == 1, 
int> = 0>
 
  345    static constexpr ctype eps_ = 1.0e-7;
 
  346    const ctype eps0 = eps_*(b[1] - b[0]);
 
  347    return b[0] - eps0 <= point[0] && point[0] <= b[1] + eps0;
 
  355template<
class ctype, 
int dimworld>
 
  357                                       const Dune::FieldVector<ctype, dimworld>& min,
 
  358                                       const Dune::FieldVector<ctype, dimworld>& max)
 
  360    std::array<ctype, 2*dimworld> bBox;
 
  361    std::copy(min.begin(), min.end(), bBox.begin());
 
  362    std::copy(max.begin(), max.end(), bBox.begin()+dimworld);
 
 
  371template<
int dimworld, 
class ctypea, 
class ctypeb, 
typename std::enable_if_t<dimworld == 3, 
int> = 0>
 
  374    using ctype = 
typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
 
  375    static constexpr ctype eps_ = 1.0e-7;
 
  376    const ctype scale0 = std::max(b[3]-b[0], a[3]-a[0]);
 
  377    const ctype scale1 = std::max(b[4]-b[1], a[4]-a[1]);
 
  378    const ctype scale2 = std::max(b[5]-b[2], a[5]-a[2]);
 
  379    const ctype maxScale = std::max(scale0, std::max(scale1, scale2));
 
  380    const ctype minEps = maxScale*Detail::minimumBaseEpsilon<ctype>;
 
  381    const ctype eps0 = std::max(eps_*scale0, minEps);
 
  382    const ctype eps1 = std::max(eps_*scale1, minEps);
 
  383    const ctype eps2 = std::max(eps_*scale2, minEps);
 
  384    return (b[0] - eps0 <= a[3] && a[0] <= b[3] + eps0 &&
 
  385            b[1] - eps1 <= a[4] && a[1] <= b[4] + eps1 &&
 
  386            b[2] - eps2 <= a[5] && a[2] <= b[5] + eps2);
 
 
  395template<
int dimworld, 
class ctypea, 
class ctypeb, 
typename std::enable_if_t<dimworld == 2, 
int> = 0>
 
  398    using ctype = 
typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
 
  399    static constexpr ctype eps_ = 1.0e-7;
 
  400    const ctype scale0 = std::max(b[2]-b[0], a[2]-a[0]);
 
  401    const ctype scale1 = std::max(b[3]-b[1], a[3]-a[1]);
 
  402    const ctype maxScale = std::max(scale0, scale1);
 
  403    const ctype minEps = maxScale*Detail::minimumBaseEpsilon<ctype>;
 
  404    const ctype eps0 = std::max(eps_*scale0, minEps);
 
  405    const ctype eps1 = std::max(eps_*scale1, minEps);
 
  406    return (b[0] - eps0 <= a[2] && a[0] <= b[2] + eps0 &&
 
  407            b[1] - eps1 <= a[3] && a[1] <= b[3] + eps1);
 
  415template<
int dimworld, 
class ctypea, 
class ctypeb, 
typename std::enable_if_t<dimworld == 1, 
int> = 0>
 
  418    using ctype = 
typename Dune::PromotionTraits<ctypea, ctypeb>::PromotedType;
 
  419    static constexpr ctype eps_ = 1.0e-7;
 
  420    const ctype scale0 = std::max(b[1]-b[0], a[1]-a[0]);
 
  421    const ctype eps0 = std::max(eps_*scale0, Detail::minimumBaseEpsilon<ctype>*scale0);
 
  422    return b[0] - eps0 <= a[1] && a[0] <= b[1] + eps0;
 
  430template<
int dimworld, 
class ctype>
 
  434    for (
int d = 0; d < dimworld; ++d)
 
  438        if (point[d] > b[d+dimworld])
 
  439            squaredDistance += (point[d] - b[d+dimworld])*(point[d] - b[d+dimworld]);
 
 
BoundingBoxTree()=default
Default Constructor.
const ctype * getBoundingBoxCoordinates(std::size_t nodeIdx) const
Get an existing bounding box for a given node.
Definition boundingboxtree.hh:146
bool isLeaf(const BoundingBoxNode &node, std::size_t nodeIdx) const
Definition boundingboxtree.hh:155
const EntitySet & entitySet() const
the entity set this tree was built with
Definition boundingboxtree.hh:134
ElementSet EntitySet
Definition boundingboxtree.hh:84
void build(std::shared_ptr< const GeometricEntitySet > set)
Build up bounding box tree for a grid with leafGridView.
Definition boundingboxtree.hh:94
BoundingBoxTree(std::shared_ptr< const GeometricEntitySet > set)
Constructor with gridView.
Definition boundingboxtree.hh:90
std::size_t numBoundingBoxes() const
Get the number of bounding boxes currently in the tree.
Definition boundingboxtree.hh:150
const BoundingBoxNode & getBoundingBoxNode(std::size_t nodeIdx) const
Interface to be used by other bounding box trees.
Definition boundingboxtree.hh:142
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:291
constexpr BJ bj
Tag for the Beavers-Joseph slip condition.
Definition slipcondition.hh:42
Distance implementation details.
Definition cvfelocalresidual.hh:25
bool intersectsBoundingBoxBoundingBox(const ctypea *a, const ctypeb *b)
Check whether a bounding box is intersecting another bounding box (dimworld == 3)
Definition boundingboxtree.hh:372
ctype squaredDistancePointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Compute squared distance between point and bounding box.
Definition boundingboxtree.hh:431
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:305