KASKADE 7 development version
multiGridSolver.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-2013 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
17#ifndef MULTI_GRID_SOLVER_HH_
18#define MULTI_GRID_SOLVER_HH_
19
20#include <memory> // std::unique_ptr
21#include <vector>
22#include <cmath>
23#include <fstream>
24
25#include <iostream> // std::cout, std::endl
26
27#include "dune/grid/common/grid.hh"
28#include "dune/istl/bcrsmatrix.hh"
29#include "dune/common/fmatrix.hh"
30#include "dune/common/fvector.hh"
31
32#include "fem/fixdune.hh"
33#include "linalg/conjugation.hh"
34#include "linalg/triplet.hh"
36
37namespace Kaskade
38{
39 namespace MultiGridSolver_Detail
40 {
41 // convenient template alias
42 template <class Scalar, int n, class Allocator> using BlockVector = Dune::BlockVector<Dune::FieldVector<Scalar,n>,Allocator>;
43
45 template <class Scalar, int n, bool resetSolution=false>
46 void axpy(Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1> > const& P,
49 Scalar alpha = 1.0)
50 {
51 if(resetSolution) y *= 0.0;
52 assert(P.M()==x.N());
53 assert(P.N()==y.N());
54
55 auto riter = P.begin(), rend = P.end();
56 for(;riter!=rend; ++riter)
57 {
58 auto citer = riter->begin(), cend = riter->end();
59 for(;citer!=cend; ++citer) y[riter.index()] += alpha * (*citer)[0][0] * x[citer.index()];
60 }
61 }
62
64 template <class Scalar, int n, bool resetSolution=false>
65 void atxpy(Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1> > const& P,
68 Scalar alpha = 1.0)
69 {
70 if(resetSolution) y *= 0.0;
71 assert(P.M()==y.N());
72 assert(P.N()==x.N());
73
74 auto riter = P.begin(), rend = P.end();
75 for(;riter!=rend; ++riter)
76 {
77 auto citer = riter->begin(), cend = riter->end();
78 for(;citer!=cend; ++citer) y[citer.index()] += alpha * (*citer)[0][0] * x[riter.index()];
79 }
80 }
81
82 template <class Scalar, int n>
83 void applyProlongation(Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1> > const& P,
86 {
87 axpy<Scalar,n,true>(P,x,y);
88 }
89
90 template <class Scalar, int n>
94 {
95 atxpy<Scalar,n,true>(P,x,y);
96 }
97
98
129 template < class Grid >
131 {
132 typedef typename Grid::LevelGridView::IndexSet::IndexType IndexType;
133 typedef typename std::pair<IndexType,float> FatherIndexValue;
134 typedef typename std::vector<FatherIndexValue> FatherSimplexPairs;
135
136 public:
137 std::vector< std::vector<FatherSimplexPairs> > levelParentsVector;
138 std::vector< std::vector<int> > levelDisappear;
139
140 ParentalNodes( Grid const& grd ): levelParentsVector(grd.maxLevel()), levelDisappear(grd.maxLevel())
141 {
142 for(int levelNr=1; levelNr<=grd.maxLevel(); levelNr++)
143 findParents(grd,levelNr);
144 }
145
146 private:
147 void findParents( const Grid& grd, int levelNr )
148 {
149 // First we iterate through all elements in
150 // the current level. In each element we iterate through each corner node. First we check if we
151 // visited it before (vector "processed"). If not we collect the barycentric coordinates in
152 // the father element and the corresponding level indices of the father corner vertex in the
153 // level above ( using vector<pair<int index,double barycentricCoordinate> > >, each vector
154 // consisting of maximal four pairs ). We also collect the nodes, which disappear from one to
155 // another level, we need them (!) to build up consistent prolongations.
156
157 typedef typename Grid::template Codim<0>::LevelIterator ElementLevelIterator;
158 typedef typename Grid::LevelGridView::IndexSet::IndexType IndexType;
159
160 std::vector<FatherSimplexPairs> levelParents;
161 levelParents.resize( grd.size(levelNr,Grid::dimension) );
162
163 // helpvector to avoid multiple processing of identical vertices
164 std::vector<bool> processed(grd.size(Grid::dimension),false);
165
166 // disappearance monitor: necessary to keep track of disappearing nodes
167 std::vector<bool> disappears( grd.size(levelNr-1,Grid::dimension) , true );
168
169 typename Grid::LevelGridView::IndexSet const& indexSet = grd.levelView(levelNr).indexSet() ;
170 typename Grid::LevelGridView::IndexSet const& fatherIndexSet = grd.levelView(levelNr-1).indexSet();
171
172 // iterate through all cells on current level
173 ElementLevelIterator itEnd = grd.levelGridView(levelNr).template end<0>() ;
174 for (ElementLevelIterator it = grd.levelGridView(levelNr).template begin<0>() ; it != itEnd; ++it)
175 {
176 // for storing the father level indices of the father's corner points
177 std::vector<IndexType> fatherIndices;
178
179 // VertexPointer to father Corners
180 typename Grid::template Codim<0>::Entity itFather = (*it).father();
181
182 for(int i=0 ; i<=Grid::dimension ; i++ )
183 {
184 fatherIndices.push_back( fatherIndexSet.subIndex(*itFather, i, Grid::dimension) );
185 // corners of the father cell won't disappear on coarser level
186 disappears[ indexSet.subIndex( *itFather,i,Grid::dimension ) ] = false;
187 }
188
189 // now regard corners of subentity
190 for( int i=0 ; i<=Grid::dimension ; i++ )
191 {
192 IndexType idx_child = indexSet.subIndex(*it, i, Grid::dimension);
193 if (!processed[idx_child])
194 {
195 processed[idx_child] = true;
196
197 std::vector<float> relativeCoord;
198 relativeCoord.push_back(1);
199 for( int component = 0 ; component < Grid::dimension ; component++ )
200 {
201 relativeCoord.push_back( it->geometryInFather().corner(i)[component] );
202 relativeCoord.front() -= relativeCoord.back();
203 }
204
205 for( int component = 0 ; component <= Grid::dimension ; component++ )
206 {
207 FatherIndexValue couple;
208 couple.first = fatherIndices[component];
209 couple.second = relativeCoord[component];
210 levelParents[idx_child].push_back(couple);
211 }
212
213 // TODO: instead use barycentric() from fem/barycentric.hh, something like this:
214 // Dune::FieldVector<typename Grid::ctype,Grid::dimension+1> relativeCoord
215 // = barycentric(it->geometryInFather().corner(i));
216 // ...for() {...
217 // couple.second = relativeCoord[(component+1)%(Grid::dimension+1)];
218 // ... }
219 //
220 // somehow barycentric coordinates are in different order than mine
221
222 }
223 }
224 }
225
226 // store which nodes will not turn up on the coarser level
227 for (int k = 0 ; k < disappears.size(); k++ )
228 if(disappears[k])
229 levelDisappear[levelNr-1].push_back(k);
230
231 // move data to the global store.
232 levelParentsVector[levelNr-1].swap(levelParents);
233 }
234 };
235
236
237
239 template <class Grid, class Scalar=double>
240 std::vector<Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1> > > computeProlongations( const Grid& grd )
241 {
242 std::vector<Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1>>> stack;
243
244 int maxiLevel = grd.maxLevel();
245 // creates levelParentsVector
246 ParentalNodes<Grid> parentalNodes( grd );
247
248 std::vector<std::vector<int> > disappear(parentalNodes.levelDisappear);
249
250 int disappearSumBefore = 0, 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 , Grid::dimension ) + disappearSumBefore ;
258 int prolRows = grd.size( levelNr , Grid::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,Grid::dimension)*(Grid::dimension+1);
267 Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1>> prolMatrix(prolRows,prolCols,nz,Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1>>::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
273 auto row = prolMatrix.createbegin(), rend = prolMatrix.createend();
274 for (;row!=rend; ++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 <= Grid::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 <= Grid::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 stack.push_back( prolMatrix );
302 }
303
304 return stack;
305 }
306
307 // ------------------------------------------------------------------------------------------------------
308
320 template <class Grid, class Scalar, int nComponents=1, class Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,nComponents,nComponents> > >
322 {
324
325 public:
326 // sets the member levelMatrixStack, a vector of level stiffness matrices
327 MultiLevelStack( Grid const& grid , Matrix const& A , bool onlyLowerTriangle = false)
328 : prolongations(computeProlongations(grid)), levelMatrixStack(prolongations.size()+1)
329 {
330 // number of prolongations ( = # gridlevels - 1 )
331 size_t prolongationStackSize = prolongations.size();
332 // sets the first entry of levelMatrixStack to A (stiffness matrix on leaflevel)
333// levelMatrixStack.push_back(bcrsA);
334 levelMatrixStack.back() = A;
335
336 for(int level = prolongationStackSize; level>0; --level)
337 {
338 // format needed for toolbox conjugation.hh --> C=C+P^T*A*P
339 std::unique_ptr<Dune::MatrixIndexSet> C = conjugationPattern( prolongations[level-1] , levelMatrixStack[level] , onlyLowerTriangle);
340 Matrix Cnew;
341 // exportIdx from Dune::MatrixIndexSet
342 C->exportIdx(Cnew);
343 // initialize Cnew
344 Cnew = 0.0;
345 // now Cnew = Cnew + P^T * A * P , where P and A are level corresponding
346 // prolongation- and stiffness matrices
347 conjugation( Cnew , prolongations[level-1] , levelMatrixStack[level] , onlyLowerTriangle );
348 // append new stiffness matrix
349 levelMatrixStack[level-1] = Cnew;
350 }
351 }
352
354 Dune::BCRSMatrix<MatrixBlock> const& stiffnessMatrix(size_t level) const { return levelMatrixStack[level]; }
355
357 size_t size() const { return levelMatrixStack.size(); }
358
359 Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1> > const& prolongation(size_t level) const { return prolongations[level]; }
360
361 //private:
362 private:
363 std::vector<Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1> > > prolongations;
364 std::vector<Matrix> levelMatrixStack;
365 };
366 }
367 // ------------------------------------------------------------------------------------------------------
368
376 template < class Grid, int nComponents=1>
378 {
379 typedef double Scalar;
382
383 public:
384 //forward declaration
385 struct Parameter;
386
390 MultigridSolver(Dune::BCRSMatrix<MatrixBlock> const& A, Grid const& grid, Parameter params=Parameter())
391 : parameter(params), levelStack(grid,A),
393 mgPre("MULTIGRIDSOLVER: ")
394 {}
395
396 template <class Assembler, int row, int col, class BlockFilter>
398 : MultigridSolver( (transposed)
399 ? *(A.getAssembler().template get<MatrixAsTriplet<Scalar> >(false,row,row+1,col,col+1).transpose().template toBCRS<nComponents>())
400 : *(A.getAssembler().template get<MatrixAsTriplet<Scalar> >(false,row,row+1,col,col+1).template toBCRS<nComponents>()),
401 grid,
402 params)
403// : MultigridSolver(*(A.getAssembler().template getBlockPointer<Dune::BCRSMatrix<MatrixBlock>,row,col>()), grid, params)
404 {}
405
406 void apply(CoeffVector& solution, CoeffVector& rightHand)
407 {
408 int level = levelStack.size() - 1;
409 double relDefect = 1;
410
411 for(int i=0;i<parameter.maxSteps;i++)
412 {
413 mgSolveRecursive( solution , rightHand , level );
414 // calculate relative Defect
415 CoeffVector defect(rightHand);
416 levelStack.stiffnessMatrix(level).mmv(solution,defect);
417 relDefect = defect.two_norm()/rightHand.two_norm();
418 if( relDefect < parameter.maxTol)
419 {
420 if(parameter.verbose) std::cout << mgPre << "converged after " << i << " iterations (relative defect = " << relDefect << ")." << std::endl;
421 return;
422 }
423 }
424 if(parameter.verbose) std::cout << mgPre << "NOT converged after " << parameter.maxSteps << " iterations (relative defect = " << relDefect << ")." << std::endl;
425 }
426
427 void setParameter(Parameter p) { parameter = p; }
428
429 private:
430 void mgSolveRecursive(CoeffVector& solution, CoeffVector& rightHand, int level)
431 {
432 if(level==0)
433 {
434 solver.apply(solution,rightHand);
435 }
436 else
437 {
438 // pre-smoothing
439 applySmoothing( solution , rightHand , level );
440 CoeffVector levelRightHand( levelStack.prolongation(level-1).M() ), tmpRhs(rightHand);
441 levelRightHand = 0.0;
442 levelStack.stiffnessMatrix(level).mmv( solution , tmpRhs );// mmv(const X &x, Y &y) ... y -= A x
443 // restriction residual:
444 MultiGridSolver_Detail::applyTransposedProlongation(levelStack.prolongation(level-1), tmpRhs, levelRightHand);
445 // initialize level-error
446 CoeffVector levelError(levelRightHand);
447 levelError = 0;
448
449 mgSolveRecursive( levelError , levelRightHand , level - 1 );
450 // prolongate correction
451 MultiGridSolver_Detail::axpy(levelStack.prolongation(level-1), levelError, solution);
452 // post-smoothing
453 applySmoothing( solution , rightHand , level );
454 }
455 }
456
457 void applySmoothing( CoeffVector& solution , CoeffVector const& rhs , int level )
458 {
459 JacobiSolver<Scalar,nComponents> jacobi(levelStack.stiffnessMatrix(level), parameter.maxSmoothingSteps, 0.5);
460 jacobi.apply(solution,rhs);
461 }
462
463 Parameter parameter;
464 const MultiGridSolver_Detail::MultiLevelStack<Grid,Scalar,nComponents> levelStack;
465 DirectSolver<CoeffVector,CoeffVector> solver;
466 std::string mgPre;
467
468 public:
470 {
471 explicit Parameter(size_t maxSteps_, size_t maxSmoothingSteps_, double maxTol_, double relaxation_=0.5, bool verbose_=false)
472 : maxSteps(maxSteps_),maxSmoothingSteps(maxSmoothingSteps_), maxTol(maxTol_), relaxation(relaxation_), verbose(verbose_)
473 {}
474
475 explicit Parameter(size_t maxSteps_=100, size_t maxSmoothingSteps_=10, size_t maxCGSteps_=1000, size_t lookahead_=25,
476 double maxTol_=1e-9, double relaxation_=0.5, bool verbose_=false, bool useDirectLevel0Solver_ = true)
477 : maxSteps(maxSteps_),maxSmoothingSteps(maxSmoothingSteps_), maxCGSteps(maxCGSteps_), lookahead(lookahead_),
478 maxTol(maxTol_), relaxation(relaxation_), verbose(verbose_), useDirectLevel0Solver(useDirectLevel0Solver_)
479 {}
480
481 Parameter(Parameter const&) = default;
482 Parameter& operator=(Parameter const&) = default;
483
485 double maxTol, relaxation, cgTol = 1e-9, eps = 1e-15;
487 };
488 };
489
490 template <class Grid, int nComponents=1> using MultiGridSolver = MultigridSolver<Grid,nComponents>;
491
492 template < class Grid, int nComponents=1>
493 class MultiGridPreconditioner : public MultiGridSolver<Grid,nComponents>
494 {
495 typedef double Scalar;
497 public:
499
500 MultiGridPreconditioner(Dune::BCRSMatrix<MatrixBlock> const& A, Grid const& grid, Parameter p=Parameter())
501 : MultiGridSolver<Grid,nComponents>(A,grid,Parameter(p.maxSteps,p.maxSmoothingSteps,0,p.relaxation,p.verbose))
502 {}
503
504 template <class Assembler, int row, int col, class BlockFilter>
506 : MultiGridSolver<Grid,nComponents>(A,grid,Parameter(p.maxSteps,p.maxSmoothingSteps,0,p.relaxation,p.verbose))
507 {}
508 };
509}
510
511#endif
An adaptor presenting a Dune::LinearOperator <domain_type,range_type> interface to a contiguous sub-b...
Operator with matrix-representation and coordinate mappings.
MultiGridPreconditioner(Dune::BCRSMatrix< MatrixBlock > const &A, Grid const &grid, Parameter p=Parameter())
MultiGridPreconditioner(AssembledGalerkinOperator< Assembler, row, row+1, col, col+1, BlockFilter > const &A, Grid const &grid, Parameter p=Parameter())
MultiGridSolver< Grid, nComponents >::Parameter Parameter
size_t size() const
Number of grid levels.
Dune::BCRSMatrix< MatrixBlock > const & stiffnessMatrix(size_t level) const
Read-only access to level-th entry of matrix stack, i.e. to the stiffness matrix corresponding to lev...
MultiLevelStack(Grid const &grid, Matrix const &A, bool onlyLowerTriangle=false)
Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const & prolongation(size_t level) const
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
void setParameter(Parameter p)
MultigridSolver(Dune::BCRSMatrix< MatrixBlock > const &A, Grid const &grid, Parameter params=Parameter())
void apply(CoeffVector &solution, CoeffVector &rightHand)
MultigridSolver(AssembledGalerkinOperator< Assembler, row, row+1, col, col+1, BlockFilter > const &A, Grid const &grid, Parameter params=Parameter(), bool transposed=false)
This file contains various utility functions that augment the basic functionality of Dune.
NumaBCRSMatrix< Dune::FieldMatrix< Scalar, m, m > > stiffnessMatrix(Space const &space, Conductivity const &kappa)
Creates a stiffness matrix for the given FE space.
DirectType
Available direct solvers for linear equation systems.
Definition: enums.hh:35
@ MUMPS
MUMPS sparse solver.
MatrixProperties
Characterizations of sparse matrix properties.
Definition: enums.hh:76
void applyProlongation(Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BlockVector< Dune::FieldVector< Scalar, n > > const &x, Dune::BlockVector< Dune::FieldVector< Scalar, n > > &y)
void atxpy(Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BlockVector< Dune::FieldVector< Scalar, n > > const &x, Dune::BlockVector< Dune::FieldVector< Scalar, n > > &y, Scalar alpha=1.0)
Compute . If resetSolution=true computes .
void applyTransposedProlongation(Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BlockVector< Dune::FieldVector< Scalar, n > > const &x, Dune::BlockVector< Dune::FieldVector< Scalar, n > > &y)
std::vector< Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > > computeProlongations(const Grid &grd)
Compute prolongation matrices between consecutive grid levels.
void axpy(Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BlockVector< Dune::FieldVector< Scalar, n > > const &x, Dune::BlockVector< Dune::FieldVector< Scalar, n > > &y, Scalar alpha=1.0)
Compute . If resetSolution=true computes .
void conjugation(Dune::BCRSMatrix< Entry > &C, Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BCRSMatrix< Entry > const &A, bool onlyLowerTriangle=false)
Computes the triple sparse matrix product .
Definition: conjugation.hh:286
T transpose(T x)
auto & component(LinearProductSpace< Scalar, Sequence > &x)
Definition: linearspace.hh:463
std::unique_ptr< Dune::MatrixIndexSet > conjugationPattern(Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > const &P, Dune::BCRSMatrix< Entry > const &A, bool onlyLowerTriangle=false)
Creates the sparsity pattern of .
Definition: conjugation.hh:43
Parameter(size_t maxSteps_, size_t maxSmoothingSteps_, double maxTol_, double relaxation_=0.5, bool verbose_=false)
Parameter & operator=(Parameter const &)=default
Parameter(size_t maxSteps_=100, size_t maxSmoothingSteps_=10, size_t maxCGSteps_=1000, size_t lookahead_=25, double maxTol_=1e-9, double relaxation_=0.5, bool verbose_=false, bool useDirectLevel0Solver_=true)
Parameter(Parameter const &)=default