IODA Bundle
test/interface/Model.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_MODEL_H_
12 #define TEST_INTERFACE_MODEL_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/LocalConfiguration.h"
25 #include "eckit/testing/Test.h"
26 #include "oops/base/Geometry.h"
27 #include "oops/base/Model.h"
29 #include "oops/base/State.h"
31 #include "oops/mpi/mpi.h"
32 #include "oops/runs/Test.h"
33 #include "oops/util/DateTime.h"
34 #include "oops/util/Duration.h"
35 #include "test/TestEnvironment.h"
36 
37 namespace test {
38 
39 // =================================================================================================
40 
41 template <typename MODEL> class ModelFixture : 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 State_ & xref() {return *getInstance().xref_;}
51  static const ModelAux_ & bias() {return *getInstance().bias_;}
52  static const Model_ & model() {return *getInstance().model_;}
53  static void reset() {
54  getInstance().xref_.reset();
55  getInstance().bias_.reset();
56  getInstance().model_.reset();
57  getInstance().resol_.reset();
58  getInstance().test_.reset();
59  }
60 
61  private:
63  static ModelFixture<MODEL> theModelFixture;
64  return theModelFixture;
65  }
66 
68  test_.reset(new eckit::LocalConfiguration(TestEnvironment::config(), "model test"));
69 
70  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "geometry");
71  resol_.reset(new Geometry_(resolConfig, oops::mpi::world()));
72 
73  const eckit::LocalConfiguration biasConf(TestEnvironment::config(), "model aux control");
74  bias_.reset(new ModelAux_(*resol_, biasConf));
75 
76  const eckit::LocalConfiguration conf(TestEnvironment::config(), "model");
77  model_.reset(new Model_(*resol_, conf));
78 
79  const eckit::LocalConfiguration iniConf(TestEnvironment::config(), "initial condition");
80  xref_.reset(new State_(*resol_, iniConf));
81  }
82 
83  ~ModelFixture<MODEL>() {}
84 
85  std::unique_ptr<const eckit::LocalConfiguration> test_;
86  std::unique_ptr<const Geometry_> resol_;
87  std::unique_ptr<const State_> xref_;
88  std::unique_ptr<const ModelAux_> bias_;
89  std::unique_ptr<const Model_> model_;
90 };
91 
92 // =================================================================================================
93 
94 /// \brief tests constructor, timeResolution() method and print method
95 template <typename MODEL> void testModelConstructor() {
96  typedef ModelFixture<MODEL> Test_;
97 
98  const util::Duration zero(0);
99  EXPECT(Test_::model().timeResolution() > zero);
100  oops::Log::test() << "Testing Model: " << Test_::model() << std::endl;
101 }
102 
103 // -------------------------------------------------------------------------------------------------
104 
105 template <typename MODEL> void testModelNoForecast() {
106  typedef ModelFixture<MODEL> Test_;
107  typedef oops::State<MODEL> State_;
108 
109  const double ininorm = Test_::xref().norm();
110  State_ xx(Test_::xref());
111  const util::DateTime vt(xx.validTime());
112 
113  const util::Duration zero(0);
115 
116  Test_::model().forecast(xx, Test_::bias(), zero, post);
117 
118  EXPECT(xx.validTime() == vt);
119  EXPECT(xx.norm() == ininorm);
120 
121 // Recomputing initial norm to make sure nothing bad happened
122  EXPECT(Test_::xref().norm() == ininorm);
123 }
124 
125 // -------------------------------------------------------------------------------------------------
126 
127 template <typename MODEL> void testModelForecast() {
128  typedef ModelFixture<MODEL> Test_;
129  typedef oops::State<MODEL> State_;
130 
131  const double fnorm = Test_::test().getDouble("final norm");
132  const double tol = Test_::test().getDouble("tolerance");
133  const util::Duration len(Test_::test().getString("forecast length"));
134 
135  const double ininorm = Test_::xref().norm();
136  State_ xx(Test_::xref());
137  const util::DateTime vt(xx.validTime()+len);
138 
140 
141  Test_::model().forecast(xx, Test_::bias(), len, post);
142 
143  EXPECT(xx.validTime() == vt);
144 
145  oops::Log::debug() << "xx.norm(): " << std::fixed << std::setprecision(8) << xx.norm()
146  << std::endl;
147  oops::Log::debug() << "fnorm: " << std::fixed << std::setprecision(8) << fnorm << std::endl;
148 
149  EXPECT(oops::is_close(xx.norm(), fnorm, tol));
150 
151 // Recomputing initial norm to make sure nothing bad happened
152  EXPECT(Test_::xref().norm() == ininorm);
153 }
154 
155 // -------------------------------------------------------------------------------------------------
156 
157 template <typename MODEL> void testModelReForecast() {
158  typedef ModelFixture<MODEL> Test_;
159  typedef oops::State<MODEL> State_;
160 
161  const bool testreforecast = Test_::test().getBool("test reforecast", true);
162 
163  if (testreforecast) {
164  // Forecast duration
165  const util::Duration len(Test_::test().getString("forecast length"));
166 
167  const double ininorm = Test_::xref().norm();
168 
169  // Initial states
170  State_ xx1(Test_::xref());
171  State_ xx2(Test_::xref());
172 
173  // Time at forecast end
174  const util::DateTime vt(xx1.validTime()+len);
175 
177 
178  // Forecast 1
179  Test_::model().forecast(xx1, Test_::bias(), len, post);
180 
181  // Forecast 2
182  Test_::model().forecast(xx2, Test_::bias(), len, post);
183 
184  // Check forecasts ran to expected time
185  EXPECT(xx1.validTime() == vt);
186  EXPECT(xx2.validTime() == vt);
187 
188  // Print the final norms
189  oops::Log::debug() << "xx1.norm(): " << std::fixed << std::setprecision(8) << xx1.norm()
190  << std::endl;
191  oops::Log::debug() << "xx2.norm(): " << std::fixed << std::setprecision(8) << xx2.norm()
192  << std::endl;
193 
194  // Pass or fail condition
195  EXPECT(xx1.norm() == xx2.norm());
196 
197  // Recomputing initial norm to make sure nothing bad happened
198  EXPECT(Test_::xref().norm() == ininorm);
199  } else {
200  // Dummy test
201  EXPECT(0.0 == 0.0);
202  }
203 }
204 
205 // =================================================================================================
206 
207 template <typename MODEL>
208 class Model : public oops::Test {
209  public:
210  Model() {}
212  private:
213  std::string testid() const override {return "test::Model<" + MODEL::name() + ">";}
214 
215  void register_tests() const override {
216  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
217 
218  ts.emplace_back(CASE("interface/Model/testModelConstructor")
219  { testModelConstructor<MODEL>(); });
220  ts.emplace_back(CASE("interface/Model/testModelNoForecast")
221  { testModelNoForecast<MODEL>(); });
222  ts.emplace_back(CASE("interface/Model/testModelForecast")
223  { testModelForecast<MODEL>(); });
224  ts.emplace_back(CASE("interface/Model/testModelReForecast")
225  { testModelReForecast<MODEL>(); });
226  }
227 
228  void clear() const override {}
229 };
230 
231 // =================================================================================================
232 
233 } // namespace test
234 
235 #endif // TEST_INTERFACE_MODEL_H_
program test
Geometry class used in oops; subclass of interface class interface::Geometry.
Abstract nonlinear forecast model used by high level algorithms and applications.
Control model post processing.
Definition: PostProcessor.h:30
State class used in oops; subclass of interface class interface::State.
double norm() const
Norm (used in tests)
std::unique_ptr< const State_ > xref_
std::unique_ptr< const eckit::LocalConfiguration > test_
std::unique_ptr< const ModelAux_ > bias_
static const Model_ & model()
oops::State< MODEL > State_
oops::Model< MODEL > Model_
static const eckit::Configuration & test()
static ModelFixture< MODEL > & getInstance()
static const Geometry_ & resol()
static const ModelAux_ & bias()
oops::ModelAuxControl< MODEL > ModelAux_
static const State_ & xref()
std::unique_ptr< const Model_ > model_
oops::Geometry< MODEL > Geometry_
std::unique_ptr< const Geometry_ > resol_
void register_tests() const override
std::string testid() const override
void clear() 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 testModelConstructor()
tests constructor, timeResolution() method and print method
void testModelNoForecast()
void testModelReForecast()
void testModelForecast()
CASE("assimilation/FullGMRES/FullGMRES")