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