UFO
test/ufo/PoissonDiskThinning.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 Met Office UK
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_POISSONDISKTHINNING_H_
9 #define TEST_UFO_POISSONDISKTHINNING_H_
10 
11 #include <iomanip>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 #include "eckit/config/LocalConfiguration.h"
17 #include "eckit/testing/Test.h"
18 #include "ioda/ObsSpace.h"
19 #include "ioda/ObsVector.h"
20 #include "oops/mpi/mpi.h"
21 #include "oops/runs/Test.h"
22 #include "oops/util/Expect.h"
23 #include "test/TestEnvironment.h"
25 #include "ufo/filters/Variables.h"
26 
27 namespace ufo {
28 namespace test {
29 
30 void testPoissonDiskThinning(const eckit::LocalConfiguration &conf,
31  bool expectValidationError = false) {
32  util::DateTime bgn(conf.getString("window begin"));
33  util::DateTime end(conf.getString("window end"));
34 
35  const eckit::LocalConfiguration obsSpaceConf(conf, "obs space");
36  ioda::ObsTopLevelParameters obsParams;
37  obsParams.validateAndDeserialize(obsSpaceConf);
38  ioda::ObsSpace obsspace(obsParams, oops::mpi::world(), bgn, end, oops::mpi::myself());
39 
40  if (conf.has("air_pressures")) {
41  const std::vector<float> air_pressures = conf.getFloatVector("air_pressures");
42  obsspace.put_db("MetaData", "air_pressure", air_pressures);
43  const std::vector<float> air_pressure_obserrors(air_pressures.size(), 1.0f);
44  obsspace.put_db("ObsError", "air_pressure", air_pressure_obserrors);
45  }
46 
47  if (conf.has("min_vertical_spacing")) {
48  const std::vector<float> min_vertical_spacing = conf.getFloatVector("min_vertical_spacing");
49  obsspace.put_db("MetaData", "min_vertical_spacing", min_vertical_spacing);
50  }
51 
52  if (conf.has("category")) {
53  const std::vector<int> categories = conf.getIntVector("category");
54  obsspace.put_db("MetaData", "category", categories);
55  }
56 
57  if (conf.has("string_category")) {
58  const std::vector<std::string> categories = conf.getStringVector("string_category");
59  obsspace.put_db("MetaData", "string_category", categories);
60  }
61 
62  if (conf.has("priority")) {
63  const std::vector<int> priorities = conf.getIntVector("priority");
64  obsspace.put_db("MetaData", "priority", priorities);
65  }
66 
67  std::shared_ptr<ioda::ObsDataVector<float>> obserr(new ioda::ObsDataVector<float>(
68  obsspace, obsspace.obsvariables(), "ObsError"));
69  std::shared_ptr<ioda::ObsDataVector<int>> qcflags(new ioda::ObsDataVector<int>(
70  obsspace, obsspace.obsvariables()));
71 
72  eckit::LocalConfiguration filterConf(conf, "Poisson Disk Thinning");
73  ufo::PoissonDiskThinningParameters filterParameters;
74  filterParameters.validateAndDeserialize(filterConf);
75  ufo::PoissonDiskThinning filter(obsspace, filterParameters, qcflags, obserr);
76  if (expectValidationError) {
77  EXPECT_THROWS(filter.preProcess());
78  return;
79  } else {
80  filter.preProcess();
81  }
82 
83  const std::vector<size_t> expectedThinnedObsIndices =
84  conf.getUnsignedVector("expected_thinned_obs_indices");
85  std::vector<size_t> thinnedObsIndices;
86  for (size_t i = 0; i < qcflags->nlocs(); ++i)
87  if ((*qcflags)[0][i] == ufo::QCflags::thinned)
88  thinnedObsIndices.push_back(i);
89  EXPECT_EQUAL(thinnedObsIndices, expectedThinnedObsIndices);
90 }
91 
92 CASE("ufo/PoissonDiskThinning/No thinning") {
93  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
94  "No thinning"));
95 }
96 
97 CASE("ufo/PoissonDiskThinning/"
98  "Horizontal thinning, min spacing smaller than nearest neighbor spacing") {
99  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
100  "Horizontal thinning, min spacing "
101  "smaller than nearest neighbor spacing"));
102 }
103 
104 CASE("ufo/PoissonDiskThinning/"
105  "Horizontal thinning, min spacing larger than nearest neighbor spacing") {
106  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
107  "Horizontal thinning, min spacing "
108  "larger than nearest neighbor spacing"));
109 }
110 
111 CASE("ufo/PoissonDiskThinning/"
112  "Vertical thinning, min spacing smaller than nearest neighbor spacing") {
113  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
114  "Vertical thinning, min spacing "
115  "smaller than nearest neighbor spacing"));
116 }
117 
118 CASE("ufo/PoissonDiskThinning/"
119  "Vertical thinning, min spacing larger than nearest neighbor spacing") {
120  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
121  "Vertical thinning, min spacing "
122  "larger than nearest neighbor spacing"));
123 }
124 
125 CASE("ufo/PoissonDiskThinning/Vertical thinning, where clause") {
126  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
127  "Vertical thinning, where clause"));
128 }
129 
130 CASE("ufo/PoissonDiskThinning/"
131  "Time thinning, min spacing equal to nearest neighbor spacing") {
132  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
133  "Time thinning, min spacing "
134  "equal to nearest neighbor spacing"));
135 }
136 
137 CASE("ufo/PoissonDiskThinning/"
138  "Time thinning, min spacing larger than nearest neighbor spacing") {
139  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
140  "Time thinning, min spacing "
141  "larger than nearest neighbor spacing"));
142 }
143 
144 CASE("ufo/PoissonDiskThinning/"
145  "Horizontal and vertical thinning, min spacing larger than nearest neighbor spacing") {
146  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
147  "Horizontal and vertical thinning, min spacing "
148  "larger than nearest neighbor spacing"));
149 }
150 
151 CASE("ufo/PoissonDiskThinning/"
152  "Horizontal and time thinning, min spacing larger than nearest neighbor spacing") {
153  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
154  "Horizontal and time thinning, min spacing "
155  "larger than nearest neighbor spacing"));
156 }
157 
158 CASE("ufo/PoissonDiskThinning/"
159  "Vertical and time thinning, min spacing larger than nearest neighbor spacing") {
160  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
161  "Vertical and time thinning, min spacing "
162  "larger than nearest neighbor spacing"));
163 }
164 
165 CASE("ufo/PoissonDiskThinning/"
166  "Horizontal, vertical and time thinning, min spacing larger than nearest neighbor spacing") {
167  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
168  "Horizontal, vertical and time thinning, min "
169  "spacing larger than nearest neighbor spacing"));
170 }
171 
172 CASE("ufo/PoissonDiskThinning/Priorities") {
173  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
174  "Priorities"));
175 }
176 
177 CASE("ufo/PoissonDiskThinning/Int-valued categories") {
178  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
179  "Int-valued categories"));
180 }
181 
182 CASE("ufo/PoissonDiskThinning/String-valued categories") {
183  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
184  "String-valued categories"));
185 }
186 
187 CASE("ufo/PoissonDiskThinning/Variable min spacings") {
188  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
189  "Variable min spacings"));
190 }
191 
192 CASE("ufo/PoissonDiskThinning/Variable min spacings, shuffling") {
193  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
194  "Variable min spacings, shuffling"));
195 }
196 
197 CASE("ufo/PoissonDiskThinning/Cylindrical exclusion volumes") {
198  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
199  "Cylindrical exclusion volumes"));
200 }
201 
202 CASE("ufo/PoissonDiskThinning/Ellipsoidal exclusion volumes") {
203  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
204  "Ellipsoidal exclusion volumes"));
205 }
206 
207 CASE("ufo/PoissonDiskThinning/Incorrectly ordered min horizontal spacings") {
208  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
209  "Incorrectly ordered min horizontal spacings"),
210  true /*expectValidationError?*/);
211 }
212 
213 CASE("ufo/PoissonDiskThinning/Incorrectly ordered min vertical spacings") {
214  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
215  "Incorrectly ordered min vertical spacings"),
216  true /*expectValidationError?*/);
217 }
218 
219 CASE("ufo/PoissonDiskThinning/Incorrectly ordered min time spacings") {
220  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
221  "Incorrectly ordered min time spacings"),
222  true /*expectValidationError?*/);
223 }
224 
225 class PoissonDiskThinning : public oops::Test {
226  private:
227  std::string testid() const override {return "ufo::test::PoissonDiskThinning";}
228 
229  void register_tests() const override {}
230 
231  void clear() const override {}
232 };
233 
234 } // namespace test
235 } // namespace ufo
236 
237 #endif // TEST_UFO_POISSONDISKTHINNING_H_
Thins observations by iterating over them in random order and retaining each observation lying outsid...
Options controlling the operation of the PoissonDiskThinning filter.
constexpr int thinned
Definition: QCflags.h:26
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
void testPoissonDiskThinning(const eckit::LocalConfiguration &conf, bool expectValidationError=false)
Definition: RunCRTM.h:27