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::ObsSpace obsspace(obsSpaceConf, oops::mpi::world(), bgn, end, oops::mpi::myself());
37 
38  if (conf.has("air_pressures")) {
39  const std::vector<float> air_pressures = conf.getFloatVector("air_pressures");
40  obsspace.put_db("MetaData", "air_pressure", air_pressures);
41  const std::vector<float> air_pressure_obserrors(air_pressures.size(), 1.0f);
42  obsspace.put_db("ObsError", "air_pressure", air_pressure_obserrors);
43  }
44 
45  if (conf.has("min_vertical_spacing")) {
46  const std::vector<float> min_vertical_spacing = conf.getFloatVector("min_vertical_spacing");
47  obsspace.put_db("MetaData", "min_vertical_spacing", min_vertical_spacing);
48  }
49 
50  if (conf.has("category")) {
51  const std::vector<int> categories = conf.getIntVector("category");
52  obsspace.put_db("MetaData", "category", categories);
53  }
54 
55  if (conf.has("priority")) {
56  const std::vector<int> priorities = conf.getIntVector("priority");
57  obsspace.put_db("MetaData", "priority", priorities);
58  }
59 
60  std::shared_ptr<ioda::ObsDataVector<float>> obserr(new ioda::ObsDataVector<float>(
61  obsspace, obsspace.obsvariables(), "ObsError"));
62  std::shared_ptr<ioda::ObsDataVector<int>> qcflags(new ioda::ObsDataVector<int>(
63  obsspace, obsspace.obsvariables()));
64 
65  const eckit::LocalConfiguration filterConf(conf, "Poisson Disk Thinning");
66  ufo::PoissonDiskThinning filter(obsspace, filterConf, qcflags, obserr);
67  if (expectValidationError) {
68  EXPECT_THROWS(filter.preProcess());
69  return;
70  } else {
71  filter.preProcess();
72  }
73 
74  const std::vector<size_t> expectedThinnedObsIndices =
75  conf.getUnsignedVector("expected_thinned_obs_indices");
76  std::vector<size_t> thinnedObsIndices;
77  for (size_t i = 0; i < qcflags->nlocs(); ++i)
78  if ((*qcflags)[0][i] == ufo::QCflags::thinned)
79  thinnedObsIndices.push_back(i);
80  EXPECT_EQUAL(thinnedObsIndices, expectedThinnedObsIndices);
81 }
82 
83 CASE("ufo/PoissonDiskThinning/No thinning") {
84  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
85  "No thinning"));
86 }
87 
88 CASE("ufo/PoissonDiskThinning/"
89  "Horizontal thinning, min spacing smaller than nearest neighbor spacing") {
90  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
91  "Horizontal thinning, min spacing "
92  "smaller than nearest neighbor spacing"));
93 }
94 
95 CASE("ufo/PoissonDiskThinning/"
96  "Horizontal thinning, min spacing larger than nearest neighbor spacing") {
97  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
98  "Horizontal thinning, min spacing "
99  "larger than nearest neighbor spacing"));
100 }
101 
102 CASE("ufo/PoissonDiskThinning/"
103  "Vertical thinning, min spacing smaller than nearest neighbor spacing") {
104  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
105  "Vertical thinning, min spacing "
106  "smaller than nearest neighbor spacing"));
107 }
108 
109 CASE("ufo/PoissonDiskThinning/"
110  "Vertical thinning, min spacing larger than nearest neighbor spacing") {
111  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
112  "Vertical thinning, min spacing "
113  "larger than nearest neighbor spacing"));
114 }
115 
116 CASE("ufo/PoissonDiskThinning/Vertical thinning, where clause") {
117  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
118  "Vertical thinning, where clause"));
119 }
120 
121 CASE("ufo/PoissonDiskThinning/"
122  "Time thinning, min spacing equal to nearest neighbor spacing") {
123  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
124  "Time thinning, min spacing "
125  "equal to nearest neighbor spacing"));
126 }
127 
128 CASE("ufo/PoissonDiskThinning/"
129  "Time thinning, min spacing larger than nearest neighbor spacing") {
130  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
131  "Time thinning, min spacing "
132  "larger than nearest neighbor spacing"));
133 }
134 
135 CASE("ufo/PoissonDiskThinning/"
136  "Horizontal and vertical thinning, min spacing larger than nearest neighbor spacing") {
137  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
138  "Horizontal and vertical thinning, min spacing "
139  "larger than nearest neighbor spacing"));
140 }
141 
142 CASE("ufo/PoissonDiskThinning/"
143  "Horizontal and time thinning, min spacing larger than nearest neighbor spacing") {
144  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
145  "Horizontal and time thinning, min spacing "
146  "larger than nearest neighbor spacing"));
147 }
148 
149 CASE("ufo/PoissonDiskThinning/"
150  "Vertical and time thinning, min spacing larger than nearest neighbor spacing") {
151  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
152  "Vertical and time thinning, min spacing "
153  "larger than nearest neighbor spacing"));
154 }
155 
156 CASE("ufo/PoissonDiskThinning/"
157  "Horizontal, vertical and time thinning, min spacing larger than nearest neighbor spacing") {
158  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
159  "Horizontal, vertical and time thinning, min "
160  "spacing larger than nearest neighbor spacing"));
161 }
162 
163 CASE("ufo/PoissonDiskThinning/Priorities") {
164  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
165  "Priorities"));
166 }
167 
168 CASE("ufo/PoissonDiskThinning/Categories") {
169  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
170  "Categories"));
171 }
172 
173 CASE("ufo/PoissonDiskThinning/Variable min spacings") {
174  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
175  "Variable min spacings"));
176 }
177 
178 CASE("ufo/PoissonDiskThinning/Variable min spacings, shuffling") {
179  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
180  "Variable min spacings, shuffling"));
181 }
182 
183 CASE("ufo/PoissonDiskThinning/Cylindrical exclusion volumes") {
184  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
185  "Cylindrical exclusion volumes"));
186 }
187 
188 CASE("ufo/PoissonDiskThinning/Ellipsoidal exclusion volumes") {
189  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
190  "Ellipsoidal exclusion volumes"));
191 }
192 
193 CASE("ufo/PoissonDiskThinning/Incorrectly ordered min horizontal spacings") {
194  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
195  "Incorrectly ordered min horizontal spacings"),
196  true /*expectValidationError?*/);
197 }
198 
199 CASE("ufo/PoissonDiskThinning/Incorrectly ordered min vertical spacings") {
200  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
201  "Incorrectly ordered min vertical spacings"),
202  true /*expectValidationError?*/);
203 }
204 
205 CASE("ufo/PoissonDiskThinning/Incorrectly ordered min time spacings") {
206  testPoissonDiskThinning(eckit::LocalConfiguration(::test::TestEnvironment::config(),
207  "Incorrectly ordered min time spacings"),
208  true /*expectValidationError?*/);
209 }
210 
211 class PoissonDiskThinning : public oops::Test {
212  private:
213  std::string testid() const override {return "ufo::test::PoissonDiskThinning";}
214 
215  void register_tests() const override {}
216 
217  void clear() const override {}
218 };
219 
220 } // namespace test
221 } // namespace ufo
222 
223 #endif // TEST_UFO_POISSONDISKTHINNING_H_
ufo::test::testPoissonDiskThinning
void testPoissonDiskThinning(const eckit::LocalConfiguration &conf, bool expectValidationError=false)
Definition: test/ufo/PoissonDiskThinning.h:30
ufo::test::CASE
CASE("ufo/MetOfficeBuddyPairFinder/" "Duplicates, constraints on buddy counts, legacy pair collector")
Definition: test/ufo/MetOfficeBuddyPairFinder.h:171
ufo::FilterBase::preProcess
void preProcess()
Definition: FilterBase.cc:66
ufo
Definition: RunCRTM.h:27
ufo::PoissonDiskThinning
Thins observations by iterating over them in random order and retaining each observation lying outsid...
Definition: src/ufo/filters/PoissonDiskThinning.h:52
Variables.h
ufo::test::PoissonDiskThinning::clear
void clear() const override
Definition: test/ufo/PoissonDiskThinning.h:217
ufo::test::PoissonDiskThinning::register_tests
void register_tests() const override
Definition: test/ufo/PoissonDiskThinning.h:215
ufo::QCflags::thinned
constexpr int thinned
Definition: QCflags.h:21
ufo::test::PoissonDiskThinning::testid
std::string testid() const override
Definition: test/ufo/PoissonDiskThinning.h:213
ioda::ObsDataVector
Definition: BackgroundCheck.h:26
PoissonDiskThinning.h
ufo::test::PoissonDiskThinning
Definition: test/ufo/PoissonDiskThinning.h:211
conf
Definition: conf.py:1