GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/discretization/facecentered/diamond/geometryhelper.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 70 81 86.4%
Functions: 72 79 91.1%
Branches: 45 163 27.6%

Line Branch Exec Source
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 //
7 /*!
8 * \file
9 * \ingroup DiamondDiscretization
10 * \copydoc Dumux::DiamondGeometryHelper
11 */
12 #ifndef DUMUX_DISCRETIZATION_FACECENTERED_DIAMOND_GEOMETRY_HELPER_HH
13 #define DUMUX_DISCRETIZATION_FACECENTERED_DIAMOND_GEOMETRY_HELPER_HH
14
15 #include <array>
16
17 #include <dune/common/reservedvector.hh>
18 #include <dune/common/fvector.hh>
19 #include <dune/geometry/multilineargeometry.hh>
20 #include <dune/geometry/type.hh>
21
22 #include <dumux/common/math.hh>
23
24 namespace Dumux {
25
26 //! Traits for an efficient corner storage for fc diamond method
27 template <class ct>
28 struct FCDiamondMLGeometryTraits : public Dune::MultiLinearGeometryTraits<ct>
29 {
30 // we use static vectors to store the corners as we know
31 // the maximum number of corners in advance (2^dim)
32 template< int mydim, int cdim >
33 struct CornerStorage
34 {
35 using Type = Dune::ReservedVector< Dune::FieldVector< ct, cdim >, (1<<mydim)>;
36 };
37 };
38
39 namespace Detail::FCDiamond {
40
41 template<Dune::GeometryType::Id gt>
42 struct ScvCorners;
43
44 template<>
45 struct ScvCorners<Dune::GeometryTypes::triangle>
46 {
47 static constexpr Dune::GeometryType type()
48 { return Dune::GeometryTypes::triangle; }
49
50 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
51 static constexpr std::array<std::array<Key, 3>, 3> keys = {{
52 { Key{0, 2}, Key{1, 2}, Key{0, 0} },
53 { Key{2, 2}, Key{0, 2}, Key{0, 0} },
54 { Key{1, 2}, Key{2, 2}, Key{0, 0} }
55 }};
56 };
57
58 template<>
59 struct ScvCorners<Dune::GeometryTypes::quadrilateral>
60 {
61 static constexpr Dune::GeometryType type()
62 { return Dune::GeometryTypes::triangle; }
63
64 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
65 static constexpr std::array<std::array<Key, 3>, 4> keys = {{
66 { Key{2, 2}, Key{0, 2}, Key{0, 0} },
67 { Key{1, 2}, Key{3, 2}, Key{0, 0} },
68 { Key{0, 2}, Key{1, 2}, Key{0, 0} },
69 { Key{3, 2}, Key{2, 2}, Key{0, 0} }
70 }};
71 };
72
73 template<>
74 struct ScvCorners<Dune::GeometryTypes::tetrahedron>
75 {
76 static constexpr Dune::GeometryType type()
77 { return Dune::GeometryTypes::tetrahedron; }
78
79 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
80 static constexpr std::array<std::array<Key, 4>, 4> keys = {{
81 { Key{0, 3}, Key{1, 3}, Key{2, 3}, Key{0, 0} },
82 { Key{1, 3}, Key{0, 3}, Key{3, 3}, Key{0, 0} },
83 { Key{0, 3}, Key{2, 3}, Key{3, 3}, Key{0, 0} },
84 { Key{2, 3}, Key{1, 3}, Key{3, 3}, Key{0, 0} }
85 }};
86 };
87
88 template<>
89 struct ScvCorners<Dune::GeometryTypes::hexahedron>
90 {
91 static constexpr Dune::GeometryType type()
92 { return Dune::GeometryTypes::pyramid; }
93
94 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
95 static constexpr std::array<std::array<Key, 5>, 6> keys = {{
96 { Key{4, 3}, Key{0, 3}, Key{6, 3}, Key{2, 3}, Key{0, 0} },
97 { Key{1, 3}, Key{5, 3}, Key{3, 3}, Key{7, 3}, Key{0, 0} },
98 { Key{4, 3}, Key{5, 3}, Key{0, 3}, Key{1, 3}, Key{0, 0} },
99 { Key{2, 3}, Key{3, 3}, Key{6, 3}, Key{7, 3}, Key{0, 0} },
100 { Key{0, 3}, Key{1, 3}, Key{2, 3}, Key{3, 3}, Key{0, 0} },
101 { Key{6, 3}, Key{7, 3}, Key{4, 3}, Key{5, 3}, Key{0, 0} }
102 }};
103 };
104
105 template<Dune::GeometryType::Id gt>
106 struct ScvfCorners;
107
108 template<>
109 struct ScvfCorners<Dune::GeometryTypes::triangle>
110 {
111 static constexpr Dune::GeometryType type()
112 { return Dune::GeometryTypes::line; }
113
114 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
115 static constexpr std::array<std::array<Key, 2>, 3> keys = {{
116 { Key{0, 2}, Key{0, 0} },
117 { Key{1, 2}, Key{0, 0} },
118 { Key{2, 2}, Key{0, 0} }
119 }};
120 };
121
122 template<>
123 struct ScvfCorners<Dune::GeometryTypes::quadrilateral>
124 {
125 static constexpr Dune::GeometryType type()
126 { return Dune::GeometryTypes::line; }
127
128 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
129 static constexpr std::array<std::array<Key, 2>, 4> keys = {{
130 { Key{0, 2}, Key{0, 0} },
131 { Key{1, 2}, Key{0, 0} },
132 { Key{2, 2}, Key{0, 0} },
133 { Key{3, 2}, Key{0, 0} }
134 }};
135 };
136
137 template<>
138 struct ScvfCorners<Dune::GeometryTypes::tetrahedron>
139 {
140 static constexpr Dune::GeometryType type()
141 { return Dune::GeometryTypes::triangle; }
142
143 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
144 static constexpr std::array<std::array<Key, 3>, 6> keys = {{
145 { Key{0, 3}, Key{1, 3}, Key{0, 0} },
146 { Key{2, 3}, Key{0, 3}, Key{0, 0} },
147 { Key{1, 3}, Key{2, 3}, Key{0, 0} },
148 { Key{0, 3}, Key{3, 3}, Key{0, 0} },
149 { Key{1, 3}, Key{3, 3}, Key{0, 0} },
150 { Key{2, 3}, Key{3, 3}, Key{0, 0} }
151 }};
152 };
153
154 template<>
155 struct ScvfCorners<Dune::GeometryTypes::hexahedron>
156 {
157 static constexpr Dune::GeometryType type()
158 { return Dune::GeometryTypes::triangle; }
159
160 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
161 static constexpr std::array<std::array<Key, 3>, 12> keys = {{
162 { Key{0, 3}, Key{4, 3}, Key{0, 0} },
163 { Key{1, 3}, Key{5, 3}, Key{0, 0} },
164 { Key{2, 3}, Key{6, 3}, Key{0, 0} },
165 { Key{3, 3}, Key{7, 3}, Key{0, 0} },
166 { Key{0, 3}, Key{2, 3}, Key{0, 0} },
167 { Key{1, 3}, Key{3, 3}, Key{0, 0} },
168 { Key{0, 3}, Key{1, 3}, Key{0, 0} },
169 { Key{2, 3}, Key{3, 3}, Key{0, 0} },
170 { Key{4, 3}, Key{6, 3}, Key{0, 0} },
171 { Key{5, 3}, Key{7, 3}, Key{0, 0} },
172 { Key{4, 3}, Key{5, 3}, Key{0, 0} },
173 { Key{6, 3}, Key{7, 3}, Key{0, 0} }
174 }};
175 };
176
177 // convert key array to global corner storage
178 template<class S, class Geo, class KeyArray, std::size_t... I>
179 1954536 S keyToCornerStorageImpl(const Geo& geo, const KeyArray& key, std::index_sequence<I...>)
180 {
181 using Dune::referenceElement;
182 1954536 const auto ref = referenceElement(geo);
183 // key is a pair of a local sub-entity index (first) and the sub-entity's codim (second)
184 2923276 return { geo.global(ref.position(key[I].first, key[I].second))... };
185 }
186
187 // convert key array to global corner storage
188 template<class S, class Geo, class T, std::size_t N, class Indices = std::make_index_sequence<N>>
189 977268 S keyToCornerStorage(const Geo& geo, const std::array<T, N>& key)
190 {
191
2/4
✓ Branch 1 taken 34274 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 34280 times.
✗ Branch 5 not taken.
977268 return keyToCornerStorageImpl<S>(geo, key, Indices{});
192 }
193
194 // boundary corners for the i-th facet
195 template<class S, class Geo, std::size_t... ii>
196 326 S boundaryCornerStorageImpl(const Geo& geo, unsigned int i, std::index_sequence<ii...>)
197 {
198 using Dune::referenceElement;
199 326 const auto ref = referenceElement(geo);
200 // simply the vertices of the facet i
201 350 return { geo.global(ref.position(ref.subEntity(i, 1, ii, Geo::mydimension), Geo::mydimension))... };
202 }
203
204 // boundary corners for the i-th facet
205 template<class S, std::size_t numCorners, class Geo>
206 166 S boundaryCornerStorage(const Geo& geo, unsigned int i)
207 {
208 166 return boundaryCornerStorageImpl<S>(geo, i, std::make_index_sequence<numCorners>{});
209 }
210
211 template<class IndexType, Dune::GeometryType::Id gt>
212 struct InsideOutsideScv;
213
214 template<class IndexType>
215 struct InsideOutsideScv<IndexType, Dune::GeometryTypes::triangle>
216 {
217 static constexpr std::array<std::array<IndexType, 2>, 3> pairs = {{
218 {0, 1}, {0, 2}, {1, 2}
219 }};
220 };
221
222 template<class IndexType>
223 struct InsideOutsideScv<IndexType, Dune::GeometryTypes::quadrilateral>
224 {
225 static constexpr std::array<std::array<IndexType, 2>, 4> pairs = {{
226 {0, 2}, {1, 2}, {0, 3}, {1, 3}
227 }};
228 };
229
230 template<class IndexType>
231 struct InsideOutsideScv<IndexType, Dune::GeometryTypes::tetrahedron>
232 {
233 static constexpr std::array<std::array<IndexType, 2>, 6> pairs = {{
234 {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
235 }};
236 };
237
238 template<class IndexType>
239 struct InsideOutsideScv<IndexType, Dune::GeometryTypes::hexahedron>
240 {
241 static constexpr std::array<std::array<IndexType, 2>, 12> pairs = {{
242 {0, 2}, {1, 2}, {0, 3}, {1, 3}, {0, 4}, {1, 4},
243 {2, 4}, {3, 4}, {0, 5}, {1, 5}, {2, 5}, {3, 5}
244 }};
245 };
246
247 } // end namespace Detail::FCDiamond
248
249 /*!
250 * \ingroup DiamondDiscretization
251 * \brief Helper class to construct SCVs and SCVFs for the diamond scheme
252 */
253 template <class GridView, class ScvType, class ScvfType>
254 class DiamondGeometryHelper
255 {
256 using Element = typename GridView::template Codim<0>::Entity;
257
258 static constexpr auto dim = GridView::dimension;
259 static constexpr auto dimWorld = GridView::dimensionworld;
260
261 using ScvCornerStorage = typename ScvType::Traits::CornerStorage;
262 using LocalIndexType = typename ScvType::Traits::LocalIndexType;
263 using ScvfCornerStorage = typename ScvfType::Traits::CornerStorage;
264
265 // for the normal
266 using ctype = typename GridView::ctype;
267 using GlobalPosition = typename Dune::FieldVector<ctype, GridView::dimensionworld>;
268
269 public:
270
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
128652 explicit DiamondGeometryHelper(const typename Element::Geometry& geo)
271
4/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10278 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
128629 : geo_(geo)
272 {}
273
274 //! Create a corner storage with the scv corners for a given face (codim-1) index
275 463234 ScvCornerStorage getScvCorners(unsigned int localFacetIndex) const
276 {
277
2/2
✓ Branch 1 taken 373080 times.
✓ Branch 2 taken 16 times.
463228 const auto type = geo_.type();
278
1/2
✓ Branch 0 taken 165122 times.
✗ Branch 1 not taken.
165178 if (type == Dune::GeometryTypes::triangle)
279 {
280 using Corners = Detail::FCDiamond::ScvCorners<Dune::GeometryTypes::triangle>;
281
2/4
✓ Branch 1 taken 20514 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20514 times.
✗ Branch 5 not taken.
194226 return Detail::FCDiamond::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localFacetIndex]);
282 }
283
2/2
✓ Branch 0 taken 54106 times.
✓ Branch 1 taken 12 times.
54170 else if (type == Dune::GeometryTypes::quadrilateral)
284 {
285 using Corners = Detail::FCDiamond::ScvCorners<Dune::GeometryTypes::quadrilateral>;
286
3/5
✓ Branch 1 taken 13760 times.
✓ Branch 2 taken 84400 times.
✓ Branch 4 taken 13760 times.
✗ Branch 5 not taken.
✗ Branch 3 not taken.
209224 return Detail::FCDiamond::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localFacetIndex]);
287 }
288
1/2
✓ Branch 0 taken 36462 times.
✗ Branch 1 not taken.
36474 else if (type == Dune::GeometryTypes::tetrahedron)
289 {
290 using Corners = Detail::FCDiamond::ScvCorners<Dune::GeometryTypes::tetrahedron>;
291 17664 return Detail::FCDiamond::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localFacetIndex]);
292 }
293 else if (type == Dune::GeometryTypes::hexahedron)
294 {
295 using Corners = Detail::FCDiamond::ScvCorners<Dune::GeometryTypes::hexahedron>;
296
2/4
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
344504 return Detail::FCDiamond::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localFacetIndex]);
297 }
298 else
299 DUNE_THROW(Dune::NotImplemented, "Scv geometries for type " << type);
300 }
301
302 //! Create a corner storage with the scvf corners for a given edge (codim-2) index
303 514082 ScvfCornerStorage getScvfCorners(unsigned int localEdgeIndex) const
304 {
305
1/2
✓ Branch 1 taken 418342 times.
✗ Branch 2 not taken.
514070 const auto type = geo_.type();
306
1/2
✓ Branch 0 taken 210380 times.
✗ Branch 1 not taken.
210380 if (type == Dune::GeometryTypes::triangle)
307 {
308 using Corners = Detail::FCDiamond::ScvfCorners<Dune::GeometryTypes::triangle>;
309
1/2
✓ Branch 1 taken 20514 times.
✗ Branch 2 not taken.
194202 return Detail::FCDiamond::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localEdgeIndex]);
310 }
311
1/2
✓ Branch 0 taken 99372 times.
✗ Branch 1 not taken.
99372 else if (type == Dune::GeometryTypes::quadrilateral)
312 {
313 using Corners = Detail::FCDiamond::ScvfCorners<Dune::GeometryTypes::quadrilateral>;
314
1/2
✓ Branch 1 taken 13760 times.
✗ Branch 2 not taken.
209168 return Detail::FCDiamond::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localEdgeIndex]);
315 }
316
1/2
✓ Branch 0 taken 72900 times.
✗ Branch 1 not taken.
72900 else if (type == Dune::GeometryTypes::tetrahedron)
317 {
318 using Corners = Detail::FCDiamond::ScvfCorners<Dune::GeometryTypes::tetrahedron>;
319 26472 return Detail::FCDiamond::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localEdgeIndex]);
320 }
321 else if (type == Dune::GeometryTypes::hexahedron)
322 {
323 using Corners = Detail::FCDiamond::ScvfCorners<Dune::GeometryTypes::hexahedron>;
324 395408 return Detail::FCDiamond::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localEdgeIndex]);
325 }
326 else
327 DUNE_THROW(Dune::NotImplemented, "Scvf geometries for type " << type);
328 }
329
330 //! Create the sub control volume face geometries on the boundary for a given face index
331 166 ScvfCornerStorage getBoundaryScvfCorners(unsigned int localFacetIndex) const
332 {
333
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
166 const auto type = geo_.type();
334 if (type == Dune::GeometryTypes::triangle || type == Dune::GeometryTypes::quadrilateral)
335 160 return Detail::FCDiamond::boundaryCornerStorage<ScvfCornerStorage, 2>(geo_, localFacetIndex);
336 else if (type == Dune::GeometryTypes::tetrahedron)
337 return Detail::FCDiamond::boundaryCornerStorage<ScvfCornerStorage, 3>(geo_, localFacetIndex);
338 else if (type == Dune::GeometryTypes::hexahedron)
339 166 return Detail::FCDiamond::boundaryCornerStorage<ScvfCornerStorage, 4>(geo_, localFacetIndex);
340 else
341 DUNE_THROW(Dune::NotImplemented, "Boundary scvf geometries for type " << type);
342 }
343
344 463132 GlobalPosition facetCenter(unsigned int localFacetIndex) const
345 {
346 463132 return geo_.global(referenceElement(geo_).position(localFacetIndex, 1));
347 }
348
349 514070 std::array<LocalIndexType, 2> getInsideOutsideScvForScvf(unsigned int localEdgeIndex)
350 {
351
1/2
✓ Branch 1 taken 384068 times.
✗ Branch 2 not taken.
514070 const auto type = geo_.type();
352
1/2
✓ Branch 0 taken 210380 times.
✗ Branch 1 not taken.
210380 if (type == Dune::GeometryTypes::triangle)
353 194202 return Detail::FCDiamond::InsideOutsideScv<LocalIndexType, Dune::GeometryTypes::triangle>::pairs[localEdgeIndex];
354
1/2
✓ Branch 0 taken 99372 times.
✗ Branch 1 not taken.
99372 else if (type == Dune::GeometryTypes::quadrilateral)
355 209168 return Detail::FCDiamond::InsideOutsideScv<LocalIndexType, Dune::GeometryTypes::quadrilateral>::pairs[localEdgeIndex];
356
1/2
✓ Branch 0 taken 72900 times.
✗ Branch 1 not taken.
72900 else if (type == Dune::GeometryTypes::tetrahedron)
357 26472 return Detail::FCDiamond::InsideOutsideScv<LocalIndexType, Dune::GeometryTypes::tetrahedron>::pairs[localEdgeIndex];
358 else if (type == Dune::GeometryTypes::hexahedron)
359 84228 return Detail::FCDiamond::InsideOutsideScv<LocalIndexType, Dune::GeometryTypes::hexahedron>::pairs[localEdgeIndex];
360 else
361 DUNE_THROW(Dune::NotImplemented, "Inside outside scv pairs for type " << type);
362 }
363
364 //! number of interior sub control volume faces (number of codim-2 entities)
365 899441 std::size_t numInteriorScvf()
366 {
367 899441 return referenceElement(geo_).size(2);
368 }
369
370 //! number of sub control volumes (number of codim-1 entities)
371 848563 std::size_t numScv()
372 {
373
6/6
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 4 times.
✓ Branch 7 taken 14 times.
✓ Branch 8 taken 4 times.
848563 return referenceElement(geo_).size(1);
374 }
375
376 template<int d = dimWorld, std::enable_if_t<(d==3), int> = 0>
377 110700 GlobalPosition normal(const ScvfCornerStorage& p, const std::array<LocalIndexType, 2>& scvPair)
378 {
379 332100 auto normal = Dumux::crossProduct(p[1]-p[0], p[2]-p[0]);
380 110700 normal /= normal.two_norm();
381
382 110700 const auto ref = referenceElement(geo_);
383 122028 const auto v = facetCenter_(scvPair[1], ref) - facetCenter_(scvPair[0], ref);
384
385
2/2
✓ Branch 0 taken 46526 times.
✓ Branch 1 taken 64174 times.
110700 const auto s = v*normal;
386
2/2
✓ Branch 0 taken 46526 times.
✓ Branch 1 taken 64174 times.
110700 if (std::signbit(s))
387 110700 normal *= -1;
388
389 110700 return normal;
390 }
391
392 template<int d = dimWorld, std::enable_if_t<(d==2), int> = 0>
393 403370 GlobalPosition normal(const ScvfCornerStorage& p, const std::array<LocalIndexType, 2>& scvPair)
394 {
395 //! obtain normal vector by 90° counter-clockwise rotation of t
396 806740 const auto t = p[1] - p[0];
397 403370 GlobalPosition normal({-t[1], t[0]});
398 403370 normal /= normal.two_norm();
399
400 403370 const auto ref = referenceElement(geo_);
401 806740 const auto v = facetCenter_(scvPair[1], ref) - facetCenter_(scvPair[0], ref);
402
403
2/2
✓ Branch 0 taken 176156 times.
✓ Branch 1 taken 227214 times.
403370 const auto s = v*normal;
404
2/2
✓ Branch 0 taken 176156 times.
✓ Branch 1 taken 227214 times.
403370 if (std::signbit(s))
405 403370 normal *= -1;
406
407 403370 return normal;
408 }
409
410 const typename Element::Geometry& elementGeometry() const
411 { return geo_; }
412
413 private:
414 template<class RefElement>
415 1028140 GlobalPosition facetCenter_(unsigned int localFacetIndex, const RefElement& ref) const
416 {
417 928768 return geo_.global(ref.position(localFacetIndex, 1));
418 }
419
420 const typename Element::Geometry& geo_; //!< Reference to the element geometry
421 };
422
423 } // end namespace Dumux
424
425 #endif
426