dune-pdelab 2.10-git
Loading...
Searching...
No Matches
colored.hh
Go to the documentation of this file.
1#ifndef DUNE_PDELAB_COMMON_PARTITION_HALO_COLORED_HH
2#define DUNE_PDELAB_COMMON_PARTITION_HALO_COLORED_HH
3
5
7
9#include <dune/grid/concepts/entity.hh>
10
11#include <set>
12#include <span>
13#include <vector>
14
15
17
19struct ColoringError : public PartitionError {};
20
21namespace Impl {
22
30template<class BasePartition>
31class ColoredHaloAdaptor {
32public:
34 using EntitySet = typename BasePartition::EntitySet;
36 using Element = typename BasePartition::Element;
38 using PatchSet = typename BasePartition::PatchSet;
40 using LabelSet = std::vector<PatchSet>;
43
44
51 explicit ColoredHaloAdaptor(BasePartition&& base, std::size_t halo_distance)
52 : _entity_set{base.entitySet()}
53 , _halo_distance{halo_distance}
54 {
55 update(std::move(base));
56 }
57
59 [[nodiscard]] constexpr static auto haloRegion(const Dune::Concept::Entity auto& entity) {
61 }
62
64 [[nodiscard]] EntitySet entitySet() const noexcept { return _entity_set; }
65
67 [[nodiscard]] auto begin() const { return _partition_set->begin(); }
68
70 [[nodiscard]] auto end() const { return _partition_set->end(); }
71
72private:
73
74 // A simple graph representation using CSR format
75 class Graph {
76 public:
77 Graph(std::vector<std::size_t>&& row_ptr, std::vector<std::size_t>&& col_idx)
78 : row_ptr_(std::move(row_ptr)), col_idx_(std::move(col_idx)) {}
79
80 auto operator[](std::size_t vertex) const {
81 return std::span(col_idx_.data() + row_ptr_[vertex], col_idx_.data() + row_ptr_[vertex + 1]);
82 }
83
84 auto size() const { return row_ptr_.size() - 1; }
85 private:
88 };
89
90protected:
91
92 void update(BasePartition&& base) {
93 // post-condition: patches in the same color do not have entities in their halo
94 _entity_set = base.entitySet();
95
96 if (_halo_distance == all_overlap_halo_region) {
97 DUNE_THROW(PartitionError, "ColoredHaloAdaptor does not support all-overlap halo region.");
98 } else if (_halo_distance == all_interior_halo_region) {
99 // all patches must be in one label
100 _partition_set = std::make_shared<PartitionSet>(1);
101 for (auto& label_set : base)
102 for (auto& patch_set : label_set)
103 (*_partition_set)[0].emplace_back(std::move(patch_set));
104 return;
105 }
106
107 // build connectivity graph between patches
108 Graph graph = makeGraph(base, _halo_distance);
109
110 // perfom actual coloring
111 auto [colors, color_count] = makeColors(graph);
112
113 // assing colored partitions
114 _partition_set = std::make_shared<PartitionSet>(color_count);
115 std::size_t patch = 0;
116 for (auto& label_set : base)
117 for (auto& patch_set : label_set)
118 (*_partition_set)[colors[patch++]].emplace_back(std::move(patch_set));
119 }
120
121private:
122
123 // build connectivity graph between patches based on shared entities in their halo
124 Graph makeGraph(const BasePartition& base, std::size_t halo_distance) {
125
126 std::size_t patch = 0;
127 for (auto& label_set : base)
128 patch += std::distance(label_set.begin(), label_set.end());
129
130 auto all_entities_layout = [](GeometryType gt, int dimgrid) { return true; };
131 Dune::MultipleCodimMultipleGeomTypeMapper<EntitySet> all_mapper(base.entitySet(), all_entities_layout);
132
133 // build connectivity between patches based on shared entities in their halo
134 Dune::MatrixIndexSet patch_links(patch, patch);
135 Dune::MatrixIndexSet entity_owners(all_mapper.size(), patch);
136
137 // if an entity is owned by different patches, it is in the overlap and a link between patches is made
138 auto mark_entity_overlap = [&](const Element& entity, std::size_t id) {
140 for (const auto& sub_entity : subEntities(entity, Dune::Codim<codim>{})) {
141 auto entity_index = all_mapper.index(sub_entity);
142 std::visit([&](const auto& owners){
143 for (auto owner : owners) {
144 patch_links.add(owner,id);
145 patch_links.add(id,owner);
146 }
147 }, entity_owners.columnIndices(entity_index));
148 entity_owners.add(entity_index, id);
149 }
150 });
151 };
152
153 // propagate the overlap on neighboring entities recursively until the halo distance is reached
154 std::function<void(const Element&,std::size_t,std::size_t)> mark_overlap;
155 mark_overlap = [&](const Element& entity, std::size_t id, std::size_t halo_distance) {
156 mark_entity_overlap(entity, id);
157 if (halo_distance != 0) {
158 for (const auto& intersection : intersections(base.entitySet(), entity))
159 if (intersection.neighbor())
160 mark_overlap(intersection.outside(), id, halo_distance-1);
161 }
162 };
163
164 patch = 0;
165 for (const auto& label_set : base) {
166 for (const auto& patch_set : label_set) {
167 for (const auto& entity : patch_set) {
168 mark_overlap(entity, patch, _halo_distance);
169 }
170 ++patch;
171 }
172 }
173
174 // build graph from connectivity
175 std::vector<std::size_t> row_ptr(patch_links.rows() + 1, 0);
177 col_idx.reserve(patch_links.size());
178
179 for (std::size_t i = 0; i != patch_links.rows(); ++i) {
180 std::visit([&](const auto& neighbors){
181 row_ptr[i+1] = row_ptr[i] + neighbors.size();
182 col_idx.insert(col_idx.end(), neighbors.begin(), neighbors.end());
183 }, patch_links.columnIndices(i));
184 }
185 return Graph{std::move(row_ptr), std::move(col_idx)};
186 }
187
188 // use DSatur to color graph (https://en.wikipedia.org/wiki/DSatur#Pseudocode)
189 auto makeColors(const auto& graph) {
192 std::vector<std::size_t> color(graph.size(), uncolored);
193 std::vector<unsigned char> degree(graph.size(), 0);
194 Dune::MatrixIndexSet adjacent_colors(graph.size(), graph.size());
195 std::vector<bool> used(graph.size(), false);
196 std::size_t max_color = 0;
197
198 // // Struct to store information
200
201 // initialize the priority queue with saturation degree 0 and degree of each vertex
202 for (std::size_t vertex = 0; vertex != graph.size(); ++vertex) {
203 if (graph[vertex].size() >= max_degree)
204 DUNE_THROW(ColoringError,
205 "Vertex " << vertex << " has degree " << graph[vertex].size()
206 << " which exceeds the maximum supported degree of " << max_degree << " for coloring.");
207 degree[vertex] = graph[vertex].size();
209 }
210
211 // process all vertices in the queue
212 while (not queue.empty()) {
213 // choose the vertex with highest saturation degree, breaking ties with its degree
214 // and remove it from the priority queue
215 auto it = queue.begin();
216 std::size_t node = (*it)[2];
217 queue.erase(it);
218
219 // mark used colors by neighbors
220 for (std::size_t neighbor : graph[node])
221 if (color[neighbor] != uncolored)
222 used[color[neighbor]] = true;
223 // identify the lowest feasible colour for this node
224 std::size_t this_color = 0;
225 while (this_color != used.size() && used[this_color])
226 ++this_color;
227 // reset used colors by neighbors
228 for (std::size_t neighbor : graph[node])
229 if (color[neighbor] != uncolored)
230 used[color[neighbor]] = false;
231
232 // assign color to node
233 color[node] = this_color;
234 max_color = std::max(max_color, this_color);
235
236 // update priority queue: neighbor saturation and degrees change with the coloring of this node
237 for (std::size_t neighbor : graph[node]) {
238 if (color[neighbor] == uncolored) {
239 auto it = queue.find( std::array<std::size_t, 3>{ adjacent_colors.rowsize(neighbor), degree[neighbor], neighbor });
240 auto suggest_it = std::next(it);
241 queue.erase(it);
242 adjacent_colors.add(neighbor, this_color);
243 degree[neighbor]--;
244 queue.emplace_hint( suggest_it, std::array<std::size_t, 3>{ adjacent_colors.rowsize(neighbor), degree[neighbor], neighbor });
245 }
246 }
247 }
248
249 // check post-condition: vertices do not neighbor any vertex with the same color
250 for (std::size_t vertex = 0; vertex != graph.size(); ++vertex)
251 for(auto neighbor : graph[vertex]) {
252 if (vertex != neighbor and color[vertex] == color[neighbor])
253 DUNE_THROW(ColoringError, "Coloring is incorrect!");
254 if (color[vertex] == uncolored)
255 DUNE_THROW(ColoringError, "Vertex " << vertex << " is uncolored!");
256 if (color[vertex] >= max_color+1)
257 DUNE_THROW(ColoringError, "Vertex " << vertex << " is an unexpected color!");
258 }
259
260 return std::make_tuple(std::move(color), max_color+1);
261 }
262
263private:
264 EntitySet _entity_set;
265 std::shared_ptr<PartitionSet> _partition_set;
266 std::size_t _halo_distance;
267};
268
269} // namespace Impl
270} // namespace Dune::PDELab::EntitySetPartition
271
272#endif // DUNE_PDELAB_COMMON_PARTITION_HALO_COLORED_HH
std::size_t degree(const Node &node)
int id()
Hierarchy< Domain, A >::Iterator update
reference operator[](size_type i)
int size() const
constexpr void forEach(Range &&range, F &&f)
bool gt(const T &first, const T &second, typename EpsilonType< T >::Type epsilon=DefaultEpsilon< T, style >::value())
#define DUNE_THROW(E,...)
STL namespace.
For backward compatibility – Do not use this!
Definition colored.hh:16
static constexpr std::size_t all_overlap_halo_region
Constant for a halo distance with all halo regions being in the overlap.
Definition region.hh:24
static constexpr std::integral_constant< HaloRegion, HaloRegion::Interior > interior_halo_region
Constant for interior halo region.
Definition region.hh:15
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<... > intersections(const GV &gv, const Entity &e)
IteratorRange<... > subEntities(const E &e, Codim< codim > c)
ALBERTA EL Element
Exception for coloring errors.
Definition colored.hh:19
Exception for partition errors.
Definition region.hh:27
T begin(T... args)
T distance(T... args)
T emplace_hint(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
T insert(T... args)
T make_tuple(T... args)
T max(T... args)
T move(T... args)
T next(T... args)
T reserve(T... args)
T visit(T... args)