FV3 Bundle
GMRESR.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2009-2016 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #ifndef OOPS_ASSIMILATION_GMRESR_H_
12 #define OOPS_ASSIMILATION_GMRESR_H_
13 
14 #include <cmath>
15 #include <vector>
16 
17 #include "oops/util/dot_product.h"
18 #include "oops/util/formats.h"
19 #include "oops/util/Logger.h"
20 
21 namespace oops {
22 
23 /*! \file GMRESR.h
24  * \brief GMRESR solver for Ax=b.
25  *
26  * GMRESR solver for Ax=b. (H.A. Van der Vorst and C. Vuik, 1994,
27  * Numerical Linear Algebra with Applications, 1(4), 369-386.)
28  * A must be square, but need not be symmetric. (For a symmetric matrix,
29  * and constant preconditioner, GMRESR is simply PCG with full
30  * orthogonalisation.) A preconditioner must be supplied that, given a
31  * vector q, returns an approximate solution of Ap=q. The preconditioner
32  * can be variable.
33  *
34  * On entry:
35  * - x = starting point, \f$ X_0 \f$.
36  * - b = right hand side.
37  * - A = \f$ A \f$.
38  * - precond = preconditioner \f$ F_k \approx (A)^{-1} \f$.
39  *
40  * On exit, x will contain the solution.
41  * The return value is the achieved reduction in residual norm.
42  *
43  * Iteration will stop if the maximum iteration limit "maxiter" is reached
44  * or if the residual norm reduces by a factor of "tolerance".
45  *
46  * VECTOR must implement:
47  * - dot_product
48  * - operator(=)
49  * - operator(+=),
50  * - operator(-=)
51  * - operator(*=) [double * VECTOR],
52  * - axpy
53  *
54  * AMATRIX and PMATRIX must implement a method:
55  * - void multiply(const VECTOR&, VECTOR&) const
56  *
57  * which applies the matrix to the first argument, and returns the
58  * matrix-vector product in the second. (Note: the const is optional, but
59  * recommended.)
60  */
61 
62 template <typename VECTOR, typename AMATRIX, typename PMATRIX>
63 double GMRESR(VECTOR & xx, const VECTOR & bb,
64  const AMATRIX & A, const PMATRIX & precond,
65  const int maxiter, const double tolerance) {
66  const double stagthresh = 1.0e-3;
67  const double smallres = 1.0e-6;
68 
69  std::vector<VECTOR> cvecs;
70  std::vector<VECTOR> zvecs;
71  VECTOR cc(xx);
72  VECTOR zz(xx);
73 
74  VECTOR rr(bb);
75  A.multiply(xx, zz); // zz=Axx
76  rr -= zz;
77 
78  double normReduction = 1.0;
79  double rrnorm = sqrt(dot_product(rr, rr));
80  double cdotr = rrnorm;
81  const double rrnorm0 = rrnorm;
82 
83  if (rrnorm > smallres) {
84  Log::info() << std::endl;
85  for (int jiter = 0; jiter < maxiter; ++jiter) {
86  Log::info() << " GMRESR Starting Iteration " << jiter+1 << std::endl;
87 
88  // test for stagnation
89  if (std::abs(cdotr) < stagthresh*rrnorm) {
90  Log::info() << "GMRESR stagnated. Doing an LSQR step." << std::endl;
91  A.multiply(rr, zz); // should be A^T, but we assume A is symmetric.
92  } else {
93  precond.multiply(rr, zz); // returns zz as approximate solution of Azz=rr
94  }
95 
96  A.multiply(zz, cc); // cc=Azz
97 
98  for (int jj = 0; jj < jiter; ++jj) {
99  double alpha = -dot_product(cvecs[jj], cc);
100  cc.axpy(alpha, cvecs[jj]); // cc = cc - <c[jj],cc>*c[jj];
101  zz.axpy(alpha, zvecs[jj]); // zz = zz - <c[jj],cc>*z[jj];
102  }
103 
104  double ccnorm = sqrt(dot_product(cc, cc));
105  cvecs.push_back(cc); // c[jiter]=cc
106  cvecs[jiter] *= 1.0/ccnorm;
107  zvecs.push_back(zz); // z[jiter]=zz
108  zvecs[jiter] *= 1.0/ccnorm;
109 
110  cdotr = dot_product(cvecs[jiter], rr);
111  rr.axpy(-cdotr, cvecs[jiter]);
112  xx.axpy(cdotr, zvecs[jiter]);
113 
114  rrnorm = sqrt(dot_product(rr, rr));
115  normReduction = rrnorm/rrnorm0;
116  Log::info() << "GMRESR end of iteration " << jiter+1 << ". Norm reduction= "
117  << util::full_precision(normReduction) << std::endl << std::endl;
118 
119  if (normReduction < tolerance) {
120  Log::info() << "GMRESR: Achieved required reduction in residual norm." << std::endl;
121  break;
122  }
123  }
124  }
125 
126  return normReduction;
127 }
128 
129 } // namespace oops
130 
131 #endif // OOPS_ASSIMILATION_GMRESR_H_
double GMRESR(VECTOR &xx, const VECTOR &bb, const AMATRIX &A, const PMATRIX &precond, const int maxiter, const double tolerance)
Definition: GMRESR.h:63
real, dimension(:,:), allocatable, private bb
Definition: tridiagonal.F90:75
The namespace for the main oops code.
subroutine, public info(self)
real(fp), parameter, public tolerance