IODA Bundle
ModelSpaceCovarianceBase.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_BASE_MODELSPACECOVARIANCEBASE_H_
12 #define OOPS_BASE_MODELSPACECOVARIANCEBASE_H_
13 
14 #include <map>
15 #include <memory>
16 #include <string>
17 #include <vector>
18 
19 #include <boost/make_unique.hpp>
20 #include <boost/noncopyable.hpp>
21 #include <boost/ptr_container/ptr_vector.hpp>
22 #include <boost/range/adaptor/reversed.hpp>
23 
24 #include "eckit/config/LocalConfiguration.h"
25 #include "eckit/exception/Exceptions.h"
26 #include "oops/base/Geometry.h"
27 #include "oops/base/Increment.h"
30 #include "oops/base/State.h"
31 #include "oops/base/Variables.h"
32 #include "oops/util/AssociativeContainers.h"
33 #include "oops/util/Logger.h"
34 #include "oops/util/parameters/ConfigurationParameter.h"
35 #include "oops/util/parameters/HasParameters_.h"
36 #include "oops/util/parameters/OptionalParameter.h"
37 #include "oops/util/parameters/Parameters.h"
38 #include "oops/util/parameters/RequiredPolymorphicParameter.h"
39 #include "oops/util/Random.h"
40 
41 namespace util {
42  class DateTime;
43 }
44 
45 namespace oops {
46 
47 // -----------------------------------------------------------------------------
48 
49 // Should this be one with the ErrorCovariance class in the interface directory? YT
50 
51 /// Abstract base class for model space error covariances.
52 ///
53 /// Note: subclasses can opt to extract their settings either from a Configuration object or from a
54 /// subclass of Parameters.
55 ///
56 /// In the former case, they should provide a constructor taking a const reference to an
57 /// eckit::Configuration object. In the latter case, the implementer should first define a subclass
58 /// of Parameters holding the settings of the model-space covariance change in question. The latter
59 /// should then typedef `Parameters_` to the name of that subclass and provide a constructor taking
60 /// a const reference to an instance of that subclass.
61 template <typename MODEL>
67  typedef typename boost::ptr_vector<LinearVariableChangeBase_> ChvarVec_;
68  typedef typename ChvarVec_::iterator iter_;
69  typedef typename ChvarVec_::const_iterator icst_;
70  typedef typename ChvarVec_::const_reverse_iterator ircst_;
71 
72  public:
73  ModelSpaceCovarianceBase(const State_ &, const State_ &,
75  ModelSpaceCovarianceBase(const State_ &, const State_ &,
76  const Geometry_ &, const eckit::Configuration &);
78 
79  void randomize(Increment_ &) const;
80  void multiply(const Increment_ &, Increment_ &) const;
81  void inverseMultiply(const Increment_ &, Increment_ &) const;
82  void getVariance(Increment_ &) const;
83 
84  private:
85  virtual void doRandomize(Increment_ &) const = 0;
86  virtual void doMultiply(const Increment_ &, Increment_ &) const = 0;
87  virtual void doInverseMultiply(const Increment_ &, Increment_ &) const = 0;
88 
91 };
92 
93 // =============================================================================
94 
95 template <typename MODEL>
96 class CovarianceFactory;
97 
98 // -----------------------------------------------------------------------------
99 
100 /// \brief A subclass of ModelSpaceCovarianceParametersBase storing the values of all options in a
101 /// single Configuration object.
102 ///
103 /// This object can be accessed by calling the value() method of the \p config member variable.
104 ///
105 /// The ConfigurationParameter class does not perform any parameter validation; models using
106 /// GenericModelSpaceCovarianceParameters should therefore ideally be refactored, replacing this
107 /// class with a dedicated subclass of ModelSpaceCovarianceParametersBase storing each parameter in
108 /// a separate (Optional/Required)Parameter object.
109 ///
110 template <typename MODEL>
112  OOPS_CONCRETE_PARAMETERS(GenericModelSpaceCovarianceParameters,
114  public:
115  ConfigurationParameter config{this};
116 };
117 
118 // -----------------------------------------------------------------------------
119 
120 /// \brief Contains a polymorphic parameter holding an instance of a subclass of
121 /// ModelSpaceCovarianceParametersBase.
122 template <typename MODEL>
123 class ModelSpaceCovarianceParametersWrapper : public Parameters {
124  OOPS_CONCRETE_PARAMETERS(ModelSpaceCovarianceParametersWrapper, Parameters)
125  public:
126  /// After deserialization, holds an instance of a subclass of ModelSpaceCovarianceParametersBase
127  /// controlling the behavior of a covariance model. The type of the subclass is determined by
128  /// the value of the "name" key in the Configuration object from which this object is
129  /// deserialized.
130  RequiredPolymorphicParameter<ModelSpaceCovarianceParametersBase<MODEL>, CovarianceFactory<MODEL>>
131  covarianceParameters{"covariance model", this};
132 };
133 
134 // =============================================================================
135 
136 /// Covariance Factory
137 template <typename MODEL>
141 
142  public:
143  /// \brief Create and return a new covariance model.
144  ///
145  /// The covariance model is determined by the \c covarianceModel attribute of \p parameters.
146  /// \p parameters must be an instance of the subclass of ModelSpaceCovarianceParametersBase
147  /// associated with that covariance model, otherwise an exception will be thrown.
149  const Geometry_ &, const Variables &,
150  const State_ &, const State_ &);
151 
152  /// \brief Create and return a new covariance model.
153  ///
154  /// Deprecated overload taking a Configuration instead of a ModelSpaceCovarianceParametersBase.
155  static ModelSpaceCovarianceBase<MODEL> * create(const eckit::Configuration &,
156  const Geometry_ &, const Variables &,
157  const State_ &, const State_ &);
158 
159  /// \brief Create and return an instance of the subclass of ModelSpaceCovarianceParametersBase
160  /// storing parameters of the specified covariance model.
161  static std::unique_ptr<ModelSpaceCovarianceParametersBase<MODEL>> createParameters(
162  const std::string &covarianceModel);
163 
164  /// \brief Return the names of all covariance models that can be created by one of the
165  /// registered makers.
166  static std::vector<std::string> getMakerNames() {
167  return keys(getMakers());
168  }
169 
170  virtual ~CovarianceFactory() = default;
171 
172  protected:
173  /// \brief Register a maker able to create covariance models of type \p name.
174  explicit CovarianceFactory(const std::string &name);
175 
176  private:
178  const Geometry_ &, const Variables &,
179  const State_ &, const State_ &) = 0;
180 
181  virtual std::unique_ptr<ModelSpaceCovarianceParametersBase<MODEL>> makeParameters() const = 0;
182 
183  static std::map < std::string, CovarianceFactory<MODEL> * > & getMakers() {
184  static std::map < std::string, CovarianceFactory<MODEL> * > makers_;
185  return makers_;
186  }
187 };
188 
189 // -----------------------------------------------------------------------------
190 
191 template<class MODEL, class COVAR>
192 class CovarMaker : public CovarianceFactory<MODEL> {
193  /// Defined as T::Parameters_ if COVAR defines a Parameters_ type; otherwise as
194  /// GenericModelSpaceCovarianceParameters<MODEL>.
195  typedef TParameters_IfAvailableElseFallbackType_t<
197 
200 
203  const Geometry_ & resol, const Variables & vars,
204  const State_ & xb, const State_ & fg) override {
205  const auto &stronglyTypedParams = dynamic_cast<const Parameters_&>(params);
206  return new COVAR(resol, vars,
207  parametersOrConfiguration<HasParameters_<COVAR>::value>(stronglyTypedParams),
208  xb, fg);
209  }
210 
211  std::unique_ptr<ModelSpaceCovarianceParametersBase<MODEL>> makeParameters() const override {
212  return boost::make_unique<Parameters_>();
213  }
214 
215  public:
216  explicit CovarMaker(const std::string & name) : CovarianceFactory<MODEL>(name) {}
217 };
218 
219 // =============================================================================
220 
221 template <typename MODEL>
223  if (getMakers().find(name) != getMakers().end()) {
224  throw std::runtime_error(name + " already registered in covariance factory.");
225  }
226  getMakers()[name] = this;
227 }
228 
229 // -----------------------------------------------------------------------------
230 
231 template <typename MODEL>
234  const Geometry_ & resol,
235  const Variables & vars,
236  const State_ & xb, const State_ & fg) {
237  const std::string id = parameters.covarianceModel.value().value();
238  Log::trace() << "ModelSpaceCovarianceBase type = " << id << std::endl;
239  typename std::map<std::string, CovarianceFactory<MODEL>*>::iterator jcov = getMakers().find(id);
240  if (jcov == getMakers().end()) {
241  Log::error() << id << " does not exist in CovarianceFactory." << std::endl;
242  Log::error() << "CovarianceFactory has " << getMakers().size() << " elements:" << std::endl;
243  for (typename std::map<std::string, CovarianceFactory<MODEL>*>::const_iterator
244  jj = getMakers().begin(); jj != getMakers().end(); ++jj) {
245  Log::error() << "A " << jj->first << " B" << std::endl;
246  }
247  throw std::runtime_error(id + " does not exist in covariance factory.");
248  }
249  Variables vars_in(vars);
250  Variables vars_out;
251  for (const LinearVariableChangeParametersWrapper<MODEL> &variableChange :
252  boost::adaptors::reverse(parameters.variableChanges.value())) {
253  const LinearVariableChangeParametersBase &variableChangeParameters =
254  variableChange.variableChangeParameters;
255  if (variableChangeParameters.inputVariables.value() != boost::none &&
256  variableChangeParameters.outputVariables.value() != boost::none) {
257  vars_out = *variableChangeParameters.outputVariables.value();
258  if (!(vars_in == vars_out)) {
259  Log::error() << "Input variables: " << vars_in << std::endl;
260  Log::error() << "Output variables: " << vars_out << std::endl;
261  throw eckit::BadParameter("Sequence of variable changes is not consistent");
262  }
263  vars_in = *variableChangeParameters.inputVariables.value();
264  }
265  }
266  return (*jcov).second->make(parameters, resol, vars_in, xb, fg);
267 }
268 
269 // -----------------------------------------------------------------------------
270 
271 template <typename MODEL>
273  const eckit::Configuration & conf,
274  const Geometry_ & resol,
275  const Variables & vars,
276  const State_ & xb, const State_ & fg) {
278  parameters.validateAndDeserialize(conf);
279  return create(parameters.covarianceParameters, resol, vars, xb, fg);
280 }
281 
282 // -----------------------------------------------------------------------------
283 
284 template <typename MODEL>
285 std::unique_ptr<ModelSpaceCovarianceParametersBase<MODEL>>
287  const std::string &name) {
288  typename std::map<std::string, CovarianceFactory<MODEL>*>::iterator it =
289  getMakers().find(name);
290  if (it == getMakers().end()) {
291  throw std::runtime_error(name + " does not exist in CovarianceFactory");
292  }
293  return it->second->makeParameters();
294 }
295 
296 // =============================================================================
297 
298 template <typename MODEL>
300  const State_ & bg, const State_ & fg,
301  const Geometry_ & resol,
302  const ModelSpaceCovarianceParametersBase<MODEL> & parameters) {
303  for (const LinearVariableChangeParametersWrapper<MODEL> &variableChange :
304  parameters.variableChanges.value()) {
306  bg, fg, resol, variableChange.variableChangeParameters));
307  }
308  randomizationSize_ = parameters.randomizationSize;
309 }
310 
311 // -----------------------------------------------------------------------------
312 
313 template <typename MODEL>
315  const State_ & bg, const State_ & fg,
316  const Geometry_ & resol,
317  const eckit::Configuration & conf)
319  bg, fg, resol, validateAndDeserialize<GenericModelSpaceCovarianceParameters<MODEL>>(conf))
320 {}
321 
322 // -----------------------------------------------------------------------------
323 
324 template <typename MODEL>
326  // TODO(notguillaume): Generalize to non-square change of variable
327  if (chvars_.size()) {
328  this->doRandomize(dx); // dx = C^1/2 dx
329  // K_N K_N-1 ... K_1
330  for (icst_ it = chvars_.begin(); it != chvars_.end(); ++it) {
331  dx = it->multiply(dx); // dx = K_i dx
332  }
333  } else {
334  this->doRandomize(dx);
335  }
336 }
337 
338 // -----------------------------------------------------------------------------
339 
340 template <typename MODEL>
342  Increment_ & dxo) const {
343  if (chvars_.size()) {
344  // K_1^T K_2^T .. K_N^T
345  std::unique_ptr<Increment_> dxchvarin(new Increment_(dxi));
346  for (ircst_ it = chvars_.rbegin(); it != chvars_.rend(); ++it) {
347  Increment_ dxchvarout = it->multiplyAD(*dxchvarin);
348  dxchvarin.reset(new Increment_(dxchvarout));
349  }
350  Increment_ dxchvarout(*dxchvarin, false);
351 
352  this->doMultiply(*dxchvarin, dxchvarout);
353 
354  // K_N K_N-1 ... K_1
355  dxchvarin.reset(new Increment_(dxchvarout));
356  for (icst_ it = chvars_.begin(); it != chvars_.end(); ++it) {
357  Increment_ dxchvarout = it->multiply(*dxchvarin);
358  dxchvarin.reset(new Increment_(dxchvarout));
359  }
360  dxo = *dxchvarin;
361  } else {
362  this->doMultiply(dxi, dxo);
363  }
364 }
365 
366 // -----------------------------------------------------------------------------
367 
368 template <typename MODEL>
370  Increment_ & dxo) const {
371  if (chvars_.size()) {
372  // K_1^{-1} K_2^{-1} .. K_N^{-1}
373  std::unique_ptr<Increment_> dxchvarin(new Increment_(dxi));
374  for (ircst_ it = chvars_.rbegin(); it != chvars_.rend(); ++it) {
375  Increment_ dxchvarout = it->multiplyInverse(*dxchvarin);
376  dxchvarin.reset(new Increment_(dxchvarout));
377  }
378  Increment_ dxchvarout(*dxchvarin, false);
379 
380  this->doInverseMultiply(*dxchvarin, dxchvarout);
381 
382  // K_N^T^{-1} K_N-1^T^{-1} ... K_1^T^{-1}
383  dxchvarin.reset(new Increment_(dxchvarout));
384  for (icst_ it = chvars_.begin(); it != chvars_.end(); ++it) {
385  Increment_ dxchvarout = it->multiplyInverseAD(*dxchvarin);
386  dxchvarin.reset(new Increment_(dxchvarout));
387  }
388  dxo = *dxchvarin;
389  } else {
390  this->doInverseMultiply(dxi, dxo);
391  }
392 }
393 
394 // -----------------------------------------------------------------------------
395 
396 template <typename MODEL>
398  Increment_ dx(variance);
399  Increment_ dxsq(variance);
400  Increment_ mean(variance);
401  mean.zero();
402  variance.zero();
403  for (size_t ie = 0; ie < randomizationSize_; ++ie) {
404  this->randomize(dx);
405  dx -= mean;
406  dxsq = dx;
407  dxsq.schur_product_with(dx);
408  double rk_var = static_cast<double>(ie)/static_cast<double>(ie+1);
409  double rk_mean = 1.0/static_cast<double>(ie+1);
410  variance.axpy(rk_var, dxsq, false);
411  mean.axpy(rk_mean, dx, false);
412  }
413  double rk_norm = 1.0/static_cast<double>(randomizationSize_-1);
414  variance *= rk_norm;
415 }
416 
417 // -----------------------------------------------------------------------------
418 
419 } // namespace oops
420 
421 #endif // OOPS_BASE_MODELSPACECOVARIANCEBASE_H_
Geometry< MODEL > Geometry_
CovarMaker(const std::string &name)
ModelSpaceCovarianceBase< MODEL > * make(const ModelSpaceCovarianceParametersBase< MODEL > &params, const Geometry_ &resol, const Variables &vars, const State_ &xb, const State_ &fg) override
TParameters_IfAvailableElseFallbackType_t< COVAR, GenericModelSpaceCovarianceParameters< MODEL > > Parameters_
std::unique_ptr< ModelSpaceCovarianceParametersBase< MODEL > > makeParameters() const override
virtual std::unique_ptr< ModelSpaceCovarianceParametersBase< MODEL > > makeParameters() const =0
static std::vector< std::string > getMakerNames()
Return the names of all covariance models that can be created by one of the registered makers.
CovarianceFactory(const std::string &name)
Register a maker able to create covariance models of type name.
virtual ModelSpaceCovarianceBase< MODEL > * make(const ModelSpaceCovarianceParametersBase< MODEL > &, const Geometry_ &, const Variables &, const State_ &, const State_ &)=0
virtual ~CovarianceFactory()=default
static std::unique_ptr< ModelSpaceCovarianceParametersBase< MODEL > > createParameters(const std::string &covarianceModel)
Create and return an instance of the subclass of ModelSpaceCovarianceParametersBase storing parameter...
static ModelSpaceCovarianceBase< MODEL > * create(const ModelSpaceCovarianceParametersBase< MODEL > &, const Geometry_ &, const Variables &, const State_ &, const State_ &)
Create and return a new covariance model.
static std::map< std::string, CovarianceFactory< MODEL > * > & getMakers()
A subclass of ModelSpaceCovarianceParametersBase storing the values of all options in a single Config...
Geometry class used in oops; subclass of interface class interface::Geometry.
Increment class used in oops.
Base class of classes storing parameters controlling specific linear variable changes.
Contains a polymorphic parameter holding an instance of a subclass of LinearVariableChangeParametersB...
ChvarVec_::const_reverse_iterator ircst_
LinearVariableChangeBase< MODEL > LinearVariableChangeBase_
virtual void doMultiply(const Increment_ &, Increment_ &) const =0
boost::ptr_vector< LinearVariableChangeBase_ > ChvarVec_
ModelSpaceCovarianceBase(const State_ &, const State_ &, const Geometry_ &, const ModelSpaceCovarianceParametersBase< MODEL > &)
virtual void doInverseMultiply(const Increment_ &, Increment_ &) const =0
void inverseMultiply(const Increment_ &, Increment_ &) const
virtual void doRandomize(Increment_ &) const =0
void multiply(const Increment_ &, Increment_ &) const
Base class for classes storing parameters of a particular model-space error covariance implementation...
Parameter< std::vector< LinearVariableChangeParametersWrapper< MODEL > > > variableChanges
OptionalParameter< std::string > covarianceModel
Covariance model name.
Contains a polymorphic parameter holding an instance of a subclass of ModelSpaceCovarianceParametersB...
RequiredPolymorphicParameter< ModelSpaceCovarianceParametersBase< MODEL >, CovarianceFactory< MODEL > > covarianceParameters
State class used in oops; subclass of interface class interface::State.
void axpy(const double &w, const Increment &dx, const bool check=true)
void schur_product_with(const Increment &other)
Compute Schur product of this Increment with other, assign to this Increment.
void zero()
Zero out this Increment.
The namespace for the main oops code.