OOPS
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.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  // MINRES iteration
100  Log::info() << std::endl;
101  for (int jiter = 0; jiter < maxiter; ++jiter) {
102  Log::info() << " MINRES Starting Iteration " << jiter+1 << std::endl;
103 
104  v = y;
105  v *= 1/beta;
106  A.multiply(v, y);
107 
108  if (jiter > 0) {
109  y.axpy(-beta/oldb, r1);
110  }
111 
112  double alpha = dot_product(y, v);
113  y.axpy(-alpha/beta, r2);
114  r1 = r2;
115  r2 = y;
116 
117  precond.multiply(r2, y);
118 
119  oldb = beta;
120  beta = sqrt(dot_product(y, r2));
121 
122  // Apply Givens Rotation
123  double oldeps = epsln;
124  double delta = cs*dbar + sn*alpha;
125  double gbar = sn*dbar - cs*alpha;
126  epsln = sn*beta;
127  dbar = -cs*beta;
128 
129  // Compute Givens rotation matrix parameters
130  double gamma = sqrt(gbar*gbar + beta*beta); // update this parameter
131 
132  cs = gbar/gamma;
133  sn = beta/gamma;
134  double phi = cs*phibar;
135  phibar = sn*phibar;
136 
137  // Update x
138  double denom = 1/gamma;
139  work1 = work2;
140  work2 = work;
141  work = v;
142  work *= denom;
143  work.axpy(-oldeps*denom, work1);
144  work.axpy(-delta*denom, work2);
145  x.axpy(phi, work);
146 
147  normReduction = phibar/ynrm2;
148 
149  Log::info() << "MINRES end of iteration " << jiter+1 << ". PNorm reduction= "
150  << util::full_precision(normReduction) << std::endl << std::endl;
151 
152  if (normReduction <= tolerance) {
153  Log::info() << "MINRES: Achieved required reduction in residual norm." << std::endl;
154  jiter += 1;
155  break;
156  }
157  }
158 
159  Log::info() << "MINRES: end" << std::endl;
160 
161  return normReduction;
162 }
163 
164 } // namespace oops
165 
166 #endif // OOPS_ASSIMILATION_MINRES_H_
oops
The namespace for the main oops code.
Definition: ErrorCovarianceL95.cc:22
dcmip_initial_conditions_test_4::gamma
real(8), parameter gamma
Definition: dcmip_initial_conditions_test_4_v3.f90:75
oops::MINRES
double MINRES(VECTOR &x, const VECTOR &b, const AMATRIX &A, const PMATRIX &precond, const int maxiter, const double tolerance)
Definition: MINRES.h:66