diff --git a/src/metkit/codes/GRIBDecoder.cc b/src/metkit/codes/GRIBDecoder.cc index e66ddb9f..9a4f6a58 100644 --- a/src/metkit/codes/GRIBDecoder.cc +++ b/src/metkit/codes/GRIBDecoder.cc @@ -37,6 +37,13 @@ bool GRIBDecoder::match(const eckit::message::Message& msg) const { (p[0] == 'B' and p[1] == 'U' and p[2] == 'D' and p[3] == 'G')); } +namespace { +bool isInteger(double val) { + double intpart; + return std::modf(val, &intpart) == 0.0; +} +} // namespace + void GRIBDecoder::getMetadata(const eckit::message::Message& msg, eckit::message::MetadataGatherer& gather, const eckit::message::GetMetadataOptions& options) const { @@ -59,14 +66,36 @@ void GRIBDecoder::getMetadata(const eckit::message::Message& msg, eckit::message switch (options.valueRepresentation) { case eckit::message::ValueRepresentation::String: { - gather.setValue(name, k.getString()); + // TODO - remove as soon as https://jira.ecmwf.int/browse/ECC-2113 is fixed + if (k.name() == "levelist") { + double val = k.getDouble(); + if (isInteger(val)) { + gather.setValue(name, eckit::translate(static_cast(val))); + } + else { + gather.setValue(name, eckit::translate(val)); + } + } + else { + gather.setValue(name, k.getString()); + } break; } case eckit::message::ValueRepresentation::Native: { std::visit( [&](auto&& v) { using Type = std::decay_t; - if constexpr (std::is_same_v || std::is_arithmetic_v) { + // TODO - remove as soon as https://jira.ecmwf.int/browse/ECC-2113 is fixed + if (k.name() == "levelist") { + double val = k.getDouble(); + if (isInteger(val)) { + gather.setValue(name, static_cast(val)); + } + else { + gather.setValue(name, val); + } + } + else if constexpr (std::is_same_v || std::is_arithmetic_v) { gather.setValue(name, std::forward(v)); } else if constexpr (std::is_same_v>) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 20e5a00b..719a4663 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,9 @@ ecbuild_get_test_multidata( TARGET metkit_get_odb_data multiodb2.odb NOCHECK ) +configure_file(pl.grib pl.grib COPYONLY) +configure_file(sol.grib sol.grib COPYONLY) + add_custom_target(soft_link_expand_test_data ALL COMMAND ${CMAKE_COMMAND} -E create_symlink "${CMAKE_CURRENT_SOURCE_DIR}/expand" "${CMAKE_CURRENT_BINARY_DIR}/expand") diff --git a/tests/pl.grib b/tests/pl.grib new file mode 100644 index 00000000..1523bf95 Binary files /dev/null and b/tests/pl.grib differ diff --git a/tests/sol.grib b/tests/sol.grib new file mode 100644 index 00000000..3a1a2424 Binary files /dev/null and b/tests/sol.grib differ diff --git a/tests/test_codes_decoder.cc b/tests/test_codes_decoder.cc index 34c209e4..304ec960 100644 --- a/tests/test_codes_decoder.cc +++ b/tests/test_codes_decoder.cc @@ -16,6 +16,7 @@ #include #include "eckit/config/LocalConfiguration.h" +#include "eckit/io/FileHandle.h" #include "eckit/io/MemoryHandle.h" #include "eckit/message/Message.h" #include "eckit/message/Reader.h" @@ -454,6 +455,93 @@ CASE("test codessplitter unstr_latlot.tmpl String") { } } +CASE("test levelist String") { + eckit::FileHandle f("pl.grib"); + + eckit::message::Reader reader(f); + eckit::message::Message msg; + + std::vector expect{"0", "0.02", "0.2", "2", "20", "200"}; + for (size_t i = 0; i < expect.size(); ++i) { + msg = reader.next(); + EXPECT(msg); + + MetadataSetter md; + eckit::message::TypedSetter gatherer{md}; + eckit::message::GetMetadataOptions mdOpts{}; + mdOpts.valueRepresentation = eckit::message::ValueRepresentation::String; + msg.getMetadata(gatherer, mdOpts); + { MD_EXPECT_STRING(md, "levelist", expect[i]); } + } + msg = reader.next(); + EXPECT(!msg); +} + +CASE("test levelist Native") { + eckit::FileHandle f("pl.grib"); + + eckit::message::Reader reader(f); + eckit::message::Message msg; + + std::vector expect{0, 0.02, 0.2, 2, 20, 200}; + for (size_t i = 0; i < expect.size(); ++i) { + msg = reader.next(); + EXPECT(msg); + + MetadataSetter md; + eckit::message::TypedSetter gatherer{md}; + eckit::message::GetMetadataOptions mdOpts{}; + mdOpts.valueRepresentation = eckit::message::ValueRepresentation::Native; + msg.getMetadata(gatherer, mdOpts); + { MD_EXPECT_DOUBLE(md, "levelist", expect[i]); } + } + msg = reader.next(); + EXPECT(!msg); +} + +CASE("test levelist String") { + eckit::FileHandle f("sol.grib"); + + eckit::message::Reader reader(f); + eckit::message::Message msg; + + std::vector expect{"0.02", "0.2", "2", "20"}; + for (size_t i = 0; i < expect.size(); ++i) { + msg = reader.next(); + EXPECT(msg); + + MetadataSetter md; + eckit::message::TypedSetter gatherer{md}; + eckit::message::GetMetadataOptions mdOpts{}; + mdOpts.valueRepresentation = eckit::message::ValueRepresentation::String; + msg.getMetadata(gatherer, mdOpts); + { MD_EXPECT_STRING(md, "levelist", expect[i]); } + } + msg = reader.next(); + EXPECT(!msg); +} + +CASE("test levelist Native") { + eckit::FileHandle f("sol.grib"); + + eckit::message::Reader reader(f); + eckit::message::Message msg; + + std::vector expect{0.02, 0.2, 2, 20}; + for (size_t i = 0; i < expect.size(); ++i) { + msg = reader.next(); + EXPECT(msg); + + MetadataSetter md; + eckit::message::TypedSetter gatherer{md}; + eckit::message::GetMetadataOptions mdOpts{}; + mdOpts.valueRepresentation = eckit::message::ValueRepresentation::Native; + msg.getMetadata(gatherer, mdOpts); + { MD_EXPECT_DOUBLE(md, "levelist", expect[i]); } + } + msg = reader.next(); + EXPECT(!msg); +} //----------------------------------------------------------------------------------------------------------------------