OOPS
DRIPCGMinimizer.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_DRIPCGMINIMIZER_H_
12 #define OOPS_ASSIMILATION_DRIPCGMINIMIZER_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 /// Derber-Rosati IPCG Minimizer
31 /*!
32  * \brief Derber-Rosati Inexact-Preconditioned Conjugate Gradients solver.
33  *
34  * This solver is based on the Golub-Ye Inexact-Preconditioned Conjugate
35  * Gradients solver for Ax=b (G.H. Golub and Q. Ye 1999/00,
36  * SIAM J. Sci. Comput. 21(4) 1305-1320), and on the Derber and Rosati double
37  * PCG algorithm (J. Derber and A. Rosati, 1989, J. Phys. Oceanog. 1333-1347).
38  * It solves \f$ Ax=b\f$ for the particular case \f$ A=B^{-1}+C\f$,
39  * without requiring the application of \f$ B^{-1}\f$.
40  *
41  * A must be square, symmetric, positive definite.
42  *
43  * A preconditioner must be supplied that, given a vector q, returns an
44  * approximation to \f$ (AB)^{-1} q\f$. The preconditioner can be variable.
45  * Note that the traditional \f$ B\f$-preconditioning corresponds to
46  * precond=\f$I\f$.
47  *
48  * On entry:
49  * - x = starting point, \f$ X_0 \f$.
50  * - xh = \f$ B^{-1} x_0\f$.
51  * - b = right hand side.
52  * - B = \f$ B \f$.
53  * - C = \f$ C \f$.
54  * - precond = preconditioner \f$ F_k \approx (AB)^{-1} \f$.
55  *
56  * On exit, x will contain the solution \f$ x \f$ and xh will contain
57  * \f$ B^{-1} x\f$.
58  * The return value is the achieved reduction in residual norm.
59  *
60  * Iteration will stop if the maximum iteration limit "maxiter" is reached
61  * or if the residual norm reduces by a factor of "tolerance".
62  *
63  * Each of BMATRIX, CMATRIX and PMATRIX must implement a method:
64  * - void multiply(const VECTOR&, VECTOR&) const
65  *
66  * which applies the matrix to the first argument, and returns the
67  * matrix-vector product in the second. (Note: the const is optonal, but
68  * recommended.)
69  */
70 
71 // -----------------------------------------------------------------------------
72 
73 template<typename MODEL, typename OBS> class DRIPCGMinimizer : public DRMinimizer<MODEL, OBS> {
78 
79  public:
80  const std::string classname() const override {return "DRIPCGMinimizer";}
81  DRIPCGMinimizer(const eckit::Configuration &, const CostFct_ &);
83 
84  private:
85  double solve(CtrlInc_ &, CtrlInc_ &, CtrlInc_ &, const Bmat_ &, const HtRinvH_ &,
86  const double, const double, const int, const double) override;
87 
89 };
90 
91 // =============================================================================
92 
93 template<typename MODEL, typename OBS>
94 DRIPCGMinimizer<MODEL, OBS>::DRIPCGMinimizer(const eckit::Configuration & conf, const CostFct_ & J)
95  : DRMinimizer<MODEL, OBS>(J), lmp_(conf)
96 {}
97 
98 // -----------------------------------------------------------------------------
99 
100 template<typename MODEL, typename OBS>
102  const Bmat_ & B, const HtRinvH_ & HtRinvH,
103  const double costJ0Jb, const double costJ0JoJc,
104  const int maxiter, const double tolerance) {
105  CtrlInc_ ap(xh);
106  CtrlInc_ pp(xh);
107  CtrlInc_ ph(xh);
108  CtrlInc_ ss(xh);
109  CtrlInc_ sh(xh);
110  CtrlInc_ dr(xh);
111  CtrlInc_ r0(xh);
112 
113  std::vector<CtrlInc_> vvecs; // for re-orthogonalization
114  std::vector<CtrlInc_> zvecs; // for re-orthogonalization
115  std::vector<double> scals; // for re-orthogonalization
116  // reserve space in vectors to avoid extra copies
117  vvecs.reserve(maxiter+1);
118  zvecs.reserve(maxiter+1);
119  scals.reserve(maxiter+1);
120 
121  const double costJ0 = costJ0Jb + costJ0JoJc;
122 
123  r0 = rr;
124 
125  lmp_.multiply(rr, sh);
126  B.multiply(sh, ss);
127 
128  double dotRr0 = dot_product(rr, rr);
129  double dotSr0 = dot_product(rr, ss);
130  double normReduction = 1.0;
131  double rdots = dotSr0;
132  double rdots_old = dotSr0;
133 
134  vvecs.push_back(rr);
135  zvecs.push_back(ss);
136  scals.push_back(1.0/dotSr0);
137 
138  Log::info() << std::endl;
139  for (int jiter = 0; jiter < maxiter; ++jiter) {
140  Log::info() << " DRIPCG Starting Iteration " << jiter+1 << std::endl;
141 
142  if (jiter == 0) {
143  pp = ss;
144  ph = sh;
145  } else {
146  dr -= rr; // dr=oldr-r
147  double beta = -dot_product(ss, dr)/rdots_old;
148 
149  pp *= beta;
150  pp += ss; // p = s + beta*p
151 
152  ph *= beta;
153  ph += sh; // ph = sh + beta*ph
154  }
155 
156  HtRinvH.multiply(pp, ap);
157  ap += ph;
158 
159  dr = rr;
160 
161  double rho = dot_product(pp, ap);
162  double alpha = rdots/rho;
163  Log::info() << "DRIPCGMinimizer rho = " << rho << ", alpha = " << alpha << std::endl;
164 
165  xx.axpy(alpha, pp); // xx = xx + alpha*pp
166  xh.axpy(alpha, ph); // xh = xh + alpha*ph
167  rr.axpy(-alpha, ap); // rr = rr - alpha*ap
168 
169  // Compute the quadratic cost function
170  double costJ = costJ0 - 0.5 * dot_product(xx, r0);
171  double costJb = costJ0Jb + 0.5 * dot_product(xx, xh);
172  double costJoJc = costJ - costJb;
173 
174  // Re-orthogonalization
175  for (int jj = 0; jj < jiter; ++jj) {
176  double proj = scals[jj] * dot_product(rr, zvecs[jj]);
177  rr.axpy(-proj, vvecs[jj]);
178  }
179 
180  lmp_.multiply(rr, sh);
181  B.multiply(sh, ss);
182 
183  rdots_old = rdots;
184  rdots = dot_product(rr, ss);
185 // There is an issue where in some cases ss goes to zero before rr. The convergence
186 // check below only checks for rr. Leaving the commented lines here for further invertigation.
187 // double sdots = dot_product(ss, ss);
188 // double rdotr = dot_product(rr, rr);
189 // Log::info() << "DRIPCGMinimizer rdots = " << rdots
190 // << ", sdots = " << sdots << ", rdotr = " << rdotr << std::endl;
191  normReduction = sqrt(dot_product(rr, rr)/dotRr0);
192 
193  Log::info() << "DRIPCG end of iteration " << jiter+1 << ". Norm reduction= "
194  << util::full_precision(normReduction) << std::endl
195  << " Quadratic cost function: J (" << jiter+1 << ") = "
196  << util::full_precision(costJ) << std::endl
197  << " Quadratic cost function: Jb (" << jiter+1 << ") = "
198  << util::full_precision(costJb) << std::endl
199  << " Quadratic cost function: JoJc(" << jiter+1 << ") = "
200  << util::full_precision(costJoJc) << std::endl << std::endl;
201 
202  // Save the pairs for preconditioning
203  lmp_.push(pp, ph, ap, rho);
204 
205  if (normReduction < tolerance) {
206  Log::info() << "DRIPCG: Achieved required reduction in residual norm." << std::endl;
207  break;
208  }
209 
210  vvecs.push_back(rr);
211  zvecs.push_back(ss);
212  scals.push_back(1.0/rdots);
213  }
214 
215 // Generate the (second-level) Limited Memory Preconditioner
216  lmp_.update(B);
217 
218  return normReduction;
219 }
220 
221 // -----------------------------------------------------------------------------
222 
223 } // namespace oops
224 
225 #endif // OOPS_ASSIMILATION_DRIPCGMINIMIZER_H_
DRMinimizer.h
oops
The namespace for the main oops code.
Definition: ErrorCovarianceL95.cc:22
HtRinvHMatrix.h
oops::BMatrix::multiply
void multiply(const CtrlInc_ &x, CtrlInc_ &bx) const
Definition: BMatrix.h:33
oops::DRIPCGMinimizer::lmp_
QNewtonLMP< CtrlInc_, Bmat_ > lmp_
Definition: DRIPCGMinimizer.h:88
CostFunction.h
oops::QNewtonLMP
Definition: QNewtonLMP.h:40
oops::DRIPCGMinimizer::~DRIPCGMinimizer
~DRIPCGMinimizer()
Definition: DRIPCGMinimizer.h:82
oops::ControlIncrement
Definition: ControlIncrement.h:46
oops::DRIPCGMinimizer::classname
const std::string classname() const override
Definition: DRIPCGMinimizer.h:80
QNewtonLMP.h
oops::DRIPCGMinimizer::DRIPCGMinimizer
DRIPCGMinimizer(const eckit::Configuration &, const CostFct_ &)
Definition: DRIPCGMinimizer.h:94
oops::DRIPCGMinimizer::CtrlInc_
ControlIncrement< MODEL, OBS > CtrlInc_
Definition: DRIPCGMinimizer.h:76
oops::HtRinvHMatrix
The matrix.
Definition: HtRinvHMatrix.h:35
BMatrix.h
oops::DRMinimizer
DR (Derber and Rosati) Minimizers.
Definition: DRMinimizer.h:44
oops::DRIPCGMinimizer
Derber-Rosati IPCG Minimizer.
Definition: DRIPCGMinimizer.h:73
oops::DRIPCGMinimizer::CostFct_
CostFunction< MODEL, OBS > CostFct_
Definition: DRIPCGMinimizer.h:75
oops::DRIPCGMinimizer::HtRinvH_
HtRinvHMatrix< MODEL, OBS > HtRinvH_
Definition: DRIPCGMinimizer.h:77
oops::DRIPCGMinimizer::solve
double solve(CtrlInc_ &, CtrlInc_ &, CtrlInc_ &, const Bmat_ &, const HtRinvH_ &, const double, const double, const int, const double) override
Definition: DRIPCGMinimizer.h:101
ControlIncrement.h
oops::BMatrix
The matrix.
Definition: BMatrix.h:27
oops::CostFunction
Cost Function.
Definition: CostFunction.h:53
oops::DRIPCGMinimizer::Bmat_
BMatrix< MODEL, OBS > Bmat_
Definition: DRIPCGMinimizer.h:74
oops::HtRinvHMatrix::multiply
void multiply(const CtrlInc_ &dx, CtrlInc_ &dz) const
Definition: HtRinvHMatrix.h:60
oops::ControlIncrement::axpy
void axpy(const double, const ControlIncrement &)
Definition: ControlIncrement.h:196