OOPS
PLanczos.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_PLANCZOS_H_
12 #define OOPS_ASSIMILATION_PLANCZOS_H_
13 
14 #include <cmath>
15 #include <vector>
16 
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 PLanczos.h
25  * \brief Preconditioned Lanczos solver.
26  *
27  * This algorihtm is based on the standard Preconditioned Lanczos
28  * method for solving the linear system Ax = b
29  *
30  * A must be square and symmetric.
31  *
32  * On entry:
33  * - x = starting point, \f$ x_0 \f$.
34  * - b = right hand side.
35  * - A = \f$ A \f$.
36  * - precond = preconditioner \f$ P_k \f$.
37  *
38  * On exit, x will contain the solution \f$ x \f$
39  *
40  * The return value is the achieved reduction in preconditioned residual norm.
41  *
42  * Iteration will stop if the maximum iteration limit "maxiter" is reached
43  * or if the residual norm reduces by a factor of "tolerance".
44  *
45  * VECTOR must implement:
46  * - dot_product
47  * - operator(=)
48  * - operator(+=),
49  * - operator(-=)
50  * - operator(*=) [double * VECTOR],
51  * - axpy
52  *
53  * Each of AMATRIX and PMATRIX must implement a method:
54  * - void multiply(const VECTOR&, VECTOR&) const
55  *
56  * which applies the matrix to the first argument, and returns the
57  * matrix-vector product in the second. (Note: the const is optional, but
58  * recommended.)
59  */
60 
61 template <typename VECTOR, typename AMATRIX, typename PMATRIX>
62 double PLanczos(VECTOR & xx, const VECTOR & bb,
63  const AMATRIX & A, const PMATRIX & precond,
64  const int maxiter, const double tolerance) {
65  VECTOR zz(xx);
66  VECTOR ww(xx);
67 
68  std::vector<VECTOR> vVEC;
69  std::vector<VECTOR> zVEC;
70  // reserve space to avoid extra copies
71  vVEC.reserve(maxiter+1);
72  zVEC.reserve(maxiter+1);
73 
74  Log::debug() << "PLanczos xx = " << xx << std::endl;
75  Log::debug() << "PLanczos bb = " << bb << std::endl;
76 
77  std::vector<double> alphas;
78  std::vector<double> betas;
79  std::vector<double> dd;
80  std::vector<double> yy;
81 
82  // Initial residual r = b - Ax
83  VECTOR rr(bb);
84  double xnrm2 = dot_product(xx, xx);
85  if (xnrm2 > 0.0) {
86  A.multiply(xx, zz);
87  rr -= zz;
88  }
89  Log::debug() << "PLanczos rr = " << rr << std::endl;
90 
91  // z = precond r
92  precond.multiply(rr, zz);
93  Log::debug() << "PLanczos zz = " << zz << std::endl;
94 
95  double normReduction = 1.0;
96  double beta0 = sqrt(dot_product(rr, zz));
97  double beta = 0.0;
98  Log::debug() << "PLanczos beta0 = " << beta0 << std::endl;
99 
100  VECTOR vv(rr);
101  vv *= 1/beta0;
102  zz *= 1/beta0;
103 
104  zVEC.push_back(zz); // zVEC[0] = z_1 ---> required for re-orthogonalization
105  vVEC.push_back(vv); // vVEC[0] = v_1 ---> required for re-orthogonalization
106 
107  Log::debug() << "PLanczos vv = " << vv << std::endl;
108  Log::debug() << "PLanczos zz = " << zz << std::endl;
109 
110  int jiter = 0;
111  Log::info() << std::endl;
112  while (jiter < maxiter) {
113  Log::info() << " PLanczos Starting Iteration " << jiter+1 << std::endl;
114 
115  // w = A z - beta * vold
116  A.multiply(zz, ww); // w = A z
117  Log::debug() << "PLanczos ww = " << ww << std::endl;
118  if (jiter > 0) ww.axpy(-beta, vVEC[jiter-1]);
119 
120  double alpha = dot_product(zz, ww);
121  Log::debug() << "PLanczos alpha = " << alpha << std::endl;
122 
123  ww.axpy(-alpha, vv); // w = w - alpha * v
124  Log::debug() << "PLanczos ww = " << ww << std::endl;
125 
126  // Re-orthogonalization
127  for (int iiter = 0; iiter < jiter; ++iiter) {
128  double proj = dot_product(ww, zVEC[iiter]);
129  ww.axpy(-proj, vVEC[iiter]);
130  }
131  Log::debug() << "PLanczos ww = " << ww << std::endl;
132 
133  precond.multiply(ww, zz); // z = precond w
134  Log::debug() << "PLanczos zz = " << zz << std::endl;
135 
136  beta = sqrt(dot_product(zz, ww));
137  Log::debug() << "PLanczos beta = " << beta << std::endl;
138 
139  vv = ww;
140  vv *= 1/beta;
141  zz *= 1/beta;
142  Log::debug() << "PLanczos vv = " << vv << std::endl;
143  Log::debug() << "PLanczos zz = " << zz << std::endl;
144 
145  zVEC.push_back(zz); // zVEC[jiter+1] = z_jiter
146  vVEC.push_back(vv); // vVEC[jiter+1] = v_jiter
147 
148  alphas.push_back(alpha);
149 
150  if (jiter == 0) {
151  yy.push_back(beta0/alpha);
152  dd.push_back(beta0);
153  } else {
154  // Solve the tridiagonal system T_jiter y_jiter = beta0 * e_1
155  dd.push_back(beta0*dot_product(zVEC[0], vv));
156  TriDiagSolve(alphas, betas, dd, yy);
157  }
158 
159  // Gradient norm in precond metric --> sqrt(r'z) --> beta * y(jiter)
160  double rznorm = beta*std::abs(yy[jiter]);
161  Log::debug() << "PLanczos rznorm = " << rznorm << std::endl;
162 
163  normReduction = rznorm/beta0;
164 
165  betas.push_back(beta);
166 
167  Log::info() << "PLanczos end of iteration " << jiter+1 << ". Norm reduction= "
168  << util::full_precision(normReduction) << std::endl << std::endl;
169 
170  ++jiter;
171 
172  if (normReduction < tolerance) {
173  Log::info() << "PLanczos: Achieved required reduction in residual norm." << std::endl;
174  break;
175  }
176  }
177  Log::debug() << "PLanczos jiter = " << jiter << std::endl;
178 
179  // Calculate the solution (xh = Binv x)
180  for (int iiter = 0; iiter < jiter; ++iiter) {
181  xx.axpy(yy[iiter], zVEC[iiter]);
182  }
183 
184  Log::info() << "PLanczos: end" << std::endl;
185 
186  return normReduction;
187 }
188 
189 } // namespace oops
190 
191 #endif // OOPS_ASSIMILATION_PLANCZOS_H_
oops
The namespace for the main oops code.
Definition: ErrorCovarianceL95.cc:22
oops::PLanczos
double PLanczos(VECTOR &xx, const VECTOR &bb, const AMATRIX &A, const PMATRIX &precond, const int maxiter, const double tolerance)
Definition: PLanczos.h:62
oops::TriDiagSolve
void TriDiagSolve(const std::vector< double > &diag, const std::vector< double > &sub, const std::vector< double > &rhs, std::vector< double > &sol)
Definition: oops/assimilation/TriDiagSolve.h:25
TriDiagSolve.h