8 #ifndef TEST_UFO_OBSFUNCTION_H_
9 #define TEST_UFO_OBSFUNCTION_H_
16 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
18 #include "eckit/config/LocalConfiguration.h"
19 #include "eckit/testing/Test.h"
20 #include "ioda/distribution/DistributionUtils.h"
21 #include "ioda/ObsSpace.h"
22 #include "ioda/ObsVector.h"
23 #include "oops/mpi/mpi.h"
24 #include "oops/runs/Test.h"
25 #include "oops/util/Expect.h"
26 #include "oops/util/missingValues.h"
27 #include "test/interface/ObsTestsFixture.h"
28 #include "test/TestEnvironment.h"
32 #include "ufo/GeoVaLs.h"
33 #include "ufo/ObsDiagnostics.h"
40 template <>
struct VectorPrintSelector<
util::DateTime> {
typedef VectorPrintSimple selector; };
60 size_t &num_missing_mismatches) {
62 num_missing_mismatches = 0;
64 for (
size_t ivar = 0; ivar < vals.nvars() ; ++ivar) {
65 for (
size_t jj = 0; jj < ref.nlocs() ; ++jj) {
67 vals[ivar][jj] -= ref[ivar][jj];
72 ++num_missing_mismatches;
75 int nobs = globalNumNonMissingObs(*ospace.distribution(), 1, vals[ivar]);
76 float rms = dotProduct(*ospace.distribution(), 1, vals[ivar], vals[ivar]);
77 if (nobs > 0) rms = sqrt(rms /
static_cast<float>(nobs));
94 const eckit::Configuration &,
98 const size_t nvars = ref.nvars();
99 EXPECT_EQUAL(vals.nvars(), nvars);
101 for (
size_t i = 0; i < nvars; ++i)
102 EXPECT_EQUAL(vals[i], ref[i]);
104 for (
size_t i = 0; i < nvars; ++i)
105 EXPECT_EQUAL(vals_ofd[i], ref[i]);
113 const eckit::Configuration &obsfuncconf,
117 const double tol = obsfuncconf.getDouble(
"tolerance");
118 const bool expectMissingToMatch =
119 obsfuncconf.getBool(
"expect missing value locations to match",
false);
120 const size_t nvars = ref.nvars();
121 EXPECT_EQUAL(vals.nvars(), nvars);
124 std::vector<float> rms_out(nvars);
125 size_t numMissingMismatches;
128 oops::Log::info() <<
"Vector difference between reference and computed: " << std::endl;
129 oops::Log::info() << vals << std::endl;
130 for (
size_t ivar = 0; ivar < nvars; ivar++) {
132 EXPECT(rms_out[ivar] < 100*tol);
134 if (expectMissingToMatch)
135 EXPECT_EQUAL(numMissingMismatches, 0);
137 dataVectorDiff(ospace, vals_ofd, ref, rms_out, numMissingMismatches);
138 oops::Log::info() <<
"Vector difference between reference and computed via ObsFilterData: "
140 oops::Log::info() << vals_ofd << std::endl;
141 for (
size_t ivar = 0; ivar < nvars; ivar++) {
143 EXPECT(rms_out[ivar] < 100*tol);
145 if (expectMissingToMatch)
146 EXPECT_EQUAL(numMissingMismatches, 0);
151 template <
typename T>
154 const eckit::LocalConfiguration obsfuncconf(conf,
"obs function");
161 EXPECT_THROWS_MSG(
ObsFunction<T>{funcname}, expectedMessage.c_str());
171 const oops::Variables geovars = allfuncvars.
allFromGroup(
"GeoVaLs").toOopsVariables();
172 std::unique_ptr<GeoVaLs> gval;
173 if (geovars.size() > 0) {
174 const eckit::LocalConfiguration gconf(conf,
"geovals");
175 gval.reset(
new GeoVaLs(gconf, ospace, geovars));
176 inputs.associate(*gval);
180 ioda::ObsVector bias(ospace);
182 inputs.associate(bias,
"ObsBiasData");
185 const oops::Variables diagvars = allfuncvars.
allFromGroup(
"ObsDiag").toOopsVariables();
186 std::unique_ptr<ObsDiagnostics> diags;
187 if (diagvars.size() > 0) {
188 const eckit::LocalConfiguration diagconf(conf,
"obs diagnostics");
190 inputs.associate(*diags);
194 const oops::Variables outputvars(obsfuncconf,
"variables");
198 obsfunc.compute(inputs, vals);
202 EXPECT_THROWS_MSG(obsfunc.compute(inputs, vals), expectedMessage.c_str());
205 vals.save(
"TestResult");
209 inputs.get(funcname, vals_ofd);
220 typedef ::test::ObsTestsFixture<ObsTraits> Test_;
222 std::vector<eckit::LocalConfiguration> typeconfs;
223 ::test::TestEnvironment::config().get(
"observations", typeconfs);
225 for (std::size_t jj = 0; jj < Test_::obspace().size(); ++jj) {
226 ioda::ObsSpace &ospace = Test_::obspace()[jj].obsspace();
227 const eckit::Configuration &conf = typeconfs[jj];
231 Variable funcname(conf.getSubConfiguration(
"obs function"));
233 doTestFunction<float>(ospace, conf);
235 doTestFunction<int>(ospace, conf);
237 doTestFunction<std::string>(ospace, conf);
239 doTestFunction<util::DateTime>(ospace, conf);
241 throw eckit::testing::TestException(
"Variable " + funcname.
fullName() +
242 " is not an ObsFunction", Here());
253 std::string
testid()
const override {
return "ufo::test::ObsFunction";}
256 std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
258 ts.emplace_back(
CASE(
"ufo/ObsFunction/testFunction")
263 ::test::ObsTestsFixture<ObsTraits>::reset();
std::string fullName() const
const std::string & group() const
Variables allFromGroup(const std::string &) const
void register_tests() const override
void clear() const override
std::string testid() const override
const char * expectComputeToThrow
void dataVectorDiff(const ioda::ObsSpace &ospace, ioda::ObsDataVector< float > &vals, const ioda::ObsDataVector< float > &ref, std::vector< float > &rms_out, size_t &num_missing_mismatches)
void checkResults(const ioda::ObsSpace &, const eckit::Configuration &, const ioda::ObsDataVector< T > &vals, const ioda::ObsDataVector< T > &vals_ofd, const ioda::ObsDataVector< T > &ref)
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
const char * expectConstructorToThrow
void doTestFunction(ioda::ObsSpace &ospace, const eckit::Configuration &conf)
Common properties of ObsFunctions producing values of type FunctionValue.