3.6-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_ASSEMBLY_COLORING_HH
25#define DUMUX_ASSEMBLY_COLORING_HH
26
27#include <vector>
28#include <deque>
29#include <iostream>
30#include <tuple>
31#include <algorithm>
32
33#include <dune/common/timer.hh>
34#include <dune/common/exceptions.hh>
35
36#include <dumux/io/format.hh>
38
39#ifndef DOXYGEN // hide from doxygen
40namespace Dumux::Detail {
41
43template <class GridGeometry>
44std::vector<std::vector<std::size_t>>
45computeConnectedElements(const GridGeometry& gg)
46{
47 std::vector<std::vector<std::size_t>> connectedElements;
48
49 if constexpr (GridGeometry::discMethod == DiscretizationMethods::cctpfa)
50 {
51 connectedElements.resize(gg.gridView().size(0));
52 const auto& eMapper = gg.elementMapper();
53 for (const auto& element : elements(gg.gridView()))
54 {
55 const auto eIdx = eMapper.index(element);
56 for (const auto& intersection : intersections(gg.gridView(), element))
57 if (intersection.neighbor())
58 connectedElements[eMapper.index(intersection.outside())].push_back(eIdx);
59 }
60 }
61
62 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::box
63 || GridGeometry::discMethod == DiscretizationMethods::pq1bubble)
64 {
65 static constexpr int dim = GridGeometry::GridView::dimension;
66 connectedElements.resize(gg.gridView().size(dim));
67 const auto& vMapper = gg.vertexMapper();
68 for (const auto& element : elements(gg.gridView()))
69 {
70 const auto eIdx = gg.elementMapper().index(element);
71 for (int i = 0; i < element.subEntities(dim); i++)
72 connectedElements[vMapper.subIndex(element, i, dim)].push_back(eIdx);
73 }
74 }
75
76 else if constexpr (
77 GridGeometry::discMethod == DiscretizationMethods::fcstaggered
78 || GridGeometry::discMethod == DiscretizationMethods::ccmpfa
79 )
80 {
81 // for MPFA-O schemes the assembly of each element residual touches all vertex neighbors
82 // for face-centered staggered it is all codim-2 neighbors (vertex neighbors in 2D, edge neighbors in 3D)
83 // but we use vertex neighbors also in 3D for simplicity
84 std::vector<std::vector<std::size_t>> vToElements;
85 static constexpr int dim = GridGeometry::GridView::dimension;
86 vToElements.resize(gg.gridView().size(dim));
87 const auto& vMapper = gg.vertexMapper();
88 for (const auto& element : elements(gg.gridView()))
89 {
90 const auto eIdx = gg.elementMapper().index(element);
91 for (int i = 0; i < element.subEntities(dim); i++)
92 vToElements[vMapper.subIndex(element, i, dim)].push_back(eIdx);
93 }
94
95 connectedElements.resize(gg.gridView().size(0));
96 for (const auto& element : elements(gg.gridView()))
97 {
98 const auto eIdx = gg.elementMapper().index(element);
99 for (int i = 0; i < element.subEntities(dim); i++)
100 {
101 const auto& e = vToElements[vMapper.subIndex(element, i, dim)];
102 connectedElements[eIdx].insert(connectedElements[eIdx].end(), e.begin(), e.end());
103 }
104
105 // make unique
106 std::sort(connectedElements[eIdx].begin(), connectedElements[eIdx].end());
107 connectedElements[eIdx].erase(
108 std::unique(connectedElements[eIdx].begin(), connectedElements[eIdx].end()),
109 connectedElements[eIdx].end()
110 );
111 }
112 }
113
114 // nothing has to be precomputed here as only immediate face neighbors are connected
115 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::fcdiamond)
116 return connectedElements;
117
118 else
119 DUNE_THROW(Dune::NotImplemented,
120 "Missing coloring scheme implementation for this discretization method"
121 );
122
123 return connectedElements;
124}
125
138template<class GridGeometry, class ConnectedElements>
139void addNeighborColors(const GridGeometry& gg,
140 const typename GridGeometry::LocalView::Element& element,
141 const std::vector<int>& colors,
142 const ConnectedElements& connectedElements,
143 std::vector<int>& neighborColors)
144{
145 if constexpr (
146 GridGeometry::discMethod == DiscretizationMethods::cctpfa
147 || GridGeometry::discMethod == DiscretizationMethods::ccmpfa
148 || GridGeometry::discMethod == DiscretizationMethods::fcstaggered
149 )
150 {
151 // we modify neighbor elements during the assembly
152 // check who else modifies these neighbor elements
153 const auto& eMapper = gg.elementMapper();
154 for (const auto& intersection : intersections(gg.gridView(), element))
155 {
156 if (intersection.neighbor())
157 {
158 // direct face neighbors
159 const auto nIdx = eMapper.index(intersection.outside());
160 neighborColors.push_back(colors[nIdx]);
161
162 // neighbor-neighbors
163 for (const auto nnIdx : connectedElements[eMapper.index(intersection.outside())])
164 neighborColors.push_back(colors[nnIdx]);
165 }
166 }
167 }
168
169 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::box
170 || GridGeometry::discMethod == DiscretizationMethods::pq1bubble)
171 {
172 // we modify the vertex dofs of our element during the assembly
173 // check who else modifies these vertex dofs
174 const auto& vMapper = gg.vertexMapper();
175 static constexpr int dim = GridGeometry::GridView::dimension;
176 // direct vertex neighbors
177 for (int i = 0; i < element.subEntities(dim); i++)
178 for (auto eIdx : connectedElements[vMapper.subIndex(element, i, dim)])
179 neighborColors.push_back(colors[eIdx]);
180 }
181
182 else if constexpr (GridGeometry::discMethod == DiscretizationMethods::fcdiamond)
183 {
184 // we modify neighbor faces during the assembly
185 // check who else modifies these neighbor elements
186 const auto& eMapper = gg.elementMapper();
187 for (const auto& intersection : intersections(gg.gridView(), element))
188 if (intersection.neighbor())
189 neighborColors.push_back(colors[eMapper.index(intersection.outside())]);
190 }
191
192 else
193 DUNE_THROW(Dune::NotImplemented,
194 "Missing coloring scheme implementation for this discretization method"
195 );
196}
197
203int smallestAvailableColor(const std::vector<int>& colors,
204 std::vector<bool>& colorUsed)
205{
206 const int numColors = colors.size();
207 colorUsed.assign(numColors, false);
208
209 // The worst case for e.g. numColors=3 is colors={0, 1, 2}
210 // in which case we return 3 as smallest available color
211 // That means, we only track candidates in the (half-open) interval [0, numColors)
212 // Mark candidate colors which are present in colors
213 for (int i = 0; i < numColors; i++)
214 if (colors[i] >= 0 && colors[i] < numColors)
215 colorUsed[colors[i]] = true;
216
217 // return smallest color not in colors
218 for (int i = 0; i < numColors; i++)
219 if (!colorUsed[i])
220 return i;
221
222 return numColors;
223}
224
225} // end namespace Dumux::Detail
226#endif // DOXYGEN
227
228namespace Dumux {
229
250template<class GridGeometry>
251auto computeColoring(const GridGeometry& gg, int verbosity = 1)
252{
253 Dune::Timer timer;
254
255 using ElementSeed = typename GridGeometry::GridView::Grid::template Codim<0>::EntitySeed;
256 struct Coloring
257 {
258 using Sets = std::deque<std::vector<ElementSeed>>;
259 using Colors = std::vector<int>;
260
261 Coloring(std::size_t size) : sets{}, colors(size, -1) {}
262
263 Sets sets;
264 Colors colors;
265 };
266
267 Coloring coloring(gg.gridView().size(0));
268
269 // pre-reserve some memory for helper arrays to avoid reallocation
270 std::vector<int> neighborColors; neighborColors.reserve(30);
271 std::vector<bool> colorUsed; colorUsed.reserve(30);
272
273 // dof to element map to speed up neighbor search
274 const auto connectedElements = Detail::computeConnectedElements(gg);
275
276 for (const auto& element : elements(gg.gridView()))
277 {
278 // compute neighbor colors based on discretization-dependent stencil
279 neighborColors.clear();
280 Detail::addNeighborColors(gg, element, coloring.colors, connectedElements, neighborColors);
281
282 // find smallest color (positive integer) not in neighborColors
283 const auto color = Detail::smallestAvailableColor(neighborColors, colorUsed);
284
285 // assign color to element
286 coloring.colors[gg.elementMapper().index(element)] = color;
287
288 // add element to the set of elements with the same color
289 if (color < coloring.sets.size())
290 coloring.sets[color].push_back(element.seed());
291 else
292 coloring.sets.push_back(std::vector<ElementSeed>{ element.seed() });
293 }
294
295 if (verbosity > 0)
296 std::cout << Fmt::format("Colored {} elements with {} colors in {} seconds.\n",
297 gg.gridView().size(0), coloring.sets.size(), timer.elapsed());
298
299 return coloring;
300}
301
303template<class DiscretizationMethod>
304struct SupportsColoring : public std::false_type {};
305
306template<> struct SupportsColoring<DiscretizationMethods::CCTpfa> : public std::true_type {};
307template<> struct SupportsColoring<DiscretizationMethods::CCMpfa> : public std::true_type {};
308template<> struct SupportsColoring<DiscretizationMethods::Box> : public std::true_type {};
309template<> struct SupportsColoring<DiscretizationMethods::FCStaggered> : public std::true_type {};
310template<> struct SupportsColoring<DiscretizationMethods::FCDiamond> : public std::true_type {};
311template<> struct SupportsColoring<DiscretizationMethods::PQ1Bubble> : public std::true_type {};
312
313} // end namespace Dumux
314
315#endif
The available discretization methods in Dumux.
Formatting based on the fmt-library which implements std::format of C++20.
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
auto computeColoring(const GridGeometry &gg, int verbosity=1)
Compute iterable lists of element seeds partitioned by color.
Definition: coloring.hh:251
Distance implementation details.
Definition: cvfelocalresidual.hh:37
constexpr CCMpfa ccmpfa
Definition: method.hh:135
constexpr FCDiamond fcdiamond
Definition: method.hh:141
constexpr CCTpfa cctpfa
Definition: method.hh:134
CVFE< CVFEMethods::CR_RT > FCDiamond
Definition: method.hh:90
constexpr Box box
Definition: method.hh:136
CVFE< CVFEMethods::PQ1 > Box
Definition: method.hh:83
CVFE< CVFEMethods::PQ1Bubble > PQ1Bubble
Definition: method.hh:97
constexpr PQ1Bubble pq1bubble
Definition: method.hh:137
constexpr FCStaggered fcstaggered
Definition: method.hh:140
Traits specifying if a given discretization tag supports coloring.
Definition: coloring.hh:304