FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
bicgstab.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
11namespace FEAT
12{
13 namespace Solver
14 {
15
20 {
21 left,
22 right
23 };
24
26
29 inline std::ostream& operator<<(std::ostream& os, BiCGStabPreconVariant precon_variant)
30 {
31 switch(precon_variant)
32 {
33 case BiCGStabPreconVariant::left:
34 return os << "left";
35 case BiCGStabPreconVariant::right:
36 return os << "right";
37 default:
38 return os << "unknown";
39 }
40 }
41
42 inline std::istream& operator>>(std::istream& is, BiCGStabPreconVariant& precon_variant)
43 {
44 String s;
45 if((is >> s).fail())
46 return is;
47
48 if(s.compare_no_case("left") == 0)
49 precon_variant = BiCGStabPreconVariant::left;
50 else if(s.compare_no_case("right") == 0)
51 precon_variant = BiCGStabPreconVariant::right;
52 else
53 is.setstate(std::ios_base::failbit);
54
55 return is;
56 }
57
59
134 template<typename Matrix_, typename Filter_>
135 class BiCGStab :
136 public PreconditionedIterativeSolver<typename Matrix_::VectorTypeR>
137 {
138 public:
140 typedef Matrix_ MatrixType;
142 typedef Filter_ FilterType;
144 typedef typename MatrixType::VectorTypeR VectorType;
146 typedef typename MatrixType::DataType DataType;
151
152 protected:
173
174 public:
190 explicit BiCGStab(const MatrixType& matrix, const FilterType& filter,
191 std::shared_ptr<PrecondType> precond = nullptr,
192 BiCGStabPreconVariant precon_variant = BiCGStabPreconVariant::left)
193 :
194 BaseClass("BiCGStab", precond),
195 _system_matrix(matrix),
196 _system_filter(filter),
197 _precon_variant(precon_variant)
198 {
199 XASSERT(precon_variant == BiCGStabPreconVariant::left || precon_variant == BiCGStabPreconVariant::right);
200
201 // we always need to compute defect norms
202 this->_force_def_norm_calc = true;
203
204 // set communicator by system matrix
205 this->_set_comm_by_matrix(matrix);
206 }
207
227 explicit BiCGStab(const String& section_name, const PropertyMap* section,
228 const MatrixType& matrix, const FilterType& filter,
229 std::shared_ptr<PrecondType> precond = nullptr)
230 :
231 BaseClass("BiCGStab", section_name, section, precond),
232 _system_matrix(matrix),
233 _system_filter(filter),
235 {
236 // we always need to compute defect norms
237 this->_force_def_norm_calc = true;
238
239 // set communicator by system matrix
240 this->_set_comm_by_matrix(matrix);
241 // Check if we have set _p_variant
242 auto p_variant_p = section->query("precon_variant");
243 if(p_variant_p.second && !p_variant_p.first.parse(this->_precon_variant))
244 throw ParseError(section_name + ".precon_variant", p_variant_p.first, "one of: left, right");
245 }
246
248 virtual String name() const override
249 {
250 return "BiCGStab";
251 }
252
259 virtual void force_defect_norm_calc(bool DOXY(force)) override
260 {
261 // force is already applied in constructor
262 }
263
265 virtual void init_symbolic() override
266 {
268 // create all temporary vectors
269 _vec_p_tilde = this->_system_matrix.create_vector_r();
270 _vec_q_tilde = this->_system_matrix.create_vector_r();
271 _vec_r = this->_system_matrix.create_vector_r();
272 _vec_r_hat_0 = this->_system_matrix.create_vector_r();
273 _vec_r_tilde = this->_system_matrix.create_vector_r();
274 _vec_t_tilde = this->_system_matrix.create_vector_r();
275 _vec_tmp = this->_system_matrix.create_vector_r();
276 }
277
279 virtual void done_symbolic() override
280 {
281 _vec_p_tilde.clear();
282 _vec_q_tilde.clear();
283 _vec_r.clear();
284 _vec_r_hat_0.clear();
285 _vec_r_tilde.clear();
286 _vec_t_tilde.clear();
287 _vec_tmp.clear();
288
290 }
291
293 virtual Status correct(VectorType& vec_sol, const VectorType& vec_rhs) override
294 {
295 // compute initial defect
296 this->_system_matrix.apply(this->_vec_r, vec_sol, vec_rhs, -DataType(1));
297 this->_system_filter.filter_def(this->_vec_r);
298
299 // apply solver
300 this->_status = _apply_intern(vec_sol, vec_rhs);
301
302 // plot summary
303 this->plot_summary();
304
305 // return status
306 return this->_status;
307 }
308
310 virtual Status apply(VectorType& vec_cor, const VectorType& vec_def) override
311 {
312 // save rhs vector as initial defect
313 this->_vec_r.copy(vec_def);
314
315 // format solution vector
316 vec_cor.format();
317
318 // apply solver
319 this->_status = _apply_intern(vec_cor, vec_def);
320
321 // plot summary
322 this->plot_summary();
323
324 // return status
325 return this->_status;
326 }
327
328
335 virtual void set_precon_variant(BiCGStabPreconVariant precon_variant)
336 {
337 XASSERT(precon_variant == BiCGStabPreconVariant::left || precon_variant == BiCGStabPreconVariant::right);
338 _precon_variant = precon_variant;
339 }
340
341 protected:
354 Status _apply_intern(VectorType& vec_sol, const VectorType& DOXY(vec_rhs))
355 {
356 IterationStats pre_iter(*this);
357 Statistics::add_solver_expression(std::make_shared<ExpressionStartSolve>(this->name()));
358 VectorType& vec_p_tilde (_vec_p_tilde);
359 VectorType& vec_r (_vec_r);
360 VectorType& vec_r_tilde (_vec_r_tilde);
361 VectorType& vec_t (_vec_tmp);
362 VectorType& vec_t_tilde (_vec_t_tilde);
363 VectorType& vec_q (_vec_tmp);
364 VectorType& vec_q_tilde (_vec_q_tilde);
365
366 const MatrixType& mat_sys(this->_system_matrix);
367 const FilterType& fil_sys(this->_system_filter);
368 Status status(Status::progress);
369
370 // Apply preconditioner to initial defect and save it to p_0
371 if(!this->_apply_precond(vec_p_tilde, _vec_r, fil_sys))
372 {
373 Statistics::add_solver_expression(
374 std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
375 return Status::aborted;
376 }
377
378 // We set the arbitrary vector r^[0] = r[0]
379 _vec_r_hat_0.copy(vec_r);
380 // r~[0] = M^{-1} r[0]
381 vec_r_tilde.copy(vec_p_tilde);
382
383 const VectorType& vec_r_hat_0(_vec_r_hat_0);
384
385 DataType rho(0);
386
387 // Left preconditioned: rho[k] = <r^[0], r~[k]>
388 if(_precon_variant == BiCGStabPreconVariant::left)
389 {
390 rho = vec_r_hat_0.dot(vec_r_tilde);
391 }
392 // Right preconditioned: rho[k] = <r^[0], r[k]>
393 else
394 {
395 rho = vec_r_hat_0.dot(vec_r);
396 }
397
398 // Compute initial defect
399 status = this->_set_initial_defect(vec_r, vec_sol);
400
401 pre_iter.destroy();
402
403 while(status == Status::progress)
404 {
405 IterationStats stat(*this);
406
407 // q[k] = A p~[k]
408 mat_sys.apply(vec_q, vec_p_tilde);
409 fil_sys.filter_def(vec_q);
410
411 // Apply preconditioner to primal search direction
412 // q~[k] = M^{-1} q[k]
413 if(!this->_apply_precond(vec_q_tilde, vec_q, fil_sys))
414 {
415 stat.destroy();
416 Statistics::add_solver_expression(
417 std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
418 return Status::aborted;
419 }
420
421 DataType alpha(0);
422 // Left preconditioned: alpha[k] = rho[k] / <r^[0], q~[k]>
423 if(_precon_variant == BiCGStabPreconVariant::left)
424 {
425 alpha = rho / vec_r_hat_0.dot(vec_q_tilde);
426 }
427 // Right preconditioned: alpha[k] = rho[k] / <r^[0], q[k]>
428 else
429 {
430 alpha = rho / vec_r_hat_0.dot(vec_q);
431 }
432
433 // First "half" update
434 // x[k+1/2] = x[k] + alpha[k] p~[k]
435 vec_sol.axpy(vec_p_tilde, alpha);
436
437 // r[k+1/2] = r[k] - alpha[k] q[k]
438 vec_r.axpy(vec_q, -alpha);
439
440 // Check if we are already converged or failed after the "half" update
441 {
442 Status status_half(Status::progress);
443
444 DataType def_old(this->_def_cur);
445 DataType def_half(vec_r.norm2());
446
447 // ensure that the defect is neither NaN nor infinity
448 if(!Math::isfinite(def_half))
449 {
450 status_half = Status::aborted;
451 }
452 // is diverged?
453 else if(this->is_diverged(def_half))
454 {
455 this->_def_cur = def_half;
456 status_half = Status::diverged;
457 }
458 // minimum iterations not reached yet?
459 else if(this->_num_iter < this->_min_iter)
460 {
461 status_half = Status::progress;
462 }
463 // is converged?
464 else if(this->is_converged(def_half))
465 {
466 this->_def_cur = def_half;
467 status_half = Status::success;
468 }
469
470 // If we break early, we still count this iteration and plot it if necessary
471 if(status_half != Status::progress)
472 {
473 ++this->_num_iter;
474 this->_def_prev = def_old;
475
476 // plot?
477 if(this->_plot_iter())
478 this->_plot_iter_line(this->_num_iter, this->_def_cur, def_old);
479
480 stat.destroy();
481 Statistics::add_solver_expression(
482 std::make_shared<ExpressionEndSolve>(this->name(), status_half, this->get_num_iter()));
483
484 return status_half;
485 }
486 }
487
488 // Update preconditioned defect: r~[k+1/2] = r~[k] - alpha q[k]
489 vec_r_tilde.axpy(vec_q_tilde, -alpha);
490
491 // t = A r~[k+1/2]
492 mat_sys.apply(vec_t, vec_r_tilde);
493 fil_sys.filter_def(vec_t);
494
495 // Apply preconditioner for correction direction
496 // t~[k] = M^{-1} t
497 if(!this->_apply_precond(vec_t_tilde, vec_t, fil_sys))
498 {
499 stat.destroy();
500 Statistics::add_solver_expression(
501 std::make_shared<ExpressionEndSolve>(this->name(), Status::aborted, this->get_num_iter()));
502 return Status::aborted;
503 }
504
505 DataType omega(0);
506 // Left preconditioned: omega[k] = <t~[k], r~[k+1/2] / <t~[k], t~[k]>
507 if(_precon_variant == BiCGStabPreconVariant::left)
508 {
509 omega = vec_t_tilde.dot(vec_r_tilde) / vec_t_tilde.dot(vec_t_tilde);
510 }
511 // Right preconditioned: omega[k] = <t[k], r[k+1/2] / <t[k], t[k]>
512 else
513 {
514 omega = vec_t.dot(vec_r) / vec_t.dot(vec_t);
515 }
516
517 if(!Math::isfinite(omega))
518 {
519 // This should not happen: BiCGStab breakdown
520 status = Status::aborted;
521 stat.destroy();
522 Statistics::add_solver_expression(
523 std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
524 return status;
525 }
526
527 // Second "half" update
528 // x[k+1] = x[k+1/2] + omega r~[k+1/2]
529 vec_sol.axpy(vec_r_tilde, omega);
530
531 // Upate defect
532 // r[k+1] = r[k] - omega t[k]
533 vec_r.axpy(vec_t, -omega);
534
535 // Compute defect norm
536 status = this->_set_new_defect(vec_r, vec_sol);
537
538 if(status != Status::progress)
539 {
540 stat.destroy();
541 Statistics::add_solver_expression(
542 std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
543 return status;
544 }
545
546 // Update preconditioned defect
547 // r~[k+1] = r~[k] - omega t~[k]
548 vec_r_tilde.axpy(vec_t_tilde, -omega);
549
550 // Save old rho
551 DataType rho2(rho);
552 // Left preconditioned: rho[k+1] = <r^[0], r~[k+1]>
553 if(_precon_variant == BiCGStabPreconVariant::left)
554 {
555 rho = vec_r_hat_0.dot(vec_r_tilde);
556 }
557 // Right preconditioned: rho[k+1] = <r^[0], r[k+1]>
558 else
559 {
560 rho = vec_r_hat_0.dot(vec_r);
561 }
562
563 // beta[k] = (rho[k+1]*alpha[k]) / (rho[k]*omega[k])
564 DataType beta((rho/rho2)*(alpha/omega));
565 if(!Math::isfinite(beta))
566 {
567 // This should not happen: BiCGStab breakdown
568 status = Status::aborted;
569 stat.destroy();
570 Statistics::add_solver_expression(
571 std::make_shared<ExpressionEndSolve>(this->name(), status, this->get_num_iter()));
572 return status;
573 }
574
575 // p~[k+1] = r~[k+1] + beta(p~[k] - omega[k] q~[k])
576 vec_p_tilde.axpy(vec_q_tilde, -omega);
577 vec_p_tilde.scale(vec_p_tilde, beta);
578 vec_p_tilde.axpy(vec_r_tilde);
579
580 }
581
582 // we should never reach this point...
583 Statistics::add_solver_expression(
584 std::make_shared<ExpressionEndSolve>(this->name(), Status::undefined, this->get_num_iter()));
585 return Status::undefined;
586 }
587 }; // class BiCGStab<...>
588
607 template<typename Matrix_, typename Filter_>
608 inline std::shared_ptr<BiCGStab<Matrix_, Filter_>> new_bicgstab(
609 const Matrix_& matrix, const Filter_& filter,
610 std::shared_ptr<SolverBase<typename Matrix_::VectorTypeL>> precond = nullptr,
611 BiCGStabPreconVariant precon_variant = BiCGStabPreconVariant::left)
612 {
613 return std::make_shared<BiCGStab<Matrix_, Filter_>>(matrix, filter, precond, precon_variant);
614 }
615
637 template<typename Matrix_, typename Filter_>
638 inline std::shared_ptr<BiCGStab<Matrix_, Filter_>> new_bicgstab(
639 const String& section_name, const PropertyMap* section,
640 const Matrix_& matrix, const Filter_& filter,
641 std::shared_ptr<SolverBase<typename Matrix_::VectorTypeL>> precond = nullptr)
642 {
643 return std::make_shared<BiCGStab<Matrix_, Filter_>>(section_name, section, matrix, filter, precond);
644 }
645 } // namespace Solver
646} // 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.
(Preconditioned) Bi-Conjugate Gradient Stabilized solver implementation
Definition: bicgstab.hpp:137
SolverBase< VectorType > PrecondType
The type of the preconditioner.
Definition: bicgstab.hpp:150
virtual void force_defect_norm_calc(bool force) override
Forces the calculation of defect norms in every iteration (overridden)
Definition: bicgstab.hpp:259
virtual void init_symbolic() override
Symbolic initialization method.
Definition: bicgstab.hpp:265
virtual Status apply(VectorType &vec_cor, const VectorType &vec_def) override
Solver application method.
Definition: bicgstab.hpp:310
PreconditionedIterativeSolver< VectorType > BaseClass
Our base class.
Definition: bicgstab.hpp:148
VectorType _vec_r_hat_0
The arbitrary starting vector.
Definition: bicgstab.hpp:166
BiCGStab(const String &section_name, const PropertyMap *section, const MatrixType &matrix, const FilterType &filter, std::shared_ptr< PrecondType > precond=nullptr)
Constructor using a PropertyMap.
Definition: bicgstab.hpp:227
virtual Status correct(VectorType &vec_sol, const VectorType &vec_rhs) override
Solver correction method.
Definition: bicgstab.hpp:293
VectorType _vec_tmp
Temporary vector.
Definition: bicgstab.hpp:170
virtual String name() const override
Returns a descriptive string.
Definition: bicgstab.hpp:248
BiCGStab(const MatrixType &matrix, const FilterType &filter, std::shared_ptr< PrecondType > precond=nullptr, BiCGStabPreconVariant precon_variant=BiCGStabPreconVariant::left)
Constructor.
Definition: bicgstab.hpp:190
VectorType _vec_r_tilde
The preconditioned defect vector.
Definition: bicgstab.hpp:164
const MatrixType & _system_matrix
the matrix for the solver
Definition: bicgstab.hpp:154
BiCGStabPreconVariant _precon_variant
Precondition from left or right?
Definition: bicgstab.hpp:172
virtual void set_precon_variant(BiCGStabPreconVariant precon_variant)
Sets the preconditioning variant (left or right)
Definition: bicgstab.hpp:335
VectorType _vec_t_tilde
t~[k] = M^{-1} A r~[k+1/2]
Definition: bicgstab.hpp:168
virtual void done_symbolic() override
Symbolic finalization method.
Definition: bicgstab.hpp:279
MatrixType::VectorTypeR VectorType
The vector type this solver can be applied to.
Definition: bicgstab.hpp:144
const FilterType & _system_filter
the filter for the solver
Definition: bicgstab.hpp:156
VectorType _vec_p_tilde
The preconditioned primal search direction.
Definition: bicgstab.hpp:158
MatrixType::DataType DataType
The floating point precision.
Definition: bicgstab.hpp:146
Status _apply_intern(VectorType &vec_sol, const VectorType &vec_rhs)
Internal function, applies the solver.
Definition: bicgstab.hpp:354
Matrix_ MatrixType
The matrix type this solver can be applied to.
Definition: bicgstab.hpp:140
VectorType _vec_q_tilde
q~[k] = M^{-1} A q[k]
Definition: bicgstab.hpp:160
Filter_ FilterType
The filter to apply.
Definition: bicgstab.hpp:142
VectorType _vec_r
The defect vector.
Definition: bicgstab.hpp:162
Helper class for iteration statistics collection.
Definition: base.hpp:392
void destroy()
destroy the objects contents (and generate Statistics::expression) before the actual destructor call
Definition: base.hpp:464
bool _force_def_norm_calc
whether skipping of defect computation is allowed or not
Definition: iterative.hpp:249
Index _min_iter
minimum number of iterations
Definition: iterative.hpp:227
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
bool is_diverged() const
checks for divergence
Definition: iterative.hpp:552
DataType _def_prev
previous iteration defect
Definition: iterative.hpp:241
virtual void _plot_iter_line(Index num_iter, DataType def_cur, DataType def_prev)
Plots an iteration line.
Definition: iterative.hpp:773
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 _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
virtual Status _set_initial_defect(const VectorType &vec_def, const VectorType &vec_sol)
Internal function: sets the initial defect vector.
Definition: iterative.hpp:802
bool is_converged() const
checks for convergence
Definition: iterative.hpp:533
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
bool isfinite(T_ x)
Checks whether a value is finite.
std::istream & operator>>(std::istream &is, Pack::Type &t)
stream input operator for Pack::Type
Definition: pack.hpp:189
BiCGStabPreconVariant
Enum for different preconditioning variants for BiCGStab.
Definition: bicgstab.hpp:20
Status
Solver status return codes enumeration.
Definition: base.hpp:47
@ success
solving successful (convergence criterion fulfilled)
@ progress
continue iteration (internal use only)
@ undefined
undefined status
@ diverged
solver diverged (divergence criterion fulfilled)
@ aborted
premature abort (solver aborted due to internal errors or preconditioner failure)
std::shared_ptr< BiCGStab< Matrix_, Filter_ > > new_bicgstab(const Matrix_ &matrix, const Filter_ &filter, std::shared_ptr< SolverBase< typename Matrix_::VectorTypeL > > precond=nullptr, BiCGStabPreconVariant precon_variant=BiCGStabPreconVariant::left)
Creates a new BiCGStab solver object.
Definition: bicgstab.hpp:608
FEAT namespace.
Definition: adjactor.hpp:12