version 3.11-dev
coloring.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//
12#ifndef DUMUX_ASSEMBLY_COLORING_HH
13#define DUMUX_ASSEMBLY_COLORING_HH
14
15#include <vector>
16#include <deque>
17#include <iostream>
18#include <tuple>
19#include <algorithm>
20
21#include <dune/common/timer.hh>
22#include <dune/common/exceptions.hh>
23
24#include <dumux/io/format.hh>
26
27#ifndef DOXYGEN // hide from doxygen
28namespace Dumux::Detail {
29
31template <class GridGeometry>
32std::vector<std::vector<std::size_t>>
33computeConnectedElements(const GridGeometry& gg)
34{
35 std::vector<std::vector<std::size_t>> connectedElements;
36
37 if constexpr (GridGeometry::discMethod == DiscretizationMethods::cctpfa)
38 {
39 connectedElements.resize(gg.gridView().size(0));
40 const auto& eMapper = gg.elementMapper();
41 for (const auto& element : elements(gg.gridView()))
42 {
43 const auto eIdx = eMapper.index(element);
44 for (const auto& intersection : intersections(gg.gridView(), element))
45 if (intersection.neighbor())
46 connectedElements[eMapper.index(intersection.outside())].push_back(eIdx);
47 }
48 }
49
50 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::box
51 || GridGeometry::discMethod == DiscretizationMethods::pq1bubble
52 || GridGeometry::discMethod == DiscretizationMethods::pq2)
53 {
54 static constexpr int dim = GridGeometry::GridView::dimension;
55 connectedElements.resize(gg.gridView().size(dim));
56 const auto& vMapper = gg.vertexMapper();
57 for (const auto& element : elements(gg.gridView()))
58 {
59 const auto eIdx = gg.elementMapper().index(element);
60 for (int i = 0; i < element.subEntities(dim); i++)
61 connectedElements[vMapper.subIndex(element, i, dim)].push_back(eIdx);
62 }
63 }
64
65 else if constexpr (
66 GridGeometry::discMethod == DiscretizationMethods::fcstaggered
67 || GridGeometry::discMethod == DiscretizationMethods::ccmpfa
68 )
69 {
70 // for MPFA-O schemes the assembly of each element residual touches all vertex neighbors
71 // for face-centered staggered it is all codim-2 neighbors (vertex neighbors in 2D, edge neighbors in 3D)
72 // but we use vertex neighbors also in 3D for simplicity
73 std::vector<std::vector<std::size_t>> vToElements;
74 static constexpr int dim = GridGeometry::GridView::dimension;
75 vToElements.resize(gg.gridView().size(dim));
76 const auto& vMapper = gg.vertexMapper();
77 for (const auto& element : elements(gg.gridView()))
78 {
79 const auto eIdx = gg.elementMapper().index(element);
80 for (int i = 0; i < element.subEntities(dim); i++)
81 vToElements[vMapper.subIndex(element, i, dim)].push_back(eIdx);
82 }
83
84 connectedElements.resize(gg.gridView().size(0));
85 for (const auto& element : elements(gg.gridView()))
86 {
87 const auto eIdx = gg.elementMapper().index(element);
88 for (int i = 0; i < element.subEntities(dim); i++)
89 {
90 const auto& e = vToElements[vMapper.subIndex(element, i, dim)];
91 connectedElements[eIdx].insert(connectedElements[eIdx].end(), e.begin(), e.end());
92 }
93
94 // make unique
95 std::sort(connectedElements[eIdx].begin(), connectedElements[eIdx].end());
96 connectedElements[eIdx].erase(
97 std::unique(connectedElements[eIdx].begin(), connectedElements[eIdx].end()),
98 connectedElements[eIdx].end()
99 );
100 }
101 }
102
103 // nothing has to be precomputed here as only immediate face neighbors are connected
104 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::fcdiamond)
105 return connectedElements;
106
107 else
108 DUNE_THROW(Dune::NotImplemented,
109 "Missing coloring scheme implementation for this discretization method"
110 );
111
112 return connectedElements;
113}
114
127template<class GridGeometry, class ConnectedElements>
128void addNeighborColors(const GridGeometry& gg,
129 const typename GridGeometry::LocalView::Element& element,
130 const std::vector<int>& colors,
131 const ConnectedElements& connectedElements,
132 std::vector<int>& neighborColors)
133{
134 if constexpr (
135 GridGeometry::discMethod == DiscretizationMethods::cctpfa
136 || GridGeometry::discMethod == DiscretizationMethods::ccmpfa
137 || GridGeometry::discMethod == DiscretizationMethods::fcstaggered
138 )
139 {
140 // we modify neighbor elements during the assembly
141 // check who else modifies these neighbor elements
142 const auto& eMapper = gg.elementMapper();
143 for (const auto& intersection : intersections(gg.gridView(), element))
144 {
145 if (intersection.neighbor())
146 {
147 // direct face neighbors
148 const auto nIdx = eMapper.index(intersection.outside());
149 neighborColors.push_back(colors[nIdx]);
150
151 // neighbor-neighbors
152 for (const auto nnIdx : connectedElements[eMapper.index(intersection.outside())])
153 neighborColors.push_back(colors[nnIdx]);
154 }
155 }
156 }
157
158 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::box
159 || GridGeometry::discMethod == DiscretizationMethods::pq1bubble
160 || GridGeometry::discMethod == DiscretizationMethods::pq2)
161 {
162 // we modify the vertex dofs of our element during the assembly
163 // check who else modifies these vertex dofs
164 const auto& vMapper = gg.vertexMapper();
165 static constexpr int dim = GridGeometry::GridView::dimension;
166 // direct vertex neighbors
167 for (int i = 0; i < element.subEntities(dim); i++)
168 for (auto eIdx : connectedElements[vMapper.subIndex(element, i, dim)])
169 neighborColors.push_back(colors[eIdx]);
170 }
171
172 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::fcdiamond)
173 {
174 // we modify neighbor faces during the assembly
175 // check who else modifies these neighbor elements
176 const auto& eMapper = gg.elementMapper();
177 for (const auto& intersection : intersections(gg.gridView(), element))
178 if (intersection.neighbor())
179 neighborColors.push_back(colors[eMapper.index(intersection.outside())]);
180 }
181
182 else
183 DUNE_THROW(Dune::NotImplemented,
184 "Missing coloring scheme implementation for this discretization method"
185 );
186}
187
193int smallestAvailableColor(const std::vector<int>& colors,
194 std::vector<bool>& colorUsed)
195{
196 const int numColors = colors.size();
197 colorUsed.assign(numColors, false);
198
199 // The worst case for e.g. numColors=3 is colors={0, 1, 2}
200 // in which case we return 3 as smallest available color
201 // That means, we only track candidates in the (half-open) interval [0, numColors)
202 // Mark candidate colors which are present in colors
203 for (int i = 0; i < numColors; i++)
204 if (colors[i] >= 0 && colors[i] < numColors)
205 colorUsed[colors[i]] = true;
206
207 // return smallest color not in colors
208 for (int i = 0; i < numColors; i++)
209 if (!colorUsed[i])
210 return i;
211
212 return numColors;
213}
214
215} // end namespace Dumux::Detail
216#endif // DOXYGEN
217
218namespace Dumux {
219
240template<class GridGeometry>
241auto computeColoring(const GridGeometry& gg, int verbosity = 1)
242{
243 Dune::Timer timer;
244
245 using ElementSeed = typename GridGeometry::GridView::Grid::template Codim<0>::EntitySeed;
246 struct Coloring
247 {
248 using Sets = std::deque<std::vector<ElementSeed>>;
249 using Colors = std::vector<int>;
250
251 Coloring(std::size_t size) : sets{}, colors(size, -1) {}
252
253 Sets sets;
254 Colors colors;
255 };
256
257 Coloring coloring(gg.gridView().size(0));
258
259 // pre-reserve some memory for helper arrays to avoid reallocation
260 std::vector<int> neighborColors; neighborColors.reserve(30);
261 std::vector<bool> colorUsed; colorUsed.reserve(30);
262
263 // dof to element map to speed up neighbor search
264 const auto connectedElements = Detail::computeConnectedElements(gg);
265
266 for (const auto& element : elements(gg.gridView()))
267 {
268 // compute neighbor colors based on discretization-dependent stencil
269 neighborColors.clear();
270 Detail::addNeighborColors(gg, element, coloring.colors, connectedElements, neighborColors);
271
272 // find smallest color (positive integer) not in neighborColors
273 const auto color = Detail::smallestAvailableColor(neighborColors, colorUsed);
274
275 // assign color to element
276 coloring.colors[gg.elementMapper().index(element)] = color;
277
278 // add element to the set of elements with the same color
279 if (color < coloring.sets.size())
280 coloring.sets[color].push_back(element.seed());
281 else
282 coloring.sets.push_back(std::vector<ElementSeed>{ element.seed() });
283 }
284
285 if (verbosity > 0)
286 std::cout << Fmt::format("Colored {} elements with {} colors in {} seconds.\n",
287 gg.gridView().size(0), coloring.sets.size(), timer.elapsed());
288
289 return coloring;
290}
291
293template<class DiscretizationMethod>
294struct SupportsColoring : public std::false_type {};
295
296template<> struct SupportsColoring<DiscretizationMethods::CCTpfa> : public std::true_type {};
297template<> struct SupportsColoring<DiscretizationMethods::CCMpfa> : public std::true_type {};
298template<> struct SupportsColoring<DiscretizationMethods::Box> : public std::true_type {};
299template<> struct SupportsColoring<DiscretizationMethods::FCStaggered> : public std::true_type {};
300template<> struct SupportsColoring<DiscretizationMethods::FCDiamond> : public std::true_type {};
301template<> struct SupportsColoring<DiscretizationMethods::PQ1Bubble> : public std::true_type {};
302template<> struct SupportsColoring<DiscretizationMethods::PQ2> : public std::true_type {};
303
304} // end namespace Dumux
305
306#endif
Formatting based on the fmt-library which implements std::format of C++20.
The available discretization methods in Dumux.
Definition: cvfelocalresidual.hh:30
constexpr CCMpfa ccmpfa
Definition: method.hh:155
constexpr FCDiamond fcdiamond
Definition: method.hh:162
constexpr PQ2 pq2
Definition: method.hh:157
constexpr CCTpfa cctpfa
Definition: method.hh:154
CVFE< CVFEMethods::CR_RT > FCDiamond
Definition: method.hh:105
constexpr Box box
Definition: method.hh:156
CVFE< CVFEMethods::PQ1 > Box
Definition: method.hh:98
CVFE< CVFEMethods::PQ2 > PQ2
Definition: method.hh:118
CVFE< CVFEMethods::PQ1Bubble > PQ1Bubble
Definition: method.hh:112
constexpr PQ1Bubble pq1bubble
Definition: method.hh:158
constexpr FCStaggered fcstaggered
Definition: method.hh:161
Definition: adapt.hh:17
auto computeColoring(const GridGeometry &gg, int verbosity=1)
Compute iterable lists of element seeds partitioned by color.
Definition: coloring.hh:241
Traits specifying if a given discretization tag supports coloring.
Definition: coloring.hh:294