Loading [MathJax]/extensions/tex2jax.js
OOPS
All Classes Namespaces Files Functions Variables Typedefs Macros Pages
test/interface/ErrorCovariance.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 TEST_INTERFACE_ERRORCOVARIANCE_H_
12 #define TEST_INTERFACE_ERRORCOVARIANCE_H_
13 
14 #include <cmath>
15 #include <iostream>
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
20 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
21 
22 #include <boost/noncopyable.hpp>
23 
24 #include "eckit/config/Configuration.h"
25 #include "eckit/testing/Test.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/mpi/mpi.h"
33 #include "oops/runs/Test.h"
34 #include "oops/util/DateTime.h"
35 #include "oops/util/dot_product.h"
36 #include "oops/util/Expect.h"
37 #include "oops/util/Logger.h"
38 #include "test/TestEnvironment.h"
39 
40 namespace test {
41 
42 // =============================================================================
43 
44 template <typename MODEL> class ErrorCovarianceFixture : private boost::noncopyable {
47 
48  public:
49  static const eckit::Configuration & test() {return *getInstance().test_;}
50  static const Geometry_ & resol() {return *getInstance().resol_;}
51  static const oops::Variables & ctlvars() {return *getInstance().ctlvars_;}
52  static const util::DateTime & time() {return *getInstance().time_;}
53  static const Covariance_ & covariance() {return *getInstance().B_;}
54  static void reset() {
55  getInstance().B_.reset();
56  getInstance().time_.reset();
57  getInstance().ctlvars_.reset();
58  getInstance().resol_.reset();
59  getInstance().test_.reset();
60  }
61 
62  private:
64  static ErrorCovarianceFixture<MODEL> theErrorCovarianceFixture;
65  return theErrorCovarianceFixture;
66  }
67 
69  oops::instantiateCovarFactory<MODEL>();
70 
71  test_.reset(new eckit::LocalConfiguration(TestEnvironment::config(), "covariance test"));
72 
73  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "geometry");
74  resol_.reset(new Geometry_(resolConfig, oops::mpi::world()));
75 
76  ctlvars_.reset(new oops::Variables(TestEnvironment::config(), "analysis variables"));
77 
78  const eckit::LocalConfiguration fgconf(TestEnvironment::config(), "background");
79  oops::State<MODEL> xx(*resol_, fgconf);
80 
81  time_.reset(new util::DateTime(xx.validTime()));
82 
83 // Setup the B matrix
84  const eckit::LocalConfiguration covar(TestEnvironment::config(), "background error");
85  B_.reset(oops::CovarianceFactory<MODEL>::create(covar, *resol_, *ctlvars_, xx, xx));
86  }
87 
88  ~ErrorCovarianceFixture<MODEL>() {}
89 
90  std::unique_ptr<const eckit::LocalConfiguration> test_;
91  std::unique_ptr<const Geometry_> resol_;
92  std::unique_ptr<const oops::Variables> ctlvars_;
93  std::unique_ptr<const util::DateTime> time_;
94  std::unique_ptr<Covariance_> B_;
95 };
96 
97 // =============================================================================
98 
99 template <typename MODEL> void testErrorCovarianceZero() {
100  typedef ErrorCovarianceFixture<MODEL> Test_;
101  typedef oops::Increment<MODEL> Increment_;
102 
103  Increment_ dx1(Test_::resol(), Test_::ctlvars(), Test_::time());
104  Increment_ dx2(Test_::resol(), Test_::ctlvars(), Test_::time());
105 
106  Test_::covariance().randomize(dx2);
107  oops::Log::test() << "dx2.norm()=" << dx2.norm() << std::endl;
108 
109  EXPECT(dx1.norm() == 0.0);
110  EXPECT(dx2.norm() > 0.0);
111 
112  Test_::covariance().multiply(dx1, dx2);
113  EXPECT(dx2.norm() == 0.0);
114 
115  const bool testinverse = Test_::test().getBool("testinverse", true);
116  if (testinverse)
117  {
118  oops::Log::test() << "Doing zero test for inverse" << std::endl;
119  dx1.zero();
120  Test_::covariance().randomize(dx2);
121  EXPECT(dx1.norm() == 0.0);
122  EXPECT(dx2.norm() > 0.0);
123  Test_::covariance().inverseMultiply(dx1, dx2);
124  EXPECT(dx2.norm() == 0.0);
125  } else {
126  oops::Log::test() << "Not doing zero test for inverse" << std::endl;
127  }
128 }
129 
130 // -----------------------------------------------------------------------------
131 
132 template <typename MODEL> void testErrorCovarianceInverse() {
133  typedef ErrorCovarianceFixture<MODEL> Test_;
134  typedef oops::Increment<MODEL> Increment_;
135 
136  const bool testinverse = Test_::test().getBool("testinverse", true);
137  if (testinverse)
138  {
139  Increment_ dx1(Test_::resol(), Test_::ctlvars(), Test_::time());
140  Increment_ dx2(Test_::resol(), Test_::ctlvars(), Test_::time());
141  Increment_ dx3(Test_::resol(), Test_::ctlvars(), Test_::time());
142  Test_::covariance().randomize(dx1);
143  EXPECT(dx1.norm() > 0.0);
144 
145  Test_::covariance().multiply(dx1, dx2);
146  Test_::covariance().inverseMultiply(dx2, dx3);
147 
148  EXPECT(dx2.norm() > 0.0);
149  EXPECT(dx3.norm() > 0.0);
150  dx3 -= dx1;
151  const double tol = Test_::test().getDouble("tolerance");
152  EXPECT(dx3.norm()/dx1.norm() < tol);
153  } else {
154  return;
155  }
156 }
157 
158 // -----------------------------------------------------------------------------
159 
160 template <typename MODEL> void testErrorCovarianceSym() {
161  typedef ErrorCovarianceFixture<MODEL> Test_;
162  typedef oops::Increment<MODEL> Increment_;
163 
164  Increment_ dx(Test_::resol(), Test_::ctlvars(), Test_::time());
165  Increment_ Bdx(Test_::resol(), Test_::ctlvars(), Test_::time());
166  Increment_ dy(Test_::resol(), Test_::ctlvars(), Test_::time());
167  Increment_ Bdy(Test_::resol(), Test_::ctlvars(), Test_::time());
168 
169  dx.random();
170  dy.random();
171 
172  Test_::covariance().multiply(dx, Bdx);
173  Test_::covariance().multiply(dy, Bdy);
174  const double zz1 = dot_product(dx, Bdy);
175  const double zz2 = dot_product(Bdx, dy);
176  oops::Log::test() << "<dx,Bdy>-<Bdx,dy>/<dx,Bdy>="
177  << (zz1-zz2)/zz1 << std::endl;
178  oops::Log::test() << "<dx,Bdy>-<Bdx,dy>/<Bdx,dy>="
179  << (zz1-zz2)/zz2 << std::endl;
180  const double tol = Test_::test().getDouble("tolerance");
181  EXPECT(oops::is_close(zz1, zz2, tol));
182 }
183 
184 // -----------------------------------------------------------------------------
185 
186 template <typename MODEL> void testCovarianceParametersWrapperValidName() {
187  eckit::LocalConfiguration config(TestEnvironment::config(), "background error");
189  EXPECT_NO_THROW(parameters.validateAndDeserialize(config));
190 }
191 
192 // -----------------------------------------------------------------------------
193 
194 template <typename MODEL> void testCovarianceParametersWrapperInvalidName() {
195  eckit::LocalConfiguration config;
196  config.set("covariance model", "###INVALID###");
198  if (oops::Parameters::isValidationSupported())
199  EXPECT_THROWS_MSG(parameters.validate(config), "unrecognized enum value");
200  EXPECT_THROWS_MSG(parameters.deserialize(config),
201  "does not exist in CovarianceFactory");
202 }
203 
204 // -----------------------------------------------------------------------------
205 
206 template <typename MODEL> void testCovarianceFactoryGetMakerNames() {
207  eckit::LocalConfiguration config(TestEnvironment::config(), "background error");
208  const std::string validName = config.getString("covariance model");
209  const std::vector<std::string> registeredNames =
211  const bool found = std::find(registeredNames.begin(), registeredNames.end(), validName) !=
212  registeredNames.end();
213  EXPECT(found);
214 }
215 
216 // =============================================================================
217 
218 template <typename MODEL>
219 class ErrorCovariance : public oops::Test {
220  public:
223 
224  private:
225  std::string testid() const override {return "test::ErrorCovariance<" + MODEL::name() + ">";}
226 
227  void register_tests() const override {
228  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
229 
230  ts.emplace_back(CASE("interface/ErrorCovariance/testErrorCovarianceZero")
231  { testErrorCovarianceZero<MODEL>(); });
232  ts.emplace_back(CASE("interface/ErrorCovariance/testErrorCovarianceInverse")
233  { testErrorCovarianceInverse<MODEL>(); });
234  ts.emplace_back(CASE("interface/ErrorCovariance/testErrorCovarianceSym")
235  { testErrorCovarianceSym<MODEL>(); });
236  ts.emplace_back(CASE("interface/ErrorCovariance/testCovarianceParametersWrapperValidName")
237  { testCovarianceParametersWrapperValidName<MODEL>(); });
238  ts.emplace_back(CASE("interface/ErrorCovariance/testCovarianceParametersWrapperInvalidName")
239  { testCovarianceParametersWrapperInvalidName<MODEL>(); });
240  ts.emplace_back(CASE("interface/ErrorCovariance/testCovarianceFactoryGetMakerNames")
241  { testCovarianceFactoryGetMakerNames<MODEL>(); });
242  }
243 
244  void clear() const override {}
245 };
246 
247 // =============================================================================
248 
249 } // namespace test
250 
251 #endif // TEST_INTERFACE_ERRORCOVARIANCE_H_
static std::vector< std::string > getMakerNames()
Return the names of all covariance models that can be created by one of the registered makers.
Geometry class used in oops; subclass of interface class interface::Geometry.
Increment class used in oops.
Contains a polymorphic parameter holding an instance of a subclass of ModelSpaceCovarianceParametersB...
State class used in oops; subclass of interface class interface::State.
static ErrorCovarianceFixture< MODEL > & getInstance()
static const util::DateTime & time()
static const eckit::Configuration & test()
static const oops::Variables & ctlvars()
static const Covariance_ & covariance()
std::unique_ptr< const util::DateTime > time_
oops::ModelSpaceCovarianceBase< MODEL > Covariance_
std::unique_ptr< const oops::Variables > ctlvars_
std::unique_ptr< const Geometry_ > resol_
std::unique_ptr< Covariance_ > B_
std::unique_ptr< const eckit::LocalConfiguration > test_
std::string testid() const override
static const eckit::Configuration & config()
const eckit::mpi::Comm & world()
Default communicator with all MPI tasks (ie MPI_COMM_WORLD)
Definition: oops/mpi/mpi.cc:84
void testCovarianceFactoryGetMakerNames()
void testCovarianceParametersWrapperValidName()
void testCovarianceParametersWrapperInvalidName()
CASE("test_linearmodelparameterswrapper_valid_name")