GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/discretization/pq1bubble/geometryhelper.hh
Date: 2025-06-28 19:18:10
Exec Total Coverage
Lines: 111 114 97.4%
Functions: 80 81 98.8%
Branches: 60 174 34.5%

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 PQ1BubbleDiscretization
10 * \brief Helper class constructing the dual grid finite volume geometries
11 * for the cvfe discretizazion method
12 */
13 #ifndef DUMUX_DISCRETIZATION_PQ1BUBBLE_GEOMETRY_HELPER_HH
14 #define DUMUX_DISCRETIZATION_PQ1BUBBLE_GEOMETRY_HELPER_HH
15
16 #include <array>
17
18 #include <dune/common/exceptions.hh>
19
20 #include <dune/geometry/type.hh>
21 #include <dune/geometry/referenceelements.hh>
22 #include <dune/geometry/multilineargeometry.hh>
23 #include <dune/common/reservedvector.hh>
24
25 #include <dumux/common/math.hh>
26 #include <dumux/geometry/volume.hh>
27 #include <dumux/discretization/box/boxgeometryhelper.hh>
28
29 namespace Dumux {
30
31 //! Traits for an efficient corner storage for the PQ1Bubble method
32 template <class ct>
33 struct PQ1BubbleMLGeometryTraits : public Dune::MultiLinearGeometryTraits<ct>
34 {
35 // we use static vectors to store the corners as we know
36 // the maximum number of corners in advance (2^dim)
37 template< int mydim, int cdim >
38 struct CornerStorage
39 {
40 using Type = Dune::ReservedVector< Dune::FieldVector< ct, cdim >, (1<<mydim)+1>;
41 };
42 };
43
44 namespace Detail::PQ1Bubble {
45
46 template<Dune::GeometryType::Id gt>
47 struct OverlappingScvCorners;
48
49 template<>
50 struct OverlappingScvCorners<Dune::GeometryTypes::line>
51 {
52 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
53 static constexpr std::array<std::array<Key, 2>, 1> keys = {{
54 { Key{0, 1}, Key{1, 1} }
55 }};
56 };
57
58 template<>
59 struct OverlappingScvCorners<Dune::GeometryTypes::triangle>
60 {
61 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
62 static constexpr std::array<std::array<Key, 3>, 1> keys = {{
63 { Key{0, 1}, Key{1, 1}, Key{2, 1} }
64 }};
65 };
66
67 template<>
68 struct OverlappingScvCorners<Dune::GeometryTypes::quadrilateral>
69 {
70 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
71 static constexpr std::array<std::array<Key, 4>, 1> keys = {{
72 { Key{2, 1}, Key{1, 1}, Key{0, 1}, Key{3, 1} }
73 }};
74 };
75
76 template<>
77 struct OverlappingScvCorners<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>, 1> keys = {{
81 { Key{0, 1}, Key{1, 1}, Key{2, 1}, Key{3, 1} }
82 }};
83 };
84
85 template<>
86 struct OverlappingScvCorners<Dune::GeometryTypes::hexahedron>
87 {
88 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
89 static constexpr std::array<std::array<Key, 6>, 1> keys = {{
90 { Key{0, 1}, Key{2, 1}, Key{3, 1}, Key{1, 1}, Key{4, 1}, Key{5, 1} }
91 }};
92 };
93
94
95 template<Dune::GeometryType::Id gt>
96 struct OverlappingScvfCorners;
97
98 template<>
99 struct OverlappingScvfCorners<Dune::GeometryTypes::line>
100 {
101 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
102 static constexpr std::array<std::array<Key, 1>, 1> keys = {{
103 { Key{0, 0} }
104 }};
105 };
106
107 template<>
108 struct OverlappingScvfCorners<Dune::GeometryTypes::triangle>
109 {
110 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
111 static constexpr std::array<std::array<Key, 2>, 3> keys = {{
112 { Key{0, 1}, Key{1, 1} },
113 { Key{0, 1}, Key{2, 1} },
114 { Key{1, 1}, Key{2, 1} }
115 }};
116 };
117
118 template<>
119 struct OverlappingScvfCorners<Dune::GeometryTypes::quadrilateral>
120 {
121 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
122 static constexpr std::array<std::array<Key, 2>, 4> keys = {{
123 { Key{0, 1}, Key{2, 1} },
124 { Key{2, 1}, Key{1, 1} },
125 { Key{0, 1}, Key{3, 1} },
126 { Key{1, 1}, Key{3, 1} }
127 }};
128 };
129
130 template<>
131 struct OverlappingScvfCorners<Dune::GeometryTypes::tetrahedron>
132 {
133 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
134 static constexpr std::array<std::array<Key, 3>, 10> keys = {{
135 { Key{0, 1}, Key{1, 1}, Key{2, 1} },
136 { Key{0, 1}, Key{1, 1}, Key{3, 1} },
137 { Key{0, 1}, Key{2, 1}, Key{3, 1} },
138 { Key{1, 1}, Key{2, 1}, Key{3, 1} }
139 }};
140 };
141
142 template<>
143 struct OverlappingScvfCorners<Dune::GeometryTypes::hexahedron>
144 {
145 using Key = std::pair<std::uint8_t, std::uint8_t>; // (i, codim)
146 static constexpr std::array<std::array<Key, 3>, 8> keys = {{
147 { Key{4, 1}, Key{0, 1}, Key{2, 1} },
148 { Key{4, 1}, Key{2, 1}, Key{1, 1} },
149 { Key{4, 1}, Key{0, 1}, Key{3, 1} },
150 { Key{4, 1}, Key{1, 1}, Key{3, 1} },
151 { Key{5, 1}, Key{0, 1}, Key{2, 1} },
152 { Key{5, 1}, Key{2, 1}, Key{1, 1} },
153 { Key{5, 1}, Key{0, 1}, Key{3, 1} },
154 { Key{5, 1}, Key{1, 1}, Key{3, 1} }
155 }};
156 };
157
158 } // end namespace Detail::PQ1Bubble
159
160 /*!
161 * \ingroup PQ1BubbleDiscretization
162 * \brief A class to create sub control volume and sub control volume face geometries per element
163 */
164 template <class GridView, class ScvType, class ScvfType>
165 class PQ1BubbleGeometryHelper
166 {
167 using Scalar = typename GridView::ctype;
168 using GlobalPosition = typename Dune::FieldVector<Scalar, GridView::dimensionworld>;
169 using ScvCornerStorage = typename ScvType::Traits::CornerStorage;
170 using ScvfCornerStorage = typename ScvfType::Traits::CornerStorage;
171 using LocalIndexType = typename ScvType::Traits::LocalIndexType;
172
173 using Element = typename GridView::template Codim<0>::Entity;
174 using Intersection = typename GridView::Intersection;
175
176 static constexpr auto dim = GridView::dimension;
177 static constexpr auto dimWorld = GridView::dimensionworld;
178 public:
179
180 123953 PQ1BubbleGeometryHelper(const typename Element::Geometry& geometry)
181 123953 : geo_(geometry)
182
1/2
✓ Branch 1 taken 12000 times.
✗ Branch 2 not taken.
123953 , boxHelper_(geometry)
183 {}
184
185 //! Create a vector with the scv corners
186 547821 ScvCornerStorage getScvCorners(unsigned int localScvIdx) const
187 {
188 // proceed according to number of corners of the element
189 547821 const auto type = geo_.type();
190 547821 const auto numBoxScv = boxHelper_.numScv();
191 // reuse box geometry helper for the corner scvs
192
2/2
✓ Branch 0 taken 424560 times.
✓ Branch 1 taken 123261 times.
547821 if (localScvIdx < numBoxScv)
193 424560 return boxHelper_.getScvCorners(localScvIdx);
194
195
1/2
✓ Branch 0 taken 90160 times.
✗ Branch 1 not taken.
123261 const auto localOverlappingScvIdx = localScvIdx-numBoxScv;
196
1/2
✓ Branch 1 taken 32064 times.
✗ Branch 2 not taken.
123261 if (type == Dune::GeometryTypes::triangle)
197 {
198 using Corners = Detail::PQ1Bubble::OverlappingScvCorners<Dune::GeometryTypes::triangle>;
199 68496 return Detail::Box::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localOverlappingScvIdx]);
200 }
201
1/2
✓ Branch 1 taken 4412 times.
✗ Branch 2 not taken.
54765 else if (type == Dune::GeometryTypes::quadrilateral)
202 {
203 using Corners = Detail::PQ1Bubble::OverlappingScvCorners<Dune::GeometryTypes::quadrilateral>;
204 50352 return Detail::Box::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localOverlappingScvIdx]);
205 }
206
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
4413 else if (type == Dune::GeometryTypes::tetrahedron)
207 {
208 using Corners = Detail::PQ1Bubble::OverlappingScvCorners<Dune::GeometryTypes::tetrahedron>;
209 4412 return Detail::Box::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localOverlappingScvIdx]);
210 }
211 1 else if (type == Dune::GeometryTypes::hexahedron)
212 {
213 using Corners = Detail::PQ1Bubble::OverlappingScvCorners<Dune::GeometryTypes::hexahedron>;
214 392705 return Detail::Box::keyToCornerStorage<ScvCornerStorage>(geo_, Corners::keys[localOverlappingScvIdx]);
215 }
216 else
217 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scv geometries for dim=" << dim
218 << " dimWorld=" << dimWorld
219 << " type=" << type);
220 }
221
222 547821 Dune::GeometryType getScvGeometryType(unsigned int localScvIdx) const
223 {
224 // proceed according to number of corners of the element
225 547821 const auto type = geo_.type();
226 547821 const auto numBoxScv = boxHelper_.numScv();
227
2/2
✓ Branch 0 taken 424560 times.
✓ Branch 1 taken 123261 times.
547821 if (localScvIdx < numBoxScv)
228 424560 return Dune::GeometryTypes::cube(dim);
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90160 times.
150913 else if (type == Dune::GeometryTypes::simplex(dim))
230 72908 return Dune::GeometryTypes::simplex(dim);
231
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
22701 else if (type == Dune::GeometryTypes::quadrilateral)
232 50352 return Dune::GeometryTypes::quadrilateral;
233 1 else if (type == Dune::GeometryTypes::hexahedron)
234 1 return Dune::GeometryTypes::none(dim); // octahedron
235 else
236 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scv geometries for dim=" << dim
237 << " dimWorld=" << dimWorld
238 << " type=" << type);
239 }
240
241 //! Create a vector with the corners of sub control volume faces
242 857952 ScvfCornerStorage getScvfCorners(unsigned int localScvfIdx) const
243 {
244 // proceed according to number of corners
245 857952 const auto type = geo_.type();
246 857952 const auto numBoxScvf = boxHelper_.numInteriorScvf();
247 // reuse box geometry helper for the corner scvs
248
2/2
✓ Branch 0 taken 433392 times.
✓ Branch 1 taken 424560 times.
857952 if (localScvfIdx < numBoxScvf)
249 433392 return boxHelper_.getScvfCorners(localScvfIdx);
250
251
1/2
✓ Branch 0 taken 302544 times.
✗ Branch 1 not taken.
424560 const auto localOverlappingScvfIdx = localScvfIdx-numBoxScvf;
252
1/2
✓ Branch 1 taken 128256 times.
✗ Branch 2 not taken.
424560 if (type == Dune::GeometryTypes::triangle)
253 {
254 using Corners = Detail::PQ1Bubble::OverlappingScvfCorners<Dune::GeometryTypes::triangle>;
255 205488 return Detail::Box::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localOverlappingScvfIdx]);
256 }
257
1/2
✓ Branch 1 taken 17648 times.
✗ Branch 2 not taken.
219072 else if (type == Dune::GeometryTypes::quadrilateral)
258 {
259 using Corners = Detail::PQ1Bubble::OverlappingScvfCorners<Dune::GeometryTypes::quadrilateral>;
260 201408 return Detail::Box::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localOverlappingScvfIdx]);
261 }
262
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
17664 else if (type == Dune::GeometryTypes::tetrahedron)
263 {
264 using Corners = Detail::PQ1Bubble::OverlappingScvfCorners<Dune::GeometryTypes::tetrahedron>;
265 17648 return Detail::Box::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localOverlappingScvfIdx]);
266 }
267 16 else if (type == Dune::GeometryTypes::hexahedron)
268 {
269 using Corners = Detail::PQ1Bubble::OverlappingScvfCorners<Dune::GeometryTypes::hexahedron>;
270 613928 return Detail::Box::keyToCornerStorage<ScvfCornerStorage>(geo_, Corners::keys[localOverlappingScvfIdx]);
271 }
272 else
273 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scvf geometries for dim=" << dim
274 << " dimWorld=" << dimWorld
275 << " type=" << type);
276 }
277
278 857952 Dune::GeometryType getInteriorScvfGeometryType(unsigned int localScvfIdx) const
279 {
280
1/2
✓ Branch 1 taken 75200 times.
✗ Branch 2 not taken.
857952 const auto numBoxScvf = boxHelper_.numInteriorScvf();
281
4/4
✓ Branch 0 taken 17656 times.
✓ Branch 1 taken 26484 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 12 times.
857952 if (localScvfIdx < numBoxScvf)
282 return Dune::GeometryTypes::cube(dim-1);
283 else
284 17664 return Dune::GeometryTypes::simplex(dim-1);
285 }
286
287 //! Create the sub control volume face geometries on the boundary
288 18094 ScvfCornerStorage getBoundaryScvfCorners(unsigned int localFacetIndex,
289 unsigned int indexInFacet) const
290 {
291
1/2
✓ Branch 1 taken 14246 times.
✗ Branch 2 not taken.
18094 return boxHelper_.getBoundaryScvfCorners(localFacetIndex, indexInFacet);
292 }
293
294 17430 Dune::GeometryType getBoundaryScvfGeometryType(unsigned int localScvfIdx) const
295 {
296 return Dune::GeometryTypes::cube(dim-1);
297 }
298
299 template<int d = dimWorld, std::enable_if_t<(d==3), int> = 0>
300 44140 GlobalPosition normal(const ScvfCornerStorage& p, const std::array<LocalIndexType, 2>& scvPair)
301 {
302 132420 auto normal = Dumux::crossProduct(p[1]-p[0], p[2]-p[0]);
303 44140 normal /= normal.two_norm();
304
305
2/4
✓ Branch 1 taken 44140 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 44140 times.
✗ Branch 5 not taken.
88280 GlobalPosition v = dofPosition(scvPair[1]) - dofPosition(scvPair[0]);
306
307
2/2
✓ Branch 0 taken 8828 times.
✓ Branch 1 taken 35312 times.
44140 const auto s = v*normal;
308
2/2
✓ Branch 0 taken 8828 times.
✓ Branch 1 taken 35312 times.
44140 if (std::signbit(s))
309 44140 normal *= -1;
310
311 44140 return normal;
312 }
313
314 template<int d = dimWorld, std::enable_if_t<(d==2), int> = 0>
315 813792 GlobalPosition normal(const ScvfCornerStorage& p, const std::array<LocalIndexType, 2>& scvPair)
316 {
317 //! obtain normal vector by 90° counter-clockwise rotation of t
318 1627584 const auto t = p[1] - p[0];
319 813792 GlobalPosition normal({-t[1], t[0]});
320 813792 normal /= normal.two_norm();
321
322
2/4
✓ Branch 1 taken 813792 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 813792 times.
✗ Branch 5 not taken.
1627584 GlobalPosition v = dofPosition(scvPair[1]) - dofPosition(scvPair[0]);
323
324
2/2
✓ Branch 0 taken 261152 times.
✓ Branch 1 taken 552640 times.
813792 const auto s = v*normal;
325
2/2
✓ Branch 0 taken 261152 times.
✓ Branch 1 taken 552640 times.
813792 if (std::signbit(s))
326 813792 normal *= -1;
327
328 813792 return normal;
329 }
330
331 //! the wrapped element geometry
332 const typename Element::Geometry& elementGeometry() const
333 { return geo_; }
334
335 //! number of interior sub control volume faces
336 123925 static auto numInteriorScvf(Dune::GeometryType type)
337 {
338 123925 return Dune::referenceElement<Scalar, dim>(type).size(dim-1) + Dune::referenceElement<Scalar, dim>(type).size(dim);
339 }
340
341 //! number of boundary sub control volume faces for face localFacetIndex
342 7452 static auto numBoundaryScvf(Dune::GeometryType type, unsigned int localFacetIndex)
343 {
344 7452 return Dune::referenceElement<Scalar, dim>(type).size(localFacetIndex, 1, dim);
345 }
346
347 //! number of sub control volumes (number of codim-1 entities)
348
1/2
✓ Branch 1 taken 12000 times.
✗ Branch 2 not taken.
123261 std::size_t numScv() const
349 {
350
8/10
✓ Branch 1 taken 117509 times.
✓ Branch 2 taken 21101 times.
✓ Branch 4 taken 404704 times.
✓ Branch 5 taken 90160 times.
✓ Branch 7 taken 12000 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 61600 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 49600 times.
✓ Branch 13 taken 12000 times.
671074 return boxHelper_.numScv() + 1;
351 }
352
353 //! get scv volume
354 547813 Scalar scvVolume(unsigned int localScvIdx, const ScvCornerStorage& p) const
355 {
356
1/2
✓ Branch 1 taken 525744 times.
✗ Branch 2 not taken.
547813 const auto scvType = getScvGeometryType(localScvIdx);
357 if constexpr (dim == 3)
358
2/2
✓ Branch 0 taken 22068 times.
✓ Branch 1 taken 1 times.
22069 if (scvType == Dune::GeometryTypes::none(dim))
359 1 return octahedronVolume_(p);
360
361 547812 return Dumux::convexPolytopeVolume<dim>(
362 scvType,
363 1736128 [&](unsigned int i){ return p[i]; }
364 );
365 }
366
367 //! number of element dofs
368 142169968 static std::size_t numElementDofs(Dune::GeometryType type)
369 {
370 142169968 return Dune::referenceElement<Scalar, dim>(type).size(dim) + 1;
371 }
372
373 //! number of hybrid dofs
374 static std::size_t numNonCVLocalDofs(Dune::GeometryType type)
375 {
376 return 0;
377 }
378
379 //! Number of local dofs related to an intersection with index iIdx
380 static auto numLocalDofsIntersection(Dune::GeometryType type, unsigned int iIdx)
381 {
382 return Dune::referenceElement<Scalar, dim>(type).size(iIdx, 1, dim);
383 }
384
385 //! Local dof index related to a localDof, with index ilocalDofIdx, on an intersection with index iIdx
386 static auto localDofIndexIntersection(Dune::GeometryType type, unsigned int iIdx, unsigned int ilocalDofIdx)
387 {
388 return Dune::referenceElement<Scalar, dim>(type).subEntity(iIdx, 1, ilocalDofIdx, dim);
389 }
390
391 template<class DofMapper>
392 107903979 static auto dofIndex(const DofMapper& dofMapper, const Element& element, unsigned int localDofIdx)
393 {
394
3/3
✓ Branch 1 taken 7880128 times.
✓ Branch 2 taken 78016385 times.
✓ Branch 3 taken 22007466 times.
107903979 if (localDofIdx < numElementDofs(element.type())-1)
395 83652912 return dofMapper.subIndex(element, localDofIdx, dim);
396 else
397 24251067 return dofMapper.index(element);
398 }
399
400 static GlobalPosition dofPosition(const Element& element, unsigned int localDofIdx)
401 {
402 if (localDofIdx < numElementDofs(element.geometry().type())-1)
403 return element.geometry().corner(localDofIdx);
404 else
405 return element.geometry().center();
406 }
407
408 2263677 GlobalPosition dofPosition(unsigned int localDofIdx) const
409 {
410
3/3
✓ Branch 1 taken 488040 times.
✓ Branch 2 taken 1382933 times.
✓ Branch 3 taken 392704 times.
2263677 if (localDofIdx < numElementDofs(geo_.type())-1)
411 2053464 return geo_.corner(localDofIdx);
412 else
413 653313 return geo_.center();
414 }
415
416 857932 std::array<LocalIndexType, 2> getScvPairForScvf(unsigned int localScvfIndex) const
417 {
418 857932 const auto numEdges = referenceElement(geo_).size(dim-1);
419
2/2
✓ Branch 0 taken 433380 times.
✓ Branch 1 taken 424552 times.
857932 if (localScvfIndex < numEdges)
420 return {
421 433380 static_cast<LocalIndexType>(referenceElement(geo_).subEntity(localScvfIndex, dim-1, 0, dim)),
422 433380 static_cast<LocalIndexType>(referenceElement(geo_).subEntity(localScvfIndex, dim-1, 1, dim))
423 866760 };
424 else
425 return {
426 424552 static_cast<LocalIndexType>(numElementDofs(geo_.type())-1),
427 424552 static_cast<LocalIndexType>(localScvfIndex-numEdges)
428 424552 };
429 }
430
431 17430 std::array<LocalIndexType, 2> getScvPairForBoundaryScvf(unsigned int localFacetIndex, unsigned int localIsScvfIndex) const
432 {
433 17430 const LocalIndexType insideScvIdx
434 17430 = static_cast<LocalIndexType>(referenceElement(geo_).subEntity(localFacetIndex, 1, localIsScvfIndex, dim));
435 17430 return { insideScvIdx, insideScvIdx };
436 }
437
438 857932 bool isOverlappingScvf(unsigned int localScvfIndex) const
439 {
440
4/4
✓ Branch 1 taken 462152 times.
✓ Branch 2 taken 395780 times.
✓ Branch 3 taken 37600 times.
✓ Branch 4 taken 37600 times.
857932 if (localScvfIndex < boxHelper_.numInteriorScvf())
441 return false;
442 else
443 424552 return true;
444 }
445
446 bool isOverlappingBoundaryScvf(unsigned int localFacetIndex) const
447 {
448 return false;
449 }
450
451 547813 bool isOverlappingScv(unsigned int localScvIndex) const
452 {
453
4/4
✓ Branch 1 taken 160861 times.
✓ Branch 2 taken 386952 times.
✓ Branch 3 taken 12000 times.
✓ Branch 4 taken 37600 times.
547813 if (localScvIndex < boxHelper_.numScv())
454 return false;
455 else
456 123261 return true;
457 }
458
459 private:
460 1 Scalar octahedronVolume_(const ScvCornerStorage& p) const
461 {
462 using std::abs;
463 return 1.0/6.0 * (
464 4 abs(Dumux::tripleProduct(p[4]-p[0], p[1]-p[0], p[2]-p[0]))
465 4 + abs(Dumux::tripleProduct(p[5]-p[0], p[1]-p[0], p[2]-p[0]))
466 1 );
467 }
468
469 const typename Element::Geometry& geo_; //!< Reference to the element geometry
470 Dumux::BoxGeometryHelper<GridView, dim, ScvType, ScvfType> boxHelper_;
471 };
472
473 template <class GridView, class ScvType, class ScvfType>
474 class HybridPQ1BubbleGeometryHelper
475 {
476 using Scalar = typename GridView::ctype;
477 using GlobalPosition = typename Dune::FieldVector<Scalar, GridView::dimensionworld>;
478 using ScvCornerStorage = typename ScvType::Traits::CornerStorage;
479 using ScvfCornerStorage = typename ScvfType::Traits::CornerStorage;
480 using LocalIndexType = typename ScvType::Traits::LocalIndexType;
481
482 using Element = typename GridView::template Codim<0>::Entity;
483 using Intersection = typename GridView::Intersection;
484
485 static constexpr auto dim = GridView::dimension;
486 static constexpr auto dimWorld = GridView::dimensionworld;
487 public:
488
489 HybridPQ1BubbleGeometryHelper(const typename Element::Geometry& geometry)
490 : geo_(geometry)
491 , boxHelper_(geometry)
492 {}
493
494 //! Create a vector with the scv corners
495 ScvCornerStorage getScvCorners(unsigned int localScvIdx) const
496 {
497 // proceed according to number of corners of the element
498 const auto numBoxScv = boxHelper_.numScv();
499 // reuse box geometry helper for the corner scvs
500 if (localScvIdx < numBoxScv)
501 return boxHelper_.getScvCorners(localScvIdx);
502
503 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scv corners call for hybrid dofs");
504 }
505
506 Dune::GeometryType getScvGeometryType(unsigned int localScvIdx) const
507 {
508 // proceed according to number of corners of the element
509 const auto numBoxScv = boxHelper_.numScv();
510
511 if (localScvIdx < numBoxScv)
512 return Dune::GeometryTypes::cube(dim);
513
514 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scv geometry call for hybrid dofs");
515 }
516
517 //! Create a vector with the corners of sub control volume faces
518 ScvfCornerStorage getScvfCorners(unsigned int localScvfIdx) const
519 {
520 // proceed according to number of corners
521 const auto numBoxScvf = boxHelper_.numInteriorScvf();
522 // reuse box geometry helper for the corner scvs
523 if (localScvfIdx < numBoxScvf)
524 return boxHelper_.getScvfCorners(localScvfIdx);
525
526 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scvf corners call for hybrid dofs");
527 }
528
529 Dune::GeometryType getInteriorScvfGeometryType(unsigned int localScvfIdx) const
530 {
531 const auto numBoxScvf = boxHelper_.numInteriorScvf();
532 if (localScvfIdx < numBoxScvf)
533 return Dune::GeometryTypes::cube(dim-1);
534
535 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble interior scvf geometry type call for hybrid dofs");
536 }
537
538 //! Create the sub control volume face geometries on the boundary
539 ScvfCornerStorage getBoundaryScvfCorners(unsigned int localFacetIndex,
540 unsigned int indexInFacet) const
541 {
542 return boxHelper_.getBoundaryScvfCorners(localFacetIndex, indexInFacet);
543 }
544
545 Dune::GeometryType getBoundaryScvfGeometryType(unsigned int localScvfIdx) const
546 {
547 return Dune::GeometryTypes::cube(dim-1);
548 }
549
550 template<int d = dimWorld, std::enable_if_t<(d==3), int> = 0>
551 GlobalPosition normal(const ScvfCornerStorage& p, const std::array<LocalIndexType, 2>& scvPair)
552 {
553 auto normal = Dumux::crossProduct(p[1]-p[0], p[2]-p[0]);
554 normal /= normal.two_norm();
555
556 GlobalPosition v = dofPosition(scvPair[1]) - dofPosition(scvPair[0]);
557
558 const auto s = v*normal;
559 if (std::signbit(s))
560 normal *= -1;
561
562 return normal;
563 }
564
565 template<int d = dimWorld, std::enable_if_t<(d==2), int> = 0>
566 GlobalPosition normal(const ScvfCornerStorage& p, const std::array<LocalIndexType, 2>& scvPair)
567 {
568 //! obtain normal vector by 90° counter-clockwise rotation of t
569 const auto t = p[1] - p[0];
570 GlobalPosition normal({-t[1], t[0]});
571 normal /= normal.two_norm();
572
573 GlobalPosition v = dofPosition(scvPair[1]) - dofPosition(scvPair[0]);
574
575 const auto s = v*normal;
576 if (std::signbit(s))
577 normal *= -1;
578
579 return normal;
580 }
581
582 //! the wrapped element geometry
583 const typename Element::Geometry& elementGeometry() const
584 { return geo_; }
585
586 //! number of interior sub control volume faces
587 static auto numInteriorScvf(Dune::GeometryType type)
588 {
589 return Dune::referenceElement<Scalar, dim>(type).size(dim-1);
590 }
591
592 //! number of boundary sub control volume faces for face localFacetIndex
593 static auto numBoundaryScvf(Dune::GeometryType type, unsigned int localFacetIndex)
594 {
595 return Dune::referenceElement<Scalar, dim>(type).size(localFacetIndex, 1, dim);
596 }
597
598 //! number of sub control volumes (number of codim-1 entities)
599 std::size_t numScv() const
600 {
601 return boxHelper_.numScv();
602 }
603
604 //! get scv volume
605 Scalar scvVolume(unsigned int localScvIdx, const ScvCornerStorage& p) const
606 {
607 const auto scvType = getScvGeometryType(localScvIdx);
608
609 return Dumux::convexPolytopeVolume<dim>(
610 scvType,
611 [&](unsigned int i){ return p[i]; }
612 );
613 }
614
615 //! number of element dofs
616 static std::size_t numElementDofs(Dune::GeometryType type)
617 {
618 return Dune::referenceElement<Scalar, dim>(type).size(dim) + 1;
619 }
620
621 //! number of hybrid dofs
622 static std::size_t numNonCVLocalDofs(Dune::GeometryType type)
623 {
624 return 1;
625 }
626
627 //! Number of local dofs related to an intersection with index iIdx
628 static auto numLocalDofsIntersection(Dune::GeometryType type, unsigned int iIdx)
629 {
630 return Dune::referenceElement<Scalar, dim>(type).size(iIdx, 1, dim);
631 }
632
633 //! Local dof index related to a localDof, with index ilocalDofIdx, on an intersection with index iIdx
634 static auto localDofIndexIntersection(Dune::GeometryType type, unsigned int iIdx, unsigned int ilocalDofIdx)
635 {
636 return Dune::referenceElement<Scalar, dim>(type).subEntity(iIdx, 1, ilocalDofIdx, dim);
637 }
638
639 template<class DofMapper>
640 static auto dofIndex(const DofMapper& dofMapper, const Element& element, unsigned int localDofIdx)
641 {
642 if (localDofIdx < numElementDofs(element.type())-1)
643 return dofMapper.subIndex(element, localDofIdx, dim);
644 else
645 return dofMapper.index(element);
646 }
647
648 static GlobalPosition dofPosition(const Element& element, unsigned int localDofIdx)
649 {
650 if (localDofIdx < numElementDofs(element.geometry().type())-1)
651 return element.geometry().corner(localDofIdx);
652 else
653 return element.geometry().center();
654 }
655
656 GlobalPosition dofPosition(unsigned int localDofIdx) const
657 {
658 if (localDofIdx < numElementDofs(geo_.type())-1)
659 return geo_.corner(localDofIdx);
660 else
661 return geo_.center();
662 }
663
664 std::array<LocalIndexType, 2> getScvPairForScvf(unsigned int localScvfIndex) const
665 {
666 const auto numEdges = referenceElement(geo_).size(dim-1);
667 if (localScvfIndex < numEdges)
668 return {
669 static_cast<LocalIndexType>(referenceElement(geo_).subEntity(localScvfIndex, dim-1, 0, dim)),
670 static_cast<LocalIndexType>(referenceElement(geo_).subEntity(localScvfIndex, dim-1, 1, dim))
671 };
672
673 DUNE_THROW(Dune::NotImplemented, "PQ1Bubble scv pair call for hybrid dofs");
674 }
675
676 std::array<LocalIndexType, 2> getScvPairForBoundaryScvf(unsigned int localFacetIndex, unsigned int localIsScvfIndex) const
677 {
678 const LocalIndexType insideScvIdx
679 = static_cast<LocalIndexType>(referenceElement(geo_).subEntity(localFacetIndex, 1, localIsScvfIndex, dim));
680 return { insideScvIdx, insideScvIdx };
681 }
682
683 bool isOverlappingScvf(unsigned int localScvfIndex) const
684 { return false; }
685
686 bool isOverlappingBoundaryScvf(unsigned int localFacetIndex) const
687 { return false; }
688
689 bool isOverlappingScv(unsigned int localScvIndex) const
690 { return false; }
691
692 private:
693 const typename Element::Geometry& geo_; //!< Reference to the element geometry
694 Dumux::BoxGeometryHelper<GridView, dim, ScvType, ScvfType> boxHelper_;
695 };
696
697 } // end namespace Dumux
698
699 #endif
700