dune-istl  2.11
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 
17 #include <dune/common/exceptions.hh>
18 #include <dune/common/math.hh>
19 #include <dune/common/simd/io.hh>
20 #include <dune/common/simd/simd.hh>
21 #include <dune/common/std/type_traits.hh>
22 #include <dune/common/timer.hh>
23 
24 #include <dune/istl/allocator.hh>
25 #include <dune/istl/bcrsmatrix.hh>
28 #include <dune/istl/operators.hh>
31 #include <dune/istl/solver.hh>
33 
34 namespace Dune {
46  //=====================================================================
47  // Implementation of this interface
48  //=====================================================================
49 
58  template<class X>
59  class LoopSolver : public IterativeSolver<X,X> {
60  public:
61  using typename IterativeSolver<X,X>::domain_type;
62  using typename IterativeSolver<X,X>::range_type;
63  using typename IterativeSolver<X,X>::field_type;
64  using typename IterativeSolver<X,X>::real_type;
65 
66  // copy base class constructors
68 
69  // don't shadow four-argument version of apply defined in the base class
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:
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:
126  using typename IterativeSolver<X,X>::domain_type;
127  using typename IterativeSolver<X,X>::range_type;
128  using typename IterativeSolver<X,X>::field_type;
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
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:
188  };
189  DUNE_REGISTER_SOLVER("gradientsolver", defaultIterativeSolverCreator<Dune::GradientSolver>());
190 
192  template<class X>
193  class CGSolver : public IterativeSolver<X,X> {
194  public:
195  using typename IterativeSolver<X,X>::domain_type;
196  using typename IterativeSolver<X,X>::range_type;
197  using typename IterativeSolver<X,X>::field_type;
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
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 
351  COND_MAT T(i, i, COND_MAT::row_wise);
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:
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:
422  using typename IterativeSolver<X,X>::domain_type;
423  using typename IterativeSolver<X,X>::range_type;
424  using typename IterativeSolver<X,X>::field_type;
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
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:
598  template<class CountType>
600  };
601  DUNE_REGISTER_SOLVER("bicgstabsolver", defaultIterativeSolverCreator<Dune::BiCGSTABSolver>());
602 
609  template<class X>
610  class MINRESSolver : public IterativeSolver<X,X> {
611  public:
612  using typename IterativeSolver<X,X>::domain_type;
613  using typename IterativeSolver<X,X>::range_type;
614  using typename IterativeSolver<X,X>::field_type;
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
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:
810  };
811  DUNE_REGISTER_SOLVER("minressolver", defaultIterativeSolverCreator<Dune::MINRESSolver>());
812 
826  template<class X, class Y=X, class F = Y>
828  {
829  public:
830  using typename IterativeSolver<X,Y>::domain_type;
831  using typename IterativeSolver<X,Y>::range_type;
832  using typename IterativeSolver<X,Y>::field_type;
833  using typename IterativeSolver<X,Y>::real_type;
834 
835  protected:
837 
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))
983  DUNE_THROW(SolverAbort,
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
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
1108  {
1109  field_type temp = cs * dx + sn * dy;
1110  dy = -conjugate(sn) * dx + cs * dy;
1111  dx = temp;
1112  }
1113 
1122  };
1123  DUNE_REGISTER_SOLVER("restartedgmressolver", defaultIterativeSolverCreator<Dune::RestartedGMResSolver>());
1124 
1138  template<class X, class Y=X, class F = Y>
1140  {
1141  public:
1145  using typename RestartedGMResSolver<X,Y>::real_type;
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
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 
1281 private:
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
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:
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>
1500  class RestartedFCGSolver : public IterativeSolver<X,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
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;
1669  };
1670  DUNE_REGISTER_SOLVER("restartedfcgsolver", defaultIterativeSolverCreator<Dune::RestartedFCGSolver>());
1671 
1678  template<class X>
1680  public:
1681  using typename RestartedFCGSolver<X>::domain_type;
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:
1732  };
1733  DUNE_REGISTER_SOLVER("completefcgsolver", defaultIterativeSolverCreator<Dune::CompleteFCGSolver>());
1735 } // end namespace
1736 
1737 #endif
Base class for scalar product and norm computation.
Definition: scalarproducts.hh:52
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
typename IterativeSolver< X, X >::template Iteration< unsigned int > Iteration
Definition: solvers.hh:187
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
A linear operator.
Definition: operators.hh:68
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
void generatePlaneRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
Definition: solvers.hh:1074
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
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
Wrapper to use a range of ARPACK++ eigenvalue solvers.
Definition: arpackpp.hh:244
Minimal Residual Method (MINRES)
Definition: solvers.hh:610
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
gradient method
Definition: solvers.hh:124
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
Define base class for scalar product and norm.
A sparse block matrix with compressed row storage.
Definition: bcrsmatrix.hh:466
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:142
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
Statistics about the application of an inverse operator.
Definition: solver.hh:49
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:280
Complete flexible conjugate gradient method.
Definition: solvers.hh:1679
implements the Flexible Generalized Minimal Residual (FGMRes) method (right preconditioned) ...
Definition: solvers.hh:1139
typename IterativeSolver< X, X >::template Iteration< unsigned int > Iteration
Definition: solvers.hh:1120
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1391
void clear()
Resets all data.
Definition: solver.hh:58
std::shared_ptr< const LinearOperator< X, X > > _op
Definition: solver.hh:506
Bi-conjugate Gradient Stabilized (BiCG-STAB)
Definition: solvers.hh:420
typename IterativeSolver< X, X >::template Iteration< unsigned int > Iteration
Definition: solvers.hh:413
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
size_type N() const
number of rows (counted in blocks)
Definition: bcrsmatrix.hh:2004
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
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
void applyPlaneRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
Definition: solvers.hh:1107
Base class for all implementations of iterative solvers.
Definition: solver.hh:205
Accelerated flexible conjugate gradient method.
Definition: solvers.hh:1500
RestartedFCGSolver(std::shared_ptr< const LinearOperator< X, X >> op, std::shared_ptr< const ScalarProduct< X >> sp, std::shared_ptr< Preconditioner< X, X >> prec, const ParameterTree &config)
Definition: solvers.hh:1564
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1693
X::field_type field_type
The field type of the operator.
Definition: solver.hh:110
void update(X &w, int i, const std::vector< std::vector< field_type, fAlloc > > &H, const std::vector< field_type, fAlloc > &s, const std::vector< X > &v)
Definition: solvers.hh:1040
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)
Definition: solvers.hh:884
DUNE_REGISTER_SOLVER("cholmod", [](auto opTraits, const auto &op, const Dune::ParameterTree &config) -> std::shared_ptr< typename decltype(opTraits)::solver_type > { using OpTraits=decltype(opTraits);using M=typename OpTraits::matrix_type;using D=typename OpTraits::domain_type;if constexpr(OpTraits::isParallel){ if(opTraits.getCommOrThrow(op).communicator().size() > 1) DUNE_THROW(Dune::InvalidStateException, "CholMod works only for sequential operators.");} if constexpr(OpTraits::isAssembled &&(std::is_same_v< typename FieldTraits< D >::field_type, double >||std::is_same_v< typename FieldTraits< D >::field_type, float >)){ const auto &A=opTraits.getAssembledOpOrThrow(op);const M &mat=A->getmat();auto solver=std::make_shared< Dune::Cholmod< D >>();solver->setMatrix(mat);return solver;} DUNE_THROW(UnsupportedType, "Unsupported Type in Cholmod (only double and float supported)");})
void apply(X &x, Y &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:911
typename IterativeSolver< X, X >::template Iteration< unsigned int > Iteration
Definition: solvers.hh:809
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
Implementation of the BCRSMatrix class.
CreateIterator createend()
get create iterator pointing to one after the last block
Definition: bcrsmatrix.hh:1103
void apply(X &x, Y &b, [[maybe_unused]] double reduction, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:924
double condition_estimate
Estimate of condition number.
Definition: solver.hh:81
typename IterativeSolver< X, X >::template Iteration< CountType > Iteration
Definition: solvers.hh:599
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
std::enable_if< std::is_same< field_type, real_type >::value, T >::type conjugate(const T &t)
Definition: solvers.hh:1063
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:440
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, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:628
int _restart
Definition: solvers.hh:1121
std::shared_ptr< Preconditioner< X, X > > _prec
Definition: solver.hh:507
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1583
int _maxit
Definition: solver.hh:510
int _verbose
Definition: solver.hh:511
Build in a row-wise manner.
Definition: bcrsmatrix.hh:518
bool converged
True if convergence criterion has been met.
Definition: solver.hh:75
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
Preconditioned loop solver.
Definition: solvers.hh:59
scalar_real_type _reduction
Definition: solver.hh:509
Y range_type
Type of the range of the operator to be inverted.
Definition: solver.hh:107
typename IterativeSolver< X, X >::template Iteration< unsigned int > Iteration
Definition: solvers.hh:116
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
Simd::Scalar< real_type > scalar_real_type
scalar type underlying the field_type
Definition: solver.hh:116
std::shared_ptr< const ScalarProduct< X > > _sp
Definition: solver.hh:508
implements the Generalized Minimal Residual (GMRes) method
Definition: solvers.hh:827
int _mmax
Definition: solvers.hh:1661
void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator,.
Definition: solvers.hh:73
typename std::allocator_traits< typename AllocatorTraits< T >::type >::template rebind_alloc< X > ReboundAllocatorType
Definition: allocator.hh:37
X domain_type
Type of the domain of the operator to be inverted.
Definition: solver.hh:104
conjugate gradient method
Definition: solvers.hh:193
ReboundAllocatorType< X, field_type > fAlloc
field_type Allocator retrieved from domain type
Definition: solvers.hh:839
std::enable_if_t<!is_complex< T >::value, T > conj(const T &r)
Definition: matrixmarket.hh:776
void apply(X &x, Y &b, [[maybe_unused]] double reduction, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1170
Definition: allocator.hh:11
A vector of blocks with memory management.
Definition: bvector.hh:391
ReboundAllocatorType< X, real_type > rAlloc
real_type Allocator retrieved from domain type
Definition: solvers.hh:841
static constexpr bool enableConditionEstimate
Definition: solvers.hh:208
Define general, extensible interface for operators. The available implementation wraps a matrix...
Thrown when a solver aborts due to some problem.
Definition: istlexception.hh:46
typename IterativeSolver< X, X >::template Iteration< unsigned int > Iteration
Definition: solvers.hh:1668
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
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
Define general, extensible interface for inverse operators.
CreateIterator createbegin()
get initial create iterator
Definition: bcrsmatrix.hh:1097
PropertyMapTypeSelector< Amg::VertexVisitedTag, Amg::PropertiesGraph< G, Amg::VertexProperties, EP, VM, EM > >::Type get([[maybe_unused]] const Amg::VertexVisitedTag &tag, Amg::PropertiesGraph< G, Amg::VertexProperties, EP, VM, EM > &graph)
Definition: dependency.hh:293
std::enable_if<!std::is_same< field_type, real_type >::value, T >::type conjugate(const T &t)
Definition: solvers.hh:1068
Generalized preconditioned conjugate gradient solver.
Definition: solvers.hh:1307
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)
Definition: solvers.hh:1367