FV3 Bundle
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 <string>
17 
18 #define BOOST_TEST_NO_MAIN
19 #define BOOST_TEST_ALTERNATIVE_INIT_API
20 #define BOOST_TEST_DYN_LINK
21 
22 #include <boost/noncopyable.hpp>
23 #include <boost/scoped_ptr.hpp>
24 #include <boost/test/unit_test.hpp>
25 
26 #include "eckit/config/Configuration.h"
29 #include "oops/base/Variables.h"
32 #include "oops/interface/State.h"
33 #include "oops/runs/Test.h"
34 #include "oops/util/DateTime.h"
35 #include "oops/util/dot_product.h"
36 #include "oops/util/Logger.h"
37 #include "test/TestEnvironment.h"
38 
39 namespace test {
40 
41 // =============================================================================
42 
43 template <typename MODEL> class ErrorCovarianceFixture : private boost::noncopyable {
46 
47  public:
48  static const eckit::Configuration & test() {return *getInstance().test_;}
49  static const Geometry_ & resol() {return *getInstance().resol_;}
50  static const oops::Variables & ctlvars() {return *getInstance().ctlvars_;}
51  static const util::DateTime & time() {return *getInstance().time_;}
52  static const Covariance_ & covariance() {return *getInstance().B_;}
53 
54  private:
56  static ErrorCovarianceFixture<MODEL> theErrorCovarianceFixture;
57  return theErrorCovarianceFixture;
58  }
59 
61  oops::instantiateCovarFactory<MODEL>();
62 
63  test_.reset(new eckit::LocalConfiguration(TestEnvironment::config(), "CovarianceTest"));
64 
65  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "Geometry");
66  resol_.reset(new Geometry_(resolConfig));
67 
68  const eckit::LocalConfiguration varConfig(TestEnvironment::config(), "Variables");
69  ctlvars_.reset(new oops::Variables(varConfig));
70 
71  const eckit::LocalConfiguration fgconf(TestEnvironment::config(), "State");
72  oops::State<MODEL> xx(*resol_, *ctlvars_, fgconf);
73 
74  time_.reset(new util::DateTime(xx.validTime()));
75 
76 // Setup the B matrix
77  const eckit::LocalConfiguration covar(TestEnvironment::config(), "Covariance");
78  B_.reset(oops::CovarianceFactory<MODEL>::create(covar, *resol_, *ctlvars_, xx, xx));
79  }
80 
82 
83  boost::scoped_ptr<const eckit::LocalConfiguration> test_;
84  boost::scoped_ptr<const Geometry_> resol_;
85  boost::scoped_ptr<const oops::Variables> ctlvars_;
86  boost::scoped_ptr<const util::DateTime> time_;
87  boost::scoped_ptr<Covariance_> B_;
88 };
89 
90 // =============================================================================
91 
92 template <typename MODEL> void testErrorCovarianceZero() {
93  typedef ErrorCovarianceFixture<MODEL> Test_;
94  typedef oops::Increment<MODEL> Increment_;
95 
96  Increment_ dx1(Test_::resol(), Test_::ctlvars(), Test_::time());
97  Increment_ dx2(Test_::resol(), Test_::ctlvars(), Test_::time());
98 
99  Test_::covariance().randomize(dx2);
100  oops::Log::info() << "dx2.norm()=" << dx2.norm() << std::endl;
101 
102  BOOST_CHECK_EQUAL(dx1.norm(), 0.0);
103  BOOST_CHECK(dx2.norm() > 0.0);
104  Test_::covariance().multiply(dx1, dx2);
105  BOOST_CHECK_EQUAL(dx2.norm(), 0.0);
106 
107  const bool testinverse = Test_::test().getBool("testinverse", true);
108  if (testinverse)
109  {
110  oops::Log::info() << "Doing zero test for inverse" << std::endl;
111  dx1.zero();
112  Test_::covariance().randomize(dx2);
113  BOOST_CHECK_EQUAL(dx1.norm(), 0.0);
114  BOOST_CHECK(dx2.norm() > 0.0);
115  Test_::covariance().inverseMultiply(dx1, dx2);
116  BOOST_CHECK_EQUAL(dx2.norm(), 0.0);
117  } else {
118  oops::Log::info() << "Not doing zero test for inverse" << std::endl;
119  }
120 }
121 
122 // -----------------------------------------------------------------------------
123 
124 template <typename MODEL> void testErrorCovarianceInverse() {
125  typedef ErrorCovarianceFixture<MODEL> Test_;
126  typedef oops::Increment<MODEL> Increment_;
127 
128  const bool testinverse = Test_::test().getBool("testinverse", true);
129  if (testinverse)
130  {
131  Increment_ dx1(Test_::resol(), Test_::ctlvars(), Test_::time());
132  Increment_ dx2(Test_::resol(), Test_::ctlvars(), Test_::time());
133  Increment_ dx3(Test_::resol(), Test_::ctlvars(), Test_::time());
134  Test_::covariance().randomize(dx1);
135  BOOST_CHECK(dx1.norm() > 0.0);
136 
137  Test_::covariance().multiply(dx1, dx2);
138  Test_::covariance().inverseMultiply(dx2, dx3);
139 
140  BOOST_CHECK(dx2.norm() > 0.0);
141  BOOST_CHECK(dx3.norm() > 0.0);
142  dx3 -= dx1;
143  const double tol = Test_::test().getDouble("tolerance");
144  BOOST_CHECK_SMALL(dx3.norm(), tol);
145  } else {
146  return;
147  }
148 }
149 
150 // -----------------------------------------------------------------------------
151 
152 template <typename MODEL> void testErrorCovarianceSym() {
153  typedef ErrorCovarianceFixture<MODEL> Test_;
154  typedef oops::Increment<MODEL> Increment_;
155 
156  Increment_ dx(Test_::resol(), Test_::ctlvars(), Test_::time());
157  Increment_ Bdx(Test_::resol(), Test_::ctlvars(), Test_::time());
158  Increment_ dy(Test_::resol(), Test_::ctlvars(), Test_::time());
159  Increment_ Bdy(Test_::resol(), Test_::ctlvars(), Test_::time());
160 
161  dx.random();
162  dy.random();
163 
164  Test_::covariance().multiply(dx, Bdx);
165  Test_::covariance().multiply(dy, Bdy);
166  const double zz1 = dot_product(dx, Bdy);
167  const double zz2 = dot_product(Bdx, dy);
168  oops::Log::info() << "<dx,Bdy>-<Bdx,dy>/<dx,Bdy>="
169  << (zz1-zz2)/zz1 << std::endl;
170  oops::Log::info() << "<dx,Bdy>-<Bdx,dy>/<Bdx,dy>="
171  << (zz1-zz2)/zz2 << std::endl;
172  const double tol = Test_::test().getDouble("tolerance");
173  BOOST_CHECK_CLOSE(zz1, zz2, tol);
174 }
175 
176 // =============================================================================
177 
178 template <typename MODEL> class ErrorCovariance : public oops::Test {
179  public:
181  virtual ~ErrorCovariance() {}
182  private:
183  std::string testid() const {return "test::ErrorCovariance<" + MODEL::name() + ">";}
184 
185  void register_tests() const {
186  boost::unit_test::test_suite * ts = BOOST_TEST_SUITE("interface/ErrorCovariance");
187 
188  ts->add(BOOST_TEST_CASE(&testErrorCovarianceZero<MODEL>));
189  ts->add(BOOST_TEST_CASE(&testErrorCovarianceInverse<MODEL>));
190  ts->add(BOOST_TEST_CASE(&testErrorCovarianceSym<MODEL>));
191 
192  boost::unit_test::framework::master_test_suite().add(ts);
193  }
194 };
195 
196 // =============================================================================
197 
198 } // namespace test
199 
200 #endif // TEST_INTERFACE_ERRORCOVARIANCE_H_
boost::scoped_ptr< Covariance_ > B_
static const util::DateTime & time()
boost::scoped_ptr< const util::DateTime > time_
Encapsulates the model state.
static const eckit::Configuration & config()
program test
character(len=32) name
boost::scoped_ptr< const Geometry_ > resol_
static const oops::Variables & ctlvars()
static const Covariance_ & covariance()
subroutine, public info(self)
Abstract base class for model space error covariances.
Increment Class: Difference between two states.
static ErrorCovarianceFixture< MODEL > & getInstance()
boost::scoped_ptr< const eckit::LocalConfiguration > test_
boost::scoped_ptr< const oops::Variables > ctlvars_
oops::ModelSpaceCovarianceBase< MODEL > Covariance_
static const eckit::Configuration & test()
const util::DateTime validTime() const
Time.