UFO
test/ufo/ObsDiagnostics.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_OBSDIAGNOSTICS_H_
9 #define TEST_UFO_OBSDIAGNOSTICS_H_
10 
11 #include <memory>
12 #include <string>
13 #include <vector>
14 
15 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
16 
17 #include "eckit/config/LocalConfiguration.h"
18 #include "eckit/testing/Test.h"
19 #include "ioda/ObsSpace.h"
20 #include "ioda/ObsVector.h"
21 #include "oops/base/Variables.h"
22 #include "oops/mpi/mpi.h"
23 #include "oops/runs/Test.h"
24 #include "test/TestEnvironment.h"
25 #include "ufo/GeoVaLs.h"
26 #include "ufo/Locations.h"
27 #include "ufo/ObsBias.h"
28 #include "ufo/ObsDiagnostics.h"
29 #include "ufo/ObsOperator.h"
30 
31 namespace eckit
32 {
33  // Don't use the contracted output for this type: the current implementation works only
34  // with integer types.
35  // TODO(wsmigaj) Report this as a bug in eckit.
36  template <> struct VectorPrintSelector<float> { typedef VectorPrintSimple selector; };
37 } // namespace eckit
38 
39 namespace ufo {
40 namespace test {
41 
42 // -----------------------------------------------------------------------------
43 
45  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
46 
47  // Setup ObsSpace
48  util::DateTime bgn(conf.getString("window begin"));
49  util::DateTime end(conf.getString("window end"));
50  const eckit::LocalConfiguration obsconf(conf, "obs space");
51  ioda::ObsTopLevelParameters obsparams;
52  obsparams.validateAndDeserialize(obsconf);
53  ioda::ObsSpace ospace(obsparams, oops::mpi::world(), bgn, end, oops::mpi::myself());
54  const size_t nlocs = ospace.nlocs();
55 
56  // initialize observation operator (set variables requested from the model,
57  // variables simulated by the observation operator, other init)
58  eckit::LocalConfiguration obsopconf(conf, "obs operator");
59  ObsOperatorParametersWrapper obsopparams;
60  obsopparams.validateAndDeserialize(obsopconf);
61  ObsOperator hop(ospace, obsopparams);
62 
63  // read geovals from the file
64  eckit::LocalConfiguration gconf(conf, "geovals");
65  const GeoVaLs gval(gconf, ospace, hop.requiredVars());
66 
67  // initialize bias correction
68  eckit::LocalConfiguration biasconf = conf.getSubConfiguration("obs bias");
69  ObsBiasParameters biasparams;
70  biasparams.validateAndDeserialize(biasconf);
71  const ObsBias ybias(ospace, biasparams);
72 
73  // create obsvector to hold H(x)
74  ioda::ObsVector hofx(ospace);
75 
76  // create obsvector to hold bias
77  ioda::ObsVector bias(ospace);
78  bias.zero();
79 
80  // create diagnostics to hold HofX diags
81  eckit::LocalConfiguration diagconf(conf, "obs diagnostics");
82  oops::Variables diagvars(diagconf, "variables");
83  EXPECT(diagvars.size() > 0);
84  std::unique_ptr<Locations> locs(hop.locations());
85  ObsDiagnostics diags(ospace, *(locs.get()), diagvars);
86 
87  // call H(x) to compute diagnostics
88  hop.simulateObs(gval, hofx, ybias, bias, diags);
89 
90  // read tolerance and reference Diagnostics
91  const double tol = conf.getDouble("tolerance");
92  eckit::LocalConfiguration diagrefconf(conf, "reference obs diagnostics");
93  ObsDiagnostics diagref(diagrefconf, ospace, diagvars);
94 
95  // loop over all diag variables and levels and compare with reference
96  for (size_t ivar = 0; ivar < diagvars.size(); ivar++) {
97  const size_t nlevs = diags.nlevs(diagvars[ivar]);
98  EXPECT(nlevs == diagref.nlevs(diagvars[ivar]));
99  for (size_t ilev = 0; ilev < nlevs; ilev++) {
100  std::vector<float> ref(nlocs);
101  std::vector<float> computed(nlocs);
102  diags.get(computed, diagvars[ivar], ilev);
103  diagref.get(ref, diagvars[ivar], ilev);
104 
105  float rms = 0.0;
106  for (size_t iloc = 0; iloc < nlocs; iloc++) {
107  ref[iloc] -= computed[iloc];
108  rms += ref[iloc] * ref[iloc];
109  }
110  rms = sqrt(rms / nlocs);
111 
112  EXPECT(rms < 100*tol);
113  oops::Log::info() << diagvars[ivar] << ", level " << ilev <<
114  ": difference between reference and computed: " << ref << std::endl;
115  }
116  }
117 }
118 
119 // -----------------------------------------------------------------------------
120 
121 class ObsDiagnostics : public oops::Test {
122  public:
124  virtual ~ObsDiagnostics() {}
125  private:
126  std::string testid() const override {return "ufo::test::ObsDiagnostics";}
127 
128  void register_tests() const override {
129  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
130 
131  ts.emplace_back(CASE("ufo/ObsDiagnostics/testObsDiagnostics")
132  { testObsDiagnostics(); });
133  }
134 
135  void clear() const override {}
136 };
137 
138 // -----------------------------------------------------------------------------
139 
140 } // namespace test
141 } // namespace ufo
142 
143 #endif // TEST_UFO_OBSDIAGNOSTICS_H_
Parameters influencing the bias correction process.
std::unique_ptr< Locations > locations() const
Operator locations.
Definition: ObsOperator.cc:67
void simulateObs(const GeoVaLs &, ioda::ObsVector &, const ObsBias &, ioda::ObsVector &, ObsDiagnostics &) const
Obs Operator.
Definition: ObsOperator.cc:47
const oops::Variables & requiredVars() const
Operator input required from Model.
Definition: ObsOperator.cc:61
Contains a polymorphic parameter holding an instance of a subclass of ObsOperatorParametersBase.
void register_tests() const override
std::string testid() const override
Forward declarations.
Definition: ObsAodExt.h:21
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27