KASKADE 7 development version
multiGridStacks.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2012 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
18#ifndef MULTIGRIDSTACKS_HH
19#define MULTIGRIDSTACKS_HH
20
21#include <memory> // std::unique_ptr
22#include <vector>
23#include <map>
24#include <time.h>
25#include <math.h>
26#include <fstream>
27
28#include <iostream> // std::cout, std::endl
29using std::cout;
30using std::endl;
31
32
33#include "dune/grid/common/grid.hh"
34#include "dune/grid/common/entitypointer.hh"
35#include "dune/grid/common/entity.hh"
36#include "dune/grid/io/file/dgfparser/dgfparser.hh"
37#include "dune/istl/matrix.hh"
38#include "dune/istl/bcrsmatrix.hh"
39#include "dune/common/fmatrix.hh"
40#include "dune/common/iteratorfacades.hh"
41#include "dune/istl/matrixindexset.hh"
42
43#include "dune/istl/preconditioners.hh"
44#include "dune/istl/solvers.hh"
45
46// #include "fem/barycentric.hh"
47#include "fem/fixdune.hh"
48#include "fem/mllgeometry.hh"
49#include "fem/fetransfer.hh"
50#include "linalg/conjugation.hh"
51#include "linalg/triplet.hh"
52
73void bcrsPrint( const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >& bcrsMatrix );
74double energyNorm( const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >& matrix_,
76
77//--------------------------------------------------------------------------------------------------------------------------
78
79
90template < class Grd >
92{
93 typedef typename Grd::LevelGridView::IndexSet::IndexType IndexType;
94 typedef typename std::pair<IndexType,float> FatherIndexValue;
95 typedef typename std::vector<FatherIndexValue> FatherSimplexPairs;
96
97 private:
98 void findParents( const Grd& grd, int levelNr );
99 public:
100 std::vector< std::vector<FatherSimplexPairs> > levelParentsVector;
101 std::vector< std::vector<int> > levelDisappear;
102
103 ParentalNodes( Grd const& grd ): levelParentsVector(grd.maxLevel()), levelDisappear(grd.maxLevel())
104 {
105 for(int levelNr=1; levelNr<=grd.maxLevel(); levelNr++)
106 findParents(grd,levelNr);
107 }
108};
109
110template < class Grd >
111void ParentalNodes<Grd>::findParents( const Grd& grd, int levelNr )
112{
113 // First we iterate through all elements in
114 // the current level. In each element we iterate through each corner node. First we check if we
115 // visited it before (vector "processed"). If not we collect the barycentric coordinates in
116 // the father element and the corresponding level indices of the father corner vertex in the
117 // level above ( using vector<pair<int index,double barycentricCoordinate> > >, each vector
118 // consisting of maximal four pairs ). We also collect the nodes, which disappear from one to
119 // another level, we need them (!) to build up consistent prolongations.
120
121 typedef typename Grd::template Codim<0>::LevelIterator ElementLevelIterator;
122 typedef typename Grd::LevelGridView::IndexSet::IndexType IndexType;
123
124 std::vector<FatherSimplexPairs> levelParents;
125 levelParents.resize( grd.size(levelNr,Grd::dimension) );
126
127 // helpvector to avoid multiple processing of identical vertices
128 std::vector<bool> processed(grd.size(Grd::dimension),false);
129
130 // disappearance monitor: necessary to keep track of disappearing nodes
131 std::vector<bool> disappears( grd.size(levelNr-1,Grd::dimension) , true );
132
133 typename Grd::LevelGridView::IndexSet const& indexSet = grd.levelGridView(levelNr).indexSet() ;
134 typename Grd::LevelGridView::IndexSet const& fatherIndexSet = grd.levelGridView(levelNr-1).indexSet();
135
136 // iterate through all cells on current level
137 ElementLevelIterator itEnd = grd.levelGridView(levelNr).template end<0>() ;
138 for (ElementLevelIterator it = grd.levelGridView(levelNr).template begin<0>() ; it != itEnd; ++it)
139 {
140 // for storing the father level indices of the father's corner points
141 std::vector<IndexType> fatherIndices;
142
143 // VertexPointer to father Corners
144 typename Grd::template Codim<0>::Entity itFather = (*it).father();
145
146 for(int i=0 ; i<=Grd::dimension ; i++ )
147 {
148 fatherIndices.push_back( fatherIndexSet.subIndex(itFather, i, Grd::dimension) );
149 // corners of the father cell won't disappear on coarser level
150 disappears[ indexSet.subIndex( itFather,i,Grd::dimension ) ] = false;
151 }
152
153 // now regard corners of subentity
154 for( int i=0 ; i<=Grd::dimension ; i++ )
155 {
156 IndexType idx_child = indexSet.subIndex(*it, i, Grd::dimension);
157 if (!processed[idx_child])
158 {
159 processed[idx_child] = true;
160
161 std::vector<float> relativeCoord;
162 relativeCoord.push_back(1);
163 for( int component = 0 ; component < Grd::dimension ; component++ )
164 {
165 relativeCoord.push_back( it->geometryInFather().corner(i)[component] );
166 relativeCoord.front() -= relativeCoord.back();
167 }
168
169 for( int component = 0 ; component <= Grd::dimension ; component++ )
170 {
171 FatherIndexValue couple;
172 couple.first = fatherIndices[component];
173 couple.second = relativeCoord[component];
174 levelParents[idx_child].push_back(couple);
175 }
176
177 // TODO: instead use barycentric() from fem/barycentric.hh, something like this:
178 // Dune::FieldVector<typename Grd::ctype,Grd::dimension+1> relativeCoord
179 // = barycentric(it->geometryInFather().corner(i));
180 // ...for() {...
181 // couple.second = relativeCoord[(component+1)%(Grd::dimension+1)];
182 // ... }
183 //
184 // somehow barycentric coordinates are in different order than mine
185
186 }
187 }
188 }
189
190 // store which nodes will not turn up on the coarser level
191 for (int k = 0 ; k < disappears.size(); k++ )
192 if(disappears[k])
193 levelDisappear[levelNr-1].push_back(k);
194
195 // move data to the global store.
196 levelParentsVector[levelNr-1].swap(levelParents);
197}
198
199//--------------------------------------------------------------------------------------------------------------------------
200
226// example usage: ProlongationStack<Grid> prolstack( gridManager.grid() );
227
228// creates Vector prolStack of prolongationmatrices
229template < class Grd >
231{
233
234 public:
235 std::vector<Dune::BCRSMatrix<M> > prolStack;
236 ProlongationStack( const Grd& grd );
237};
238
239
240template < class Grd >
242{
243 int maxiLevel = grd.maxLevel();
244 // creates levelParentsVector
245 ParentalNodes<Grd> parentalNodes( grd );
246
247 std::vector<std::vector<int> > disappear(parentalNodes.levelDisappear);
248
249 int disappearSumBefore = 0;
250 int disappearSumAfter = 0;
251
252 for(int levelNr = 1 ; levelNr <= maxiLevel ; levelNr++)
253 {
254 disappearSumBefore = disappearSumAfter;
255 disappearSumAfter += disappear[levelNr-1].size();
256
257 int prolCols = grd.size( levelNr-1 , Grd::dimension ) + disappearSumBefore ;
258 int prolRows = grd.size( levelNr , Grd::dimension ) + disappearSumAfter ;
259
260 // In order to create a BCRS Prolongation matrix we first compute an upper bound for the
261 // number of nonzeros. The nodes on lower levels just retain their values and are not
262 // interpolated, hence there is exactly one nonzero entry in the row.
263 // Each child node's value is determined by the dim+1 values of its father simplex's corners, such that
264 // each row has at most dim+1 nonzeros. Most refinement schemes lead to even sparser prolongation matrices,
265 // as not all father's corners contribute. We start with the worst case here.
266 int nz = disappearSumAfter + grd.size(levelNr,Grd::dimension)*(Grd::dimension+1);
267 Dune::BCRSMatrix<M> prolMatrix(prolRows,prolCols,nz,Dune::BCRSMatrix<M>::row_wise);
268
269 // Now we create the sparsity pattern. Here we can be more precise and allocate only those entries
270 // which are actually nonzero. Remember that "very close to zero" barycentric coordinates have been
271 // set to exactly zero.
272 typedef Dune::BCRSMatrix<M>::CreateIterator Iter;
273
274 for (Iter row=prolMatrix.createbegin(); row!=prolMatrix.createend(); ++row)
275 {
276 if (row.index() < disappearSumBefore)
277 row.insert( row.index() );
278 else if (row.index() >= disappearSumBefore && row.index() < disappearSumAfter )
279 row.insert( disappearSumBefore + disappear[levelNr-1][ row.index() - disappearSumBefore ] );
280 else
281 for( int k = 0 ; k <= Grd::dimension ; k++ )
282 if (parentalNodes.levelParentsVector[levelNr-1][row.index()-disappearSumAfter][k].second > 0)
283 row.insert( parentalNodes.levelParentsVector[levelNr-1][row.index()-disappearSumAfter][k].first + disappearSumBefore );
284 }
285
286 // now enter the values
287 for(int row = 0 ; row < disappearSumBefore ; row++)
288 prolMatrix[row][row] = 1;
289 for(int indx = 0 ; indx < disappear[levelNr-1].size(); indx++)
290 prolMatrix[ disappearSumBefore + indx ][ disappear[levelNr-1][indx] + disappearSumBefore ] = 1;
291 for(int row = disappearSumAfter ; row < prolRows ; row++)
292 {
293 for( int k = 0 ; k <= Grd::dimension ; k++ )
294 if (parentalNodes.levelParentsVector[levelNr-1][row-disappearSumAfter /*row.index()*/][k].second > 0)
295 {
296 prolMatrix[row][ parentalNodes.levelParentsVector[levelNr-1][row-disappearSumAfter][k].first + disappearSumBefore ]
297 = parentalNodes.levelParentsVector[levelNr-1][row-disappearSumAfter][k].second;
298 }
299 }
300
301 prolStack.push_back( prolMatrix );
302 }
303}
304
305// ------------------------------------------------------------------------------------------------------
306
319// example usage: ProlongationStack<Grid> prolStack( gridManager.grid() ); MlStack<Grid> myStack( prolStack , bcrsMatrix );
320
321// creates vector levelMatrixStack of level stiffness matrices
322template < class Grd >
324{
326 public:
327 // sets the member levelMatrixStack, a vector of level stiffness matrices
328 MlStack( ProlongationStack<Grd> const& ps , Dune::BCRSMatrix<M> const& bcrsA , bool onlyLowerTriangle = false);
329 std::vector<Dune::BCRSMatrix<M> > levelMatrixStack;
330};
331
332
333template < class Grd >
334MlStack<Grd>::MlStack(ProlongationStack<Grd> const& ps , Dune::BCRSMatrix<M> const& bcrsA , bool onlyLowerTriangle)
335{
336 // number of prolongations ( = # gridlevels - 1 )
337 int prols = ps.prolStack.size();
338 // sets the first entry of levelMatrixStack to A (stiffness matrix on leaflevel)
339 levelMatrixStack.push_back(bcrsA);
340
341 for(int i = 0 ; i < prols ; i++)
342 {
343 // format needed for toolbox conjugation.hh --> C=C+P^T*A*P
344 std::unique_ptr<Dune::MatrixIndexSet> C = conjugationPattern<double,M>( ps.prolStack[prols-1-i] , levelMatrixStack[ i ] , onlyLowerTriangle);
345 Dune::BCRSMatrix<M> Cnew;
346 // exportIdx from Dune::MatrixIndexSet
347 C->exportIdx(Cnew);
348 // initialize Cnew
349 Cnew *= 0.0;
350 // now Cnew = Cnew + P^T * A * P , where P and A are level corresponding
351 // prolongation- and stiffness matrices
352 conjugation( Cnew , ps.prolStack[prols-1-i] , levelMatrixStack[ i ] , onlyLowerTriangle );
353 // append new stiffness matrix
354 levelMatrixStack.push_back( Cnew );
355 }
356}
357
358// ------------------------------------------------------------------------------------------------------
359
374template < class Grd , class domain_type >
376{
379 typedef Dune::SeqJac<Dune::BCRSMatrix<M>,CoeffVector,CoeffVector> JacobiSmoother;
380 private:
381 int mNumOfLevels;
382 const ProlongationStack<Grd> &mProlongations;
383 const MlStack<Grd> &mLevelMatrices;
384 double mJacRelaxFactor, mMgIter, mMgSmoothings, mMaxTol, mTimeDirectSolve , mExactSolEnergyNorm ;
385 public:
386 MultigridSolver( const ProlongationStack<Grd>& prolongations,
387 const MlStack<Grd>& levelMatrices,
388 double relax,
389 double mgIter,
390 double mgSmoothings,
391 double maxTol );
392 void mgSolve( domain_type& solution , domain_type& rightHand );
393 private:
394 void mgSolveRecursive( CoeffVector& solution , CoeffVector& rightHand , int Level );
395 void jacobiSmooth( CoeffVector& solution , CoeffVector& rightHand , int Level );
396};
397
398// constructor
399template < class Grd , class domain_type >
401 const MlStack<Grd>& levelMatrices,
402 double relax,
403 double mgIter,
404 double mgSmoothings,
405 double maxTol
406 ): mProlongations( prolongations ),
407 mLevelMatrices( levelMatrices )
408{
409 mNumOfLevels = levelMatrices.levelMatrixStack.size();
410 mJacRelaxFactor = relax;
411 mMgIter = mgIter;
412 mMgSmoothings = mgSmoothings;
413 mMaxTol = maxTol;
414}
415
416//member mgSolve()
417template < class Grd , class domain_type >
418void MultigridSolver<Grd,domain_type>::mgSolve( domain_type& domain_type_solution , domain_type& domain_type_rightHand )
419{
420 int Level = mNumOfLevels - 1;
421 double relDefect;
422
423 // references Dune::BlockVector
424 CoeffVector &solution = boost::fusion::at_c<0>(domain_type_solution.data);
425 CoeffVector &rightHand = boost::fusion::at_c<0>(domain_type_rightHand.data);
426
427 for(int i=0;i<mMgIter;i++)
428 {
429 mgSolveRecursive( solution , rightHand , Level );
430 // calculate relative Defect
431 CoeffVector defect(rightHand);
432 mLevelMatrices.levelMatrixStack.front().mmv( solution , defect );
433 relDefect = defect.two_norm()/rightHand.two_norm();
434 if( relDefect < mMaxTol)
435 {
436 cout << "MG converged: " << i << " iterations. rel.Defect = "<< relDefect<< "\n";
437 break;
438 }
439 else if( i==mMgIter-1 )
440 cout << "MG not converged: " << mMgIter << " iterations. rel. Defect = "<< relDefect<< '\n';
441 }
442}
443
444//member mgSolveRecursive()
445template < class Grd, class domain_type >
446void MultigridSolver<Grd,domain_type>::mgSolveRecursive( CoeffVector& solution , CoeffVector& rightHand , int Level )
447{
448 if(Level==0)
449 {
450 // direct solve on Level 0
451 Dune::MatrixAdapter<Dune::BCRSMatrix<M>, CoeffVector, CoeffVector> matrixAdapter( mLevelMatrices.levelMatrixStack.back() );
452 TrivialPreconditioner<CoeffVector> trivialPrecond;
453 Dune::InverseOperatorResult resultInfo;
454 CoeffVector rhsDummy(rightHand);
455 Dune::CGSolver<CoeffVector> cg( matrixAdapter , trivialPrecond , 1.0e-14 , 1000 , 0 );
456 cg.apply( solution , rhsDummy , resultInfo );
457 mTimeDirectSolve += resultInfo.elapsed;
458
459 }
460 else
461 {
462 // pre-smoothing
463 jacobiSmooth( solution , rightHand , Level );
464 CoeffVector levelRightHand( mProlongations.prolStack[Level-1].M() ), tmpRhs(rightHand);
465 mLevelMatrices.levelMatrixStack[mNumOfLevels-Level-1].mmv( solution , tmpRhs );// mmv(const X &x, Y &y) ... y -= A x
466 // restriction residual:
467 mProlongations.prolStack[Level-1].mtv( tmpRhs , levelRightHand );// mtv(const X &x, Y &y) ... y = A^T x
468 // initialize level-error
469 CoeffVector levelError(levelRightHand);
470 levelError *= 0;
471 mgSolveRecursive( levelError , levelRightHand , Level - 1 );
472 // prolongate correction
473 mProlongations.prolStack[Level-1].umv( levelError , solution );// umv(const X &x, Y &y) ... y += A x
474 // post-smoothing
475 jacobiSmooth( solution , rightHand , Level );
476 }
477}
478
479
480// member jacobiSmooth()
481template < class Grd ,class domain_type>
482void MultigridSolver<Grd,domain_type>::jacobiSmooth( CoeffVector& solution , CoeffVector& rightHand , int Level )
483{
484 JacobiSmoother jacobi( mLevelMatrices.levelMatrixStack[ mNumOfLevels-Level-1 ] , mMgSmoothings , mJacRelaxFactor );
485 CoeffVector rhsDummy(rightHand);
486 jacobi.pre( solution , rhsDummy );
487 jacobi.apply( solution , rhsDummy );
488 jacobi.post( solution );
489}
490
491// ------------------------------------------------------------------------------------------------------
492
493// for output in console
494void bcrsPrint( const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >& bcrsMatrix )
495{
496 for(int i=0;i<bcrsMatrix.N();i++)
497 {
498 for(int k =0;k<bcrsMatrix.M();k++)
499 {
500 if(bcrsMatrix.exists(i,k)) cout << bcrsMatrix[i][k] << " ";
501 else cout << "0 ";
502 }
503 cout << endl;
504 }
505 cout<<endl;
506}
507
508// ------------------------------------------------------------------------------------------------------
509
510
511double energyNorm( const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >& matrix_, const Dune::BlockVector<Dune::FieldVector<double,1> >& vec_ )
512{
514 Avec_=0;
515 matrix_.mv(vec_,Avec_);// mv (const X &x, Y &y) ... y = A x
516 return sqrt(Avec_*vec_);
517}
518
519#endif
MlStack(ProlongationStack< Grd > const &ps, Dune::BCRSMatrix< M > const &bcrsA, bool onlyLowerTriangle=false)
std::vector< Dune::BCRSMatrix< M > > levelMatrixStack
void mgSolve(domain_type &solution, domain_type &rightHand)
MultigridSolver(const ProlongationStack< Grd > &prolongations, const MlStack< Grd > &levelMatrices, double relax, double mgIter, double mgSmoothings, double maxTol)
Finds the parent nodes and their interpolation weight for each node in the grid. usage eg....
std::vector< std::vector< FatherSimplexPairs > > levelParentsVector
std::vector< std::vector< int > > levelDisappear
ParentalNodes(Grd const &grd)
std::vector< Dune::BCRSMatrix< M > > prolStack
ProlongationStack(const Grd &grd)
Tools for transfer of data between grids.
This file contains various utility functions that augment the basic functionality of Dune.
auto conjugation(NumaBCRSMatrix< EntryP, IndexP > const &P, NumaBCRSMatrix< EntryA, IndexA > const &A, bool onlyLowerTriangle=false, bool createDiagonal=false)
Creates the conjugation product .
Definition: conjugation.hh:123
auto const & component(LinearProductSpace< Scalar, Sequence > const &x)
Provides access to the m-th component of a product space.
Definition: linearspace.hh:457
Class for transformations between ancestors and their children.
void bcrsPrint(const Dune::BCRSMatrix< Dune::FieldMatrix< double, 1, 1 > > &bcrsMatrix)
double energyNorm(const Dune::BCRSMatrix< Dune::FieldMatrix< double, 1, 1 > > &matrix_, const Dune::BlockVector< Dune::FieldVector< double, 1 > > &vec_)