FV3 Bundle
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> class DRIPCGMinimizer : public DRMinimizer<MODEL> {
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>
94 DRIPCGMinimizer<MODEL>::DRIPCGMinimizer(const eckit::Configuration & conf, const CostFct_ & J)
95  : DRMinimizer<MODEL>(J), lmp_(conf)
96 {}
97 
98 // -----------------------------------------------------------------------------
99 
100 template<typename MODEL>
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_ ww(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 
117  lmp_.multiply(rr, sh);
118  B.multiply(sh, ss);
119 
120  double dotRr0 = dot_product(rr, rr);
121  double dotSr0 = dot_product(rr, ss);
122  double normReduction = 1.0;
123  double rdots = dotSr0;
124  double rdots_old = dotSr0;
125 
126  vvecs.push_back(rr);
127  zvecs.push_back(ss);
128  scals.push_back(1.0/dotSr0);
129 
130  Log::info() << std::endl;
131  for (int jiter = 0; jiter < maxiter; ++jiter) {
132  Log::info() << " DRIPCG Starting Iteration " << jiter+1 << std::endl;
133 
134  if (jiter == 0) {
135  pp = ss;
136  ph = sh;
137  } else {
138  dr -= rr; // dr=oldr-r
139  double beta = -dot_product(ss, dr)/rdots_old;
140 
141  pp *= beta;
142  pp += ss; // p = s + beta*p
143 
144  ph *= beta;
145  ph += sh; // ph = sh + beta*ph
146  }
147 
148  HtRinvH.multiply(pp, ap);
149  ap += ph;
150 
151  dr = rr;
152 
153  double rho = dot_product(pp, ap);
154  double alpha = rdots/rho;
155 
156  xx.axpy(alpha, pp); // xx = xx + alpha*pp
157  xh.axpy(alpha, ph); // xh = xh + alpha*ph
158  rr.axpy(-alpha, ap); // rr = rr - alpha*ap
159 
160  // Re-orthogonalization
161  for (int jj = 0; jj < jiter; ++jj) {
162  double proj = scals[jj] * dot_product(rr, zvecs[jj]);
163  rr.axpy(-proj, vvecs[jj]);
164  }
165 
166  lmp_.multiply(rr, sh);
167  B.multiply(sh, ss);
168 
169  rdots_old = rdots;
170  rdots = dot_product(rr, ss);
171  normReduction = sqrt(dot_product(rr, rr)/dotRr0);
172 
173  Log::info() << "DRIPCG end of iteration " << jiter+1 << ". Norm reduction= "
174  << util::full_precision(normReduction) << std::endl << std::endl;
175 
176  // Save the pairs for preconditioning
177  lmp_.push(pp, ph, ap, rho);
178 
179  if (normReduction < tolerance) {
180  Log::info() << "DRIPCG: Achieved required reduction in residual norm." << std::endl;
181  break;
182  }
183 
184  vvecs.push_back(rr);
185  zvecs.push_back(ss);
186  scals.push_back(1.0/rdots);
187  }
188 
189 // Generate the (second-level) Limited Memory Preconditioner
190  lmp_.update(B);
191 
192  return normReduction;
193 }
194 
195 // -----------------------------------------------------------------------------
196 
197 } // namespace oops
198 
199 #endif // OOPS_ASSIMILATION_DRIPCGMINIMIZER_H_
const std::string classname() const override
QNewtonLMP< CtrlInc_, Bmat_ > lmp_
Definition: conf.py:1
ControlIncrement< MODEL > CtrlInc_
BMatrix< MODEL > Bmat_
Cost Function.
Definition: CostFunction.h:56
Derber-Rosati IPCG Minimizer.
The namespace for the main oops code.
HtRinvHMatrix< MODEL > HtRinvH_
void multiply(const CtrlInc_ &dx, CtrlInc_ &dz) const
Definition: HtRinvHMatrix.h:64
subroutine, public info(self)
DRIPCGMinimizer(const eckit::Configuration &, const CostFct_ &)
real(fp), parameter, public tolerance
The matrix.
Definition: BMatrix.h:27
CostFunction< MODEL > CostFct_
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
double solve(CtrlInc_ &, CtrlInc_ &, CtrlInc_ &, const Bmat_ &, const HtRinvH_ &, const double, const double, const int, const double) override