8 #ifndef TEST_IODA_EXTENDEDOBSSPACE_H_
9 #define TEST_IODA_EXTENDEDOBSSPACE_H_
16 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
18 #include "eckit/config/LocalConfiguration.h"
19 #include "eckit/testing/Test.h"
23 #include "oops/test/TestEnvironment.h"
24 #include "oops/util/Expect.h"
26 #include "ioda/IodaTrait.h"
35 util::DateTime bgn(conf.getString(
"window begin"));
36 util::DateTime end(conf.getString(
"window end"));
37 const eckit::LocalConfiguration obsSpaceConf(conf,
"obs space");
39 obsParams.validateAndDeserialize(obsSpaceConf);
42 const bool expectThrows = conf.getBool(
"expectThrows",
false);
52 if (obsdata.obs_group_vars().empty())
53 throw eckit::BadValue(
"Must set 'group variables' configuration option", Here());
55 if (!obsSpaceConf.has(
"extension"))
56 throw eckit::BadValue(
"Must set 'extension' configuration option", Here());
58 const int nlevs = obsSpaceConf.getInt(
"extension.average profiles onto model levels", 0);
60 if (nlevs <= 0)
return;
62 const int MPIsize = obsdata.comm().size();
63 const int MPIrank = obsdata.comm().rank();
66 const int nlocs =
static_cast<int>(obsdata.
nlocs());
67 std::stringstream expectednumber;
68 expectednumber <<
"expected nlocs (" << MPIsize <<
" PE, rank " << MPIrank <<
")";
69 const int nlocs_expected = conf.getInt(expectednumber.str());
70 EXPECT_EQUAL(
nlocs, nlocs_expected);
73 const int gnlocs =
static_cast<int>(obsdata.globalNumLocs());
74 expectednumber.str(
"");
75 expectednumber <<
"expected gnlocs (" << MPIsize <<
" PE, rank " << MPIrank <<
")";
76 const int gnlocs_expected = conf.getInt(expectednumber.str());
77 EXPECT_EQUAL(gnlocs, gnlocs_expected);
80 const int nrecs =
static_cast<int>(obsdata.nrecs());
81 expectednumber.str(
"");
82 expectednumber <<
"expected nrecs (" << MPIsize <<
" PE, rank " << MPIrank <<
")";
83 const int nrecs_expected = conf.getInt(expectednumber.str());
84 EXPECT_EQUAL(nrecs, nrecs_expected);
88 std::vector <int> extended_obs_space(
nlocs);
89 obsdata.get_db(
"MetaData",
"extended_obs_space", extended_obs_space);
90 const size_t extendedObsSpaceStart =
91 std::find(extended_obs_space.begin(),
92 extended_obs_space.end(), 1) - extended_obs_space.begin();
95 EXPECT_EQUAL((
nlocs - extendedObsSpaceStart) % nlevs, 0);
97 for (
int iloc = 0; iloc < extendedObsSpaceStart; ++iloc)
98 EXPECT_EQUAL(extended_obs_space[iloc], 0);
99 for (
int iloc = extendedObsSpaceStart; iloc <
nlocs; ++iloc)
100 EXPECT_EQUAL(extended_obs_space[iloc], 1);
104 const float missingValueFloat = util::missingValue(missingValueFloat);
108 for (
int ivar = 0; ivar <
obsvars.size(); ++ivar) {
109 const std::string varname =
obsvars[ivar];
110 obsdata.get_db(
"ObsValue", varname,
val);
111 obsdata.get_db(
"ObsError", varname,
err);
112 for (
int iloc = extendedObsSpaceStart; iloc <
nlocs; ++iloc) {
113 EXPECT_EQUAL(
val[iloc], missingValueFloat);
114 EXPECT_EQUAL(
err[iloc], missingValueFloat);
120 if (obsdata.has(
"MetaData",
"station_id")) {
121 const std::string missingValueString = util::missingValue(missingValueString);
122 std::vector <std::string> statid(
nlocs);
123 obsdata.get_db(
"MetaData",
"station_id", statid);
124 for (
int iloc = extendedObsSpaceStart; iloc <
nlocs; ++iloc)
125 EXPECT_EQUAL(statid[iloc], missingValueString);
131 const std::vector <std::string> extendedVarsToCheck =
132 {
"latitude",
"longitude",
"air_pressure"};
134 const std::vector <std::string> &nonMissingExtendedVars =
135 obsSpaceConf.getStringVector(
"extension.variables filled with non-missing values",
136 {
"latitude",
"longitude",
"datetime",
137 "air_pressure",
"air_pressure_levels"});
138 std::vector <float> val_extended(
nlocs);
139 for (
auto &varname : extendedVarsToCheck) {
141 if (obsdata.has(
"MetaData", varname)) {
142 const bool filledWithNonMissing =
143 std::find(nonMissingExtendedVars.begin(), nonMissingExtendedVars.end(), varname) !=
144 nonMissingExtendedVars.end();
145 obsdata.get_db(
"MetaData", varname, val_extended);
146 if (filledWithNonMissing) {
147 for (
int iloc = extendedObsSpaceStart; iloc <
nlocs; ++iloc)
148 EXPECT(val_extended[iloc] != missingValueFloat);
150 for (
int iloc = extendedObsSpaceStart; iloc <
nlocs; ++iloc)
151 EXPECT_EQUAL(val_extended[iloc], missingValueFloat);
160 const std::vector<std::size_t> recidx_all_recnums = obsdata.recidx_all_recnums();
162 EXPECT_EQUAL(nrecs % 2, 0);
163 std::size_t nrecs_original = nrecs / 2;
164 const std::vector<std::size_t> original_recnums(recidx_all_recnums.begin(),
165 recidx_all_recnums.begin() + nrecs / 2);
166 const std::vector<std::size_t> extended_recnums(recidx_all_recnums.begin() + nrecs / 2,
167 recidx_all_recnums.end());
168 std::size_t gnrecs_original = original_recnums.empty() ? 0 : (original_recnums.back() + 1);
169 obsdata.distribution()->max(gnrecs_original);
171 std::vector<std::size_t> extended_recnums_expected;
172 for (std::size_t
i : original_recnums)
173 extended_recnums_expected.push_back(
i + gnrecs_original);
174 EXPECT_EQUAL(extended_recnums, extended_recnums_expected);
178 std::vector <size_t> index_processors = obsdata.index();
179 obsdata.distribution()->allGatherv(index_processors);
180 std::sort(index_processors.begin(), index_processors.end());
181 auto it_unique = std::unique(index_processors.begin(), index_processors.end());
182 index_processors.erase(it_unique, index_processors.end());
184 std::vector <size_t> index_processors_expected(index_processors.size());
185 std::iota(index_processors_expected.begin(), index_processors_expected.end(), 0);
187 EXPECT_EQUAL(index_processors, index_processors_expected);
194 std::string
testid()
const override {
return "ioda::test::ExtendedObsSpace";}
197 std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
200 for (
const std::string & testCaseName : conf.keys())
203 ts.emplace_back(
CASE(
"ioda/ExtendedObsSpace/" + testCaseName, testCaseConf)
void clear() const override
std::string testid() const override
void register_tests() const override
static const eckit::Configuration & config()
void testExtendedObsSpace(const eckit::LocalConfiguration &conf)
CASE("Derived variable, unit conversion, and exception checking methods")
const eckit::mpi::Comm & myself()
Default communicator with each MPI task by itself.
const eckit::mpi::Comm & world()
Default communicator with all MPI tasks (ie MPI_COMM_WORLD)