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