OOPS
test/interface/VariableChange.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2018 UCAR
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  */
7 
8 #ifndef TEST_INTERFACE_VARIABLECHANGE_H_
9 #define TEST_INTERFACE_VARIABLECHANGE_H_
10 
11 #include <cmath>
12 #include <iostream>
13 #include <memory>
14 #include <string>
15 #include <vector>
16 
17 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
18 
19 #include <boost/noncopyable.hpp>
20 
21 #include "eckit/config/Configuration.h"
22 #include "eckit/testing/Test.h"
26 #include "oops/interface/State.h"
27 #include "oops/mpi/mpi.h"
28 #include "oops/runs/Test.h"
29 #include "oops/util/Expect.h"
30 #include "oops/util/Logger.h"
31 #include "test/TestEnvironment.h"
32 
33 namespace test {
34 
35 // -------------------------------------------------------------------------------------------------
36 
37 template <typename MODEL> class VariableChangeFixture : private boost::noncopyable {
40 
41  public:
42  static std::vector<eckit::LocalConfiguration> & confs() {return getInstance().confs_;}
43  static const State_ & xx() {return *getInstance().xx_;}
44  static const Geometry_ & resol() {return *getInstance().resol_;}
45 
46  private:
48  static VariableChangeFixture<MODEL> theVariableChangeFixture;
49  return theVariableChangeFixture;
50  }
51 
53  oops::instantiateVariableChangeFactory<MODEL>();
54 
55  // Geometry for the test
56  const eckit::LocalConfiguration resolConfig(TestEnvironment::config(), "geometry");
57  resol_.reset(new Geometry_(resolConfig, oops::mpi::world()));
58 
59  // Configuration (list of all variable changes)
60  TestEnvironment::config().get("variable change tests", confs_);
61  }
62 
63  ~VariableChangeFixture<MODEL>() {}
64 
65  std::vector<eckit::LocalConfiguration> confs_;
66  std::unique_ptr<const Geometry_> resol_;
67 };
68 
69 // -------------------------------------------------------------------------------------------------
70 
71 template <typename MODEL> void testVariableChangeInverse() {
72  typedef VariableChangeFixture<MODEL> Test_;
73  typedef oops::State<MODEL> State_;
74  typedef oops::VariableChangeBase<MODEL> VariableChange_;
75  typedef oops::VariableChangeFactory<MODEL> VariableChangeFactory_;
76 
77  // Loop over all variable changes
78  for (std::size_t jj = 0; jj < Test_::confs().size(); ++jj) {
79  // Construct variable change
80  std::unique_ptr<VariableChange_> \
81  changevar(VariableChangeFactory_::create(Test_::confs()[jj], Test_::resol()));
82 
83  // User specified tolerance for pass/fail
84  const double tol = Test_::confs()[jj].getDouble("tolerance inverse");
85 
86  // Create states with input and output variables
87  const eckit::LocalConfiguration initialConfig(Test_::confs()[jj], "state");
88  State_ xx(Test_::resol(), initialConfig);
89 
90  // Save copy of the initial state
91  State_ xref(xx);
92 
93  // Order, inverse first or not (default)
94  // Note: switch input and output variables in configuration if true
95  const bool inverseFirst = Test_::confs()[jj].getBool("inverse first", false);
96 
97  // Convert from input to output variables and back (or vice versa)
98  if (inverseFirst) {
99  oops::Variables varin(Test_::confs()[jj], "input variables");
100  State_ xin(Test_::resol(), varin, xx.validTime());
101  changevar->changeVarInverse(xx, xin);
102  changevar->changeVar(xin, xx);
103  } else {
104  oops::Variables varout(Test_::confs()[jj], "output variables");
105  State_ xout(Test_::resol(), varout, xx.validTime());
106  changevar->changeVar(xx, xout);
107  changevar->changeVarInverse(xout, xx);
108  }
109 
110  // Compute norms of the result and reference
111  const double xxnorm_ref = xref.norm();
112  const double xxnorm_tst = xx.norm();
113 
114  // Print the input and final state
115  oops::Log::info() << "<xin>, <K^{-1}[K(xin)]>, (<xin>-<K^{-1}[K(xin)]<xin>)/>=" << xxnorm_ref <<
116  " " << xxnorm_tst << " " << (xxnorm_ref - xxnorm_tst)/xxnorm_ref <<std::endl;
117 
118  // Is result similar to the reference
119  EXPECT(oops::is_close(xxnorm_tst, xxnorm_ref, tol));
120  }
121 }
122 
123 // -------------------------------------------------------------------------------------------------
124 
125 template <typename MODEL> void testVariableChangeParametersWrapperValidName() {
126  typedef VariableChangeFixture<MODEL> Test_;
127  for (const eckit::Configuration &config : Test_::confs()) {
129  EXPECT_NO_THROW(parameters.validateAndDeserialize(config));
130  }
131 }
132 
133 // -------------------------------------------------------------------------------------------------
134 
135 template <typename MODEL> void testVariableChangeParametersWrapperInvalidName() {
136  eckit::LocalConfiguration config;
137  config.set("variable change", "###INVALID###");
139  if (oops::Parameters::isValidationSupported())
140  EXPECT_THROWS_MSG(parameters.validate(config), "unrecognized enum value");
141  EXPECT_THROWS_MSG(parameters.deserialize(config),
142  "does not exist in VariableChangeFactory");
143 }
144 
145 // -------------------------------------------------------------------------------------------------
146 
147 template <typename MODEL> void testVariableChangeFactoryGetMakerNames() {
148  typedef VariableChangeFixture<MODEL> Test_;
149  const std::vector<std::string> registeredNames =
151  for (const eckit::Configuration &config : Test_::confs()) {
152  const std::string validName = config.getString("variable change");
153  const bool found = std::find(registeredNames.begin(), registeredNames.end(), validName) !=
154  registeredNames.end();
155  EXPECT(found);
156  }
157 }
158 
159 // -------------------------------------------------------------------------------------------------
160 
161 template <typename MODEL> class VariableChange : public oops::Test {
162  public:
164  virtual ~VariableChange() {}
165  private:
166  std::string testid() const override {return "test::VariableChange<" + MODEL::name() + ">";}
167 
168  void register_tests() const override {
169  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
170 
171  ts.emplace_back(CASE("interface/VariableChange/testVariableChangeInverse")
172  { testVariableChangeInverse<MODEL>(); });
173  ts.emplace_back(CASE("interface/VariableChange/"
174  "testVariableChangeParametersWrapperValidName")
175  { testVariableChangeParametersWrapperValidName<MODEL>(); });
176  ts.emplace_back(CASE("interface/VariableChange/"
177  "testVariableChangeParametersWrapperInvalidName")
178  { testVariableChangeParametersWrapperInvalidName<MODEL>(); });
179  ts.emplace_back(CASE("interface/VariableChange/"
180  "testVariableChangeFactoryGetMakerNames")
181  { testVariableChangeFactoryGetMakerNames<MODEL>(); });
182  }
183 
184  void clear() const override {}
185 };
186 
187 // -------------------------------------------------------------------------------------------------
188 
189 } // namespace test
190 
191 #endif // TEST_INTERFACE_VARIABLECHANGE_H_
test::testVariableChangeParametersWrapperValidName
void testVariableChangeParametersWrapperValidName()
Definition: test/interface/VariableChange.h:125
oops::VariableChangeBase
Definition: VariableChangeBase.h:49
mpi.h
test::VariableChange::VariableChange
VariableChange()
Definition: test/interface/VariableChange.h:163
test::VariableChangeFixture::State_
oops::State< MODEL > State_
Definition: test/interface/VariableChange.h:39
test::VariableChange
Definition: test/interface/VariableChange.h:161
test::CASE
CASE("test_linearmodelparameterswrapper_valid_name")
Definition: LinearModelFactory.cc:22
oops::VariableChangeParametersWrapper
Contains a polymorphic parameter holding an instance of a subclass of VariableChangeParametersBase.
Definition: VariableChangeBase.h:100
test
Definition: LinearModelFactory.cc:20
test::VariableChangeFixture::confs
static std::vector< eckit::LocalConfiguration > & confs()
Definition: test/interface/VariableChange.h:42
test::testVariableChangeFactoryGetMakerNames
void testVariableChangeFactoryGetMakerNames()
Definition: test/interface/VariableChange.h:147
test::VariableChangeFixture::Geometry_
oops::Geometry< MODEL > Geometry_
Definition: test/interface/VariableChange.h:38
oops::VariableChangeFactory
VariableChange factory.
Definition: VariableChangeBase.h:75
test::VariableChange::register_tests
void register_tests() const override
Definition: test/interface/VariableChange.h:168
test::VariableChangeFixture
Definition: test/interface/VariableChange.h:37
test::VariableChange::~VariableChange
virtual ~VariableChange()
Definition: test/interface/VariableChange.h:164
Test.h
test::testVariableChangeParametersWrapperInvalidName
void testVariableChangeParametersWrapperInvalidName()
Definition: test/interface/VariableChange.h:135
test::TestEnvironment::config
static const eckit::Configuration & config()
Definition: TestEnvironment.h:40
test::VariableChangeFixture::getInstance
static VariableChangeFixture< MODEL > & getInstance()
Definition: test/interface/VariableChange.h:47
instantiateVariableChangeFactory.h
test::VariableChangeFixture::confs_
std::vector< eckit::LocalConfiguration > confs_
Definition: test/interface/VariableChange.h:65
oops::Geometry
Geometry class used in oops; subclass of interface class above.
Definition: oops/interface/Geometry.h:189
test::testVariableChangeInverse
void testVariableChangeInverse()
Definition: test/interface/VariableChange.h:71
TestEnvironment.h
test::VariableChangeFixture::resol_
std::unique_ptr< const Geometry_ > resol_
Definition: test/interface/VariableChange.h:66
oops::State
Encapsulates the model state.
Definition: CostJbState.h:28
test::VariableChange::clear
void clear() const override
Definition: test/interface/VariableChange.h:184
test::VariableChange::testid
std::string testid() const override
Definition: test/interface/VariableChange.h:166
oops::Test
Definition: Test.h:39
oops::VariableChangeFactory::getMakerNames
static std::vector< std::string > getMakerNames()
Return the names of all variable changes that can be created by one of the registered makers.
Definition: VariableChangeBase.h:139
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
test::VariableChangeFixture::resol
static const Geometry_ & resol()
Definition: test/interface/VariableChange.h:44
test::VariableChangeFixture::xx
static const State_ & xx()
Definition: test/interface/VariableChange.h:43
VariableChangeBase.h
Geometry.h