version 3.11-dev
Loading...
Searching...
No Matches
distributedintersectingentities.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-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_GEOMETRY_DISTRIBUTED_INTERSECTING_ENTITIES_HH
14#define DUMUX_GEOMETRY_DISTRIBUTED_INTERSECTING_ENTITIES_HH
15
16#include <vector>
17#include <array>
18#include <utility>
19
20#include <dune/common/fvector.hh>
21#include <dune/common/promotiontraits.hh>
22#include <dune/geometry/type.hh>
23#include <dune/geometry/multilineargeometry.hh>
24#include <dune/grid/common/gridenums.hh>
25#include <dune/grid/common/partitionset.hh>
26
33
34namespace Dumux::Detail {
35
42template<class Entity, class PartitionSet>
43bool inPartition(const Entity& e, PartitionSet partitions)
44{
45 if constexpr (requires { e.partitionType(); })
46 return partitions.contains(e.partitionType());
47 else
48 return true;
49}
50
58template<class Entity>
59bool isUniquelyOwned(const Entity& e)
60{ return inPartition(e, Dune::Partitions::interior); }
61
62} // end namespace Dumux::Detail
63
64namespace Dumux {
65
79template<class EntitySet, class ctype, int dimworld>
80inline std::vector<std::pair<int, std::size_t>>
81intersectingEntities(const Dune::FieldVector<ctype, dimworld>& point,
83 bool isCartesianGrid = false,
84 bool onlyOwned = true)
85{
86 std::vector<std::pair<int, std::size_t>> result;
87 if (!tree.hasLocalEntities())
88 return result;
89
90 const auto localEntities = intersectingEntities(point, tree.localTree(), isCartesianGrid);
91 const int rank = tree.rank();
92 result.reserve(localEntities.size());
93 for (const auto localIdx : localEntities)
94 {
95 const auto& set = tree.entitySet();
96 if (onlyOwned && !Detail::isUniquelyOwned(set.entity(localIdx)))
97 continue;
98 result.emplace_back(rank, localIdx);
99 }
100 return result;
101}
102
108template<class DomainEntitySet, class TargetEntitySet>
110{
111 using ctype = typename Dune::PromotionTraits<typename DomainEntitySet::ctype, typename TargetEntitySet::ctype>::PromotedType;
112 static constexpr int dimensionworld = DomainEntitySet::dimensionworld;
113 using GlobalPosition = Dune::FieldVector<ctype, dimensionworld>;
114
116 std::size_t domainIndex;
118 std::size_t targetIndex;
119 std::vector<GlobalPosition> corners;
120};
121
153template<class DomainEntitySet, class TargetEntitySet,
154 class DomainPartitionSet = Dune::Partitions::Interior>
155std::vector<DistributedIntersectionInfo<DomainEntitySet, TargetEntitySet>>
158 DomainPartitionSet domainPartitions = {})
159{
160 static_assert(int(DomainEntitySet::dimensionworld) == int(TargetEntitySet::dimensionworld),
161 "Can only intersect distributed bounding box trees of the same world dimension");
162
163 using Info = DistributedIntersectionInfo<DomainEntitySet, TargetEntitySet>;
164 static constexpr int dimworld = DomainEntitySet::dimensionworld;
165 static constexpr int dimTarget = TargetEntitySet::Entity::Geometry::mydimension;
166 using TargetCtype = typename TargetEntitySet::ctype;
167 using ImportedGeometry = Dune::MultiLinearGeometry<TargetCtype, dimTarget, dimworld>;
168 using ImportedEntitySet = GeometriesEntitySet<ImportedGeometry>;
169 using ImportedGlobalPosition = Dune::FieldVector<TargetCtype, dimworld>;
170
171 const auto& comm = treeA.comm();
172 const int myRank = comm.rank();
173 const int numProc = comm.size();
174
175 // 1. Pack each owned target entity into a buffer for every remote domain partition
176 // it overlaps. A single logarithmic tree-tree query of the local target tree
177 // against the replicated process tree of the domain determines, with subtree
178 // pruning, which target entities overlap which remote domain partitions.
179 std::vector<std::vector<char>> sendBufs(numProc);
180 if (treeB.hasLocalEntities())
181 {
182 const auto& setB = treeB.entitySet();
183
184 // collect, per local target entity, the remote domain ranks it overlaps
185 std::vector<std::vector<int>> destinations(setB.size());
186 for (const auto& [targetIdx, processLeaf] : intersectingBoxes(treeB.localTree(), treeA.processTree()))
187 if (const int p = treeA.processForLeaf(processLeaf); p != myRank)
188 destinations[targetIdx].push_back(p);
189
190 // pack each owned entity once and append it to each of its destinations' buffers
191 std::vector<char> entityBuf;
192 for (const auto& entity : setB)
193 {
194 const auto entityIdx = setB.index(entity);
195 if (!Detail::isUniquelyOwned(entity) || destinations[entityIdx].empty())
196 continue;
197
198 entityBuf.clear();
199 const auto geometry = entity.geometry();
200 Detail::packValue(entityBuf, myRank);
201 Detail::packValue(entityBuf, static_cast<std::size_t>(entityIdx));
202 Detail::packValue(entityBuf, static_cast<unsigned int>(geometry.type().id()));
203 const int numCorners = geometry.corners();
204 Detail::packValue(entityBuf, numCorners);
205 for (int c = 0; c < numCorners; ++c)
206 {
207 const auto corner = geometry.corner(c);
208 for (int d = 0; d < dimworld; ++d)
209 Detail::packValue(entityBuf, static_cast<TargetCtype>(corner[d]));
210 }
211
212 for (const int p : destinations[entityIdx])
213 sendBufs[p].insert(sendBufs[p].end(), entityBuf.begin(), entityBuf.end());
214 }
215 }
216
217 // 2. Exchange the boundary target entities with their destination processes only.
218 // Each rank knows whom it sends to (sendBufs) but not who sends to it; a
219 // nonblocking-consensus (NBX) sparse data exchange discovers the senders and
220 // sizes on the fly, avoiding any dense O(numProc^2) count collective.
221 std::vector<char> recvBuf;
222 if (numProc > 1)
223 recvBuf = Detail::exchangeSparse(comm, sendBufs);
224
225 // 3. Deserialize imported target entities that overlap this process' domain box
226 std::vector<ImportedGeometry> importedGeometries;
227 std::vector<std::pair<int, std::size_t>> importedOrigin; // (rank, local index)
228 if (treeA.hasLocalEntities() && !recvBuf.empty())
229 {
230 const auto* const myDomainBox = treeA.localBoundingBox().data();
231 const char* cursor = recvBuf.data();
232 const char* const end = recvBuf.data() + recvBuf.size();
233 while (cursor < end)
234 {
235 const int originRank = Detail::unpackValue<int>(cursor);
236 const auto originIndex = Detail::unpackValue<std::size_t>(cursor);
237 const auto topologyId = Detail::unpackValue<unsigned int>(cursor);
238 const int numCorners = Detail::unpackValue<int>(cursor);
239
240 std::vector<ImportedGlobalPosition> corners(numCorners);
241 for (int c = 0; c < numCorners; ++c)
242 for (int d = 0; d < dimworld; ++d)
243 corners[c][d] = Detail::unpackValue<TargetCtype>(cursor);
244
245 // skip our own entities (handled by the local-local pass below)
246 if (originRank == myRank)
247 continue;
248
249 ImportedGeometry geometry(Dune::GeometryType(topologyId, dimTarget), corners);
250
251 // skip entities that don't overlap our domain partition
252 std::array<TargetCtype, 2*dimworld> box{};
254 if (!intersectsBoundingBoxBoundingBox<dimworld>(box.data(), myDomainBox))
255 continue;
256
257 importedGeometries.push_back(std::move(geometry));
258 importedOrigin.emplace_back(originRank, originIndex);
259 }
260 }
261
262 // 4. Compute the local intersections, keeping only those we own (interior domain entity)
263 std::vector<Info> result;
264 if (!treeA.hasLocalEntities())
265 return result;
266
267 const auto& localTreeA = treeA.localTree();
268 const auto& setA = treeA.entitySet();
269
270 // (a) against our own local target entities
271 if (treeB.hasLocalEntities())
272 {
273 const auto& setB = treeB.entitySet();
274 const auto raw = intersectingEntities(localTreeA, treeB.localTree());
275 for (const auto& is : raw)
276 {
277 if (!Detail::inPartition(setA.entity(is.first()), domainPartitions))
278 continue;
279 if (!Detail::isUniquelyOwned(setB.entity(is.second())))
280 continue;
281 result.push_back(Info{
282 myRank, is.first(), myRank, is.second(),
283 {is.corners().begin(), is.corners().end()}
284 });
285 }
286 }
287
288 // (b) against the imported (remote) target entities
289 if (!importedGeometries.empty())
290 {
291 const auto importedSet = std::make_shared<const ImportedEntitySet>(std::move(importedGeometries));
292 const BoundingBoxTree<ImportedEntitySet> importedTree(importedSet);
293 const auto raw = intersectingEntities(localTreeA, importedTree);
294 for (const auto& is : raw)
295 {
296 if (!Detail::inPartition(setA.entity(is.first()), domainPartitions))
297 continue;
298 const auto [originRank, originIndex] = importedOrigin[is.second()];
299 result.push_back(Info{
300 myRank, is.first(), originRank, originIndex,
301 {is.corners().begin(), is.corners().end()}
302 });
303 }
304 }
305
306 return result;
307}
308
309} // end namespace Dumux
310
311#endif
An axis-aligned bounding box volume hierarchy for dune grids.
An axis-aligned bounding box volume tree implementation.
Definition boundingboxtree.hh:105
An MPI-parallel axis-aligned bounding box volume tree.
Definition distributedboundingboxtree.hh:61
const LocalTree & localTree() const
the process-local bounding box tree (only valid if hasLocalEntities())
Definition distributedboundingboxtree.hh:162
const EntitySet & entitySet() const
the entity set this tree was built with
Definition distributedboundingboxtree.hh:146
const ProcessTree & processTree() const
the replicated process tree over the per-process boxes
Definition distributedboundingboxtree.hh:170
std::span< const ctype, 2 *dimworld > localBoundingBox() const
the bounding box (min then max) of this process' partition (only valid if hasLocalEntities())
Definition distributedboundingboxtree.hh:178
const Communication & comm() const
the communicator this tree was built with
Definition distributedboundingboxtree.hh:150
int processForLeaf(std::size_t leafIdx) const
the rank owning the given leaf of the process tree
Definition distributedboundingboxtree.hh:174
int rank() const
the rank of this process
Definition distributedboundingboxtree.hh:154
bool hasLocalEntities() const
whether this process holds any local entities
Definition distributedboundingboxtree.hh:158
A distributed (MPI-parallel) axis-aligned bounding box volume hierarchy.
An interface for a set of geometric entities.
void intersectingBoxes(const ctype *box, const BoundingBoxTree< EntitySet > &tree, std::size_t node, std::vector< std::size_t > &entities)
Compute all entities whose bounding box overlaps the given box.
Definition intersectingentities.hh:167
void computeGeometryBoundingBox(ctype *b, const Geometry &geometry)
Compute the bounding box of a geometry.
Definition boundingboxtree.hh:51
std::vector< std::pair< int, std::size_t > > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const DistributedBoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false, bool onlyOwned=true)
Compute all intersections between entities and a point on a distributed tree.
Definition distributedintersectingentities.hh:81
std::vector< char > exchangeSparse(const Communication &comm, std::vector< std::vector< char > > &sendBufs, int tag=7373)
Exchange variable-sized byte messages with a sparse set of peer processes.
Definition nonblockingsparseexchange.hh:46
Algorithms that finds which geometric entities intersect.
Definition cvfelocalresidual.hh:25
void packValue(std::vector< char > &buf, const T &value)
Append the raw bytes of a trivially-copyable value to a byte buffer.
Definition packing.hh:25
bool isUniquelyOwned(const Entity &e)
Whether an entity is uniquely owned by the calling process.
Definition distributedintersectingentities.hh:59
T unpackValue(const char *&cursor)
Read a trivially-copyable value from a byte buffer and advance the cursor.
Definition packing.hh:34
bool inPartition(const Entity &e, PartitionSet partitions)
Whether an entity belongs to one of the given parallel partitions.
Definition distributedintersectingentities.hh:43
constexpr Box box
Definition method.hh:176
std::size_t numCorners(Shape shape)
Returns the number of corners of a given geometry.
Definition throatproperties.hh:220
Definition adapt.hh:17
bool intersectsBoundingBoxBoundingBox(const ctypea *a, const ctypeb *b)
Check whether a bounding box is intersecting another bounding box (dimworld == 3).
Definition boundingboxtree.hh:372
A dynamic sparse data exchange (DSDE) of byte messages between processes.
Helpers to (de)serialize trivially-copyable values into a byte buffer (e.g. for point-to-point or col...
An intersection of two entities of distributed entity sets.
Definition distributedintersectingentities.hh:110
std::size_t targetIndex
the local index of the target entity on targetRank
Definition distributedintersectingentities.hh:118
Dune::FieldVector< ctype, dimensionworld > GlobalPosition
Definition distributedintersectingentities.hh:113
typename Dune::PromotionTraits< typename DomainEntitySet::ctype, typename TargetEntitySet::ctype >::PromotedType ctype
Definition distributedintersectingentities.hh:111
std::size_t domainIndex
the local index of the domain entity on domainRank
Definition distributedintersectingentities.hh:116
int domainRank
the rank owning the domain (first) entity
Definition distributedintersectingentities.hh:115
std::vector< GlobalPosition > corners
the corners of the (simplex) intersection geometry
Definition distributedintersectingentities.hh:119
static constexpr int dimensionworld
Definition distributedintersectingentities.hh:112
int targetRank
the rank owning the target (second) entity
Definition distributedintersectingentities.hh:117