KASKADE 7 development version
multiplicativeMultigrid.hh
Go to the documentation of this file.
1
2/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3/* */
4/* This file is part of the library KASKADE 7 */
5/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
6/* */
7/* Copyright (C) 2015-2020 Zuse Institute Berlin */
8/* */
9/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
10/* see $KASKADE/academic.txt */
11/* */
12/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14#ifndef MG_MULTIPLICATIVEMULTIGRID_HH
15#define MG_MULTIPLICATIVEMULTIGRID_HH
16
17#include <type_traits>
18
19#include <boost/timer/timer.hpp>
20
21#include <dune/istl/preconditioner.hh>
22
23#include "fem/spaces.hh"
24#include "linalg/conjugation.hh"
25#include "linalg/direct.hh"
29#include "mg/prolongation.hh"
30#include "utilities/memory.hh"
31#include "utilities/timing.hh"
32
33namespace Kaskade
34{
35
36
37 // ----------------------------------------------------------------------------------------------------------------------
38
72 template <class Entry, class Index, class Smoother, class Prolongation>
73 class MultiplicativeMultiGrid: public SymmetricPreconditioner<typename Smoother::domain_type,typename Smoother::range_type>
74 {
75 public:
76 using field_type = typename Smoother::field_type;
77 using domain_type = typename Smoother::domain_type;
78 using range_type = typename Smoother::range_type;
79 using CoarsePreconditioner = Dune::Preconditioner<domain_type,range_type>; // symmetric would be better? but elaborate implementation for direct solvers
80
85
95 template <class MakeSmoother>
96 MultiplicativeMultiGrid(MultiGridStack<Prolongation,Entry,Index>&& mgStack_, MakeSmoother const& makeSmoother,
97 std::unique_ptr<CoarsePreconditioner>&& coarsePreconditioner_, int nPre_=3, int nPost_=3)
98 : mgStack(std::move(mgStack_)), nPre(nPre_), nPost(nPost_), coarsePreconditioner(std::move(coarsePreconditioner_)),
99 linesearch(false), smootherStepSize(1.0)
100 {
101 // Create the smoothers for all levels.
102 Timings& timer = Timings::instance();
103 timer.start("smoother construction");
104 for (int l=1; l<mgStack.levels(); ++l)
105 smoothers.push_back(makeSmoother(mgStack.a(l)));
106 timer.stop("smoother construction");
107 }
108
110
112
113
119 virtual void apply(domain_type& x, range_type const& r)
120 {
121 assert(x.two_norm()==0);
122 range_type b = r;
123 runMG(x,b,mgStack.levels()-1);
124 }
125
127 {
128 apply(x,r);
129 return x*r;
130 }
131
132 virtual bool requiresInitializedInput() const
133 {
134 return true;
135 }
136
145 void setSmoothings(int nPre_, int nPost_)
146 {
147 nPre = nPre_;
148 nPost = nPost_;
149 assert(nPre>=0 && nPost>=0 && nPre+nPost>0);
150 }
151
157 void setSmootherStepSize(double w)
158 {
159 assert(w>0);
160 smootherStepSize = w;
161 }
162
163 double getSmootherStepSize() const { return smootherStepSize; }
164
177 void setLinesearch(bool ls)
178 {
179 linesearch = ls;
180 }
181
186 {
187 return *coarsePreconditioner;
188 }
189
193 std::pair<int,int> getSmoothings()
194 {
195 return std::make_pair(nPre,nPost);
196 }
197
198 private:
199 // precondition: x==0
200 void runMG(domain_type& x, range_type& r, int level)
201 {
202 Timings& timer = Timings::instance();
203
204 if (level==0)
205 {
206 timer.start("coarse grid solver");
207 coarsePreconditioner->pre(x,r);
208 coarsePreconditioner->apply(x,r);
209 coarsePreconditioner->post(x);
210 timer.stop("coarse grid solver");
211 }
212 else
213 {
214 auto& s = smoothers[level-1]; // Smoother S
215 auto const& a = mgStack.a(level); // Galerkin matrix A
216 double w = smootherStepSize;
217 domain_type dx(x); // temporary vector
218 range_type adx(r);
219
220 // pre-smoothing
221 bool const sRequiresZeroInput = s.requiresInitializedInput();
222 s.pre(x,r);
223 for (int i=0; i<nPre; ++i)
224 {
225 if (sRequiresZeroInput) dx = 0;
226 timer.start("smoother application");
227 s.apply(dx,r); // dx = B^{-1} r
228 timer.stop("smoother application");
229
230 timer.start("matrix-vector");
231 if (linesearch)
232 {
233 double dxadx = a.mv(dx,adx); // adx = A*dx residual update direction
234 w = dx*r / (dxadx); // w = dx*r / dx*A*dx "optimal" step length
235 r.axpy(-w,adx); // r = r - w*adx update residual
236 }
237 else
238 a.usmv(-w,dx,r); // r = r - w*A*dx update residual (without intermediate adx access)
239 timer.stop("matrix-vector");
240
241 x.axpy(w,dx); // x = x + w*dx update iterate
242 }
243 s.post(x);
244
245 // coarse grid correction
246 auto const& p = mgStack.p(level-1);
247 timer.start("restriction");
248 range_type cr; cr.resize(p.M());
249 p.mtv(r,cr); // cr = P^T r
250 timer.stop("restriction");
251 domain_type cx; cx.resize(p.M()); cx = 0;
252 runMG(cx,cr,level-1); // cx ~ (P^T A P)^{-1} cr
253 timer.start("prolongation");
254 p.mv(cx,dx); // dx = P*cx
255 timer.stop("prolongation");
256 x += dx; // x = x+dx
257 a.usmv(-1,dx,r); // r = r-A*dx
258
259
260 // post-smoothing
261 s.pre(x,r);
262 for (int i=0; i<nPost; ++i)
263 {
264 if (sRequiresZeroInput) dx = 0;
265 timer.start("smoother application");
266 s.apply(dx,r); // dx = B^{-1} r
267 timer.stop("smoother application");
268
269 if (i+1<nPost || linesearch) // update residual only if needed lateron
270 {
271 timer.start("matrix-vector");
272 if (linesearch)
273 {
274 double dxadx = a.mv(dx,adx); // adx = A*dx
275 w = dx*r / (dxadx); // w = dx*r / dx*A*dx
276 r.axpy(-w,adx); // r = r - w*adx
277 }
278 else
279 a.usmv(-w,dx,r); // r = r - w*A*dx
280 timer.stop("matrix-vector");
281 }
282 x.axpy(w,dx); // x = x + w*dx
283 }
284 s.post(x);
285
286 // optional line search
287 if (linesearch)
288 {
289 a.mv(x,dx); // dx = Ax
290 double omega = (x*r) / (dx*x); // omega = r^T x / x^T A x
291 x *= 1+omega; // x = x + omega * x
292 }
293 }
294 }
295
296 MultiGridStack<Prolongation,Entry,Index> mgStack;
297 std::vector<Smoother> smoothers;
298 int nPre, nPost;
299 std::unique_ptr<CoarsePreconditioner> coarsePreconditioner;
300 bool linesearch;
301 double smootherStepSize;
302 };
303
304 // ----------------------------------------------------------------------------------------------------------------------
305
319 template <class Entry, class Index, class Prolongation, class MakeSmoother, class CoarsePreconditioner>
321 MakeSmoother const& makeSmoother,
322 std::unique_ptr<CoarsePreconditioner>&& coarsePreconditioner,
323 int nPre=3, int nPost=3)
324 {
325 using Smoother = std::result_of_t<MakeSmoother(NumaBCRSMatrix<Entry,Index>)>;
327 std::move(mgStack),makeSmoother,std::move(coarsePreconditioner),nPre,nPost);
328 }
329
330 // ----------------------------------------------------------------------------------------------------------------------
331 // ----------------------------------------------------------------------------------------------------------------------
332
338 {
339 public:
340 template <typename Matrix>
341 auto operator()(Matrix const& a) const
342 {
343 return JacobiPreconditioner(a);
344 }
345 };
346
352 template <typename Space, typename Scalar=float>
354 {
355 public:
362 MakeAdditiveSchwarzSmoother(Space const& space_, double targetCondition_=-1.0)
363 : space(space_), targetCondition(targetCondition_)
364 {}
365
366 template <typename Entry, typename Index>
368 {
370 Index>(space,a,targetCondition);
371 }
372
373 private:
374 Space const& space;
375 double targetCondition;
376 };
377
382 template <typename Matrix>
384 {
386 }
387
391 template <class Domain, class Range, class SparseIndex>
392 class DirectPreconditionerFloatWrapper : public Dune::Preconditioner<Domain,Range>
393 {
394 public:
395 using FloatDomain = Domain;
396 using FloatRange = Range;
397 static constexpr int domainBlockSize = Domain::block_type::dimension;
398 static constexpr int rangeBlockSize = Range::block_type::dimension;
403
404 DirectPreconditionerFloatWrapper(FloatMatrix const& matA, DirectType directType) : directSolver(DoubleMatrix(matA), directType) {}
405
406 virtual void pre (FloatDomain &, FloatRange &) {}
407
408 virtual void apply (FloatDomain & x, FloatRange const& b)
409 {
410 DoubleDomain xd(x.size());
411 DoubleRange bd(b.size());
412 auto endBd = vectorToSequence(b, &(bd[0][0]));
413 if(endBd != &(bd[0][0]) + bd.dim()) {
414 throw DirectSolverException("Copying float to double block-vector failed. End Iterators differ.",__FILE__,__LINE__);
415 }
416 directSolver.apply(xd, bd);
417 auto endX = vectorToSequence(xd, &(x[0][0]));
418 if(endX != &(x[0][0]) + x.dim()) {
419 throw DirectSolverException("Copying float to double block-vector failed. End Iterators differ.",__FILE__,__LINE__);
420 }
421 }
422
423 virtual void post (FloatDomain &) {}
424
425 private:
427 };
428
435 template <int domainBlockSize, int rangeBlockSize, class Index>
437 {
440 }
441
442 // ----------------------------------------------------------------------------------------------------------------------
443 // ----------------------------------------------------------------------------------------------------------------------
444
459 template <class Entry, class Index, class GridMan>
460 auto makeJacobiMultiGrid(NumaBCRSMatrix<Entry,Index> const& A, GridMan const& gridman,
461 int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
462 {
463 Timings& timer = Timings::instance();
464
465 timer.start("MG stack creation");
466 auto mgStack = makeGeometricMultiGridStack(gridman,duplicate(A),onlyLowerTriangle);
467 timer.stop("MG stack creation");
468
469 timer.start("direct solver creation");
470 auto coarsePreconditioner = makeDirectPreconditioner(std::move(mgStack.coarseGridMatrix()),directType);
471 timer.stop("direct solver creation");
472
473 timer.start("MG creation");
474 auto mg = makeMultiplicativeMultiGrid(std::move(mgStack),MakeJacobiSmoother(),moveUnique(std::move(coarsePreconditioner)),nPre,nPost);
475 timer.stop("MG creation");
476 mg.setSmootherStepSize(0.5);
477
478 return mg;
479 }
480
495 template <class Entry, class Index, class Space, class MakeSmoother>
497 MakeSmoother const& makeSmoother, int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
498 {
499 Timings& timer = Timings::instance();
500 timer.start("create P multigrid stack");
501 auto mgStack = makePMultiGridStack(space,std::move(A),onlyLowerTriangle);
502 timer.stop("create P multigrid stack");
503
504 timer.start("create MG as coarse solver");
505 auto coarsePreconditioner = makeJacobiMultiGrid(std::move(mgStack.coarseGridMatrix()),space.gridManager(),nPre,nPost,onlyLowerTriangle,directType);
506 coarsePreconditioner.setSmootherStepSize(0.6);
507 timer.stop("create MG as coarse solver");
508
509 timer.start("create multigrid");
510 auto mg = makeMultiplicativeMultiGrid(std::move(mgStack),makeSmoother,moveUnique(std::move(coarsePreconditioner)),nPre,nPost);
511 timer.stop("create multigrid");
512
513 return mg;
514 }
515
536 template <class Entry, class Index, class Space, class CoarseSpace>
538 NumaBCRSMatrix<Entry,Index> coarseA, CoarseSpace const& coarseSpace,
539 int nPre=3, int nPost=3, DirectType directType=DirectType::MUMPS)
540 {
541 Timings& timer = Timings::instance();
542 timer.start("create P multigrid stack");
543 auto mgStack = makePMultiGridStack(space,std::move(A),coarseSpace,std::move(coarseA));
544 timer.stop("create P multigrid stack");
545
546 timer.start("create MG as coarse solver");
547 auto coarsePreconditioner = makeJacobiMultiGrid(std::move(mgStack.coarseGridMatrix()),space.gridManager(),nPre,nPost,false,directType);
548 coarsePreconditioner.setSmootherStepSize(0.6);
549 timer.stop("create MG as coarse solver");
550
551 timer.start("create multigrid");
552 auto mg = makeMultiplicativeMultiGrid(std::move(mgStack),MakeAdditiveSchwarzSmoother<Space>(space),
553 moveUnique(std::move(coarsePreconditioner)),nPre,nPost);
554 mg.setSmootherStepSize(Space::Grid::dimension==3 ? 0.4 : 0.5);
555 timer.stop("create multigrid");
556
557 return mg;
558 }
559
580 template <class Entry, class Index, class Space>
582 int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
583 {
584 auto mg = makeMultiplicativePMultiGrid(std::move(A),space,MakeAdditiveSchwarzSmoother<Space>(space),
585 nPre,nPost,onlyLowerTriangle,directType);
586 mg.setSmootherStepSize(Space::Grid::dimension==3 ? 0.4 : 0.5);
587 return mg;
588 }
589
602 template <class Entry, class Index, class FineSpace>
603 auto makeJacobiPMultiGrid(NumaBCRSMatrix<Entry,Index> A, FineSpace const& space,
604 int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
605 {
606 auto mg = makeMultiplicativePMultiGrid(std::move(A),space,MakeJacobiSmoother(),nPre,nPost,onlyLowerTriangle,directType);
607 mg.setSmootherStepSize(0.5);
608 return mg;
609 }
610
611
612
613
614 // ---------------------------------------------------------------------------------------------------------
615
616
617}
618
619#endif
virtual void pre(FloatDomain &, FloatRange &)
DirectPreconditionerFloatWrapper(FloatMatrix const &matA, DirectType directType)
virtual void apply(FloatDomain &x, FloatRange const &b)
typename MatrixTraits< DoubleMatrix >::NaturalRange DoubleRange
typename MatrixTraits< DoubleMatrix >::NaturalDomain DoubleDomain
To be raised if a direct solver fails.
virtual void apply(Domain &x, Range &b, Dune::InverseOperatorResult &res)
Solves the system for the given right hand side b.
Definition: direct.hh:244
Functor for creating overlapping Schwarz smoothers.
MakeAdditiveSchwarzSmoother(Space const &space_, double targetCondition_=-1.0)
Constructor.
auto operator()(NumaBCRSMatrix< Entry, Index > const &a) const
Functor for creating Jacobi smoothers.
auto operator()(Matrix const &a) const
Class for multigrid stacks.
A general multiplicative multigrid preconditioner.
CoarsePreconditioner & getCoarsePreconditioner()
Provides access to the coarse grid preconditioner.
void setLinesearch(bool ls)
Enable or disable the line search option.
typename Smoother::domain_type domain_type
typename Smoother::field_type field_type
MultiplicativeMultiGrid(MultiplicativeMultiGrid &&other)=default
MultiplicativeMultiGrid & operator=(MultiplicativeMultiGrid &&other)=default
void setSmoothings(int nPre_, int nPost_)
Sets the number of pre- and post-smoothing iterations to perform.
virtual field_type applyDp(domain_type &x, range_type const &r)
Computes and returns .
Dune::Preconditioner< domain_type, range_type > CoarsePreconditioner
virtual void apply(domain_type &x, range_type const &r)
Application of preconditioner.
typename Smoother::range_type range_type
MultiplicativeMultiGrid()=default
Default constructor.
void setSmootherStepSize(double w)
Define the smoother step size.
virtual bool requiresInitializedInput() const
Returns true if the target vector x has to be initialized to zero before calling apply or applyDp.
std::pair< int, int > getSmoothings()
Returns a pair of number of pre- and post-smoothing iterations to perform.
MultiplicativeMultiGrid(MultiGridStack< Prolongation, Entry, Index > &&mgStack_, MakeSmoother const &makeSmoother, std::unique_ptr< CoarsePreconditioner > &&coarsePreconditioner_, int nPre_=3, int nPost_=3)
Constructor.
An additive overlapping domain decomposition type preconditioner for higher order finite elements app...
Interface for symmetric preconditioners.
Supports gathering and reporting execution times information for nested program parts.
Definition: timing.hh:64
static Timings & instance()
Returns a reference to a single default instance.
void stop(std::string const &name)
Stops the timing of given section.
struct Times const * start(std::string const &name)
Starts or continues the timing of given section.
DirectType
Available direct solvers for linear equation systems.
Definition: enums.hh:35
@ MUMPS
MUMPS sparse solver.
auto makeBlockJacobiPMultiGrid(NumaBCRSMatrix< Entry, Index > A, Space const &space, NumaBCRSMatrix< Entry, Index > coarseA, CoarseSpace const &coarseSpace, int nPre=3, int nPost=3, DirectType directType=DirectType::MUMPS)
Convenience function creating multiplicative multigrid preconditioner of V-cycle type for higher orde...
auto makeDirectPreconditioner(Matrix &&A, DirectType directType=DirectType::MUMPS)
Creates a direct solver for the given matrix.
auto makeMultiplicativeMultiGrid(MultiGridStack< Prolongation, Entry, Index > &&mgStack, MakeSmoother const &makeSmoother, std::unique_ptr< CoarsePreconditioner > &&coarsePreconditioner, int nPre=3, int nPost=3)
Convenience function creating multiplicative multigrid preconditioner of V-cycle type for P1 elements...
auto makeJacobiMultiGrid(NumaBCRSMatrix< Entry, Index > const &A, GridMan const &gridman, int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
Convenience function creating multiplicative Jacobi multigrid for P1 elements.
auto makeMultiplicativePMultiGrid(NumaBCRSMatrix< Entry, Index > &&A, Space const &space, MakeSmoother const &makeSmoother, int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
Convenience function creating multiplicative multigrid preconditioner of V-cycle type for higher orde...
auto makePMultiGridStack(FineSpace const &space, Matrix &&A, bool onlyLowerTriangle)
convenience routine for creating multigrid stacks based on coarsening by reducing the ansatz order fr...
auto makeBlockJacobiPMultiGrid(NumaBCRSMatrix< Entry, Index > A, Space const &space, int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
Convenience function creating multiplicative multigrid preconditioner of V-cycle type for higher orde...
MultiGridStack< MGProlongation, Entry, Index > makeGeometricMultiGridStack(GridMan const &gridManager, NumaBCRSMatrix< Entry, Index > &&A, size_t minNodes=10000, bool onlyLowerTriangle=false)
convenience routine for creating multigrid stacks based on geometric coarsening for P1 elements
auto makeJacobiPMultiGrid(NumaBCRSMatrix< Entry, Index > A, FineSpace const &space, int nPre=3, int nPost=3, bool onlyLowerTriangle=false, DirectType directType=DirectType::MUMPS)
Convenience function creating multiplicative multigrid preconditioner of V-cycle type with Jacobi smo...
auto moveUnique(A &&a)
Creates a dynamically allocated object from an r-value reference.
Definition: memory.hh:33
A duplicate(A const &a)
Creates a copy of a given object.
Definition: memory.hh:48
OutIter vectorToSequence(double x, OutIter iter)
Definition: crsutil.hh:30
Convenience typedefs and creation functions for common function spaces.
void NaturalDomain
The natural domain type.
Definition: matrixTraits.hh:50
void NaturalRange
The natural range type.
Definition: matrixTraits.hh:58