FV3 Bundle
RPLanczosMinimizer.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_RPLANCZOSMINIMIZER_H_
12 #define OOPS_ASSIMILATION_RPLANCZOSMINIMIZER_H_
13 
14 #include <cmath>
15 #include <string>
16 #include <vector>
17 
24 #include "oops/util/dot_product.h"
25 #include "oops/util/formats.h"
26 #include "oops/util/Logger.h"
27 
28 namespace oops {
29 
30 /// RLanczos Minimizer
31 /*!
32  * \brief Augmented Restricted Lanczos method. It is the Lanczos version
33  * of RPCG.
34  *
35  * This solver is based on the algorithm from Gurol, PhD Manuscript,
36  * 2013. It performs minimization in the observation space.
37  *
38  * It solves the linear system \f$ (I + R^{-1}HBH^T) lambda = H^T R^{-1}d \f$
39  * with \f$ HBH^T \f$ inner-product in the augmented observation space.
40  *
41  * Note that the traditional \f$ B\f$-preconditioning in model space
42  * corresponds to \f$I\f$ for this algorithm.
43  *
44  * A second-level preconditioner, \f$ G \f$, must be symmetric and
45  * positive definite with respect to \f$ HBH^T \f$ inner-product.
46  * Possible preconditioning is detailed in S. Gurol, PhD Manuscript, 2013.
47  *
48  * On entry:
49  * - vv = starting point, \f$ v_0 \f$.
50  * - vvp = starting point augmented part, \f$ vp_0 \f$
51  * - rr = right hand side.
52  * - aa = \f$ H (xb - xk) \f$
53  * - sigma = \f$ (xb - xk)^T B^{-1} (xb - xk)\f$.
54  * - HBHt = \f$ HBH^T \f$.
55  * - Rinv = \f$ R^{-1} \f$.
56  * - G = preconditioner \f$ G \f$.
57  *
58  * On exit, vv and vvp will contain the solution \f$ lambda = [vv; vp] \f$
59  *
60  * The return value is the achieved reduction in preconditioned residual norm.
61  *
62  * Iteration will stop if the maximum iteration limit "maxiter" is reached
63  * or if the preconditioned residual norm reduces by a factor of "tolerance".
64  */
65 
66 // -----------------------------------------------------------------------------
67 
68 template<typename MODEL> class RPLanczosMinimizer : public DualMinimizer<MODEL> {
73 
74  public:
75  const std::string classname() const override {return "RPLanczosMinimizer";}
76  RPLanczosMinimizer(const eckit::Configuration &, const CostFct_ & J): DualMinimizer<MODEL>(J) {}
78 
79  private:
80  double solve(Dual_ &, double &, Dual_ &, const HBHt_ &, const Rinv_ &,
81  const int &, const double &, Dual_ &, const double &) override;
82 };
83 
84 // =============================================================================
85 
86 template<typename MODEL>
87 double RPLanczosMinimizer<MODEL>::solve(Dual_ & vv, double & vvp, Dual_ & rr,
88  const HBHt_ & HBHt, const Rinv_ & Rinv,
89  const int & maxiter, const double & tolerance,
90  Dual_ & dy, const double & sigma) {
91  IdentityMatrix<Dual_> precond;
92 
93  Dual_ zz(vv);
94  Dual_ ww(vv);
95  Dual_ tt(vv);
96  Dual_ vold(vv);
97  Dual_ v(vv);
98 
99  // augmented part of the vectors
100  double rrp = 1.0;
101  double zzp;
102  double wwp;
103  double ttp = 0.0;
104  double voldp = 0.0;
105  double vp = 1.0;
106 
107  std::vector<Dual_> vVEC; // required for re-orthogonalization
108  std::vector<Dual_> tVEC; // required for re-orthogonalization
109  std::vector<Dual_> zVEC; // required for solution
110  std::vector<double> vpVEC;
111  std::vector<double> tpVEC;
112  std::vector<double> zpVEC;
113  std::vector<double> alphas;
114  std::vector<double> betas;
115  std::vector<double> y;
116  std::vector<double> d;
117 
118  // zzaug = Gaug rraug
119  precond.multiply(rr, zz);
120  zzp = rrp;
121 
122  // ttaug = HBHtaug zzaug
123  HBHt.multiply(zz, tt);
124  tt.axpy(zzp, dy);
125  ttp = dot_product(dy, zz) + sigma*zzp;
126 
127  double normReduction = 1.0;
128  double beta0 = sqrt(dot_product(rr, tt) + rrp*ttp);
129  double beta = 0.0;
130 
131  vold.zero();
132  v = rr;
133  vp = rrp;
134  v *= 1/beta0;
135  vp *= 1/beta0;
136  tt *= 1/beta0;
137  zz *= 1/beta0;
138  ttp *= 1/beta0;
139  zzp *= 1/beta0;
140 
141  vVEC.clear();
142  zVEC.clear();
143  tVEC.clear();
144  vpVEC.clear();
145  zpVEC.clear();
146  tpVEC.clear();
147 
148  betas.clear();
149  alphas.clear();
150 
151  vVEC.push_back(v);
152  zVEC.push_back(zz);
153  tVEC.push_back(tt);
154  vpVEC.push_back(vp);
155  zpVEC.push_back(zzp);
156  tpVEC.push_back(ttp);
157 
158  int jiter;
159  Log::info() << std::endl;
160  for (jiter = 0; jiter < maxiter; ++jiter) {
161  Log::info() << "RPLanczos Starting Iteration " << jiter+1 << std::endl;
162 
163  // ww = (RinvHBHt + I) zz - beta * vold
164  Rinv.multiply(tt, ww);
165  ww += zz;
166  wwp = zzp;
167  ww.axpy(-beta, vold);
168  wwp -= beta*voldp;
169 
170  double alpha = dot_product(tt, ww) + ttp*wwp;
171 
172  ww.axpy(-alpha, v); // w = w - alpha * v
173  wwp -= alpha*vp;
174 
175  // Re-orthogonalization
176  for (int iiter = 0; iiter < jiter; ++iiter) {
177  double proj = dot_product(ww, tVEC[iiter]) + wwp * tpVEC[iiter];
178  ww.axpy(-proj, vVEC[iiter]);
179  wwp -= proj * vpVEC[iiter];
180  }
181 
182  // wwaug = Gaug zzaug
183  precond.multiply(ww, zz);
184  zzp = wwp;
185 
186  // ttaug = HBHtaug zzaug
187  HBHt.multiply(zz, tt);
188  tt.axpy(zzp, dy);
189  ttp = dot_product(dy, zz) + sigma*zzp;
190 
191  beta = sqrt(dot_product(tt, ww) + ttp*wwp);
192 
193  vold = v;
194  voldp = vp;
195  v = ww;
196  vp = wwp;
197  v *= 1/beta;
198  vp *= 1/beta;
199  tt *= 1/beta;
200  zz *= 1/beta;
201  ttp *= 1/beta;
202  zzp *= 1/beta;
203 
204  vVEC.push_back(v);
205  zVEC.push_back(zz);
206  tVEC.push_back(tt);
207  vpVEC.push_back(vp);
208  zpVEC.push_back(zzp);
209  tpVEC.push_back(ttp);
210 
211  alphas.push_back(alpha);
212 
213  y.clear();
214  if (jiter == 0) {
215  y.push_back(beta0/alpha);
216  } else {
217  // Solve the tridiagonal system T_jiter y_jiter = beta0 * e_1
218  d.clear();
219  for (int iiter = 0; iiter <= jiter; ++iiter) {
220  d.push_back(beta0*(dot_product(tVEC[0], vVEC[iiter]) + tpVEC[0]*vpVEC[iiter]));
221  }
222  TriDiagSolve(alphas, betas, d, y);
223  }
224 
225  // Gradient norm in precond metric --> sqrt(r't) --> beta * y(jiter)
226  double rznorm = beta*std::abs(y[jiter]);
227 
228  normReduction = rznorm/beta0;
229 
230  betas.push_back(beta);
231 
232  Log::info() << "RPLanczos end of iteration " << jiter+1 << ". Norm reduction= "
233  << util::full_precision(normReduction) << std::endl << std::endl;
234 
235  if (normReduction < tolerance) {
236  Log::info() << "RPLanczos: Achieved required reduction in residual norm." << std::endl;
237  break;
238  }
239  }
240 
241  // Calculate the solution (xh = Binv x)
242  for (int iiter = 0; iiter < jiter; ++iiter) {
243  vv.axpy(y[iiter], zVEC[iiter]);
244  vvp += y[iiter]*zpVEC[iiter];
245  }
246 
247  Log::info() << "RPLanczos: end" << std::endl;
248 
249  return normReduction;
250 }
251 
252 // -----------------------------------------------------------------------------
253 
254 } // namespace oops
255 
256 #endif // OOPS_ASSIMILATION_RPLANCZOSMINIMIZER_H_
real(fp), parameter ttp
Definition: ufo_aod_mod.F90:28
void multiply(const Dual_ &dx, Dual_ &dy) const
Definition: RinvMatrix.h:36
RinvMatrix< MODEL > Rinv_
Container of dual space vectors for all terms of the cost function.
Definition: DualVector.h:34
const std::string classname() const override
RLanczos Minimizer.
Cost Function.
Definition: CostFunction.h:56
integer, parameter sigma
Flags to indicate where climatology pressure levels are pressure or sigma levels. ...
CostFunction< MODEL > CostFct_
void TriDiagSolve(const std::vector< double > &diag, const std::vector< double > &sub, const std::vector< double > &rhs, std::vector< double > &sol)
Definition: TriDiagSolve.h:18
Dual Minimizer.
Definition: DualMinimizer.h:40
RPLanczosMinimizer(const eckit::Configuration &, const CostFct_ &J)
The namespace for the main oops code.
The matrix.
Definition: HBHtMatrix.h:33
subroutine, public info(self)
real(fp), parameter, public tolerance
DualVector< MODEL > Dual_
double solve(Dual_ &, double &, Dual_ &, const HBHt_ &, const Rinv_ &, const int &, const double &, Dual_ &, const double &) override
void multiply(const VECTOR &a, VECTOR &b) const
Identity matrix.
The matrix.
Definition: RinvMatrix.h:29
void multiply(const Dual_ &dy, Dual_ &dz) const
Definition: HBHtMatrix.h:62
HBHtMatrix< MODEL > HBHt_
void axpy(const double, const DualVector &)
Definition: DualVector.h:213