Dune Core Modules (2.9.0)

solvers.hh
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 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>
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>
26 #include <dune/istl/eigenvalue/arpackpp.hh>
27 #include <dune/istl/istlexception.hh>
28 #include <dune/istl/operators.hh>
29 #include <dune/istl/preconditioner.hh>
31 #include <dune/istl/solver.hh>
32 #include <dune/istl/solverregistry.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  virtual void apply (X& x, X& b, InverseOperatorResult& res)
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:
116  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
117  };
118  DUNE_REGISTER_ITERATIVE_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  virtual void apply (X& x, X& b, InverseOperatorResult& res)
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  _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:
187  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
188  };
189  DUNE_REGISTER_ITERATIVE_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 
256  CGSolver (std::shared_ptr<const LinearOperator<X,X>> op, std::shared_ptr<ScalarProduct<X>> sp,
257  std::shared_ptr<Preconditioner<X,X>> prec,
258  scalar_real_type reduction, int maxit, int verbose, bool condition_estimate)
259  : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose),
260  condition_estimate_(condition_estimate)
261  {
262  if (condition_estimate && !(std::is_same<field_type,float>::value || std::is_same<field_type,double>::value)) {
263  condition_estimate_ = false;
264  std::cerr << "WARNING: Condition estimate was disabled. It is only available for double and float field types!" << std::endl;
265  }
266  }
267 
279  virtual void apply (X& x, X& b, InverseOperatorResult& res)
280  {
281  Iteration iteration(*this,res);
282  _prec->pre(x,b); // prepare preconditioner
283 
284  _op->applyscaleadd(-1,x,b); // overwrite b with defect
285 
286  real_type def = _sp->norm(b); // compute norm
287  if(iteration.step(0, def)){
288  _prec->post(x);
289  return;
290  }
291 
292  X p(x); // the search direction
293  X q(x); // a temporary vector
294 
295  // Remember lambda and beta values for condition estimate
296  std::vector<real_type> lambdas(0);
297  std::vector<real_type> betas(0);
298 
299  // some local variables
300  field_type rho,rholast,lambda,alpha,beta;
301 
302  // determine initial search direction
303  p = 0; // clear correction
304  _prec->apply(p,b); // apply preconditioner
305  rholast = _sp->dot(p,b); // orthogonalization
306 
307  // the loop
308  int i=1;
309  for ( ; i<=_maxit; i++ )
310  {
311  // minimize in given search direction p
312  _op->apply(p,q); // q=Ap
313  alpha = _sp->dot(p,q); // scalar product
314  lambda = Simd::cond(def==field_type(0.), field_type(0.), rholast/alpha); // minimization
315  if constexpr (enableConditionEstimate)
316  if (condition_estimate_)
317  lambdas.push_back(std::real(lambda));
318  x.axpy(lambda,p); // update solution
319  b.axpy(-lambda,q); // update defect
320 
321  // convergence test
322  def=_sp->norm(b); // comp defect norm
323  if(iteration.step(i, def))
324  break;
325 
326  // determine new search direction
327  q = 0; // clear correction
328  _prec->apply(q,b); // apply preconditioner
329  rho = _sp->dot(q,b); // orthogonalization
330  beta = Simd::cond(def==field_type(0.), field_type(0.), rho/rholast); // scaling factor
331  if constexpr (enableConditionEstimate)
332  if (condition_estimate_)
333  betas.push_back(std::real(beta));
334  p *= beta; // scale old search direction
335  p += q; // orthogonalization with correction
336  rholast = rho; // remember rho for recurrence
337  }
338 
339  _prec->post(x); // postprocess preconditioner
340 
341  if (condition_estimate_) {
342 #if HAVE_ARPACKPP
343  if constexpr (enableConditionEstimate) {
344  using std::sqrt;
345 
346  // Build T matrix which has extreme eigenvalues approximating
347  // those of the original system
348  // (see Y. Saad, Iterative methods for sparse linear systems)
349 
350  COND_MAT T(i, i, COND_MAT::row_wise);
351 
352  for (auto row = T.createbegin(); row != T.createend(); ++row) {
353  if (row.index() > 0)
354  row.insert(row.index()-1);
355  row.insert(row.index());
356  if (row.index() < T.N() - 1)
357  row.insert(row.index()+1);
358  }
359  for (int row = 0; row < i; ++row) {
360  if (row > 0) {
361  T[row][row-1] = sqrt(betas[row-1]) / lambdas[row-1];
362  }
363 
364  T[row][row] = 1.0 / lambdas[row];
365  if (row > 0) {
366  T[row][row] += betas[row-1] / lambdas[row-1];
367  }
368 
369  if (row < i - 1) {
370  T[row][row+1] = sqrt(betas[row]) / lambdas[row];
371  }
372  }
373 
374  // Compute largest and smallest eigenvalue of T matrix and return as estimate
376 
377  real_type eps = 0.0;
378  COND_VEC eigv;
379  real_type min_eigv, max_eigv;
380  arpack.computeSymMinMagnitude (eps, eigv, min_eigv);
381  arpack.computeSymMaxMagnitude (eps, eigv, max_eigv);
382 
383  res.condition_estimate = max_eigv / min_eigv;
384 
385  if (this->_verbose > 0) {
386  std::cout << "Min eigv estimate: " << Simd::io(min_eigv) << '\n';
387  std::cout << "Max eigv estimate: " << Simd::io(max_eigv) << '\n';
388  std::cout << "Condition estimate: "
389  << Simd::io(max_eigv / min_eigv) << std::endl;
390  }
391  }
392 #else
393  std::cerr << "WARNING: Condition estimate was requested. This requires ARPACK, but ARPACK was not found!" << std::endl;
394 #endif
395  }
396  }
397 
398  private:
399  bool condition_estimate_ = false;
400 
401  // Matrix and vector types used for condition estimate
404 
405  protected:
412  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
413  };
414  DUNE_REGISTER_ITERATIVE_SOLVER("cgsolver", defaultIterativeSolverCreator<Dune::CGSolver>());
415 
416  // Ronald Kriemanns BiCG-STAB implementation from Sumo
418  template<class X>
419  class BiCGSTABSolver : public IterativeSolver<X,X> {
420  public:
421  using typename IterativeSolver<X,X>::domain_type;
422  using typename IterativeSolver<X,X>::range_type;
423  using typename IterativeSolver<X,X>::field_type;
424  using typename IterativeSolver<X,X>::real_type;
425 
426  // copy base class constructors
428 
429  // don't shadow four-argument version of apply defined in the base class
431 
439  virtual void apply (X& x, X& b, InverseOperatorResult& res)
440  {
441  using std::abs;
442  const Simd::Scalar<real_type> EPSILON=1e-80;
443  using std::abs;
444  double it;
445  field_type rho, rho_new, alpha, beta, h, omega;
446  real_type norm;
447 
448  //
449  // get vectors and matrix
450  //
451  X& r=b;
452  X p(x);
453  X v(x);
454  X t(x);
455  X y(x);
456  X rt(x);
457 
458  //
459  // begin iteration
460  //
461 
462  // r = r - Ax; rt = r
463  Iteration<double> iteration(*this,res);
464  _prec->pre(x,r); // prepare preconditioner
465 
466  _op->applyscaleadd(-1,x,r); // overwrite b with defect
467 
468  rt=r;
469 
470  norm = _sp->norm(r);
471  if(iteration.step(0, norm)){
472  _prec->post(x);
473  return;
474  }
475  p=0;
476  v=0;
477 
478  rho = 1;
479  alpha = 1;
480  omega = 1;
481 
482  //
483  // iteration
484  //
485 
486  for (it = 0.5; it < _maxit; it+=.5)
487  {
488  //
489  // preprocess, set vecsizes etc.
490  //
491 
492  // rho_new = < rt , r >
493  rho_new = _sp->dot(rt,r);
494 
495  // look if breakdown occurred
496  if (Simd::allTrue(abs(rho) <= EPSILON))
497  DUNE_THROW(SolverAbort,"breakdown in BiCGSTAB - rho "
498  << Simd::io(rho) << " <= EPSILON " << EPSILON
499  << " after " << it << " iterations");
500  if (Simd::allTrue(abs(omega) <= EPSILON))
501  DUNE_THROW(SolverAbort,"breakdown in BiCGSTAB - omega "
502  << Simd::io(omega) << " <= EPSILON " << EPSILON
503  << " after " << it << " iterations");
504 
505 
506  if (it<1)
507  p = r;
508  else
509  {
510  beta = Simd::cond(norm==field_type(0.),
511  field_type(0.), // no need for orthogonalization if norm is already 0
512  ( rho_new / rho ) * ( alpha / omega ));
513  p.axpy(-omega,v); // p = r + beta (p - omega*v)
514  p *= beta;
515  p += r;
516  }
517 
518  // y = W^-1 * p
519  y = 0;
520  _prec->apply(y,p); // apply preconditioner
521 
522  // v = A * y
523  _op->apply(y,v);
524 
525  // alpha = rho_new / < rt, v >
526  h = _sp->dot(rt,v);
527 
528  if ( Simd::allTrue(abs(h) < EPSILON) )
529  DUNE_THROW(SolverAbort,"abs(h) < EPSILON in BiCGSTAB - abs(h) "
530  << Simd::io(abs(h)) << " < EPSILON " << EPSILON
531  << " after " << it << " iterations");
532 
533  alpha = Simd::cond(norm==field_type(0.),
534  field_type(0.),
535  rho_new / h);
536 
537  // apply first correction to x
538  // x <- x + alpha y
539  x.axpy(alpha,y);
540 
541  // r = r - alpha*v
542  r.axpy(-alpha,v);
543 
544  //
545  // test stop criteria
546  //
547 
548  norm = _sp->norm(r);
549  if(iteration.step(it, norm)){
550  break;
551  }
552 
553  it+=.5;
554 
555  // y = W^-1 * r
556  y = 0;
557  _prec->apply(y,r);
558 
559  // t = A * y
560  _op->apply(y,t);
561 
562  // omega = < t, r > / < t, t >
563  h = _sp->dot(t,t);
564  omega = Simd::cond(norm==field_type(0.),
565  field_type(0.),
566  _sp->dot(t,r)/h);
567 
568  // apply second correction to x
569  // x <- x + omega y
570  x.axpy(omega,y);
571 
572  // r = s - omega*t (remember : r = s)
573  r.axpy(-omega,t);
574 
575  rho = rho_new;
576 
577  //
578  // test stop criteria
579  //
580 
581  norm = _sp->norm(r);
582  if(iteration.step(it, norm)){
583  break;
584  }
585  } // end for
586 
587  _prec->post(x); // postprocess preconditioner
588  }
589 
590  protected:
597  template<class CountType>
598  using Iteration = typename IterativeSolver<X,X>::template Iteration<CountType>;
599  };
600  DUNE_REGISTER_ITERATIVE_SOLVER("bicgstabsolver", defaultIterativeSolverCreator<Dune::BiCGSTABSolver>());
601 
608  template<class X>
609  class MINRESSolver : public IterativeSolver<X,X> {
610  public:
611  using typename IterativeSolver<X,X>::domain_type;
612  using typename IterativeSolver<X,X>::range_type;
613  using typename IterativeSolver<X,X>::field_type;
614  using typename IterativeSolver<X,X>::real_type;
615 
616  // copy base class constructors
618 
619  // don't shadow four-argument version of apply defined in the base class
621 
627  virtual void apply (X& x, X& b, InverseOperatorResult& res)
628  {
629  using std::sqrt;
630  using std::abs;
631  Iteration iteration(*this, res);
632  // prepare preconditioner
633  _prec->pre(x,b);
634 
635  // overwrite rhs with defect
636  _op->applyscaleadd(-1.0,x,b); // b -= Ax
637 
638  // some temporary vectors
639  X z(b), dummy(b);
640  z = 0.0;
641 
642  // calculate preconditioned defect
643  _prec->apply(z,b); // r = W^-1 (b - Ax)
644  real_type def = _sp->norm(z);
645  if (iteration.step(0, def)){
646  _prec->post(x);
647  return;
648  }
649 
650  // recurrence coefficients as computed in Lanczos algorithm
651  field_type alpha, beta;
652  // diagonal entries of givens rotation
653  std::array<real_type,2> c{{0.0,0.0}};
654  // off-diagonal entries of givens rotation
655  std::array<field_type,2> s{{0.0,0.0}};
656 
657  // recurrence coefficients (column k of tridiag matrix T_k)
658  std::array<field_type,3> T{{0.0,0.0,0.0}};
659 
660  // the rhs vector of the min problem
661  std::array<field_type,2> xi{{1.0,0.0}};
662 
663  // beta is real and positive in exact arithmetic
664  // since it is the norm of the basis vectors (in unpreconditioned case)
665  beta = sqrt(_sp->dot(b,z));
666  field_type beta0 = beta;
667 
668  // the search directions
669  std::array<X,3> p{{b,b,b}};
670  p[0] = 0.0;
671  p[1] = 0.0;
672  p[2] = 0.0;
673 
674  // orthonormal basis vectors (in unpreconditioned case)
675  std::array<X,3> q{{b,b,b}};
676  q[0] = 0.0;
677  q[1] *= Simd::cond(def==field_type(0.),
678  field_type(0.),
679  real_type(1.0)/beta);
680  q[2] = 0.0;
681 
682  z *= Simd::cond(def==field_type(0.),
683  field_type(0.),
684  real_type(1.0)/beta);
685 
686  // the loop
687  int i = 1;
688  for( ; i<=_maxit; i++) {
689 
690  dummy = z;
691  int i1 = i%3,
692  i0 = (i1+2)%3,
693  i2 = (i1+1)%3;
694 
695  // symmetrically preconditioned Lanczos algorithm (see Greenbaum p.121)
696  _op->apply(z,q[i2]); // q[i2] = Az
697  q[i2].axpy(-beta,q[i0]);
698  // alpha is real since it is the diagonal entry of the hermitian tridiagonal matrix
699  // from the Lanczos Algorithm
700  // so the order in the scalar product doesn't matter even for the complex case
701  alpha = _sp->dot(z,q[i2]);
702  q[i2].axpy(-alpha,q[i1]);
703 
704  z = 0.0;
705  _prec->apply(z,q[i2]);
706 
707  // beta is real and positive in exact arithmetic
708  // since it is the norm of the basis vectors (in unpreconditioned case)
709  beta = sqrt(_sp->dot(q[i2],z));
710 
711  q[i2] *= Simd::cond(def==field_type(0.),
712  field_type(0.),
713  real_type(1.0)/beta);
714  z *= Simd::cond(def==field_type(0.),
715  field_type(0.),
716  real_type(1.0)/beta);
717 
718  // QR Factorization of recurrence coefficient matrix
719  // apply previous givens rotations to last column of T
720  T[1] = T[2];
721  if(i>2) {
722  T[0] = s[i%2]*T[1];
723  T[1] = c[i%2]*T[1];
724  }
725  if(i>1) {
726  T[2] = c[(i+1)%2]*alpha - s[(i+1)%2]*T[1];
727  T[1] = c[(i+1)%2]*T[1] + s[(i+1)%2]*alpha;
728  }
729  else
730  T[2] = alpha;
731 
732  // update QR factorization
733  generateGivensRotation(T[2],beta,c[i%2],s[i%2]);
734  // to last column of T_k
735  T[2] = c[i%2]*T[2] + s[i%2]*beta;
736  // and to the rhs xi of the min problem
737  xi[i%2] = -s[i%2]*xi[(i+1)%2];
738  xi[(i+1)%2] *= c[i%2];
739 
740  // compute correction direction
741  p[i2] = dummy;
742  p[i2].axpy(-T[1],p[i1]);
743  p[i2].axpy(-T[0],p[i0]);
744  p[i2] *= real_type(1.0)/T[2];
745 
746  // apply correction/update solution
747  x.axpy(beta0*xi[(i+1)%2],p[i2]);
748 
749  // remember beta_old
750  T[2] = beta;
751 
752  // check for convergence
753  // the last entry in the rhs of the min-problem is the residual
754  def = abs(beta0*xi[i%2]);
755  if(iteration.step(i, def)){
756  break;
757  }
758  } // end for
759 
760  // postprocess preconditioner
761  _prec->post(x);
762  }
763 
764  private:
765 
766  void generateGivensRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
767  {
768  using std::sqrt;
769  using std::abs;
770  using std::max;
771  using std::min;
772  const real_type eps = 1e-15;
773  real_type norm_dx = abs(dx);
774  real_type norm_dy = abs(dy);
775  real_type norm_max = max(norm_dx, norm_dy);
776  real_type norm_min = min(norm_dx, norm_dy);
777  real_type temp = norm_min/norm_max;
778  // we rewrite the code in a vectorizable fashion
779  cs = Simd::cond(norm_dy < eps,
780  real_type(1.0),
781  Simd::cond(norm_dx < eps,
782  real_type(0.0),
783  Simd::cond(norm_dy > norm_dx,
784  real_type(1.0)/sqrt(real_type(1.0) + temp*temp)*temp,
785  real_type(1.0)/sqrt(real_type(1.0) + temp*temp)
786  )));
787  sn = Simd::cond(norm_dy < eps,
788  field_type(0.0),
789  Simd::cond(norm_dx < eps,
790  field_type(1.0),
791  Simd::cond(norm_dy > norm_dx,
792  // dy and dx are real in exact arithmetic
793  // thus dx*dy is real so we can explicitly enforce it
794  field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*dx*dy/norm_dx/norm_dy,
795  // dy and dx is real in exact arithmetic
796  // so we don't have to conjugate both of them
797  field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*dy/dx
798  )));
799  }
800 
801  protected:
802  using IterativeSolver<X,X>::_op;
803  using IterativeSolver<X,X>::_prec;
804  using IterativeSolver<X,X>::_sp;
805  using IterativeSolver<X,X>::_reduction;
806  using IterativeSolver<X,X>::_maxit;
807  using IterativeSolver<X,X>::_verbose;
808  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
809  };
810  DUNE_REGISTER_ITERATIVE_SOLVER("minressolver", defaultIterativeSolverCreator<Dune::MINRESSolver>());
811 
825  template<class X, class Y=X, class F = Y>
827  {
828  public:
829  using typename IterativeSolver<X,Y>::domain_type;
830  using typename IterativeSolver<X,Y>::range_type;
831  using typename IterativeSolver<X,Y>::field_type;
832  using typename IterativeSolver<X,Y>::real_type;
833 
834  protected:
836 
838  using fAlloc = ReboundAllocatorType<X,field_type>;
840  using rAlloc = ReboundAllocatorType<X,real_type>;
841 
842  public:
843 
850  RestartedGMResSolver (const LinearOperator<X,Y>& op, Preconditioner<X,Y>& prec, scalar_real_type reduction, int restart, int maxit, int verbose) :
851  IterativeSolver<X,Y>::IterativeSolver(op,prec,reduction,maxit,verbose),
852  _restart(restart)
853  {}
854 
861  RestartedGMResSolver (const LinearOperator<X,Y>& op, const ScalarProduct<X>& sp, Preconditioner<X,Y>& prec, scalar_real_type reduction, int restart, int maxit, int verbose) :
862  IterativeSolver<X,Y>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
863  _restart(restart)
864  {}
865 
878  RestartedGMResSolver (std::shared_ptr<const LinearOperator<X,Y> > op, std::shared_ptr<Preconditioner<X,X> > prec, const ParameterTree& configuration) :
879  IterativeSolver<X,Y>::IterativeSolver(op,prec,configuration),
880  _restart(configuration.get<int>("restart"))
881  {}
882 
883  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) :
884  IterativeSolver<X,Y>::IterativeSolver(op,sp,prec,configuration),
885  _restart(configuration.get<int>("restart"))
886  {}
887 
894  RestartedGMResSolver (std::shared_ptr<const LinearOperator<X,Y>> op,
895  std::shared_ptr<const ScalarProduct<X>> sp,
896  std::shared_ptr<Preconditioner<X,Y>> prec,
897  scalar_real_type reduction, int restart, int maxit, int verbose) :
898  IterativeSolver<X,Y>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
899  _restart(restart)
900  {}
901 
910  virtual void apply (X& x, Y& b, InverseOperatorResult& res)
911  {
912  apply(x,b,Simd::max(_reduction),res);
913  }
914 
923  virtual void apply (X& x, Y& b, [[maybe_unused]] double reduction, InverseOperatorResult& res)
924  {
925  using std::abs;
926  const Simd::Scalar<real_type> EPSILON = 1e-80;
927  const int m = _restart;
928  real_type norm = 0.0;
929  int j = 1;
930  std::vector<field_type,fAlloc> s(m+1), sn(m);
931  std::vector<real_type,rAlloc> cs(m);
932  // need copy of rhs if GMRes has to be restarted
933  Y b2(b);
934  // helper vector
935  Y w(b);
936  std::vector< std::vector<field_type,fAlloc> > H(m+1,s);
937  std::vector<F> v(m+1,b);
938 
939  Iteration iteration(*this,res);
940 
941  // clear solver statistics and set res.converged to false
942  _prec->pre(x,b);
943 
944  // calculate defect and overwrite rhs with it
945  _op->applyscaleadd(-1.0,x,b); // b -= Ax
946  // calculate preconditioned defect
947  v[0] = 0.0; _prec->apply(v[0],b); // r = W^-1 b
948  norm = _sp->norm(v[0]);
949  if(iteration.step(0, norm)){
950  _prec->post(x);
951  return;
952  }
953 
954  while(j <= _maxit && res.converged != true) {
955 
956  int i = 0;
957  v[0] *= Simd::cond(norm==real_type(0.),
958  real_type(0.),
959  real_type(1.0)/norm);
960  s[0] = norm;
961  for(i=1; i<m+1; i++)
962  s[i] = 0.0;
963 
964  for(i=0; i < m && j <= _maxit && res.converged != true; i++, j++) {
965  w = 0.0;
966  // use v[i+1] as temporary vector
967  v[i+1] = 0.0;
968  // do Arnoldi algorithm
969  _op->apply(v[i],v[i+1]);
970  _prec->apply(w,v[i+1]);
971  for(int k=0; k<i+1; k++) {
972  // notice that _sp->dot(v[k],w) = v[k]\adjoint w
973  // so one has to pay attention to the order
974  // in the scalar product for the complex case
975  // doing the modified Gram-Schmidt algorithm
976  H[k][i] = _sp->dot(v[k],w);
977  // w -= H[k][i] * v[k]
978  w.axpy(-H[k][i],v[k]);
979  }
980  H[i+1][i] = _sp->norm(w);
981  if(Simd::allTrue(abs(H[i+1][i]) < EPSILON))
983  "breakdown in GMRes - |w| == 0.0 after " << j << " iterations");
984 
985  // normalize new vector
986  v[i+1] = w;
987  v[i+1] *= Simd::cond(norm==real_type(0.),
988  field_type(0.),
989  real_type(1.0)/H[i+1][i]);
990 
991  // update QR factorization
992  for(int k=0; k<i; k++)
993  applyPlaneRotation(H[k][i],H[k+1][i],cs[k],sn[k]);
994 
995  // compute new givens rotation
996  generatePlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
997  // finish updating QR factorization
998  applyPlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
999  applyPlaneRotation(s[i],s[i+1],cs[i],sn[i]);
1000 
1001  // norm of the defect is the last component the vector s
1002  norm = abs(s[i+1]);
1003 
1004  iteration.step(j, norm);
1005 
1006  } // end for
1007 
1008  // calculate update vector
1009  w = 0.0;
1010  update(w,i,H,s,v);
1011  // and current iterate
1012  x += w;
1013 
1014  // restart GMRes if convergence was not achieved,
1015  // i.e. linear defect has not reached desired reduction
1016  // and if j < _maxit (do not restart on last iteration)
1017  if( res.converged != true && j < _maxit ) {
1018 
1019  if(_verbose > 0)
1020  std::cout << "=== GMRes::restart" << std::endl;
1021  // get saved rhs
1022  b = b2;
1023  // calculate new defect
1024  _op->applyscaleadd(-1.0,x,b); // b -= Ax;
1025  // calculate preconditioned defect
1026  v[0] = 0.0;
1027  _prec->apply(v[0],b);
1028  norm = _sp->norm(v[0]);
1029  }
1030 
1031  } //end while
1032 
1033  // postprocess preconditioner
1034  _prec->post(x);
1035  }
1036 
1037  protected :
1038 
1039  void update(X& w, int i,
1040  const std::vector<std::vector<field_type,fAlloc> >& H,
1041  const std::vector<field_type,fAlloc>& s,
1042  const std::vector<X>& v) {
1043  // solution vector of the upper triangular system
1044  std::vector<field_type,fAlloc> y(s);
1045 
1046  // backsolve
1047  for(int a=i-1; a>=0; a--) {
1048  field_type rhs(s[a]);
1049  for(int b=a+1; b<i; b++)
1050  rhs -= H[a][b]*y[b];
1051  y[a] = Simd::cond(rhs==field_type(0.),
1052  field_type(0.),
1053  rhs/H[a][a]);
1054 
1055  // compute update on the fly
1056  // w += y[a]*v[a]
1057  w.axpy(y[a],v[a]);
1058  }
1059  }
1060 
1061  template<typename T>
1062  typename std::enable_if<std::is_same<field_type,real_type>::value,T>::type conjugate(const T& t) {
1063  return t;
1064  }
1065 
1066  template<typename T>
1067  typename std::enable_if<!std::is_same<field_type,real_type>::value,T>::type conjugate(const T& t) {
1068  using std::conj;
1069  return conj(t);
1070  }
1071 
1072  void
1073  generatePlaneRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
1074  {
1075  using std::sqrt;
1076  using std::abs;
1077  using std::max;
1078  using std::min;
1079  const real_type eps = 1e-15;
1080  real_type norm_dx = abs(dx);
1081  real_type norm_dy = abs(dy);
1082  real_type norm_max = max(norm_dx, norm_dy);
1083  real_type norm_min = min(norm_dx, norm_dy);
1084  real_type temp = norm_min/norm_max;
1085  // we rewrite the code in a vectorizable fashion
1086  cs = Simd::cond(norm_dy < eps,
1087  real_type(1.0),
1088  Simd::cond(norm_dx < eps,
1089  real_type(0.0),
1090  Simd::cond(norm_dy > norm_dx,
1091  real_type(1.0)/sqrt(real_type(1.0) + temp*temp)*temp,
1092  real_type(1.0)/sqrt(real_type(1.0) + temp*temp)
1093  )));
1094  sn = Simd::cond(norm_dy < eps,
1095  field_type(0.0),
1096  Simd::cond(norm_dx < eps,
1097  field_type(1.0),
1098  Simd::cond(norm_dy > norm_dx,
1099  field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*dx*conjugate(dy)/norm_dx/norm_dy,
1100  field_type(1.0)/sqrt(real_type(1.0) + temp*temp)*conjugate(dy/dx)
1101  )));
1102  }
1103 
1104 
1105  void
1106  applyPlaneRotation(field_type &dx, field_type &dy, real_type &cs, field_type &sn)
1107  {
1108  field_type temp = cs * dx + sn * dy;
1109  dy = -conjugate(sn) * dx + cs * dy;
1110  dx = temp;
1111  }
1112 
1113  using IterativeSolver<X,Y>::_op;
1114  using IterativeSolver<X,Y>::_prec;
1115  using IterativeSolver<X,Y>::_sp;
1116  using IterativeSolver<X,Y>::_reduction;
1117  using IterativeSolver<X,Y>::_maxit;
1118  using IterativeSolver<X,Y>::_verbose;
1119  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1120  int _restart;
1121  };
1122  DUNE_REGISTER_ITERATIVE_SOLVER("restartedgmressolver", defaultIterativeSolverCreator<Dune::RestartedGMResSolver>());
1123 
1137  template<class X, class Y=X, class F = Y>
1139  {
1140  public:
1144  using typename RestartedGMResSolver<X,Y>::real_type;
1145 
1146  private:
1148 
1150  using fAlloc = typename RestartedGMResSolver<X,Y>::fAlloc;
1152  using rAlloc = typename RestartedGMResSolver<X,Y>::rAlloc;
1153 
1154  public:
1155  // copy base class constructors
1157 
1158  // don't shadow four-argument version of apply defined in the base class
1160 
1169  void apply (X& x, Y& b, [[maybe_unused]] double reduction, InverseOperatorResult& res) override
1170  {
1171  using std::abs;
1172  const Simd::Scalar<real_type> EPSILON = 1e-80;
1173  const int m = _restart;
1174  real_type norm = 0.0;
1175  int i, j = 1, k;
1176  std::vector<field_type,fAlloc> s(m+1), sn(m);
1177  std::vector<real_type,rAlloc> cs(m);
1178  // helper vector
1179  Y tmp(b);
1180  std::vector< std::vector<field_type,fAlloc> > H(m+1,s);
1181  std::vector<F> v(m+1,b);
1182  std::vector<X> w(m+1,b);
1183 
1184  Iteration iteration(*this,res);
1185  // setup preconditioner if it does something in pre
1186 
1187  // calculate residual and overwrite a copy of the rhs with it
1188  _prec->pre(x, b);
1189  v[0] = b;
1190  _op->applyscaleadd(-1.0, x, v[0]); // b -= Ax
1191 
1192  norm = _sp->norm(v[0]); // the residual norm
1193  if(iteration.step(0, norm)){
1194  _prec->post(x);
1195  return;
1196  }
1197 
1198  // start iterations
1199  res.converged = false;;
1200  while(j <= _maxit && res.converged != true)
1201  {
1202  v[0] *= (1.0 / norm);
1203  s[0] = norm;
1204  for(i=1; i<m+1; ++i)
1205  s[i] = 0.0;
1206 
1207  // inner loop
1208  for(i=0; i < m && j <= _maxit && res.converged != true; i++, j++)
1209  {
1210  w[i] = 0.0;
1211  // compute wi = M^-1*vi (also called zi)
1212  _prec->apply(w[i], v[i]);
1213  // compute vi = A*wi
1214  // use v[i+1] as temporary vector for w
1215  _op->apply(w[i], v[i+1]);
1216  // do Arnoldi algorithm
1217  for(int kk=0; kk<i+1; kk++)
1218  {
1219  // notice that _sp->dot(v[k],v[i+1]) = v[k]\adjoint v[i+1]
1220  // so one has to pay attention to the order
1221  // in the scalar product for the complex case
1222  // doing the modified Gram-Schmidt algorithm
1223  H[kk][i] = _sp->dot(v[kk],v[i+1]);
1224  // w -= H[k][i] * v[kk]
1225  v[i+1].axpy(-H[kk][i], v[kk]);
1226  }
1227  H[i+1][i] = _sp->norm(v[i+1]);
1228  if(Simd::allTrue(abs(H[i+1][i]) < EPSILON))
1229  DUNE_THROW(SolverAbort, "breakdown in fGMRes - |w| (-> "
1230  << w[i] << ") == 0.0 after "
1231  << j << " iterations");
1232 
1233  // v[i+1] = w*1/H[i+1][i]
1234  v[i+1] *= real_type(1.0)/H[i+1][i];
1235 
1236  // update QR factorization
1237  for(k=0; k<i; k++)
1238  this->applyPlaneRotation(H[k][i],H[k+1][i],cs[k],sn[k]);
1239 
1240  // compute new givens rotation
1241  this->generatePlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
1242 
1243  // finish updating QR factorization
1244  this->applyPlaneRotation(H[i][i],H[i+1][i],cs[i],sn[i]);
1245  this->applyPlaneRotation(s[i],s[i+1],cs[i],sn[i]);
1246 
1247  // norm of the residual is the last component of vector s
1248  using std::abs;
1249  norm = abs(s[i+1]);
1250  iteration.step(j, norm);
1251  } // end inner for loop
1252 
1253  // calculate update vector
1254  tmp = 0.0;
1255  this->update(tmp, i, H, s, w);
1256  // and update current iterate
1257  x += tmp;
1258 
1259  // restart fGMRes if convergence was not achieved,
1260  // i.e. linear residual has not reached desired reduction
1261  // and if still j < _maxit (do not restart on last iteration)
1262  if( res.converged != true && j < _maxit)
1263  {
1264  if (_verbose > 0)
1265  std::cout << "=== fGMRes::restart" << std::endl;
1266  // get rhs
1267  v[0] = b;
1268  // calculate new defect
1269  _op->applyscaleadd(-1.0, x,v[0]); // b -= Ax;
1270  // calculate preconditioned defect
1271  norm = _sp->norm(v[0]); // update the residual norm
1272  }
1273 
1274  } // end outer while loop
1275 
1276  // post-process preconditioner
1277  _prec->post(x);
1278  }
1279 
1280 private:
1288  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1289  };
1290  DUNE_REGISTER_ITERATIVE_SOLVER("restartedflexiblegmressolver", defaultIterativeSolverCreator<Dune::RestartedFlexibleGMResSolver>());
1291 
1305  template<class X>
1307  {
1308  public:
1309  using typename IterativeSolver<X,X>::domain_type;
1310  using typename IterativeSolver<X,X>::range_type;
1311  using typename IterativeSolver<X,X>::field_type;
1312  using typename IterativeSolver<X,X>::real_type;
1313 
1314  private:
1316 
1318  using fAlloc = ReboundAllocatorType<X,field_type>;
1319 
1320  public:
1321 
1322  // don't shadow four-argument version of apply defined in the base class
1324 
1331  GeneralizedPCGSolver (const LinearOperator<X,X>& op, Preconditioner<X,X>& prec, scalar_real_type reduction, int maxit, int verbose, int restart = 10) :
1332  IterativeSolver<X,X>::IterativeSolver(op,prec,reduction,maxit,verbose),
1333  _restart(restart)
1334  {}
1335 
1343  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) :
1344  IterativeSolver<X,X>::IterativeSolver(op,sp,prec,reduction,maxit,verbose),
1345  _restart(restart)
1346  {}
1347 
1348 
1361  GeneralizedPCGSolver (std::shared_ptr<const LinearOperator<X,X> > op, std::shared_ptr<Preconditioner<X,X> > prec, const ParameterTree& configuration) :
1362  IterativeSolver<X,X>::IterativeSolver(op,prec,configuration),
1363  _restart(configuration.get<int>("restart"))
1364  {}
1365 
1366  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) :
1367  IterativeSolver<X,X>::IterativeSolver(op,sp,prec,configuration),
1368  _restart(configuration.get<int>("restart"))
1369  {}
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  virtual void apply (X& x, X& b, InverseOperatorResult& res)
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  int ii=0;
1414  // determine initial search direction
1415  *(p[0]) = 0; // clear correction
1416  _prec->apply(*(p[0]),b); // apply preconditioner
1417  rho = _sp->dot(*(p[0]),b); // orthogonalization
1418  _op->apply(*(p[0]),q); // q=Ap
1419  pp[0] = _sp->dot(*(p[0]),q); // scalar product
1420  lambda = rho/pp[0]; // minimization
1421  x.axpy(lambda,*(p[0])); // update solution
1422  b.axpy(-lambda,q); // update defect
1423 
1424  // convergence test
1425  def=_sp->norm(b); // comp defect norm
1426  ++i;
1427  if(iteration.step(i, def)){
1428  _prec->post(x);
1429  return;
1430  }
1431 
1432  while(i<_maxit) {
1433  // the loop
1434  int end=std::min(_restart, _maxit-i+1);
1435  for (ii=1; ii<end; ++ii )
1436  {
1437  //std::cout<<" ii="<<ii<<" i="<<i<<std::endl;
1438  // compute next conjugate direction
1439  prec_res = 0; // clear correction
1440  _prec->apply(prec_res,b); // apply preconditioner
1441 
1442  p[ii].reset(new X(prec_res));
1443  _op->apply(prec_res, q);
1444 
1445  for(int j=0; j<ii; ++j) {
1446  rho =_sp->dot(q,*(p[j]))/pp[j];
1447  p[ii]->axpy(-rho, *(p[j]));
1448  }
1449 
1450  // minimize in given search direction
1451  _op->apply(*(p[ii]),q); // q=Ap
1452  pp[ii] = _sp->dot(*(p[ii]),q); // scalar product
1453  rho = _sp->dot(*(p[ii]),b); // orthogonalization
1454  lambda = rho/pp[ii]; // minimization
1455  x.axpy(lambda,*(p[ii])); // update solution
1456  b.axpy(-lambda,q); // update defect
1457 
1458  // convergence test
1459  def = _sp->norm(b); // comp defect norm
1460 
1461  ++i;
1462  iteration.step(i, def);
1463  }
1464  if(res.converged)
1465  break;
1466  if(end==_restart) {
1467  *(p[0])=*(p[_restart-1]);
1468  pp[0]=pp[_restart-1];
1469  }
1470  }
1471 
1472  // postprocess preconditioner
1473  _prec->post(x);
1474 
1475  }
1476 
1477  private:
1484  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1485  int _restart;
1486  };
1487  DUNE_REGISTER_ITERATIVE_SOLVER("generalizedpcgsolver", defaultIterativeSolverCreator<Dune::GeneralizedPCGSolver>());
1488 
1500  template<class X>
1501  class RestartedFCGSolver : public IterativeSolver<X,X> {
1502  public:
1503  using typename IterativeSolver<X,X>::domain_type;
1504  using typename IterativeSolver<X,X>::range_type;
1505  using typename IterativeSolver<X,X>::field_type;
1506  using typename IterativeSolver<X,X>::real_type;
1507 
1508  private:
1510 
1511  public:
1512  // don't shadow four-argument version of apply defined in the base class
1520  scalar_real_type reduction, int maxit, int verbose, int mmax = 10) : IterativeSolver<X,X>(op, prec, reduction, maxit, verbose), _mmax(mmax)
1521  {
1522  }
1523 
1530  scalar_real_type reduction, int maxit, int verbose, int mmax = 10) : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose), _mmax(mmax)
1531  {
1532  }
1533 
1539  RestartedFCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1540  std::shared_ptr<const ScalarProduct<X>> sp,
1541  std::shared_ptr<Preconditioner<X,X>> prec,
1542  scalar_real_type reduction, int maxit, int verbose,
1543  int mmax = 10)
1544  : IterativeSolver<X,X>(op, sp, prec, reduction, maxit, verbose), _mmax(mmax)
1545  {}
1546 
1559  RestartedFCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1560  std::shared_ptr<Preconditioner<X,X>> prec,
1561  const ParameterTree& config)
1562  : IterativeSolver<X,X>(op, prec, config), _mmax(config.get("mmax", 10))
1563  {}
1564 
1565  RestartedFCGSolver (std::shared_ptr<const LinearOperator<X,X>> op,
1566  std::shared_ptr<const ScalarProduct<X>> sp,
1567  std::shared_ptr<Preconditioner<X,X>> prec,
1568  const ParameterTree& config)
1569  : IterativeSolver<X,X>(op, sp, prec, config), _mmax(config.get("mmax", 10))
1570  {}
1571 
1584  virtual void apply (X& x, X& b, InverseOperatorResult& res)
1585  {
1586  using rAlloc = ReboundAllocatorType<X,field_type>;
1587  res.clear();
1588  Iteration iteration(*this,res);
1589  _prec->pre(x,b); // prepare preconditioner
1590  _op->applyscaleadd(-1,x,b); // overwrite b with defect
1591 
1592  //arrays for interim values:
1593  std::vector<X> d(_mmax+1, x); // array for directions
1594  std::vector<X> Ad(_mmax+1, x); // array for Ad[i]
1595  std::vector<field_type,rAlloc> ddotAd(_mmax+1,0); // array for <d[i],Ad[i]>
1596  X w(x);
1597 
1598  real_type def = _sp->norm(b); // compute norm
1599  if(iteration.step(0, def)){
1600  _prec->post(x);
1601  return;
1602  }
1603 
1604  // some local variables
1605  field_type alpha;
1606 
1607  // the loop
1608  int i=1;
1609  int i_bounded=0;
1610  while(i<=_maxit && !res.converged) {
1611  for (; i_bounded <= _mmax && i<= _maxit; i_bounded++) {
1612  d[i_bounded] = 0; // reset search direction
1613  _prec->apply(d[i_bounded], b); // apply preconditioner
1614  w = d[i_bounded]; // copy of current d[i]
1615  // orthogonalization with previous directions
1616  orthogonalizations(i_bounded,Ad,w,ddotAd,d);
1617 
1618  //saving interim values for future calculating
1619  _op->apply(d[i_bounded], Ad[i_bounded]); // save Ad[i]
1620  ddotAd[i_bounded]=_sp->dot(d[i_bounded],Ad[i_bounded]); // save <d[i],Ad[i]>
1621  alpha = _sp->dot(d[i_bounded], b)/ddotAd[i_bounded]; // <d[i],b>/<d[i],Ad[i]>
1622 
1623  //update solution and defect
1624  x.axpy(alpha, d[i_bounded]);
1625  b.axpy(-alpha, Ad[i_bounded]);
1626 
1627  // convergence test
1628  def = _sp->norm(b); // comp defect norm
1629 
1630  iteration.step(i, def);
1631  i++;
1632  }
1633  //restart: exchange first and last stored values
1634  cycle(Ad,d,ddotAd,i_bounded);
1635  }
1636 
1637  //correct i which is wrong if convergence was not achieved.
1638  i=std::min(_maxit,i);
1639 
1640  _prec->post(x); // postprocess preconditioner
1641  }
1642 
1643  private:
1644  //This function is called every iteration to orthogonalize against the last search directions
1645  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) {
1646  // The RestartedFCGSolver uses only values with lower array index;
1647  for (int k = 0; k < i_bounded; k++) {
1648  d[i_bounded].axpy(-_sp->dot(Ad[k], w) / ddotAd[k], d[k]); // d[i] -= <<Ad[k],w>/<d[k],Ad[k]>>d[k]
1649  }
1650  }
1651 
1652  // This function is called every mmax iterations to handle limited array sizes.
1653  virtual void cycle(std::vector<X>& Ad,std::vector<X>& d,std::vector<field_type,ReboundAllocatorType<X,field_type> >& ddotAd,int& i_bounded) {
1654  // Reset loop index and exchange the first and last arrays
1655  i_bounded = 1;
1656  std::swap(Ad[0], Ad[_mmax]);
1657  std::swap(d[0], d[_mmax]);
1658  std::swap(ddotAd[0], ddotAd[_mmax]);
1659  }
1660 
1661  protected:
1662  int _mmax;
1663  using IterativeSolver<X,X>::_op;
1664  using IterativeSolver<X,X>::_prec;
1665  using IterativeSolver<X,X>::_sp;
1666  using IterativeSolver<X,X>::_reduction;
1667  using IterativeSolver<X,X>::_maxit;
1668  using IterativeSolver<X,X>::_verbose;
1669  using Iteration = typename IterativeSolver<X,X>::template Iteration<unsigned int>;
1670  };
1671  DUNE_REGISTER_ITERATIVE_SOLVER("restartedfcgsolver", defaultIterativeSolverCreator<Dune::RestartedFCGSolver>());
1672 
1679  template<class X>
1681  public:
1682  using typename RestartedFCGSolver<X>::domain_type;
1683  using typename RestartedFCGSolver<X>::range_type;
1684  using typename RestartedFCGSolver<X>::field_type;
1685  using typename RestartedFCGSolver<X>::real_type;
1686 
1687  // copy base class constructors
1689 
1690  // don't shadow four-argument version of apply defined in the base class
1692 
1693  // just a minor part of the RestartedFCGSolver apply method will be modified
1694  virtual void apply (X& x, X& b, InverseOperatorResult& res) override {
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  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) 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  virtual 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_ITERATIVE_SOLVER("completefcgsolver", defaultIterativeSolverCreator<Dune::CompleteFCGSolver>());
1735 } // end namespace
1736 
1737 #endif
Implementation of the BCRSMatrix class.
Wrapper to use a range of ARPACK++ eigenvalue solvers.
Definition: arpackpp.hh:245
void computeSymMaxMagnitude(const Real &epsilon, BlockVector &x, Real &lambda) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation lambda of its ...
Definition: arpackpp.hh:289
void computeSymMinMagnitude(const Real &epsilon, BlockVector &x, Real &lambda) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation lambda of its ...
Definition: arpackpp.hh:391
A sparse block matrix with compressed row storage.
Definition: bcrsmatrix.hh:466
@ row_wise
Build in a row-wise manner.
Definition: bcrsmatrix.hh:521
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:1972
Bi-conjugate Gradient Stabilized (BiCG-STAB)
Definition: solvers.hh:419
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:439
A vector of blocks with memory management.
Definition: bvector.hh:395
conjugate gradient method
Definition: solvers.hh:193
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
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:279
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:256
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:1680
virtual void apply(X &x, X &b, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1694
Generalized preconditioned conjugate gradient solver.
Definition: solvers.hh:1307
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:1343
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:1331
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:1391
GeneralizedPCGSolver(std::shared_ptr< const LinearOperator< X, X > > op, std::shared_ptr< Preconditioner< X, X > > prec, const ParameterTree &configuration)
Constructor.
Definition: solvers.hh:1361
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
gradient method
Definition: solvers.hh:124
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:142
Simd::Scalar< real_type > scalar_real_type
scalar type underlying the field_type
Definition: solver.hh:114
Y range_type
Type of the range of the operator to be inverted.
Definition: solver.hh:105
X domain_type
Type of the domain of the operator to be inverted.
Definition: solver.hh:102
X::field_type field_type
The field type of the operator.
Definition: solver.hh:108
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:111
Base class for all implementations of iterative solvers.
Definition: solver.hh:203
Preconditioned loop solver.
Definition: solvers.hh:59
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator,.
Definition: solvers.hh:73
Minimal Residual Method (MINRES)
Definition: solvers.hh:609
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:627
Hierarchical structure of string parameters.
Definition: parametertree.hh:37
Accelerated flexible conjugate gradient method.
Definition: solvers.hh:1501
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:1519
RestartedFCGSolver(std::shared_ptr< const LinearOperator< X, X >> op, std::shared_ptr< Preconditioner< X, X >> prec, const ParameterTree &config)
Constructor.
Definition: solvers.hh:1559
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:1539
virtual void apply(X &x, X &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:1584
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:1529
implements the Flexible Generalized Minimal Residual (FGMRes) method (right preconditioned)
Definition: solvers.hh:1139
void apply(X &x, Y &b, [[maybe_unused]] double reduction, InverseOperatorResult &res) override
Apply inverse operator.
Definition: solvers.hh:1169
implements the Generalized Minimal Residual (GMRes) method
Definition: solvers.hh:827
virtual void apply(X &x, Y &b, [[maybe_unused]] double reduction, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:923
RestartedGMResSolver(std::shared_ptr< const LinearOperator< X, Y > > op, std::shared_ptr< Preconditioner< X, X > > prec, const ParameterTree &configuration)
Constructor.
Definition: solvers.hh:878
ReboundAllocatorType< X, field_type > fAlloc
field_type Allocator retrieved from domain type
Definition: solvers.hh:838
ReboundAllocatorType< X, real_type > rAlloc
real_type Allocator retrieved from domain type
Definition: solvers.hh:840
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:894
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:850
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:861
virtual void apply(X &x, Y &b, InverseOperatorResult &res)
Apply inverse operator.
Definition: solvers.hh:910
Base class for scalar product and norm computation.
Definition: scalarproducts.hh:52
Thrown when a solver aborts due to some problem.
Definition: istlexception.hh:46
A few common exception classes.
IO interface of the SIMD abstraction.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
auto min(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::min()
Definition: defaults.hh:89
auto max(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::max()
Definition: defaults.hh:81
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
Define general, extensible interface for operators. The available implementation wraps a matrix.
Define base class for scalar product and norm.
Include file for users of the SIMD abstraction layer.
Define general, extensible interface for inverse operators.
Statistics about the application of an inverse operator.
Definition: solver.hh:48
double condition_estimate
Estimate of condition number.
Definition: solver.hh:79
void clear()
Resets all data.
Definition: solver.hh:56
bool converged
True if convergence criterion has been met.
Definition: solver.hh:73
A simple timing class.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (Apr 26, 22:29, 2024)