UFO
test/ufo/Locations.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 UK Met Office
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_LOCATIONS_H_
9 #define TEST_UFO_LOCATIONS_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 "oops/mpi/mpi.h"
21 #include "oops/runs/Test.h"
22 #include "oops/util/DateTime.h"
23 #include "oops/util/FloatCompare.h"
24 #include "oops/util/Logger.h"
25 #include "oops/util/parameters/Parameters.h"
26 #include "oops/util/parameters/RequiredParameter.h"
27 #include "test/TestEnvironment.h"
28 #include "ufo/Locations.h"
29 
30 namespace ufo {
31 namespace test {
32 
33 /// Parameters describing Locations/TimeMask test
34 class LocationsTimeTestParameters : public oops::Parameters {
35  OOPS_CONCRETE_PARAMETERS(LocationsTimeTestParameters, Parameters)
36  public:
37  /// t1 & t2 for subsetting locations
38  oops::RequiredParameter<util::DateTime> t1{"t1", this};
39  oops::RequiredParameter<util::DateTime> t2{"t2", this};
40  /// reference mask
41  oops::RequiredParameter<std::vector<bool>> refTimeMask{"reference mask", this};
42 };
43 
44 /// Parameters describing Locations test
45 class LocationsTestParameters : public oops::Parameters {
46  OOPS_CONCRETE_PARAMETERS(LocationsTestParameters, Parameters)
47  public:
48  /// reference longitudes
49  oops::RequiredParameter<std::vector<float>> refLons{"reference lons", this};
50  /// reference latitudes
51  oops::RequiredParameter<std::vector<float>> refLats{"reference lats", this};
52  /// set of tests for time masks
53  oops::RequiredParameter<std::vector<LocationsTimeTestParameters>>
54  timeMaskTests{"time mask tests", this};
55 };
56 
57 /// Code shared by all Locations tests
58 class LocationsTestFixture : private boost::noncopyable {
59  public:
60  static const ioda::ObsSpace & obsspace() {return *getInstance().obsspace_;}
61  static const eckit::LocalConfiguration & testconfig() {return getInstance().testconfig_;}
63 
64  private:
66  static LocationsTestFixture theLocationsTestFixture;
67  return theLocationsTestFixture;
68  }
69 
71  const eckit::Configuration & conf = ::test::TestEnvironment::config();
72  util::DateTime bgn(conf.getString("window begin"));
73  util::DateTime end(conf.getString("window end"));
74  const eckit::LocalConfiguration obsconf(conf, "obs space");
75  ioda::ObsTopLevelParameters obsparams;
76  obsparams.validateAndDeserialize(obsconf);
77  obsspace_.reset(new ioda::ObsSpace(obsparams, oops::mpi::world(), bgn, end,
78  oops::mpi::myself()));
79  testconfig_ = conf.getSubConfiguration("locations test");
80  testparams_.validateAndDeserialize(testconfig_);
81  }
82 
83  std::shared_ptr<ioda::ObsSpace> obsspace_;
84  eckit::LocalConfiguration testconfig_;
86 };
87 
88 // -----------------------------------------------------------------------------
89 /// Tests Locations constructors and method size()
90 void testLocations() {
91  typedef LocationsTestFixture Test_;
92 
93  const size_t nlocs = Test_::obsspace().nlocs();
94 
95  // testConstructor:: Locations(const eckit::Configuration &)
96  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
97  Locations locs1(conf, oops::mpi::world());
98  EXPECT(locs1.size() == nlocs);
99  oops::Log::test() << "Locations(configuration, eckit mpi communicator): " << locs1 << std::endl;
100 
101  // testConstructor::Locations(const ioda::ObsSpace &);
102 /* Locations locs2(Test_::obsspace());
103  EXPECT(locs2.size() == nlocs);
104  oops::Log::test() << "Locations(obsspace) constructor: " << locs2 << std::endl;*/
105 }
106 
107 // -----------------------------------------------------------------------------
108 /// Tests Locations accessors lons() and lats()
109 void testLonsLats() {
110  typedef LocationsTestFixture Test_;
111 
112  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
113  Locations locs(conf, oops::mpi::world());
114 
115  const LocationsTestParameters & params = Test_::testparams();
116  const float abstol = 1.0e-8;
117  EXPECT(oops::are_all_close_absolute(params.refLons.value(), locs.lons(), abstol));
118  EXPECT(oops::are_all_close_absolute(params.refLats.value(), locs.lats(), abstol));
119 }
120 
121 // -----------------------------------------------------------------------------
122 extern "C" {
123  /// similar to LonsLats test, on Fortran level
124  /// Returns 1 if the test passes, 0 if the test fails
125  int test_locations_lonslats_f90(const Locations &, const eckit::Configuration &);
126 }
127 
128 /// Tests Locations accessors lons() and lats() from Fortran
130  typedef LocationsTestFixture Test_;
131 
132  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
133  Locations locs(conf, oops::mpi::world());
134 
135  EXPECT(test_locations_lonslats_f90(locs, Test_::testconfig()));
136 }
137 
138 // -----------------------------------------------------------------------------
139 /// Tests Locations::isInTimeWindow method
140 void testTimeMask() {
141  typedef LocationsTestFixture Test_;
142 
143  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
144  Locations locs(conf, oops::mpi::world());
145 
146  const LocationsTestParameters & params = Test_::testparams();
147  for (const auto & test : params.timeMaskTests.value()) {
148  EXPECT_EQUAL(test.refTimeMask.value(), locs.isInTimeWindow(test.t1, test.t2));
149  }
150 }
151 
152 // -----------------------------------------------------------------------------
153 extern "C" {
154  /// similar to TimeMask test, on Fortran level
155  /// Returns 1 if the test passes, 0 if the test fails
156  int test_locations_timemask_f90(const Locations &, const eckit::Configuration &);
157 }
158 
159 /// Tests Locations::isInTimeWindow method from Fortran
161  typedef LocationsTestFixture Test_;
162 
163  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
164  Locations locs(conf, oops::mpi::world());
165 
166  EXPECT(test_locations_timemask_f90(locs, Test_::testconfig()));
167 }
168 
169 // -----------------------------------------------------------------------------
170 /// Tests operator+= (concatenation of two Locations)
172  typedef LocationsTestFixture Test_;
173 
174  const eckit::LocalConfiguration conf(::test::TestEnvironment::config());
175  Locations locs1(conf, oops::mpi::world());
176  Locations locs2(conf, oops::mpi::world());
177  const size_t nlocs = locs1.size();
178 
179  locs1 += locs2;
180 
181  EXPECT_EQUAL(locs1.size(), 2*nlocs);
182 
183  const float abstol = 1.0e-8;
184 
185  /// test that concatenated longitudes have two copies of original lons
186  const std::vector<float> & lons = locs1.lons();
187  std::vector<float> lons1(lons.begin(), lons.begin() + nlocs);
188  std::vector<float> lons2(lons.begin() + nlocs, lons.end());
189  EXPECT(oops::are_all_close_absolute(lons1, lons2, abstol));
190  EXPECT(oops::are_all_close_absolute(lons1, locs2.lons(), abstol));
191 
192  /// test that concatenated latitudes have two copies of original lats
193  const std::vector<float> & lats = locs1.lats();
194  std::vector<float> lats1(lats.begin(), lats.begin() + nlocs);
195  std::vector<float> lats2(lats.begin() + nlocs, lats.end());
196  EXPECT(oops::are_all_close_absolute(lats1, lats2, abstol));
197  EXPECT(oops::are_all_close_absolute(lats1, locs2.lats(), abstol));
198 }
199 
200 // -----------------------------------------------------------------------------
201 
202 class Locations : public oops::Test {
203  public:
205  virtual ~Locations() = default;
206 
207  private:
208  std::string testid() const override {return "ufo::test::Locations";}
209 
210  void register_tests() const override {
211  std::vector<eckit::testing::Test>& ts = eckit::testing::specification();
212 
213  ts.emplace_back(CASE("ufo/Locations/testLocations")
214  { testLocations(); });
215  ts.emplace_back(CASE("ufo/Locations/testLonsLats")
216  { testLonsLats(); });
217  ts.emplace_back(CASE("ufo/Locations/testFortranLonsLats")
218  { testFortranLonsLats(); });
219  ts.emplace_back(CASE("ufo/Locations/testTimeMask")
220  { testTimeMask(); });
221  ts.emplace_back(CASE("ufo/Locations/testFortranTimeMask")
222  { testFortranTimeMask(); });
223  ts.emplace_back(CASE("ufo/Locations/testConcatenation")
224  { testConcatenate(); });
225  }
226 
227  void clear() const override {}
228 };
229 
230 // -----------------------------------------------------------------------------
231 
232 } // namespace test
233 } // namespace ufo
234 
235 #endif // TEST_UFO_LOCATIONS_H_
void register_tests() const override
virtual ~Locations()=default
std::string testid() const override
void clear() const override
Code shared by all Locations tests.
static const LocationsTestParameters & testparams()
static const ioda::ObsSpace & obsspace()
static const eckit::LocalConfiguration & testconfig()
LocationsTestParameters testparams_
eckit::LocalConfiguration testconfig_
static LocationsTestFixture & getInstance()
std::shared_ptr< ioda::ObsSpace > obsspace_
Parameters describing Locations test.
oops::RequiredParameter< std::vector< float > > refLats
reference latitudes
oops::RequiredParameter< std::vector< LocationsTimeTestParameters > > timeMaskTests
set of tests for time masks
oops::RequiredParameter< std::vector< float > > refLons
reference longitudes
Parameters describing Locations/TimeMask test.
oops::RequiredParameter< util::DateTime > t1
t1 & t2 for subsetting locations
oops::RequiredParameter< std::vector< bool > > refTimeMask
reference mask
oops::RequiredParameter< util::DateTime > t2
void testLonsLats()
Tests Locations accessors lons() and lats()
void testFortranLonsLats()
Tests Locations accessors lons() and lats() from Fortran.
int test_locations_timemask_f90(const Locations &, const eckit::Configuration &)
void testLocations()
Tests Locations constructors and method size()
void testTimeMask()
Tests Locations::isInTimeWindow method.
void testConcatenate()
Tests operator+= (concatenation of two Locations)
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
int test_locations_lonslats_f90(const Locations &, const eckit::Configuration &)
void testFortranTimeMask()
Tests Locations::isInTimeWindow method from Fortran.
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27