dune-pdelab 2.10-git
Loading...
Searching...
No Matches
metis.hh
Go to the documentation of this file.
1#ifndef DUNE_PDELAB_COMMON_PARTITION_METIS_HH
2#define DUNE_PDELAB_COMMON_PARTITION_METIS_HH
3
4
8
9#include <dune/grid/concepts/entity.hh>
10#include <dune/grid/concepts/gridview.hh>
12
14#include <dune/common/metis.hh>
15
16#if !HAVE_METIS
17#error This file should only be included if metis is available
18#endif
19
20#include <vector>
21#include <memory>
22
24
25namespace Impl {
26
36template<Dune::Concept::GridView EntitySet, Dune::Concept::Entity Entity>
37class EntitySeedContainer {
38 using EntitySeed = typename Entity::EntitySeed;
39
40 // Iterator over entity seeds
41 class ConstIterator : public RandomAccessIteratorFacade<ConstIterator, Entity, Entity> {
42 using typename RandomAccessIteratorFacade<ConstIterator, Entity, Entity>::DifferenceType;
43 public:
44
45 // Construct an iterator from a seed iterator and a entity set
46 explicit ConstIterator(typename std::vector<EntitySeed>::const_iterator seed_it, const EntitySet& entity_set)
47 : _entity_set{&entity_set}
48 , _seed_it{std::move(seed_it)}
49 {}
50
51 // Default constructor
52 explicit ConstIterator() {}
53
54 // Iterator concept methods
55 bool equals(const ConstIterator &other) const
56 {
57 return _seed_it == other._seed_it;
58 }
59
60 // Dereference to get an entity
61 Entity dereference() const {
62 return _entity_set->grid().entity(*_seed_it);
63 }
64
65 // Advance the iterator
66 void increment() {
67 ++_seed_it;
68 }
69
70 // Decrement the iterator
71 void decrement(){
72 --_seed_it;
73 }
74
75 // Advance the iterator by n positions
76 void advance(DifferenceType n) {
77 std::advance(_seed_it, n);
78 }
79
80 // Get the distance to another iterator
81 DifferenceType distanceTo(const ConstIterator& other) const {
82 return std::distance(_seed_it, other._seed_it);
83 }
84
85 private:
86 EntitySet const * _entity_set;
88 };
89
90public:
91
92 // Construct an empty container for entity seeds
93 explicit EntitySeedContainer(const EntitySet& entity_set, std::vector<EntitySeed>&& seeds)
94 : _entity_set{entity_set}
95 , _seeds{std::move(seeds)}
96 {}
97
98 // Begin of the entity seed container
99 [[nodiscard]] ConstIterator begin() const {
100 return ConstIterator{_seeds.begin(), _entity_set};
101 }
102
103 // End of the entity seed container
104 [[nodiscard]] ConstIterator end() const {
105 return ConstIterator{_seeds.end(), _entity_set};
106 }
107
108 [[nodiscard]] std::size_t size() const {
109 return _seeds.size();
110 }
111
112private:
113 EntitySet _entity_set;
115};
116
117
125template<Dune::Concept::GridView ES>
126class MetisMixin {
127public:
129 using EntitySet = ES;
131 using Element = typename EntitySet::template Codim<0>::Entity;
133 using PatchSet = EntitySeedContainer<EntitySet, Element>;
135 using LabelSet = std::vector<PatchSet>;
137 using PartitionSet = std::array<LabelSet,1>;
138
145 explicit MetisMixin(const EntitySet& entity_set, std::size_t patches)
146 : _entity_set{entity_set}
147 , _patches{patches}
148 {
149 update(_entity_set);
150 }
151
153 [[nodiscard]] EntitySet entitySet() const noexcept { return _entity_set; }
154
156 [[nodiscard]] auto begin() const {
157 return _partition_set->begin();
158 }
159
161 [[nodiscard]] auto end() const {
162 return _partition_set->end();
163 }
164
165protected:
172 void update(EntitySet entity_set) {
173
174 _entity_set = entity_set;
175 if (_patches == 0) {
176 std::size_t entities_per_patch = 100;
177 switch(EntitySet::dimension) {
178 case 1: entities_per_patch = 125; break;
179 case 2: entities_per_patch = 250; break;
180 default: entities_per_patch = 500; break;
181 }
182 _patches = std::max<std::size_t>(1,entity_set.size(0) / entities_per_patch);
183 }
184 if (_patches == 1) {
185 // all entities in one patch
186 _partition_set = std::make_shared<PartitionSet>();
187
188 // set entity seeds to each assigned patch
190 for (const auto& element : elements(_entity_set))
191 seeds.emplace_back(element.seed());
192
193 _partition_set = std::make_shared<PartitionSet>();
194 (*_partition_set)[0] = LabelSet{PatchSet{_entity_set, std::move(seeds)}};
195 return;
196 }
197
198
199 const std::size_t dimension = EntitySet::dimension;
201 // setup METIS parameters
202 idx_t parts = _patches; // number of partitions
203 idx_t ncommonnodes = 2; // number of nodes elements must have in common to be considered adjacent to each other
204 idx_t edgecut = std::numeric_limits<idx_t>::max(); // will store number of edges cut by partition
205
206 std::vector<idx_t> cells, nodes, element_part, node_part;
208 cells.reserve(_entity_set.size(0));
209 nodes.reserve(_entity_set.size(dimension));
210
211 // create graph of elements and vertices
212 int vertices = 0;
213 cells.push_back(vertices);
214 for (const auto& element : elements(_entity_set)) {
215 const auto& ref_element = referenceElement<double, dimension>(element.type());
216 edgecut = std::min<idx_t>(edgecut, ref_element.size(1));
217 vertices += ref_element.size(dimension);
218 cells.push_back(vertices);
219 seeds.emplace_back(element.seed());
220
221 for (int k = 0; k != ref_element.size(dimension); ++k)
222 nodes.push_back(_entity_set.indexSet().subIndex(element, k, dimension));
223 }
224
225 idx_t element_count = cells.size()-1;
226 idx_t node_count = nodes.size();
227 element_part.assign(element_count, 0);
228 node_part.assign(node_count, 0);
229
230 // actual partition of elements
231#if (!HAVE_SCOTCH_METIS) || (HAVE_SCOTCH_METIS && SCOTCH_VERSION >= 7)
232 // METIS 5+ supports dual graph partitioning of meshes, but in case we use scotch, it's only implemented in 7+
233 auto result = METIS_PartMeshDual(
234 &element_count,
235 &node_count,
236 cells.data(),
237 nodes.data(),
238 nullptr,
239 nullptr,
240 &ncommonnodes,
241 &parts,
242 nullptr,
243 nullptr,
244 &edgecut,
245 element_part.data(),
246 node_part.data()
247 );
248
249 if (result != METIS_OK)
250 DUNE_THROW(PartitionError, "Metis could not partition the grid");
251#else
252 DUNE_THROW(PartitionError, "Metis version does not support mesh partitioning, please update to metis 5+ or scotch 7+");
253#endif
254
255 // assign entity seeds to each patch
257 for (std::size_t i = 0; i != element_part.size(); ++i)
258 seed_patches[element_part[i]].emplace_back(std::move(seeds[i]));
259
260 // move seeds into patch sets
261 _partition_set = std::make_shared<PartitionSet>();
262 for (std::size_t i = 0; i != _patches; ++i)
263 (*_partition_set)[0].emplace_back(_entity_set, std::move(seed_patches[i]));
264 }
265
266private:
267 std::shared_ptr<PartitionSet> _partition_set;
268 EntitySet _entity_set;
269 std::size_t _patches;
270};
271
272} //namespace Impl
273
274
283template<Dune::Concept::GridView EntitySet>
284struct Metis
285 : public Impl::MetisMixin<EntitySet>
286 , public Impl::UncoloredHaloMixin<EntitySet>
287{
295 explicit Metis(const EntitySet& entity_set, std::size_t patches = 0, std::size_t halo_distance = all_interior_halo_region)
296 : Impl::MetisMixin<EntitySet>{entity_set, patches}
297 , Impl::UncoloredHaloMixin<EntitySet>::UncoloredHaloMixin{halo_distance}
298 {
299 update(entity_set);
300 }
301
303 void update(const EntitySet& entity_set) {
304 Impl::MetisMixin<EntitySet>::update(entity_set);
305 Impl::UncoloredHaloMixin<EntitySet>::updateHalo(*this);
306 }
307};
308
317template<Dune::Concept::GridView EntitySet>
319 : public Impl::ColoredHaloAdaptor<Impl::MetisMixin<EntitySet>>
320{
321
329 explicit MetisColored(const EntitySet& entity_set, std::size_t patches = 0, std::size_t halo_distance = all_interior_halo_region)
330 : Impl::ColoredHaloAdaptor<Impl::MetisMixin<EntitySet>>{Impl::MetisMixin<EntitySet>{entity_set, patches}, halo_distance}
331 , _patches{patches}
332 {}
333
335 void update(const EntitySet& entity_set) {
336 Impl::MetisMixin<EntitySet> base(entity_set, _patches);
337 Impl::ColoredHaloAdaptor<Impl::MetisMixin<EntitySet>>::update(std::move(base));
338 }
339
340private:
341 std::size_t _patches;
342};
343
344
345} // namespace Dune::PDELab::EntitySetPartition
346
347#endif // DUNE_PDELAB_COMMON_PARTITION_METIS_HH
Hierarchy< Domain, A >::Iterator update
void seed(const Vertex &vertex)
T & dereference() const
void decrement()
bool equals(const SLListConstIterator< T, A > &other) const
void increment()
difference_type distanceTo(const ArrayListIterator< T, N, A > &other) const
#define DUNE_THROW(E,...)
STL namespace.
Definition colored.hh:16
static constexpr std::size_t all_interior_halo_region
Constant for a halo distance with all halo regions being in the interior.
Definition region.hh:21
IteratorRange<... > vertices(const GV &gv)
IteratorRange<... > elements(const GV &gv)
ALBERTA EL Element
GridImp::template Codim< cd >::Entity Entity
Partition set with entities split on several patches using METIS.
Definition metis.hh:287
void update(const EntitySet &entity_set)
Update the partition with a new entity set.
Definition metis.hh:303
Metis(const EntitySet &entity_set, std::size_t patches=0, std::size_t halo_distance=all_interior_halo_region)
Construct a Metis uncolored entity set partition.
Definition metis.hh:295
Colored partition set with entities split on several patches using METIS.
Definition metis.hh:320
MetisColored(const EntitySet &entity_set, std::size_t patches=0, std::size_t halo_distance=all_interior_halo_region)
Construct a Metis colored entiy set partition.
Definition metis.hh:329
void update(const EntitySet &entity_set)
Update the partition with a new entity set.
Definition metis.hh:335
T advance(T... args)
T assign(T... args)
T begin(T... args)
T data(T... args)
T distance(T... args)
T emplace_back(T... args)
T end(T... args)
T max(T... args)
T move(T... args)
T push_back(T... args)
T reserve(T... args)
T size(T... args)