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