Dune-Fufem 2.11-git
Loading...
Searching...
No Matches
transferoperatorassembler.hh
Go to the documentation of this file.
1// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set ts=8 sw=4 et sts=4:
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_TRANSFER_OPERATOR_ASSEMBLER_HH
8#define DUNE_FUFEM_ASSEMBLERS_TRANSFER_OPERATOR_ASSEMBLER_HH
9
10#include <vector>
11#include <map>
12#include <memory>
13
16#include <dune/common/timer.hh>
18
20
21namespace Dune::Fufem::Impl {
22
23template <class GridType>
24class MultiLevelPQ1Indices
25{
26 private:
27 static const int dim = GridType::dimension;
28
29 public:
30
31 MultiLevelPQ1Indices(const GridType& grid) :
32 grid(grid)
33 {
34 const auto& localIdSet = grid.localIdSet();
35 const auto& leafIndexSet = grid.leafIndexSet();
36
37 int maxLevel = grid.maxLevel();
38
39 idToIndex.resize(maxLevel+1);
40 size_.resize(maxLevel+1);
41
42 size_[maxLevel] = grid.size(dim);
43
44 // build extended level indices as map (localId -> index)
45 // 1. enumerate vertices on each level
46 // 2. enumerate leaf vertices on each finer level to emulate copies of them
47 // 3. on maxlevel take the leaf indices
48 //
49 // example: level=*, copy=(*), leaf=[*]
50 //
51 // [1] - - - - - - - [2]---[3]---[4] - - - [5]
52 //
53 // (4) - - - - - - - 1-----------2-----------3
54 //
55 // 1-----------------------2-----------------------3
56
57 // first use the level indices
58 for(int level=0; level<maxLevel; ++level)
59 {
60 const auto& indexSet = grid.levelIndexSet(level);
61 size_[level] = indexSet.size(dim);
62 for (const auto& it : vertices(grid.levelGridView(level)))
63 idToIndex[level][localIdSet.id(it)] = indexSet.index(it);
64 }
65
66 for (const auto& it : vertices(grid.leafGridView()))
67 {
68 idToIndex[maxLevel][localIdSet.id(it)] = leafIndexSet.index(it);
69
70 for(int level=it.level()+1; level<maxLevel; ++level)
71 {
72 idToIndex[level][localIdSet.id(it)] = size_[level];
73 ++size_[level];
74 }
75 }
76 }
77
78 int size(int level)
79 {
80 return size_[level];
81 }
82
83 template<class LocalView>
84 int index(const LocalView& localView, const int i, const int level) const
85 {
86 const Dune::LocalKey& localKey = localView.tree().finiteElement().localCoefficients().localKey(i);
87 const IdType id = grid.localIdSet().subId(localView.element(), localKey.subEntity(), localKey.codim());
88 return idToIndex[level].find(id)->second;
89 }
90
91
92 private:
93 const GridType& grid;
94
95 typedef typename GridType::Traits::LocalIdSet::IdType IdType;
97 std::vector<int> size_;
98};
99
100} // namespace Dune::Fufem::Impl
101
102
104template <class GridType>
106
107 public:
108 TransferOperatorAssembler(const GridType& grid) :
109 grid(grid)
110 {}
111
112
113 template <class TransferOperator>
115 {
117
118 int maxLevel = grid.maxLevel();
119
120 M.resize(maxLevel);
121
122 for (int i=0; i<maxLevel; ++i)
123 M[i] = &(const_cast<typename TransferOperator::TransferOperatorType&>(T[i].getMatrix()));
125 }
126
127 template <class TransferOperator, class RealTransferOperator>
129 {
130 typedef typename RealTransferOperator::TransferOperatorType TransferOperatorType;
132
133 int maxLevel = grid.maxLevel();
134
135 M.resize(maxLevel);
136
137 for (int i=0; i<maxLevel; ++i)
138 {
139 RealTransferOperator* t = dynamic_cast<RealTransferOperator*>(T[i]);
140 M[i] = &(const_cast<TransferOperatorType&>(t->getMatrix()));
141 }
143 }
144
145 template <class TransferOperator>
147 {
149
150 int maxLevel = grid.maxLevel();
151
152 M.resize(maxLevel);
153
154 for (int i=0; i<maxLevel; ++i)
155 M[i] = &(const_cast<typename TransferOperator::TransferOperatorType&>(T[i]->getMatrix()));
157 }
158
167 template <class Matrix>
169 {
170 while(M.size() < uint(grid.maxLevel()))
171 M.push_back(std::make_shared<Matrix>());
172
173 std::vector <Matrix*> Mraw(M.size());
174 for (size_t i=0; i<M.size(); ++i)
175 Mraw[i] = M[i].get();
176
178 }
179
188 template <class Matrix>
190 {
191 typedef std::map<int, double> LinearCombination;
192 typedef std::vector<LinearCombination> BaseTransformation;
193 typedef std::vector<BaseTransformation> TransformationHierarchy;
195 typedef typename LevelBasis::LocalView::Tree::FiniteElement LFE;
196 typedef typename LFE::Traits::LocalBasisType::Traits::RangeType FERange;
197
198 Dune::Timer timer;
199
200 int maxLevel = grid.maxLevel();
201
202 std::vector<LevelBasis> levelBasis;
203 for(int level=0; level<=maxLevel; ++level)
204 levelBasis.emplace_back(grid.levelGridView(level));
205
206 Dune::Fufem::Impl::MultiLevelPQ1Indices<GridType> multiLevelIndexSet(grid);
207
208#ifdef FE_VERBOSE
209 std::cout << "FE:" << "localId -> index maps build in " << timer.elapsed() << " seconds." << std::endl;
210#endif
211
212
213 TransformationHierarchy transformationHierarchy(maxLevel);
214 for (int level=0; level<maxLevel; ++level)
215 transformationHierarchy[level].resize(multiLevelIndexSet.size(level+1));
216
217 // set all nodes as not processed
219 for (int level=0; level<=maxLevel; ++level)
220 processed[level].resize(multiLevelIndexSet.size(level), false);
221
222 // loop over all levels
223 timer.reset();
224 for(int level=0; level<grid.maxLevel(); ++level)
225 {
226 auto coarseLocalView = levelBasis[level].localView();
227 auto fineLocalView = levelBasis[level+1].localView();
228
229 // loop over all elements of current level
230 for (const auto& cIt : elements(grid.levelGridView(level)))
231 {
232 coarseLocalView.bind(cIt);
233 const LFE& coarseFE = coarseLocalView.tree().finiteElement();
234
235 // if element is leaf the transfer to the next level is locally the identity
236 if (cIt.isLeaf())
237 {
238 for (int coarseLevel=level; coarseLevel<maxLevel; ++coarseLevel)
239 {
240 int fineLevel = coarseLevel+1;
241
242 for(size_t j=0; j<coarseFE.localBasis().size(); ++j)
243 {
244 int fineIndex = multiLevelIndexSet.index(coarseLocalView, j, fineLevel);
245
246 // visit each child node only once
247 if (processed[fineLevel][fineIndex][0])
248 continue;
249
250 int coarseIndex = multiLevelIndexSet.index(coarseLocalView, j, coarseLevel);
251 transformationHierarchy[coarseLevel][fineIndex][coarseIndex] = 1.0;
252 processed[fineLevel][fineIndex][0] = true;
253 }
254 }
255 }
256 else
257 {
258 int coarseLevel = level;
259 int fineLevel = level+1;
260
261 // store coarse node indices since we need them often
262 std::vector<int> coarseIndex(coarseFE.localBasis().size());
263 for(size_t i=0; i<coarseFE.localBasis().size(); ++i)
264 coarseIndex[i] = multiLevelIndexSet.index(coarseLocalView, i, coarseLevel);
265
266 std::vector<FERange> valuesAtPosition(coarseFE.localBasis().size());
267
268 // loop over all children on next level
269 for (const auto& fIt : descendantElements(cIt,level+1))
270 {
271 fineLocalView.bind(fIt);
272 const LFE& fineFE = fineLocalView.tree().finiteElement();
273
274 // we need the reference element to get the local position of the subentities corresponding to fine basis functions
275 auto fineRefElement = Dune::ReferenceElements<double, dim>::general(fIt.type());
276
277 // loop over all child nodes
278 for(size_t j=0; j<fineFE.localBasis().size(); ++j)
279 {
280 int fineIndex = multiLevelIndexSet.index(fineLocalView, j, fineLevel);
281
282 // visit each child node only once
283 if (processed[fineLevel][fineIndex][0])
284 continue;
285
286 // get local coordinates of subentity in fine element
287 const Dune::LocalKey& localKey = fineFE.localCoefficients().localKey(j);
288 auto localPositionFine = fineRefElement.position(localKey.subEntity(), localKey.codim());
289
290 // compute local coordinates of subentity in coarse element
291 auto localPositionCoarse = fIt.geometryInFather().global(localPositionFine);
292
293 // evaluate coarse basis functions at the position of the subentity corresponding to the fine basis function
294 coarseFE.localBasis().evaluateFunction(localPositionCoarse, valuesAtPosition);
295
296 for(size_t i=0; i<coarseFE.localBasis().size(); ++i)
297 {
298 if (valuesAtPosition[i] > 1e-5)
299 transformationHierarchy[coarseLevel][fineIndex][coarseIndex[i]] = valuesAtPosition[i];
300 }
301
302 processed[fineLevel][fineIndex][0] = true;
303 } // loop over all child nodes
304 } // end of loop over all children on next level
305 }
306 } // end of loop over all elements of current level
307 } // end of loop over all levels
308#ifdef FE_VERBOSE
309 std::cout << "FE:" << "Grid traversed for transfer operators in " << timer.elapsed() << " seconds." << std::endl;
310#endif
311
312 // setup transfer operator matrices
313 timer.reset();
314 // T.resize(maxLevel);
315 for(int level=0; level<maxLevel; ++level)
316 {
317 Dune::MatrixIndexSet indices(multiLevelIndexSet.size(level+1), multiLevelIndexSet.size(level));
318
319 for(size_t row=0; row<transformationHierarchy[level].size(); ++row)
320 for(const auto& colIt : transformationHierarchy[level][row])
321 indices.add(row,colIt.first);
322
323 indices.exportIdx(*T[level]);
324
325 for(size_t row=0; row<transformationHierarchy[level].size(); ++row)
326 {
327 for(const auto& colIt : transformationHierarchy[level][row])
328 {
329 // if (colIt->second != 0.0)
330 (*T[level])[row][colIt.first] = 0.0;
331 for(size_t i=0; i<Matrix::block_type::rows; ++i)
332 (*T[level])[row][colIt.first][i][i] = colIt.second;
333 }
334 }
335
336 transformationHierarchy[level].clear();
337 }
338
339#ifdef FE_VERBOSE
340 for(int level=0; level<maxLevel; ++level)
341 std::cout << "FE:" << "Transfer " << level << " -> " << level+1 << " is a "<< (*T[level]).N() << " x " << (*T[level]).M() << " matrix." << std::endl;
342 std::cout << "FE:" << "Transfer operator matrices set up in " << timer.elapsed() << " seconds." << std::endl;
343#endif
344 }
345
346
347 private:
348 static const int dim = GridType::dimension;
349 const GridType& grid;
350};
351
352#endif
int id()
const Matrix & getMatrix() const
int maxLevel() const
int size() const
static TupleAccessTraits< typenameAtType< N, Tuple >::Type >::NonConstType get(Tuple &t)
size_type dim() const
static constexpr size_type M()
std::ptrdiff_t index() const
const IndexSet & indexSet() const
const Grid & grid() const
Grid< dim, dimworld, ct, GridFamily >::LeafGridView leafGridView(const Grid< dim, dimworld, ct, GridFamily > &grid)
Grid< dim, dimworld, ct, GridFamily >::LevelGridView levelGridView(const Grid< dim, dimworld, ct, GridFamily > &grid, int level)
IteratorRange<... > vertices(const GV &gv)
void exportIdx(MatrixType &matrix) const
void add(size_type row, size_type col)
constexpr unsigned int codim() const noexcept
constexpr unsigned int subEntity() const noexcept
void reset() noexcept
double elapsed() const noexcept
auto size(GeometryType type) const
const LevelIndexSet & levelIndexSet(int level) const
int size(int level, int codim) const
int maxLevel() const
const LeafIndexSet & leafIndexSet() const
const LocalIdSet & localIdSet() const
LevelGridView levelGridView(int level) const
Assembler for a hierarchy of multigrid transfer operators.
Definition transferoperatorassembler.hh:105
void assembleMatrixHierarchy(std::vector< Matrix * > &T) const
assemble hierarchy of transfer operators for P1 elements
Definition transferoperatorassembler.hh:189
void assembleOperatorPointerHierarchy(std::vector< TransferOperator * > &T) const
Definition transferoperatorassembler.hh:146
void assembleOperatorHierarchy(std::vector< TransferOperator > &T) const
Definition transferoperatorassembler.hh:114
TransferOperatorAssembler(const GridType &grid)
Definition transferoperatorassembler.hh:108
void assembleDerivedOperatorPointerHierarchy(std::vector< TransferOperator * > &T) const
Definition transferoperatorassembler.hh:128
void assembleMatrixHierarchy(std::vector< std::shared_ptr< Matrix > > &M) const
assemble hierarchy of transfer operators for P1 elements
Definition transferoperatorassembler.hh:168
T emplace_back(T... args)
T endl(T... args)
T forward(T... args)