Dune Core Modules (2.5.1)

poweriteration.hh
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_ISTL_EIGENVALUE_POWERITERATION_HH
4 #define DUNE_ISTL_EIGENVALUE_POWERITERATION_HH
5 
6 #include <cstddef> // provides std::size_t
7 #include <cmath> // provides std::sqrt, std::abs
8 
9 #include <type_traits> // provides std::is_same
10 #include <iostream> // provides std::cout, std::endl
11 #include <limits> // provides std::numeric_limits
12 #include <ios> // provides std::left, std::ios::left
13 #include <iomanip> // provides std::setw, std::resetiosflags
14 #include <memory> // provides std::unique_ptr
15 #include <string> // provides std::string
16 
17 #include <dune/common/exceptions.hh> // provides DUNE_THROW(...)
18 
19 #include <dune/istl/operators.hh> // provides Dune::LinearOperator
20 #include <dune/istl/solvercategory.hh> // provides Dune::SolverCategory::sequential
21 #include <dune/istl/solvertype.hh> // provides Dune::IsDirectSolver
22 #include <dune/istl/operators.hh> // provides Dune::MatrixAdapter
23 #include <dune/istl/istlexception.hh> // provides Dune::ISTLError
24 #include <dune/istl/io.hh> // provides Dune::printvector(...)
25 #include <dune/istl/solvers.hh> // provides Dune::InverseOperatorResult
26 
27 
28 namespace Dune
29 {
30 
38  template <class X, class Y = X>
40  {
41  public:
42  typedef X domain_type;
43  typedef Y range_type;
44  typedef typename X::field_type field_type;
45 
46  enum {category = Dune::SolverCategory::sequential};
47 
48  ScalingLinearOperator (field_type immutable_scaling,
49  const field_type& mutable_scaling)
50  : immutable_scaling_(immutable_scaling),
51  mutable_scaling_(mutable_scaling)
52  {}
53 
54  virtual void apply (const X& x, Y& y) const
55  {
56  y = x;
57  y *= immutable_scaling_*mutable_scaling_;
58  }
59 
60  virtual void applyscaleadd (field_type alpha, const X& x, Y& y) const
61  {
62  X temp(x);
63  temp *= immutable_scaling_*mutable_scaling_;
64  y.axpy(alpha,temp);
65  }
66 
67  protected:
68  const field_type immutable_scaling_;
69  const field_type& mutable_scaling_;
70  };
71 
72 
81  template <class OP1, class OP2>
83  : public Dune::LinearOperator<typename OP1::domain_type,
84  typename OP1::range_type>
85  {
86  public:
87  typedef typename OP1::domain_type domain_type;
88  typedef typename OP1::range_type range_type;
89  typedef typename domain_type::field_type field_type;
90 
91  enum {category = Dune::SolverCategory::sequential};
92 
93  LinearOperatorSum (const OP1& op1, const OP2& op2)
94  : op1_(op1), op2_(op2)
95  {
96  static_assert(std::is_same<typename OP2::domain_type,domain_type>::value,
97  "Domain type of both operators doesn't match!");
98  static_assert(std::is_same<typename OP2::range_type,range_type>::value,
99  "Range type of both operators doesn't match!");
100  }
101 
102  virtual void apply (const domain_type& x, range_type& y) const
103  {
104  op1_.apply(x,y);
105  op2_.applyscaleadd(1.0,x,y);
106  }
107 
108  virtual void applyscaleadd (field_type alpha,
109  const domain_type& x, range_type& y) const
110  {
111  range_type temp(y);
112  op1_.apply(x,temp);
113  op2_.applyscaleadd(1.0,x,temp);
114  y.axpy(alpha,temp);
115  }
116 
117  protected:
118  const OP1& op1_;
119  const OP2& op2_;
120  };
121 
122 
130  template <typename ISTLLinearSolver, typename BCRSMatrix>
132  {
133  public:
134  static void setMatrix (ISTLLinearSolver& solver,
135  const BCRSMatrix& matrix)
136  {
137  static const bool is_direct_solver
138  = Dune::IsDirectSolver<ISTLLinearSolver>::value;
141  }
142 
143  protected:
148  template <bool is_direct_solver, typename Dummy = void>
150  {
151  static void setMatrix (ISTLLinearSolver&,
152  const BCRSMatrix&)
153  {}
154  };
155 
160  template <typename Dummy>
161  struct Implementation<true,Dummy>
162  {
163  static void setMatrix (ISTLLinearSolver& solver,
164  const BCRSMatrix& matrix)
165  {
166  solver.setMatrix(matrix);
167  }
168  };
169  };
170 
171 
209  template <typename BCRSMatrix, typename BlockVector>
211  {
212  protected:
213  // Type definitions for type of iteration operator (m_ - mu_*I)
218 
219  public:
221  typedef typename BlockVector::field_type Real;
222 
225 
226  public:
242  const unsigned int nIterationsMax = 1000,
243  const unsigned int verbosity_level = 0)
244  : m_(m), nIterationsMax_(nIterationsMax),
245  verbosity_level_(verbosity_level),
246  mu_(0.0),
247  matrixOperator_(m_),
248  scalingOperator_(-1.0,mu_),
249  itOperator_(matrixOperator_,scalingOperator_),
250  nIterations_(0),
251  title_(" PowerIteration_Algorithms: "),
252  blank_(title_.length(),' ')
253  {
254  // assert that BCRSMatrix type has blocklevel 2
255  static_assert
257  "Only BCRSMatrices with blocklevel 2 are supported.");
258 
259  // assert that BCRSMatrix type has square blocks
260  static_assert
261  (BCRSMatrix::block_type::rows == BCRSMatrix::block_type::cols,
262  "Only BCRSMatrices with square blocks are supported.");
263 
264  // assert that m_ is square
265  const int nrows = m_.M() * BCRSMatrix::block_type::rows;
266  const int ncols = m_.N() * BCRSMatrix::block_type::cols;
267  if (nrows != ncols)
268  DUNE_THROW(Dune::ISTLError,"Matrix is not square ("
269  << nrows << "x" << ncols << ").");
270  }
271 
276 
282 
295  inline void applyPowerIteration (const Real& epsilon,
296  BlockVector& x, Real& lambda) const
297  {
298  // print verbosity information
299  if (verbosity_level_ > 0)
300  std::cout << title_
301  << "Performing power iteration approximating "
302  << "the dominant eigenvalue." << std::endl;
303 
304  // allocate memory for auxiliary variables
305  BlockVector y(x);
306  BlockVector temp(x);
307 
308  // perform power iteration
309  x *= (1.0 / x.two_norm());
310  m_.mv(x,y);
311  Real r_norm = std::numeric_limits<Real>::max();
312  nIterations_ = 0;
313  while (r_norm > epsilon)
314  {
315  // update and check number of iterations
316  if (++nIterations_ > nIterationsMax_)
317  DUNE_THROW(Dune::ISTLError,"Power iteration did not converge "
318  << "in " << nIterationsMax_ << " iterations "
319  << "(║residual║_2 = " << r_norm << ", epsilon = "
320  << epsilon << ").");
321 
322  // do one iteration of the power iteration algorithm
323  // (use that y = m_ * x)
324  x = y;
325  x *= (1.0 / y.two_norm());
326 
327  // get approximated eigenvalue lambda via the Rayleigh quotient
328  m_.mv(x,y);
329  lambda = x * y;
330 
331  // get norm of residual (use that y = m_ * x)
332  temp = y;
333  temp.axpy(-lambda,x);
334  r_norm = temp.two_norm();
335 
336  // print verbosity information
337  if (verbosity_level_ > 1)
338  std::cout << blank_ << std::left
339  << "iteration " << std::setw(3) << nIterations_
340  << " (║residual║_2 = " << std::setw(11) << r_norm
341  << "): λ = " << lambda << std::endl
342  << std::resetiosflags(std::ios::left);
343  }
344 
345  // print verbosity information
346  if (verbosity_level_ > 0)
347  {
348  std::cout << blank_ << "Result ("
349  << "#iterations = " << nIterations_ << ", "
350  << "║residual║_2 = " << r_norm << "): "
351  << "λ = " << lambda << std::endl;
352  if (verbosity_level_ > 2)
353  {
354  // print approximated eigenvector via DUNE-ISTL I/O methods
355  Dune::printvector(std::cout,x,blank_+"x",blank_+"row");
356  }
357  }
358  }
359 
388  template <typename ISTLLinearSolver,
389  bool avoidLinSolverCrime = false>
390  inline void applyInverseIteration (const Real& epsilon,
391  ISTLLinearSolver& solver,
392  BlockVector& x, Real& lambda) const
393  {
394  constexpr Real gamma = 0.0;
395  applyInverseIteration(gamma,epsilon,solver,x,lambda);
396  }
397 
427  template <typename ISTLLinearSolver,
428  bool avoidLinSolverCrime = false>
429  inline void applyInverseIteration (const Real& gamma,
430  const Real& epsilon,
431  ISTLLinearSolver& solver,
432  BlockVector& x, Real& lambda) const
433  {
434  // print verbosity information
435  if (verbosity_level_ > 0)
436  {
437  std::cout << title_;
438  if (gamma == 0.0)
439  std::cout << "Performing inverse iteration approximating "
440  << "the least dominant eigenvalue." << std::endl;
441  else
442  std::cout << "Performing inverse iteration with shift "
443  << "gamma = " << gamma << " approximating the "
444  << "eigenvalue closest to gamma." << std::endl;
445  }
446 
447  // initialize iteration operator,
448  // initialize iteration matrix when needed
449  updateShiftMu(gamma,solver);
450 
451  // allocate memory for linear solver statistics
452  Dune::InverseOperatorResult solver_statistics;
453 
454  // allocate memory for auxiliary variables
455  BlockVector y(x);
456  Real y_norm;
457  BlockVector temp(x);
458 
459  // perform inverse iteration with shift
460  x *= (1.0 / x.two_norm());
461  Real r_norm = std::numeric_limits<Real>::max();
462  nIterations_ = 0;
463  while (r_norm > epsilon)
464  {
465  // update and check number of iterations
466  if (++nIterations_ > nIterationsMax_)
467  DUNE_THROW(Dune::ISTLError,"Inverse iteration "
468  << (gamma != 0.0 ? "with shift " : "") << "did not "
469  << "converge in " << nIterationsMax_ << " iterations "
470  << "(║residual║_2 = " << r_norm << ", epsilon = "
471  << epsilon << ").");
472 
473  // do one iteration of the inverse iteration with shift algorithm,
474  // part 1: solve (m_ - gamma*I) * y = x for y
475  // (protect x from being changed)
476  temp = x;
477  solver.apply(y,temp,solver_statistics);
478 
479  // get norm of y
480  y_norm = y.two_norm();
481 
482  // compile time switch between accuracy and efficiency
483  if (avoidLinSolverCrime)
484  {
485  // get approximated eigenvalue lambda via the Rayleigh quotient
486  // (use that x_new = y / y_norm)
487  m_.mv(y,temp);
488  lambda = (y * temp) / (y_norm * y_norm);
489 
490  // get norm of residual
491  // (use that x_new = y / y_norm, additionally use that temp = m_ * y)
492  temp.axpy(-lambda,y);
493  r_norm = temp.two_norm() / y_norm;
494  }
495  else
496  {
497  // get approximated eigenvalue lambda via the Rayleigh quotient
498  // (use that x_new = y / y_norm and use that (m_ - gamma*I) * y = x)
499  lambda = gamma + (y * x) / (y_norm * y_norm);
500 
501  // get norm of residual
502  // (use that x_new = y / y_norm and use that (m_ - gamma*I) * y = x)
503  temp = x; temp.axpy(gamma-lambda,y);
504  r_norm = temp.two_norm() / y_norm;
505  }
506 
507  // do one iteration of the inverse iteration with shift algorithm,
508  // part 2: update x
509  x = y;
510  x *= (1.0 / y_norm);
511 
512  // print verbosity information
513  if (verbosity_level_ > 1)
514  std::cout << blank_ << std::left
515  << "iteration " << std::setw(3) << nIterations_
516  << " (║residual║_2 = " << std::setw(11) << r_norm
517  << "): λ = " << lambda << std::endl
518  << std::resetiosflags(std::ios::left);
519  }
520 
521  // print verbosity information
522  if (verbosity_level_ > 0)
523  {
524  std::cout << blank_ << "Result ("
525  << "#iterations = " << nIterations_ << ", "
526  << "║residual║_2 = " << r_norm << "): "
527  << "λ = " << lambda << std::endl;
528  if (verbosity_level_ > 2)
529  {
530  // print approximated eigenvector via DUNE-ISTL I/O methods
531  Dune::printvector(std::cout,x,blank_+"x",blank_+"row");
532  }
533  }
534  }
535 
566  template <typename ISTLLinearSolver,
567  bool avoidLinSolverCrime = false>
568  inline void applyRayleighQuotientIteration (const Real& epsilon,
569  ISTLLinearSolver& solver,
570  BlockVector& x, Real& lambda) const
571  {
572  // print verbosity information
573  if (verbosity_level_ > 0)
574  std::cout << title_
575  << "Performing Rayleigh quotient iteration for "
576  << "estimated eigenvalue " << lambda << "." << std::endl;
577 
578  // allocate memory for linear solver statistics
579  Dune::InverseOperatorResult solver_statistics;
580 
581  // allocate memory for auxiliary variables
582  BlockVector y(x);
583  Real y_norm;
584  Real lambda_update;
585  BlockVector temp(x);
586 
587  // perform Rayleigh quotient iteration
588  x *= (1.0 / x.two_norm());
589  Real r_norm = std::numeric_limits<Real>::max();
590  nIterations_ = 0;
591  while (r_norm > epsilon)
592  {
593  // update and check number of iterations
594  if (++nIterations_ > nIterationsMax_)
595  DUNE_THROW(Dune::ISTLError,"Rayleigh quotient iteration did not "
596  << "converge in " << nIterationsMax_ << " iterations "
597  << "(║residual║_2 = " << r_norm << ", epsilon = "
598  << epsilon << ").");
599 
600  // update iteration operator,
601  // update iteration matrix when needed
602  updateShiftMu(lambda,solver);
603 
604  // do one iteration of the Rayleigh quotient iteration algorithm,
605  // part 1: solve (m_ - lambda*I) * y = x for y
606  // (protect x from being changed)
607  temp = x;
608  solver.apply(y,temp,solver_statistics);
609 
610  // get norm of y
611  y_norm = y.two_norm();
612 
613  // compile time switch between accuracy and efficiency
614  if (avoidLinSolverCrime)
615  {
616  // get approximated eigenvalue lambda via the Rayleigh quotient
617  // (use that x_new = y / y_norm)
618  m_.mv(y,temp);
619  lambda = (y * temp) / (y_norm * y_norm);
620 
621  // get norm of residual
622  // (use that x_new = y / y_norm, additionally use that temp = m_ * y)
623  temp.axpy(-lambda,y);
624  r_norm = temp.two_norm() / y_norm;
625  }
626  else
627  {
628  // get approximated eigenvalue lambda via the Rayleigh quotient
629  // (use that x_new = y / y_norm and use that (m_ - lambda_old*I) * y = x)
630  lambda_update = (y * x) / (y_norm * y_norm);
631  lambda += lambda_update;
632 
633  // get norm of residual
634  // (use that x_new = y / y_norm and use that (m_ - lambda_old*I) * y = x)
635  temp = x; temp.axpy(-lambda_update,y);
636  r_norm = temp.two_norm() / y_norm;
637  }
638 
639  // do one iteration of the Rayleigh quotient iteration algorithm,
640  // part 2: update x
641  x = y;
642  x *= (1.0 / y_norm);
643 
644  // print verbosity information
645  if (verbosity_level_ > 1)
646  std::cout << blank_ << std::left
647  << "iteration " << std::setw(3) << nIterations_
648  << " (║residual║_2 = " << std::setw(11) << r_norm
649  << "): λ = " << lambda << std::endl
650  << std::resetiosflags(std::ios::left);
651  }
652 
653  // print verbosity information
654  if (verbosity_level_ > 0)
655  {
656  std::cout << blank_ << "Result ("
657  << "#iterations = " << nIterations_ << ", "
658  << "║residual║_2 = " << r_norm << "): "
659  << "λ = " << lambda << std::endl;
660  if (verbosity_level_ > 2)
661  {
662  // print approximated eigenvector via DUNE-ISTL I/O methods
663  Dune::printvector(std::cout,x,blank_+"x",blank_+"row");
664  }
665  }
666  }
667 
724  template <typename ISTLLinearSolver,
725  bool avoidLinSolverCrime = false>
726  inline void applyTLIMEIteration (const Real& gamma, const Real& eta,
727  const Real& epsilon,
728  ISTLLinearSolver& solver,
729  const Real& delta, const std::size_t& m,
730  bool& extrnl,
731  BlockVector& x, Real& lambda) const
732  {
733  // use same variable names as in [Szyld, 1988]
734  BlockVector& x_s = x;
735  Real& mu_s = lambda;
736 
737  // print verbosity information
738  if (verbosity_level_ > 0)
739  std::cout << title_
740  << "Performing TLIME iteration for "
741  << "estimated eigenvalue in the "
742  << "interval (" << gamma - eta << ","
743  << gamma + eta << ")." << std::endl;
744 
745  // allocate memory for linear solver statistics
746  Dune::InverseOperatorResult solver_statistics;
747 
748  // allocate memory for auxiliary variables
749  bool doRQI;
750  Real mu;
751  BlockVector y(x_s);
752  Real omega;
753  Real mu_s_old;
754  Real mu_s_update;
755  BlockVector temp(x_s);
756  Real q_norm, r_norm;
757 
758  // perform TLIME iteration
759  x_s *= (1.0 / x_s.two_norm());
760  extrnl = true;
761  doRQI = false;
762  r_norm = std::numeric_limits<Real>::max();
763  nIterations_ = 0;
764  while (r_norm > epsilon)
765  {
766  // update and check number of iterations
767  if (++nIterations_ > nIterationsMax_)
768  DUNE_THROW(Dune::ISTLError,"TLIME iteration did not "
769  << "converge in " << nIterationsMax_
770  << " iterations (║residual║_2 = " << r_norm
771  << ", epsilon = " << epsilon << ").");
772 
773  // set shift for next iteration according to inverse iteration
774  // with shift (II) resp. Rayleigh quotient iteration (RQI)
775  if (doRQI)
776  mu = mu_s;
777  else
778  mu = gamma;
779 
780  // update II/RQI iteration operator,
781  // update II/RQI iteration matrix when needed
782  updateShiftMu(mu,solver);
783 
784  // do one iteration of the II/RQI algorithm,
785  // part 1: solve (m_ - mu*I) * y = x for y
786  temp = x_s;
787  solver.apply(y,temp,solver_statistics);
788 
789  // do one iteration of the II/RQI algorithm,
790  // part 2: compute omega
791  omega = (1.0 / y.two_norm());
792 
793  // backup the old Rayleigh quotient
794  mu_s_old = mu_s;
795 
796  // compile time switch between accuracy and efficiency
797  if (avoidLinSolverCrime)
798  {
799  // update the Rayleigh quotient mu_s, i.e. the approximated eigenvalue
800  // (use that x_new = y * omega)
801  m_.mv(y,temp);
802  mu_s = (y * temp) * (omega * omega);
803 
804  // get norm of "the residual with respect to the shift used by II",
805  // use normal representation of q
806  // (use that x_new = y * omega, use that temp = m_ * y)
807  temp.axpy(-gamma,y);
808  q_norm = temp.two_norm() * omega;
809 
810  // get norm of "the residual with respect to the Rayleigh quotient"
811  r_norm = q_norm*q_norm - (gamma-mu_s)*(gamma-mu_s);
812  // prevent that truncation errors invalidate the norm
813  // (we don't want to calculate sqrt of a negative number)
814  if (r_norm >= 0)
815  {
816  // use relation between the norms of r and q for efficiency
817  r_norm = std::sqrt(r_norm);
818  }
819  else
820  {
821  // use relation between r and q
822  // (use that x_new = y * omega, use that temp = (m_ - gamma*I) * y = q / omega)
823  temp.axpy(gamma-mu_s,y);
824  r_norm = temp.two_norm() * omega;
825  }
826  }
827  else
828  {
829  // update the Rayleigh quotient mu_s, i.e. the approximated eigenvalue
830  if (!doRQI)
831  {
832  // (use that x_new = y * omega, additionally use that (m_ - gamma*I) * y = x_s)
833  mu_s = gamma + (y * x_s) * (omega * omega);
834  }
835  else
836  {
837  // (use that x_new = y * omega, additionally use that (m_ - mu_s_old*I) * y = x_s)
838  mu_s_update = (y * x_s) * (omega * omega);
839  mu_s += mu_s_update;
840  }
841 
842  // get norm of "the residual with respect to the shift used by II"
843  if (!doRQI)
844  {
845  // use special representation of q in the II case
846  // (use that x_new = y * omega, additionally use that (m_ - gamma*I) * y = x_s)
847  q_norm = omega;
848  }
849  else
850  {
851  // use special representation of q in the RQI case
852  // (use that x_new = y * omega, additionally use that (m_ - mu_s_old*I) * y = x_s)
853  temp = x_s; temp.axpy(mu_s-gamma,y);
854  q_norm = temp.two_norm() * omega;
855  }
856 
857  // get norm of "the residual with respect to the Rayleigh quotient"
858  // don't use efficient relation between the norms of r and q, as
859  // this relation seems to yield a less accurate r_norm in the case
860  // where linear solver crime is admitted
861  if (!doRQI)
862  {
863  // (use that x_new = y * omega and use that (m_ - gamma*I) * y = x_s)
864  temp = x_s; temp.axpy(gamma-lambda,y);
865  r_norm = temp.two_norm() * omega;
866  }
867  else
868  {
869  // (use that x_new = y * omega and use that (m_ - mu_s_old*I) * y = x_s)
870  temp = x_s; temp.axpy(-mu_s_update,y);
871  r_norm = temp.two_norm() * omega;
872  }
873  }
874 
875  // do one iteration of the II/RQI algorithm,
876  // part 3: update x
877  x_s = y; x_s *= omega;
878 
879  // // for relative residual norm mode, scale with mu_s^{-1}
880  // r_norm /= std::abs(mu_s);
881 
882  // print verbosity information
883  if (verbosity_level_ > 1)
884  std::cout << blank_ << "iteration "
885  << std::left << std::setw(3) << nIterations_
886  << " (" << (doRQI ? "RQI," : "II, ")
887  << " " << (doRQI ? "—>" : " ") << " "
888  << "║r║_2 = " << std::setw(11) << r_norm
889  << ", " << (doRQI ? " " : "—>") << " "
890  << "║q║_2 = " << std::setw(11) << q_norm
891  << "): λ = " << lambda << std::endl
892  << std::resetiosflags(std::ios::left);
893 
894  // check if the eigenvalue closest to gamma lies in J
895  if (!doRQI && q_norm < eta)
896  {
897  // J is not free of eigenvalues
898  extrnl = false;
899 
900  // by theory we know now that mu_s also lies in J
901  assert(std::abs(mu_s-gamma) < eta);
902 
903  // switch to RQI
904  doRQI = true;
905  }
906 
907  // revert to II if J is not free of eigenvalues but
908  // at some point mu_s falls back again outside J
909  if (!extrnl && doRQI && std::abs(mu_s-gamma) >= eta)
910  doRQI = false;
911 
912  // if eigenvalue closest to gamma does not lie in J use RQI
913  // solely to accelerate the convergence to this eigenvalue
914  // when II has become stationary
915  if (extrnl && !doRQI)
916  {
917  // switch to RQI if the relative change of the Rayleigh
918  // quotient indicates that II has become stationary
919  if (nIterations_ >= m &&
920  std::abs(mu_s - mu_s_old) / std::abs(mu_s) < delta)
921  doRQI = true;
922  }
923  }
924 
925  // // compute final residual and lambda again (paranoia....)
926  // m_.mv(x_s,temp);
927  // mu_s = x_s * temp;
928  // temp.axpy(-mu_s,x_s);
929  // r_norm = temp.two_norm();
930  // // r_norm /= std::abs(mu_s);
931 
932  // print verbosity information
933  if (verbosity_level_ > 0)
934  {
935  if (extrnl)
936  std::cout << blank_ << "Interval "
937  << "(" << gamma - eta << "," << gamma + eta
938  << ") is free of eigenvalues, approximating "
939  << "the closest eigenvalue." << std::endl;
940  std::cout << blank_ << "Result ("
941  << "#iterations = " << nIterations_ << ", "
942  << "║residual║_2 = " << r_norm << "): "
943  << "λ = " << lambda << std::endl;
944  if (verbosity_level_ > 2)
945  {
946  // print approximated eigenvector via DUNE-ISTL I/O methods
947  Dune::printvector(std::cout,x,blank_+"x",blank_+"row");
948  }
949  }
950  }
951 
961  {
962  // return iteration operator
963  return itOperator_;
964  }
965 
980  inline const BCRSMatrix& getIterationMatrix () const
981  {
982  // create iteration matrix on demand
983  if (!itMatrix_)
984  itMatrix_ = std::unique_ptr<BCRSMatrix>(new BCRSMatrix(m_));
985 
986  // return iteration matrix
987  return *itMatrix_;
988  }
989 
994  inline unsigned int getIterationCount () const
995  {
996  if (nIterations_ == 0)
997  DUNE_THROW(Dune::ISTLError,"No algorithm applied, yet.");
998 
999  return nIterations_;
1000  }
1001 
1002  protected:
1017  template <typename ISTLLinearSolver>
1018  inline void updateShiftMu (const Real& mu,
1019  ISTLLinearSolver& solver) const
1020  {
1021  // do nothing if new shift equals the old one
1022  if (mu == mu_) return;
1023 
1024  // update shift mu_, i.e. update iteration operator
1025  mu_ = mu;
1026 
1027  // update iteration matrix when needed
1028  if (itMatrix_)
1029  {
1030  // iterate over entries in iteration matrix diagonal
1031  constexpr int rowBlockSize = BCRSMatrix::block_type::rows;
1032  constexpr int colBlockSize = BCRSMatrix::block_type::cols;
1033  for (typename BCRSMatrix::size_type i = 0;
1034  i < itMatrix_->M()*rowBlockSize; ++i)
1035  {
1036  // access m_[i,i] where i is the flat index of a row/column
1037  const Real& m_entry = m_
1038  [i/rowBlockSize][i/colBlockSize][i%rowBlockSize][i%colBlockSize];
1039  // access *itMatrix[i,i] where i is the flat index of a row/column
1040  Real& entry = (*itMatrix_)
1041  [i/rowBlockSize][i/colBlockSize][i%rowBlockSize][i%colBlockSize];
1042  // change current entry in iteration matrix diagonal
1043  entry = m_entry - mu_;
1044  }
1045  // notify linear solver about change of the iteration matrix object
1047  (solver,*itMatrix_);
1048  }
1049  }
1050 
1051  protected:
1052  // parameters related to iterative eigenvalue algorithms
1053  const BCRSMatrix& m_;
1054  const unsigned int nIterationsMax_;
1055 
1056  // verbosity setting
1057  const unsigned int verbosity_level_;
1058 
1059  // shift mu_ used by iteration operator/matrix (m_ - mu_*I)
1060  mutable Real mu_;
1061 
1062  // iteration operator (m_ - mu_*I), passing shift mu_ by reference
1063  const MatrixOperator matrixOperator_;
1064  const ScalingOperator scalingOperator_;
1065  OperatorSum itOperator_;
1066 
1067  // iteration matrix (m_ - mu_*I), provided on demand when needed
1068  // (e.g. for preconditioning)
1069  mutable std::unique_ptr<BCRSMatrix> itMatrix_;
1070 
1071  // memory for storing temporary variables (mutable as they shall
1072  // just be effectless auxiliary variables of the const apply*(...)
1073  // methods)
1074  mutable unsigned int nIterations_;
1075 
1076  // constants for printing verbosity information
1077  const std::string title_;
1078  const std::string blank_;
1079  };
1080 
1081 } // namespace Dune
1082 
1083 
1084 #endif // DUNE_ISTL_EIGENVALUE_POWERITERATION_HH
A sparse block matrix with compressed row storage.
Definition: bcrsmatrix.hh:423
@ blocklevel
The number of blocklevels the matrix contains.
Definition: bcrsmatrix.hh:465
A::size_type size_type
The type for the index access and the size.
Definition: bcrsmatrix.hh:457
size_type M() const
number of columns (counted in blocks)
Definition: bcrsmatrix.hh:1909
void mv(const X &x, Y &y) const
y = A x
Definition: bcrsmatrix.hh:1580
size_type N() const
number of rows (counted in blocks)
Definition: bcrsmatrix.hh:1903
A vector of blocks with memory management.
Definition: bvector.hh:313
B::field_type field_type
export the type representing the field
Definition: bvector.hh:319
derive error class from the base class in common
Definition: istlexception.hh:16
A linear operator representing the sum of two linear operators.
Definition: poweriteration.hh:85
virtual void apply(const domain_type &x, range_type &y) const
apply operator to x: The input vector is consistent and the output must also be consistent on the in...
Definition: poweriteration.hh:102
A linear operator.
Definition: operators.hh:62
Adapter to turn a matrix into a linear operator.
Definition: operators.hh:122
A class template for performing some iterative eigenvalue algorithms based on power iteration.
Definition: poweriteration.hh:211
PowerIteration_Algorithms(const PowerIteration_Algorithms &)=delete
void applyInverseIteration(const Real &epsilon, ISTLLinearSolver &solver, BlockVector &x, Real &lambda) const
Perform the inverse iteration algorithm to compute an approximation lambda of the least dominant (i....
Definition: poweriteration.hh:390
void applyTLIMEIteration(const Real &gamma, const Real &eta, const Real &epsilon, ISTLLinearSolver &solver, const Real &delta, const std::size_t &m, bool &extrnl, BlockVector &x, Real &lambda) const
Perform the "two-level iterative method for eigenvalue calculations (TLIME)" iteration algorit...
Definition: poweriteration.hh:726
PowerIteration_Algorithms(const BCRSMatrix &m, const unsigned int nIterationsMax=1000, const unsigned int verbosity_level=0)
Construct from required parameters.
Definition: poweriteration.hh:241
void applyPowerIteration(const Real &epsilon, BlockVector &x, Real &lambda) const
Perform the power iteration algorithm to compute an approximation lambda of the dominant (i....
Definition: poweriteration.hh:295
OperatorSum IterationOperator
Type of iteration operator (m_ - mu_*I)
Definition: poweriteration.hh:224
void applyRayleighQuotientIteration(const Real &epsilon, ISTLLinearSolver &solver, BlockVector &x, Real &lambda) const
Perform the Rayleigh quotient iteration algorithm to compute an approximation lambda of an eigenvalue...
Definition: poweriteration.hh:568
void applyInverseIteration(const Real &gamma, const Real &epsilon, ISTLLinearSolver &solver, BlockVector &x, Real &lambda) const
Perform the inverse iteration with shift algorithm to compute an approximation lambda of the eigenval...
Definition: poweriteration.hh:429
void updateShiftMu(const Real &mu, ISTLLinearSolver &solver) const
Update shift mu_, i.e. update iteration operator/matrix (m_ - mu_*I).
Definition: poweriteration.hh:1018
const BCRSMatrix & getIterationMatrix() const
Return the iteration matrix (m_ - mu_*I), provided on demand when needed (e.g. for direct solvers or ...
Definition: poweriteration.hh:980
unsigned int getIterationCount() const
Return the number of iterations in last application of an algorithm.
Definition: poweriteration.hh:994
IterationOperator & getIterationOperator()
Return the iteration operator (m_ - mu_*I).
Definition: poweriteration.hh:960
PowerIteration_Algorithms & operator=(const PowerIteration_Algorithms &)=delete
BlockVector::field_type Real
Type of underlying field.
Definition: poweriteration.hh:221
A linear operator scaling vectors by a scalar value. The scalar value can be changed as it is given i...
Definition: poweriteration.hh:40
Helper class for notifying a DUNE-ISTL linear solver about a change of the iteration matrix object in...
Definition: poweriteration.hh:132
block_vector_unmanaged & axpy(const field_type &a, const block_vector_unmanaged &y)
vector space axpy operation
Definition: bvector.hh:124
FieldTraits< field_type >::real_type two_norm() const
two norm sqrt(sum over squared values of entries)
Definition: bvector.hh:193
A few common exception classes.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
void printvector(std::ostream &s, const V &v, std::string title, std::string rowtext, int columns=1, int width=10, int precision=2)
Print an ISTL vector.
Definition: io.hh:102
Some generic functions for pretty printing vectors and matrices.
Dune namespace.
Definition: alignment.hh:11
Define general, extensible interface for operators. The available implementation wraps a matrix.
Implementations of the inverse operator interface.
Templates characterizing the type of a solver.
Statistics about the application of an inverse operator.
Definition: solver.hh:32
@ sequential
Category for sequential solvers.
Definition: solvercategory.hh:21
Implementation that works together with iterative ISTL solvers, e.g. Dune::CGSolver or Dune::BiCGSTAB...
Definition: poweriteration.hh:150
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 13, 22:30, 2024)