KASKADE 7 development version
fgmres.hh
Go to the documentation of this file.
1#ifndef FGMRES_HH
2#define FGMRES_HH
3
4#include<cmath>
5#include<complex>
6#include<iostream>
7#include<iomanip>
8#include<string>
9
10#include "dune/istl/solvers.hh"
11#include "dune/istl/istlexception.hh"
12#include "dune/istl/operators.hh"
13#include "dune/istl/preconditioners.hh"
14#include "dune/istl/scalarproducts.hh"
15#include <dune/common/timer.hh>
16#include <dune/common/static_assert.hh>
17
18
30 template<class X>
31 class RestartedFGMResSolver : public Dune::InverseOperator<X,X>
32 {
33 public:
34 typedef X Y;
35 typedef X F;
36
38 typedef X domain_type;
40 typedef Y range_type;
42 typedef typename X::field_type field_type;
44 typedef F basis_type;
45
53 template<class L, class P>
54 RestartedFGMResSolver (L& op, P& prec, double reduction, int restart, int maxit, int verbose, bool recalc_defect = false) :
55 _A_(op), _M(prec),
56 ssp(), _sp(ssp), _restart(restart),
57 _reduction(reduction), _maxit(maxit), _verbose(verbose),
58 _recalc_defect(recalc_defect)
59 {
60 dune_static_assert(static_cast<int>(P::category) == static_cast<int>(SolverCategory::sequential),
61 "P must be sequential!");
62 dune_static_assert(static_cast<int>(L::category) == static_cast<int>(SolverCategory::sequential),
63 "L must be sequential!");
64 }
65
73 template<class L, class S, class P>
74 RestartedFGMResSolver (L& op, S& sp, P& prec, double reduction, int restart, int maxit, int verbose, bool recalc_defect = false) :
75 _A_(op), _M(prec),
76 _sp(sp), _restart(restart),
77 _reduction(reduction), _maxit(maxit), _verbose(verbose),
78 _recalc_defect(recalc_defect)
79 {
80 dune_static_assert(static_cast<int>(P::category) == static_cast<int>(SolverCategory::sequential),
81 "P must be sequential!");
82 dune_static_assert(static_cast<int>(L::category) == static_cast<int>(SolverCategory::sequential),
83 "L must be sequential!");
84 }
85
87 virtual void apply (X& x, X& b, Dune::InverseOperatorResult& res)
88 {
89 apply(x,b,_reduction,res);
90 };
91
97 virtual void apply (X& x, Y& b, double reduction, Dune::InverseOperatorResult& res)
98 {
99 int m = _restart;
100 field_type norm;
101 field_type norm_old = 0.0;
102 field_type norm_0;
103 field_type beta;
104 int i, j = 1, k;
105 std::vector<field_type> s(m+1), cs(m), sn(m);
106 std::vector<field_type> sw(m+1), csw(m), snw(m);
107 // helper vector
108 X tmp(b.size());
109 std::vector< std::vector<field_type> > H(m+1,s), Hw(m+1,s);
110 std::vector<F> v(1,b);
111 std::vector<X> w(1,b);
112
113 // start timer
114 Timer watch; // start a timer
115
116 // clear solver statistics
117 res.clear();
118
119 _M.pre(x,b);
120
121 norm_0 = _sp.norm(b);
122 if(x.size()!=0)
123 _A_.applyscaleadd(-1,x,b); // overwrite b with defect
124 else
125 {
126 x.resize(b.size());
127 x=0.0;
128 }
129 v[0]=b;
130 beta = _sp.norm(v[0]);
131
132
133 // avoid division by zero
134 if (norm_0 == 0.0)
135 norm_0 = 1.0;
136
137 norm = norm_old = _sp.norm(v[0]);
138
139 // print header
140 if (_verbose > 0)
141 {
142 std::cout << "=== RestartedGMResSolver" << std::endl;
143 if (_verbose > 1)
144 {
145 this->printHeader(std::cout);
146 this->printOutput(std::cout,0,norm);
147 }
148 }
149
150 // check convergence
151 if (norm <= reduction * norm_0) {
152 _M.post(x); // postprocess preconditioner
153 res.converged = true;
154 if (_verbose > 0) // final print
155 print_result(res);
156 return;
157 }
158
159 while (j <= _maxit && res.converged != true) {
160 v[0] *= (1.0 / beta);
161 for (i=1; i<=m; i++) s[i] = 0.0;
162 s[0] = beta;
163
164 for (i = 0; i < m && j <= _maxit && res.converged != true; i++, j++) {
165 if(w.size()<i+1) w.push_back(b);
166 w[i] = 0.0;
167 if(v.size()<i+2) v.push_back(b);
168 v[i+1] = 0.0;
169 _M.apply(w[i], v[i]);
170 _A_.apply(w[i], /* => */ v[i+1]);
171 for (k = 0; k <= i; k++) {
172 H[k][i] = _sp.dot(v[i+1], v[k]);
173 // w -= H[k][i] * v[k];
174 v[i+1].axpy(-H[k][i], v[k]);
175 }
176 H[i+1][i] = _sp.norm(v[i+1]);
177 if (H[i+1][i] == 0.0)
178 DUNE_THROW(ISTLError,"breakdown in GMRes - |w| "
179 << w[i] << " == 0.0 after " << j << " iterations");
180 // v[i+1] = w * (1.0 / H[i+1][i]);
181 v[i+1] *= (1.0 / H[i+1][i]);
182
183 for (k = 0; k < i; k++)
184 applyPlaneRotation(H[k][i], H[k+1][i], cs[k], sn[k]);
185
186 generatePlaneRotation(H[i][i], H[i+1][i], cs[i], sn[i]);
187 applyPlaneRotation(H[i][i], H[i+1][i], cs[i], sn[i]);
188 applyPlaneRotation(s[i], s[i+1], cs[i], sn[i]);
189
190 norm = std::abs(s[i+1]);
191
192 if (_verbose > 1) // print
193 {
194 this->printOutput(std::cout,j,norm,norm_old);
195 }
196
197 norm_old = norm;
198
199 if (norm < reduction * norm_0) {
200 res.converged = true;
201 }
202 }
203
204 tmp = 0.0;
205 // calc update vector
206 update(tmp, i - 1, H, s, w);
207 if (_verbose > 1)
208 {
209 std::cout << "|dx|:" << _sp.norm(tmp) << " " << std::flush;
210 };
211
212 // r = (b - A * x);
213 // update defect
214 _A_.applyscaleadd(-1,tmp, /* => */ b);
215
216 x += tmp;
217
218 beta = _sp.norm(b);
219 norm = beta;
220 v[0]=b;
221
222 res.converged = false;
223
224 norm_old = norm;
225
226 if (norm < reduction * norm_0) {
227 // fill statistics
228 res.converged = true;
229 }
230
231 if (res.converged != true && _verbose > 0)
232 std::cout << "=== GMRes::restart\n";
233 }
234
235 _M.post(x); // postprocess preconditioner
236
237 res.iterations = j;
238 res.reduction = norm / norm_0;
239 res.conv_rate = pow(res.reduction,1.0/j);
240 res.elapsed = watch.elapsed();
241
242 if (_verbose>0)
243 print_result(res);
244 }
245 private:
246
247 void
248 print_result (const Dune::InverseOperatorResult & res) const
249 {
250 int j = res.iterations>0?res.iterations:1;
251 std::cout << "=== rate=" << res.conv_rate
252 << ", T=" << res.elapsed
253 << ", TIT=" << res.elapsed/j
254 << ", IT=" << res.iterations
255 << std::endl;
256 }
257
258 static void
259 update(X &x, int k,
260 std::vector< std::vector<field_type> > & h,
261 std::vector<field_type> & s, std::vector<F> v)
262 {
263 std::vector<field_type> y(s);
264
265 // Backsolve:
266 for (int i = k; i >= 0; i--) {
267 y[i] /= h[i][i];
268 for (int j = i - 1; j >= 0; j--)
269 y[j] -= h[j][i] * y[i];
270 }
271
272 for (int j = 0; j <= k; j++)
273 // x += v[j] * y[j];
274 x.axpy(y[j],v[j]);
275 }
276
277 void
278 generatePlaneRotation(field_type &dx, field_type &dy, field_type &cs, field_type &sn)
279 {
280 if (dy == 0.0) {
281 cs = 1.0;
282 sn = 0.0;
283 } else if (std::abs(dy) > std::abs(dx)) {
284 field_type temp = dx / dy;
285 sn = 1.0 / std::sqrt( 1.0 + temp*temp );
286 cs = temp * sn;
287 } else {
288 field_type temp = dy / dx;
289 cs = 1.0 / std::sqrt( 1.0 + temp*temp );
290 sn = temp * cs;
291 }
292 }
293
294
295 void
296 applyPlaneRotation(field_type &dx, field_type &dy, field_type &cs, field_type &sn)
297 {
298 field_type temp = cs * dx + sn * dy;
299 dy = -sn * dx + cs * dy;
300 dx = temp;
301 }
302
303 Dune::LinearOperator<X,X>& _A_;
304 Dune::Preconditioner<X,X>& _M;
305 Dune::SeqScalarProduct<X> ssp;
306 Dune::ScalarProduct<X>& _sp;
307 int _restart;
308 double _reduction;
309 int _maxit;
310 int _verbose;
311 bool _recalc_defect;
312 };
313
316#endif
implements the Generalized Minimal Residual (GMRes) method
Definition: fgmres.hh:32
virtual void apply(X &x, X &b, Dune::InverseOperatorResult &res)
Definition: fgmres.hh:87
X::field_type field_type
The field type of the operator to be inverted.
Definition: fgmres.hh:42
Y range_type
The range type of the operator to be inverted.
Definition: fgmres.hh:40
F basis_type
The field type of the basis vectors.
Definition: fgmres.hh:44
virtual void apply(X &x, Y &b, double reduction, Dune::InverseOperatorResult &res)
Apply inverse operator.
Definition: fgmres.hh:97
X domain_type
The domain type of the operator to be inverted.
Definition: fgmres.hh:38
RestartedFGMResSolver(L &op, S &sp, P &prec, double reduction, int restart, int maxit, int verbose, bool recalc_defect=false)
Set up solver.
Definition: fgmres.hh:74
RestartedFGMResSolver(L &op, P &prec, double reduction, int restart, int maxit, int verbose, bool recalc_defect=false)
Set up solver.
Definition: fgmres.hh:54