FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
idrs.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#include <vector>
11#include <kernel/global/vector.hpp>
12#include <kernel/lafem/dense_matrix.hpp>
13#include <kernel/lafem/dense_vector.hpp>
14#include <kernel/util/random.hpp>
15#include <kernel/util/dist.hpp>
16namespace FEAT
17{
18 namespace Solver
19 {
20
38 template<
39 typename Matrix_,
40 typename Filter_>
41 class IDRS :
42 public PreconditionedIterativeSolver<typename Matrix_::VectorTypeR>
43 {
44 public:
45 typedef Matrix_ MatrixType;
46 typedef Filter_ FilterType;
47 typedef typename MatrixType::VectorTypeR VectorType;
48 typedef typename MatrixType::DataType DataType;
49 typedef typename MatrixType::IndexType IndexType;
51
55
56 protected:
58 const MatrixType& _system_matrix;
60 const FilterType& _system_filter;
64 VectorType _vec_q, _vec_r, _vec_v, _vec_t;
66 VectorType _vec_res;
68 std::vector<VectorType> _vec_P, _vec_dR, _vec_dX;
70 DMatrix _dmat_M, _dmat_Minv;
72 DVector _dvec_m, _dvec_dm, _dvec_c;
73 bool _shadow_space_setup, _random;
74
75 public:
91 explicit IDRS(const MatrixType& matrix, const FilterType& filter, Index krylov_dim,
92 std::shared_ptr<PrecondType> precond = nullptr) :
93 BaseClass("IDRS(" + stringify(krylov_dim) + ")", precond),
94 _system_matrix(matrix),
95 _system_filter(filter),
96 _krylov_dim(krylov_dim),
97 _shadow_space_setup(false),
98 _random(true)
99 {
100 // set communicator by system matrix
101 this->_set_comm_by_matrix(matrix);
102 }
103
104 explicit IDRS(const String& section_name, const PropertyMap* section,
105 const MatrixType& matrix, const FilterType& filter, std::shared_ptr<PrecondType> precond = nullptr) :
106 BaseClass("IDRS", section_name, section, precond),
107 _system_matrix(matrix),
108 _system_filter(filter),
109 _shadow_space_setup(false),
110 _random(true)
111 {
112 // set communicator by system matrix
113 this->_set_comm_by_matrix(matrix);
114
115 // Check if we have set _krylov_vim
116 auto krylov_dim_p = section->query("krylov_dim");
117 if(!krylov_dim_p.second)
118 throw ParseError("IDRS config section is missing the mandatory krylov_dim!");
119
120 if(!krylov_dim_p.first.parse(this->_krylov_dim) || (this->_krylov_dim <= Index(0)))
121 throw ParseError(section_name + ".krylov_dim", krylov_dim_p.first, "a positive integer");
122
123 this->set_plot_name("IDRS("+stringify(_krylov_dim)+")");
124 }
125
129 virtual ~IDRS()
130 {
131 }
132
134 virtual String name() const override
135 {
136 return "IDRS";
137 }
138
139 virtual void init_symbolic() override
140 {
142
145 _dvec_dm = DVector(_krylov_dim);
146 _dvec_c = DVector(_krylov_dim);
147
148 _vec_q = this->_system_matrix.create_vector_r();
149 _vec_r = _vec_q.clone(LAFEM::CloneMode::Layout);
151 _vec_t = _vec_q.clone(LAFEM::CloneMode::Layout);
152 _vec_v = _vec_q.clone(LAFEM::CloneMode::Layout);
153 _vec_dX.reserve(_krylov_dim);
154 _vec_dR.reserve(_krylov_dim);
155 _vec_P.reserve(_krylov_dim);
156
157 for(Index i(0); i < _krylov_dim; ++i)
158 {
159 _vec_dX.push_back(this->_vec_q.clone(LAFEM::CloneMode::Layout));
160 _vec_dR.push_back(this->_vec_q.clone(LAFEM::CloneMode::Layout));
161 _vec_P.push_back( this->_vec_q.clone(LAFEM::CloneMode::Layout));
162 }
163 }
164
165 virtual void done_symbolic() override
166 {
167 _vec_q.clear();
168 _vec_r.clear();
169 _vec_res.clear();
170 _vec_t.clear();
171 _vec_v.clear();
172
173 _vec_dX.clear();
174 _vec_dR.clear();
175 _vec_P.clear();
176
178 }
179
187 virtual void set_krylov_dim(Index krylov_dim)
188 {
189 XASSERT(krylov_dim > Index(0));
190 _krylov_dim = krylov_dim;
191 }
192
194 virtual Status apply(VectorType& vec_sol, const VectorType& vec_rhs) override
195 {
196 // save input rhs vector as initial defect
197 this->_vec_res.copy(vec_rhs);
198
199 // clear solution vector
200 vec_sol.format();
201
202 // apply solver
203 this->_status = _apply_intern(vec_sol, vec_rhs);
204
205 // plot summary
206 this->plot_summary();
207
208 // return status
209 return this->_status;
210 }
211
213 virtual Status correct(VectorType& vec_sol, const VectorType& vec_rhs) override
214 {
215 // compute initial defect
216 this->_system_matrix.apply(this->_vec_res, vec_sol, vec_rhs, -DataType(1));
217 this->_system_filter.filter_def(this->_vec_res);
218
219 // apply solver
220 this->_status = _apply_intern(vec_sol, vec_rhs);
221
222 // plot summary
223 this->plot_summary();
224
225 // return status
226 return this->_status;
227 }
228
235 void reset_shadow_space( bool random = true)
236 {
237 _random = random;
238 _shadow_space_setup = false;
239 }
240
241
242
243 protected:
244
245 void _set_shadow_space()
246 {
247 // select set of random vectors
248 Random rng;
249
250 // use world comm rank as seed unless a truly random seed is desired
251 if(!_random)
252 rng = Random(Random::SeedType(Dist::Comm::world().rank()+1));
253
254 for (Index l(0); l<_krylov_dim; ++l)
255 _vec_P.at(l).format(rng, DataType(0), DataType(1));
256
257 //orthonormalize vector set P (modified Gram-Schmidt)
258 for (Index j(0); j<_krylov_dim; ++j)
259 {
260 for (Index i(0); i<j; ++i)
261 {
262 _vec_P.at(j).axpy(_vec_P.at(i), -_vec_P.at(j).dot(_vec_P.at(i)));
263 }
264 _vec_P.at(j).scale(_vec_P.at(j), DataType(1)/_vec_P.at(j).norm2());
265 }
266 _shadow_space_setup = true;
267 }
268
269
270
271
272 virtual Status _apply_intern(VectorType& vec_sol, const VectorType& DOXY(vec_rhs))
273 {
274 IterationStats pre_iter(*this);
275 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
276 const MatrixType& matrix(this->_system_matrix);
277 const FilterType& filter(this->_system_filter);
278
279 // compute initial defect
280 Status status = this->_set_initial_defect(this->_vec_res, vec_sol);
281 _vec_t.copy(_vec_res);
282 if(!this->_apply_precond(this->_vec_r, this->_vec_t, filter))
283 {
284 pre_iter.destroy();
285 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
286 return Status::aborted;
287 }
288 //select random vector set (shadow space)
289 if (!_shadow_space_setup)
290 _set_shadow_space();
291
292 pre_iter.destroy();
293
294 //produce start vectors
295 IterationStats first_iter(*this);
296 DataType om(0);
297 for (Index k(0); k < _krylov_dim; ++k)
298 {
299 matrix.apply(_vec_v, _vec_r);
300 filter.filter_def(_vec_v);
301 //save unpreconditioned residual update
302 _vec_t.copy(_vec_v);
303 if(!this->_apply_precond(this->_vec_v, this->_vec_t, filter))
304 {
305 first_iter.destroy();
306 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
307 return Status::aborted;
308 }
309 om = _vec_v.dot(_vec_r) / _vec_v.dot(_vec_v);
310 _vec_dX.at(k).scale(_vec_r, om);
311 _vec_dR.at(k).scale(_vec_v, -om);
312 vec_sol.axpy(_vec_dX.at(k));
313 _vec_r.axpy(_vec_dR.at(k));
314 _vec_res.axpy(_vec_t, -om);
315
316 // push our new defect
317 status = this->_set_new_defect(_vec_res, vec_sol);
318
319 //check for early convergence
320 if (status != Status::progress)
321 {
322 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
323 return status;
324 }
325 // update k-th column of M
326 for (Index l(0); l < _krylov_dim; ++l)
327 _dmat_M(l,k, _vec_P.at(l).dot(_vec_dR.at(k)) );
328
329 }
330
331 Index oldest(0);
332 //calculate m
333 for (Index l(0); l< _krylov_dim; ++l)
334 _dvec_m(l, _vec_P.at(l).dot(_vec_r) );
335
336 first_iter.destroy();
337 // outer loop
338 while(status == Status::progress)
339 {
340 IterationStats stat(*this);
341
342 //inner loop
343 for (Index k(0); k <= _krylov_dim; ++k)
344 {
345 //solve c=M\m
346 _dmat_Minv = _dmat_M.inverse();
347 _dmat_Minv.apply(_dvec_c, _dvec_m);
348
349 _vec_q.scale(_vec_dR.at(0), -_dvec_c(0) );
350 for (Index l(1); l < _krylov_dim; ++l)
351 _vec_q.axpy(_vec_dR.at(l), -_dvec_c(l));
352
353 _vec_v.copy(_vec_q);
354 _vec_v.axpy(_vec_r);
355
356 if (k == 0)
357 {
358 matrix.apply(_vec_dR.at(oldest), _vec_v);
359 filter.filter_def(_vec_dR.at(oldest));
360 if(!this->_apply_precond(this->_vec_t, this->_vec_dR.at(oldest), filter))
361 {
362 stat.destroy();
363 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
364 return Status::aborted;
365 }
366 om = _vec_v.dot(_vec_t) / _vec_t.dot(_vec_t);
367 _vec_dR.at(oldest).copy(_vec_q);
368 _vec_dR.at(oldest).axpy(_vec_t, -om);
369
370 //dX(oldest)=-dX*c+om*v
371 _vec_dX.at(oldest).scale(_vec_dX.at(oldest), -_dvec_c(oldest));
372 for (Index l(0); l < oldest; ++l)
373 _vec_dX.at(oldest).axpy(_vec_dX.at(l), -_dvec_c(l));
374 for (Index l(oldest+1); l < _krylov_dim; ++l)
375 _vec_dX.at(oldest).axpy(_vec_dX.at(l), -_dvec_c(l));
376 _vec_dX.at(oldest).axpy(_vec_v, om);
377
378 matrix.apply(_vec_t, _vec_dX.at(oldest));
379 filter.filter_def(_vec_t);
380 }
381 else
382 {
383 //dX(oldest)=-dX*c+om*v
384 _vec_dX.at(oldest).scale(_vec_dX.at(oldest), -_dvec_c(oldest));
385 for (Index l(0); l < oldest; ++l)
386 _vec_dX.at(oldest).axpy(_vec_dX.at(l), -_dvec_c(l));
387 for (Index l(oldest+1); l < _krylov_dim; ++l)
388 _vec_dX.at(oldest).axpy(_vec_dX.at(l), -_dvec_c(l));
389 _vec_dX.at(oldest).axpy(_vec_v, om);
390
391 matrix.apply( _vec_dR.at(oldest), _vec_dX.at(oldest));
392 filter.filter_def(_vec_dR.at(oldest));
393 _vec_t.copy(_vec_dR.at(oldest));
394 if(!this->_apply_precond(this->_vec_dR.at(oldest), this->_vec_t, filter))
395 {
396 stat.destroy();
397 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
398 return Status::aborted;
399 }
400 _vec_dR.at(oldest).scale(_vec_dR.at(oldest), DataType(-1));
401 }
402
403
404 _vec_r.axpy(_vec_dR.at(oldest));
405 vec_sol.axpy(_vec_dX.at(oldest));
406 _vec_res.axpy(_vec_t, -1);
407
408 status = this->_set_new_defect(_vec_res, vec_sol);
409 if (status != Status::progress)
410 break;
411
412 for (Index l(0); l < _krylov_dim; ++l)
413 {
414 _dvec_dm(l, _vec_P.at(l).dot(_vec_dR.at(oldest)) );
415 _dmat_M( l, oldest, _dvec_dm(l));
416 }
417 _dvec_m.axpy(_dvec_dm);
418 oldest = (oldest+1) % _krylov_dim;
419 } //end inner loop
420
421 } //end outer loop
422 // finished
423 Statistics::add_solver_expression(std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
424 return status;
425 } //_apply_intern(...)
426 }; // class IDRS<...>
427
446 template<typename Matrix_, typename Filter_>
447 inline std::shared_ptr<IDRS<Matrix_, Filter_>> new_idrs(
448 const Matrix_& matrix, const Filter_& filter, Index krylov_dim,
449 std::shared_ptr<SolverBase<typename Matrix_::VectorTypeL>> precond = nullptr)
450 {
451 return std::make_shared<IDRS<Matrix_, Filter_>>(matrix, filter, krylov_dim, precond);
452 }
453
475 template<typename Matrix_, typename Filter_>
476 inline std::shared_ptr<IDRS<Matrix_, Filter_>> new_idrs(
477 const String& section_name, const PropertyMap* section,
478 const Matrix_& matrix, const Filter_& filter,
479 std::shared_ptr<SolverBase<typename Matrix_::VectorTypeL>> precond = nullptr)
480 {
481 return std::make_shared<IDRS<Matrix_, Filter_>>(section_name, section, matrix, filter, precond);
482 }
483 } // namespace Solver
484} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
static Comm world()
Returns a copy of the world communicator.
Definition: dist.cpp:429
Dense data matrix class template.
void apply(DenseVector< DT_, IT_ > &r, const DenseVector< DT_, IT_ > &x) const
Calculate .
DenseMatrix inverse() const
Create an inverse of the current matrix.
Dense data vector class template.
void axpy(const DenseVector &x, const DT_ alpha=DT_(1))
Calculate .
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.
Pseudo-Random Number Generator.
Definition: random.hpp:54
std::uint64_t SeedType
seed type
Definition: random.hpp:57
IDR(s) solver implementation.
Definition: idrs.hpp:43
virtual ~IDRS()
Empty virtual destructor.
Definition: idrs.hpp:129
virtual Status apply(VectorType &vec_sol, const VectorType &vec_rhs) override
Solver application method.
Definition: idrs.hpp:194
DVector _dvec_m
local ("small") dense vectors
Definition: idrs.hpp:72
void reset_shadow_space(bool random=true)
Reset the shadow space before the next system will be solved.
Definition: idrs.hpp:235
virtual String name() const override
Returns a descriptive string.
Definition: idrs.hpp:134
std::vector< VectorType > _vec_P
n x s "matrices"
Definition: idrs.hpp:68
DMatrix _dmat_M
dense s x s - matrices
Definition: idrs.hpp:70
IDRS(const MatrixType &matrix, const FilterType &filter, Index krylov_dim, std::shared_ptr< PrecondType > precond=nullptr)
Constructor.
Definition: idrs.hpp:91
VectorType _vec_q
auxillary vectors from the algorithm
Definition: idrs.hpp:64
virtual void done_symbolic() override
Symbolic finalization method.
Definition: idrs.hpp:165
virtual Status correct(VectorType &vec_sol, const VectorType &vec_rhs) override
Definition: idrs.hpp:213
const FilterType & _system_filter
the filter for the solver
Definition: idrs.hpp:60
VectorType _vec_res
real (unpreconditioned) residual
Definition: idrs.hpp:66
virtual void set_krylov_dim(Index krylov_dim)
Sets the inner Krylov space dimension.
Definition: idrs.hpp:187
virtual void init_symbolic() override
Symbolic initialization method.
Definition: idrs.hpp:139
const MatrixType & _system_matrix
the matrix for the solver
Definition: idrs.hpp:58
Index _krylov_dim
krylov dimension (s)
Definition: idrs.hpp:62
void set_plot_name(const String &plot_name)
Sets the plot name of the solver.
Definition: iterative.hpp:517
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
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
virtual void plot_summary() const
Plot a summary of the last solver run.
Definition: iterative.hpp:627
virtual Status _set_initial_defect(const VectorType &vec_def, const VectorType &vec_sol)
Internal function: sets the initial defect vector.
Definition: iterative.hpp:802
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
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)
std::shared_ptr< IDRS< Matrix_, Filter_ > > new_idrs(const Matrix_ &matrix, const Filter_ &filter, Index krylov_dim, std::shared_ptr< SolverBase< typename Matrix_::VectorTypeL > > precond=nullptr)
Creates a new IDR(s) solver object.
Definition: idrs.hpp:447
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.