IODA
ObsSpaceIndexRecnum.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_OBSSPACEINDEXRECNUM_H_
9 #define TEST_IODA_OBSSPACEINDEXRECNUM_H_
10 
11 #include <cmath>
12 #include <set>
13 #include <string>
14 #include <vector>
15 
16 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
17 
18 #include <boost/noncopyable.hpp>
19 #include <boost/shared_ptr.hpp>
20 
21 #include "eckit/config/LocalConfiguration.h"
22 #include "eckit/testing/Test.h"
23 
24 #include "oops/mpi/mpi.h"
25 #include "oops/runs/Test.h"
26 #include "oops/test/TestEnvironment.h"
27 
28 #include "ioda/distribution/Accumulator.h"
29 #include "ioda/IodaTrait.h"
30 #include "ioda/ObsSpace.h"
31 
32 namespace ioda {
33 namespace test {
34 
35 // -----------------------------------------------------------------------------
36 
37 class ObsSpaceTestFixture : private boost::noncopyable {
38  public:
39  static ioda::ObsSpace & obspace(const std::size_t ii) {
40  return *getInstance().ospaces_.at(ii);
41  }
42  static std::size_t size() {return getInstance().ospaces_.size();}
43  static void cleanup() {
44  auto &spaces = getInstance().ospaces_;
45  for (auto &space : spaces) {
46  space->save();
47  space.reset();
48  }
49  }
50 
51  private:
53  static ObsSpaceTestFixture theObsSpaceTestFixture;
54  return theObsSpaceTestFixture;
55  }
56 
58  util::DateTime bgn(::test::TestEnvironment::config().getString("window begin"));
59  util::DateTime end(::test::TestEnvironment::config().getString("window end"));
60 
61  std::vector<eckit::LocalConfiguration> conf;
62  ::test::TestEnvironment::config().get("observations", conf);
63 
64  for (std::size_t jj = 0; jj < conf.size(); ++jj) {
65  eckit::LocalConfiguration obsconf(conf[jj], "obs space");
66  std::string distname = obsconf.getString("distribution", "RoundRobin");
67  boost::shared_ptr<ioda::ObsSpace> tmp(new ioda::ObsSpace(obsconf, oops::mpi::world(),
68  bgn, end, oops::mpi::myself()));
69  ospaces_.push_back(tmp);
70  }
71  }
72 
74 
75  std::vector<boost::shared_ptr<ioda::ObsSpace> > ospaces_;
76 };
77 
78 // -----------------------------------------------------------------------------
79 
80 void testConstructor() {
81  typedef ObsSpaceTestFixture Test_;
82 
83  std::vector<eckit::LocalConfiguration> conf;
84  ::test::TestEnvironment::config().get("observations", conf);
85 
86  for (std::size_t jj = 0; jj < Test_::size(); ++jj) {
87  // Grab the test configuration which holds the expected data.
88  eckit::LocalConfiguration testConfig;
89  conf[jj].get("test data", testConfig);
90  oops::Log::debug() << "Test data configuration: " << testConfig << std::endl;
91 
92  const ObsSpace &odb = Test_::obspace(jj);
93 
94  // Get the number of locations (nlocs) from the ObsSpace object
95  std::size_t GlobalNlocs = odb.globalNumLocs();
96  std::size_t Nlocs = odb.nlocs();
97  std::size_t Nvars = odb.nvars();
98  bool ObsAreSorted = odb.obsAreSorted();
99 
100  // Get the expected nlocs from the obspace object's configuration
101  std::size_t ExpectedGlobalNlocs = testConfig.getUnsigned("nlocs");
102  std::size_t ExpectedNvars = testConfig.getUnsigned("nvars");
103  bool ExpectedObsAreSorted = testConfig.getBool("obs are sorted");
104 
105  oops::Log::debug() << "GlobalNlocs, ExpectedGlobalNlocs: " << GlobalNlocs << ", "
106  << ExpectedGlobalNlocs << std::endl;
107  oops::Log::debug() << "Nvars, ExpectedNvars: " << Nvars << ", "
108  << ExpectedNvars << std::endl;
109  oops::Log::debug() << "ObsAreSorted, ExpectedObsAreSorted: " << ObsAreSorted << ", "
110  << ExpectedObsAreSorted << std::endl;
111 
112  EXPECT(GlobalNlocs == ExpectedGlobalNlocs);
113  if (Nlocs > 0)
114  EXPECT(Nvars == ExpectedNvars);
115  EXPECT(ObsAreSorted == ExpectedObsAreSorted);
116 
117  // records are ambigious and not implemented for halo distribution
118  if (odb.distribution()->name() != "Halo") {
119  std::size_t Nrecs = 0;
120  std::set<std::size_t> recIndices;
121  auto accumulator = odb.distribution()->createAccumulator<std::size_t>();
122  for (std::size_t loc = 0; loc < Nlocs; ++loc) {
123  if (bool isNewRecord = recIndices.insert(odb.recnum()[loc]).second) {
124  accumulator->addTerm(loc, 1);
125  ++Nrecs;
126  }
127  }
128  const size_t ExpectedNrecs = odb.nrecs();
129  EXPECT_EQUAL(Nrecs, ExpectedNrecs);
130 
131  // Calculate the global number of unique records
132  std::size_t GlobalNrecs = accumulator->computeResult();
133  std::size_t ExpectedGlobalNrecs = testConfig.getUnsigned("nrecs");
134  EXPECT_EQUAL(GlobalNrecs, ExpectedGlobalNrecs);
135  }
136  }
137 }
138 
139 // -----------------------------------------------------------------------------
140 
142  typedef ObsSpaceTestFixture Test_;
143 
144  std::vector<eckit::LocalConfiguration> conf;
145  ::test::TestEnvironment::config().get("observations", conf);
146 
147  for (std::size_t jj = 0; jj < Test_::size(); ++jj) {
148  // Grab the test configuration which holds the expected data.
149  eckit::LocalConfiguration testConfig;
150  conf[jj].get("test data", testConfig);
151  oops::Log::debug() << "Test data configuration: " << testConfig << std::endl;
152 
153  // Get the index and recnum vectors from the obs space
154  std::vector<std::size_t> Index = Test_::obspace(jj).index();
155  std::vector<std::size_t> Recnum = Test_::obspace(jj).recnum();
156 
157  // Get the expected index and recnum vectors from the obspace object's configuration
158 
159  int MyMpiSize = Test_::obspace(jj).comm().size();
160  int MyMpiRank = Test_::obspace(jj).comm().rank();
161 
162  std::string MyPath = "mpi size" + std::to_string(MyMpiSize) +
163  ".rank" + std::to_string(MyMpiRank);
164  std::vector<std::size_t> ExpectedIndex = testConfig.getUnsignedVector(MyPath + ".index");
165  std::vector<std::size_t> ExpectedRecnum = testConfig.getUnsignedVector(MyPath + ".recnum");
166  eckit::LocalConfiguration recidxTestConfig;
167  testConfig.get(MyPath + ".recidx", recidxTestConfig);
168 
169  oops::Log::debug() << "Index, ExpectedIndex: " << Index << ", "
170  << ExpectedIndex << std::endl;
171  oops::Log::debug() << "Recnum, ExpectedRecnum: " << Recnum << ", "
172  << ExpectedRecnum << std::endl;
173 
174  EXPECT(Index == ExpectedIndex);
175  EXPECT(Recnum == ExpectedRecnum);
176 
177  // check that the recidx data structure got initialized properly
178  oops::Log::debug() << "recidxTestConfig: " << recidxTestConfig << std::endl;
179  std::vector<std::size_t> RecIdxRecNums = Test_::obspace(jj).recidx_all_recnums();
180  for (std::size_t i = 0; i < RecIdxRecNums.size(); ++i) {
181  std::size_t RecNum = RecIdxRecNums[i];
182  std::string TestConfigKey = "rec" + std::to_string(RecNum);
183  std::vector<std::size_t> ExpectedRecIdxVector =
184  recidxTestConfig.getUnsignedVector(TestConfigKey);
185  std::vector<std::size_t> RecIdxVector = Test_::obspace(jj).recidx_vector(RecNum);
186 
187  oops::Log::debug() << "RecIdxVector, ExpectedRecIdxVector: "
188  << RecIdxVector << ", " << ExpectedRecIdxVector << std::endl;
189  EXPECT(RecIdxVector == ExpectedRecIdxVector);
190  }
191  }
192 }
193 
194 // -----------------------------------------------------------------------------
195 
196 void testCleanup() {
197  // This test removes the obsspaces and ensures that they evict their contents
198  // to disk successfully.
199  typedef ObsSpaceTestFixture Test_;
200 
201  Test_::cleanup();
202 }
203 
204 // -----------------------------------------------------------------------------
205 
206 class ObsSpaceIndexRecnum : public oops::Test {
207  public:
209  virtual ~ObsSpaceIndexRecnum() {}
210  private:
211  std::string testid() const override {return "test::ObsSpaceIndexRecnum<ioda::IodaTrait>";}
212 
213  void register_tests() const override {
214  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
215 
216  ts.emplace_back(CASE("ioda/ObsSpaceIndexRecnum/testConstructor")
217  { testConstructor(); });
218  ts.emplace_back(CASE("ioda/ObsSpaceIndexRecnum/testIndexRecnum")
219  { testIndexRecnum(); });
220  ts.emplace_back(CASE("ioda/ObsSpaceIndexRecnum/testCleanup")
221  { testCleanup(); });
222  }
223 
224  void clear() const override {}
225 };
226 
227 // -----------------------------------------------------------------------------
228 
229 } // namespace test
230 } // namespace ioda
231 
232 #endif // TEST_IODA_OBSSPACEINDEXRECNUM_H_
Observation data class for IODA.
Definition: src/ObsSpace.h:116
const std::vector< std::size_t > & recnum() const
return reference to the record number vector
Definition: src/ObsSpace.h:222
std::size_t nrecs() const
return the number of records in the obs space container
Definition: src/ObsSpace.h:185
std::shared_ptr< const Distribution > distribution() const
return MPI distribution object
Definition: src/ObsSpace.h:335
size_t nlocs() const
return the number of locations in the obs space. Note that nlocs may be smaller than global unique nl...
Definition: src/ObsSpace.h:176
std::size_t nvars() const
return the number of variables in the obs space container. "Variables" refers to the quantities that ...
Definition: ObsSpace.cc:189
bool obsAreSorted() const
true if the groups in the recidx data member are sorted
Definition: src/ObsSpace.h:314
std::size_t globalNumLocs() const
return the total number of locations in the corresponding obs spaces across all MPI tasks
Definition: src/ObsSpace.h:168
std::string testid() const override
void register_tests() const override
std::vector< boost::shared_ptr< ioda::ObsSpace > > ospaces_
static ioda::ObsSpace & obspace(const std::size_t ii)
static ObsSpaceTestFixture & getInstance()
CASE("Derived variable and unit conversion methods")