DUNE PDELab (git)

globalvaluedlocalfiniteelement.hh
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3
4// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_GLOBALVALUEDLOCALFINITEELEMENT_HH
8#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_GLOBALVALUEDLOCALFINITEELEMENT_HH
9
10#include <array>
11#include <numeric>
12
15#include <dune/common/math.hh>
17
18#include <dune/geometry/referenceelements.hh>
19
20#include <dune/localfunctions/common/localbasis.hh>
21#include <dune/localfunctions/common/localfiniteelementtraits.hh>
22
23#include <dune/functions/common/densevectorview.hh>
24
25namespace Dune::Functions::Impl
26{
27
41 struct ContravariantPiolaTransformator
42 {
47 template<typename Values, typename LocalCoordinate, typename Geometry>
48 static auto apply(Values& values,
49 const LocalCoordinate& xi,
50 const Geometry& geometry)
51 {
52 auto jacobianTransposed = geometry.jacobianTransposed(xi);
53 auto integrationElement = geometry.integrationElement(xi);
54
55 for (auto& value : values)
56 {
57 auto tmp = value;
58 // Here we cannot directly use
59 // jacobianTransposed.mtv(tmp, value);
60 // because mtv expects the DenseVector interface.
61 auto tmpDenseVector = Impl::DenseVectorView(tmp);
62 auto valueDenseVector = Impl::DenseVectorView(value);
63 jacobianTransposed.mtv(tmpDenseVector, valueDenseVector);
64 value /= integrationElement;
65 }
66 }
67
77 template<typename Gradients, typename LocalCoordinate, typename Geometry>
78 static auto applyJacobian(Gradients& gradients,
79 const LocalCoordinate& xi,
80 const Geometry& geometry)
81 {
82 auto jacobianTransposed = geometry.jacobianTransposed(xi);
83 auto integrationElement = geometry.integrationElement(xi);
84 for (auto& gradient : gradients)
85 {
86 auto tmp = gradient;
87 gradient = 0;
88 for (size_t k=0; k<gradient.M(); k++)
89 for (size_t l=0; l<tmp.N(); l++)
90 // Use sparseRange because jacobianTransposed may be a sparse DiagonalMatrix
91 for(auto&& [jacobianTransposed_l_j, j] : sparseRange(jacobianTransposed[l]))
92 gradient[j][k] += jacobianTransposed_l_j * tmp[l][k];
93 gradient /= integrationElement;
94 }
95 }
96
104 template<class Function, class LocalCoordinate, class Element>
105 class LocalValuedFunction
106 {
107 const Function& f_;
108 const Element& element_;
109
110 using LocalValue = LocalCoordinate;
111
112 public:
113
114 LocalValuedFunction(const Function& f, const Element& element)
115 : f_(f), element_(element)
116 {}
117
118 auto operator()(const LocalCoordinate& xi) const
119 {
120 auto globalValue = f_(xi);
121
122 // Apply the inverse Piola transform
123 auto jacobianInverseTransposed = element_.geometry().jacobianInverseTransposed(xi);
124 auto integrationElement = element_.geometry().integrationElement(xi);
125
126 auto localValue = LocalValue{};
127
128 // Here we cannot directly use
129 // jacobianInverseTransposed.mtv(globalValue, localValue);
130 // because mtv expects the DenseVector interface.
131 auto globalValueDenseVector = Impl::DenseVectorView(globalValue);
132 auto localValueDenseVector = Impl::DenseVectorView(localValue);
133 jacobianInverseTransposed.mtv(globalValueDenseVector, localValueDenseVector);
134 localValue *= integrationElement;
135
136 return localValue;
137 }
138 };
139 };
140
154 struct CovariantPiolaTransformator
155 {
160 template<typename Values, typename LocalCoordinate, typename Geometry>
161 static auto apply(Values& values,
162 const LocalCoordinate& xi,
163 const Geometry& geometry)
164 {
165 auto jacobianInverseTransposed = geometry.jacobianInverseTransposed(xi);
166
167 for (auto& value : values)
168 {
169 auto tmp = value;
170 // Here we cannot directly use
171 // jacobianInverseTransposed.mv(tmp, value);
172 // because mv expects the DenseVector interface.
173 auto tmpDenseVector = Impl::DenseVectorView(tmp);
174 auto valueDenseVector = Impl::DenseVectorView(value);
175 jacobianInverseTransposed.mv(tmpDenseVector, valueDenseVector);
176 }
177 }
178
188 template<typename Gradients, typename LocalCoordinate, typename Geometry>
189 static auto applyJacobian(Gradients& gradients,
190 const LocalCoordinate& xi,
191 const Geometry& geometry)
192 {
193 auto jacobianInverseTransposed = geometry.jacobianInverseTransposed(xi);
194
195 for (auto& gradient : gradients)
196 {
197 auto tmp = gradient;
198 gradient = 0;
199 for (size_t j=0; j<gradient.N(); j++)
200 for (size_t k=0; k<gradient.M(); k++)
201 // Use sparseRange because jacobianTransposed may be a sparse DiagonalMatrix
202 for(auto&& [jacobianInverseTransposed_j_l, l] : sparseRange(jacobianInverseTransposed[j]))
203 gradient[j][k] += jacobianInverseTransposed_j_l * tmp[l][k];
204 }
205 }
206
214 template<class Function, class LocalCoordinate, class Element>
215 class LocalValuedFunction
216 {
217 const Function& f_;
218 const Element& element_;
219
220 public:
221
222 LocalValuedFunction(const Function& f, const Element& element)
223 : f_(f), element_(element)
224 {}
225
226 auto operator()(const LocalCoordinate& xi) const
227 {
228 auto globalValue = f_(xi);
229
230 // Apply the inverse Piola transform
231 auto jacobianTransposed = element_.geometry().jacobianTransposed(xi);
232
233 auto localValue = globalValue;
234 // Here we cannot directly use
235 // jacobianTransposed.mv(globalValue, localValue);
236 // because mv expects the DenseVector interface.
237 auto localValueDenseVector = Impl::DenseVectorView(localValue);
238 auto globalValueDenseVector = Impl::DenseVectorView(globalValue);
239 jacobianTransposed.mv(globalValueDenseVector, localValueDenseVector);
240
241 return localValue;
242 }
243 };
244 };
245
252 template<class Transformator, class LocalValuedLocalBasis, class Element>
253 class GlobalValuedLocalBasis
254 {
255 public:
256 using Traits = typename LocalValuedLocalBasis::Traits;
257
260 void bind(const LocalValuedLocalBasis& localValuedLocalBasis, const Element& element)
261 {
262 localValuedLocalBasis_ = &localValuedLocalBasis;
263 element_ = &element;
264 }
265
268 auto size() const
269 {
270 return localValuedLocalBasis_->size();
271 }
272
274 void evaluateFunction(const typename Traits::DomainType& x,
275 std::vector<typename Traits::RangeType>& out) const
276 {
277 localValuedLocalBasis_->evaluateFunction(x,out);
278
279 Transformator::apply(out, x, element_->geometry());
280 }
281
287 void evaluateJacobian(const typename Traits::DomainType& x,
288 std::vector<typename Traits::JacobianType>& out) const
289 {
290 localValuedLocalBasis_->evaluateJacobian(x,out);
291
292 Transformator::applyJacobian(out, x, element_->geometry());
293 }
294
301 void partial(const std::array<unsigned int,2>& order,
302 const typename Traits::DomainType& x,
303 std::vector<typename Traits::RangeType>& out) const
304 {
305 auto totalOrder = std::accumulate(order.begin(), order.end(), 0);
306 if (totalOrder == 0) {
307 evaluateFunction(x, out);
308 } else if (totalOrder == 1) {
309 auto const direction = std::distance(order.begin(), std::find(order.begin(), order.end(), 1));
310 out.resize(size());
311
312 // TODO: The following is wasteful: We compute the full Jacobian and then return
313 // only a part of it. While we need the full Jacobian of the underlying local-valued LFE,
314 // it should be possible to compute only a partial Piola transform for the requested
315 // partial derivatives.
316 std::vector<typename Traits::JacobianType> fullJacobian;
317 localValuedLocalBasis_->evaluateJacobian(x,fullJacobian);
318
319 Transformator::applyJacobian(fullJacobian, x, element_->geometry());
320
321 for (std::size_t i=0; i<out.size(); i++)
322 for (std::size_t j=0; j<out[i].size(); j++)
323 out[i][j] = fullJacobian[i][j][direction];
324
325 } else
326 DUNE_THROW(NotImplemented, "Partial derivatives of order 2 or higher");
327 }
328
330 auto order() const
331 {
332 return localValuedLocalBasis_->order();
333 }
334
335 const LocalValuedLocalBasis* localValuedLocalBasis_;
336 const Element* element_;
337 };
338
347 template<class Transformator, class LocalValuedLocalInterpolation, class Element>
348 class GlobalValuedLocalInterpolation
349 {
350 public:
353 void bind(const LocalValuedLocalInterpolation& localValuedLocalInterpolation, const Element& element)
354 {
355 localValuedLocalInterpolation_ = &localValuedLocalInterpolation;
356 element_ = &element;
357 }
358
359 template<typename F, typename C>
360 void interpolate (const F& f, std::vector<C>& out) const
361 {
362 using LocalCoordinate = typename Element::Geometry::LocalCoordinate;
363 typename Transformator::template LocalValuedFunction<F,LocalCoordinate,Element> localValuedFunction(f, *element_);
364 localValuedLocalInterpolation_->interpolate(localValuedFunction, out);
365 }
366
367 private:
368 const LocalValuedLocalInterpolation* localValuedLocalInterpolation_;
369 const Element* element_;
370 };
371
372
379 template<class Transformator, class LocalValuedLFE, class Element>
380 class GlobalValuedLocalFiniteElement
381 {
382 using LocalBasis = GlobalValuedLocalBasis<Transformator,
383 typename LocalValuedLFE::Traits::LocalBasisType,
384 Element>;
385 using LocalInterpolation = GlobalValuedLocalInterpolation<Transformator,
386 typename LocalValuedLFE::Traits::LocalInterpolationType,
387 Element>;
388
389 public:
392 using Traits = LocalFiniteElementTraits<LocalBasis,
393 typename LocalValuedLFE::Traits::LocalCoefficientsType,
394 LocalInterpolation>;
395
396 GlobalValuedLocalFiniteElement() {}
397
398 void bind(const LocalValuedLFE& localValuedLFE, const Element& element)
399 {
400 globalValuedLocalBasis_.bind(localValuedLFE.localBasis(), element);
401 globalValuedLocalInterpolation_.bind(localValuedLFE.localInterpolation(), element);
402 localValuedLFE_ = &localValuedLFE;
403 }
404
407 const typename Traits::LocalBasisType& localBasis() const
408 {
409 return globalValuedLocalBasis_;
410 }
411
414 const typename Traits::LocalCoefficientsType& localCoefficients() const
415 {
416 return localValuedLFE_->localCoefficients();
417 }
418
421 const typename Traits::LocalInterpolationType& localInterpolation() const
422 {
423 return globalValuedLocalInterpolation_;
424 }
425
427 std::size_t size() const
428 {
429 return localValuedLFE_->size();
430 }
431
434 GeometryType type() const
435 {
436 return localValuedLFE_->type();
437 }
438
439 private:
440
441 typename Traits::LocalBasisType globalValuedLocalBasis_;
442 typename Traits::LocalInterpolationType globalValuedLocalInterpolation_;
443 const LocalValuedLFE* localValuedLFE_;
444 };
445
446} // namespace Dune::Functions::Impl
447
448#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_GLOBALVALUEDLOCALFINITEELEMENT_HH
GeometryType
Type representing VTK's entity geometry types.
Definition: common.hh:132
Implements a matrix constructed from a given type representing a field and compile-time given number ...
Implements a vector constructed from a given type representing a field and a compile-time given size.
#define DUNE_THROW(E,...)
Definition: exceptions.hh:312
void interpolate(const F &f, const GFS &gfs, XG &xg)
interpolation from a given grid function
Definition: interpolate.hh:177
constexpr T accumulate(Range &&range, T value, F &&f)
Accumulate values.
Definition: hybridutilities.hh:279
auto sparseRange(Range &&range)
Allow structured-binding for-loops for sparse iterators.
Definition: rangeutilities.hh:722
Some useful basic math stuff.
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
Utilities for reduction like operations on ranges.
LB LocalBasisType
Definition: localfiniteelementtraits.hh:16
LC LocalCoefficientsType
Definition: localfiniteelementtraits.hh:20
LI LocalInterpolationType
Definition: localfiniteelementtraits.hh:24
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jan 8, 23:30, 2025)