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-FileCopyrightInfo: 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 Geometry | ||
10 | * \brief Compute the volume of several common geometry types | ||
11 | */ | ||
12 | #ifndef DUMUX_GEOMETRY_VOLUME_HH | ||
13 | #define DUMUX_GEOMETRY_VOLUME_HH | ||
14 | |||
15 | #include <cmath> | ||
16 | #include <limits> | ||
17 | #include <type_traits> | ||
18 | |||
19 | #include <dune/common/exceptions.hh> | ||
20 | #include <dune/geometry/type.hh> | ||
21 | #include <dune/geometry/quadraturerules.hh> | ||
22 | |||
23 | #include <dumux/common/math.hh> | ||
24 | |||
25 | namespace Dumux { | ||
26 | |||
27 | /*! | ||
28 | * \ingroup Geometry | ||
29 | * \brief Compute the volume of several common geometry types | ||
30 | * \param type the geometry type | ||
31 | * \param c a function returning the ith corner (in Dune reference element order) | ||
32 | * e.g. `[&](unsigned int i){ return corners[i]; }`, where `corners` is a | ||
33 | * random access container storing the corners, and the returned corner is stored | ||
34 | * in a container (e.g. Dune::FieldVector) that exports `value_type` and `dimension`. | ||
35 | * \tparam dim the dimension of the geometry | ||
36 | * \tparam CornerF the function type (is deduced) | ||
37 | * \return volume of the geometry or NaN signalling not implemented | ||
38 | * \note This is only correct for convex polytopes (flat sides) | ||
39 | */ | ||
40 | template<int dim, class CornerF> | ||
41 | 43617239 | auto convexPolytopeVolume(Dune::GeometryType type, const CornerF& c) | |
42 | { | ||
43 | using ctype = typename std::decay_t<decltype(c(0))>::value_type; | ||
44 | static constexpr int coordDim = std::decay_t<decltype(c(0))>::dimension; | ||
45 | static_assert(coordDim >= dim, "Coordinate dimension has to be larger than geometry dimension"); | ||
46 | |||
47 | // not implemented for coordinate dimension larger than 3 | ||
48 | if constexpr (coordDim > 3) | ||
49 | return std::numeric_limits<ctype>::quiet_NaN(); | ||
50 | |||
51 | if constexpr (dim == 0) | ||
52 | ✗ | return 1.0; | |
53 | |||
54 | else if constexpr (dim == 1) | ||
55 | 25427322 | return (c(1)-c(0)).two_norm(); | |
56 | |||
57 | else if constexpr (dim == 2) | ||
58 | { | ||
59 |
1/2✓ Branch 0 taken 323786 times.
✗ Branch 1 not taken.
|
41458621 | if (type == Dune::GeometryTypes::triangle) |
60 | { | ||
61 | if constexpr (coordDim == 2) | ||
62 | { | ||
63 | // make sure we are using positive volumes | ||
64 | // the cross product of edge vectors might be negative, | ||
65 | // depending on the element orientation | ||
66 | using std::abs; | ||
67 | 3204826 | return 0.5*abs(Dumux::crossProduct(c(1)-c(0), c(2)-c(0))); | |
68 | } | ||
69 | else // coordDim == 3 | ||
70 | 936448 | return 0.5*Dumux::crossProduct(c(1)-c(0), c(2)-c(0)).two_norm(); | |
71 | |||
72 | } | ||
73 |
1/2✓ Branch 0 taken 323754 times.
✗ Branch 1 not taken.
|
40985443 | else if (type == Dune::GeometryTypes::quadrilateral) |
74 | { | ||
75 | if constexpr (coordDim == 2) | ||
76 | { | ||
77 | // make sure we are using positive volumes | ||
78 | // the cross product of diagonals might be negative, | ||
79 | // depending on the element orientation | ||
80 | using std::abs; | ||
81 | 338084305 | return 0.5*abs(Dumux::crossProduct(c(3)-c(0), c(2)-c(1))); | |
82 | } | ||
83 | else // coordDim == 3 | ||
84 | 27363920 | return 0.5*Dumux::crossProduct(c(3)-c(0), c(2)-c(1)).two_norm(); | |
85 | |||
86 | } | ||
87 | else | ||
88 | return std::numeric_limits<ctype>::quiet_NaN(); | ||
89 | } | ||
90 | |||
91 | else if constexpr (dim == 3) | ||
92 | { | ||
93 |
1/2✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
|
1751192 | if (type == Dune::GeometryTypes::tetrahedron) |
94 | { | ||
95 | using std::abs; | ||
96 | 22080 | return 1.0/6.0 * abs( | |
97 | 220680 | Dumux::tripleProduct(c(3)-c(0), c(1)-c(0), c(2)-c(0)) | |
98 | 22080 | ); | |
99 | } | ||
100 |
1/2✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
|
1729112 | else if (type == Dune::GeometryTypes::hexahedron) |
101 | { | ||
102 | // after Grandy 1997, Efficient computation of volume of hexahedron | ||
103 | 5077720 | const auto v = c(7)-c(0); | |
104 | using std::abs; | ||
105 | return 1.0/6.0 * ( | ||
106 | 13540688 | abs(Dumux::tripleProduct(v, c(1)-c(0), c(3)-c(5))) | |
107 | 13540688 | + abs(Dumux::tripleProduct(v, c(4)-c(0), c(5)-c(6))) | |
108 | 13540688 | + abs(Dumux::tripleProduct(v, c(2)-c(0), c(6)-c(3))) | |
109 | 1692624 | ); | |
110 | } | ||
111 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
36488 | else if (type == Dune::GeometryTypes::pyramid) |
112 | { | ||
113 | // 1/3 * base * height | ||
114 | // for base see case Dune::GeometryTypes::quadrilateral above | ||
115 | // = 1/3 * (1/2 * norm(ADxBC)) * ((ADxBC)/norm(AD x BC) ⋅ AE) | ||
116 | // = 1/6 * (AD x BC) ⋅ AE | ||
117 | using std::abs; | ||
118 | 36484 | return 1.0/6.0 * abs( | |
119 | 364672 | Dumux::tripleProduct(c(3)-c(0), c(2)-c(1), c(4)-c(0)) | |
120 | 36484 | ); | |
121 | } | ||
122 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | else if (type == Dune::GeometryTypes::prism) |
123 | { | ||
124 | // compute as sum of a pyramid (0-1-3-4-5) and a tetrahedron (2-0-1-5) | ||
125 | using std::abs; | ||
126 | return 1.0/6.0 * ( | ||
127 | 20 | abs(Dumux::tripleProduct(c(3)-c(1), c(4)-c(0), c(5)-c(0))) | |
128 | 20 | + abs(Dumux::tripleProduct(c(5)-c(2), c(0)-c(2), c(1)-c(2))) | |
129 | 4 | ); | |
130 | } | ||
131 | else | ||
132 | return std::numeric_limits<ctype>::quiet_NaN(); | ||
133 | } | ||
134 | else | ||
135 | return std::numeric_limits<ctype>::quiet_NaN(); | ||
136 | } | ||
137 | |||
138 | /*! | ||
139 | * \ingroup Geometry | ||
140 | * \brief The volume of a given geometry | ||
141 | */ | ||
142 | template<class Geometry> | ||
143 | 292 | auto convexPolytopeVolume(const Geometry& geo) | |
144 | { | ||
145 | 292 | const auto v = convexPolytopeVolume<Geometry::mydimension>( | |
146 | 490 | geo.type(), [&](unsigned int i){ return geo.corner(i); } | |
147 | ); | ||
148 | |||
149 | // fall back to the method of the geometry if no specialized | ||
150 | // volume function is implemented for the geometry type | ||
151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
|
292 | return std::isnan(v) ? geo.volume() : v; |
152 | } | ||
153 | |||
154 | /*! | ||
155 | * \ingroup Geometry | ||
156 | * \brief The volume of a given geometry | ||
157 | */ | ||
158 | template<class Geometry> | ||
159 | 146 | auto volume(const Geometry& geo, unsigned int integrationOrder = 4) | |
160 | { | ||
161 | using ctype = typename Geometry::ctype; | ||
162 | 146 | ctype volume = 0.0; | |
163 | 292 | const auto rule = Dune::QuadratureRules<ctype, Geometry::mydimension>::rule(geo.type(), integrationOrder); | |
164 | 4938 | for (const auto& qp : rule) | |
165 | 4554 | volume += geo.integrationElement(qp.position())*qp.weight(); | |
166 | 292 | return volume; | |
167 | } | ||
168 | |||
169 | /*! | ||
170 | * \ingroup Geometry | ||
171 | * \brief The volume of a given geometry with an extrusion/transformation policy | ||
172 | * \note depending on the transformation this might not be an accurate quadrature rule anymore | ||
173 | */ | ||
174 | template<class Geometry, class Transformation> | ||
175 | 86517 | auto volume(const Geometry& geo, Transformation transformation, unsigned int integrationOrder = 4) | |
176 | { | ||
177 | using ctype = typename Geometry::ctype; | ||
178 | 86517 | ctype volume = 0.0; | |
179 |
1/4✓ Branch 3 taken 86517 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
248268 | const auto rule = Dune::QuadratureRules<ctype, Geometry::mydimension>::rule(geo.type(), integrationOrder); |
180 |
4/4✓ Branch 0 taken 778623 times.
✓ Branch 1 taken 86517 times.
✓ Branch 2 taken 778623 times.
✓ Branch 3 taken 86517 times.
|
1816797 | for (const auto& qp : rule) |
181 |
2/4✓ Branch 1 taken 101517 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 101517 times.
✗ Branch 5 not taken.
|
1557246 | volume += transformation.integrationElement(geo, qp.position())*qp.weight(); |
182 |
1/2✓ Branch 0 taken 86517 times.
✗ Branch 1 not taken.
|
173034 | return volume; |
183 | } | ||
184 | |||
185 | } // end namespace Dumux | ||
186 | |||
187 | #endif | ||
188 |