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"
21 #include "oops/mpi/mpi.h"
22 #include "oops/runs/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");
40 const bool expectThrows = conf.getBool(
"expectThrows",
false);
44 bgn, end, oops::mpi::myself()));
47 ioda::ObsSpace obsdata(obsSpaceConf, oops::mpi::world(), bgn, end, oops::mpi::myself());
51 throw eckit::BadValue(
"Must set 'group variables' configuration option", Here());
53 if (!obsSpaceConf.has(
"extension"))
54 throw eckit::BadValue(
"Must set 'extension' configuration option", Here());
56 const int nlevs = obsSpaceConf.getInt(
"extension.average profiles onto model levels", 0);
58 if (nlevs <= 0)
return;
60 const int MPIsize = obsdata.
comm().size();
61 const int MPIrank = obsdata.
comm().rank();
64 const int nlocs =
static_cast<int>(obsdata.
nlocs());
65 std::stringstream expectednumber;
66 expectednumber <<
"expected nlocs (" << MPIsize <<
" PE, rank " << MPIrank <<
")";
67 const int nlocs_expected = conf.getInt(expectednumber.str());
68 EXPECT_EQUAL(nlocs, nlocs_expected);
72 expectednumber.str(
"");
73 expectednumber <<
"expected gnlocs (" << MPIsize <<
" PE, rank " << MPIrank <<
")";
74 const int gnlocs_expected = conf.getInt(expectednumber.str());
75 EXPECT_EQUAL(gnlocs, gnlocs_expected);
78 const int nrecs =
static_cast<int>(obsdata.
nrecs());
79 expectednumber.str(
"");
80 expectednumber <<
"expected nrecs (" << MPIsize <<
" PE, rank " << MPIrank <<
")";
81 const int nrecs_expected = conf.getInt(expectednumber.str());
82 EXPECT_EQUAL(nrecs, nrecs_expected);
86 std::vector <int> extended_obs_space(nlocs);
87 obsdata.
get_db(
"MetaData",
"extended_obs_space", extended_obs_space);
88 const size_t extendedObsSpaceStart =
89 std::find(extended_obs_space.begin(),
90 extended_obs_space.end(), 1) - extended_obs_space.begin();
93 EXPECT_EQUAL((nlocs - extendedObsSpaceStart) % nlevs, 0);
95 for (
int iloc = 0; iloc < extendedObsSpaceStart; ++iloc)
96 EXPECT_EQUAL(extended_obs_space[iloc], 0);
97 for (
int iloc = extendedObsSpaceStart; iloc < nlocs; ++iloc)
98 EXPECT_EQUAL(extended_obs_space[iloc], 1);
102 const float missingValueFloat = util::missingValue(missingValueFloat);
103 std::vector <float> val(nlocs);
104 std::vector <float> err(nlocs);
105 const oops::Variables& obsvars = obsdata.
obsvariables();
106 for (
int ivar = 0; ivar < obsvars.size(); ++ivar) {
107 const std::string varname = obsvars[ivar];
108 obsdata.
get_db(
"ObsValue", varname, val);
109 obsdata.
get_db(
"ObsError", varname, err);
110 for (
int iloc = extendedObsSpaceStart; iloc < nlocs; ++iloc) {
111 EXPECT_EQUAL(val[iloc], missingValueFloat);
112 EXPECT_EQUAL(err[iloc], missingValueFloat);
118 if (obsdata.
has(
"MetaData",
"station_id")) {
119 const std::string missingValueString = util::missingValue(missingValueString);
120 std::vector <std::string> statid(nlocs);
121 obsdata.
get_db(
"MetaData",
"station_id", statid);
122 for (
int iloc = extendedObsSpaceStart; iloc < nlocs; ++iloc)
123 EXPECT_EQUAL(statid[iloc], missingValueString);
129 const std::vector <std::string> extendedVarsToCheck =
130 {
"latitude",
"longitude",
"air_pressure"};
132 const std::vector <std::string> &nonMissingExtendedVars =
133 obsSpaceConf.getStringVector(
"extension.variables filled with non-missing values",
134 {
"latitude",
"longitude",
"datetime",
135 "air_pressure",
"air_pressure_levels"});
136 std::vector <float> val_extended(nlocs);
137 for (
auto &varname : extendedVarsToCheck) {
139 if (obsdata.
has(
"MetaData", varname)) {
140 const bool filledWithNonMissing =
141 std::find(nonMissingExtendedVars.begin(), nonMissingExtendedVars.end(), varname) !=
142 nonMissingExtendedVars.end();
143 obsdata.
get_db(
"MetaData", varname, val_extended);
144 if (filledWithNonMissing) {
145 for (
int iloc = extendedObsSpaceStart; iloc < nlocs; ++iloc)
146 EXPECT(val_extended[iloc] != missingValueFloat);
148 for (
int iloc = extendedObsSpaceStart; iloc < nlocs; ++iloc)
149 EXPECT_EQUAL(val_extended[iloc], missingValueFloat);
160 EXPECT_EQUAL(nrecs % 2, 0);
161 std::size_t nrecs_original = nrecs / 2;
162 const std::vector<std::size_t> original_recnums(recidx_all_recnums.begin(),
163 recidx_all_recnums.begin() + nrecs / 2);
164 const std::vector<std::size_t> extended_recnums(recidx_all_recnums.begin() + nrecs / 2,
165 recidx_all_recnums.end());
166 std::size_t gnrecs_original = original_recnums.empty() ? 0 : (original_recnums.back() + 1);
169 std::vector<std::size_t> extended_recnums_expected;
170 for (std::size_t i : original_recnums)
171 extended_recnums_expected.push_back(i + gnrecs_original);
172 EXPECT_EQUAL(extended_recnums, extended_recnums_expected);
176 std::vector <size_t> index_processors = obsdata.
index();
178 std::sort(index_processors.begin(), index_processors.end());
179 auto it_unique = std::unique(index_processors.begin(), index_processors.end());
180 index_processors.erase(it_unique, index_processors.end());
182 std::vector <size_t> index_processors_expected(index_processors.size());
183 std::iota(index_processors_expected.begin(), index_processors_expected.end(), 0);
185 EXPECT_EQUAL(index_processors, index_processors_expected);
192 std::string
testid()
const override {
return "ioda::test::ExtendedObsSpace";}
195 std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
197 const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
198 for (
const std::string & testCaseName : conf.keys())
200 const eckit::LocalConfiguration testCaseConf(::test::TestEnvironment::config(), testCaseName);
201 ts.emplace_back(
CASE(
"ioda/ExtendedObsSpace/" + testCaseName, testCaseConf)
Observation data class for IODA.
bool has(const std::string &group, const std::string &name) const
return true if group/variable exists
std::vector< std::size_t > recidx_all_recnums() const
return all record numbers from the recidx_ data member
std::size_t nrecs() const
return the number of records in the obs space container
const std::vector< std::string > & obs_group_vars() const
return YAML configuration parameter: obsdatain.obsgrouping.group variables
const std::vector< std::size_t > & index() const
return reference to the index vector
const eckit::mpi::Comm & comm() const
std::shared_ptr< const Distribution > distribution() const
return MPI distribution object
size_t nlocs() const
return the number of locations in the obs space. Note that nlocs may be smaller than global unique nl...
void get_db(const std::string &group, const std::string &name, std::vector< int > &vdata, const std::vector< int > &chanSelect={ }) const
transfer data from the obs container to vdata
void save()
save the obs space data into a file (if obsdataout specified)
std::size_t globalNumLocs() const
return the total number of locations in the corresponding obs spaces across all MPI tasks
const oops::Variables & obsvariables() const
return oops variables object (simulated variables)
void clear() const override
std::string testid() const override
void register_tests() const override
void testExtendedObsSpace(const eckit::LocalConfiguration &conf)
CASE("Derived variable and unit conversion methods")