DUNE PDELab (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
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.
Implementation of the BCRSMatrix class.
Define general, extensible interface for inverse operators.
#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.
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)