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 Evaluate P1/Q1 basis with bubble function | ||
11 | */ | ||
12 | #ifndef DUMUX_DISCRETIZATION_PQ1BUBBLE_LOCAL_FINITE_ELEMENT_HH | ||
13 | #define DUMUX_DISCRETIZATION_PQ1BUBBLE_LOCAL_FINITE_ELEMENT_HH | ||
14 | |||
15 | #include <array> | ||
16 | #include <vector> | ||
17 | #include <numeric> | ||
18 | #include <algorithm> | ||
19 | |||
20 | #include <dune/common/fmatrix.hh> | ||
21 | #include <dune/common/fvector.hh> | ||
22 | #include <dune/common/exceptions.hh> | ||
23 | |||
24 | #include <dune/geometry/type.hh> | ||
25 | #include <dune/geometry/referenceelements.hh> | ||
26 | |||
27 | #include <dune/localfunctions/common/localbasis.hh> | ||
28 | #include <dune/localfunctions/common/localfiniteelementtraits.hh> | ||
29 | #include <dune/localfunctions/common/localkey.hh> | ||
30 | |||
31 | #include <dune/localfunctions/lagrange/lagrangesimplex.hh> | ||
32 | #include <dune/localfunctions/lagrange/lagrangecube.hh> | ||
33 | |||
34 | namespace Dumux::Detail { | ||
35 | |||
36 | /*! | ||
37 | * \brief P1/Q1 + Bubble on the reference element | ||
38 | * | ||
39 | * \tparam D Type to represent the field in the domain | ||
40 | * \tparam R Type to represent the field in the range | ||
41 | * \tparam dim Dimension of the domain element | ||
42 | * \tparam typeId The geometry type | ||
43 | */ | ||
44 | template<class D, class R, unsigned int dim, Dune::GeometryType::Id typeId> | ||
45 | class PQ1BubbleLocalBasis | ||
46 | { | ||
47 | using PQ1FiniteElement = std::conditional_t< | ||
48 | Dune::GeometryType{ typeId } == Dune::GeometryTypes::cube(dim), | ||
49 | Dune::LagrangeCubeLocalFiniteElement<D, R, dim, 1>, | ||
50 | Dune::LagrangeSimplexLocalFiniteElement<D, R, dim, 1> | ||
51 | >; | ||
52 | static constexpr std::size_t numDofs | ||
53 | = Dune::GeometryType{ typeId } == Dune::GeometryTypes::cube(dim) ? (1<<dim)+1 : (dim+1)+1; | ||
54 | public: | ||
55 | using Traits = Dune::LocalBasisTraits< | ||
56 | D, dim, Dune::FieldVector<D, dim>, | ||
57 | R, 1, Dune::FieldVector<R, 1>, | ||
58 | Dune::FieldMatrix<R, 1, dim> | ||
59 | >; | ||
60 | |||
61 | 56 | PQ1BubbleLocalBasis() | |
62 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
56 | : pq1FiniteElement_{} |
63 | { | ||
64 | // precompute center values for normalization | ||
65 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
56 | const auto& p1Basis = pq1FiniteElement_.localBasis(); |
66 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
56 | const auto refElement = Dune::referenceElement<typename Traits::DomainFieldType, dim>(type()); |
67 | 56 | const auto& center = refElement.position(0, 0); | |
68 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
56 | p1Basis.evaluateFunction(center, pq1AtCenter_); |
69 | 56 | } | |
70 | |||
71 | /*! | ||
72 | * \brief Number of shape functions (one for each vertex and one in the element) | ||
73 | */ | ||
74 | static constexpr unsigned int size() | ||
75 | { return numDofs; } | ||
76 | |||
77 | /*! | ||
78 | * \brief Evaluate all shape functions | ||
79 | */ | ||
80 | 37431036 | void evaluateFunction(const typename Traits::DomainType& x, | |
81 | std::vector<typename Traits::RangeType>& out) const | ||
82 | { | ||
83 | 37431036 | out.reserve(size()); | |
84 | 37431036 | const auto& p1Basis = pq1FiniteElement_.localBasis(); | |
85 | 37431036 | p1Basis.evaluateFunction(x, out); | |
86 | 37431036 | const auto bubble = evaluateBubble_(x); | |
87 | 37431036 | out.resize(size()); | |
88 | 37431036 | out.back() = bubble; | |
89 |
2/2✓ Branch 0 taken 64603880 times.
✓ Branch 1 taken 18715518 times.
|
166638796 | for (int i = 0; i < numDofs-1; ++i) |
90 | 129207760 | out[i] -= pq1AtCenter_[i]*out.back(); | |
91 | 37431036 | } | |
92 | |||
93 | /*! | ||
94 | * \brief Evaluate the Jacobians of all shape functions | ||
95 | */ | ||
96 | 2105276 | void evaluateJacobian(const typename Traits::DomainType& x, | |
97 | std::vector<typename Traits::JacobianType>& out) const | ||
98 | { | ||
99 | 2105276 | out.reserve(size()); | |
100 | 2105276 | const auto& p1Basis = pq1FiniteElement_.localBasis(); | |
101 | 2105276 | p1Basis.evaluateJacobian(x, out); | |
102 | |||
103 | 2105276 | std::vector<typename Traits::RangeType> shapeValues; | |
104 |
1/2✓ Branch 1 taken 1052638 times.
✗ Branch 2 not taken.
|
2105276 | p1Basis.evaluateFunction(x, shapeValues); |
105 | |||
106 | 2105276 | const auto bubbleJacobian = evaluateBubbleJacobian_(x); | |
107 | |||
108 |
2/2✓ Branch 1 taken 3792408 times.
✓ Branch 2 taken 1052638 times.
|
9690092 | for (int i = 0; i < numDofs-1; ++i) |
109 |
2/2✓ Branch 0 taken 7791464 times.
✓ Branch 1 taken 3792408 times.
|
23167744 | for (int k = 0; k < dim; ++k) |
110 | 15582928 | out[i][0][k] -= pq1AtCenter_[i]*bubbleJacobian[0][k]; | |
111 | |||
112 |
1/2✓ Branch 1 taken 1052638 times.
✗ Branch 2 not taken.
|
2105276 | out.resize(size()); |
113 |
1/2✓ Branch 0 taken 1052638 times.
✗ Branch 1 not taken.
|
2105276 | out.back() = bubbleJacobian; |
114 | 2105276 | } | |
115 | |||
116 | /** \brief Evaluate partial derivatives of any order of all shape functions | ||
117 | * | ||
118 | * \param order Order of the partial derivatives, in the classic multi-index notation | ||
119 | * \param in Position where to evaluate the derivatives | ||
120 | * \param[out] out The desired partial derivatives | ||
121 | */ | ||
122 | ✗ | void partial(const std::array<unsigned int, dim>& order, | |
123 | const typename Traits::DomainType& in, | ||
124 | std::vector<typename Traits::RangeType>& out) const | ||
125 | { | ||
126 | ✗ | DUNE_THROW(Dune::NotImplemented, "Partial derivatives"); | |
127 | } | ||
128 | |||
129 | /*! | ||
130 | * \brief Evaluate the Jacobians of all shape functions | ||
131 | * we are actually cubic/quartic but cannot represent all cubic/quartic polynomials | ||
132 | */ | ||
133 | static constexpr unsigned int order() | ||
134 | { | ||
135 | return 1; | ||
136 | } | ||
137 | |||
138 | /*! | ||
139 | * \brief The reference element type | ||
140 | */ | ||
141 | static constexpr Dune::GeometryType type() | ||
142 | { | ||
143 | return { typeId }; | ||
144 | } | ||
145 | private: | ||
146 | // evaluate bubble function at x | ||
147 | 18715518 | typename Traits::RangeType evaluateBubble_(const typename Traits::DomainType& x) const | |
148 | { | ||
149 | if constexpr (type() == Dune::GeometryTypes::simplex(dim)) | ||
150 | { | ||
151 | if constexpr (dim == 2) | ||
152 | 10258192 | return 27*x[0]*x[1]*(1-x[0]-x[1]); | |
153 | else if constexpr (dim == 3) | ||
154 | 754062 | return 256*x[0]*x[1]*x[2]*(1-x[0]-x[1]-x[2]); | |
155 | } | ||
156 | else if constexpr (type() == Dune::GeometryTypes::cube(dim)) | ||
157 | { | ||
158 | if constexpr (dim == 2) | ||
159 | 7703264 | return 16*x[0]*x[1]*(1-x[0])*(1-x[1]); | |
160 | else if constexpr (dim == 3) | ||
161 | ✗ | return 64*x[0]*x[1]*x[2]*(1-x[0])*(1-x[1])*(1-x[2]); | |
162 | } | ||
163 | else | ||
164 | DUNE_THROW(Dune::NotImplemented, "Bubble function for " << type()); | ||
165 | } | ||
166 | |||
167 | // evaluate bubble function at x | ||
168 | 2105276 | typename Traits::JacobianType evaluateBubbleJacobian_(const typename Traits::DomainType& x) const | |
169 | { | ||
170 | if constexpr (type() == Dune::GeometryTypes::simplex(dim)) | ||
171 | { | ||
172 | if constexpr (dim == 2) | ||
173 | 836288 | return {{27*(x[1]*(1-x[0]-x[1]) - x[0]*x[1]), | |
174 | 836288 | 27*(x[0]*(1-x[0]-x[1]) - x[0]*x[1])}}; | |
175 | else if constexpr (dim == 3) | ||
176 | 103324 | return {{256*(x[1]*x[2]*(1-x[0]-x[1]-x[2]) - x[0]*x[1]*x[2]), | |
177 | 103324 | 256*(x[0]*x[2]*(1-x[0]-x[1]-x[2]) - x[0]*x[1]*x[2]), | |
178 | 103324 | 256*(x[0]*x[1]*(1-x[0]-x[1]-x[2]) - x[0]*x[1]*x[2])}}; | |
179 | } | ||
180 | else if constexpr (type() == Dune::GeometryTypes::cube(dim)) | ||
181 | { | ||
182 | if constexpr (dim == 2) | ||
183 | 1165664 | return {{16*(x[1]*(1-x[0])*(1-x[1]) - x[0]*x[1]*(1-x[1])), | |
184 | 1165664 | 16*(x[0]*(1-x[0])*(1-x[1]) - x[0]*x[1]*(1-x[0]))}}; | |
185 | else if constexpr (dim == 3) | ||
186 | ✗ | return {{64*(x[1]*x[2]*(1-x[0])*(1-x[1])*(1-x[2]) - x[0]*x[1]*x[2]*(1-x[1]))*(1-x[2]), | |
187 | ✗ | 64*(x[0]*x[2]*(1-x[0])*(1-x[1])*(1-x[2]) - x[0]*x[1]*x[2]*(1-x[0]))*(1-x[2]), | |
188 | ✗ | 64*(x[0]*x[1]*(1-x[0])*(1-x[1])*(1-x[2]) - x[0]*x[1]*x[2]*(1-x[0]))*(1-x[1])}}; | |
189 | } | ||
190 | else | ||
191 | DUNE_THROW(Dune::NotImplemented, "Bubble function for " << type() << " dim = " << dim); | ||
192 | } | ||
193 | |||
194 | PQ1FiniteElement pq1FiniteElement_; | ||
195 | std::vector<typename Traits::RangeType> pq1AtCenter_; | ||
196 | }; | ||
197 | |||
198 | /*! | ||
199 | * \brief Associations of the P1/Q1 + Bubble degrees of freedom to the facets of the reference element | ||
200 | * \tparam dim Dimension of the reference element | ||
201 | * \tparam typeId The geometry type | ||
202 | */ | ||
203 | template<int dim, Dune::GeometryType::Id typeId> | ||
204 | class PQ1BubbleLocalCoefficients | ||
205 | { | ||
206 | static constexpr std::size_t numDofs | ||
207 | = Dune::GeometryType{ typeId } == Dune::GeometryTypes::cube(dim) ? (1<<dim)+1 : (dim+1)+1; | ||
208 | public: | ||
209 | |||
210 | PQ1BubbleLocalCoefficients() | ||
211 | { | ||
212 | // Dune::LocalKey is constructed with | ||
213 | // - the local index with respect to the subentity type | ||
214 | // - the codim of the subentity the dof is attached to | ||
215 | // - the local number of the function to evaluate | ||
216 | |||
217 | // vertex dofs | ||
218 | for (std::size_t i=0; i<size()-1; i++) | ||
219 | localKeys_[i] = Dune::LocalKey(i, dim, 0); | ||
220 | |||
221 | // cell dof | ||
222 | localKeys_.back() = Dune::LocalKey(0, 0, 0); | ||
223 | } | ||
224 | |||
225 | //! Number of coefficients | ||
226 | static constexpr std::size_t size () | ||
227 | { return numDofs; } | ||
228 | |||
229 | //! Get i-th local key | ||
230 | 4714080 | const Dune::LocalKey& localKey (std::size_t i) const | |
231 | 4714080 | { return localKeys_[i]; } | |
232 | |||
233 | private: | ||
234 | std::array<Dune::LocalKey, numDofs> localKeys_; | ||
235 | }; | ||
236 | |||
237 | /*! | ||
238 | * \brief Evaluate the degrees of freedom of a P1 + Bubble basis | ||
239 | * | ||
240 | * \tparam LocalBasis The corresponding set of shape functions | ||
241 | */ | ||
242 | template<class LocalBasis> | ||
243 | class PQ1BubbleLocalInterpolation | ||
244 | { | ||
245 | public: | ||
246 | /*! | ||
247 | * \brief Evaluate a given function at the vertices and the cell midpoint | ||
248 | * | ||
249 | * \tparam F Type of function to evaluate | ||
250 | * \tparam C Type used for the values of the function | ||
251 | * \param[in] f Function to evaluate (call operator that gets a local position) | ||
252 | * \param[out] out Array of function values | ||
253 | */ | ||
254 | template<typename F, typename C> | ||
255 | ✗ | void interpolate (const F& f, std::vector<C>& out) const | |
256 | { | ||
257 | ✗ | constexpr auto dim = LocalBasis::Traits::dimDomain; | |
258 | |||
259 | ✗ | out.resize(LocalBasis::size()); | |
260 | |||
261 | ✗ | const auto refElement = Dune::referenceElement<typename LocalBasis::Traits::DomainFieldType,dim>(LocalBasis::type()); | |
262 | |||
263 | // Evaluate at the vertices and at the center | ||
264 | ✗ | for (int i = 0; i < refElement.size(dim); ++i) | |
265 | ✗ | out[i] = f(refElement.position(i, dim)); | |
266 | ✗ | out.back() = f(refElement.position(0, 0)); | |
267 | ✗ | } | |
268 | }; | ||
269 | |||
270 | } // end namespace Dumux::Detail | ||
271 | |||
272 | namespace Dumux { | ||
273 | |||
274 | /*! | ||
275 | * \brief P1/Q1 + Bubble finite element | ||
276 | * | ||
277 | * \tparam D type used for domain coordinates | ||
278 | * \tparam R type used for function values | ||
279 | * \tparam dim dimension of the reference element | ||
280 | * \tparam typeId The geometry type | ||
281 | */ | ||
282 | template<class D, class R, int dim, Dune::GeometryType::Id typeId> | ||
283 |
2/4✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
84 | class PQ1BubbleLocalFiniteElement |
284 | { | ||
285 | using Basis = Detail::PQ1BubbleLocalBasis<D, R, dim, typeId>; | ||
286 | using Coefficients = Detail::PQ1BubbleLocalCoefficients<dim, typeId>; | ||
287 | using Interpolation = Detail::PQ1BubbleLocalInterpolation<Basis>; | ||
288 | |||
289 | static constexpr Dune::GeometryType gt = Dune::GeometryType{ typeId }; | ||
290 | static_assert( | ||
291 | gt == Dune::GeometryTypes::cube(dim) || gt == Dune::GeometryTypes::simplex(dim), | ||
292 | "Only implemented for cubes and simplices" | ||
293 | ); | ||
294 | |||
295 | public: | ||
296 | using Traits = Dune::LocalFiniteElementTraits<Basis, Coefficients, Interpolation>; | ||
297 | |||
298 | /*! | ||
299 | * \brief Returns the local basis, i.e., the set of shape functions | ||
300 | */ | ||
301 | 28 | const typename Traits::LocalBasisType& localBasis() const | |
302 | { | ||
303 | 28 | return basis_; | |
304 | } | ||
305 | |||
306 | /*! | ||
307 | * \brief Returns the assignment of the degrees of freedom to the element subentities | ||
308 | */ | ||
309 | 28 | const typename Traits::LocalCoefficientsType& localCoefficients() const | |
310 | { | ||
311 | 28 | return coefficients_; | |
312 | } | ||
313 | |||
314 | /*! | ||
315 | * \brief Returns object that evaluates degrees of freedom | ||
316 | */ | ||
317 | 28 | const typename Traits::LocalInterpolationType& localInterpolation() const | |
318 | { | ||
319 | 28 | return interpolation_; | |
320 | } | ||
321 | |||
322 | /*! | ||
323 | * \brief The number of coefficients in the basis | ||
324 | */ | ||
325 | static constexpr std::size_t size() | ||
326 | { | ||
327 | return Basis::size(); | ||
328 | } | ||
329 | |||
330 | /*! | ||
331 | * \brief The reference element type that the local finite element is defined on | ||
332 | */ | ||
333 | static constexpr Dune::GeometryType type() | ||
334 | { | ||
335 | return Traits::LocalBasisType::type(); | ||
336 | } | ||
337 | |||
338 | private: | ||
339 | Basis basis_; | ||
340 | Coefficients coefficients_; | ||
341 | Interpolation interpolation_; | ||
342 | }; | ||
343 | |||
344 | } // end namespace Dumux | ||
345 | |||
346 | #endif | ||
347 |