IODA
test/ioda/ObsSpace.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_IODA_OBSSPACE_H_
9 #define TEST_IODA_OBSSPACE_H_
10 
11 #include <cmath>
12 #include <string>
13 #include <vector>
14 
15 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
16 
17 #include <boost/noncopyable.hpp>
18 #include <boost/shared_ptr.hpp>
19 
20 #include "eckit/config/LocalConfiguration.h"
21 #include "eckit/testing/Test.h"
22 
23 #include "oops/mpi/mpi.h"
24 #include "oops/runs/Test.h"
25 #include "oops/test/TestEnvironment.h"
26 
27 #include "ioda/IodaTrait.h"
28 #include "ioda/ObsSpace.h"
29 
30 namespace ioda {
31 namespace test {
32 
33 // -----------------------------------------------------------------------------
34 
35 class ObsSpaceTestFixture : private boost::noncopyable {
36  public:
37  static ioda::ObsSpace & obspace(const std::size_t ii) {
38  return *getInstance().ospaces_.at(ii);
39  }
40  static std::size_t size() {return getInstance().ospaces_.size();}
41 
42  private:
44  static ObsSpaceTestFixture theObsSpaceTestFixture;
45  return theObsSpaceTestFixture;
46  }
47 
49  util::DateTime bgn(::test::TestEnvironment::config().getString("window begin"));
50  util::DateTime end(::test::TestEnvironment::config().getString("window end"));
51 
52  std::vector<eckit::LocalConfiguration> conf;
53  ::test::TestEnvironment::config().get("observations", conf);
54 
55  for (std::size_t jj = 0; jj < conf.size(); ++jj) {
56  eckit::LocalConfiguration obsconf(conf[jj], "obs space");
57  boost::shared_ptr<ioda::ObsSpace> tmp(new ioda::ObsSpace(obsconf, oops::mpi::world(),
58  bgn, end, oops::mpi::myself()));
59  ospaces_.push_back(tmp);
60  }
61  }
62 
64 
65  std::vector<boost::shared_ptr<ioda::ObsSpace> > ospaces_;
66 };
67 
68 // -----------------------------------------------------------------------------
69 
70 void testConstructor() {
71  typedef ObsSpaceTestFixture Test_;
72 
73  std::vector<eckit::LocalConfiguration> conf;
74  ::test::TestEnvironment::config().get("observations", conf);
75 
76  for (std::size_t jj = 0; jj < Test_::size(); ++jj) {
77  // Get the distribution method. If the method is "InefficientDistribution", then
78  // don't do the mpi allreduce calls. What is going on is that InefficientDistribution
79  // is distributing all observations to all mpi tasks, so if you do the allreduce
80  // calls you will overcount the sums (double count when 2 mpi tasks, triple count
81  // with 3 mpi tasks, etc.)
82  std::string DistMethod = conf[jj].getString("obs space.distribution", "RoundRobin");
83 
84  // Get the numbers of locations (nlocs) from the ObsSpace object
85  std::size_t Nlocs = Test_::obspace(jj).nlocs();
86  std::size_t Nrecs = Test_::obspace(jj).nrecs();
87  std::size_t Nvars = Test_::obspace(jj).nvars();
88  if (DistMethod != "InefficientDistribution") {
89  Test_::obspace(jj).comm().allReduceInPlace(Nlocs, eckit::mpi::sum());
90  Test_::obspace(jj).comm().allReduceInPlace(Nrecs, eckit::mpi::sum());
91  }
92 
93  // Get the expected nlocs from the obspace object's configuration
94  std::size_t ExpectedNlocs = conf[jj].getUnsigned("obs space.test data.nlocs");
95  std::size_t ExpectedNrecs = conf[jj].getUnsigned("obs space.test data.nrecs");
96  std::size_t ExpectedNvars = conf[jj].getUnsigned("obs space.test data.nvars");
97 
98  // Get the obs grouping/sorting parameters from the ObsSpace object
99  std::string ObsGroupVar = Test_::obspace(jj).obs_group_var();
100  std::string ObsSortVar = Test_::obspace(jj).obs_sort_var();
101  std::string ObsSortOrder = Test_::obspace(jj).obs_sort_order();
102 
103  // Get the expected obs grouping/sorting parameters from the configuration
104  std::string ExpectedObsGroupVar =
105  conf[jj].getString("obs space.test data.expected group variable");
106  std::string ExpectedObsSortVar =
107  conf[jj].getString("obs space.test data.expected sort variable");
108  std::string ExpectedObsSortOrder =
109  conf[jj].getString("obs space.test data.expected sort order");
110 
111  oops::Log::debug() << "Nlocs, ExpectedNlocs: " << Nlocs << ", "
112  << ExpectedNlocs << std::endl;
113  oops::Log::debug() << "Nrecs, ExpectedNrecs: " << Nrecs << ", "
114  << ExpectedNrecs << std::endl;
115  oops::Log::debug() << "Nvars, ExpectedNvars: " << Nvars << ", "
116  << ExpectedNvars << std::endl;
117 
118  oops::Log::debug() << "ObsGroupVar, ExpectedObsGroupVar: " << ObsGroupVar << ", "
119  << ExpectedObsGroupVar << std::endl;
120  oops::Log::debug() << "ObsSortVar, ExpectedObsSortVar: " << ObsSortVar << ", "
121  << ExpectedObsSortVar << std::endl;
122  oops::Log::debug() << "ObsSortOrder, ExpectedObsSortOrder: " << ObsSortOrder << ", "
123  << ExpectedObsSortOrder << std::endl;
124 
125  EXPECT(Nlocs == ExpectedNlocs);
126  EXPECT(Nrecs == ExpectedNrecs);
127  EXPECT(Nvars == ExpectedNvars);
128 
129  EXPECT(ObsGroupVar == ExpectedObsGroupVar);
130  EXPECT(ObsSortVar == ExpectedObsSortVar);
131  EXPECT(ObsSortOrder == ExpectedObsSortOrder);
132  }
133 }
134 
135 // -----------------------------------------------------------------------------
136 
137 void testGetDb() {
138  typedef ObsSpaceTestFixture Test_;
139 
140  std::vector<eckit::LocalConfiguration> conf;
141  ::test::TestEnvironment::config().get("observations", conf);
142 
143  for (std::size_t jj = 0; jj < Test_::size(); ++jj) {
144  std::string DistMethod = conf[jj].getString("obs space.distribution", "RoundRobin");
145 
146  // Set up a pointer to the ObsSpace object for convenience
147  ioda::ObsSpace * Odb = &(Test_::obspace(jj));
148  std::size_t Nlocs = Odb->nlocs();
149 
150  // Get the variables section from the test data and perform checks accordingly
151  std::vector<eckit::LocalConfiguration> varconf =
152  conf[jj].getSubConfigurations("obs space.test data.variables");
153  double Tol = conf[jj].getDouble("obs space.test data.tolerance");
154  for (std::size_t i = 0; i < varconf.size(); ++i) {
155  // Read in the variable group, name and expected norm values from the configuration
156  std::string VarName = varconf[i].getString("name");
157  std::string GroupName = varconf[i].getString("group");
158  std::string VarType = varconf[i].getString("type");
159 
160  // Do different checks according to type
161  if (VarType == "float") {
162  // Check the type from ObsSpace
163  ObsDtype VarDataType = Odb->dtype(GroupName, VarName);
164  EXPECT(VarDataType == ObsDtype::Float);
165 
166  // Check auto-conversion to double from ObsSpace float
167  // Check the norm
168  std::vector<double> TestVec(Nlocs);
169  Odb->get_db(GroupName, VarName, TestVec);
170 
171  // Calculate the norm of the vector
172  double ExpectedVnorm = varconf[i].getDouble("norm");
173  double Vnorm = 0.0;
174  for (std::size_t j = 0; j < Nlocs; ++j) {
175  Vnorm += pow(TestVec[j], 2.0);
176  }
177  if (DistMethod != "InefficientDistribution") {
178  Test_::obspace(jj).comm().allReduceInPlace(Vnorm, eckit::mpi::sum());
179  }
180  Vnorm = sqrt(Vnorm);
181 
182  EXPECT(oops::is_close(Vnorm, ExpectedVnorm, Tol));
183  } else if (VarType == "integer") {
184  // Check the type from ObsSpace
185  ObsDtype VarDataType = Odb->dtype(GroupName, VarName);
186  EXPECT(VarDataType == ObsDtype::Integer);
187 
188  // Check the norm
189  std::vector<int> TestVec(Nlocs);
190  Odb->get_db(GroupName, VarName, TestVec);
191 
192  // Calculate the norm of the vector
193  double ExpectedVnorm = varconf[i].getDouble("norm");
194  double Vnorm = 0.0;
195  for (std::size_t j = 0; j < Nlocs; ++j) {
196  Vnorm += pow(static_cast<double>(TestVec[j]), 2.0);
197  }
198  if (DistMethod != "InefficientDistribution") {
199  Test_::obspace(jj).comm().allReduceInPlace(Vnorm, eckit::mpi::sum());
200  }
201  Vnorm = sqrt(Vnorm);
202 
203  EXPECT(oops::is_close(Vnorm, ExpectedVnorm, Tol));
204  } else if (VarType == "string") {
205  // Check the type from ObsSpace
206  ObsDtype VarDataType = Odb->dtype(GroupName, VarName);
207  EXPECT(VarDataType == ObsDtype::String);
208 
209  // Check the first and last values of the vector
210  std::string ExpectedFirstValue = varconf[i].getString("first value");
211  std::string ExpectedLastValue = varconf[i].getString("last value");
212  std::vector<std::string> TestVec(Nlocs);
213  Odb->get_db(GroupName, VarName, TestVec);
214 
215  EXPECT(TestVec[0] == ExpectedFirstValue);
216  EXPECT(TestVec[Nlocs-1] == ExpectedLastValue);
217  }
218  }
219  }
220 }
221 
222 // -----------------------------------------------------------------------------
223 
224 void testPutDb() {
225  typedef ObsSpaceTestFixture Test_;
226 
227  std::string VarName("DummyVar");
228 
229  for (std::size_t jj = 0; jj < Test_::size(); ++jj) {
230  // Set up a pointer to the ObsSpace object for convenience
231  ioda::ObsSpace * Odb = &(Test_::obspace(jj));
232 
233  // Create a dummy vector to put into the database
234  // Load up the vector with contrived data, put the vector then
235  // get the vector and see if the contrived data made it through.
236  std::size_t Nlocs = Odb->nlocs();
237  std::vector<double> TestVec(Nlocs);
238  std::vector<double> ExpectedVec(Nlocs);
239 
240  for (std::size_t i = 0; i < Nlocs; ++i) {
241  ExpectedVec[i] = static_cast<double>(i);
242  }
243 
244  // Put the vector into the database. Then read the vector back from the database
245  // and compare to the original
246  Odb->put_db("MetaData", VarName, ExpectedVec);
247  Odb->get_db("MetaData", VarName, TestVec);
248 
249  bool VecMatch = true;
250  for (std::size_t i = 0; i < Nlocs; ++i) {
251  VecMatch = VecMatch && (static_cast<int>(ExpectedVec[i]) == static_cast<int>(TestVec[i]));
252  }
253 
254  EXPECT(VecMatch);
255  }
256 }
257 
258 // -----------------------------------------------------------------------------
259 
261  typedef ObsSpaceTestFixture Test_;
262 
263  std::string VarName("DummyVar");
264 
265  for (std::size_t jj = 0; jj < Test_::size(); ++jj) {
266  // Set up a pointer to the ObsSpace object for convenience
267  ioda::ObsSpace * Odb = &(Test_::obspace(jj));
268 
269  // Create a dummy vector to put into the database
270  // All rows read from the input file should be read only.
271  // All rows added since the read of the input file should be writeable.
272  std::size_t Nlocs = Odb->nlocs();
273  std::vector<double> TestVec(Nlocs);
274  std::vector<double> ExpectedVec(Nlocs);
275 
276  for (std::size_t i = 0; i < Nlocs; ++i) {
277  ExpectedVec[i] = static_cast<double>(i);
278  }
279 
280  // Put the vector into the database. Then read the vector back from the database
281  // and compare to the original
282  Odb->put_db("TestGroup", VarName, ExpectedVec);
283  Odb->get_db("TestGroup", VarName, TestVec);
284 
285  bool VecMatch = true;
286  for (std::size_t i = 0; i < Nlocs; ++i) {
287  VecMatch = VecMatch && (static_cast<int>(ExpectedVec[i]) == static_cast<int>(TestVec[i]));
288  }
289  EXPECT(VecMatch);
290 
291  // Now update the vector with the original multiplied by 2.
292  for (std::size_t i = 0; i < Nlocs; ++i) {
293  ExpectedVec[i] = ExpectedVec[i] * 2;
294  }
295 
296  Odb->put_db("TestGroup", VarName, ExpectedVec);
297  Odb->get_db("TestGroup", VarName, TestVec);
298 
299  VecMatch = true;
300  for (std::size_t i = 0; i < Nlocs; ++i) {
301  VecMatch = VecMatch && (static_cast<int>(ExpectedVec[i]) == static_cast<int>(TestVec[i]));
302  }
303  EXPECT(VecMatch);
304  }
305 }
306 
307 // -----------------------------------------------------------------------------
308 
309 class ObsSpace : public oops::Test {
310  public:
311  ObsSpace() {}
312  virtual ~ObsSpace() {}
313  private:
314  std::string testid() const override {return "test::ObsSpace<ioda::IodaTrait>";}
315 
316  void register_tests() const override {
317  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
318 
319  ts.emplace_back(CASE("ioda/ObsSpace/testConstructor")
320  { testConstructor(); });
321  ts.emplace_back(CASE("ioda/ObsSpace/testGetDb")
322  { testGetDb(); });
323  ts.emplace_back(CASE("ioda/ObsSpace/testPutDb")
324  { testPutDb(); });
325  ts.emplace_back(CASE("ioda/ObsSpace/testWriteableGroup")
326  { testWriteableGroup(); });
327  }
328 
329  void clear() const override {}
330 };
331 
332 // -----------------------------------------------------------------------------
333 
334 } // namespace test
335 } // namespace ioda
336 
337 #endif // TEST_IODA_OBSSPACE_H_
ioda::test::testPutDb
void testPutDb()
Definition: test/ioda/ObsSpace.h:224
ioda::ObsSpace::get_db
void get_db(const std::string &group, const std::string &name, std::vector< int > &vdata) const
Definition: ObsSpace.cc:167
ioda::test::ObsSpaceTestFixture::getInstance
static ObsSpaceTestFixture & getInstance()
Definition: test/ioda/ObsSpace.h:43
ioda::test::ObsSpace::ObsSpace
ObsSpace()
Definition: test/ioda/ObsSpace.h:311
ioda::test::ObsSpaceTestFixture::obspace
static ioda::ObsSpace & obspace(const std::size_t ii)
Definition: test/ioda/ObsSpace.h:37
ioda::test::ObsSpaceTestFixture::ObsSpaceTestFixture
ObsSpaceTestFixture()
Definition: test/ioda/ObsSpace.h:48
ObsSpace.h
ioda::test::ObsSpaceTestFixture::~ObsSpaceTestFixture
~ObsSpaceTestFixture()
Definition: test/ioda/ObsSpace.h:63
ioda::test::ObsSpace::~ObsSpace
virtual ~ObsSpace()
Definition: test/ioda/ObsSpace.h:312
ioda::ObsDtype::Integer
@ Integer
ioda::test::ObsSpace::testid
std::string testid() const override
Definition: test/ioda/ObsSpace.h:314
ioda::test::testWriteableGroup
void testWriteableGroup()
Definition: test/ioda/ObsSpace.h:260
ioda::test::testGetDb
void testGetDb()
Definition: test/ioda/ObsSpace.h:137
ioda::test::ObsSpaceTestFixture
Definition: test/ioda/ObsSpace.h:35
ioda
Definition: IodaUtils.cc:13
ioda::ObsDtype::String
@ String
ioda::test::ObsSpaceTestFixture::ospaces_
std::vector< boost::shared_ptr< ioda::ObsSpace > > ospaces_
Definition: test/ioda/ObsSpace.h:65
ioda::test::testConstructor
void testConstructor()
Definition: test/core/ObsSpaceContainer.h:76
ioda::test::ObsSpace
Definition: test/ioda/ObsSpace.h:309
ioda::ObsSpace::nlocs
std::size_t nlocs() const
Definition: ObsSpace.cc:344
ioda::ObsSpace::dtype
ObsDtype dtype(const std::string &, const std::string &) const
Definition: ObsSpace.cc:292
ioda::test::ObsSpace::clear
void clear() const override
Definition: test/ioda/ObsSpace.h:329
ioda::ObsSpace::put_db
void put_db(const std::string &group, const std::string &name, const std::vector< int > &vdata)
Definition: ObsSpace.cc:242
ioda::test::ObsSpaceTestFixture::size
static std::size_t size()
Definition: test/ioda/ObsSpace.h:40
ioda::ObsDtype
ObsDtype
Definition: ObsData.h:63
ioda::ObsSpace
Observation Space View.
Definition: src/ObsSpace.h:35
ioda::test::ObsSpace::register_tests
void register_tests() const override
Definition: test/ioda/ObsSpace.h:316
ioda::ObsDtype::Float
@ Float