FV3 Bundle
test/interface/LinearModel.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_LINEARMODEL_H_
12 #define TEST_INTERFACE_LINEARMODEL_H_
13 
14 #include <algorithm>
15 #include <cmath>
16 #include <iomanip>
17 #include <iostream>
18 #include <limits>
19 #include <string>
20 #include <vector>
21 
22 #define BOOST_TEST_NO_MAIN
23 #define BOOST_TEST_ALTERNATIVE_INIT_API
24 #define BOOST_TEST_DYN_LINK
25 
26 #include <boost/noncopyable.hpp>
27 #include <boost/scoped_ptr.hpp>
28 #include <boost/test/unit_test.hpp>
29 
30 #include "eckit/config/LocalConfiguration.h"
36 #include "oops/base/Variables.h"
41 #include "oops/interface/Model.h"
44 #include "oops/interface/State.h"
45 #include "oops/runs/Test.h"
46 #include "oops/util/DateTime.h"
47 #include "oops/util/dot_product.h"
48 #include "oops/util/Duration.h"
49 #include "test/TestEnvironment.h"
50 
51 namespace test {
52 
53 // =============================================================================
54 
55 template <typename MODEL> class LinearModelFixture : private boost::noncopyable {
64 
65  public:
66  static const eckit::Configuration & test() {return *getInstance().test_;}
67  static const Geometry_ & resol() {return *getInstance().resol_;}
68  static const oops::Variables & ctlvars() {return *getInstance().ctlvars_;}
69  static const util::DateTime & time() {return *getInstance().time_;}
70  static const Covariance_ & covariance() {return *getInstance().B_;}
71  static const Model_ & model() {return *getInstance().model_;}
72  static const State_ & xref() {return *getInstance().xref_;}
73  static const ModelAux_ & bias() {return *getInstance().bias_;}
74  static const ModelAuxIncr_ & dbias() {return *getInstance().dbias_;}
75  static const LinearModel_ & tlm() {return *getInstance().tlm_;}
76 
77  private:
79  static LinearModelFixture<MODEL> theLinearModelFixture;
80  return theLinearModelFixture;
81  }
82 
84  test_.reset(new eckit::LocalConfiguration(TestEnvironment::config(), "LinearModelTest"));
85  const util::Duration len(test_->getString("fclength"));
86 
87  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "Geometry");
88  resol_.reset(new Geometry_(resolConfig));
89 
90  const eckit::LocalConfiguration varConfig(TestEnvironment::config(), "Variables");
91  ctlvars_.reset(new oops::Variables(varConfig));
92 
93  const eckit::LocalConfiguration biasConf(TestEnvironment::config(), "ModelBias");
94  bias_.reset(new ModelAux_(*resol_, biasConf));
95  dbias_.reset(new ModelAuxIncr_(*resol_, biasConf));
96 
97  const eckit::LocalConfiguration nlConf(TestEnvironment::config(), "Model");
98  model_.reset(new Model_(*resol_, nlConf));
99 
100  const eckit::LocalConfiguration iniConf(TestEnvironment::config(), "State");
101  xref_.reset(new State_(*resol_, model_->variables(), iniConf));
102  time_.reset(new util::DateTime(xref_->validTime()));
103 
104 // Create a covariance matrix
105  oops::instantiateCovarFactory<MODEL>();
106  const eckit::LocalConfiguration covar(TestEnvironment::config(), "Covariance");
108 
109 // Linear model configuration
110  tlConf_.reset(new eckit::LocalConfiguration(TestEnvironment::config(), "LinearModel"));
111 
112 // Setup trajectory for TL and AD
113  oops::instantiateTlmFactory<MODEL>();
114  boost::ptr_vector<LinearModel_> tlmvec;
118  pptraj));
119  State_ xx(*xref_);
120  model_->forecast(xx, *bias_, len, post);
121  tlm_.reset(tlmvec.release(tlmvec.begin()).release());
122  }
123 
125 
126  boost::scoped_ptr<const eckit::LocalConfiguration> test_;
127  boost::scoped_ptr<const eckit::LocalConfiguration> tlConf_;
128  boost::scoped_ptr<const Geometry_> resol_;
129  boost::scoped_ptr<const util::DateTime> time_;
130  boost::scoped_ptr<const oops::Variables> ctlvars_;
131  boost::scoped_ptr<const State_> xref_;
132  boost::scoped_ptr<const Model_> model_;
133  boost::scoped_ptr<const ModelAux_> bias_;
134  boost::scoped_ptr<const ModelAuxIncr_> dbias_;
135  boost::scoped_ptr<const Covariance_> B_;
136  boost::scoped_ptr<const LinearModel_> tlm_;
137 };
138 
139 // =============================================================================
140 
141 template <typename MODEL> void testLinearModelConstructor() {
142  typedef LinearModelFixture<MODEL> Test_;
143 
144  const util::Duration zero(0);
145  BOOST_CHECK(Test_::tlm().timeResolution() > zero);
146 }
147 
148 // -----------------------------------------------------------------------------
149 
150 template <typename MODEL> void testLinearModelZeroLength() {
151  typedef LinearModelFixture<MODEL> Test_;
152  typedef oops::Increment<MODEL> Increment_;
153  typedef oops::ModelAuxIncrement<MODEL> ModelAuxIncr_;
154 
155  const util::DateTime vt(Test_::time());
156  const util::Duration zero(0);
157 
158  Increment_ dxref(Test_::resol(), Test_::ctlvars(), vt);
159  Test_::covariance().randomize(dxref);
160  ModelAuxIncr_ daux(Test_::dbias());
161  const double ininorm = dxref.norm();
162  BOOST_CHECK(ininorm > 0.0);
163 
164  Increment_ dx(Test_::resol(), Test_::ctlvars(), vt);
165  Increment_ dxm(Test_::resol(), Test_::tlm().variables(), vt);
166  dxm = dxref;
167  Test_::tlm().forecastTL(dxm, daux, zero);
168  dx = dxm;
169  BOOST_CHECK_EQUAL(dx.validTime(), vt);
170  BOOST_CHECK_EQUAL(dx.norm(), ininorm);
171 
172  dxm.zero();
173  dxm = dxref;
174  Test_::tlm().forecastAD(dxm, daux, zero);
175  dx = dxm;
176  BOOST_CHECK_EQUAL(dx.validTime(), vt);
177  BOOST_CHECK_EQUAL(dx.norm(), ininorm);
178 }
179 
180 // -----------------------------------------------------------------------------
181 
182 template <typename MODEL> void testLinearModelZeroPert() {
183  typedef LinearModelFixture<MODEL> Test_;
184  typedef oops::Increment<MODEL> Increment_;
185  typedef oops::ModelAuxIncrement<MODEL> ModelAuxIncr_;
186 
187  const util::Duration len(Test_::test().getString("fclength"));
188  const util::DateTime t1(Test_::time());
189  const util::DateTime t2(t1 + len);
190  BOOST_CHECK(t2 > t1);
191 
192  Increment_ dx(Test_::resol(), Test_::tlm().variables(), t1);
193  ModelAuxIncr_ daux(Test_::dbias());
194 
195  dx.zero();
196  daux.zero();
197  BOOST_CHECK_EQUAL(dx.norm(), 0.0);
198  Test_::tlm().forecastTL(dx, daux, len);
199  BOOST_CHECK_EQUAL(dx.validTime(), t2);
200  BOOST_CHECK_EQUAL(dx.norm(), 0.0);
201 
202  dx.zero();
203  daux.zero();
204  BOOST_CHECK_EQUAL(dx.norm(), 0.0);
205  Test_::tlm().forecastAD(dx, daux, len);
206  BOOST_CHECK_EQUAL(dx.validTime(), t1);
207  BOOST_CHECK_EQUAL(dx.norm(), 0.0);
208 }
209 
210 // -----------------------------------------------------------------------------
211 
212 template <typename MODEL> void testLinearModelLinearity() {
213  typedef LinearModelFixture<MODEL> Test_;
214  typedef oops::Increment<MODEL> Increment_;
215  typedef oops::ModelAuxIncrement<MODEL> ModelAuxIncr_;
216 
217  const util::Duration len(Test_::test().getString("fclength"));
218  const util::DateTime t1(Test_::time());
219  const util::DateTime t2(t1 + len);
220  BOOST_CHECK(t2 > t1);
221  const double zz = 3.1415;
222 
223  Increment_ dx1(Test_::resol(), Test_::tlm().variables(), t1);
224  Test_::covariance().randomize(dx1);
225  ModelAuxIncr_ daux1(Test_::dbias());
226  BOOST_CHECK(dx1.norm() > 0.0);
227 
228  Increment_ dx2(dx1);
229  ModelAuxIncr_ daux2(daux1);
230 
231  Test_::tlm().forecastTL(dx1, daux1, len);
232  BOOST_CHECK_EQUAL(dx1.validTime(), t2);
233  dx1 *= zz;
234  daux1 *= zz;
235 
236  dx2 *= zz;
237  daux2 *= zz;
238  Test_::tlm().forecastTL(dx2, daux2, len);
239  BOOST_CHECK_EQUAL(dx2.validTime(), t2);
240 
241  const double tol = Test_::test().getDouble("toleranceAD");
242  BOOST_CHECK_CLOSE(dx1.norm(), dx2.norm(), tol);
243 }
244 
245 // -----------------------------------------------------------------------------
246 
247 template <typename MODEL> void testLinearApproximation() {
248  typedef LinearModelFixture<MODEL> Test_;
249  typedef oops::Increment<MODEL> Increment_;
250  typedef oops::State<MODEL> State_;
251 
252  const util::Duration len(Test_::test().getString("fclength"));
253  const util::DateTime t1(Test_::time());
254  const util::DateTime t2(t1 + len);
255  BOOST_CHECK(t2 > t1);
256 
257  Increment_ dx0(Test_::resol(), Test_::tlm().variables(), t1);
258  Test_::covariance().randomize(dx0);
259  BOOST_CHECK(dx0.norm() > 0.0);
260 
261  Increment_ dx(dx0);
262  Test_::tlm().forecastTL(dx, Test_::dbias(), len);
263  const double dxnorm = dx.norm();
264 
266  State_ xx0(Test_::xref());
267  Test_::model().forecast(xx0, Test_::bias(), len, post);
268 
269  const unsigned int ntest = Test_::test().getInt("testiterTL");
270  double zz = 1.0;
271  if (Test_::test().has("firstmulTL")) {
272  zz = Test_::test().getDouble("firstmulTL");
273  }
274 
275  std::vector<double> errors;
276  for (unsigned int jtest = 0; jtest < ntest; ++jtest) {
277  State_ xx(Test_::xref());
278  Increment_ pert(dx0);
279  pert *= zz;
280  xx += pert;
281  Test_::model().forecast(xx, Test_::bias(), len, post);
282 
283  Increment_ diff(Test_::resol(), Test_::tlm().variables(), t2);
284  diff.diff(xx, xx0);
285  const double difnorm = diff.norm();
286  const double err = zz * dxnorm / difnorm;
287  Increment_ derr(dx);
288  derr *= zz;
289  derr -= diff;
290  const double errnorm = derr.norm();
291  errors.push_back(errnorm / difnorm);
292  oops::Log::test() << "TL error = " << std::setprecision(16) << err
293  << ", relative error = " << errnorm / difnorm << std::endl;
294  zz /= 10.0;
295  }
296 
297 // Analyze results
298  const double approx = *std::min_element(errors.begin(), errors.end());
299  oops::Log::test() << "Test TL min error = " << approx << std::endl;
300  const double tol = Test_::test().getDouble("toleranceTL");
301  BOOST_CHECK(approx < tol);
302 }
303 
304 // -----------------------------------------------------------------------------
305 
306 template <typename MODEL> void testLinearModelAdjoint() {
307  typedef LinearModelFixture<MODEL> Test_;
308  typedef oops::Increment<MODEL> Increment_;
309  typedef oops::ModelAuxIncrement<MODEL> ModelAuxIncr_;
310 
311  const util::Duration len(Test_::test().getString("fclength"));
312  const util::DateTime t1(Test_::time());
313  const util::DateTime t2(t1 + len);
314  BOOST_CHECK(t2 > t1);
315 
316  Increment_ dx11(Test_::resol(), Test_::tlm().variables(), t1);
317  Test_::covariance().randomize(dx11);
318  ModelAuxIncr_ daux1(Test_::dbias());
319  BOOST_CHECK(dx11.norm() > 0.0);
320  Increment_ dx12(dx11);
321  Test_::tlm().forecastTL(dx12, daux1, len);
322  BOOST_CHECK(dx12.norm() > 0.0);
323 
324  Increment_ dx22(Test_::resol(), Test_::tlm().variables(), t2);
325  Test_::covariance().randomize(dx22);
326  ModelAuxIncr_ daux2(Test_::dbias());
327  BOOST_CHECK(dx22.norm() > 0.0);
328  Increment_ dx21(dx22);
329  Test_::tlm().forecastAD(dx21, daux2, len);
330  BOOST_CHECK(dx21.norm() > 0.0);
331 
332  BOOST_CHECK(dx11.norm() != dx22.norm());
333  BOOST_CHECK_EQUAL(dx11.validTime(), t1);
334  BOOST_CHECK_EQUAL(dx21.validTime(), t1);
335  BOOST_CHECK_EQUAL(dx12.validTime(), t2);
336  BOOST_CHECK_EQUAL(dx22.validTime(), t2);
337 
338  const double dot1 = dot_product(dx11, dx21);
339  const double dot2 = dot_product(dx12, dx22);
340  const double tol = Test_::test().getDouble("toleranceAD");
341  BOOST_CHECK_CLOSE(dot1, dot2, tol);
342 }
343 
344 // =============================================================================
345 
346 template <typename MODEL> class LinearModel : public oops::Test {
347  public:
349  virtual ~LinearModel() {}
350  private:
351  std::string testid() const {return "test::LinearModel<" + MODEL::name() + ">";}
352 
353  void register_tests() const {
354  boost::unit_test::test_suite * ts = BOOST_TEST_SUITE("interface/LinearModel");
355 
356  ts->add(BOOST_TEST_CASE(&testLinearModelConstructor<MODEL>));
357  ts->add(BOOST_TEST_CASE(&testLinearModelZeroLength<MODEL>));
358  ts->add(BOOST_TEST_CASE(&testLinearModelZeroPert<MODEL>));
359  ts->add(BOOST_TEST_CASE(&testLinearModelLinearity<MODEL>));
360  ts->add(BOOST_TEST_CASE(&testLinearApproximation<MODEL>));
361  ts->add(BOOST_TEST_CASE(&testLinearModelAdjoint<MODEL>));
362  boost::unit_test::framework::master_test_suite().add(ts);
363  }
364 };
365 
366 // =============================================================================
367 
368 } // namespace test
369 
370 #endif // TEST_INTERFACE_LINEARMODEL_H_
boost::scoped_ptr< const eckit::LocalConfiguration > test_
static const ModelAuxIncr_ & dbias()
void testLinearApproximation()
oops::ModelAuxIncrement< MODEL > ModelAuxIncr_
static const eckit::Configuration & test()
boost::scoped_ptr< const ModelAuxIncr_ > dbias_
oops::Increment< MODEL > Increment_
boost::scoped_ptr< const util::DateTime > time_
integer, parameter ntest
Definition: type_nicas.F90:35
boost::scoped_ptr< const oops::Variables > ctlvars_
void testLinearModelLinearity()
real, parameter t2
Encapsulates the model state.
Save trajectory during forecast run.
static const eckit::Configuration & config()
program test
boost::scoped_ptr< const Geometry_ > resol_
character(len=32) name
oops::ModelAuxControl< MODEL > ModelAux_
boost::scoped_ptr< const ModelAux_ > bias_
real(double), parameter zero
real, dimension(:,:,:), allocatable vt
oops::ModelSpaceCovarianceBase< MODEL > Covariance_
static const Geometry_ & resol()
std::string testid() const
real, parameter t1
static const LinearModel_ & tlm()
Control model post processing.
void testLinearModelZeroLength()
Encapsulates the nonlinear forecast model.
Abstract base class for model space error covariances.
static const ModelAux_ & bias()
string tlm
Definition: TLM_vs_NLM.py:25
boost::scoped_ptr< const eckit::LocalConfiguration > tlConf_
void testLinearModelAdjoint()
oops::Geometry< MODEL > Geometry_
string release
Definition: conf.py:67
boost::scoped_ptr< const State_ > xref_
Increment Class: Difference between two states.
boost::scoped_ptr< const Covariance_ > B_
static const oops::Variables & ctlvars()
boost::scoped_ptr< const LinearModel_ > tlm_
oops::LinearModel< MODEL > LinearModel_
Control model post processing.
Definition: PostProcessor.h:31
void testLinearModelZeroPert()
void testLinearModelConstructor()
static const util::DateTime & time()
static const Covariance_ & covariance()
Encapsulates the linear forecast model.
boost::scoped_ptr< const Model_ > model_
void enrollProcessor(PostBase_ *pp)
Definition: PostProcessor.h:39
static LinearModelFixture< MODEL > & getInstance()