FV3 Bundle
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 <string>
17 #include <vector>
18 
19 #define BOOST_TEST_NO_MAIN
20 #define BOOST_TEST_ALTERNATIVE_INIT_API
21 #define BOOST_TEST_DYN_LINK
22 
23 #include <boost/noncopyable.hpp>
24 #include <boost/scoped_ptr.hpp>
25 #include <boost/test/unit_test.hpp>
26 
27 #include "eckit/config/Configuration.h"
29 #include "oops/base/Variables.h"
33 #include "oops/interface/State.h"
34 #include "oops/runs/Test.h"
35 #include "oops/util/DateTime.h"
36 #include "oops/util/dot_product.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>
51  & linvarchgconfs() {return getInstance().linvarchgconfs_;}
52  static const State_ & xx() {return *getInstance().xx_;}
53  static const Geometry_ & resol() {return *getInstance().resol_;}
54  static const DateTime_ & time() {return *getInstance().time_;}
55 
56  private:
58  static LinearVariableChangeFixture<MODEL> theLinearVariableChangeFixture;
59  return theLinearVariableChangeFixture;
60  }
61 
63  oops::instantiateLinearVariableChangeFactory<MODEL>();
64 
65  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "Geometry");
66  resol_.reset(new Geometry_(resolConfig));
67 
68  const oops::Variables vars(eckit::LocalConfiguration(TestEnvironment::config(), "State"));
69  const eckit::LocalConfiguration fgconf(TestEnvironment::config(), "State");
70  xx_.reset(new State_(*resol_, vars, fgconf));
71 
72  time_.reset(new util::DateTime(xx_->validTime()));
73 
74  TestEnvironment::config().get("LinearVariableChangeTests", linvarchgconfs_);
75  }
76 
78 
79  std::vector<eckit::LocalConfiguration> linvarchgconfs_;
80  boost::scoped_ptr<const State_ > xx_;
81  boost::scoped_ptr<const Geometry_> resol_;
82  boost::scoped_ptr<const util::DateTime> time_;
83 };
84 
85 // -----------------------------------------------------------------------------
86 
87 template <typename MODEL> void testLinearVariableChangeZero() {
89  typedef oops::Increment<MODEL> Increment_;
90  typedef oops::LinearVariableChangeBase<MODEL> LinearVariableChange_;
91  typedef oops::LinearVariableChangeFactory<MODEL> LinearVariableChangeFactory_;
92 
93  for (std::size_t jj = 0; jj < Test_::linvarchgconfs().size(); ++jj) {
94  eckit::LocalConfiguration varinconf(Test_::linvarchgconfs()[jj], "inputVariables");
95  eckit::LocalConfiguration varoutconf(Test_::linvarchgconfs()[jj], "outputVariables");
96  oops::Variables varin(varinconf);
97  oops::Variables varout(varoutconf);
98 
99  boost::scoped_ptr<LinearVariableChange_> changevar(LinearVariableChangeFactory_::create(
100  Test_::xx(), Test_::xx(),
101  Test_::resol(), Test_::linvarchgconfs()[jj]));
102 
103  Increment_ dxin(Test_::resol(), varin, Test_::time());
104  Increment_ KTdxin(Test_::resol(), varout, Test_::time());
105  Increment_ dxout(Test_::resol(), varout, Test_::time());
106  Increment_ Kdxout(Test_::resol(), varin, Test_::time());
107 
108  // dxout = 0, check if K.dxout = 0
109  dxout.zero();
110  changevar->multiply(dxout, Kdxout);
111  BOOST_CHECK_EQUAL(Kdxout.norm(), 0.0);
112 
113  // dxin = 0, check if K^T.dxin = 0
114  dxin.zero();
115  changevar->multiplyAD(dxin, KTdxin);
116  BOOST_CHECK_EQUAL(KTdxin.norm(), 0.0);
117 
118  const bool testinverse = Test_::linvarchgconfs()[jj].getBool("testinverse", true);
119  if (testinverse)
120  {
121  oops::Log::info() << "Doing zero test for inverse" << std::endl;
122  dxout.zero();
123  changevar->multiply(dxout, Kdxout);
124  BOOST_CHECK_EQUAL(Kdxout.norm(), 0.0);
125 
126  dxin.zero();
127  changevar->multiplyAD(dxin, KTdxin);
128  BOOST_CHECK_EQUAL(KTdxin.norm(), 0.0);
129  } else {
130  oops::Log::info() << "Not doing zero test for inverse" << std::endl;
131  }
132  }
133 }
134 // -----------------------------------------------------------------------------
135 
136 template <typename MODEL> void testLinearVariableChangeAdjoint() {
138  typedef oops::Increment<MODEL> Increment_;
139  typedef oops::LinearVariableChangeBase<MODEL> LinearVariableChange_;
140  typedef oops::LinearVariableChangeFactory<MODEL> LinearVariableChangeFactory_;
141 
142  for (std::size_t jj = 0; jj < Test_::linvarchgconfs().size(); ++jj) {
143  eckit::LocalConfiguration varinconf(Test_::linvarchgconfs()[jj], "inputVariables");
144  eckit::LocalConfiguration varoutconf(Test_::linvarchgconfs()[jj], "outputVariables");
145  oops::Variables varin(varinconf);
146  oops::Variables varout(varoutconf);
147 
148  boost::scoped_ptr<LinearVariableChange_> changevar(LinearVariableChangeFactory_::create(
149  Test_::xx(), Test_::xx(),
150  Test_::resol(), Test_::linvarchgconfs()[jj]));
151 
152  Increment_ dxin(Test_::resol(), varin, Test_::time());
153  Increment_ KTdxin(Test_::resol(), varout, Test_::time());
154  Increment_ dxout(Test_::resol(), varout, Test_::time());
155  Increment_ Kdxout(Test_::resol(), varin, Test_::time());
156 
157  dxin.random();
158  dxout.random();
159 
160  Increment_ dxin0(dxin);
161  Increment_ dxout0(dxout);
162 
163  changevar->multiply(dxout, Kdxout);
164  changevar->multiplyAD(dxin, KTdxin);
165 
166  // zz1 = <Kdxout,dxin>
167  double zz1 = dot_product(Kdxout, dxin0);
168  // zz2 = <dxout,KTdxin>
169  double zz2 = dot_product(dxout0, KTdxin);
170 
171  oops::Log::info() << "<dxout,KTdxin>-<Kdxout,dxin>/<dxout,KTdxin>="
172  << (zz1-zz2)/zz1 << std::endl;
173  oops::Log::info() << "<dxout,KTdxin>-<Kdxout,dxin>/<Kdxout,dxin>="
174  << (zz1-zz2)/zz2 << std::endl;
175  const double tol = 1e-8;
176  BOOST_CHECK_CLOSE(zz1, zz2, tol);
177  const bool testinverse = Test_::linvarchgconfs()[jj].getBool("testinverse", true);
178  if (testinverse)
179  {
180  oops::Log::info() << "Doing adjoint test for inverse" << std::endl;
181  dxin.random();
182  dxout.random();
183  dxin0 = dxin;
184  dxout0 = dxout;
185  changevar->multiplyInverse(dxout, Kdxout);
186  changevar->multiplyInverseAD(dxin, KTdxin);
187  zz1 = dot_product(Kdxout, dxin0);
188  zz2 = dot_product(dxout0, KTdxin);
189  oops::Log::info() << "<dxout,KinvTdxin>-<Kinvdxout,dxin>/<dxout,KinvTdxin>="
190  << (zz1-zz2)/zz1 << std::endl;
191  oops::Log::info() << "<dxout,KinvTdxin>-<Kinvdxout,dxin>/<Kinvdxout,dxin>="
192  << (zz1-zz2)/zz2 << std::endl;
193  BOOST_CHECK_CLOSE(zz1, zz2, tol);
194  } else {
195  oops::Log::info() << "Not doing adjoint test for inverse" << std::endl;
196  }
197  }
198 }
199 
200 // -----------------------------------------------------------------------------
201 
202 template <typename MODEL> void testLinearVariableChangeInverse() {
204  typedef oops::Increment<MODEL> Increment_;
205  typedef oops::LinearVariableChangeBase<MODEL> LinearVariableChange_;
206  typedef oops::LinearVariableChangeFactory<MODEL> LinearVariableChangeFactory_;
207 
208  for (std::size_t jj = 0; jj < Test_::linvarchgconfs().size(); ++jj) {
209  eckit::LocalConfiguration varinconf(Test_::linvarchgconfs()[jj], "inputVariables");
210  eckit::LocalConfiguration varoutconf(Test_::linvarchgconfs()[jj], "outputVariables");
211  oops::Variables varin(varinconf);
212  oops::Variables varout(varoutconf);
213 
214  const double tol = Test_::linvarchgconfs()[jj].getDouble("toleranceInverse");
215 
216  const bool testinverse = Test_::linvarchgconfs()[jj].getBool("testinverse", false);
217  if (testinverse)
218  {
219  oops::Log::info() << "Testing multiplyInverse" << std::endl;
220  boost::scoped_ptr<LinearVariableChange_> changevar(LinearVariableChangeFactory_::create(
221  Test_::xx(), Test_::xx(),
222  Test_::resol(), Test_::linvarchgconfs()[jj]));
223 
224  Increment_ dxin(Test_::resol(), varin, Test_::time());
225  Increment_ KIdxin(Test_::resol(), varout, Test_::time());
226  Increment_ KKIdxin(Test_::resol(), varin, Test_::time());
227 
228  dxin.random();
229 
230  changevar->multiplyInverse(dxin, KIdxin);
231  changevar->multiply(KIdxin, KKIdxin);
232 
233  const double zz1 = dxin.norm();
234  const double zz2 = KKIdxin.norm();
235 
236  oops::Log::info() << "<x>, <KK^{-1}x>=" << zz1 << " " << zz2 << std::endl;
237  oops::Log::info() << "<x>-<KK^{-1}x>=" << zz1-zz2 << std::endl;
238 
239  BOOST_CHECK((zz1-zz2) < tol);
240  } else {
241  oops::Log::info() << "multiplyInverse test not executed" << std::endl;
242  BOOST_CHECK(1.0 < 2.0);
243  }
244  }
245 }
246 
247 // -----------------------------------------------------------------------------
248 
249 template <typename MODEL> class LinearVariableChange : public oops::Test {
250  public:
253  private:
254  std::string testid() const {return "test::LinearVariableChange<" + MODEL::name() + ">";}
255 
256  void register_tests() const {
257  boost::unit_test::test_suite * ts = BOOST_TEST_SUITE("interface/LinearVariableChange");
258 
259  ts->add(BOOST_TEST_CASE(&testLinearVariableChangeZero<MODEL>));
260  ts->add(BOOST_TEST_CASE(&testLinearVariableChangeAdjoint<MODEL>));
261  ts->add(BOOST_TEST_CASE(&testLinearVariableChangeInverse<MODEL>));
262 
263  boost::unit_test::framework::master_test_suite().add(ts);
264  }
265 };
266 
267 // -----------------------------------------------------------------------------
268 
269 } // namespace test
270 
271 #endif // TEST_INTERFACE_LINEARVARIABLECHANGE_H_
subroutine, public create(self, c_conf)
Encapsulates the model state.
static const eckit::Configuration & config()
character(len=32) name
static LinearVariableChangeFixture< MODEL > & getInstance()
real(fp), parameter, public e
subroutine, public info(self)
static std::vector< eckit::LocalConfiguration > & linvarchgconfs()
LinearVariableChangeFactory Factory.
Base class for generic variable transform.
boost::scoped_ptr< const Geometry_ > resol_
Increment Class: Difference between two states.
boost::scoped_ptr< const util::DateTime > time_
std::vector< eckit::LocalConfiguration > linvarchgconfs_