UFO
test/ufo/TrackCheckShip.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2020 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_TRACKCHECKSHIP_H_
9 #define TEST_UFO_TRACKCHECKSHIP_H_
10 
11 #include <iomanip>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 #include <boost/none.hpp>
17 #include <boost/optional.hpp>
18 
19 #define ECKIT_TESTING_SELF_REGISTER_CASES 0
20 
21 #include "eckit/config/LocalConfiguration.h"
22 #include "eckit/testing/Test.h"
23 #include "ioda/ObsSpace.h"
24 #include "ioda/ObsVector.h"
25 #include "oops/mpi/mpi.h"
26 #include "oops/runs/Test.h"
27 #include "oops/util/Expect.h"
28 #include "oops/util/FloatCompare.h"
29 #include "test/TestEnvironment.h"
32 #include "ufo/filters/Variables.h"
33 
34 namespace ufo {
35 namespace test {
36 
37 const boost::optional<ufo::TrackCheckShipDiagnostics> setupRunFilter(
38  const eckit::LocalConfiguration &conf, std::vector<size_t> *rejectedObsIndices = nullptr) {
39  util::DateTime bgn(conf.getString("window begin"));
40  util::DateTime end(conf.getString("window end"));
41 
42  const eckit::LocalConfiguration obsSpaceConf(conf, "obs space");
43  ioda::ObsTopLevelParameters obsParams;
44  obsParams.validateAndDeserialize(obsSpaceConf);
45  ioda::ObsSpace obsspace(obsParams, oops::mpi::world(), bgn, end, oops::mpi::myself());
46 
47  if (conf.has("station_ids")) {
48  const std::vector<int> stationIds = conf.getIntVector("station_ids");
49  obsspace.put_db("MetaData", "station_id", stationIds);
50  }
51 
52  std::shared_ptr<ioda::ObsDataVector<float>> obserr(new ioda::ObsDataVector<float>(
53  obsspace, obsspace.obsvariables(), "ObsError"));
54  std::shared_ptr<ioda::ObsDataVector<int>> qcflags(new ioda::ObsDataVector<int>(
55  obsspace, obsspace.obsvariables()));
56 
57  eckit::LocalConfiguration filterConf(conf, "Ship Track Check");
58  ufo::TrackCheckShipParameters filterParameters;
59  filterParameters.validateAndDeserialize(filterConf);
60  ufo::TrackCheckShip filter(obsspace, filterParameters, qcflags, obserr);
61  filter.preProcess();
62  if (filterConf.getBool("comparison test", false) && rejectedObsIndices) {
63  for (size_t i = 0; i < qcflags->nlocs(); ++i)
64  if ((*qcflags)[0][i] == ufo::QCflags::track)
65  rejectedObsIndices->push_back(i);
66  return boost::none;
67  } else if (filterConf.getBool("unit testing mode", false)) {
68  return *filter.diagnostics();
69  }
70  return boost::none;
71 }
72 
73 void testTrackCheckShipInitialCalculations(const eckit::LocalConfiguration &conf) {
74  auto diagnostics = setupRunFilter(conf);
75  if (!diagnostics)
76  return;
77  const std::vector<double> expectedDistances = conf.getDoubleVector("expected distance");
78  const std::vector<double> expectedSpeeds = conf.getDoubleVector("expected speed");
79  const std::vector<double> expectedDistancesAveraged =
80  conf.getDoubleVector("expected distance averaged");
81  const std::vector<double> expectedSpeedsAveraged =
82  conf.getDoubleVector("expected speed averaged");
83  const std::vector<float> expectedAngles = conf.getFloatVector("expected angle");
84  const std::vector<int> expectedShort = conf.getIntVector("expected short");
85  const std::vector<int> expectedFast = conf.getIntVector("expected fast");
86  const std::vector<int> expectedBends = conf.getIntVector("expected bends");
87  const std::vector<double> expectedSumSpeeds = conf.getDoubleVector("expected sum speed");
88  const std::vector<double> expectedMeanSpeeds = conf.getDoubleVector("expected mean speed");
89  std::vector<double> calculatedDistances, calculatedSpeeds, calculatedDistancesAveraged,
90  calculatedSpeedsAveraged, calculatedSumSpeeds, calculatedMeanSpeeds;
91  std::vector<float> calculatedAngles;
92  std::vector<int> calculatedShort, calculatedFast, calculatedBends;
93  for (auto const& tracks : diagnostics->getInitialCalculationResults()) {
94  for (auto const& obsStats : tracks.first) {
95  calculatedDistances.push_back(obsStats.distance);
96  calculatedSpeeds.push_back(obsStats.speed);
97  calculatedDistancesAveraged.push_back(obsStats.distanceAveraged);
98  calculatedSpeedsAveraged.push_back(obsStats.speedAveraged);
99  calculatedAngles.push_back(obsStats.angle);
100  }
101  calculatedShort.push_back(tracks.second.numShort_);
102  calculatedFast.push_back(tracks.second.numFast_);
103  calculatedBends.push_back(tracks.second.numBends_);
104  calculatedSumSpeeds.push_back(tracks.second.sumSpeed_);
105  calculatedMeanSpeeds.push_back(tracks.second.meanSpeed_);
106  }
107  EXPECT(oops::are_all_close_relative(calculatedDistances, expectedDistances,
108  .05));
109  EXPECT(oops::are_all_close_relative(calculatedSpeeds, expectedSpeeds,
110  .05));
111  EXPECT(oops::are_all_close_relative(
112  calculatedDistancesAveraged, expectedDistancesAveraged,
113  .05));
114  EXPECT(oops::are_all_close_relative(
115  calculatedSpeedsAveraged, expectedSpeedsAveraged,
116  .05));
117  EXPECT(oops::are_all_close_absolute(
118  calculatedAngles, expectedAngles,
119  5.0f));
120  EXPECT_EQUAL(calculatedShort, expectedShort);
121  EXPECT_EQUAL(calculatedFast, expectedFast);
122  EXPECT_EQUAL(calculatedBends, expectedBends);
123  EXPECT(oops::are_all_close_relative(
124  calculatedSumSpeeds, expectedSumSpeeds,
125  .05));
126  EXPECT(oops::are_all_close_relative
127  (calculatedMeanSpeeds, expectedMeanSpeeds,
128  .05));
129 }
130 
131 void testEarlyBreakCondition(const eckit::LocalConfiguration &conf) {
132  const eckit::LocalConfiguration filterConf(conf, "Ship Track Check");
133  if (!filterConf.getBool("early break check", true)) {
134  return;
135  }
136 
137  auto diagnostics = setupRunFilter(conf);
138  if (!diagnostics)
139  return;
140 
141  std::vector<int> expectedEarlyBreaks(conf.getIntVector("expected early breaks"));
142  std::vector<int> calculatedEarlyBreaks;
143 
144  for (auto const& earlyBreakResults : diagnostics->getEarlyBreaks()) {
145  calculatedEarlyBreaks.push_back(earlyBreakResults);
146  }
147  EXPECT_EQUAL(expectedEarlyBreaks, calculatedEarlyBreaks);
148 }
149 
150 void testRejectedObservations(const eckit::LocalConfiguration &conf) {
151  std::vector<size_t> rejectedObsIndices;
152  if (setupRunFilter(conf, &rejectedObsIndices))
153  return;
154 
155  const std::vector<size_t> expectedRejectedObsIndices =
156  conf.getUnsignedVector("expected rejected obs indices");
157  EXPECT_EQUAL(rejectedObsIndices, expectedRejectedObsIndices);
158 }
159 
160 class TrackCheckShip : public oops::Test {
161  private:
162  std::string testid() const override {return "ufo::test::TrackCheckShip";}
163 
164  void register_tests() const override {
165  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
166 
167  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
168  for (const std::string & testCaseName : conf.keys())
169  {
170  const eckit::LocalConfiguration testCaseConf(::test::TestEnvironment::config(), testCaseName);
171  ts.emplace_back(CASE("ufo/TrackCheckShip/" + testCaseName, testCaseConf)
172  {
174  testEarlyBreakCondition(testCaseConf);
175  testRejectedObservations(testCaseConf);
176  });
177  }
178  }
179 
180  void clear() const override {}
181 };
182 
183 } // namespace test
184 } // namespace ufo
185 
186 #endif // TEST_UFO_TRACKCHECKSHIP_H_
void preProcess() override
Checks tracks of ships and buoys, rejecting observations whose locations and timestamps make them inc...
const TrackCheckShipDiagnostics * diagnostics() const
Options controlling the operation of the ship track check filter.
std::string testid() const override
void register_tests() const override
constexpr int track
Definition: QCflags.h:31
const boost::optional< ufo::TrackCheckShipDiagnostics > setupRunFilter(const eckit::LocalConfiguration &conf, std::vector< size_t > *rejectedObsIndices=nullptr)
void testEarlyBreakCondition(const eckit::LocalConfiguration &conf)
void testRejectedObservations(const eckit::LocalConfiguration &conf)
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
void testTrackCheckShipInitialCalculations(const eckit::LocalConfiguration &conf)
Definition: RunCRTM.h:27