8 #ifndef TEST_UFO_DATAEXTRACTOR_H_
9 #define TEST_UFO_DATAEXTRACTOR_H_
19 #include "eckit/testing/Test.h"
20 #include "oops/runs/Test.h"
21 #include "oops/util/Expect.h"
22 #include "oops/util/FloatCompare.h"
30 template <
typename T,
typename R>
31 float run_basic(
const T obVal0,
const R obVal1,
const std::vector<T> &varValues0,
32 const std::vector<R> &varValues1) {
33 const int dimIndex0 = 0;
34 const int dimIndex1 = 1;
35 const std::string &varName0 =
"var0";
36 const std::string &varName1 =
"var1";
37 const std::array<ConstrainedRange, 3> ranges {
41 assert(varValues0.size() == 5);
42 assert(varValues1.size() == 3);
44 boost::multi_array<float, 3> interpolatedArray(boost::extents[5][3][1]);
45 std::vector<float> tmp = {1, 2, 3, 4, 5,
49 for (
int j=0; j < interpolatedArray.shape()[1]; j++) {
50 for (
int i=0; i < interpolatedArray.shape()[0]; i++) {
51 interpolatedArray[i][j][0] = tmp[ind];
55 auto array =
get2DSlice(interpolatedArray, dimIndex0, dimIndex1, ranges);
57 varName1, varValues1, obVal1, ranges[dimIndex1],
63 template <
typename T,
typename R>
65 const std::vector<T> varValues0 {2, 4, 6, 8, 10};
66 const std::vector<R> varValues1 {2, 4, 6};
67 return run_basic(obVal0, obVal1, varValues0, varValues1);
71 CASE(
"ufo/DataExtractor/bilinearinterp/float_linear") {
74 EXPECT(oops::is_close_absolute(res, 7.5f, 1e-5f, 0,
75 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
79 CASE(
"ufo/DataExtractor/bilinearinterp/float_linear_at_lower_boundary_dim0") {
82 EXPECT(oops::is_close_absolute(res, 6.0f, 1e-5f, 0,
83 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
87 CASE(
"ufo/DataExtractor/bilinearinterp/float_linear_at_lower_boundary_dim1") {
90 EXPECT(oops::is_close_absolute(res, 2.0f, 1e-5f, 0,
91 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
95 CASE(
"ufo/DataExtractor/bilinearinterp/float_blinear") {
98 EXPECT(oops::is_close_absolute(res, 7.6f, 1e-5f, 0,
99 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
103 CASE(
"ufo/DataExtractor/bilinearinterp/extrapolation_lower_bound_dim0") {
110 CASE(
"ufo/DataExtractor/bilinearinterp/extrapolation_lower_bound_dim1") {
117 CASE(
"ufo/DataExtractor/bilinearinterp/extrapolation_upper_bound_dim0") {
124 CASE(
"ufo/DataExtractor/bilinearinterp/extrapolation_upper_bound_dim1") {
131 CASE(
"ufo/DataExtractor/bilinearinterp/int_int_dtype") {
133 EXPECT(oops::is_close_absolute(res, 4.0f, 1e-5f, 0,
134 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
138 CASE(
"ufo/DataExtractor/bilinearinterp/int_float_dtype") {
140 EXPECT(oops::is_close_absolute(res, 4.0f, 1e-5f, 0,
141 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
145 CASE(
"ufo/DataExtractor/bilinearinterp/float_int_dtype") {
147 EXPECT(oops::is_close_absolute(res, 4.0f, 1e-5f, 0,
148 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
152 CASE(
"ufo/DataExtractor/bilinearinterp/string_dtype") {
153 const std::vector<std::string> strVarValues0 {
"2",
"4",
"6",
"8",
"10"};
154 const std::vector<std::string> strVarValues1 {
"2",
"4",
"6"};
155 const std::vector<float> floatVarValues0 {2, 4, 6, 8, 10};
156 const std::vector<float> floatVarValues1 {2, 4, 6};
157 const std::string msg =
"Bilinear interpolation cannot be performed along coordinate axes "
158 "indexed by string variables such as ";
159 EXPECT_THROWS_MSG(
run_basic(4.2f, std::string(
"4.2"), floatVarValues0, strVarValues1),
160 (msg +
"var1.").c_str());
161 EXPECT_THROWS_MSG(
run_basic(std::string(
"4.2"), 4.2f, strVarValues0, floatVarValues1),
162 (msg +
"var0.").c_str());
163 EXPECT_THROWS_MSG(
run_basic(std::string(
"4.2"), std::string(
"4.2"),
164 strVarValues0, strVarValues1),
165 (msg +
"var0 or var1.").c_str());
169 float run_missing(
const float obVal0,
const float obVal1,
const std::vector<float> data) {
170 const std::vector<float> varValues0 {2, 4, 6, 8, 10};
171 const std::vector<float> varValues1 {2, 4, 6};
172 const std::array<ConstrainedRange, 3> ranges {
177 boost::multi_array<float, 3> interpolatedArray(boost::extents[5][3][1]);
179 for (
int j=0; j < interpolatedArray.shape()[1]; j++) {
180 for (
int i=0; i < interpolatedArray.shape()[0]; i++) {
181 interpolatedArray[i][j][0] = data[ind];
185 auto array =
get2DSlice(interpolatedArray, 0, 1, ranges);
187 "var1", varValues1, obVal1, ranges[1],
192 CASE(
"ufo/DataExtractor/bilinearinterp/one_missing") {
194 const std::vector<float> data = {
missing, 2, 3, 4, 5,
199 EXPECT(oops::is_close_absolute(res, 2.0f, 1e-5f, 0,
200 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
204 EXPECT(oops::is_close_absolute(res, 6.0f, 1e-5f, 0,
205 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
209 EXPECT(oops::is_close_absolute(res, 2.0f, 1e-5f, 0,
210 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
214 CASE(
"ufo/DataExtractor/bilinearinterp/all_missing") {
225 const std::array<ConstrainedRange, 3> &ranges) {
228 const std::vector<float> varValues0 {2, 4, 2, 4, 6};
229 const std::vector<float> varValues1 {3, 2, 4};
231 const std::vector<float> data = {1, 6, 11,
236 boost::multi_array<float, 3> interpolatedArray(boost::extents[3][5][1]);
238 for (
int j=0; j < interpolatedArray.shape()[1]; j++) {
239 for (
int i=0; i < interpolatedArray.shape()[0]; i++) {
240 interpolatedArray[i][j][0] = data[ind];
244 auto array =
get2DSlice(interpolatedArray, 1, 0, ranges);
246 "var0", varValues0, obVal0, ranges[1],
251 CASE(
"ufo/DataExtractor/bilinearinterp/range_constrain") {
253 const float obVal0 = 3.0, obVal1 = 3.0;
260 const std::array<ConstrainedRange, 3> ranges {con1, con0, con2};
263 EXPECT(oops::is_close_absolute(res, 11.0f, 1e-5f, 0,
264 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
268 CASE(
"ufo/DataExtractor/bilinearinterp/range_constrain_extrapolation") {
271 const float obVal0 = 5.0, obVal1 = 3.0;
278 const std::array<ConstrainedRange, 3> ranges {con1, con0, con2};
285 CASE(
"ufo/DataExtractor/bilinearinterp/range_constrain_3D_array") {
287 const std::vector<float> varValues0 {2, 4, 6, 8, 10};
288 const std::vector<float> varValues1 {2, 4, 6};
289 const int dimIndex0 = 0;
290 const int dimIndex1 = 2;
291 const std::string &varName0 =
"var0";
292 const std::string &varName1 =
"var1";
293 std::array<ConstrainedRange, 3> ranges {
299 boost::multi_array<float, 3> interpolatedArray(boost::extents[5][6][3]);
300 const std::vector<float> tmp = {1, 2, 3, 4, 5,
304 for (
int j=0; j < interpolatedArray.shape()[2]; j++) {
305 for (
int i=0; i < interpolatedArray.shape()[0]; i++) {
306 interpolatedArray[i][2][j] = tmp[ind];
310 auto array =
get2DSlice(interpolatedArray, dimIndex0, dimIndex1, ranges);
312 varName1, varValues1, 4.2f, ranges[dimIndex1],
314 EXPECT(oops::is_close_absolute(res, 7.6f, 1e-5f, 0,
315 oops::TestVerbosity::LOG_SUCCESS_AND_FAILURE));
319 CASE(
"ufo/DataExtractor/get2DSlice/not_2d_slice") {
324 boost::multi_array<float, 3> interpolatedArray(boost::extents[2][2][2]);
326 const std::string msg =
"Unable to fetch a 2D array slice with the provided constraints.";
327 EXPECT_THROWS_MSG(
get2DSlice(interpolatedArray, 0, 1, ranges), msg.c_str());
331 CASE(
"ufo/DataExtractor/get1DSlice/not_1d_slice") {
336 boost::multi_array<float, 3> interpolatedArray(boost::extents[2][2][2]);
338 const std::string msg =
"Unable to fetch a 1D array slice with the provided constraints.";
339 EXPECT_THROWS_MSG(
get1DSlice(interpolatedArray, 0, ranges), msg.c_str());
348 std::string
testid()
const override {
return "ufo::test::DataExtractor";}
void constrain(int newBegin, int newEnd)
Constrain the range.
float run_range_constrained(const float obVal0, const float obVal1, const std::array< ConstrainedRange, 3 > &ranges)
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
float run_missing(const float obVal0, const float obVal1, const std::vector< float > data)
float run_basic(const T obVal0, const R obVal1, const std::vector< T > &varValues0, const std::vector< R > &varValues1)
float bilinearInterpolation(const std::string &varName0, const std::vector< T > &varValues0, const T &obVal0, const ConstrainedRange &range0, const std::string &varName1, const std::vector< R > &varValues1, const R &obVal1, const ConstrainedRange &range1, const DataExtractorPayload< float >::const_array_view< 2 >::type &interpolatedArray)
Perform bilinear interpolation at 'location' at location obVal0 and obVal1, corresponding to the firs...
const DataExtractorPayload< T >::template const_array_view< 2 >::type get2DSlice(const DataExtractorPayload< T > &array, const size_t dimIndex0, const size_t dimIndex1, const std::array< ConstrainedRange, 3 > &ranges)
Fetch a 2D sliced view of a boost multi_array object.
const DataExtractorPayload< T >::template const_array_view< 1 >::type get1DSlice(const DataExtractorPayload< T > &array, const size_t dimIndex, const std::array< ConstrainedRange, 3 > &ranges)
Fetch a 1D sliced view of a boost multi_array object.