FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
fgmres.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/solver/iterative.hpp>
10
11// includes, FEAT
12#include <vector>
13
14namespace FEAT
15{
16 namespace Solver
17 {
75 template<
76 typename Matrix_,
77 typename Filter_>
78 class FGMRES :
79 public PreconditionedIterativeSolver<typename Matrix_::VectorTypeR>
80 {
81 public:
82 typedef Matrix_ MatrixType;
83 typedef Filter_ FilterType;
84 typedef typename MatrixType::VectorTypeR VectorType;
85 typedef typename MatrixType::DataType DataType;
87
89
90 protected:
92 const MatrixType& _system_matrix;
94 const FilterType& _system_filter;
100 std::vector<VectorType> _vec_v, _vec_z;
102 std::vector<DataType> _c, _s, _q;
104 std::vector<std::vector<DataType>> _h;
105
106 public:
125 explicit FGMRES(const MatrixType& matrix, const FilterType& filter, Index krylov_dim,
126 DataType inner_res_scale = DataType(0), std::shared_ptr<PrecondType> precond = nullptr) :
127 BaseClass("FGMRES(" + stringify(krylov_dim) + ")", precond),
128 _system_matrix(matrix),
129 _system_filter(filter),
130 _krylov_dim(krylov_dim)
131 {
132 // we always need to compute defect norms
133 this->_force_def_norm_calc = true;
134
135 // set communicator by system matrix
136 this->_set_comm_by_matrix(matrix);
137 set_inner_res_scale(inner_res_scale);
138 }
139
140 explicit FGMRES(const String& section_name, const PropertyMap* section,
141 const MatrixType& matrix, const FilterType& filter, std::shared_ptr<PrecondType> precond = nullptr) :
142 BaseClass("FGMRES", section_name, section, precond),
143 _system_matrix(matrix),
144 _system_filter(filter),
145 _inner_res_scale(DataType(0))
146 {
147 // we always need to compute defect norms
148 this->_force_def_norm_calc = true;
149
150 // set communicator by system matrix
151 this->_set_comm_by_matrix(matrix);
152
153 // Set _inner_res_scale by parameter or use default value
154 auto inner_res_scale_p = section->query("inner_res_scale");
155 if(inner_res_scale_p.second && (!inner_res_scale_p.first.parse(this->_inner_res_scale) || (this->_inner_res_scale < DataType(0))))
156 throw ParseError(section_name + ".inner_res_scale", inner_res_scale_p.first, "a non-negative float");
157
158 // Check if we have set _krylov_vim
159 auto krylov_dim_p = section->query("krylov_dim");
160 if(!krylov_dim_p.second)
161 throw ParseError("FGMRES config section is missing the mandatory krylov_dim!");
162
163 if(!krylov_dim_p.first.parse(this->_krylov_dim) || (this->_krylov_dim <= Index(0)))
164 throw ParseError(section_name + ".krylov_dim", krylov_dim_p.first, "a positive integer");
165
166 this->set_plot_name("FGMRES("+stringify(_krylov_dim)+")");
167 }
168
172 virtual ~FGMRES()
173 {
174 }
175
177 virtual String name() const override
178 {
179 return "FGMRES";
180 }
181
188 virtual void force_defect_norm_calc(bool DOXY(force)) override
189 {
190 // force is already applied in constructor
191 }
192
193 virtual void init_symbolic() override
194 {
196
197 _c.reserve(_krylov_dim);
198 _s.reserve(_krylov_dim);
199 _q.reserve(_krylov_dim + 1);
200 _h.resize(_krylov_dim);
201
202 for(Index i(0); i < _krylov_dim; ++i)
203 {
204 _h.at(i).resize(i+1);
205 }
206
207 _vec_v.push_back(this->_system_matrix.create_vector_r());
208 for(Index i(0); i < _krylov_dim; ++i)
209 {
210 _vec_v.push_back(this->_vec_v.front().clone(LAFEM::CloneMode::Layout));
211 _vec_z.push_back(this->_vec_v.front().clone(LAFEM::CloneMode::Layout));
212 }
213 }
214
215 virtual void done_symbolic() override
216 {
217 _vec_v.clear();
218 _vec_z.clear();
220 }
221
229 virtual void set_krylov_dim(Index krylov_dim)
230 {
231 XASSERT(krylov_dim > Index(0));
232 _krylov_dim = krylov_dim;
233 }
234
241 virtual void set_inner_res_scale(DataType inner_res_scale)
242 {
243 XASSERT(inner_res_scale >= DataType(0));
244 _inner_res_scale = inner_res_scale;
245 }
246
248 virtual Status apply(VectorType& vec_sol, const VectorType& vec_rhs) override
249 {
250 // save input rhs vector as initial defect
251 this->_vec_v.at(0).copy(vec_rhs);
252
253 // clear solution vector
254 vec_sol.format();
255
256 // apply
257 this->_status = _apply_intern(vec_sol, vec_rhs);
258 this->plot_summary();
259 return this->_status;
260 }
261
263 virtual Status correct(VectorType& vec_sol, const VectorType& vec_rhs) override
264 {
265 // compute initial defect
266 this->_system_matrix.apply(this->_vec_v.at(0), vec_sol, vec_rhs, -DataType(1));
267 this->_system_filter.filter_def(this->_vec_v.at(0));
268
269 // apply
270 this->_status = _apply_intern(vec_sol, vec_rhs);
271 this->plot_summary();
272 return this->_status;
273 }
274
275 protected:
276 virtual Status _apply_intern(VectorType& vec_sol, const VectorType& vec_rhs)
277 {
278 IterationStats pre_iter(*this);
279 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
280 const MatrixType& matrix(this->_system_matrix);
281 const FilterType& filter(this->_system_filter);
282
283 // compute initial defect
284 Status status = this->_set_initial_defect(this->_vec_v.at(0), vec_sol);
285
286 pre_iter.destroy();
287
288 // outer GMRES loop
289 while(status == Status::progress)
290 {
291 IterationStats stat(*this);
292
293 _q.clear();
294 _s.clear();
295 _c.clear();
296 _q.push_back(this->_def_cur);
297
298 // normalize v[0]
299 this->_vec_v.at(0).scale(this->_vec_v.at(0), DataType(1) / _q.back());
300
301 // inner GMRES loop
302 Index i(0);
303 while(i < this->_krylov_dim)
304 {
305 // apply preconditioner
306 if(!this->_apply_precond(this->_vec_z.at(i), this->_vec_v.at(i), filter))
307 {
308 stat.destroy();
309 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
310 return Status::aborted;
311 }
312 //filter.filter_cor(this->_vec_z.at(i));
313
314 // v[i+1] := A*z[i]
315 matrix.apply(this->_vec_v.at(i+1), this->_vec_z.at(i));
316 filter.filter_def(this->_vec_v.at(i+1));
317
318 // Gram-Schmidt process
319 for(Index k(0); k <= i; ++k)
320 {
321 this->_h.at(i).at(k) = this->_vec_v.at(i+1).dot(this->_vec_v.at(k));
322 this->_vec_v.at(i+1).axpy(this->_vec_v.at(k), -this->_h.at(i).at(k));
323 }
324
325 // normalize v[i+1]
326 DataType alpha = this->_vec_v.at(i+1).norm2();
327 this->_vec_v.at(i+1).scale(this->_vec_v.at(i+1), DataType(1) / alpha);
328
329 // apply Givens rotations
330 for(Index k(0); k < i; ++k)
331 {
332 DataType t(this->_h.at(i).at(k));
333 this->_h.at(i).at(k ) = this->_c.at(k) * t + this->_s.at(k) * this->_h.at(i).at(k+1);
334 this->_h.at(i).at(k+1) = this->_s.at(k) * t - this->_c.at(k) * this->_h.at(i).at(k+1);
335 }
336
337 // compute beta
338 DataType beta = Math::sqrt(Math::sqr(this->_h.at(i).at(i)) + Math::sqr(alpha));
339
340 // compute next plane rotation
341 _s.push_back(alpha / beta);
342 _c.push_back(this->_h.at(i).at(i) / beta);
343
344 this->_h.at(i).at(i) = beta;
345 this->_q.push_back(this->_s.back() * this->_q.at(i));
346 this->_q.at(i) *= this->_c.back();
347
348 // push our new defect
349 if(++i < this->_krylov_dim)
350 {
351 // get the absolute defect
352 DataType def_cur = Math::abs(this->_q.back());
353
354 // did we diverge?
355 if((def_cur > this->_div_abs) || (def_cur > (this->_div_rel * this->_def_init)))
356 break;
357
358 // increase iteration count
359 ++this->_num_iter;
360
361 // minimum number of iterations performed?
362 if(!(this->_num_iter < this->_min_iter))
363 {
364 // did we converge?
365 if((def_cur <= _inner_res_scale * this->_tol_abs) &&
366 ((def_cur <= _inner_res_scale * (this->_tol_rel * this->_def_init)) || (def_cur <= _inner_res_scale * this->_tol_abs_low) ))
367 break;
368
369 // maximum number of iterations performed?
370 if(this->_num_iter >= this->_max_iter)
371 break;
372 }
373
374 // set our pseudo defect
375 // compute new defect
376 this->_def_cur = def_cur;
377
378 // plot?
379 if(this->_plot_iter())
380 {
381 String msg = this->_plot_name
382 + "* " + stringify(this->_num_iter).pad_front(this->_iter_digits)
383 + " : " + stringify_fp_sci(this->_def_cur);
384 this->_print_line(msg);
385 }
386 }
387 }
388
389 Index n = Math::min(i, this->_krylov_dim);
390
391 // solve H*q = q
392 for(Index k(n); k > 0;)
393 {
394 --k;
395 this->_q.at(k) /= this->_h.at(k).at(k);
396 for(Index j(k); j > 0;)
397 {
398 --j;
399 this->_q.at(j) -= this->_h.at(k).at(j) * this->_q.at(k);
400 }
401 }
402
403 // update solution
404 for(Index k(0); k < n; ++k)
405 vec_sol.axpy(this->_vec_z.at(k), this->_q.at(k));
406
407 // compute "real" residual
408 matrix.apply(this->_vec_v.at(0), vec_sol, vec_rhs, -DataType(1));
409 filter.filter_def(this->_vec_v.at(0));
410
411 // set the current defect
412 status = this->_set_new_defect(this->_vec_v.at(0), vec_sol);
413 }
414
415 // finished
416 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
417 return status;
418 }
419 }; // class FGMRES<...>
420
443 template<typename Matrix_, typename Filter_>
444 inline std::shared_ptr<FGMRES<Matrix_, Filter_>> new_fgmres(
445 const Matrix_& matrix, const Filter_& filter, Index krylov_dim,
446 typename Matrix_::DataType inner_res_scale = typename Matrix_::DataType(0),
447 std::shared_ptr<SolverBase<typename Matrix_::VectorTypeL>> precond = nullptr)
448 {
449 return std::make_shared<FGMRES<Matrix_, Filter_>>(matrix, filter, krylov_dim, inner_res_scale, precond);
450 }
451
473 template<typename Matrix_, typename Filter_>
474 inline std::shared_ptr<FGMRES<Matrix_, Filter_>> new_fgmres(
475 const String& section_name, const PropertyMap* section,
476 const Matrix_& matrix, const Filter_& filter,
477 std::shared_ptr<SolverBase<typename Matrix_::VectorTypeL>> precond = nullptr)
478 {
479 return std::make_shared<FGMRES<Matrix_, Filter_>>(section_name, section, matrix, filter, precond);
480 }
481 } // namespace Solver
482} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
Class for parser related errors.
Definition: exception.hpp:132
A class organizing a tree of key-value pairs.
std::pair< String, bool > query(String key_path) const
Queries a value by its key path.
FGMRES(k) solver implementation.
Definition: fgmres.hpp:80
virtual void done_symbolic() override
Symbolic finalization method.
Definition: fgmres.hpp:215
virtual void set_inner_res_scale(DataType inner_res_scale)
Sets the inner residual scale.
Definition: fgmres.hpp:241
DataType _inner_res_scale
inner pseudo-residual scaling factor, see the documentation of this class for details
Definition: fgmres.hpp:98
virtual void init_symbolic() override
Symbolic initialization method.
Definition: fgmres.hpp:193
std::vector< DataType > _c
Givens rotation coefficients.
Definition: fgmres.hpp:102
const MatrixType & _system_matrix
the matrix for the solver
Definition: fgmres.hpp:92
virtual void set_krylov_dim(Index krylov_dim)
Sets the inner Krylov space dimension.
Definition: fgmres.hpp:229
virtual void force_defect_norm_calc(bool force) override
Forces the calculation of defect norms in every iteration (overridden)
Definition: fgmres.hpp:188
const FilterType & _system_filter
the filter for the solver
Definition: fgmres.hpp:94
virtual ~FGMRES()
Empty virtual destructor.
Definition: fgmres.hpp:172
std::vector< std::vector< DataType > > _h
Hessenberg matrix.
Definition: fgmres.hpp:104
Index _krylov_dim
krylov dimension
Definition: fgmres.hpp:96
virtual Status apply(VectorType &vec_sol, const VectorType &vec_rhs) override
Solver application method.
Definition: fgmres.hpp:248
virtual String name() const override
Returns a descriptive string.
Definition: fgmres.hpp:177
FGMRES(const MatrixType &matrix, const FilterType &filter, Index krylov_dim, DataType inner_res_scale=DataType(0), std::shared_ptr< PrecondType > precond=nullptr)
Constructor.
Definition: fgmres.hpp:125
virtual Status correct(VectorType &vec_sol, const VectorType &vec_rhs) override
Definition: fgmres.hpp:263
std::vector< VectorType > _vec_v
krylov basis vectors
Definition: fgmres.hpp:100
Helper class for iteration statistics collection.
Definition: base.hpp:392
bool _force_def_norm_calc
whether skipping of defect computation is allowed or not
Definition: iterative.hpp:249
void set_plot_name(const String &plot_name)
Sets the plot name of the solver.
Definition: iterative.hpp:517
DataType _def_init
initial defect
Definition: iterative.hpp:237
Index _min_iter
minimum number of iterations
Definition: iterative.hpp:227
Index _iter_digits
iteration count digits for plotting
Definition: iterative.hpp:243
Index get_num_iter() const
Returns number of performed iterations.
Definition: iterative.hpp:462
Status _status
current status of the solver
Definition: iterative.hpp:213
void _set_comm_by_matrix(const Matrix_ &matrix)
Sets the communicator for the solver from a matrix.
Definition: iterative.hpp:680
void _print_line(const String &line) const
Prints a line.
Definition: iterative.hpp:752
String _plot_name
name of the solver in plots
Definition: iterative.hpp:211
DataType _div_rel
relative divergence parameter
Definition: iterative.hpp:221
DataType _div_abs
absolute divergence parameter
Definition: iterative.hpp:223
virtual Status _set_new_defect(const VectorType &vec_def, const VectorType &vec_sol)
Internal function: sets the new (next) defect vector.
Definition: iterative.hpp:924
Index _num_iter
number of performed iterations
Definition: iterative.hpp:231
bool _plot_iter(Status st=Status::progress) const
Plot the current iteration?
Definition: iterative.hpp:720
DataType _tol_rel
relative tolerance parameter
Definition: iterative.hpp:215
DataType _def_cur
current defect
Definition: iterative.hpp:239
virtual void plot_summary() const
Plot a summary of the last solver run.
Definition: iterative.hpp:627
Index _max_iter
maximum number of iterations
Definition: iterative.hpp:229
DataType _tol_abs_low
absolute low tolerance parameter
Definition: iterative.hpp:219
virtual Status _set_initial_defect(const VectorType &vec_def, const VectorType &vec_sol)
Internal function: sets the initial defect vector.
Definition: iterative.hpp:802
DataType _tol_abs
absolute tolerance parameter
Definition: iterative.hpp:217
Abstract base-class for preconditioned iterative solvers.
Definition: iterative.hpp:1027
virtual void init_symbolic() override
Symbolic initialization method.
Definition: iterative.hpp:1086
bool _apply_precond(VectorType &vec_cor, const VectorType &vec_def, const Filter_ &filter)
Applies the preconditioner onto a defect vector.
Definition: iterative.hpp:1140
virtual void done_symbolic() override
Symbolic finalization method.
Definition: iterative.hpp:1110
Polymorphic solver interface.
Definition: base.hpp:183
String class implementation.
Definition: string.hpp:46
String pad_front(size_type len, char c=' ') const
Pads the front of the string up to a desired length.
Definition: string.hpp:392
T_ sqrt(T_ x)
Returns the square-root of a value.
Definition: math.hpp:300
T_ abs(T_ x)
Returns the absolute value.
Definition: math.hpp:275
T_ sqr(T_ x)
Returns the square of a value.
Definition: math.hpp:95
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
std::shared_ptr< FGMRES< Matrix_, Filter_ > > new_fgmres(const Matrix_ &matrix, const Filter_ &filter, Index krylov_dim, typename Matrix_::DataType inner_res_scale=typename Matrix_::DataType(0), std::shared_ptr< SolverBase< typename Matrix_::VectorTypeL > > precond=nullptr)
Creates a new FGMRES solver object.
Definition: fgmres.hpp:444
Status
Solver status return codes enumeration.
Definition: base.hpp:47
@ progress
continue iteration (internal use only)
@ aborted
premature abort (solver aborted due to internal errors or preconditioner failure)
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
String stringify_fp_sci(DataType_ value, int precision=0, int width=0, bool sign=false)
Prints a floating point value to a string in scientific notation.
Definition: string.hpp:1088
std::uint64_t Index
Index data type.