Dune-Fufem 2.11-git
Loading...
Searching...
No Matches
basisinterpolationmatrixassembler.hh
Go to the documentation of this file.
1// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set ts=8 sw=2 et sts=2:
3
4// SPDX-FileCopyrightText: Copyright © DUNE-FUFEM 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_FUFEM_ASSEMBLERS_BASIS_INTERPOLATION_MATRIX_ASSEMBLER_HH
8#define DUNE_FUFEM_ASSEMBLERS_BASIS_INTERPOLATION_MATRIX_ASSEMBLER_HH
9
10#include <type_traits>
11#include <cmath>
12#include <vector>
13
17
18#include <dune/assembler/backends/istlmatrixbackend.hh>
19
20#if DUNE_VERSION_GTE(DUNE_FUNCTIONS, 2, 11)
23#else
24#include <dune/typetree/childextraction.hh>
25#include <dune/typetree/traversal.hh>
26#endif
27
28
29
30namespace Impl{
31
32
33// This class provides the local interpolation operator
34// from a coarse local finite element to a fine local finite
35// element. The associated grid elements are mapped using a geometry
36// map. After being created, this can be bound to the coarse
37// basis functions and afterwards provides the respective interpolation
38// coefficients.
39//
40// Notice that this is restricted to cases, where FineLocalInterpolation::interpolate()
41// evaluates at a fixed deterministic point set not depending on the passed function.
42// In particular this will not work if interpolate() uses adaptive quadrature
43// or if it evaluatuated derivatives.
44template<class CoarseFiniteElement, class FineFiniteElement, class Geometry>
45class LocalInterpolationOperator
46{
47 using CoarseLocalBasis = typename CoarseFiniteElement::Traits::LocalBasisType;
48 using CoarseRange = typename CoarseLocalBasis::Traits::RangeType;
49
50 // Hack: The RangeFieldType is the best guess of a suitable type for coefficients we have here
51 using CoefficientType = typename CoarseLocalBasis::Traits::RangeFieldType;
52
53 using FineLocalInterpolation = typename FineFiniteElement::Traits::LocalInterpolationType;
54
55public:
56
57 LocalInterpolationOperator(const CoarseFiniteElement& coarseFiniteElement, const FineFiniteElement& fineFiniteElement, const Geometry& geometry)
58 : coarseLocalBasis_(coarseFiniteElement.localBasis())
59 , fineLocalInterpolation_(fineFiniteElement.localInterpolation())
60 , geometry_(geometry)
61 , coefficients_(fineFiniteElement.size())
62 , coarseValues_(fineFiniteElement.size())
63 {
64 // We first compute the values at all interpolation points.
65 // To this end a dummy call to interpolate() is used to deduce
66 // the interpolation points and evaluate the coarse bases.
67 // Later the, we can simply return the pre-computed values
68 // based on the evaluation order.
69 // This requires that interpolate() does the evaluation at
70 // a deterministic point set in a deterministic order and
71 // thus rules out e.g. adaptive quadrature.
72 // If the interpolation is given by simple point evaluations,
73 // the cache computed here is essentially the local interpolation
74 // matrix. However, it is also fine, if interpolate() does
75 // additional computations based on the values, like, e.g.
76 // a Piola-transformation.
77 auto k = 0;
78 auto trackingCoarseFunction = [&](const auto& x) {
79 coarseValues_.resize(k+1);
80 coarseLocalBasis_.evaluateFunction(geometry_(x), coarseValues_[k]);
81 return coarseValues_[k++][0];
82 };
83 fineLocalInterpolation_.interpolate(trackingCoarseFunction, coefficients_);
84 }
85
86 const auto& bindToCoarseBasisFunction(std::size_t coarseIndex)
87 {
88 // baseFctj behaves like the j-th coarse bases function if
89 // interpolate() evaluates it at the same points in the same
90 // order as above.
91 auto k = 0;
92 auto baseFctj = [&](const auto& x) {
93 return coarseValues_[k++][coarseIndex];
94 };
95
96 // Interpolate j^th base function by the fine basis
97 fineLocalInterpolation_.interpolate(baseFctj, coefficients_);
98 return coefficients_;
99 }
100
101 const auto& coefficients() const
102 {
103 return coefficients_;
104 }
105
106private:
107 const CoarseLocalBasis& coarseLocalBasis_;
108 const FineLocalInterpolation& fineLocalInterpolation_;
109 const Geometry& geometry_;
110 std::vector<CoefficientType> coefficients_;
112};
113
114
115
116} // namespace Impl
117
118
130template<class MatrixType, class CoarseBasis, class FineBasis>
131static void assembleGlobalBasisTransferMatrix(MatrixType& matrix,
132 const CoarseBasis& coarseBasis,
133 const FineBasis& fineBasis,
134 const double tolerance = 1e-12)
135{
136 const auto& coarseGridView = coarseBasis.gridView();
137 const auto& fineGridView = fineBasis.gridView();
138
139 auto coarseLocalView = coarseBasis.localView();
140 auto fineLocalView = fineBasis.localView();
141
142 // for multi index access wrap the matrix to the ISTLBackend
143 constexpr bool isAssemblerMatrixBackend = requires(MatrixType& matrixBackend) {
144 MatrixType::LocalPattern(0,0);
145 matrixBackend.setZero();
146 };
147
148 constexpr bool isFufemMatrixBackend = requires(MatrixType& matrixBackend) {
149 matrixBackend.matrix();
150 matrixBackend.assign(0);
151 };
152
153 // For compatibility we support three modes:
154 // Passing a plain matrix, a dune-fufem backend,
155 // or a dune-assembler backend.
156 auto&& matrixBackend = [&]() -> decltype(auto) {
157 if constexpr(isAssemblerMatrixBackend)
158 return matrix;
159 else if constexpr(isFufemMatrixBackend)
160 return Dune::Assembler::ISTLMatrixBackend(matrix.matrix());
161 else
162 return Dune::Assembler::ISTLMatrixBackend(matrix);
163 }();
164
165 // prepare index set with multi index access
166 auto patternBuilder = matrixBackend.patternBuilder();
167 patternBuilder.resize(fineBasis, coarseBasis);
168
169 // ///////////////////////////////////////////
170 // Determine the indices present in the matrix
171 // ///////////////////////////////////////////
172
173 // This map transforms coordinates to the ancestor element
174 // by chaining the GeometryInFather entries in the vector.
175 using GeometryInFather = std::decay_t<decltype(elements(fineGridView).begin()->geometryInFather())>;
176 std::vector<GeometryInFather> geometryInFathersVector;
177 const auto geometryInFathers = [&](auto&& x) {
178 auto y = x;
179 for (const auto& g : geometryInFathersVector)
180 y = g.global(y);
181 return y;
182 };
183
184 using MatrixBackend = std::decay_t<decltype(matrixBackend)>;
185
186 auto localPattern = typename MatrixBackend::LocalPattern(fineLocalView.maxSize(), coarseLocalView.maxSize());
187
188 // loop over all fine grid elements
189 for ( const auto& fineElement : elements(fineGridView) )
190 {
191 fineLocalView.bind(fineElement);
192
193 // find a coarse element that is the parent of the fine element
194 // start in the fine grid and track the geometry mapping
195 auto coarseElement = fineElement;
196 // collect all geometryInFather's on the way
197 geometryInFathersVector.clear();
198 while ( not coarseGridView.contains(coarseElement) and coarseElement.hasFather() )
199 {
200 // add the geometry to the container
201 geometryInFathersVector.push_back(coarseElement.geometryInFather());
202 // step up one level
203 coarseElement = coarseElement.father();
204 }
205
206 // did we really end up in coarseElement?
207 if ( not coarseGridView.contains(coarseElement) )
208 DUNE_THROW( Dune::Exception, "There is a fine element without a parent in the coarse grid!");
209
210 coarseLocalView.bind(coarseElement);
211
212 localPattern.resize(fineLocalView.size(), coarseLocalView.size());
213 localPattern.clear();
214
215 Dune::TypeTree::forEachLeafNode(coarseLocalView.tree(), [&] (const auto& coarseNode, const auto& treePath) {
216 auto&& fineNode = Dune::TypeTree::child(fineLocalView.tree(), treePath);
217
218 auto localInterpolationOperator = Impl::LocalInterpolationOperator(coarseNode.finiteElement(), fineNode.finiteElement(), geometryInFathers);
219 const auto& coefficients = localInterpolationOperator.coefficients();
220
221 for (auto j : Dune::range(coarseNode.size()))
222 {
223 localInterpolationOperator.bindToCoarseBasisFunction(j);
224 for (auto i : Dune::range(fineNode.size()))
225 {
226 if (std::abs(coefficients[i]) >= tolerance)
227 localPattern.add(fineNode.localIndex(i), coarseNode.localIndex(j));
228 }
229 }
230 });
231 patternBuilder.scatter(fineLocalView, coarseLocalView, localPattern);
232 }
233
234 // Setup matrix from computed index set
235 patternBuilder.setupMatrix();
236
238 // Now set the values
240
241 for ( const auto& fineElement : elements(fineGridView) )
242 {
243 fineLocalView.bind(fineElement);
244
245 // find a coarse element that is the parent of the fine element
246 // start in the fine grid and track the geometry mapping
247 auto coarseElement = fineElement;
248 // collect all geometryInFather's on the way
249 geometryInFathersVector.clear();
250 while ( not coarseGridView.contains(coarseElement) and coarseElement.hasFather() )
251 {
252 // add the geometry to the container
253 geometryInFathersVector.push_back(coarseElement.geometryInFather());
254 // step up one level
255 coarseElement = coarseElement.father();
256 }
257
258 coarseLocalView.bind(coarseElement);
259
260 // Ideally we would assemble into a local matrix and use scatter,
261 // but the latter only allows to add values. Here we want to
262 // overwrite them.
263 Dune::TypeTree::forEachLeafNode(coarseLocalView.tree(), [&] (const auto& coarseNode, const auto& treePath) {
264 auto&& fineNode = Dune::TypeTree::child(fineLocalView.tree(), treePath);
265
266 auto localInterpolationOperator = Impl::LocalInterpolationOperator(coarseNode.finiteElement(), fineNode.finiteElement(), geometryInFathers);
267 const auto& coefficients = localInterpolationOperator.coefficients();
268
269 for (auto j : Dune::range(coarseNode.size()))
270 {
271 localInterpolationOperator.bindToCoarseBasisFunction(j);
272 const auto& globalCoarseIndex = coarseLocalView.index( coarseNode.localIndex( j ) );
273 for (auto i : Dune::range(fineNode.size()))
274 {
275 if (std::abs(coefficients[i]) >= tolerance)
276 {
277 const auto& globalFineIndex = fineLocalView.index( fineNode.localIndex( i ) );
278 matrixBackend(globalFineIndex, globalCoarseIndex) = coefficients[i];
279 }
280 }
281 }
282 });
283
284 }
285}
286
287
288#endif
static void assembleGlobalBasisTransferMatrix(MatrixType &matrix, const CoarseBasis &coarseBasis, const FineBasis &fineBasis, const double tolerance=1e-12)
Assemble the transfer matrix for multigrid methods.
Definition basisinterpolationmatrixassembler.hh:131
int size() const
#define DUNE_THROW(E,...)
void forEachLeafNode(Tree &&tree, LeafFunc &&leafFunc)
IteratorRange<... > elements(const GV &gv)