FV3 Bundle
SaddlePointLMPMatrix.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_SADDLEPOINTLMPMATRIX_H_
12 #define OOPS_ASSIMILATION_SADDLEPOINTLMPMATRIX_H_
13 
14 #include <Eigen/Dense>
15 #include <iostream>
16 #include <vector>
17 
18 #include <boost/noncopyable.hpp>
19 #include <boost/scoped_ptr.hpp>
20 
29 
30 namespace oops {
31 
32  /// The preconditioner for the saddle-point minimizer.
33  /*!
34  * The preconditioner is obtained by using low-rank updates.
35  * Let us define the matrices:
36  *
37  * \f$ R = [ 0 Rp ], G = [ Zinv*Rp' 0 ] \f$
38  * \f$ [ Rq 0 ] [ 0 Zinv'*Rq' ] \f$
39  *
40  * \f$ F = I + G*P0inv*R \f$
41  *
42  * where \f$ P0 \f$ is the initial preconditioner and \f$ I \f$ is the
43  * identity matrix of order 2.
44  *
45  * Then the preconditioner is updated from
46  *
47  * \f$ Pk = P0inv - P0inv*R*Finv*G*P0inv \f$
48  *
49  * The solvers represent matrices as objects that implement a "multiply"
50  * method. This class defines objects that apply the saddle-point matrix.
51  */
52 
53 // -----------------------------------------------------------------------------
54 
55 template<typename MODEL>
56 class SaddlePointLMPMatrix : private boost::noncopyable {
63 
64  public:
65  explicit SaddlePointLMPMatrix(const CostFct_ & j);
66 
67  void setup(const std::vector<SPVector_> &, const std::vector<SPVector_> &);
68 
69  const int & getk() const {return nvec_;}
70 
71  void multiply(const SPVector_ &, SPVector_ &) const;
72 
73  private:
74  void Pinitmultiply(const SPVector_ &, SPVector_ &) const;
75 
76  void Gmultiply(const SPVector_ &, Eigen::VectorXd &) const;
77 
78  void Rmultiply(Eigen::VectorXd &, SPVector_ &) const;
79 
80  void Fmultiply(Eigen::VectorXd &, Eigen::VectorXd &) const;
81 
82  const CostFctWeak_ & j_;
83  const bool idmodel_;
84  std::vector<SPVector_> xyVEC_;
85  std::vector<SPVector_> pqVEC_;
86  std::vector<LagVector_> RpVEC_;
87  std::vector<CtrlInc_> RqVEC_;
88  boost::scoped_ptr<SPVector_> spvecinit_;
89  int nvec_;
90  Eigen::MatrixXd ZMat_;
91  Eigen::MatrixXd FMat_;
92 };
93 
94 // =============================================================================
95 
96 template<typename MODEL>
98  : j_(dynamic_cast<const CostFctWeak_ &>(j)),
99  idmodel_(false)
100 {}
101 
102 // -----------------------------------------------------------------------------
103 
104 template<typename MODEL>
105  void SaddlePointLMPMatrix<MODEL>::setup(const std::vector<SPVector_> & xyVEC,
106  const std::vector<SPVector_> & pqVEC) {
107  xyVEC_.clear();
108  pqVEC_.clear();
109  RpVEC_.clear();
110  RqVEC_.clear();
111  for (unsigned ii = 0; ii < xyVEC.size(); ++ii) {
112  xyVEC_.push_back(xyVEC[ii]);
113  pqVEC_.push_back(pqVEC[ii]);
114  }
115 
116  nvec_ = xyVEC_.size();
117 
118  if (nvec_ != 0) {
119  spvecinit_.reset(new SPVector_(xyVEC_[0]));
120  (*spvecinit_).zero();
121 
122  SPVector_ ww(xyVEC_[0]);
123  SPVector_ yy(xyVEC_[0]);
124 
125  // RpRqVEC = pqVEC - P0 * xyVEC
126  for (unsigned jv = 0; jv < nvec_; ++jv) {
127  this->Pinitmultiply(xyVEC_[jv], ww);
128  yy = pqVEC_[jv];
129  yy -= ww;
130  RpVEC_.push_back(yy.lambda());
131  RqVEC_.push_back(yy.dx());
132  }
133 
134  // Z = RpVEC'*xVEC
135  ZMat_.resize(nvec_, nvec_);
136  double calpha = 10;
137  for (unsigned jj = 0; jj < nvec_; ++jj) {
138  for (unsigned ii = 0; ii < nvec_; ++ii) {
139  ZMat_(ii, jj) = calpha * dot_product(RpVEC_[ii], xyVEC_[jj].lambda());
140  }
141  }
142 
143  // Get F Matrix explicitly
144  // Set Identity matrix
145  Eigen::MatrixXd Ik;
146  Ik = Eigen::MatrixXd::Identity(2*nvec_, 2*nvec_);
147 
148  // Apply Fmultiply to identity matrix
149  FMat_.resize(2*nvec_, 2*nvec_);
150  Eigen::VectorXd output(2*nvec_);
151  Eigen::VectorXd input(2*nvec_);
152  for (int ii = 0; ii < 2*nvec_; ii++) {
153  input = Ik.col(ii);
154  Fmultiply(input, output);
155  FMat_.col(ii) = output;
156  }
157  }
158 }
159 
160 // =============================================================================
161 template<typename MODEL>
163  SPVector_ & z) const {
164 // P0 = [D 0 L]
165 // [0 R 0]
166 // [Lt 0 0]
167 //
168 // where M = I.
169 
170  CtrlInc_ ww(x.lambda().dx());
171 
172 // ADJ block
173  j_.runADJ(ww, true);
174  z.dx() = x.lambda().dx();
175  z.dx() -= ww;
176 
177 // TLM block
178  ww = x.dx();
179  j_.runTLM(ww, true);
180  z.lambda().zero();
181  z.lambda().dx() = x.dx();
182  z.lambda().dx() -= ww;
183 
184 // Diagonal block
185  DualVector<MODEL> diag;
186  diag.dx(new CtrlInc_(j_.jb()));
187  j_.jb().multiplyB(x.lambda().dx(), diag.dx());
188  for (unsigned jj = 0; jj < j_.nterms(); ++jj) {
189  diag.append(j_.jterm(jj).multiplyCovar(*x.lambda().getv(jj)));
190  }
191 
192  z.lambda() += diag;
193 
194 /*
195 // *********************************
196 // P0 = [D 0 I]
197 // [0 R 0]
198 // [I 0 0]
199  z.dx() = x.lambda().dx();
200  DualVector<MODEL> diag;
201  diag.dx(new CtrlInc_(j_.jb()));
202  j_.jb().multiplyB(x.lambda().dx(), diag.dx());
203  for (unsigned jj = 0; jj < j_.nterms(); ++jj) {
204  diag.append(j_.jterm(jj).multiplyCovar(*x.lambda().getv(jj)));
205  }
206  z.lambda().zero();
207  z.lambda().dx() = x.dx();
208  z.lambda() += diag;
209 // *********************************
210 */
211 }
212 // =============================================================================
213 template<typename MODEL>
215  SPVector_ & z) const {
216 // z = P0inv*x - P0inv*R*Finv*G*P0inv*x
217 
219  SPVector_ svw(x);
220  SPVector_ svt(x);
221 
222  P0inv.multiply(x, z);
223  if (nvec_ != 0) {
224  Eigen::VectorXd rhs(2*nvec_);
225  Eigen::VectorXd finvx(2*nvec_);
226  this->Gmultiply(z, rhs); // rhs = G*z
227  finvx = FMat_.colPivHouseholderQr().solve(rhs); // finvx = Finv*rhs
228  this->Rmultiply(finvx, svw); // svw = R * finvx
229  P0inv.multiply(svw, svt); // svt = P0inv * svw
230  z -= svt; // z = z - svt
231  }
232 }
233 
234 // =============================================================================
235 template<typename MODEL>
237  Eigen::VectorXd & z) const {
238  Eigen::VectorXd v1(nvec_);
239  Eigen::VectorXd v2(nvec_);
240  Eigen::VectorXd ax(nvec_);
241  Eigen::VectorXd axt(nvec_);
242  Eigen::MatrixXd ZMatt(nvec_, nvec_);
243  ZMatt = ZMat_.transpose();
244 
245  // Rp'*x and Rq'*y
246  for (unsigned jj = 0; jj < nvec_; ++jj) {
247  v1(jj) = dot_product(RpVEC_[jj], x.lambda());
248  v2(jj) = dot_product(RqVEC_[jj], x.dx());
249  }
250 
251  ax = ZMat_.colPivHouseholderQr().solve(v1); // Zinv*Rp'*x
252  axt = ZMatt.colPivHouseholderQr().solve(v2); // Ztinv*Rq'*y
253  z << ax, axt; // z = [ax ; axt]
254 }
255 
256 // =============================================================================
257 template<typename MODEL>
258 void SaddlePointLMPMatrix<MODEL>::Rmultiply(Eigen::VectorXd & x, SPVector_ & rx) const {
259  LagVector_ ww(rx.lambda());
260  ww.zero();
261  CtrlInc_ zz(rx.dx());
262  zz.zero();
263 
264  for (unsigned ii = 0; ii < nvec_; ++ii) {
265  ww.axpy(x(ii + nvec_), RpVEC_[ii]);
266  zz.axpy(x(ii), RqVEC_[ii]);
267  }
268  rx.lambda() = ww;
269  rx.dx() = zz;
270 }
271 
272 // =============================================================================
273 template<typename MODEL>
274 void SaddlePointLMPMatrix<MODEL>::Fmultiply(Eigen::VectorXd & x,
275  Eigen::VectorXd & fx) const {
277  SPVector_ tmp(*spvecinit_);
278  SPVector_ tmp2(*spvecinit_);
279  Eigen::VectorXd ww(2*nvec_);
280 
281  fx = x;
282  this->Rmultiply(x, tmp);
283  P0inv.multiply(tmp, tmp2);
284  this->Gmultiply(tmp2, ww);
285  fx += ww;
286 }
287 
288 // -----------------------------------------------------------------------------
289 } // namespace oops
290 
291 #endif // OOPS_ASSIMILATION_SADDLEPOINTLMPMATRIX_H_
ControlIncrement< MODEL > CtrlInc_
std::vector< CtrlInc_ > RqVEC_
std::vector< SPVector_ > xyVEC_
DualVector< MODEL > LagVector_
Container of dual space vectors for all terms of the cost function.
Definition: DualVector.h:34
The preconditioner for the saddle-point minimizer.
void Fmultiply(Eigen::VectorXd &, Eigen::VectorXd &) const
std::vector< SPVector_ > pqVEC_
void setup(const std::vector< SPVector_ > &, const std::vector< SPVector_ > &)
CostFctWeak< MODEL > CostFctWeak_
void Gmultiply(const SPVector_ &, Eigen::VectorXd &) const
void Rmultiply(Eigen::VectorXd &, SPVector_ &) const
void dx(CtrlInc_ *dx)
Definition: DualVector.h:45
Cost Function.
Definition: CostFunction.h:56
integer(long), parameter false
l_size ! loop over number of fields ke do j
The namespace for the main oops code.
boost::scoped_ptr< SPVector_ > spvecinit_
output
Definition: c2f.py:20
void Pinitmultiply(const SPVector_ &, SPVector_ &) const
Weak Constraint 4D-Var Cost Function.
Definition: CostFctWeak.h:44
The preconditioner for the saddle-point minimizer.
void multiply(const SPVector_ &, SPVector_ &) const
SaddlePointVector< MODEL > SPVector_
SaddlePointLMPMatrix(const CostFct_ &j)
Increment Class: Difference between two states.
const Multipliers_ & lambda() const
Accessor method to get the lambda_ component.
void multiply(const SPVector_ &, SPVector_ &) const
std::vector< LagVector_ > RpVEC_
void append(GeneralizedDepartures *)
Definition: DualVector.h:107
Control vector for the saddle point formulation.
const CtrlInc_ & dx() const
Accessor method to get the dx_ component.
void zero()
Linear algebra operators.
boost::shared_ptr< const GeneralizedDepartures > getv(const unsigned) const
Definition: DualVector.h:127
CostFunction< MODEL > CostFct_