UFO
test/ufo/ObsFunction.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 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_UFO_OBSFUNCTION_H_
9 #define TEST_UFO_OBSFUNCTION_H_
10 
11 #include <iomanip>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
17 
18 #include "eckit/config/LocalConfiguration.h"
19 #include "eckit/testing/Test.h"
20 #include "ioda/ObsSpace.h"
21 #include "ioda/ObsVector.h"
22 #include "oops/mpi/mpi.h"
23 #include "oops/runs/Test.h"
24 #include "test/TestEnvironment.h"
27 #include "ufo/filters/Variables.h"
28 #include "ufo/GeoVaLs.h"
29 #include "ufo/ObsDiagnostics.h"
30 
31 namespace ufo {
32 namespace test {
33 
34 // -----------------------------------------------------------------------------
35 
36 void dataVectorDiff(const ioda::ObsSpace & ospace, ioda::ObsDataVector<float> & vals,
37  const ioda::ObsDataVector<float> & ref, std::vector<float> & rms_out) {
38  /// Loop through variables and calculate rms for each variable
39  for (size_t ivar = 0; ivar < vals.nvars() ; ++ivar) {
40  float rms = 0.0;
41  int nobs = 0;
42  for (size_t jj = 0; jj < ref.nlocs() ; ++jj) {
43  vals[ivar][jj] -= ref[ivar][jj];
44  rms += vals[ivar][jj] * vals[ivar][jj];
45  nobs++;
46  }
47  ospace.comm().allReduceInPlace(rms, eckit::mpi::sum());
48  ospace.comm().allReduceInPlace(nobs, eckit::mpi::sum());
49  if (nobs > 0) rms = sqrt(rms / static_cast<float>(nobs));
50  rms_out[ivar] = rms;
51  }
52 }
53 
54 // -----------------------------------------------------------------------------
55 
56 void testFunction() {
57  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
58 /// Setup ObsSpace
59  util::DateTime bgn(conf.getString("window begin"));
60  util::DateTime end(conf.getString("window end"));
61  const eckit::LocalConfiguration obsconf(conf, "obs space");
62  ioda::ObsSpace ospace(obsconf, oops::mpi::world(), bgn, end, oops::mpi::myself());
63 
64 /// Setup ObsFilterData
65  ObsFilterData inputs(ospace);
66 
67 /// Get function name and which group to use for H(x)
68  const eckit::LocalConfiguration obsfuncconf(conf, "obs function");
69  Variable funcname(obsfuncconf);
70 
71 /// Setup function
72  ObsFunction obsfunc(funcname);
73  ufo::Variables allfuncvars = obsfunc.requiredVariables();
74 
75 /// Setup GeoVaLs
76  const oops::Variables geovars = allfuncvars.allFromGroup("GeoVaLs").toOopsVariables();
77  std::unique_ptr<GeoVaLs> gval;
78  if (geovars.size() > 0) {
79  const eckit::LocalConfiguration gconf(conf, "geovals");
80  gval.reset(new GeoVaLs(gconf, ospace, geovars));
81  inputs.associate(*gval);
82  }
83 
84 /// Setup ObsDiags
85  const oops::Variables diagvars = allfuncvars.allFromGroup("ObsDiag").toOopsVariables();
86  std::unique_ptr<ObsDiagnostics> diags;
87  if (diagvars.size() > 0) {
88  const eckit::LocalConfiguration diagconf(conf, "obs diagnostics");
89  diags.reset(new ObsDiagnostics(diagconf, ospace, diagvars));
90  inputs.associate(*diags);
91  }
92 
93 /// Get output variable names
94  const oops::Variables outputvars(obsfuncconf, "variables");
95 /// Compute function result
96  ioda::ObsDataVector<float> vals(ospace, outputvars, "ObsFunction", false);
97  obsfunc.compute(inputs, vals);
98  vals.save("TestResult");
99  int nvars = vals.nvars();
100 
101 /// Compute function result through ObsFilterData
102  ioda::ObsDataVector<float> vals_ofd(ospace, outputvars, "ObsFunction", false);
103  inputs.get(funcname, vals_ofd);
104 
105 /// Read reference values from ObsSpace
106  ioda::ObsDataVector<float> ref(ospace, outputvars, "TestReference");
107 
108 
109  const double tol = obsfuncconf.getDouble("tolerance");
110 
111 /// Calculate rms(f(x) - ref) and compare to tolerance
112  std::vector<float> rms_out(nvars);
113  dataVectorDiff(ospace, vals, ref, rms_out);
114 
115  oops::Log::info() << "Vector difference between reference and computed: " << std::endl;
116  oops::Log::info() << vals << std::endl;
117  for (size_t ivar = 0; ivar < nvars; ivar++) {
118  EXPECT(rms_out[ivar] < 100*tol); // change tol from percent to actual value.
119  }
120 
121  dataVectorDiff(ospace, vals_ofd, ref, rms_out);
122  oops::Log::info() << "Vector difference between reference and computed via ObsFilterData: "
123  << std::endl;
124  oops::Log::info() << vals_ofd << std::endl;
125  for (size_t ivar = 0; ivar < nvars; ivar++) {
126  EXPECT(rms_out[ivar] < 100*tol); // change tol from percent to actual value.
127  }
128 }
129 
130 // -----------------------------------------------------------------------------
131 
132 class ObsFunction : public oops::Test {
133  public:
135  virtual ~ObsFunction() {}
136  private:
137  std::string testid() const override {return "ufo::test::ObsFunction";}
138 
139  void register_tests() const override {
140  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
141 
142  ts.emplace_back(CASE("ufo/ObsFunction/testFunction")
143  { testFunction(); });
144  }
145 
146  void clear() const override {}
147 };
148 
149 // -----------------------------------------------------------------------------
150 
151 } // namespace test
152 } // namespace ufo
153 
154 #endif // TEST_UFO_OBSFUNCTION_H_
ufo::test::ObsFunction::clear
void clear() const override
Definition: test/ufo/ObsFunction.h:146
ufo::Variables
Definition: src/ufo/filters/Variables.h:24
ufo::test::GeoVaLs
Definition: test/ufo/GeoVaLs.h:168
ufo::test::testFunction
void testFunction()
Definition: test/ufo/ObsFunction.h:56
ufo::test::CASE
CASE("ufo/MetOfficeBuddyPairFinder/" "Duplicates, constraints on buddy counts, legacy pair collector")
Definition: test/ufo/MetOfficeBuddyPairFinder.h:171
ufo::test::ObsFunction::register_tests
void register_tests() const override
Definition: test/ufo/ObsFunction.h:139
ufo
Definition: RunCRTM.h:27
ufo::test::dataVectorDiff
void dataVectorDiff(const ioda::ObsSpace &ospace, ioda::ObsDataVector< float > &vals, const ioda::ObsDataVector< float > &ref, std::vector< float > &rms_out)
Definition: test/ufo/ObsFunction.h:36
ufo::test::ObsFunction::ObsFunction
ObsFunction()
Definition: test/ufo/ObsFunction.h:134
Variables.h
ufo::test::ObsFunction::~ObsFunction
virtual ~ObsFunction()
Definition: test/ufo/ObsFunction.h:135
ObsFunction.h
ioda::ObsDataVector
Definition: BackgroundCheck.h:26
ufo::test::ObsFunction
Definition: test/ufo/ObsFunction.h:132
ufo::Variables::allFromGroup
Variables allFromGroup(const std::string &) const
Definition: Variables.cc:128
ObsFilterData.h
ufo::test::ObsDiagnostics
Definition: test/ufo/ObsDiagnostics.h:102
ufo::test::ObsFilterData
Definition: test/ufo/ObsFilterData.h:212
ufo::Variable
Definition: Variable.h:23
ufo::test::ObsFunction::testid
std::string testid() const override
Definition: test/ufo/ObsFunction.h:137
conf
Definition: conf.py:1