version 3.10-dev
intersectionentityset.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// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_GEOMETRY_INTERSECTION_ENTITY_SET_HH
14#define DUMUX_GEOMETRY_INTERSECTION_ENTITY_SET_HH
15
16#include <algorithm>
17#include <cassert>
18#include <iostream>
19#include <memory>
20#include <type_traits>
21#include <utility>
22#include <vector>
23
24#include <dune/common/indices.hh>
25#include <dune/common/timer.hh>
26#include <dune/common/iteratorrange.hh>
27#include <dune/common/promotiontraits.hh>
28#include <dune/common/reservedvector.hh>
29#include <dune/geometry/affinegeometry.hh>
30#include <dune/geometry/type.hh>
31
34
36
40template<class DomainEntitySet, class TargetEntitySet>
42{
43 static constexpr int dimDomain = DomainEntitySet::Entity::Geometry::mydimension;
44 static constexpr int dimTarget = TargetEntitySet::Entity::Geometry::mydimension;
45 using ctype = typename Dune::PromotionTraits<typename DomainEntitySet::ctype, typename TargetEntitySet::ctype>::PromotedType;
46
47 static constexpr int dimWorld = DomainEntitySet::dimensionworld;
48 static_assert(dimWorld == int(TargetEntitySet::dimensionworld), "Entity sets must have the same world dimension");
49
50 static constexpr int dimIs = std::min(dimDomain, dimTarget);
51
52 using GlobalPosition = Dune::FieldVector<ctype, dimWorld>;
53 using Geometry = Dune::AffineGeometry<ctype, dimIs, dimWorld>; // geometries are always simplices
54
55 // we can only have multiple neighbors in the mixeddimensional case and then only for the side with the largest dimension
56 using IndexStorage = std::pair<std::conditional_t<dimDomain <= dimTarget, Dune::ReservedVector<std::size_t, 1>, std::vector<std::size_t>>,
57 std::conditional_t<dimTarget <= dimDomain, Dune::ReservedVector<std::size_t, 1>, std::vector<std::size_t>>>;
58
59 static constexpr auto domainIdx = Dune::index_constant<0>{};
60 static constexpr auto targetIdx = Dune::index_constant<1>{};
61
62public:
63 IntersectionEntity(const DomainEntitySet& domainEntitySet, const TargetEntitySet& targetEntitySet)
64 : domainEntitySet_(domainEntitySet)
65 , targetEntitySet_(targetEntitySet)
66 {}
67
69 void setCorners(const std::vector<GlobalPosition>& corners)
70 {
71 corners_ = corners;
72 assert(corners.size() == dimIs + 1); // Only simplex intersections are allowed
73 }
74
76 void addNeighbors(std::size_t domain, std::size_t target)
77 {
78 if (numDomainNeighbors() == 0 && numTargetNeighbors() == 0)
79 {
80 std::get<domainIdx>(neighbors_).push_back(domain);
81 std::get<targetIdx>(neighbors_).push_back(target);
82 }
83 else if (dimDomain > dimTarget)
84 std::get<domainIdx>(neighbors_).push_back(domain);
85
86 else if (dimTarget > dimDomain)
87 std::get<targetIdx>(neighbors_).push_back(target);
88
89 else
90 DUNE_THROW(Dune::InvalidStateException, "Cannot add more than one neighbor per side for equidimensional intersection!");
91 }
92
94 Geometry geometry() const
95 { return Geometry(Dune::GeometryTypes::simplex(dimIs), corners_); }
96
98 std::size_t numDomainNeighbors() const
99 { return std::get<domainIdx>(neighbors_).size(); }
100
102 std::size_t numTargetNeighbors() const
103 { return std::get<targetIdx>(neighbors_).size(); }
104
106 typename DomainEntitySet::Entity domainEntity(unsigned int n = 0) const
107 { return domainEntitySet_.entity(std::get<domainIdx>(neighbors_)[n]); }
108
110 typename TargetEntitySet::Entity targetEntity(unsigned int n = 0) const
111 { return targetEntitySet_.entity(std::get<targetIdx>(neighbors_)[n]); }
112
113private:
114 IndexStorage neighbors_;
115 std::vector<GlobalPosition> corners_;
116
117 const DomainEntitySet& domainEntitySet_;
118 const TargetEntitySet& targetEntitySet_;
119};
120
121} // end namespace Dumux::Detail::Intersections
122
123namespace Dumux {
124
129template<class DomainEntitySet, class TargetEntitySet>
131{
134
135 using ctype = typename Dune::PromotionTraits<typename DomainEntitySet::ctype, typename TargetEntitySet::ctype>::PromotedType;
136
137 static constexpr int dimWorld = DomainEntitySet::dimensionworld;
138 static_assert(dimWorld == int(TargetEntitySet::dimensionworld), "Entity sets must have the same world dimension");
139
140 using GlobalPosition = Dune::FieldVector<ctype, dimWorld>;
141
142 static constexpr int dimDomain = DomainEntitySet::Entity::Geometry::mydimension;
143 static constexpr int dimTarget = TargetEntitySet::Entity::Geometry::mydimension;
144 static constexpr bool isMixedDimensional = dimDomain != dimTarget;
145
147 using Intersections = std::vector<IntersectionEntity>;
148
149 using DomainGeometry = typename DomainEntitySet::Entity::Geometry;
150 using TargetGeometry = typename TargetEntitySet::Entity::Geometry;
151
152public:
156 using EntityIterator = typename Intersections::const_iterator;
157
162
166 void build(std::shared_ptr<const DomainEntitySet> domainSet, std::shared_ptr<const TargetEntitySet> targetSet)
167 {
168 // specialized algorithm if the target geometry is only a single entity
169 if (targetSet->size() == 1)
170 {
171 domainTree_ = std::make_shared<DomainTree>(domainSet);
172 targetEntitySet_ = targetSet;
173 build_(*domainTree_, targetEntitySet_->entity(0).geometry());
174 }
175 // specialized algorithm if the domain geometry is only a single entity
176 else if (domainSet->size() == 1)
177 {
178 domainEntitySet_ = domainSet;
179 targetTree_ = std::make_shared<TargetTree>(targetSet);
180 build_(domainEntitySet_->entity(0).geometry(), *targetTree_);
181 }
182 else
183 {
184 domainTree_ = std::make_shared<DomainTree>(domainSet);
185 targetTree_ = std::make_shared<TargetTree>(targetSet);
186 build(*domainTree_, *targetTree_);
187 }
188 }
189
193 void build(std::shared_ptr<const DomainTree> domainTree, std::shared_ptr<const TargetTree> targetTree)
194 {
195 // make sure the tree don't get out of scope
196 domainTree_ = domainTree;
197 targetTree_ = targetTree;
198 build(*domainTree_, *targetTree_);
199 }
200
205 void build(const DomainTree& domainTree, const TargetTree& targetTree)
206 {
207 Dune::Timer timer;
208
209 const auto rawIntersections = intersectingEntities(domainTree, targetTree);
210 build_(domainTree.entitySet(), targetTree.entitySet(), rawIntersections);
211
212 std::cout << "Computed " << size() << " intersection entities in " << timer.elapsed() << std::endl;
213 }
214
216 typename Intersections::const_iterator ibegin() const
217 { return intersections_.begin(); }
218
220 typename Intersections::const_iterator iend() const
221 { return intersections_.end(); }
222
224 std::size_t size() const
225 { return intersections_.size(); }
226
232 friend Dune::IteratorRange<EntityIterator> intersections(const IntersectionEntitySet& set)
233 { return {set.ibegin(), set.iend()}; }
234
235private:
236 void build_(const DomainTree& domainTree, const TargetGeometry& targetGeometry)
237 {
238 Dune::Timer timer;
239
240 const auto rawIntersections = intersectingEntities(targetGeometry, domainTree);
241 // because in intersectingEntities geometry always comes first (domain set)
242 // but here we want the geometry to be the second (target set), we need to flip the index sets
243 // of the resulting intersections
244 const bool flipNeighborIndices = true;
245 build_(domainTree.entitySet(), *targetEntitySet_, rawIntersections, flipNeighborIndices);
246
247 std::cout << "Computed " << size() << " intersection entities in " << timer.elapsed() << std::endl;
248 }
249
250 void build_(const DomainGeometry& domainGeometry, const TargetTree& targetTree)
251 {
252 Dune::Timer timer;
253
254 const auto rawIntersections = intersectingEntities(domainGeometry, targetTree);
255 build_(*domainEntitySet_, targetTree.entitySet(), rawIntersections);
256
257 std::cout << "Computed " << size() << " intersection entities in " << timer.elapsed() << std::endl;
258 }
259
260 template<class RawIntersections>
261 void build_(const DomainEntitySet& domainEntitySet, const TargetEntitySet& targetEntitySet,
262 const RawIntersections& rawIntersections,
263 bool flipNeighborIndices = false)
264 {
265 // create a map to check whether intersection geometries were already inserted
266 // Note that this can only occur if the grids have different dimensionality.
267 // If this is the case, we keep track of the intersections using the indices of the lower-
268 // dimensional entities which is identical for all geometrically identical intersections.
269 std::vector<std::vector<std::vector<GlobalPosition>>> intersectionMap;
270 std::vector<std::vector<std::size_t>> intersectionIndex;
271 if constexpr (isMixedDimensional)
272 {
273 const auto numLowDimEntities = dimTarget < dimDomain ? targetEntitySet.size() : domainEntitySet.size();
274 intersectionMap.resize(numLowDimEntities);
275 intersectionIndex.resize(numLowDimEntities);
276 }
277
278 // reserve memory for storing the intersections. In case of grids of
279 // different dimensionality this might be an overestimate. We get rid
280 // of the overhead memory at the end of this function though.
281 intersections_.clear();
282 intersections_.reserve(rawIntersections.size());
283
284 for (const auto& rawIntersection : rawIntersections)
285 {
286 bool add = true;
287
288 // Check if intersection was already inserted.
289 // In this case we only add new neighbor information as the geometry is identical.
290 if constexpr (isMixedDimensional)
291 {
292 const auto lowDimNeighborIdx = getLowDimNeighborIndex_(rawIntersection, flipNeighborIndices);
293 for (int i = 0; i < intersectionMap[lowDimNeighborIdx].size(); ++i)
294 {
295 if (rawIntersection.cornersMatch(intersectionMap[lowDimNeighborIdx][i]))
296 {
297 add = false;
298 // only add the pair of neighbors using the insertionIndex
299 auto idx = intersectionIndex[lowDimNeighborIdx][i];
300 intersections_[idx].addNeighbors(domainNeighborIndex_(rawIntersection, flipNeighborIndices), targetNeighborIndex_(rawIntersection, flipNeighborIndices));
301 break;
302 }
303 }
304 }
305
306 if(add)
307 {
308 // maybe add to the map
309 if constexpr (isMixedDimensional)
310 {
311 const auto lowDimNeighborIdx = getLowDimNeighborIndex_(rawIntersection, flipNeighborIndices);
312 intersectionMap[lowDimNeighborIdx].push_back(rawIntersection.corners());
313 intersectionIndex[lowDimNeighborIdx].push_back(intersections_.size());
314 }
315
316 // add new intersection and add the neighbors
317 intersections_.emplace_back(domainEntitySet, targetEntitySet);
318 intersections_.back().setCorners(rawIntersection.corners());
319 intersections_.back().addNeighbors(domainNeighborIndex_(rawIntersection, flipNeighborIndices), targetNeighborIndex_(rawIntersection, flipNeighborIndices));
320 }
321 }
322
323 intersections_.shrink_to_fit();
324 }
325
326 template<class RawIntersection,
327 bool enable = isMixedDimensional, std::enable_if_t<enable, int> = 0>
328 auto getLowDimNeighborIndex_(const RawIntersection& is, bool flipNeighborIndices)
329 {
330 if constexpr (dimTarget < dimDomain)
331 return targetNeighborIndex_(is, flipNeighborIndices);
332 else
333 return domainNeighborIndex_(is, flipNeighborIndices);
334 }
335
336 template<class RawIntersection>
337 auto domainNeighborIndex_(const RawIntersection& is, bool flipNeighborIndices)
338 { return flipNeighborIndices ? is.second() : is.first(); }
339
340 template<class RawIntersection>
341 auto targetNeighborIndex_(const RawIntersection& is, bool flipNeighborIndices)
342 { return flipNeighborIndices ? is.first() : is.second(); }
343
344 Intersections intersections_;
345
346 std::shared_ptr<const DomainTree> domainTree_;
347 std::shared_ptr<const TargetTree> targetTree_;
348 std::shared_ptr<const DomainEntitySet> domainEntitySet_;
349 std::shared_ptr<const TargetEntitySet> targetEntitySet_;
350};
351
352} // end namespace Dumux
353
354#endif
An axis-aligned bounding box volume hierarchy for dune grids.
An axis-aligned bounding box volume tree implementation.
Definition: boundingboxtree.hh:56
const EntitySet & entitySet() const
the entity set this tree was built with
Definition: boundingboxtree.hh:123
A class representing an intersection entity.
Definition: intersectionentityset.hh:42
std::size_t numTargetNeighbors() const
get the number of target neighbors of this intersection
Definition: intersectionentityset.hh:102
void setCorners(const std::vector< GlobalPosition > &corners)
set the intersection geometry corners
Definition: intersectionentityset.hh:69
std::size_t numDomainNeighbors() const
get the number of domain neighbors of this intersection
Definition: intersectionentityset.hh:98
IntersectionEntity(const DomainEntitySet &domainEntitySet, const TargetEntitySet &targetEntitySet)
Definition: intersectionentityset.hh:63
DomainEntitySet::Entity domainEntity(unsigned int n=0) const
get the nth domain neighbor entity
Definition: intersectionentityset.hh:106
TargetEntitySet::Entity targetEntity(unsigned int n=0) const
get the nth target neighbor entity
Definition: intersectionentityset.hh:110
void addNeighbors(std::size_t domain, std::size_t target)
add a pair of neighbor elements
Definition: intersectionentityset.hh:76
Geometry geometry() const
get the intersection geometry
Definition: intersectionentityset.hh:94
A class representing the intersection entities two geometric entity sets.
Definition: intersectionentityset.hh:131
IntersectionEntitySet()=default
Default constructor.
void build(std::shared_ptr< const DomainEntitySet > domainSet, std::shared_ptr< const TargetEntitySet > targetSet)
Build intersections.
Definition: intersectionentityset.hh:166
std::size_t size() const
the number of intersections
Definition: intersectionentityset.hh:224
void build(const DomainTree &domainTree, const TargetTree &targetTree)
Build intersections.
Definition: intersectionentityset.hh:205
void build(std::shared_ptr< const DomainTree > domainTree, std::shared_ptr< const TargetTree > targetTree)
Build intersections.
Definition: intersectionentityset.hh:193
typename Intersections::const_iterator EntityIterator
make entity iterator type available
Definition: intersectionentityset.hh:156
friend Dune::IteratorRange< EntityIterator > intersections(const IntersectionEntitySet &set)
Range generator to iterate with range-based for loops over all intersections as follows: for (const a...
Definition: intersectionentityset.hh:232
Intersections::const_iterator ibegin() const
return begin iterator to intersection container
Definition: intersectionentityset.hh:216
Intersections::const_iterator iend() const
return end iterator to intersection container
Definition: intersectionentityset.hh:220
std::vector< std::size_t > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const BoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false)
Compute all intersections between entities and a point.
Definition: intersectingentities.hh:102
Algorithms that finds which geometric entities intersect.
Definition: intersectionentityset.hh:35
Definition: adapt.hh:17