KASKADE 7 development version
additiveMultigrid.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) 2015-2020 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
13#ifndef MG_AMULTIGRID_HH
14#define MG_AMULTIGRID_HH
15
16#include <future>
17#include <memory>
18#include <type_traits>
19
20#include <dune/istl/preconditioner.hh>
21
22#include "fem/spaces.hh"
23#include "linalg/conjugation.hh"
24#include "linalg/direct.hh"
27#include "mg/prolongation.hh"
28
29namespace Kaskade
30{
45 template <class Smoother, class Prolongation, class CoarsePreconditioner=Smoother>
46 class AdditiveMultiGrid: public SymmetricPreconditioner<typename Smoother::domain_type,typename Smoother::range_type>
47 {
48 public:
49 using domain_type = typename Smoother::domain_type;
50 using range_type = typename Smoother::range_type;
52
56 AdditiveMultiGrid() = default;
57
63 template <class Entry, class Index, class MakeSmoother, class MakeCoarsePreconditioner>
64 AdditiveMultiGrid(NumaBCRSMatrix<Entry,Index> A, std::vector<Prolongation> Ps, MakeSmoother const& makeSmoother,
65 MakeCoarsePreconditioner const& makeCoarsePreconditioner, bool onlyLowerTriangle=false)
66 : prolongations(std::move(Ps))
67 {
68 for (int l=prolongations.size(); l>0; --l)
69 {
70 smoothers.insert(smoothers.begin(),makeSmoother(A,l));
71 A = conjugation(prolongations[l-1],A,onlyLowerTriangle);
72 }
73 coarsePreconditioner = std::make_unique<CoarsePreconditioner>(makeCoarsePreconditioner(A,0));
74 }
75
77
79
80 virtual void apply(domain_type& x, range_type const& r)
81 {
82 range_type b = r;
83 runMG(x,b,prolongations.size());
84 }
85
86 virtual typename Base::field_type applyDp(domain_type& x, range_type const& r)
87 {
88 apply(x,r);
89 return x*r;
90 }
91
92 virtual bool requiresInitializedInput() const
93 {
94 for (auto const& s: smoothers)
95 if (s.requiresInitializedInput())
96 return true;
97 return false;
98 }
99
100 private:
101 void runMG(domain_type& x, range_type& r, int const level)
102 {
103 if (level == 0)
104 {
105 x = 0;
106 coarsePreconditioner->pre(x,r);
107 coarsePreconditioner->apply(x,r);
108 coarsePreconditioner->post(x);
109 }
110 else
111 {
112 // first the restriction -- the smoother may modify the residual r, but the coarse grid correction won't...
113 auto const& p = prolongations[level-1];
114 range_type cr(p.M());
115 p.mtv(r,cr); // cr = P^T r
116 domain_type cx; // for the coarse grid correction
117
118 // Run the coarse grid correction in parallel. Depending on the prolongation structure and
119 // the machine this code runs on, this appears to have a minor to moderate benefit. We use
120 // std::async instead of the thread pool in order to prevent deadlocks due to recursive
121 // submission of tasks.
122 auto coarseGridCorrectionTicket = std::async(std::launch::async,[&] ()
123 {
124 cx.resize(p.M()); cx = 0;
125 runMG(cx,cr,level-1); // cx ~ (P^T A P)^{-1} cr
126 });
127
128 // Now the smoothing while the coarse grid correction is on the way
129 auto& s = smoothers[level-1]; // Smoother S
130 s.pre(x,r);
131 s.apply(x,r);
132 s.post(x);
133
134 // now wait for the coarse grid correction to be available and add it up
135 coarseGridCorrectionTicket.wait();
136 p.umv(cx,x); // dx = dx + P*cx
137 }
138 }
139
140 std::vector<Prolongation> prolongations;
141 std::vector<Smoother> smoothers;
142 std::unique_ptr<CoarsePreconditioner> coarsePreconditioner;
143 };
144
145 // ---------------------------------------------------------------------------------------------------------
146
158 template <class Entry, class Index, class Prolongation, class MakeSmoother, class MakeCoarsePreconditioner>
159 auto makeAdditiveMultiGrid(NumaBCRSMatrix<Entry,Index> const& A, std::vector<Prolongation> const& prolongations,
160 MakeSmoother const& makeSmoother, MakeCoarsePreconditioner const& makeCoarsePreconditioner,
161 bool onlyLowerTriangle=false)
162 {
163 using Smoother = std::result_of_t<MakeSmoother(NumaBCRSMatrix<Entry,Index>,int)>;
164 using CoarsePreconditioner = std::result_of_t<MakeCoarsePreconditioner(NumaBCRSMatrix<Entry,Index>,int)>;
165 return AdditiveMultiGrid<Smoother,Prolongation,CoarsePreconditioner>(A,prolongations,makeSmoother,makeCoarsePreconditioner,onlyLowerTriangle);
166 }
167
168
179 template <class Entry, class Index, class GridMan>
180 auto makeBPX(NumaBCRSMatrix<Entry,Index> const& A, GridMan const& gridman, bool onlyLowerTriangle=false)
181 {
183 auto smoother = [](auto const& a, int ){ return JacobiPreconditioner(a); };
184 auto makeCoarseSolver = [](auto const& a, int ) { return DirectSolver<typename Traits::NaturalDomain,typename Traits::NaturalRange>(a); };
185 return makeAdditiveMultiGrid(A,prolongationStack(gridman),smoother,makeCoarseSolver,onlyLowerTriangle);
186 }
187
188 // ----------------------------------------------------------------------------------------------
189
190
215 template <class Entry, class Index, class FineSpace, class MakeSmoother, class MakeCoarseSmoother>
218 MakeSmoother const& makeSmoother, MakeCoarseSmoother const& makeCoarseSmoother,
219 int coarseLevel=0, bool onlyLowerTriangle=false)
220 {
222 auto makeCoarsePreconditioner = [&](NumaBCRSMatrix<Entry,Index> const& a, int)
223 {
224 auto makeCoarseSolver = [](auto const& a, int ) { return DirectSolver<typename Traits::NaturalDomain,typename Traits::NaturalRange>(a); };
225 return makeAdditiveMultiGrid(a,prolongationStack(space.gridManager(),coarseLevel),
226 makeCoarseSmoother,makeCoarseSolver,onlyLowerTriangle);
227 };
228 std::vector<NumaBCRSMatrix<Dune::FieldMatrix<double,1,1>>> prolongations(1,prolongation<Index>(p1Space,space));
229 return makeAdditiveMultiGrid(A,prolongations,makeSmoother,makeCoarsePreconditioner,onlyLowerTriangle);
230 }
231
232 // ----------------------------------------------------------------------------------------------
233
253 template <class StorageTag, class Entry, class Index, class FineSpace>
254 auto makePBPX(NumaBCRSMatrix<Entry,Index> A, FineSpace const& space, H1Space<typename FineSpace::Grid> const& p1Space,
255 StorageTag storageTag, int coarseLevel=0, bool onlyLowerTriangle=false)
256 {
257 std::cout << "using w=2\n";
258 auto jacobi = [](auto const& a, int level){ return JacobiPreconditioner<NumaBCRSMatrix<Entry,Index>>(a,0.6); std::cout << "constructing Jacobi w=2 on level " << level << "\n"; };
259 auto patchJacobi = [&space,storageTag](auto const& a, int level){
261 return makeAdditivePMultiGrid(A,space,p1Space,patchJacobi,jacobi,coarseLevel,onlyLowerTriangle);
262 }
263}
264
265#endif
An additive multigrid preconditioner for P1 elements.
typename Smoother::domain_type domain_type
typename Smoother::range_type range_type
virtual void apply(domain_type &x, range_type const &r)
virtual bool requiresInitializedInput() const
Returns true if the target vector x has to be initialized to zero before calling apply or applyDp.
AdditiveMultiGrid(NumaBCRSMatrix< Entry, Index > A, std::vector< Prolongation > Ps, MakeSmoother const &makeSmoother, MakeCoarsePreconditioner const &makeCoarsePreconditioner, bool onlyLowerTriangle=false)
Constructor.
AdditiveMultiGrid()=default
Default constructor.
AdditiveMultiGrid(AdditiveMultiGrid &&other)=default
AdditiveMultiGrid & operator=(AdditiveMultiGrid &&other)=default
virtual Base::field_type applyDp(domain_type &x, range_type const &r)
Computes and returns .
A representation of a finite element function space defined over a domain covered by a grid.
An additive overlapping domain decomposition type preconditioner for higher order finite elements app...
Interface for symmetric preconditioners.
auto makePBPX(NumaBCRSMatrix< Entry, Index > A, FineSpace const &space, H1Space< typename FineSpace::Grid > const &p1Space, StorageTag storageTag, int coarseLevel=0, bool onlyLowerTriangle=false)
Convenience function creating additive multigrid preconditioner of V-cycle type with domain decomposi...
auto makeAdditivePMultiGrid(NumaBCRSMatrix< Entry, Index > A, FineSpace const &space, H1Space< typename FineSpace::Grid > const &p1Space, MakeSmoother const &makeSmoother, MakeCoarseSmoother const &makeCoarseSmoother, int coarseLevel=0, bool onlyLowerTriangle=false)
Convenience function creating additive multigrid preconditioner of V-cycle type for higher order elem...
std::vector< NumaBCRSMatrix< Dune::FieldMatrix< typename Mapper::Scalar, 1, 1 >, SparseIndex > > prolongationStack(FEFunctionSpace< Mapper > const &space)
Computes a stack of prolongation matrices for higher order finite element spaces.
auto makeBPX(NumaBCRSMatrix< Entry, Index > const &A, GridMan const &gridman, bool onlyLowerTriangle=false)
Convenience function creating a BPX preconditioner for P1 elements.
auto makeAdditiveMultiGrid(NumaBCRSMatrix< Entry, Index > const &A, std::vector< Prolongation > const &prolongations, MakeSmoother const &makeSmoother, MakeCoarsePreconditioner const &makeCoarsePreconditioner, bool onlyLowerTriangle=false)
Convenience function creating additive multigrid preconditioners for P1 elements.
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
Convenience typedefs and creation functions for common function spaces.
Defines domain and range types for matrix classes.
Definition: matrixTraits.hh:41