FV3 Bundle
FullGMRES.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_FULLGMRES_H_
12 #define OOPS_ASSIMILATION_FULLGMRES_H_
13 
14 #include <cmath>
15 #include <iostream>
16 #include <vector>
17 
20 #include "oops/util/dot_product.h"
21 #include "oops/util/formats.h"
22 #include "oops/util/Logger.h"
23 
24 namespace oops {
25 
26 /*! \file FullGMRES.h
27  * \brief FullGMRES solver for Ax=b.
28  *
29  * GMRES solver for Ax=b.(based on implementation following
30  * Saad-Schultz and C. T. Kelley, July 10, 1994)
31 
32  * A must be square, but need not be symmetric.
33  * A preconditioner must be supplied that, given a
34  * vector q, returns an approximate solution of Ap=q.
35  *
36  * On entry:
37  * - x = starting point, \f$ X_0 \f$.
38  * - b = right hand side.
39  * - A = \f$ A \f$.
40  * - precond = preconditioner \f$ F_k \approx (A)^{-1} \f$.
41  * - maxiter = maximum number of iterations
42  * - tol = error tolerance
43  *
44  * On exit, x will contain the solution.
45  * The return value is the achieved reduction in residual norm.
46  *
47  * Iteration will stop if the maximum iteration limit "maxiter" is reached
48  * or if the residual norm reduces by a factor of "tolerance".
49  *
50  * VECTOR must implement:
51  * - dot_product
52  * - operator(=)
53  * - operator(+=),
54  * - operator(-=)
55  * - operator(*=) [double * VECTOR],
56  * - axpy
57  *
58  * AMATRIX and PMATRIX must implement a method:
59  * - void multiply(const VECTOR&, VECTOR&) const
60  *
61  * which applies the matrix to the first argument, and returns the
62  * matrix-vector product in the second. (Note: the const is optional, but
63  * recommended.)
64  */
65 
66 template <typename VECTOR, typename AMATRIX, typename PMATRIX>
67 double FullGMRES(VECTOR & xx, const VECTOR & bb, const AMATRIX & A,
68  const PMATRIX & precond, const int maxiter,
69  const double tolerance, std::vector<VECTOR> & pqVEC,
70  std::vector<VECTOR> & xyVEC) {
71  std::vector<VECTOR> VV;
72  std::vector< std::vector<double> > H;
73  std::vector<double> cs(maxiter+1, 0);
74  std::vector<double> sn(maxiter+1, 0);
75  std::vector<double> ss;
76  std::vector<double> yy(maxiter+1, 0);
77 
78  VECTOR ww(xx);
79  VECTOR zz(xx);
80 
81  VECTOR rr(bb);
82  double xnrm2 = dot_product(xx, xx);
83  if (xnrm2 != 0) {
84  A.multiply(xx, ww);
85  rr -= ww; // r = b - Ax
86  }
87 
88  precond.multiply(rr, zz);
89 
90  double znrm2 = sqrt(dot_product(zz, zz));
91  double normReduction = 1.0;
92 
93  zz *= 1/znrm2;
94  VV.push_back(zz);
95  ss.push_back(znrm2);
96 
97  // Initialiaze (maxiter + 1) by maxiter matrix H
98  H.resize(maxiter);
99  for (int ii = 0; ii <= maxiter-1; ii++) {
100  H[ii].resize(maxiter + 1);
101  for (int jj = 0; jj <= maxiter; jj++) {
102  H[ii][jj] = 0;
103  }
104  }
105 
106  pqVEC.clear();
107  xyVEC.clear();
108 
109  int jiter;
110  // FullGMRES iteration
111  Log::info() << std::endl;
112  for (jiter = 0; jiter < maxiter; ++jiter) {
113  Log::info() << " FullGMRES Starting Iteration " << jiter+1 << std::endl;
114 
115  A.multiply(VV[jiter], zz);
116  precond.multiply(zz, ww);
117  if (jiter > 1) {
118  xyVEC.push_back(VV[jiter]);
119  pqVEC.push_back(zz);
120  }
121 
122  double avnrm2 = sqrt(dot_product(ww, ww));
123 
124  // Modified Gram-Schmidt
125  for (int jj = 0; jj <= jiter; ++jj) {
126  H[jiter][jj] = dot_product(VV[jj], ww);
127  ww.axpy(-H[jiter][jj], VV[jj]);
128  }
129 
130  H[jiter][jiter+1] = sqrt(dot_product(ww, ww));
131 
132  double av2nrm2 = H[jiter][jiter+1];
133 
134  // Re-orthogonalize if necessary
135  if (avnrm2 + 0.001*av2nrm2 == avnrm2) {
136  for (int jj = 0; jj <= jiter; ++jj) {
137  double hr = dot_product(VV[jj], ww);
138  H[jiter][jj] += hr;
139  ww.axpy(-hr, VV[jj]);
140  }
141  H[jiter][jiter+1] = sqrt(dot_product(ww, ww));
142  }
143 
144  // Check breakdown
145  if (H[jiter][jiter+1] != 0.0) {
146  ww *= 1/H[jiter][jiter+1];
147  }
148 
149  VV.push_back(ww);
150 
151  if (jiter > 0) {
152  // Apply Givens Rotation
153  for (int jj = 0; jj < jiter; ++jj) {
154  double temp = cs[jj]*H[jiter][jj] + sn[jj]*H[jiter][jj+1];
155  H[jiter][jj+1] = -sn[jj]*H[jiter][jj] + cs[jj]*H[jiter][jj+1];
156  H[jiter][jj] = temp;
157  }
158  }
159 
160  // Compute Givens rotation matrix parameters
161  rotmat(H[jiter][jiter], H[jiter][jiter+1], cs[jiter], sn[jiter]);
162 
163  H[jiter][jiter] = cs[jiter]*H[jiter][jiter] + sn[jiter]*H[jiter][jiter+1];
164  H[jiter][jiter+1] = 0.0;
165 
166  double temp = cs[jiter]*ss[jiter];
167  ss.push_back(-sn[jiter]*ss[jiter]);
168  ss[jiter] = temp;
169 
170  normReduction = std::abs(ss[jiter+1])/znrm2;
171  Log::info() << "FullGMRES end of iteration " << jiter+1 << ". PNorm reduction= "
172  << util::full_precision(normReduction) << std::endl << std::endl;
173 
174  if (normReduction <= tolerance) {
175  Log::info() << "FullGMRES: Achieved required reduction in presidual norm." << std::endl;
176  jiter += 1;
177  break;
178  }
179  }
180 
181  // Calculate the solution
182  UpTriSolve(H, ss, yy, jiter);
183  for (int jj = 0; jj < jiter; ++jj) {
184  xx.axpy(yy[jj], VV[jj]);
185  }
186 
187  return normReduction;
188 }
189 
190 } // namespace oops
191 
192 #endif // OOPS_ASSIMILATION_FULLGMRES_H_
real, dimension(:,:), allocatable, private bb
Definition: tridiagonal.F90:75
Compute the Givens rotation matrix parameters.
void rotmat(const double &a, const double &b, double &c, double &s)
Definition: rotmat.h:22
double FullGMRES(VECTOR &xx, const VECTOR &bb, const AMATRIX &A, const PMATRIX &precond, const int maxiter, const double tolerance, std::vector< VECTOR > &pqVEC, std::vector< VECTOR > &xyVEC)
Definition: FullGMRES.h:67
Solves the upper triangular system sol = H \ rhs.
The namespace for the main oops code.
subroutine, public info(self)
real(fp), parameter, public tolerance
void UpTriSolve(const std::vector< std::vector< double > > &H, const std::vector< double > &rhs, std::vector< double > &sol, const int &dim)
Definition: UpTriSolve.h:22