FV3 Bundle
DRPCGMinimizer.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_DRPCGMINIMIZER_H_
12 #define OOPS_ASSIMILATION_DRPCGMINIMIZER_H_
13 
14 #include <cmath>
15 #include <string>
16 #include <vector>
17 
18 #include "eckit/config/Configuration.h"
25 #include "oops/util/dot_product.h"
26 #include "oops/util/formats.h"
27 #include "oops/util/Logger.h"
28 
29 namespace oops {
30 
31 /// DRPCG Minimizer
32 /*!
33  * \brief Derber-Rosati Preconditioned Conjugate Gradients solver.
34  *
35  * This solver is based on the standard Preconditioned Conjugate
36  * Gradients solver for Ax=b (G. H. Golub and C. F. Van Loan, Matrix
37  * Computations), and on the Derber and Rosati double
38  * PCG algorithm (J. Derber and A. Rosati, 1989, J. Phys. Oceanog. 1333-1347).
39  * For details see S. Gurol, PhD Manuscript, 2013.
40  * It solves \f$ Ax=b\f$ for the particular case \f$ A=B^{-1}+C\f$,
41  * without requiring the application of \f$ B^{-1}\f$. This algorithm
42  * is similar to DRIPCG except it includes standard PCG instead IPCG
43  * and stopping criteria is based on the preconditioner norm.
44  *
45  * A must be square, symmetric, positive definite.
46  *
47  * A preconditioner must be supplied that, given a vector q, returns an
48  * approximation to \f$ (AB)^{-1} q\f$. Possible preconditioning
49  * is detailed in S. Gurol, PhD Manuscript, 2013.
50  * Note that the traditional \f$ B\f$-preconditioning corresponds to
51  * precond=\f$I\f$.
52  *
53  * On entry:
54  * - dx = starting point, \f$ dx_{0} \f$.
55  * - dxh = \f$ B^{-1} dx_{0} \f$.
56  * - rr = \f$ (sum B^-1 dx^{b}_{i} + ) H^T R^{-1} d \f$
57  * - B = \f$ B \f$.
58  * - C = \f$ C \f$.
59  * - precond = preconditioner \f$ F_k \approx (AB)^{-1} \f$.
60  *
61  * On exit, dx will contain the solution \f$ dx \f$ and dxh will contain
62  * \f$ B^{-1} dx\f$.
63  * The return value is the achieved reduction in preconditioned residual norm.
64  *
65  * Iteration will stop if the maximum iteration limit "maxiter" is reached
66  * or if the residual norm reduces by a factor of "tolerance".
67  *
68  * Each matrix must implement a method:
69  * - void multiply(const VECTOR&, VECTOR&) const
70  *
71  * which applies the matrix to the first argument, and returns the
72  * matrix-vector product in the second. (Note: the const is optional, but
73  * recommended.)
74  */
75 
76 // -----------------------------------------------------------------------------
77 
78 template<typename MODEL> class DRPCGMinimizer : public DRMinimizer<MODEL> {
83 
84  public:
85  const std::string classname() const override {return "DRPCGMinimizer";}
86  DRPCGMinimizer(const eckit::Configuration &, const CostFct_ &);
88 
89  private:
90  double solve(CtrlInc_ &, CtrlInc_ &, CtrlInc_ &, const Bmat_ &, const HtRinvH_ &,
91  const double, const double, const int, const double) override;
92 
94 };
95 
96 // =============================================================================
97 
98 template<typename MODEL>
99 DRPCGMinimizer<MODEL>::DRPCGMinimizer(const eckit::Configuration & conf, const CostFct_ & J)
100  : DRMinimizer<MODEL>(J), lmp_(conf)
101 {}
102 
103 // -----------------------------------------------------------------------------
104 
105 template<typename MODEL>
107  const Bmat_ & B, const HtRinvH_ & HtRinvH,
108  const double costJ0Jb, const double costJ0JoJc,
109  const int maxiter, const double tolerance) {
110  // dx increment
111  // dxh B^{-1} dx
112  // rr (sum B^{-1} dx_i^{b} +) G^T H^{-1} d
113 
114  CtrlInc_ qq(dxh);
115  CtrlInc_ pp(dxh);
116  CtrlInc_ hh(dxh);
117  CtrlInc_ zz(dxh);
118  CtrlInc_ pr(dxh);
119  CtrlInc_ r0(dxh);
120  CtrlInc_ ww(dxh);
121 
122  // vectors for re-orthogonalization
123  std::vector<CtrlInc_> vvecs;
124  std::vector<CtrlInc_> zvecs;
125  std::vector<double> scals;
126 
127  // J0
128  const double costJ0 = costJ0Jb + costJ0JoJc;
129 
130  // r_{0}
131  r0 = rr;
132 
133  // r_{0}^T r_{0}
134  Log::info() << "normr0 " << dot_product(rr, rr) << std::endl;
135 
136  // z_{0} = B LMP r_{0}
137  lmp_.multiply(rr, pr);
138  B.multiply(pr, zz);
139  // p_{0} = z_{0}
140  pp = zz;
141  // h_{0} = LMP r_{0}
142  hh = pr;
143 
144  // r_{0}^T z_{0}
145  double dotRr0 = dot_product(rr, zz);
146  double normReduction = 1.0;
147  double rdots = dotRr0;
148  double rdots_old = 0.0;
149 
150  vvecs.push_back(rr);
151  zvecs.push_back(zz);
152  scals.push_back(1.0/dotRr0);
153 
154  Log::info() << std::endl;
155  for (int jiter = 0; jiter < maxiter; ++jiter) {
156  Log::info() << " DRPCG Starting Iteration " << jiter+1 << std::endl;
157 
158  if (jiter > 0) {
159  // beta_{i} = r_{i+1}^T z_{i+1} / r_{i}^T z_{i}
160  double beta = rdots/rdots_old;
161  Log::debug() << "DRPCG beta = " << beta << std::endl;
162 
163  // p_{i+1} = z_{i+1} + beta*p_{i}
164  pp *= beta;
165  pp += zz;
166 
167  // h_{i+1} = LMP r_{i+1} + beta*h_{i}
168  hh *= beta;
169  hh += pr;
170  }
171 
172  // q_{i} = h_{i} + H^T R^{-1} H p_{i}
173  HtRinvH.multiply(pp, qq);
174  qq += hh;
175 
176  // alpha_{i} = r_{i}^T z_{i} / q_{i}^T p_{i}
177  double rho = dot_product(pp, qq);
178  double alpha = rdots/rho;
179 
180  // dx_{i+1} = dx_{i} + alpha * p_{i}
181  dx.axpy(alpha, pp);
182  // dxh_{i+1} = dxh_{i} + alpha * h_{i} ! for diagnosing Jb
183  dxh.axpy(alpha, hh);
184  // r_{i+1} = r_{i} - alpha * q_{i}
185  rr.axpy(-alpha, qq);
186 
187  // Compute the quadratic cost function
188  // J[dx_{i}] = J[0] - 0.5 dx_{i}^T r_{0}
189  double costJ = costJ0 - 0.5 * dot_product(dx, r0);
190  // Jb[dx_{i}] = 0.5 dx_{i}^T f_{i}
191  double costJb = costJ0Jb + 0.5 * dot_product(dx, dxh);
192  // Jo[dx_{i}] + Jc[dx_{i}] = J[dx_{i}] - Jb[dx_{i}]
193  double costJoJc = costJ - costJb;
194 
195  // Re-orthogonalization
196  for (int jj = 0; jj < jiter; ++jj) {
197  double proj = scals[jj] * dot_product(rr, zvecs[jj]);
198  rr.axpy(-proj, vvecs[jj]);
199  }
200 
201  // z_{i+1} = B LMP r_{i+1}
202  lmp_.multiply(rr, pr);
203  B.multiply(pr, zz);
204 
205  // r_{i}^T z_{i}
206  rdots_old = rdots;
207  // r_{i+1}^T z_{i+1}
208  rdots = dot_product(rr, zz);
209 
210  Log::info() << "rdots " << rdots << " iteration " << jiter << std::endl;
211 
212  // r_{i+1}^T z_{i+1} / r_{0}^T z_{0}
213  normReduction = sqrt(rdots/dotRr0);
214 
215  Log::info() << "DRPCG end of iteration " << jiter+1 << std::endl
216  << " Norm reduction (" << std::setw(2) << jiter+1 << ") = "
217  << util::full_precision(normReduction) << std::endl
218  << " Quadratic cost function: J (" << std::setw(2) << jiter+1 << ") = "
219  << util::full_precision(costJ) << std::endl
220  << " Quadratic cost function: Jb (" << std::setw(2) << jiter+1 << ") = "
221  << util::full_precision(costJb) << std::endl
222  << " Quadratic cost function: JoJc(" << std::setw(2) << jiter+1 << ") = "
223  << util::full_precision(costJoJc) << std::endl << std::endl;
224 
225  // Save the pairs for preconditioning
226  lmp_.push(pp, hh, qq, rho);
227 
228  if (normReduction < tolerance) {
229  Log::info() << "DRPCG: Achieved required reduction in residual norm." << std::endl;
230  break;
231  }
232 
233  vvecs.push_back(rr);
234  zvecs.push_back(zz);
235  scals.push_back(1.0/rdots);
236  }
237 
238 // Generate the (second-level) Limited Memory Preconditioner
239  lmp_.update(B);
240 
241  return normReduction;
242 }
243 
244 // -----------------------------------------------------------------------------
245 
246 } // namespace oops
247 
248 #endif // OOPS_ASSIMILATION_DRPCGMINIMIZER_H_
DRPCG Minimizer.
double solve(CtrlInc_ &, CtrlInc_ &, CtrlInc_ &, const Bmat_ &, const HtRinvH_ &, const double, const double, const int, const double) override
real(double_kind), dimension(numint), parameter pr
Definition: mpp_efp.F90:47
Definition: conf.py:1
Cost Function.
Definition: CostFunction.h:56
CostFunction< MODEL > CostFct_
DRPCGMinimizer(const eckit::Configuration &, const CostFct_ &)
HtRinvHMatrix< MODEL > HtRinvH_
const std::string classname() const override
ControlIncrement< MODEL > CtrlInc_
The namespace for the main oops code.
QNewtonLMP< CtrlInc_, Bmat_ > lmp_
void multiply(const CtrlInc_ &dx, CtrlInc_ &dz) const
Definition: HtRinvHMatrix.h:64
logical debug
Definition: mpp.F90:1297
real, parameter r0
Definition: fv_mapz_nlm.F90:41
subroutine, public info(self)
real(fp), parameter, public tolerance
The matrix.
Definition: BMatrix.h:27
BMatrix< MODEL > Bmat_
DR (Derber and Rosati) Minimizers.
Definition: DRMinimizer.h:44
void axpy(const double, const ControlIncrement &)
void multiply(const CtrlInc_ &x, CtrlInc_ &bx) const
Definition: BMatrix.h:33