OOPS
test/interface/LinearVariableChange.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_LINEARVARIABLECHANGE_H_
12 #define TEST_INTERFACE_LINEARVARIABLECHANGE_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"
27 #include "oops/base/Variables.h"
31 #include "oops/interface/State.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 LinearVariableChangeFixture : private boost::noncopyable {
47  typedef util::DateTime DateTime_;
48 
49  public:
50  static std::vector<eckit::LocalConfiguration> & confs() {return getInstance().confs_;}
51  static const State_ & xx() {return *getInstance().xx_;}
52  static const Geometry_ & resol() {return *getInstance().resol_;}
53  static const DateTime_ & time() {return *getInstance().time_;}
54 
55  private:
57  static LinearVariableChangeFixture<MODEL> theLinearVariableChangeFixture;
58  return theLinearVariableChangeFixture;
59  }
60 
62  oops::instantiateVariableChangeFactory<MODEL>();
63 
64  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "geometry");
65  resol_.reset(new Geometry_(resolConfig, oops::mpi::world()));
66 
67  const eckit::LocalConfiguration fgconf(TestEnvironment::config(), "background");
68  xx_.reset(new State_(*resol_, fgconf));
69 
70  time_.reset(new util::DateTime(xx_->validTime()));
71 
72  TestEnvironment::config().get("linear variable change tests", confs_);
73  }
74 
75  ~LinearVariableChangeFixture<MODEL>() {}
76 
77  std::vector<eckit::LocalConfiguration> confs_;
78  std::unique_ptr<const State_ > xx_;
79  std::unique_ptr<const Geometry_> resol_;
80  std::unique_ptr<const util::DateTime> time_;
81 };
82 
83 // -----------------------------------------------------------------------------
84 
85 template <typename MODEL> void testLinearVariableChangeZero() {
87  typedef oops::Increment<MODEL> Increment_;
88  typedef oops::LinearVariableChangeBase<MODEL> LinearVariableChange_;
89  typedef oops::LinearVariableChangeFactory<MODEL> LinearVariableChangeFactory_;
90 
91  for (std::size_t jj = 0; jj < Test_::confs().size(); ++jj) {
92  oops::Variables varin(Test_::confs()[jj], "input variables");
93  oops::Variables varout(Test_::confs()[jj], "output variables");
94 
95  std::unique_ptr<LinearVariableChange_> changevar(LinearVariableChangeFactory_::create(
96  Test_::xx(), Test_::xx(),
97  Test_::resol(), Test_::confs()[jj]));
98 
99  Increment_ dxinTlIAd(Test_::resol(), varin, Test_::time());
100  Increment_ dxinAdInv(Test_::resol(), varout, Test_::time());
101  Increment_ dxoutTlIAd(Test_::resol(), varout, Test_::time());
102  Increment_ dxoutAdInv(Test_::resol(), varin, Test_::time());
103 
104  // dxinTlIAd = 0, check if K.dxinTlIAd = 0
105  dxinTlIAd.zero();
106  dxoutTlIAd = changevar->multiply(dxinTlIAd);
107  EXPECT(dxoutTlIAd.norm() == 0.0);
108 
109  // dxinAdInv = 0, check if K^T.dxinAdInv = 0
110  dxinAdInv.zero();
111  dxoutAdInv = changevar->multiplyAD(dxinAdInv);
112  EXPECT(dxoutAdInv.norm() == 0.0);
113 
114  const bool testinverse = Test_::confs()[jj].getBool("test inverse", true);
115  if (testinverse)
116  {
117  oops::Log::info() << "Doing zero test for inverse" << std::endl;
118  dxinTlIAd.zero();
119  dxoutTlIAd = changevar->multiplyInverseAD(dxinTlIAd);
120  EXPECT(dxoutTlIAd.norm() == 0.0);
121 
122  dxinAdInv.zero();
123  dxoutAdInv = changevar->multiplyInverse(dxinAdInv);
124  EXPECT(dxoutAdInv.norm() == 0.0);
125  } else {
126  oops::Log::info() << "Not doing zero test for inverse" << std::endl;
127  }
128  }
129 }
130 // -----------------------------------------------------------------------------
131 
132 template <typename MODEL> void testLinearVariableChangeAdjoint() {
134  typedef oops::Increment<MODEL> Increment_;
135  typedef oops::LinearVariableChangeBase<MODEL> LinearVariableChange_;
136  typedef oops::LinearVariableChangeFactory<MODEL> LinearVariableChangeFactory_;
137 
138  for (std::size_t jj = 0; jj < Test_::confs().size(); ++jj) {
139  oops::Variables varin(Test_::confs()[jj], "input variables");
140  oops::Variables varout(Test_::confs()[jj], "output variables");
141 
142  std::unique_ptr<LinearVariableChange_> changevar(LinearVariableChangeFactory_::create(
143  Test_::xx(), Test_::xx(),
144  Test_::resol(), Test_::confs()[jj]));
145 
146  Increment_ dxinAdInv(Test_::resol(), varout, Test_::time());
147  Increment_ dxinTlIAd(Test_::resol(), varin, Test_::time());
148  Increment_ dxoutAdInv(Test_::resol(), varin, Test_::time());
149  Increment_ dxoutTlIAd(Test_::resol(), varout, Test_::time());
150 
151  dxinAdInv.random();
152  dxinTlIAd.random();
153 
154  Increment_ dxinAdInv0(dxinAdInv);
155  Increment_ dxinTlIAd0(dxinTlIAd);
156 
157  dxoutTlIAd = changevar->multiply(dxinTlIAd);
158  dxoutAdInv = changevar->multiplyAD(dxinAdInv);
159 
160  // zz1 = <dxoutTlIAd,dxinAdInv>
161  double zz1 = dot_product(dxoutTlIAd, dxinAdInv0);
162  // zz2 = <dxout,dxoutAdInv>
163  double zz2 = dot_product(dxinTlIAd0, dxoutAdInv);
164 
165  oops::Log::info() << "<dxout,KTdxin>-<Kdxout,dxin>/<dxout,KTdxin>="
166  << (zz1-zz2)/zz1 << std::endl;
167  oops::Log::info() << "<dxout,KTdxin>-<Kdxout,dxin>/<Kdxout,dxin>="
168  << (zz1-zz2)/zz2 << std::endl;
169  const double tol = 1e-10;
170  EXPECT(oops::is_close(zz1, zz2, tol));
171  const bool testinverse = Test_::confs()[jj].getBool("test inverse", true);
172  if (testinverse)
173  {
174  oops::Log::info() << "Doing adjoint test for inverse" << std::endl;
175  dxoutAdInv.zero();
176  dxoutTlIAd.zero();
177  dxinAdInv.random();
178  dxinTlIAd.random();
179  dxinAdInv0 = dxinAdInv;
180  dxinTlIAd0 = dxinTlIAd;
181  dxoutTlIAd = changevar->multiplyInverseAD(dxinTlIAd);
182  dxoutAdInv = changevar->multiplyInverse(dxinAdInv);
183  zz1 = dot_product(dxoutTlIAd, dxinAdInv0);
184  zz2 = dot_product(dxinTlIAd0, dxoutAdInv);
185  oops::Log::info() << "<dxout,KinvTdxin>-<Kinvdxout,dxin>/<dxout,KinvTdxin>="
186  << (zz1-zz2)/zz1 << std::endl;
187  oops::Log::info() << "<dxout,KinvTdxin>-<Kinvdxout,dxin>/<Kinvdxout,dxin>="
188  << (zz1-zz2)/zz2 << std::endl;
189  EXPECT(oops::is_close(zz1, zz2, tol));
190  } else {
191  oops::Log::info() << "Not doing adjoint test for inverse" << std::endl;
192  }
193  }
194 }
195 
196 // -----------------------------------------------------------------------------
197 
198 template <typename MODEL> void testLinearVariableChangeInverse() {
200  typedef oops::Increment<MODEL> Increment_;
201  typedef oops::LinearVariableChangeBase<MODEL> LinearVariableChange_;
202  typedef oops::LinearVariableChangeFactory<MODEL> LinearVariableChangeFactory_;
203 
204  for (std::size_t jj = 0; jj < Test_::confs().size(); ++jj) {
205  oops::Variables varin(Test_::confs()[jj], "input variables");
206  oops::Variables varout(Test_::confs()[jj], "output variables");
207 
208  const double tol = Test_::confs()[jj].getDouble("tolerance inverse");
209 
210  const bool testinverse = Test_::confs()[jj].getBool("test inverse", false);
211  if (testinverse)
212  {
213  oops::Log::info() << "Testing multiplyInverse" << std::endl;
214  std::unique_ptr<LinearVariableChange_> changevar(LinearVariableChangeFactory_::create(
215  Test_::xx(), Test_::xx(),
216  Test_::resol(), Test_::confs()[jj]));
217 
218  Increment_ dxinInv(Test_::resol(), varout, Test_::time());
219  Increment_ dxoutInv(Test_::resol(), varin, Test_::time());
220  Increment_ dxout(Test_::resol(), varout, Test_::time());
221 
222  dxinInv.random();
223 
224  dxoutInv = changevar->multiplyInverse(dxinInv);
225  dxout = changevar->multiply(dxoutInv);
226 
227  const double zz1 = dxinInv.norm();
228  const double zz2 = dxout.norm();
229 
230  oops::Log::info() << "<x>, <KK^{-1}x>=" << zz1 << " " << zz2 << std::endl;
231  oops::Log::info() << "<x>-<KK^{-1}x>=" << zz1-zz2 << std::endl;
232 
233  EXPECT((zz1-zz2) < tol);
234  } else {
235  oops::Log::info() << "multiplyInverse test not executed" << std::endl;
236  EXPECT(1.0 < 2.0);
237  }
238  }
239 }
240 
241 // -----------------------------------------------------------------------------
242 
243 template <typename MODEL> void testLinearVariableChangeParametersWrapperValidName() {
245  for (const eckit::Configuration &config : Test_::confs()) {
247  EXPECT_NO_THROW(parameters.validateAndDeserialize(config));
248  }
249 }
250 
251 // -----------------------------------------------------------------------------
252 
254  eckit::LocalConfiguration config;
255  config.set("variable change", "###INVALID###");
257  if (oops::Parameters::isValidationSupported())
258  EXPECT_THROWS_MSG(parameters.validate(config), "unrecognized enum value");
259  EXPECT_THROWS_MSG(parameters.deserialize(config),
260  "does not exist in LinearVariableChangeFactory");
261 }
262 
263 // -----------------------------------------------------------------------------
264 
265 template <typename MODEL> void testLinearVariableChangeFactoryGetMakerNames() {
267  const std::vector<std::string> registeredNames =
269  for (const eckit::Configuration &config : Test_::confs()) {
270  const std::string validName = config.getString("variable change");
271  const bool found = std::find(registeredNames.begin(), registeredNames.end(), validName) !=
272  registeredNames.end();
273  EXPECT(found);
274  }
275 }
276 
277 // -----------------------------------------------------------------------------
278 
279 template <typename MODEL>
281  public:
284 
285  private:
286  std::string testid() const override {return "test::LinearVariableChange<" + MODEL::name() + ">";}
287 
288  void register_tests() const override {
289  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
290 
291  ts.emplace_back(CASE("interface/LinearVariableChange/testLinearVariableChangeZero")
292  { testLinearVariableChangeZero<MODEL>(); });
293  ts.emplace_back(CASE("interface/LinearVariableChange/testLinearVariableChangeAdjoint")
294  { testLinearVariableChangeAdjoint<MODEL>(); });
295  ts.emplace_back(CASE("interface/LinearVariableChange/testLinearVariableChangeInverse")
296  { testLinearVariableChangeInverse<MODEL>(); });
297  ts.emplace_back(CASE("interface/LinearVariableChange/"
298  "testLinearVariableChangeParametersWrapperValidName")
299  { testLinearVariableChangeParametersWrapperValidName<MODEL>(); });
300  ts.emplace_back(CASE("interface/LinearVariableChange/"
301  "testLinearVariableChangeParametersWrapperInvalidName")
302  { testLinearVariableChangeParametersWrapperInvalidName<MODEL>(); });
303  ts.emplace_back(CASE("interface/LinearVariableChange/"
304  "testLinearVariableChangeFactoryGetMakerNames")
305  { testLinearVariableChangeFactoryGetMakerNames<MODEL>(); });
306  }
307 
308  void clear() const override {}
309 };
310 
311 // -----------------------------------------------------------------------------
312 
313 } // namespace test
314 
315 #endif // TEST_INTERFACE_LINEARVARIABLECHANGE_H_
test::testLinearVariableChangeZero
void testLinearVariableChangeZero()
Definition: test/interface/LinearVariableChange.h:85
test::LinearVariableChangeFixture::resol_
std::unique_ptr< const Geometry_ > resol_
Definition: test/interface/LinearVariableChange.h:79
oops::LinearVariableChangeFactory
LinearVariableChange factory.
Definition: LinearVariableChangeBase.h:85
mpi.h
test::LinearVariableChange::register_tests
void register_tests() const override
Definition: test/interface/LinearVariableChange.h:288
oops::LinearVariableChangeFactory::getMakerNames
static std::vector< std::string > getMakerNames()
Return the names of all linear variable changes that can be created by one of the registered makers.
Definition: LinearVariableChangeBase.h:155
test::testLinearVariableChangeFactoryGetMakerNames
void testLinearVariableChangeFactoryGetMakerNames()
Definition: test/interface/LinearVariableChange.h:265
test::testLinearVariableChangeParametersWrapperInvalidName
void testLinearVariableChangeParametersWrapperInvalidName()
Definition: test/interface/LinearVariableChange.h:253
test::CASE
CASE("test_linearmodelparameterswrapper_valid_name")
Definition: LinearModelFactory.cc:22
test::LinearVariableChange
Definition: test/interface/LinearVariableChange.h:280
test::LinearVariableChangeFixture::getInstance
static LinearVariableChangeFixture< MODEL > & getInstance()
Definition: test/interface/LinearVariableChange.h:56
oops::LinearVariableChangeParametersWrapper
Contains a polymorphic parameter holding an instance of a subclass of LinearVariableChangeParametersB...
Definition: LinearVariableChangeBase.h:110
test::LinearVariableChangeFixture::xx
static const State_ & xx()
Definition: test/interface/LinearVariableChange.h:51
test::LinearVariableChange::~LinearVariableChange
virtual ~LinearVariableChange()
Definition: test/interface/LinearVariableChange.h:283
test::testLinearVariableChangeParametersWrapperValidName
void testLinearVariableChangeParametersWrapperValidName()
Definition: test/interface/LinearVariableChange.h:243
test::LinearVariableChangeFixture::DateTime_
util::DateTime DateTime_
Definition: test/interface/LinearVariableChange.h:47
test
Definition: LinearModelFactory.cc:20
oops::LinearVariableChangeBase
Definition: LinearVariableChangeBase.h:53
test::LinearVariableChangeFixture::xx_
std::unique_ptr< const State_ > xx_
Definition: test/interface/LinearVariableChange.h:78
Test.h
test::LinearVariableChange::LinearVariableChange
LinearVariableChange()
Definition: test/interface/LinearVariableChange.h:282
test::LinearVariableChangeFixture::confs_
std::vector< eckit::LocalConfiguration > confs_
Definition: test/interface/LinearVariableChange.h:77
test::TestEnvironment::config
static const eckit::Configuration & config()
Definition: TestEnvironment.h:40
test::LinearVariableChangeFixture::confs
static std::vector< eckit::LocalConfiguration > & confs()
Definition: test/interface/LinearVariableChange.h:50
test::testLinearVariableChangeAdjoint
void testLinearVariableChangeAdjoint()
Definition: test/interface/LinearVariableChange.h:132
instantiateVariableChangeFactory.h
test::testLinearVariableChangeInverse
void testLinearVariableChangeInverse()
Definition: test/interface/LinearVariableChange.h:198
test::LinearVariableChangeFixture::time
static const DateTime_ & time()
Definition: test/interface/LinearVariableChange.h:53
oops::Geometry
Geometry class used in oops; subclass of interface class above.
Definition: oops/interface/Geometry.h:189
test::LinearVariableChangeFixture::resol
static const Geometry_ & resol()
Definition: test/interface/LinearVariableChange.h:52
TestEnvironment.h
test::LinearVariableChangeFixture::State_
oops::State< MODEL > State_
Definition: test/interface/LinearVariableChange.h:46
test::LinearVariableChangeFixture
Definition: test/interface/LinearVariableChange.h:44
oops::State
Encapsulates the model state.
Definition: CostJbState.h:28
test::LinearVariableChangeFixture::Geometry_
oops::Geometry< MODEL > Geometry_
Definition: test/interface/LinearVariableChange.h:45
oops::Test
Definition: Test.h:39
test::LinearVariableChangeFixture::time_
std::unique_ptr< const util::DateTime > time_
Definition: test/interface/LinearVariableChange.h:80
State.h
oops::mpi::world
const eckit::mpi::Comm & world()
Default communicator with all MPI tasks (ie MPI_COMM_WORLD)
Definition: oops/mpi/mpi.cc:22
oops::Variables
Definition: oops/base/Variables.h:23
oops::Increment
Increment Class: Difference between two states.
Definition: CostJbState.h:27
test::LinearVariableChange::testid
std::string testid() const override
Definition: test/interface/LinearVariableChange.h:286
test::LinearVariableChange::clear
void clear() const override
Definition: test/interface/LinearVariableChange.h:308
LinearVariableChangeBase.h
Variables.h
Geometry.h
Increment.h