dune-mmesh (unstable)

partitionhelper.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_MMESH_MISC_PARTITIONHELPER_HH
4#define DUNE_MMESH_MISC_PARTITIONHELPER_HH
5
6#include <dune/grid/common/partitionset.hh>
7#include <dune/mmesh/grid/rangegenerators.hh>
8
9namespace Dune {
10
11// PartitionHelper
12template <class Grid>
13struct PartitionHelper {
14 static constexpr int dim = Grid::dimension;
15 using IdType = typename Grid::IdType;
16 using ConnectivityType = std::unordered_set<int>;
17 using LinksType = std::vector<int>;
18 using LeafIterator =
19 typename Grid::LeafIterator::Implementation::HostGridLeafIterator;
20
21 PartitionHelper(const Grid& grid) : grid_(grid) {}
22
23 void distribute() {
24 // Initialize leafBegin_ and leafEnd_
25 if constexpr (dim == 2) {
26 leafBegin_ = grid().getHostGrid().finite_faces_begin();
27 leafEnd_ = grid().getHostGrid().finite_faces_end();
28 } else if constexpr (dim == 3) {
29 leafBegin_ = grid().getHostGrid().finite_cells_begin();
30 leafEnd_ = grid().getHostGrid().finite_cells_end();
31 }
32
33 if (grid().comm().size() == 1) return;
34
35 setRanks();
36 computePartitions();
37 }
38
39 template <class Entity>
40 bool contains(PartitionIteratorType pitype, const Entity& e) const {
41 return contains(pitype, partition(e));
42 }
43
44 bool contains(PartitionIteratorType pitype, int partitionType) const {
45 if (partitionType == -1) return false;
46
47 switch (pitype) {
48 case All_Partition:
49 return true;
50
51 case Interior_Partition:
52 return partitionType == 0;
53
54 case InteriorBorder_Partition:
55 case Overlap_Partition:
56 case OverlapFront_Partition:
57 return partitionType != 2;
58
59 case Ghost_Partition:
60 return partitionType == 2;
61 }
62 return false;
63 }
64
65 template <class Entity>
66 PartitionType partitionType(const Entity& e) const {
67 return partitionType(partition(e));
68 }
69
70 PartitionType partitionType(int partition) const {
71 if (partition == 0) return InteriorEntity;
72
73 if (partition == 1)
74 return BorderEntity;
75
76 else
77 return GhostEntity;
78 }
79
80 void updatePartitions() { computePartitions(); }
81
83 const LinksType& links() const { return links_; }
84
85 auto& comm() const { return grid().comm(); }
86
88 template <class Entity>
89 ConnectivityType connectivity(const Entity& e) const {
90 if constexpr (Entity::dimension == dim)
91 return e.impl().hostEntity()->info().connectivity;
92 else
93 try {
94 return interfaceConnectivity_.at(e.impl().id());
95 } catch (std::out_of_range&) {
96 return ConnectivityType();
97 }
98 }
99
101 template <class Entity>
102 int rank(const Entity& e) const {
103 if constexpr (Entity::dimension == dim)
104 return e.impl().hostEntity()->info().rank;
105 else
106 return grid().asIntersection(e).inside().impl().hostEntity()->info().rank;
107 }
108
109 const LeafIterator& leafInteriorBegin() const { return leafBegin_; }
110
111 const LeafIterator& leafInteriorEnd() const { return leafEnd_; }
112
113 private:
115 template <class Entity>
116 int partition(const Entity& e) const {
117 static constexpr int cd = Entity::codimension;
118 if (grid().comm().size() == 1) return 0; // interior
119
120 if constexpr (Entity::dimension == dim) {
121 if constexpr (Entity::codimension == 0 || Entity::codimension == dim)
122 return e.impl().hostEntity()->info().partition;
123 else {
124 auto entry = partition_[cd - 1].find(e.impl().id());
125 if (entry != partition_[cd - 1].end()) return entry->second;
126 }
127 } else {
128 auto entry = interfacePartition_[cd].find(e.impl().id());
129 if (entry != interfacePartition_[cd].end()) return entry->second;
130
131 // handle empty interface
132 return -1;
133 }
134
135 DUNE_THROW(InvalidStateException, "Partition not set yet!");
136 return 0;
137 }
138
140 template <class Entity>
141 void setPartition(const Entity& e, int partition) {
142 if constexpr (Entity::dimension == dim) {
143 if constexpr (Entity::codimension == 0 || Entity::codimension == dim)
144 e.impl().hostEntity()->info().partition = partition;
145 else
146 partition_[Entity::codimension - 1][e.impl().id()] = partition;
147 } else
148 interfacePartition_[Entity::codimension][e.impl().id()] = partition;
149 }
150
152 template <class Entity>
153 void addConnectivity(const Entity& e, int rank) {
154 if constexpr (Entity::dimension == dim)
155 e.impl().hostEntity()->info().connectivity.insert(rank);
156 else
157 interfaceConnectivity_[e.impl().id()].insert(rank);
158
159 if (partition(e) == 0)
160 if (std::find(links_.begin(), links_.end(), rank) == links_.end())
161 links_.push_back(rank);
162 }
163
165 template <class Entity>
166 void clearConnectivity(const Entity& e) {
167 if constexpr (Entity::dimension == dim)
168 e.impl().hostEntity()->info().connectivity.clear();
169 else
170 interfaceConnectivity_[e.impl().id()].clear();
171 }
172
175 void setRanks() {
176 int rank = grid().comm().rank();
177 int size = grid().comm().size();
178
179 std::size_t N;
180 if constexpr (dim == 2)
181 N = grid().getHostGrid().number_of_faces();
182 else
183 N = grid().getHostGrid().number_of_cells();
184
185 std::size_t i = 0;
186 forEntityDim<dim>([this, &i, &rank, &size, &N](const auto& fc) {
187 auto getRank = [&size, &N](std::size_t i) { return i * size / N; };
188 int r = getRank(i);
189
190 // store begin iterator
191 if (r == rank && getRank(i - 1) == rank - 1) this->leafBegin_ = fc;
192
193 // store end iterator
194 if (r == rank + 1 && getRank(i - 1) == rank) this->leafEnd_ = fc;
195
196 auto e = grid().entity(fc);
197 e.impl().hostEntity()->info().rank = r;
198 i++;
199 });
200 }
201
203 void computePartitions() {
204 links_.clear();
205
206 for (int i = 0; i <= dim; ++i) partition_[i].clear();
207
208 // Set interior elements
209 forEntityDim<dim>([this](const auto& fc) {
210 const auto e = grid().entity(fc);
211 if (rank(e) == grid().comm().rank())
212 setPartition(e, 0); // interior
213 else
214 setPartition(e, -1); // none
215
216 clearConnectivity(e);
217 });
218
219 // Set ghosts
220 forEntityDim<dim - 1>([this](const auto& fc) {
221 const auto e = grid().entity(fc);
222 const auto is = grid().asIntersection(e);
223 if (is.neighbor()) {
224 const auto& inside = is.inside();
225 const auto& outside = is.outside();
226 int pIn = partition(inside);
227 int pOut = partition(outside);
228
229 // border
230 if ((pIn == 0 && pOut != 0) or (pIn != 0 && pOut == 0)) {
231 setPartition(pIn == 0 ? outside : inside, 2); // ghost
232 addConnectivity(inside, rank(outside));
233 addConnectivity(outside, rank(inside));
234 }
235 }
236 });
237
238 // Compute interface partitions based on Codim 0 entities, this might add
239 // further ghost elements to the bulk
240 computeInterfacePartitions();
241
242 // Set facets
243 forEntityDim<dim - 1>([this](const auto& fc) {
244 const auto e = grid().entity(fc);
245 const auto is = grid().asIntersection(e);
246
247 int pIn = partition(is.inside());
248
249 if (is.neighbor()) {
250 int pOut = partition(is.outside());
251
252 // interior
253 if (pIn == 0 && pOut == 0) setPartition(e, 0);
254
255 // border
256 else if ((pIn == 0 && pOut == 2) or (pIn == 2 && pOut == 0))
257 setPartition(e, 1);
258
259 // ghost
260 else if (pIn == 2 || pOut == 2)
261 setPartition(e, 2);
262
263 // none
264 else
265 setPartition(e, -1);
266 } else {
267 // interior
268 if (pIn == 0) setPartition(e, 0);
269
270 // ghost
271 else if (pIn == 2)
272 setPartition(e, 2);
273
274 // none
275 else
276 setPartition(e, -1);
277 }
278 });
279
280 // Codim 2 in 3D
281 if constexpr (dim == 3) {
282 forEntityDim<1>([this](const auto& fc) {
283 const auto edge = grid().entity(fc);
284 std::size_t count = 0, interior = 0, ghost = 0;
285 for (const auto e : incidentElements(edge)) {
286 count++;
287 if (partition(e) == 0) interior++;
288 if (partition(e) == 2) ghost++;
289 }
290
291 // interior
292 if (interior == count) setPartition(edge, 0);
293
294 // border
295 else if (interior > 0 and ghost > 0)
296 setPartition(edge, 1);
297
298 // ghost
299 else if (interior == 0 and ghost > 0)
300 setPartition(edge, 2);
301
302 // none
303 else
304 setPartition(edge, -1);
305 });
306 }
307
308 // Set vertices
309 forEntityDim<0>([this](const auto& fc) {
310 const auto v = grid().entity(fc);
311 std::size_t count = 0, interior = 0, ghost = 0;
312 for (const auto e : incidentElements(v)) {
313 count++;
314 if (partition(e) == 0) interior++;
315 if (partition(e) == 2) ghost++;
316 }
317
318 // interior
319 if (interior == count) setPartition(v, 0);
320
321 // border
322 else if (interior > 0 and ghost > 0)
323 setPartition(v, 1);
324
325 // ghost
326 else if (interior == 0 and ghost > 0)
327 setPartition(v, 2);
328
329 // none
330 else
331 setPartition(v, -1);
332 });
333 }
334
335 public:
337 void computeInterfacePartitions() {
338 static constexpr int idim = dim - 1;
339
340 for (int i = 0; i <= idim; ++i) interfacePartition_[i].clear();
341
342 // Set interior elements
343 forEntityDim<idim>([this](const auto& fc) {
344 if (!grid().isInterface(grid().entity(fc))) return;
345
346 const auto e = grid().interfaceGrid().entity(fc);
347 const auto is = grid().asIntersection(e);
348
349 clearConnectivity(e);
350
351 if (rank(e) == grid().comm().rank()) {
352 setPartition(e, 0); // interior
353
354 // add connectivity to this entity being ghost on outside rank
355 if (is.neighbor())
356 if (rank(is.outside()) != grid().comm().rank())
357 addConnectivity(e, rank(is.outside()));
358 } else
359 setPartition(e, -1); // none
360
361 // if outside bulk entity is interior, the interface element is at least
362 // ghost
363 if (is.neighbor())
364 if (rank(is.outside()) == grid().comm().rank())
365 if (partition(e) == -1) {
366 setPartition(e, 2); // ghost
367 addConnectivity(e, rank(is.inside()));
368 }
369 });
370
371 // Set ghosts
372 forEntityDim<idim - 1>([this](const auto& fc) {
373 if (!grid().isInterface(grid().entity(fc))) return;
374
375 // convert to interface vertex
376 const auto e = grid().interfaceGrid().entity(fc);
377
378 std::size_t count = 0, interior = 0, other = 0;
379 for (const auto& incident : incidentInterfaceElements(e)) {
380 count++;
381 if (partition(incident) == 0) interior++;
382 if (partition(incident) != 0) other++;
383 }
384
385 // if we find both interior and other entities we set none to ghost
386 if (interior > 0 and other > 0)
387 for (const auto& incident : incidentInterfaceElements(e))
388 if (partition(incident) == -1) {
389 setPartition(incident, 2); // ghost
390
391 // make sure that both adjacent bulk entities are at least ghost
392 auto intersection = grid().asIntersection(incident);
393 if (partition(intersection.inside()) == -1)
394 setPartition(intersection.inside(), 2); // ghost
395 if (intersection.neighbor())
396 if (partition(intersection.outside()) == -1)
397 setPartition(intersection.outside(), 2); // ghost
398 }
399 });
400
401 // Set facets
402 forEntityDim<idim - 1>([this](const auto& fc) {
403 if (!grid().isInterface(grid().entity(fc))) return;
404
405 // convert to interface vertex
406 const auto e = grid().interfaceGrid().entity(fc);
407
408 std::size_t count = 0, interior = 0, ghost = 0;
409 std::unordered_set<int> connectivity;
410 for (const auto& incident : incidentInterfaceElements(e)) {
411 count++;
412 if (partition(incident) == 0) interior++;
413 if (partition(incident) == 2) ghost++;
414 connectivity.insert(rank(incident));
415 }
416
417 // interior
418 if (interior == count) setPartition(e, 0);
419
420 // border
421 else if (interior > 0 and ghost > 0) {
422 setPartition(e, 1);
423
424 for (const auto& incident : incidentInterfaceElements(e))
425 for (auto r : connectivity)
426 if (r != rank(incident)) addConnectivity(incident, r);
427 }
428
429 // ghost
430 else if (ghost > 0)
431 setPartition(e, 2);
432
433 // none
434 else
435 setPartition(e, -1);
436 });
437
438 // Set vertices in 3d
439 if constexpr (dim == 3) {
440 forEntityDim<idim - 2>([this](const auto& fc) {
441 if (!grid().isInterface(grid().entity(fc))) return;
442
443 const auto v = grid().interfaceGrid().entity(fc);
444
445 std::size_t count = 0, interior = 0, ghost = 0;
446 for (const auto& incident : incidentInterfaceElements(v)) {
447 count++;
448 if (partition(incident) == 0) interior++;
449 if (partition(incident) == 2) ghost++;
450 }
451
452 // interior
453 if (interior == count) setPartition(v, 0);
454
455 // border
456 else if (interior > 0 and ghost > 0)
457 setPartition(v, 1);
458
459 // ghost
460 else if (ghost > 0)
461 setPartition(v, 2);
462
463 // none
464 else
465 setPartition(v, -1);
466 });
467 }
468 }
469
470 private:
471 template <int edim, class F>
472 void forEntityDim(const F& f) {
473 if constexpr (edim == dim) {
474 if constexpr (dim == 2)
475 for (auto fc = grid().getHostGrid().finite_faces_begin();
476 fc != grid().getHostGrid().finite_faces_end(); ++fc)
477 f(fc);
478
479 if constexpr (dim == 3)
480 for (auto fc = grid().getHostGrid().finite_cells_begin();
481 fc != grid().getHostGrid().finite_cells_end(); ++fc)
482 f(fc);
483 }
484
485 if constexpr (edim == 0)
486 for (auto fc = grid().getHostGrid().finite_vertices_begin();
487 fc != grid().getHostGrid().finite_vertices_end(); ++fc)
488 f(fc);
489
490 if constexpr (edim == 1)
491 for (auto fc = grid().getHostGrid().finite_edges_begin();
492 fc != grid().getHostGrid().finite_edges_end(); ++fc)
493 f(*fc);
494
495 if constexpr (dim == 3 && edim == 2)
496 for (auto fc = grid().getHostGrid().finite_facets_begin();
497 fc != grid().getHostGrid().finite_facets_end(); ++fc)
498 f(*fc);
499 }
500
501 const Grid& grid() const { return grid_; }
502
503 std::array<double, 2> xbounds_;
504 std::array<std::unordered_map<IdType, int>, dim - 1> partition_;
505 std::array<std::unordered_map<IdType, int>, dim> interfacePartition_;
506 std::unordered_map<IdType, ConnectivityType> interfaceConnectivity_;
507 LeafIterator leafBegin_, leafEnd_;
508 LinksType links_;
509 const Grid& grid_;
510};
511
512} // end namespace Dune
513
514#endif
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Sep 5, 22:35, 2025)