Dune Core Modules (unstable)

solvers.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4// vi: set et ts=4 sw=2 sts=2:
5
6#ifndef DUNE_ISTL_SOLVERS_HH
7#define DUNE_ISTL_SOLVERS_HH
8
9#include <array>
10#include <cmath>
11#include <complex>
12#include <iostream>
13#include <memory>
14#include <type_traits>
15#include <vector>
16
18#include <dune/common/math.hh>
21#include <dune/common/std/type_traits.hh>
22#include <dune/common/timer.hh>
23
24#include <dune/istl/allocator.hh>
26#include <dune/istl/eigenvalue/arpackpp.hh>
27#include <dune/istl/istlexception.hh>
29#include <dune/istl/preconditioner.hh>
31#include <dune/istl/solver.hh>
32#include <dune/istl/solverregistry.hh>
33
34namespace Dune {
46 //=====================================================================
47 // Implementation of this interface
48 //=====================================================================
49
58 template<class X>
59 class LoopSolver : public IterativeSolver<X,X> {
60 public:
65
66 // copy base class constructors
68
69 // don't shadow four-argument version of apply defined in the base class
70 using IterativeSolver<X,X>::apply;
71
73 void apply (X& x, X& b, InverseOperatorResult& res) override
74 {
75 Iteration iteration(*this, res);
76 _prec->pre(x,b);
77
78 // overwrite b with defect
79 _op->applyscaleadd(-1,x,b);
80
81 // compute norm, \todo parallelization
82 real_type def = _sp->norm(b);
83 if(iteration.step(0, def)){
84 _prec->post(x);
85 return;
86 }
87 // prepare preconditioner
88
89 // allocate correction vector
90 X v(x);
91
92 // iteration loop
93 int i=1;
94 for ( ; i<=_maxit; i++ )
95 {
96 v = 0; // clear correction
97 _prec->apply(v,b); // apply preconditioner
98 x += v; // update solution
99 _op->applyscaleadd(-1,v,b); // update defect
100 def=_sp->norm(b); // comp defect norm
101 if(iteration.step(i, def))
102 break;
103 }
104
105 // postprocess preconditioner
106 _prec->post(x);
107 }
108
109 protected:
110 using IterativeSolver<X,X>::_op;
111 using IterativeSolver<X,X>::_prec;
112 using IterativeSolver<X,X>::_sp;
113 using IterativeSolver<X,X>::_reduction;
114 using IterativeSolver<X,X>::_maxit;
115 using IterativeSolver<X,X>::_verbose;
116 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
117 };
118 DUNE_REGISTER_SOLVER("loopsolver", defaultIterativeSolverCreator<Dune::LoopSolver>());
119
120
121 // all these solvers are taken from the SUMO library
123 template<class X>
124 class GradientSolver : public IterativeSolver<X,X> {
125 public:
129 using typename IterativeSolver<X,X>::real_type;
130
131 // copy base class constructors
133
134 // don't shadow four-argument version of apply defined in the base class
135 using IterativeSolver<X,X>::apply;
136
142 void apply (X& x, X& b, InverseOperatorResult& res) override
143 {
144 Iteration iteration(*this, res);
145 _prec->pre(x,b); // prepare preconditioner
146
147 _op->applyscaleadd(-1,x,b); // overwrite b with defec
148
149 real_type def = _sp->norm(b); // compute norm
150 if(iteration.step(0, def)){
151 _prec->post(x);
152 return;
153 }
154
155 X p(x); // create local vectors
156 X q(b);
157
158 int i=1; // loop variables
159 field_type lambda;
160 for ( ; i<=_maxit; i++ )
161 {
162 p = 0; // clear correction
163 _prec->apply(p,b); // apply preconditioner
164 _op->apply(p,q); // q=Ap
165 auto alpha = _sp->dot(q,p);
166 lambda = Simd::cond(def==field_type(0.),
167 field_type(0.), // no need for minimization if def is already 0
168 field_type(_sp->dot(p,b)/alpha)); // minimization
169 x.axpy(lambda,p); // update solution
170 b.axpy(-lambda,q); // update defect
171
172 def =_sp->norm(b); // comp defect norm
173 if(iteration.step(i, def))
174 break;
175 }
176 // postprocess preconditioner
177 _prec->post(x);
178 }
179
180 protected:
181 using IterativeSolver<X,X>::_op;
182 using IterativeSolver<X,X>::_prec;
183 using IterativeSolver<X,X>::_sp;
184 using IterativeSolver<X,X>::_reduction;
185 using IterativeSolver<X,X>::_maxit;
186 using IterativeSolver<X,X>::_verbose;
187 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
188 };
189 DUNE_REGISTER_SOLVER("gradientsolver", defaultIterativeSolverCreator<Dune::GradientSolver>());
190
192 template<class X>
193 class CGSolver : public IterativeSolver<X,X> {
194 public:
198 using typename IterativeSolver<X,X>::real_type;
199
200 // copy base class constructors
202
203 private:
205
206 protected:
207
208 static constexpr bool enableConditionEstimate = (std::is_same_v<field_type,float> || std::is_same_v<field_type,double>);
209
210 public:
211
212 // don't shadow four-argument version of apply defined in the base class
213 using IterativeSolver<X,X>::apply;
214
223 scalar_real_type reduction, int maxit, int verbose, bool condition_estimate) : IterativeSolver<X,X>(op, prec, reduction, maxit, verbose),
224 condition_estimate_(condition_estimate)
225 {
226 if (condition_estimate && !enableConditionEstimate) {
227 condition_estimate_ = false;
228 std::cerr << "WARNING: Condition estimate was disabled. It is only available for double and float field types!" << std::endl;
229 }
230 }
231
240 scalar_real_type reduction, int maxit, int verbose, bool condition_estimate) : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose),
241 condition_estimate_(condition_estimate)
242 {
243 if (condition_estimate && !(std::is_same<field_type,float>::value || std::is_same<field_type,double>::value)) {
244 condition_estimate_ = false;
245 std::cerr << "WARNING: Condition estimate was disabled. It is only available for double and float field types!" << std::endl;
246 }
247 }
248
257 CGSolver (std::shared_ptr<const LinearOperator<X,X>> op, std::shared_ptr<ScalarProduct<X>> sp,
258 std::shared_ptr<Preconditioner<X,X>> prec,
259 scalar_real_type reduction, int maxit, int verbose, bool condition_estimate)
260 : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose),
261 condition_estimate_(condition_estimate)
262 {
263 if (condition_estimate && !(std::is_same<field_type,float>::value || std::is_same<field_type,double>::value)) {
264 condition_estimate_ = false;
265 std::cerr << "WARNING: Condition estimate was disabled. It is only available for double and float field types!" << std::endl;
266 }
267 }
268
280 void apply (X& x, X& b, InverseOperatorResult& res) override
281 {
282 Iteration iteration(*this,res);
283 _prec->pre(x,b); // prepare preconditioner
284
285 _op->applyscaleadd(-1,x,b); // overwrite b with defect
286
287 real_type def = _sp->norm(b); // compute norm
288 if(iteration.step(0, def)){
289 _prec->post(x);
290 return;
291 }
292
293 X p(x); // the search direction
294 X q(x); // a temporary vector
295
296 // Remember lambda and beta values for condition estimate
297 std::vector<real_type> lambdas(0);
298 std::vector<real_type> betas(0);
299
300 // some local variables
301 field_type rho,rholast,lambda,alpha,beta;
302
303 // determine initial search direction
304 p = 0; // clear correction
305 _prec->apply(p,b); // apply preconditioner
306 rholast = _sp->dot(p,b); // orthogonalization
307
308 // the loop
309 int i=1;
310 for ( ; i<=_maxit; i++ )
311 {
312 // minimize in given search direction p
313 _op->apply(p,q); // q=Ap
314 alpha = _sp->dot(p,q); // scalar product
315 lambda = Simd::cond(def==field_type(0.), field_type(0.), field_type(rholast/alpha)); // minimization
316 if constexpr (enableConditionEstimate)
317 if (condition_estimate_)
318 lambdas.push_back(std::real(lambda));
319 x.axpy(lambda,p); // update solution
320 b.axpy(-lambda,q); // update defect
321
322 // convergence test
323 def=_sp->norm(b); // comp defect norm
324 if(iteration.step(i, def))
325 break;
326
327 // determine new search direction
328 q = 0; // clear correction
329 _prec->apply(q,b); // apply preconditioner
330 rho = _sp->dot(q,b); // orthogonalization
331 beta = Simd::cond(def==field_type(0.), field_type(0.), field_type(rho/rholast)); // scaling factor
332 if constexpr (enableConditionEstimate)
333 if (condition_estimate_)
334 betas.push_back(std::real(beta));
335 p *= beta; // scale old search direction
336 p += q; // orthogonalization with correction
337 rholast = rho; // remember rho for recurrence
338 }
339
340 _prec->post(x); // postprocess preconditioner
341
342 if (condition_estimate_) {
343#if HAVE_ARPACKPP
344 if constexpr (enableConditionEstimate) {
345 using std::sqrt;
346
347 // Build T matrix which has extreme eigenvalues approximating
348 // those of the original system
349 // (see Y. Saad, Iterative methods for sparse linear systems)
350
352
353 for (auto row = T.createbegin(); row != T.createend(); ++row) {
354 if (row.index() > 0)
355 row.insert(row.index()-1);
356 row.insert(row.index());
357 if (row.index() < T.N() - 1)
358 row.insert(row.index()+1);
359 }
360 for (int row = 0; row < i; ++row) {
361 if (row > 0) {
362 T[row][row-1] = sqrt(betas[row-1]) / lambdas[row-1];
363 }
364
365 T[row][row] = 1.0 / lambdas[row];
366 if (row > 0) {
367 T[row][row] += betas[row-1] / lambdas[row-1];
368 }
369
370 if (row < i - 1) {
371 T[row][row+1] = sqrt(betas[row]) / lambdas[row];
372 }
373 }
374
375 // Compute largest and smallest eigenvalue of T matrix and return as estimate
377
378 real_type eps = 0.0;
379 COND_VEC eigv;
380 real_type min_eigv, max_eigv;
381 arpack.computeSymMinMagnitude (eps, eigv, min_eigv);
382 arpack.computeSymMaxMagnitude (eps, eigv, max_eigv);
383
384 res.condition_estimate = max_eigv / min_eigv;
385
386 if (this->_verbose > 0) {
387 std::cout << "Min eigv estimate: " << Simd::io(min_eigv) << '\n';
388 std::cout << "Max eigv estimate: " << Simd::io(max_eigv) << '\n';
389 std::cout << "Condition estimate: "
390 << Simd::io(max_eigv / min_eigv) << std::endl;
391 }
392 }
393#else
394 std::cerr << "WARNING: Condition estimate was requested. This requires ARPACK, but ARPACK was not found!" << std::endl;
395#endif
396 }
397 }
398
399 private:
400 bool condition_estimate_ = false;
401
402 // Matrix and vector types used for condition estimate
405
406 protected:
407 using IterativeSolver<X,X>::_op;
408 using IterativeSolver<X,X>::_prec;
409 using IterativeSolver<X,X>::_sp;
410 using IterativeSolver<X,X>::_reduction;
411 using IterativeSolver<X,X>::_maxit;
412 using IterativeSolver<X,X>::_verbose;
413 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
414 };
415 DUNE_REGISTER_SOLVER("cgsolver", defaultIterativeSolverCreator<Dune::CGSolver>());
416
417 // Ronald Kriemanns BiCG-STAB implementation from Sumo
419 template<class X>
420 class BiCGSTABSolver : public IterativeSolver<X,X> {
421 public:
425 using typename IterativeSolver<X,X>::real_type;
426
427 // copy base class constructors
429
430 // don't shadow four-argument version of apply defined in the base class
431 using IterativeSolver<X,X>::apply;
432
440 void apply (X& x, X& b, InverseOperatorResult& res) override
441 {
442 using std::abs;
443 const Simd::Scalar<real_type> EPSILON=1e-80;
444 using std::abs;
445 double it;
446 field_type rho, rho_new, alpha, beta, h, omega;
447 real_type norm;
448
449 //
450 // get vectors and matrix
451 //
452 X& r=b;
453 X p(x);
454 X v(x);
455 X t(x);
456 X y(x);
457 X rt(x);
458
459 //
460 // begin iteration
461 //
462
463 // r = r - Ax; rt = r
464 Iteration<double> iteration(*this,res);
465 _prec->pre(x,r); // prepare preconditioner
466
467 _op->applyscaleadd(-1,x,r); // overwrite b with defect
468
469 rt=r;
470
471 norm = _sp->norm(r);
472 if(iteration.step(0, norm)){
473 _prec->post(x);
474 return;
475 }
476 p=0;
477 v=0;
478
479 rho = 1;
480 alpha = 1;
481 omega = 1;
482
483 //
484 // iteration
485 //
486
487 for (it = 0.5; it < _maxit; it+=.5)
488 {
489 //
490 // preprocess, set vecsizes etc.
491 //
492
493 // rho_new = < rt , r >
494 rho_new = _sp->dot(rt,r);
495
496 // look if breakdown occurred
497 if (Simd::allTrue(abs(rho) <= EPSILON))
498 DUNE_THROW(SolverAbort,"breakdown in BiCGSTAB - rho "
499 << Simd::io(rho) << " <= EPSILON " << EPSILON
500 << " after " << it << " iterations");
501 if (Simd::allTrue(abs(omega) <= EPSILON))
502 DUNE_THROW(SolverAbort,"breakdown in BiCGSTAB - omega "
503 << Simd::io(omega) << " <= EPSILON " << EPSILON
504 << " after " << it << " iterations");
505
506
507 if (it<1)
508 p = r;
509 else
510 {
511 beta = Simd::cond(norm==field_type(0.),
512 field_type(0.), // no need for orthogonalization if norm is already 0
513 field_type(( rho_new / rho ) * ( alpha / omega )));
514 p.axpy(-omega,v); // p = r + beta (p - omega*v)
515 p *= beta;
516 p += r;
517 }
518
519 // y = W^-1 * p
520 y = 0;
521 _prec->apply(y,p); // apply preconditioner
522
523 // v = A * y
524 _op->apply(y,v);
525
526 // alpha = rho_new / < rt, v >
527 h = _sp->dot(rt,v);
528
529 if ( Simd::allTrue(abs(h) < EPSILON) )
530 DUNE_THROW(SolverAbort,"abs(h) < EPSILON in BiCGSTAB - abs(h) "
531 << Simd::io(abs(h)) << " < EPSILON " << EPSILON
532 << " after " << it << " iterations");
533
534 alpha = Simd::cond(norm==field_type(0.),
535 field_type(0.),
536 field_type(rho_new / h));
537
538 // apply first correction to x
539 // x <- x + alpha y
540 x.axpy(alpha,y);
541
542 // r = r - alpha*v
543 r.axpy(-alpha,v);
544
545 //
546 // test stop criteria
547 //
548
549 norm = _sp->norm(r);
550 if(iteration.step(it, norm)){
551 break;
552 }
553
554 it+=.5;
555
556 // y = W^-1 * r
557 y = 0;
558 _prec->apply(y,r);
559
560 // t = A * y
561 _op->apply(y,t);
562
563 // omega = < t, r > / < t, t >
564 h = _sp->dot(t,t);
565 omega = Simd::cond(norm==field_type(0.),
566 field_type(0.),
567 field_type(_sp->dot(t,r)/h));
568
569 // apply second correction to x
570 // x <- x + omega y
571 x.axpy(omega,y);
572
573 // r = s - omega*t (remember : r = s)
574 r.axpy(-omega,t);
575
576 rho = rho_new;
577
578 //
579 // test stop criteria
580 //
581
582 norm = _sp->norm(r);
583 if(iteration.step(it, norm)){
584 break;
585 }
586 } // end for
587
588 _prec->post(x); // postprocess preconditioner
589 }
590
591 protected:
592 using IterativeSolver<X,X>::_op;
593 using IterativeSolver<X,X>::_prec;
594 using IterativeSolver<X,X>::_sp;
595 using IterativeSolver<X,X>::_reduction;
596 using IterativeSolver<X,X>::_maxit;
597 using IterativeSolver<X,X>::_verbose;
598 template<class CountType>
599 using Iteration = typename IterativeSolver<X,X>::template Iteration<CountType>;
600 };
601 DUNE_REGISTER_SOLVER("bicgstabsolver", defaultIterativeSolverCreator<Dune::BiCGSTABSolver>());
602
609 template<class X>
610 class MINRESSolver : public IterativeSolver<X,X> {
611 public:
615 using typename IterativeSolver<X,X>::real_type;
616
617 // copy base class constructors
619
620 // don't shadow four-argument version of apply defined in the base class
621 using IterativeSolver<X,X>::apply;
622
628 void apply (X& x, X& b, InverseOperatorResult& res) override
629 {
630 using std::sqrt;
631 using std::abs;
632 Iteration iteration(*this, res);
633 // prepare preconditioner
634 _prec->pre(x,b);
635
636 // overwrite rhs with defect
637 _op->applyscaleadd(-1.0,x,b); // b -= Ax
638
639 // some temporary vectors
640 X z(b), dummy(b);
641 z = 0.0;
642
643 // calculate preconditioned defect
644 _prec->apply(z,b); // r = W^-1 (b - Ax)
645 real_type def = _sp->norm(z);
646 if (iteration.step(0, def)){
647 _prec->post(x);
648 return;
649 }
650
651 // recurrence coefficients as computed in Lanczos algorithm
652 field_type alpha, beta;
653 // diagonal entries of givens rotation
654 std::array<real_type,2> c{{0.0,0.0}};
655 // off-diagonal entries of givens rotation
656 std::array<field_type,2> s{{0.0,0.0}};
657
658 // recurrence coefficients (column k of tridiag matrix T_k)
659 std::array<field_type,3> T{{0.0,0.0,0.0}};
660
661 // the rhs vector of the min problem
662 std::array<field_type,2> xi{{1.0,0.0}};
663
664 // beta is real and positive in exact arithmetic
665 // since it is the norm of the basis vectors (in unpreconditioned case)
666 beta = sqrt(_sp->dot(b,z));
667 field_type beta0 = beta;
668
669 // the search directions
670 std::array<X,3> p{{b,b,b}};
671 p[0] = 0.0;
672 p[1] = 0.0;
673 p[2] = 0.0;
674
675 // orthonormal basis vectors (in unpreconditioned case)
676 std::array<X,3> q{{b,b,b}};
677 q[0] = 0.0;
678 q[1] *= Simd::cond(def==field_type(0.),
679 field_type(0.),
680 field_type(real_type(1.0)/beta));
681 q[2] = 0.0;
682
683 z *= Simd::cond(def==field_type(0.),
684 field_type(0.),
685 field_type(real_type(1.0)/beta));
686
687 // the loop
688 int i = 1;
689 for( ; i<=_maxit; i++) {
690
691 dummy = z;
692 int i1 = i%3,
693 i0 = (i1+2)%3,
694 i2 = (i1+1)%3;
695
696 // symmetrically preconditioned Lanczos algorithm (see Greenbaum p.121)
697 _op->apply(z,q[i2]); // q[i2] = Az
698 q[i2].axpy(-beta,q[i0]);
699 // alpha is real since it is the diagonal entry of the hermitian tridiagonal matrix
700 // from the Lanczos Algorithm
701 // so the order in the scalar product doesn't matter even for the complex case
702 alpha = _sp->dot(z,q[i2]);
703 q[i2].axpy(-alpha,q[i1]);
704
705 z = 0.0;
706 _prec->apply(z,q[i2]);
707
708 // beta is real and positive in exact arithmetic
709 // since it is the norm of the basis vectors (in unpreconditioned case)
710 beta = sqrt(_sp->dot(q[i2],z));
711
712 q[i2] *= Simd::cond(def==field_type(0.),
713 field_type(0.),
714 field_type(real_type(1.0)/beta));
715 z *= Simd::cond(def==field_type(0.),
716 field_type(0.),
717 field_type(real_type(1.0)/beta));
718
719 // QR Factorization of recurrence coefficient matrix
720 // apply previous givens rotations to last column of T
721 T[1] = T[2];
722 if(i>2) {
723 T[0] = s[i%2]*T[1];
724 T[1] = c[i%2]*T[1];
725 }
726 if(i>1) {
727 T[2] = c[(i+1)%2]*alpha - s[(i+1)%2]*T[1];
728 T[1] = c[(i+1)%2]*T[1] + s[(i+1)%2]*alpha;
729 }
730 else
731 T[2] = alpha;
732
733 // update QR factorization
734 generateGivensRotation(T[2],beta,c[i%2],s[i%2]);
735 // to last column of T_k
736 T[2] = c[i%2]*T[2] + s[i%2]*beta;
737 // and to the rhs xi of the min problem
738 xi[i%2] = -s[i%2]*xi[(i+1)%2];
739 xi[(i+1)%2] *= c[i%2];
740
741 // compute correction direction
742 p[i2] = dummy;
743 p[i2].axpy(-T[1],p[i1]);
744 p[i2].axpy(-T[0],p[i0]);
745 p[i2] *= real_type(1.0)/T[2];
746
747 // apply correction/update solution
748 x.axpy(beta0*xi[(i+1)%2],p[i2]);
749
750 // remember beta_old
751 T[2] = beta;
752
753 // check for convergence
754 // the last entry in the rhs of the min-problem is the residual
755 def = abs(beta0*xi[i%2]);
756 if(iteration.step(i, def)){
757 break;
758 }
759 } // end for
760
761 // postprocess preconditioner
762 _prec->post(x);
763 }
764
765 private:
766
767 void generateGivensRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
768 {
769 using std::sqrt;
770 using std::abs;
771 using std::max;
772 using std::min;
773 const real_type eps = 1e-15;
774 real_type norm_dx = abs(dx);
775 real_type norm_dy = abs(dy);
776 real_type norm_max = max(norm_dx, norm_dy);
777 real_type norm_min = min(norm_dx, norm_dy);
778 real_type temp = norm_min/norm_max;
779 // we rewrite the code in a vectorizable fashion
780 cs = Simd::cond(norm_dy < eps,
781 real_type(1.0),
782 real_type(Simd::cond(norm_dx < eps,
783 real_type(0.0),
784 real_type(Simd::cond(norm_dy > norm_dx,
785 real_type(1.0)/sqrt(real_type(1.0) + temp*temp)*temp,
786 real_type(1.0)/sqrt(real_type(1.0) + temp*temp)
787 )))));
788 sn = Simd::cond(norm_dy < eps,
789 field_type(0.0),
790 field_type(Simd::cond(norm_dx < eps,
791 field_type(1.0),
792 field_type(Simd::cond(norm_dy > norm_dx,
793 // dy and dx are real in exact arithmetic
794 // thus dx*dy is real so we can explicitly enforce it
795 field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*dx*dy/norm_dx/norm_dy,
796 // dy and dx is real in exact arithmetic
797 // so we don't have to conjugate both of them
798 field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*dy/dx
799 )))));
800 }
801
802 protected:
803 using IterativeSolver<X,X>::_op;
804 using IterativeSolver<X,X>::_prec;
805 using IterativeSolver<X,X>::_sp;
806 using IterativeSolver<X,X>::_reduction;
807 using IterativeSolver<X,X>::_maxit;
808 using IterativeSolver<X,X>::_verbose;
809 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
810 };
811 DUNE_REGISTER_SOLVER("minressolver", defaultIterativeSolverCreator<Dune::MINRESSolver>());
812
826 template<class X, class Y=X, class F = Y>
828 {
829 public:
833 using typename IterativeSolver<X,Y>::real_type;
834
835 protected:
837
839 using fAlloc = ReboundAllocatorType<X,field_type>;
841 using rAlloc = ReboundAllocatorType<X,real_type>;
842
843 public:
844
851 RestartedGMResSolver (const LinearOperator<X,Y>& op, Preconditioner<X,Y>& prec, scalar_real_type reduction, int restart, int maxit, int verbose) :
852 IterativeSolver<X,Y>::IterativeSolver(op,prec,reduction,maxit,verbose),
853 _restart(restart)
854 {}
855
862 RestartedGMResSolver (const LinearOperator<X,Y>& op, const ScalarProduct<X>& sp, Preconditioner<X,Y>& prec, scalar_real_type reduction, int restart, int maxit, int verbose) :
863 IterativeSolver<X,Y>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
864 _restart(restart)
865 {}
866
879 RestartedGMResSolver (std::shared_ptr<const LinearOperator<X,Y> > op, std::shared_ptr<Preconditioner<X,X> > prec, const ParameterTree& configuration) :
880 IterativeSolver<X,Y>::IterativeSolver(op,prec,configuration),
881 _restart(configuration.get<int>("restart"))
882 {}
883
884 RestartedGMResSolver (std::shared_ptr<const LinearOperator<X,Y> > op, std::shared_ptr<const ScalarProduct<X> > sp, std::shared_ptr<Preconditioner<X,X> > prec, const ParameterTree& configuration) :
885 IterativeSolver<X,Y>::IterativeSolver(op,sp,prec,configuration),
886 _restart(configuration.get<int>("restart"))
887 {}
888
895 RestartedGMResSolver (std::shared_ptr<const LinearOperator<X,Y>> op,
896 std::shared_ptr<const ScalarProduct<X>> sp,
897 std::shared_ptr<Preconditioner<X,Y>> prec,
898 scalar_real_type reduction, int restart, int maxit, int verbose) :
899 IterativeSolver<X,Y>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
900 _restart(restart)
901 {}
902
911 void apply (X& x, Y& b, InverseOperatorResult& res) override
912 {
913 apply(x,b,Simd::max(_reduction),res);
914 }
915
924 void apply (X& x, Y& b, [[maybe_unused]] double reduction, InverseOperatorResult& res) override
925 {
926 using std::abs;
927 const Simd::Scalar<real_type> EPSILON = 1e-80;
928 const int m = _restart;
929 real_type norm = 0.0;
930 int j = 1;
931 std::vector<field_type,fAlloc> s(m+1), sn(m);
932 std::vector<real_type,rAlloc> cs(m);
933 // need copy of rhs if GMRes has to be restarted
934 Y b2(b);
935 // helper vector
936 Y w(b);
937 std::vector< std::vector<field_type,fAlloc> > H(m+1,s);
938 std::vector<F> v(m+1,b);
939
940 Iteration iteration(*this,res);
941
942 // clear solver statistics and set res.converged to false
943 _prec->pre(x,b);
944
945 // calculate defect and overwrite rhs with it
946 _op->applyscaleadd(-1.0,x,b); // b -= Ax
947 // calculate preconditioned defect
948 v[0] = 0.0; _prec->apply(v[0],b); // r = W^-1 b
949 norm = _sp->norm(v[0]);
950 if(iteration.step(0, norm)){
951 _prec->post(x);
952 return;
953 }
954
955 while(j <= _maxit && res.converged != true) {
956
957 int i = 0;
958 v[0] *= Simd::cond(norm==real_type(0.),
959 real_type(0.),
960 real_type(real_type(1.0)/norm));
961 s[0] = norm;
962 for(i=1; i<m+1; i++)
963 s[i] = 0.0;
964
965 for(i=0; i < m && j <= _maxit && res.converged != true; i++, j++) {
966 w = 0.0;
967 // use v[i+1] as temporary vector
968 v[i+1] = 0.0;
969 // do Arnoldi algorithm
970 _op->apply(v[i],v[i+1]);
971 _prec->apply(w,v[i+1]);
972 for(int k=0; k<i+1; k++) {
973 // notice that _sp->dot(v[k],w) = v[k]\adjoint w
974 // so one has to pay attention to the order
975 // in the scalar product for the complex case
976 // doing the modified Gram-Schmidt algorithm
977 H[k][i] = _sp->dot(v[k],w);
978 // w -= H[k][i] * v[k]
979 w.axpy(-H[k][i],v[k]);
980 }
981 H[i+1][i] = _sp->norm(w);
982 if(Simd::allTrue(abs(H[i+1][i]) < EPSILON))
984 "breakdown in GMRes - |w| == 0.0 after " << j << " iterations");
985
986 // normalize new vector
987 v[i+1] = w;
988 v[i+1] *= Simd::cond(norm==real_type(0.),
989 field_type(0.),
990 field_type(real_type(1.0)/H[i+1][i]));
991
992 // update QR factorization
993 for(int k=0; k<i; k++)
994 applyPlaneRotation(H[k][i],H[k+1][i],cs[k],sn[k]);
995
996 // compute new givens rotation
997 generatePlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
998 // finish updating QR factorization
999 applyPlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
1000 applyPlaneRotation(s[i],s[i+1],cs[i],sn[i]);
1001
1002 // norm of the defect is the last component the vector s
1003 norm = abs(s[i+1]);
1004
1005 iteration.step(j, norm);
1006
1007 } // end for
1008
1009 // calculate update vector
1010 w = 0.0;
1011 update(w,i,H,s,v);
1012 // and current iterate
1013 x += w;
1014
1015 // restart GMRes if convergence was not achieved,
1016 // i.e. linear defect has not reached desired reduction
1017 // and if j < _maxit (do not restart on last iteration)
1018 if( res.converged != true && j < _maxit ) {
1019
1020 if(_verbose > 0)
1021 std::cout << "=== GMRes::restart" << std::endl;
1022 // get saved rhs
1023 b = b2;
1024 // calculate new defect
1025 _op->applyscaleadd(-1.0,x,b); // b -= Ax;
1026 // calculate preconditioned defect
1027 v[0] = 0.0;
1028 _prec->apply(v[0],b);
1029 norm = _sp->norm(v[0]);
1030 }
1031
1032 } //end while
1033
1034 // postprocess preconditioner
1035 _prec->post(x);
1036 }
1037
1038 protected :
1039
1040 void update(X& w, int i,
1041 const std::vector<std::vector<field_type,fAlloc> >& H,
1042 const std::vector<field_type,fAlloc>& s,
1043 const std::vector<X>& v) {
1044 // solution vector of the upper triangular system
1045 std::vector<field_type,fAlloc> y(s);
1046
1047 // backsolve
1048 for(int a=i-1; a>=0; a--) {
1049 field_type rhs(s[a]);
1050 for(int b=a+1; b<i; b++)
1051 rhs -= H[a][b]*y[b];
1052 y[a] = Simd::cond(rhs==field_type(0.),
1053 field_type(0.),
1054 field_type(rhs/H[a][a]));
1055
1056 // compute update on the fly
1057 // w += y[a]*v[a]
1058 w.axpy(y[a],v[a]);
1059 }
1060 }
1061
1062 template<typename T>
1063 typename std::enable_if<std::is_same<field_type,real_type>::value,T>::type conjugate(const T& t) {
1064 return t;
1065 }
1066
1067 template<typename T>
1068 typename std::enable_if<!std::is_same<field_type,real_type>::value,T>::type conjugate(const T& t) {
1069 using std::conj;
1070 return conj(t);
1071 }
1072
1073 void
1074 generatePlaneRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
1075 {
1076 using std::sqrt;
1077 using std::abs;
1078 using std::max;
1079 using std::min;
1080 const real_type eps = 1e-15;
1081 real_type norm_dx = abs(dx);
1082 real_type norm_dy = abs(dy);
1083 real_type norm_max = max(norm_dx, norm_dy);
1084 real_type norm_min = min(norm_dx, norm_dy);
1085 real_type temp = norm_min/norm_max;
1086 // we rewrite the code in a vectorizable fashion
1087 cs = Simd::cond(norm_dy < eps,
1088 real_type(1.0),
1089 Simd::cond(norm_dx < eps,
1090 real_type(0.0),
1091 real_type(Simd::cond(norm_dy > norm_dx,
1092 real_type(1.0)/sqrt(real_type(1.0) + temp*temp)*temp,
1093 real_type(1.0)/sqrt(real_type(1.0) + temp*temp)
1094 ))));
1095 sn = Simd::cond(norm_dy < eps,
1096 field_type(0.0),
1097 Simd::cond(norm_dx < eps,
1098 field_type(1.0),
1099 field_type(Simd::cond(norm_dy > norm_dx,
1100 field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*dx*conjugate(dy)/norm_dx/norm_dy,
1101 field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*conjugate(dy/dx)
1102 ))));
1103 }
1104
1105
1106 void
1107 applyPlaneRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
1108 {
1109 field_type temp = cs * dx + sn * dy;
1110 dy = -conjugate(sn) * dx + cs * dy;
1111 dx = temp;
1112 }
1113
1114 using IterativeSolver<X,Y>::_op;
1115 using IterativeSolver<X,Y>::_prec;
1116 using IterativeSolver<X,Y>::_sp;
1117 using IterativeSolver<X,Y>::_reduction;
1118 using IterativeSolver<X,Y>::_maxit;
1119 using IterativeSolver<X,Y>::_verbose;
1120 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1121 int _restart;
1122 };
1123 DUNE_REGISTER_SOLVER("restartedgmressolver", defaultIterativeSolverCreator<Dune::RestartedGMResSolver>());
1124
1138 template<class X, class Y=X, class F = Y>
1140 {
1141 public:
1146
1147 private:
1149
1151 using fAlloc = typename RestartedGMResSolver<X,Y>::fAlloc;
1153 using rAlloc = typename RestartedGMResSolver<X,Y>::rAlloc;
1154
1155 public:
1156 // copy base class constructors
1158
1159 // don't shadow four-argument version of apply defined in the base class
1160 using RestartedGMResSolver<X,Y>::apply;
1161
1170 void apply (X& x, Y& b, [[maybe_unused]] double reduction, InverseOperatorResult& res) override
1171 {
1172 using std::abs;
1173 const Simd::Scalar<real_type> EPSILON = 1e-80;
1174 const int m = _restart;
1175 real_type norm = 0.0;
1176 int i, j = 1, k;
1177 std::vector<field_type,fAlloc> s(m+1), sn(m);
1178 std::vector<real_type,rAlloc> cs(m);
1179 // helper vector
1180 Y tmp(b);
1181 std::vector< std::vector<field_type,fAlloc> > H(m+1,s);
1182 std::vector<F> v(m+1,b);
1183 std::vector<X> w(m+1,b);
1184
1185 Iteration iteration(*this,res);
1186 // setup preconditioner if it does something in pre
1187
1188 // calculate residual and overwrite a copy of the rhs with it
1189 _prec->pre(x, b);
1190 v[0] = b;
1191 _op->applyscaleadd(-1.0, x, v[0]); // b -= Ax
1192
1193 norm = _sp->norm(v[0]); // the residual norm
1194 if(iteration.step(0, norm)){
1195 _prec->post(x);
1196 return;
1197 }
1198
1199 // start iterations
1200 res.converged = false;;
1201 while(j <= _maxit && res.converged != true)
1202 {
1203 v[0] *= (1.0 / norm);
1204 s[0] = norm;
1205 for(i=1; i<m+1; ++i)
1206 s[i] = 0.0;
1207
1208 // inner loop
1209 for(i=0; i < m && j <= _maxit && res.converged != true; i++, j++)
1210 {
1211 w[i] = 0.0;
1212 // compute wi = M^-1*vi (also called zi)
1213 _prec->apply(w[i], v[i]);
1214 // compute vi = A*wi
1215 // use v[i+1] as temporary vector for w
1216 _op->apply(w[i], v[i+1]);
1217 // do Arnoldi algorithm
1218 for(int kk=0; kk<i+1; kk++)
1219 {
1220 // notice that _sp->dot(v[k],v[i+1]) = v[k]\adjoint v[i+1]
1221 // so one has to pay attention to the order
1222 // in the scalar product for the complex case
1223 // doing the modified Gram-Schmidt algorithm
1224 H[kk][i] = _sp->dot(v[kk],v[i+1]);
1225 // w -= H[k][i] * v[kk]
1226 v[i+1].axpy(-H[kk][i], v[kk]);
1227 }
1228 H[i+1][i] = _sp->norm(v[i+1]);
1229 if(Simd::allTrue(abs(H[i+1][i]) < EPSILON))
1230 DUNE_THROW(SolverAbort, "breakdown in fGMRes - |w| (-> "
1231 << w[i] << ") == 0.0 after "
1232 << j << " iterations");
1233
1234 // v[i+1] = w*1/H[i+1][i]
1235 v[i+1] *= real_type(1.0)/H[i+1][i];
1236
1237 // update QR factorization
1238 for(k=0; k<i; k++)
1239 this->applyPlaneRotation(H[k][i],H[k+1][i],cs[k],sn[k]);
1240
1241 // compute new givens rotation
1242 this->generatePlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
1243
1244 // finish updating QR factorization
1245 this->applyPlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
1246 this->applyPlaneRotation(s[i],s[i+1],cs[i],sn[i]);
1247
1248 // norm of the residual is the last component of vector s
1249 using std::abs;
1250 norm = abs(s[i+1]);
1251 iteration.step(j, norm);
1252 } // end inner for loop
1253
1254 // calculate update vector
1255 tmp = 0.0;
1256 this->update(tmp, i, H, s, w);
1257 // and update current iterate
1258 x += tmp;
1259
1260 // restart fGMRes if convergence was not achieved,
1261 // i.e. linear residual has not reached desired reduction
1262 // and if still j < _maxit (do not restart on last iteration)
1263 if( res.converged != true && j < _maxit)
1264 {
1265 if (_verbose > 0)
1266 std::cout << "=== fGMRes::restart" << std::endl;
1267 // get rhs
1268 v[0] = b;
1269 // calculate new defect
1270 _op->applyscaleadd(-1.0, x,v[0]); // b -= Ax;
1271 // calculate preconditioned defect
1272 norm = _sp->norm(v[0]); // update the residual norm
1273 }
1274
1275 } // end outer while loop
1276
1277 // post-process preconditioner
1278 _prec->post(x);
1279 }
1280
1281private:
1282 using RestartedGMResSolver<X,Y>::_op;
1283 using RestartedGMResSolver<X,Y>::_prec;
1284 using RestartedGMResSolver<X,Y>::_sp;
1285 using RestartedGMResSolver<X,Y>::_reduction;
1286 using RestartedGMResSolver<X,Y>::_maxit;
1287 using RestartedGMResSolver<X,Y>::_verbose;
1288 using RestartedGMResSolver<X,Y>::_restart;
1289 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1290 };
1291 DUNE_REGISTER_SOLVER("restartedflexiblegmressolver", defaultIterativeSolverCreator<Dune::RestartedFlexibleGMResSolver>());
1292
1306 template<class X>
1308 {
1309 public:
1310 using typename IterativeSolver<X,X>::domain_type;
1311 using typename IterativeSolver<X,X>::range_type;
1312 using typename IterativeSolver<X,X>::field_type;
1313 using typename IterativeSolver<X,X>::real_type;
1314
1315 private:
1317
1319 using fAlloc = ReboundAllocatorType<X,field_type>;
1320
1321 public:
1322
1323 // don't shadow four-argument version of apply defined in the base class
1324 using IterativeSolver<X,X>::apply;
1325
1332 GeneralizedPCGSolver (const LinearOperator<X,X>& op, Preconditioner<X,X>& prec, scalar_real_type reduction, int maxit, int verbose, int restart = 10) :
1333 IterativeSolver<X,X>::IterativeSolver(op,prec,reduction,maxit,verbose),
1334 _restart(restart)
1335 {}
1336
1344 GeneralizedPCGSolver (const LinearOperator<X,X>& op, const ScalarProduct<X>& sp, Preconditioner<X,X>& prec, scalar_real_type reduction, int maxit, int verbose, int restart = 10) :
1345 IterativeSolver<X,X>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
1346 _restart(restart)
1347 {}
1348
1349
1362 GeneralizedPCGSolver (std::shared_ptr<const LinearOperator<X,X> > op, std::shared_ptr<Preconditioner<X,X> > prec, const ParameterTree& configuration) :
1363 IterativeSolver<X,X>::IterativeSolver(op,prec,configuration),
1364 _restart(configuration.get<int>("restart"))
1365 {}
1366
1367 GeneralizedPCGSolver (std::shared_ptr<const LinearOperator<X,X> > op, std::shared_ptr<const ScalarProduct<X> > sp, std::shared_ptr<Preconditioner<X,X> > prec, const ParameterTree& configuration) :
1368 IterativeSolver<X,X>::IterativeSolver(op,sp,prec,configuration),
1369 _restart(configuration.get<int>("restart"))
1370 {}
1377 GeneralizedPCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1378 std::shared_ptr<const ScalarProduct<X>> sp,
1379 std::shared_ptr<Preconditioner<X,X>> prec,
1380 scalar_real_type reduction, int maxit, int verbose,
1381 int restart = 10) :
1382 IterativeSolver<X,X>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
1383 _restart(restart)
1384 {}
1385
1391 void apply (X& x, X& b, InverseOperatorResult& res) override
1392 {
1393 Iteration iteration(*this, res);
1394 _prec->pre(x,b); // prepare preconditioner
1395 _op->applyscaleadd(-1,x,b); // overwrite b with defect
1396
1397 std::vector<std::shared_ptr<X> > p(_restart);
1398 std::vector<field_type,fAlloc> pp(_restart);
1399 X q(x); // a temporary vector
1400 X prec_res(x); // a temporary vector for preconditioner output
1401
1402 p[0].reset(new X(x));
1403
1404 real_type def = _sp->norm(b); // compute norm
1405 if(iteration.step(0, def)){
1406 _prec->post(x);
1407 return;
1408 }
1409 // some local variables
1410 field_type rho, lambda;
1411
1412 int i=0;
1413 // determine initial search direction
1414 *(p[0]) = 0; // clear correction
1415 _prec->apply(*(p[0]),b); // apply preconditioner
1416 rho = _sp->dot(*(p[0]),b); // orthogonalization
1417 _op->apply(*(p[0]),q); // q=Ap
1418 pp[0] = _sp->dot(*(p[0]),q); // scalar product
1419 lambda = rho/pp[0]; // minimization
1420 x.axpy(lambda,*(p[0])); // update solution
1421 b.axpy(-lambda,q); // update defect
1422
1423 // convergence test
1424 def=_sp->norm(b); // comp defect norm
1425 ++i;
1426 if(iteration.step(i, def)){
1427 _prec->post(x);
1428 return;
1429 }
1430
1431 while(i<_maxit) {
1432 // the loop
1433 int end=std::min(_restart, _maxit-i+1);
1434 for (int ii = 1; ii < end; ++ii)
1435 {
1436 //std::cout<<" ii="<<ii<<" i="<<i<<std::endl;
1437 // compute next conjugate direction
1438 prec_res = 0; // clear correction
1439 _prec->apply(prec_res,b); // apply preconditioner
1440
1441 p[ii].reset(new X(prec_res));
1442 _op->apply(prec_res, q);
1443
1444 for(int j=0; j<ii; ++j) {
1445 rho =_sp->dot(q,*(p[j]))/pp[j];
1446 p[ii]->axpy(-rho, *(p[j]));
1447 }
1448
1449 // minimize in given search direction
1450 _op->apply(*(p[ii]),q); // q=Ap
1451 pp[ii] = _sp->dot(*(p[ii]),q); // scalar product
1452 rho = _sp->dot(*(p[ii]),b); // orthogonalization
1453 lambda = rho/pp[ii]; // minimization
1454 x.axpy(lambda,*(p[ii])); // update solution
1455 b.axpy(-lambda,q); // update defect
1456
1457 // convergence test
1458 def = _sp->norm(b); // comp defect norm
1459
1460 ++i;
1461 iteration.step(i, def);
1462 }
1463 if(res.converged)
1464 break;
1465 if(end==_restart) {
1466 *(p[0])=*(p[_restart-1]);
1467 pp[0]=pp[_restart-1];
1468 }
1469 }
1470
1471 // postprocess preconditioner
1472 _prec->post(x);
1473
1474 }
1475
1476 private:
1477 using IterativeSolver<X,X>::_op;
1478 using IterativeSolver<X,X>::_prec;
1479 using IterativeSolver<X,X>::_sp;
1480 using IterativeSolver<X,X>::_reduction;
1481 using IterativeSolver<X,X>::_maxit;
1482 using IterativeSolver<X,X>::_verbose;
1483 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1484 int _restart;
1485 };
1486 DUNE_REGISTER_SOLVER("generalizedpcgsolver", defaultIterativeSolverCreator<Dune::GeneralizedPCGSolver>());
1487
1499 template<class X>
1501 public:
1502 using typename IterativeSolver<X,X>::domain_type;
1503 using typename IterativeSolver<X,X>::range_type;
1504 using typename IterativeSolver<X,X>::field_type;
1505 using typename IterativeSolver<X,X>::real_type;
1506
1507 private:
1509
1510 public:
1511 // don't shadow four-argument version of apply defined in the base class
1512 using IterativeSolver<X,X>::apply;
1519 scalar_real_type reduction, int maxit, int verbose, int mmax = 10) : IterativeSolver<X,X>(op, prec, reduction, maxit, verbose), _mmax(mmax)
1520 {
1521 }
1522
1529 scalar_real_type reduction, int maxit, int verbose, int mmax = 10) : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose), _mmax(mmax)
1530 {
1531 }
1532
1538 RestartedFCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1539 std::shared_ptr<const ScalarProduct<X>> sp,
1540 std::shared_ptr<Preconditioner<X,X>> prec,
1541 scalar_real_type reduction, int maxit, int verbose,
1542 int mmax = 10)
1543 : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose), _mmax(mmax)
1544 {}
1545
1558 RestartedFCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1559 std::shared_ptr<Preconditioner<X,X>> prec,
1560 const ParameterTree& configuration)
1561 : IterativeSolver<X,X>(op, prec, configuration), _mmax(configuration.get("mmax", 10))
1562 {}
1563
1564 RestartedFCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1565 std::shared_ptr<const ScalarProduct<X>> sp,
1566 std::shared_ptr<Preconditioner<X,X>> prec,
1567 const ParameterTree& config)
1568 : IterativeSolver<X,X>(op, sp, prec, config), _mmax(config.get("mmax", 10))
1569 {}
1570
1583 void apply (X& x, X& b, InverseOperatorResult& res) override
1584 {
1585 using rAlloc = ReboundAllocatorType<X,field_type>;
1586 res.clear();
1587 Iteration iteration(*this,res);
1588 _prec->pre(x,b); // prepare preconditioner
1589 _op->applyscaleadd(-1,x,b); // overwrite b with defect
1590
1591 //arrays for interim values:
1592 std::vector<X> d(_mmax+1, x); // array for directions
1593 std::vector<X> Ad(_mmax+1, x); // array for Ad[i]
1594 std::vector<field_type,rAlloc> ddotAd(_mmax+1,0); // array for <d[i],Ad[i]>
1595 X w(x);
1596
1597 real_type def = _sp->norm(b); // compute norm
1598 if(iteration.step(0, def)){
1599 _prec->post(x);
1600 return;
1601 }
1602
1603 // some local variables
1604 field_type alpha;
1605
1606 // the loop
1607 int i=1;
1608 int i_bounded=0;
1609 while(i<=_maxit && !res.converged) {
1610 for (; i_bounded <= _mmax && i<= _maxit; i_bounded++) {
1611 d[i_bounded] = 0; // reset search direction
1612 _prec->apply(d[i_bounded], b); // apply preconditioner
1613 w = d[i_bounded]; // copy of current d[i]
1614 // orthogonalization with previous directions
1615 orthogonalizations(i_bounded,Ad,w,ddotAd,d);
1616
1617 //saving interim values for future calculating
1618 _op->apply(d[i_bounded], Ad[i_bounded]); // save Ad[i]
1619 ddotAd[i_bounded]=_sp->dot(d[i_bounded],Ad[i_bounded]); // save <d[i],Ad[i]>
1620 alpha = _sp->dot(d[i_bounded], b)/ddotAd[i_bounded]; // <d[i],b>/<d[i],Ad[i]>
1621
1622 //update solution and defect
1623 x.axpy(alpha, d[i_bounded]);
1624 b.axpy(-alpha, Ad[i_bounded]);
1625
1626 // convergence test
1627 def = _sp->norm(b); // comp defect norm
1628
1629 iteration.step(i, def);
1630 i++;
1631 }
1632 //restart: exchange first and last stored values
1633 cycle(Ad,d,ddotAd,i_bounded);
1634 }
1635
1636 //correct i which is wrong if convergence was not achieved.
1637 i=std::min(_maxit,i);
1638
1639 _prec->post(x); // postprocess preconditioner
1640 }
1641
1642 private:
1643 //This function is called every iteration to orthogonalize against the last search directions
1644 virtual void orthogonalizations(const int& i_bounded,const std::vector<X>& Ad, const X& w, const std::vector<field_type,ReboundAllocatorType<X,field_type>>& ddotAd,std::vector<X>& d) {
1645 // The RestartedFCGSolver uses only values with lower array index;
1646 for (int k = 0; k < i_bounded; k++) {
1647 d[i_bounded].axpy(-_sp->dot(Ad[k], w) / ddotAd[k], d[k]); // d[i] -= <<Ad[k],w>/<d[k],Ad[k]>>d[k]
1648 }
1649 }
1650
1651 // This function is called every mmax iterations to handle limited array sizes.
1652 virtual void cycle(std::vector<X>& Ad,std::vector<X>& d,std::vector<field_type,ReboundAllocatorType<X,field_type> >& ddotAd,int& i_bounded) {
1653 // Reset loop index and exchange the first and last arrays
1654 i_bounded = 1;
1655 std::swap(Ad[0], Ad[_mmax]);
1656 std::swap(d[0], d[_mmax]);
1657 std::swap(ddotAd[0], ddotAd[_mmax]);
1658 }
1659
1660 protected:
1661 int _mmax;
1662 using IterativeSolver<X,X>::_op;
1663 using IterativeSolver<X,X>::_prec;
1664 using IterativeSolver<X,X>::_sp;
1665 using IterativeSolver<X,X>::_reduction;
1666 using IterativeSolver<X,X>::_maxit;
1667 using IterativeSolver<X,X>::_verbose;
1668 using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1669 };
1670 DUNE_REGISTER_SOLVER("restartedfcgsolver", defaultIterativeSolverCreator<Dune::RestartedFCGSolver>());
1671
1678 template<class X>
1680 public:
1682 using typename RestartedFCGSolver<X>::range_type;
1683 using typename RestartedFCGSolver<X>::field_type;
1684 using typename RestartedFCGSolver<X>::real_type;
1685
1686 // copy base class constructors
1688
1689 // don't shadow four-argument version of apply defined in the base class
1691
1692 // just a minor part of the RestartedFCGSolver apply method will be modified
1693 void apply (X& x, X& b, InverseOperatorResult& res) override
1694 {
1695 // reset limiter of orthogonalization loop
1696 _k_limit = 0;
1697 this->RestartedFCGSolver<X>::apply(x,b,res);
1698 };
1699
1700 private:
1701 // This function is called every iteration to orthogonalize against the last search directions.
1702 void orthogonalizations(const int& i_bounded,const std::vector<X>& Ad, const X& w, const std::vector<field_type,ReboundAllocatorType<X,field_type>>& ddotAd,std::vector<X>& d) override {
1703 // This FCGSolver uses values with higher array indexes too, if existent.
1704 for (int k = 0; k < _k_limit; k++) {
1705 if(i_bounded!=k)
1706 d[i_bounded].axpy(-_sp->dot(Ad[k], w) / ddotAd[k], d[k]); // d[i] -= <<Ad[k],w>/<d[k],Ad[k]>>d[k]
1707 }
1708 // The loop limit increase, if array is not completely filled.
1709 if(_k_limit<=i_bounded)
1710 _k_limit++;
1711
1712 };
1713
1714 // This function is called every mmax iterations to handle limited array sizes.
1715 void cycle(std::vector<X>& Ad, [[maybe_unused]] std::vector<X>& d, [[maybe_unused]] std::vector<field_type,ReboundAllocatorType<X,field_type> >& ddotAd,int& i_bounded) override {
1716 // Only the loop index i_bounded return to 0, if it reached mmax.
1717 i_bounded = 0;
1718 // Now all arrays are filled and the loop in void orthogonalizations can use the whole arrays.
1719 _k_limit = Ad.size();
1720 };
1721
1722 int _k_limit = 0;
1723
1724 protected:
1725 using RestartedFCGSolver<X>::_mmax;
1726 using RestartedFCGSolver<X>::_op;
1727 using RestartedFCGSolver<X>::_prec;
1728 using RestartedFCGSolver<X>::_sp;
1729 using RestartedFCGSolver<X>::_reduction;
1730 using RestartedFCGSolver<X>::_maxit;
1731 using RestartedFCGSolver<X>::_verbose;
1732 };
1733 DUNE_REGISTER_SOLVER("completefcgsolver", defaultIterativeSolverCreator<Dune::CompleteFCGSolver>());
1735} // end namespace
1736
1737#endif
Implementation of the BCRSMatrix class.
Wrapper to use a range of ARPACK++ eigenvalue solvers.
Definition: arpackpp.hh:245
void computeSymMaxMagnitude(const Real &epsilon, BlockVector &x, Real &lambda) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation lambda of its ...
Definition: arpackpp.hh:289
void computeSymMinMagnitude(const Real &epsilon, BlockVector &x, Real &lambda) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation lambda of its ...
Definition: arpackpp.hh:391
A sparse block matrix with compressed row storage.
Definition: bcrsmatrix.hh:467
@ row_wise
Build in a row-wise manner.
Definition: bcrsmatrix.hh:518
CreateIterator createend()
get create iterator pointing to one after the last block
Definition: bcrsmatrix.hh:1103
CreateIterator createbegin()
get initial create iterator
Definition: bcrsmatrix.hh:1097
size_type N() const
number of rows (counted in blocks)
Definition: bcrsmatrix.hh:2004
Bi-conjugate Gradient Stabilized (BiCG-STAB)
Definition: solvers.hh:420
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:440
A vector of blocks with memory management.
Definition: bvector.hh:392
conjugate gradient method
Definition: solvers.hh:193
CGSolver(std::shared_ptr< const LinearOperator< X, X > > op, std::shared_ptr< ScalarProduct< X > > sp, std::shared_ptr< Preconditioner< X, X > > prec, scalar_real_type reduction, int maxit, int verbose, bool condition_estimate)
Constructor to initialize a CG solver.
Definition: solvers.hh:257
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:280
CGSolver(const LinearOperator< X, X > &op, const ScalarProduct< X > &sp, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose, bool condition_estimate)
Constructor to initialize a CG solver.
Definition: solvers.hh:239
CGSolver(const LinearOperator< X, X > &op, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose, bool condition_estimate)
Constructor to initialize a CG solver.
Definition: solvers.hh:222
Complete flexible conjugate gradient method.
Definition: solvers.hh:1679
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1693
Generalized preconditioned conjugate gradient solver.
Definition: solvers.hh:1308
GeneralizedPCGSolver(const LinearOperator< X, X > &op, const ScalarProduct< X > &sp, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose, int restart=10)
Set up nonlinear preconditioned conjugate gradient solver.
Definition: solvers.hh:1344
GeneralizedPCGSolver(const LinearOperator< X, X > &op, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose, int restart=10)
Set up nonlinear preconditioned conjugate gradient solver.
Definition: solvers.hh:1332
GeneralizedPCGSolver(std::shared_ptr< const LinearOperator< X, X > > op, std::shared_ptr< Preconditioner< X, X > > prec, const ParameterTree &configuration)
Set up nonlinear preconditioned conjugate gradient solver.
Definition: solvers.hh:1362
GeneralizedPCGSolver(std::shared_ptr< const LinearOperator< X, X > > op, std::shared_ptr< const ScalarProduct< X > > sp, std::shared_ptr< Preconditioner< X, X > > prec, scalar_real_type reduction, int maxit, int verbose, int restart=10)
Set up nonlinear preconditioned conjugate gradient solver.
Definition: solvers.hh:1377
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1391
gradient method
Definition: solvers.hh:124
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:142
Simd::Scalar< real_type > scalar_real_type
scalar type underlying the field_type
Definition: solver.hh:116
Y range_type
Type of the range of the operator to be inverted.
Definition: solver.hh:107
X domain_type
Type of the domain of the operator to be inverted.
Definition: solver.hh:104
X::field_type field_type
The field type of the operator.
Definition: solver.hh:110
FieldTraits< field_type >::real_type real_type
The real type of the field type (is the same if using real numbers, but differs for std::complex)
Definition: solver.hh:113
Base class for all implementations of iterative solvers.
Definition: solver.hh:205
IterativeSolver(const LinearOperator< X, X > &op, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose)
General constructor to initialize an iterative solver.
Definition: solver.hh:232
Preconditioned loop solver.
Definition: solvers.hh:59
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator,.
Definition: solvers.hh:73
Minimal Residual Method (MINRES)
Definition: solvers.hh:610
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:628
Hierarchical structure of string parameters.
Definition: parametertree.hh:37
Accelerated flexible conjugate gradient method.
Definition: solvers.hh:1500
RestartedFCGSolver(const LinearOperator< X, X > &op, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose, int mmax=10)
Constructor to initialize a RestartedFCG solver.
Definition: solvers.hh:1518
RestartedFCGSolver(std::shared_ptr< const LinearOperator< X, X > > op, std::shared_ptr< const ScalarProduct< X > > sp, std::shared_ptr< Preconditioner< X, X > > prec, scalar_real_type reduction, int maxit, int verbose, int mmax=10)
Constructor to initialize a RestartedFCG solver.
Definition: solvers.hh:1538
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1583
RestartedFCGSolver(std::shared_ptr< const LinearOperator< X, X > > op, std::shared_ptr< Preconditioner< X, X > > prec, const ParameterTree &configuration)
Constructor to initialize a RestartedFCG solver.
Definition: solvers.hh:1558
RestartedFCGSolver(const LinearOperator< X, X > &op, const ScalarProduct< X > &sp, Preconditioner< X, X > &prec, scalar_real_type reduction, int maxit, int verbose, int mmax=10)
Constructor to initialize a RestartedFCG solver.
Definition: solvers.hh:1528
implements the Flexible Generalized Minimal Residual (FGMRes) method (right preconditioned)
Definition: solvers.hh:1140
void apply(X &x, Y &b, double reduction, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1170
implements the Generalized Minimal Residual (GMRes) method
Definition: solvers.hh:828
RestartedGMResSolver(std::shared_ptr< const LinearOperator< X, Y > > op, std::shared_ptr< Preconditioner< X, X > > prec, const ParameterTree &configuration)
Constructor.
Definition: solvers.hh:879
void apply(X &x, Y &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:911
ReboundAllocatorType< X, field_type > fAlloc
field_type Allocator retrieved from domain type
Definition: solvers.hh:839
ReboundAllocatorType< X, real_type > rAlloc
real_type Allocator retrieved from domain type
Definition: solvers.hh:841
RestartedGMResSolver(const LinearOperator< X, Y > &op, Preconditioner< X, Y > &prec, scalar_real_type reduction, int restart, int maxit, int verbose)
Set up RestartedGMResSolver solver.
Definition: solvers.hh:851
RestartedGMResSolver(const LinearOperator< X, Y > &op, const ScalarProduct< X > &sp, Preconditioner< X, Y > &prec, scalar_real_type reduction, int restart, int maxit, int verbose)
Set up RestartedGMResSolver solver.
Definition: solvers.hh:862
void apply(X &x, Y &b, double reduction, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:924
RestartedGMResSolver(std::shared_ptr< const LinearOperator< X, Y > > op, std::shared_ptr< const ScalarProduct< X > > sp, std::shared_ptr< Preconditioner< X, Y > > prec, scalar_real_type reduction, int restart, int maxit, int verbose)
Set up RestartedGMResSolver solver.
Definition: solvers.hh:895
Base class for scalar product and norm computation.
Definition: scalarproducts.hh:52
Thrown when a solver aborts due to some problem.
Definition: istlexception.hh:46
A few common exception classes.
IO interface of the SIMD abstraction.
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:485
constexpr auto min
Function object that returns the smaller of the given values.
Definition: hybridutilities.hh:507
V cond(M &&mask, const V &ifTrue, const V &ifFalse)
Like the ?: operator.
Definition: interface.hh:386
auto io(const V &v)
construct a stream inserter
Definition: io.hh:106
bool allTrue(const Mask &mask)
Whether all entries are true
Definition: interface.hh:439
auto max(const V &v1, const V &v2)
The binary maximum value over two simd objects.
Definition: interface.hh:409
typename Overloads::ScalarType< std::decay_t< V > >::type Scalar
Element type of some SIMD type.
Definition: interface.hh:235
Some useful basic math stuff.
Dune namespace.
Definition: alignedallocator.hh:13
constexpr auto get(std::integer_sequence< T, II... >, std::integral_constant< std::size_t, pos >={})
Return the entry at position pos of the given sequence.
Definition: integersequence.hh:22
Define general, extensible interface for operators. The available implementation wraps a matrix.
Define base class for scalar product and norm.
Include file for users of the SIMD abstraction layer.
Define general, extensible interface for inverse operators.
Statistics about the application of an inverse operator.
Definition: solver.hh:50
double condition_estimate
Estimate of condition number.
Definition: solver.hh:81
void clear()
Resets all data.
Definition: solver.hh:58
bool converged
True if convergence criterion has been met.
Definition: solver.hh:75
A simple timing class.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Nov 2, 23:43, 2025)