FV3 Bundle
MINRES.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_MINRES_H_
12 #define OOPS_ASSIMILATION_MINRES_H_
13 
14 #include <cmath>
15 #include <iostream>
16 #include <vector>
17 
18 #include "oops/util/dot_product.h"
19 #include "oops/util/formats.h"
20 #include "oops/util/Logger.h"
21 
22 namespace oops {
23 
24 /*! \file MINRES.h
25  * \brief MINRES solver for Ax=b.
26  *
27  * MINRES solver for Ax=b.(based on implementation following
28  * C. C. Paige and M. A. Saunders, 1975)
29 
30  * A must be square and symmetric. A can be indefinite.
31  * A symmetric positive-definite preconditioner
32  * must be supplied that, given a
33  * vector q, returns an approximate solution of Ap=q.
34  *
35  * On entry:
36  * - x = starting point, \f$ X_0 \f$.
37  * - b = right hand side.
38  * - A = \f$ A \f$.
39  * - precond = preconditioner \f$ F_k \approx (A)^{-1} \f$.
40  * - maxiter = maximum number of iterations
41  * - tol = error tolerance
42  *
43  * On exit, x will contain the solution.
44  * The return value is the achieved reduction in residual norm.
45  *
46  * Iteration will stop if the maximum iteration limit "maxiter" is reached
47  * or if the residual norm reduces by a factor of "tolerance".
48  *
49  * VECTOR must implement:
50  * - dot_product
51  * - operator(=)
52  * - operator(+=),
53  * - operator(-=)
54  * - operator(*=) [double * VECTOR],
55  * - axpy
56  *
57  * AMATRIX and PMATRIX must implement a method:
58  * - void multiply(const VECTOR&, VECTOR&) const
59  *
60  * which applies the matrix to the first argument, and returns the
61  * matrix-vector product in the second. (Note: the const is optional, but
62  * recommended.)
63  */
64 
65 template <typename VECTOR, typename AMATRIX, typename PMATRIX>
66 double MINRES(VECTOR & x, const VECTOR & b,
67  const AMATRIX & A, const PMATRIX & precond,
68  const int maxiter, const double tolerance) {
69  VECTOR r(x);
70  VECTOR work(x);
71  VECTOR v(x);
72 
73  r = b;
74  double xnrm2 = dot_product(x, x);
75  if (xnrm2 != 0) {
76  A.multiply(x, work); // sx = Ax
77  r -= work; // r = b - Ax
78  }
79  work *= 0;
80  VECTOR work2(work);
81  VECTOR work1(work);
82  VECTOR r1(r);
83  VECTOR r2(r);
84  VECTOR y(r);
85 
86  precond.multiply(r, y);
87 
88  double normReduction = 1.0;
89  double ynrm2 = sqrt(dot_product(y, y));
90  double beta = sqrt(dot_product(y, r));
91 
92  double oldb = 0;
93  double epsln = 0;
94  double cs = -1.0;
95  double sn = 0;
96  double dbar = 0;
97  double phibar = beta;
98 
99  int jiter;
100  // MINRES iteration
101  Log::info() << std::endl;
102  for (jiter = 0; jiter < maxiter; ++jiter) {
103  Log::info() << " MINRES Starting Iteration " << jiter+1 << std::endl;
104 
105  v = y;
106  v *= 1/beta;
107  A.multiply(v, y);
108 
109  if (jiter > 0) {
110  y.axpy(-beta/oldb, r1);
111  }
112 
113  double alpha = dot_product(y, v);
114  y.axpy(-alpha/beta, r2);
115  r1 = r2;
116  r2 = y;
117 
118  precond.multiply(r2, y);
119 
120  oldb = beta;
121  beta = sqrt(dot_product(y, r2));
122 
123  // Apply Givens Rotation
124  double oldeps = epsln;
125  double delta = cs*dbar + sn*alpha;
126  double gbar = sn*dbar - cs*alpha;
127  epsln = sn*beta;
128  dbar = -cs*beta;
129 
130  // Compute Givens rotation matrix parameters
131  double gamma = sqrt(gbar*gbar + beta*beta); // update this parameter
132 
133  cs = gbar/gamma;
134  sn = beta/gamma;
135  double phi = cs*phibar;
136  phibar = sn*phibar;
137 
138  // Update x
139  double denom = 1/gamma;
140  work1 = work2;
141  work2 = work;
142  work = v;
143  work *= denom;
144  work.axpy(-oldeps*denom, work1);
145  work.axpy(-delta*denom, work2);
146  x.axpy(phi, work);
147 
148  normReduction = phibar/ynrm2;
149 
150  Log::info() << "MINRES end of iteration " << jiter+1 << ". PNorm reduction= "
151  << util::full_precision(normReduction) << std::endl << std::endl;
152 
153  if (normReduction <= tolerance) {
154  Log::info() << "MINRES: Achieved required reduction in residual norm." << std::endl;
155  jiter += 1;
156  break;
157  }
158  }
159 
160  Log::info() << "MINRES: end" << std::endl;
161 
162  return normReduction;
163 }
164 
165 } // namespace oops
166 
167 #endif // OOPS_ASSIMILATION_MINRES_H_
The namespace for the main oops code.
real, parameter epsln
Definition: axis_utils.F90:63
subroutine, public info(self)
real(fp), parameter, public tolerance
real, parameter r2
Definition: fv_mapz_nlm.F90:41
double MINRES(VECTOR &x, const VECTOR &b, const AMATRIX &A, const PMATRIX &precond, const int maxiter, const double tolerance)
Definition: MINRES.h:66