From 02a260527a0a7455f352101143e8baf2a8fd640f Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Wed, 9 Aug 2023 17:00:57 +0200 Subject: [PATCH 01/17] METK-112 extended time parsing --- src/metkit/mars/TypeTime.cc | 119 +++++++++++++++++++++++------------- src/metkit/mars/TypeTime.h | 2 + 2 files changed, 78 insertions(+), 43 deletions(-) diff --git a/src/metkit/mars/TypeTime.cc b/src/metkit/mars/TypeTime.cc index fde322e0..071541e8 100644 --- a/src/metkit/mars/TypeTime.cc +++ b/src/metkit/mars/TypeTime.cc @@ -9,15 +9,15 @@ */ #include +#include #include "eckit/utils/Translator.h" - #include "eckit/types/Date.h" -#include "metkit/mars/MarsRequest.h" +#include "eckit/utils/StringTools.h" +#include "metkit/mars/MarsRequest.h" #include "metkit/mars/TypesFactory.h" #include "metkit/mars/TypeTime.h" -#include "eckit/utils/StringTools.h" namespace metkit { namespace mars { @@ -31,54 +31,87 @@ TypeTime::TypeTime(const std::string &name, const eckit::Value& settings) : TypeTime::~TypeTime() { } -bool TypeTime::expand(const MarsExpandContext&, std::string &value) const { - - long n = 0; - int colon = 0; - - for (std::string::const_iterator j = value.begin(); j != value.end(); ++j) { - switch (*j) { - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - n *= 10; - n += (*j) - '0'; - break; - - case ':': - colon++; - break; - - default: - // throw eckit::UserError(name_ + ": invalid time '" + value + "'"); - return false; +long TypeTime::seconds(std::string& value) { + long seconds=0; + long minutes = 0; + long hours = 0; + long days = 0; + std::smatch m; + if (std::regex_match (value, m, std::regex("^[0-9]+$"))) { // only digits + long time = std::stol(value); + if (time < 100) { // cases: h, hh + hours = time; + } else { + if (time < 10000) { // cases: hmm, hhmm + hours = time/100; + minutes = time%100; + } else { // cases: hmmss, hhmmss + hours = time/10000; + minutes = (time/100)%100; + seconds = time%100; + } } - } - - if (colon == 2 || (value.size() > 4 && colon == 0)) { - if (n % 100 != 0) { + if (minutes > 59 || seconds > 59) { std::ostringstream ss; - ss << "Cannot normalise time '" << value << "' - seconds not supported"; + ss << "Invalid time '" << value << "' ==> '" << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << "'" << std::endl; throw eckit::SeriousBug(ss.str(), Here()); } - n /= 100; + seconds += 60*(60*hours + minutes); } - - if (n < 100 && value.size() < 3) { - n *= 100; + else { + if (std::regex_match (value, m, std::regex("^([0-9]+):([0-5]?[0-9])(:[0-5]?[0-9])?$"))) { + int count=0; + for (int i=1; i " << d << "d" << std::setfill('0') << std::setw(2) << h << "h" << std::setfill('0') << std::setw(2) << m << "m" << std::setfill('0') << std::setw(2) << s << "s" << std::endl; + std::ostringstream oss; - oss << std::setfill('0') << std::setw(4) << n; - value = oss.str(); + oss << d << std::setfill('0') << std::setw(2) << h << std::setfill('0') << std::setw(2) << m << std::setfill('0') << std::setw(2) << s; return true; } diff --git a/src/metkit/mars/TypeTime.h b/src/metkit/mars/TypeTime.h index 14c619b2..f5707b08 100644 --- a/src/metkit/mars/TypeTime.h +++ b/src/metkit/mars/TypeTime.h @@ -38,6 +38,8 @@ class TypeTime : public Type { virtual void expand(const MarsExpandContext& ctx, std::vector& values) const override; virtual bool expand(const MarsExpandContext& ctx, std::string& value) const override; + static long seconds(std::string& value); + long by_; }; From 4c61f6a97b400dc0992d08ec458f093b4c92ae2c Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Mon, 14 Aug 2023 15:15:43 +0200 Subject: [PATCH 02/17] METK-112 wip - StepRange based on extended eckit::Time parsing --- CMakeLists.txt | 2 +- src/metkit/mars/StepRange.cc | 12 +- src/metkit/mars/TypeRange.cc | 231 +++++++++++++++++++++++++---------- src/metkit/mars/TypeRange.h | 24 ++-- src/metkit/mars/TypeTime.cc | 90 ++------------ src/metkit/mars/TypeTime.h | 3 - tests/test_codes_decoder.cc | 6 +- tests/test_expand.cc | 124 ++++++++++++++++++- tests/test_time.cc | 119 +++++++++++++----- 9 files changed, 412 insertions(+), 199 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db9795af..8b22d469 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ find_package( ecbuild 3.7.2 REQUIRED HINTS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_C project( metkit LANGUAGES CXX ) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) ######################################################################################################################## diff --git a/src/metkit/mars/StepRange.cc b/src/metkit/mars/StepRange.cc index 27cd5377..06615bb4 100644 --- a/src/metkit/mars/StepRange.cc +++ b/src/metkit/mars/StepRange.cc @@ -9,6 +9,7 @@ */ #include "metkit/mars/StepRange.h" +#include "metkit/mars/TypeTime.h" #include "eckit/exception/Exceptions.h" #include "eckit/persist/DumpLoad.h" @@ -47,16 +48,20 @@ StepRange::StepRange(const std::string& s): std::vector result; parse(s,result); + eckit::Second from, to; switch(result.size()) { case 1: - from_ = to_ = atof(result[0].c_str()); + from = eckit::Time(result[0], true); + from_ = to_ = from/3600.f; break; case 2: - from_ = atof(result[0].c_str()); - to_ = atof(result[1].c_str()); + from = eckit::Time(result[0], true); + to = eckit::Time(result[1], true); + from_ = from/3600.f; + to_ = to/3600.f; break; default: @@ -65,7 +70,6 @@ StepRange::StepRange(const std::string& s): throw eckit::BadValue(msg.str(), Here()); break; } - } void StepRange::dump(DumpLoad& a) const diff --git a/src/metkit/mars/TypeRange.cc b/src/metkit/mars/TypeRange.cc index b5680fe4..01b43b39 100644 --- a/src/metkit/mars/TypeRange.cc +++ b/src/metkit/mars/TypeRange.cc @@ -7,24 +7,90 @@ * granted to it by virtue of its status as an intergovernmental organisation nor * does it submit to any jurisdiction. */ +#include -#include "eckit/utils/Translator.h" +#include "metkit/mars/TypeRange.h" -#include "metkit/mars/MarsRequest.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/utils/StringTools.h" +#include "eckit/utils/Tokenizer.h" +#include "metkit/config/LibMetkit.h" +#include "metkit/mars/MarsLanguage.h" +#include "metkit/mars/Quantile.h" #include "metkit/mars/TypesFactory.h" -#include "metkit/mars/TypeRange.h" -#include "eckit/utils/StringTools.h" +#include "metkit/mars/TypeTime.h" + +namespace { + +enum TimeUnit { + Second = 0, + Minute = 1, + Hour = 2, + Day = 3 +}; + +TimeUnit maxUnit(const eckit::Time& t) { + if (t.seconds() == 0) { + if (t.minutes() == 0) { + if (t.hours() == 0) { + return TimeUnit::Day; + } + return TimeUnit::Hour; + } + return TimeUnit::Minute; + } + return TimeUnit::Second; +} + +std::string canonical(const eckit::Time& time) { + long d = time.hours()/24; + long h = time.hours()%24; + long m = time.minutes(); + long s = time.seconds(); + + std::string out = ""; + if (d!=0) { + out += std::to_string(d) + "D"; + } + if (h!=0) { + out += std::to_string(h) + "h"; + } + if (m!=0) { + out += std::to_string(m) + "m"; + } + if (s!=0) { + out = std::to_string(s) + "s"; + } + return out; +} + +std::string canonical(const eckit::Time& time, TimeUnit unit) { + switch (unit) { + case TimeUnit::Second: + return std::to_string(time.seconds()) + "s"; + case TimeUnit::Minute: + return std::to_string(time.minutes()) + "m"; + case TimeUnit::Day: + case TimeUnit::Hour: + default: + return std::to_string(time.hours()); + } +} -namespace metkit { -namespace mars { +} +namespace metkit::mars { //---------------------------------------------------------------------------------------------------------------------- TypeRange::TypeRange(const std::string &name, const eckit::Value& settings) : - TypeToByList(name, settings) { + Type(name, settings), + by_((std::string)settings["by"]) { + + multiple_ = true; } + TypeRange::~TypeRange() { } @@ -32,84 +98,117 @@ void TypeRange::print(std::ostream &out) const { out << "TypeRange[name=" << name_ << "]"; } +bool TypeRange::expand(const MarsExpandContext& ctx, std::string& value) const { + + eckit::Tokenizer parse("-"); + std::vector result; -bool TypeRange::expand(const MarsExpandContext& ctx, std::string &value) const { + parse(value, result); + switch (result.size()) { + case 1: { + eckit::Time start = eckit::Time(result[0], true); + value = canonical(start, maxUnit(start)); + return true; + } + case 2: { + eckit::Time start = eckit::Time(result[0], true); + eckit::Time end = eckit::Time(result[1], true); + if (start > end) { + std::ostringstream oss; + oss << name_ + ": initial value " << start << " cannot be greater that final value " << end; + throw eckit::BadValue(oss.str()); + } - long p = 0; - if (ok(value, p)) { - static eckit::Translator l2s; - value = l2s(p); - return true; + TimeUnit unit = std::max(maxUnit(start), maxUnit(end)); + value = canonical(start, unit) + "-" + canonical(end, unit); + return true; + } + default: + std::ostringstream oss; + oss << name_ + ": invalid value " << value << " " << result.size(); + throw eckit::BadValue(oss.str()); } + return false; +} - long a = 0; - long b = 0; +void TypeRange::expand(const MarsExpandContext& ctx, std::vector& values) const { - long *n = &a; + std::vector newval; - for (std::string::const_iterator j = value.begin(); j != value.end(); ++j) { - switch (*j) { - case '-': - if (j != value.begin()) { - if (n == &b) { - return false; - // throw eckit::UserError(name_ + ": invalid integer range '" + value + "' (a)"); + for (size_t i = 0; i < values.size(); ++i) { - } - n = &b; + const std::string& s = values[i]; + + if (eckit::StringTools::lower(s) == "to" || eckit::StringTools::lower(s) == "t0") { + std::vector tmpval; + TimeUnit unit; + + if (newval.size() == 0) { + std::ostringstream oss; + oss << name_ << " list: 'to' must be preceeded by a starting value."; + throw eckit::BadValue(oss.str()); } - else { - return false; - // throw eckit::UserError(name_ + ": invalid integer range '" + value + "' (b)"); + if (values.size() <= i+1) { + std::ostringstream oss; + oss << name_ << " list: 'to' must be followed by an ending value."; + throw eckit::BadValue(oss.str()); } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - (*n) *= 10; - (*n) += (*j) - '0'; - break; + eckit::Time from = eckit::Time(values[i - 1], true); + tmpval.push_back(from); + unit = maxUnit(from); - default: - { - std::string lower = eckit::StringTools::lower(value); - if (lower == "to" || lower == "t0" || lower == "by") { - return true; + eckit::Time to = eckit::Time(values[i + 1], true); + eckit::Time by = by_; + + if (i+2 < values.size() && eckit::StringTools::lower(values[i + 2]) == "by") { + if (values.size() <= i+3) { + std::ostringstream oss; + oss << name_ << " list: 'by' must be followed by a step size."; + throw eckit::BadValue(oss.str()); + } + + by = eckit::Time(values[i + 3], true); + + i += 2; } - } - return false; - // throw eckit::UserError(name_ + ": invalid integer range '" + value + "' (c)"); - break; - } - } +// std::cout << from << " " << to << " " << by << std::endl; - if (n == &a) { - std::ostringstream oss; - oss << a; + if (from > to) { + std::ostringstream oss; + oss << name_ + ": 'from' value " << from << " cannot be greater that 'to' value " << to; + throw eckit::BadValue(oss.str()); + } + if (by <= eckit::Time(0)) { + std::ostringstream oss; + oss << name_ + ": 'by' value " << by << " must be a positive number"; + throw eckit::BadValue(name_ + ": 'by' value must be a positive number"); + } + for (long j = from + by; j <= to; j += by) { + unit = std::min(unit, maxUnit(j)); + } + for (long j = from + by; j <= to; j += by) { + if (unit >= TimeUnit::Hour) { + newval.emplace_back(canonical(j, unit)); + } else { + newval.emplace_back(canonical(j)); + } + } - value = oss.str(); - return true; + i++; + } + else { + newval.push_back(tidy(ctx,s)); + } } - std::ostringstream oss; - oss << a << "-" << b; + std::swap(values, newval); - value = oss.str(); - return true; + Type::expand(ctx, values); } - static TypeBuilder type("range"); //---------------------------------------------------------------------------------------------------------------------- -} // namespace mars -} // namespace metkit + +} // namespace metkit::mars diff --git a/src/metkit/mars/TypeRange.h b/src/metkit/mars/TypeRange.h index b92cd80a..7eef8a0e 100644 --- a/src/metkit/mars/TypeRange.h +++ b/src/metkit/mars/TypeRange.h @@ -8,22 +8,20 @@ * does it submit to any jurisdiction. */ -/// @file TypeRange.h -/// @author Baudouin Raoult -/// @author Tiago Quintino -/// @date April 2016 +/// @file TypeToByListQuantile.h +/// @author Emanuele Danovaro +/// @date February 2022 -#ifndef metkit_TypeRange_H -#define metkit_TypeRange_H +#pragma once -#include "metkit/mars/TypeToByList.h" +#include "metkit/mars/Type.h" namespace metkit { namespace mars { //---------------------------------------------------------------------------------------------------------------------- -class TypeRange : public TypeToByList { +class TypeRange : public Type { public: // methods @@ -34,13 +32,15 @@ class TypeRange : public TypeToByList { private: // methods virtual void print( std::ostream &out ) const override; - virtual bool expand(const MarsExpandContext& ctx, - std::string& value) const override; + virtual bool expand(const MarsExpandContext& ctx, std::string& value) const override; + virtual void expand(const MarsExpandContext& ctx, + std::vector& values) const override; + + eckit::Time by_; + }; //---------------------------------------------------------------------------------------------------------------------- } // namespace mars } // namespace metkit - -#endif diff --git a/src/metkit/mars/TypeTime.cc b/src/metkit/mars/TypeTime.cc index 071541e8..8cbfad9d 100644 --- a/src/metkit/mars/TypeTime.cc +++ b/src/metkit/mars/TypeTime.cc @@ -31,87 +31,23 @@ TypeTime::TypeTime(const std::string &name, const eckit::Value& settings) : TypeTime::~TypeTime() { } -long TypeTime::seconds(std::string& value) { - long seconds=0; - long minutes = 0; - long hours = 0; - long days = 0; - std::smatch m; - if (std::regex_match (value, m, std::regex("^[0-9]+$"))) { // only digits - long time = std::stol(value); - if (time < 100) { // cases: h, hh - hours = time; - } else { - if (time < 10000) { // cases: hmm, hhmm - hours = time/100; - minutes = time%100; - } else { // cases: hmmss, hhmmss - hours = time/10000; - minutes = (time/100)%100; - seconds = time%100; - } - } - if (minutes > 59 || seconds > 59) { - std::ostringstream ss; - ss << "Invalid time '" << value << "' ==> '" << hours << ":" << std::setfill('0') << std::setw(2) << minutes << ":" << std::setfill('0') << std::setw(2) << seconds << "'" << std::endl; - throw eckit::SeriousBug(ss.str(), Here()); - } - seconds += 60*(60*hours + minutes); - } - else { - if (std::regex_match (value, m, std::regex("^([0-9]+):([0-5]?[0-9])(:[0-5]?[0-9])?$"))) { - int count=0; - for (int i=1; i " << d << "d" << std::setfill('0') << std::setw(2) << h << "h" << std::setfill('0') << std::setw(2) << m << "m" << std::setfill('0') << std::setw(2) << s << "s" << std::endl; - std::ostringstream oss; - oss << d << std::setfill('0') << std::setw(2) << h << std::setfill('0') << std::setw(2) << m << std::setfill('0') << std::setw(2) << s; + if (time.seconds() != 0) { + oss << "Cannot normalise time '" << value << "' - seconds not supported"; + throw eckit::SeriousBug(oss.str(), Here()); + } + if (time.hours() >= 24) { + oss << "Cannot normalise time '" << value << "' - " << time.hours() << " hours > 24 not supported"; + throw eckit::SeriousBug(oss.str(), Here()); + } + + oss << std::setfill('0') << std::setw(2) << time.hours() << std::setfill('0') << std::setw(2) << time.minutes(); + value = oss.str(); + return true; } diff --git a/src/metkit/mars/TypeTime.h b/src/metkit/mars/TypeTime.h index f5707b08..b949d97a 100644 --- a/src/metkit/mars/TypeTime.h +++ b/src/metkit/mars/TypeTime.h @@ -31,14 +31,11 @@ class TypeTime : public Type { virtual ~TypeTime() override; - private: // methods virtual void print( std::ostream &out ) const override; virtual void expand(const MarsExpandContext& ctx, std::vector& values) const override; virtual bool expand(const MarsExpandContext& ctx, std::string& value) const override; - - static long seconds(std::string& value); long by_; diff --git a/tests/test_codes_decoder.cc b/tests/test_codes_decoder.cc index 26c36eab..7f046c4a 100644 --- a/tests/test_codes_decoder.cc +++ b/tests/test_codes_decoder.cc @@ -211,7 +211,8 @@ CASE("test codessplitter unstr_latlot.tmpl Native") { MD_EXPECT_LONG(md, "forecastTime", 0); MD_EXPECT_LONG(md, "startStep", 0); MD_EXPECT_LONG(md, "endStep", 0); - MD_EXPECT_STRING(md, "stepRange", "0"); +// MD_EXPECT_STRING(md, "stepRange", "0"); + MD_EXPECT_STRING(md, "stepRange", "0h"); MD_EXPECT_LONG(md, "validityDate", 10101); MD_EXPECT_LONG(md, "validityTime", 0); MD_EXPECT_STRING(md, "typeOfFirstFixedSurface", "168"); @@ -395,7 +396,8 @@ CASE("test codessplitter unstr_latlot.tmpl String") { MD_EXPECT_STRING(md, "forecastTime", "0"); MD_EXPECT_STRING(md, "startStep", "0"); MD_EXPECT_STRING(md, "endStep", "0"); - MD_EXPECT_STRING(md, "stepRange", "0"); +// MD_EXPECT_STRING(md, "stepRange", "0"); + MD_EXPECT_STRING(md, "stepRange", "0h"); MD_EXPECT_STRING(md, "validityDate", "10101"); MD_EXPECT_STRING(md, "validityTime", "0"); MD_EXPECT_STRING(md, "typeOfFirstFixedSurface", "168"); diff --git a/tests/test_expand.cc b/tests/test_expand.cc index 7c461a56..c0416bff 100644 --- a/tests/test_expand.cc +++ b/tests/test_expand.cc @@ -67,7 +67,7 @@ CASE( "test_metkit_expand_4" ) { } CASE( "test_metkit_expand_5" ) { - const char* text = "retrieve,class=od,date=20050601,diagnostic=1,expver=1,iteration=0,levelist=1,levtype=ml,param=155.129,step=0,stream=sens,time=1200,type=sg"; + const char* text = "retrieve,class=od,date=20050601,diagnostic=1,expver=1,iteration=0,levelist=1,levtype=ml,param=155.129,stream=sens,time=1200,type=sg"; MarsRequest r = MarsRequest::parse(text); r.dump(std::cout); } @@ -176,6 +176,128 @@ CASE( "test_metkit_expand_11_quantile" ) { quantile({"0:10","3:10","to","7:10","by","2","10:10"}, {"0:10","3:10","5:10","7:10","10:10"}); } + +void timeThrows(std::vector values) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("time"); + std::cout << "timeThrows " << values << std::endl; + EXPECT_THROWS(t->expand(ctx, values)); +} + +void time(std::vector values, std::vector expected) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("time"); + std::cout << "time " << values; + t->expand(ctx, values); + std::cout << " ==> " << values << " - expected " << expected << std::endl; + ASSERT(values == expected); +} + +CASE( "test_metkit_expand_12_time" ) { + timeThrows({"87"}); + timeThrows({"000012"}); + timeThrows({"0:0:12"}); + timeThrows({"12s"}); + time({"0"}, {"0000"}); + time({"0","1","12"}, {"0000","0100","1200"}); + time({"00:30","1:30","02:50"}, {"0030","0130","0250"}); + time({"0h","3h","120m","170m"}, {"0000","0300","0200","0250"}); + + timeThrows({"to","5"}); + timeThrows({"3","to"}); + timeThrows({"3","to","2"}); + timeThrows({"1","to","3","by"}); + + time({"0","to","0"}, {"0000"}); + time({"12","to","12"}, {"1200"}); + time({"0","to","12"}, {"0000", "0600", "1200"}); + time({"0","to","6","by","1"}, {"0000", "0100", "0200", "0300", "0400", "0500", "0600"}); + time({"0","to","6","by","2"}, {"0000", "0200", "0400", "0600"}); + time({"0","to","6","by","3"}, {"0000", "0300", "0600"}); + time({"0","to","6","by","4"}, {"0000", "0400"}); + time({"0","to","6","by","5"}, {"0000", "0500"}); + time({"0","to","6","by","6"}, {"0000", "0600"}); + time({"6","to","18"}, {"0600", "1200", "1800"}); + time({"1","to","6","by","1"}, {"0100", "0200", "0300", "0400", "0500", "0600"}); + time({"1","to","6","by","2"}, {"0100", "0300", "0500"}); + time({"1","to","6","by","3"}, {"0100", "0400"}); + time({"1","to","6","by","4"}, {"0100", "0500"}); + time({"1","to","6","by","5"}, {"0100", "0600"}); + time({"1","to","6","by","6"}, {"0100"}); + + time({"1","to","3h","by","30m"}, {"0100", "0130", "0200", "0230", "0300"}); + + // quantile({"0:5","to","0:5"}, {"0:5"}); + // quantile({"3:3","to","3:3"}, {"3:3"}); + // quantile({"0:5","to","5:5"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); + // quantile({"0:5","to","5:5","by","1"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); + // quantile({"0:5","to","5:5","by","2"}, {"0:5","2:5","4:5"}); + // quantile({"0:5","to","5:5","by","3"}, {"0:5","3:5"}); + // quantile({"0:5","to","5:5","by","5"}, {"0:5","5:5"}); + // quantile({"0:5","to","5:5","by","6"}, {"0:5"}); + // quantile({"2:5","to","5:5","by","2"}, {"2:5","4:5"}); + // quantile({"3:5","to","5:5","by","2"}, {"3:5","5:5"}); + // quantile({"4:5","to","5:5","by","2"}, {"4:5"}); + // quantile({"0:10","3:10","to","7:10","by","2","10:10"}, {"0:10","3:10","5:10","7:10","10:10"}); +} + + +void stepThrows(std::vector values) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("step"); + std::cout << "stepThrows " << values << std::endl; + EXPECT_THROWS(t->expand(ctx, values)); +} + +void step(std::vector values, std::vector expected) { + DummyContext ctx; + static metkit::mars::MarsLanguage language("retrieve"); + metkit::mars::Type* t = language.type("step"); + std::cout << "step " << values << " ==> "; + t->expand(ctx, values); + std::cout << values << " - expected: " << expected << std::endl; + ASSERT(values == expected); +} + +CASE( "test_metkit_expand_13_step" ) { +// stepThrows({"-1"}); + stepThrows({"0:70"}); + step({"0:20"}, {"20m"}); + step({"1:00"}, {"1"}); + step({"1:0:0"}, {"1"}); + step({"1h"}, {"1"}); + step({"60m"}, {"1"}); + step({"1h60m"}, {"2"}); + // quantileThrows({"6:5"}); + // quantileThrows({"0:12"}); + // quantile({"2:5"}, {"2:5"}); + // quantile({"0:2","1:2","2:2"}, {"0:2","1:2","2:2"}); + // quantile({"0:2","1:3","2:5"}, {"0:2","1:3","2:5"}); + + // quantileThrows({"to","5:10"}); + // quantileThrows({"3:5","to"}); + // quantileThrows({"3:5","to","5:10"}); + // quantileThrows({"3:5","to","2:5"}); + // quantileThrows({"1:5","to","3:5","by"}); + // quantileThrows({"1:5","to","3:5","by","1:5"}); + + // quantile({"0:5","to","0:5"}, {"0:5"}); + // quantile({"3:3","to","3:3"}, {"3:3"}); + // quantile({"0:5","to","5:5"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); + // quantile({"0:5","to","5:5","by","1"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); + // quantile({"0:5","to","5:5","by","2"}, {"0:5","2:5","4:5"}); + // quantile({"0:5","to","5:5","by","3"}, {"0:5","3:5"}); + // quantile({"0:5","to","5:5","by","5"}, {"0:5","5:5"}); + // quantile({"0:5","to","5:5","by","6"}, {"0:5"}); + // quantile({"2:5","to","5:5","by","2"}, {"2:5","4:5"}); + // quantile({"3:5","to","5:5","by","2"}, {"3:5","5:5"}); + // quantile({"4:5","to","5:5","by","2"}, {"4:5"}); + // quantile({"0:10","3:10","to","7:10","by","2","10:10"}, {"0:10","3:10","5:10","7:10","10:10"}); +} + //----------------------------------------------------------------------------- } // namespace test diff --git a/tests/test_time.cc b/tests/test_time.cc index 5278004d..13cc94bc 100644 --- a/tests/test_time.cc +++ b/tests/test_time.cc @@ -33,8 +33,13 @@ CASE("Test TypeType expansions") { Type& tt(ttime); DummyContext ctx; - // 2-digit times + // 1 and 2-digit times + { + std::string value = "0"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } { std::string value = "00"; tt.expand(ctx, value); @@ -46,73 +51,59 @@ CASE("Test TypeType expansions") { EXPECT(value == "1200"); } { - std::string value = "06"; + std::string value = "6"; tt.expand(ctx, value); EXPECT(value == "0600"); } { - std::string value = "6"; + std::string value = "06"; tt.expand(ctx, value); EXPECT(value == "0600"); } - // 4-digit times + // 3 and 4-digit times { - std::string value = "0000"; + std::string value = "000"; tt.expand(ctx, value); EXPECT(value == "0000"); } { - std::string value = "0012"; - tt.expand(ctx, value); - EXPECT(value == "0012"); - } - { - std::string value = "1234"; - tt.expand(ctx, value); - EXPECT(value == "1234"); - } - { - std::string value = "0623"; - tt.expand(ctx, value); - EXPECT(value == "0623"); - } - { - std::string value = "623"; + std::string value = "0000"; tt.expand(ctx, value); - EXPECT(value == "0623"); + EXPECT(value == "0000"); } - - // 4-digit times with colons - { - std::string value = "00:00"; + std::string value = "012"; tt.expand(ctx, value); - EXPECT(value == "0000"); + EXPECT(value == "0012"); } { - std::string value = "00:12"; + std::string value = "0012"; tt.expand(ctx, value); EXPECT(value == "0012"); } { - std::string value = "12:34"; + std::string value = "1234"; tt.expand(ctx, value); EXPECT(value == "1234"); } { - std::string value = "06:23"; + std::string value = "623"; tt.expand(ctx, value); EXPECT(value == "0623"); } { - std::string value = "6:23"; + std::string value = "0623"; tt.expand(ctx, value); EXPECT(value == "0623"); } + { + std::string value = "675"; + EXPECT_THROWS_AS(tt.expand(ctx, value), BadTime); + } - // 6-digit times + // 5 and 6-digit times { std::string value = "000000"; @@ -150,13 +141,52 @@ CASE("Test TypeType expansions") { EXPECT_THROWS_AS(tt.expand(ctx, value), SeriousBug); } - // 6-digit times with colons + // times with colons + { + std::string value = "0:0"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } + { + std::string value = "00:00"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } { std::string value = "00:00:00"; tt.expand(ctx, value); EXPECT(value == "0000"); } + { + std::string value = "0:12"; + tt.expand(ctx, value); + EXPECT(value == "0012"); + } + { + std::string value = "00:12"; + tt.expand(ctx, value); + EXPECT(value == "0012"); + } + { + std::string value = "00:62"; + EXPECT_THROWS_AS(tt.expand(ctx, value), BadTime); + } + { + std::string value = "12:34"; + tt.expand(ctx, value); + EXPECT(value == "1234"); + } + { + std::string value = "6:23"; + tt.expand(ctx, value); + EXPECT(value == "0623"); + } + { + std::string value = "06:23"; + tt.expand(ctx, value); + EXPECT(value == "0623"); + } { // We don't support seconds yet. std::string value = "00:00:12"; @@ -187,6 +217,29 @@ CASE("Test TypeType expansions") { std::string value = "12:34:56"; EXPECT_THROWS_AS(tt.expand(ctx, value), SeriousBug); } + + // times with units + + { + std::string value = "0h"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } + { + std::string value = "00H"; + tt.expand(ctx, value); + EXPECT(value == "0000"); + } + { + std::string value = "60m"; + tt.expand(ctx, value); + EXPECT(value == "0100"); + } + { + std::string value = "2h30m"; + tt.expand(ctx, value); + EXPECT(value == "0230"); + } } From 4f378d687fad9ccaee4ca5b609fc11e04ece4ee8 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Wed, 20 Sep 2023 14:37:52 +0000 Subject: [PATCH 03/17] METK-112 improved time parsing + test step monotonicity --- src/metkit/mars/TypeTime.cc | 15 ++++++++------- tests/test_expand.cc | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/metkit/mars/TypeTime.cc b/src/metkit/mars/TypeTime.cc index 8cbfad9d..818fe692 100644 --- a/src/metkit/mars/TypeTime.cc +++ b/src/metkit/mars/TypeTime.cc @@ -25,7 +25,7 @@ namespace mars { //---------------------------------------------------------------------------------------------------------------------- TypeTime::TypeTime(const std::string &name, const eckit::Value& settings) : - Type(name, settings), by_(6) { + Type(name, settings), by_(6*3600) { } TypeTime::~TypeTime() { @@ -54,8 +54,8 @@ bool TypeTime::expand(const MarsExpandContext&, std::string &value) const { void TypeTime::expand(const MarsExpandContext& ctx, std::vector& values) const { - static eckit::Translator s2l; - static eckit::Translator l2s; + //static eckit::Translator s2l; + //static eckit::Translator l2s; std::vector newval; @@ -67,17 +67,18 @@ void TypeTime::expand(const MarsExpandContext& ctx, std::vector& va ASSERT(newval.size() > 0); ASSERT(i + 1 < values.size()); - long from = s2l(tidy(ctx, newval.back())); - long to = s2l(tidy(ctx, values[i + 1])); + long from = ((eckit::Second) eckit::Time(tidy(ctx, newval.back()))); + long to = ((eckit::Second) eckit::Time(tidy(ctx, values[i + 1]))); + ASSERT(from <= to); long by = by_; if (i + 3 < values.size() && eckit::StringTools::lower(values[i + 2]) == "by") { - by = s2l(tidy(ctx, values[i + 3])); + by = ((eckit::Second) eckit::Time(tidy(ctx, values[i + 3]))); i += 2; } for (long j = from + by; j <= to; j += by) { - newval.push_back(l2s(j)); + newval.push_back(eckit::Time(j)); } i++; diff --git a/tests/test_expand.cc b/tests/test_expand.cc index c0416bff..30642adb 100644 --- a/tests/test_expand.cc +++ b/tests/test_expand.cc @@ -271,6 +271,8 @@ CASE( "test_metkit_expand_13_step" ) { step({"1h"}, {"1"}); step({"60m"}, {"1"}); step({"1h60m"}, {"2"}); + step({"1-2"}, {"1-2"}); + step({"30m-1"}, {"30m-60m"}); // quantileThrows({"6:5"}); // quantileThrows({"0:12"}); // quantile({"2:5"}, {"2:5"}); From 5373ac416ab01320fe6657ad35a2830e31370859 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Wed, 27 Sep 2023 14:15:37 +0100 Subject: [PATCH 04/17] METK-112 simplified 'step' canonical form to hour (in floating point, to represent sun-hourly steps) --- src/metkit/mars/StepRange.cc | 6 +- src/metkit/mars/StepRange.h | 6 +- src/metkit/mars/TypeRange.cc | 141 +++++++++++++++++++---------------- src/metkit/mars/TypeTime.cc | 4 +- tests/test_codes_decoder.cc | 6 +- tests/test_expand.cc | 27 ++++++- tests/test_time.cc | 2 +- 7 files changed, 112 insertions(+), 80 deletions(-) diff --git a/src/metkit/mars/StepRange.cc b/src/metkit/mars/StepRange.cc index 06615bb4..a05b6fa8 100644 --- a/src/metkit/mars/StepRange.cc +++ b/src/metkit/mars/StepRange.cc @@ -54,14 +54,14 @@ StepRange::StepRange(const std::string& s): { case 1: from = eckit::Time(result[0], true); - from_ = to_ = from/3600.f; + from_ = to_ = from/3600.; break; case 2: from = eckit::Time(result[0], true); to = eckit::Time(result[1], true); - from_ = from/3600.f; - to_ = to/3600.f; + from_ = from/3600.; + to_ = to/3600.; break; default: diff --git a/src/metkit/mars/StepRange.h b/src/metkit/mars/StepRange.h index 7ff0bf33..f4e64b77 100644 --- a/src/metkit/mars/StepRange.h +++ b/src/metkit/mars/StepRange.h @@ -35,7 +35,11 @@ class StepRange { StepRange(const std::string&); StepRange(double from = 0,double to = 0): - from_(from),to_(to) {} + from_(from),to_(to) { + if (from_ != 0 && to_ == 0) { + to_ = from_; + } + } #include "metkit/mars/StepRange.b" diff --git a/src/metkit/mars/TypeRange.cc b/src/metkit/mars/TypeRange.cc index 01b43b39..eb77fb08 100644 --- a/src/metkit/mars/TypeRange.cc +++ b/src/metkit/mars/TypeRange.cc @@ -20,63 +20,68 @@ #include "metkit/mars/Quantile.h" #include "metkit/mars/TypesFactory.h" #include "metkit/mars/TypeTime.h" +#include "metkit/mars/StepRange.h" namespace { -enum TimeUnit { - Second = 0, - Minute = 1, - Hour = 2, - Day = 3 -}; - -TimeUnit maxUnit(const eckit::Time& t) { - if (t.seconds() == 0) { - if (t.minutes() == 0) { - if (t.hours() == 0) { - return TimeUnit::Day; - } - return TimeUnit::Hour; - } - return TimeUnit::Minute; - } - return TimeUnit::Second; -} +// enum TimeUnit { +// Second = 0, +// Minute = 1, +// Hour = 2, +// Day = 3 +// }; + +// TimeUnit maxUnit(const eckit::Time& t) { +// if (t.seconds() == 0) { +// if (t.minutes() == 0) { +// if (t.hours() == 0) { +// return TimeUnit::Day; +// } +// return TimeUnit::Hour; +// } +// return TimeUnit::Minute; +// } +// return TimeUnit::Second; +// } std::string canonical(const eckit::Time& time) { - long d = time.hours()/24; - long h = time.hours()%24; - long m = time.minutes(); - long s = time.seconds(); - - std::string out = ""; - if (d!=0) { - out += std::to_string(d) + "D"; - } - if (h!=0) { - out += std::to_string(h) + "h"; - } - if (m!=0) { - out += std::to_string(m) + "m"; - } - if (s!=0) { - out = std::to_string(s) + "s"; - } - return out; + return metkit::mars::StepRange(time/3600.); + + // long d = time.hours()/24; + // long h = time.hours()%24; + // long m = time.minutes(); + // long s = time.seconds(); + + // std::string out = ""; + // if (d!=0) { + // out += std::to_string(d) + "D"; + // } + // if (h!=0) { + // out += std::to_string(h) + "h"; + // } + // if (m!=0) { + // out += std::to_string(m) + "m"; + // } + // if (s!=0) { + // out = std::to_string(s) + "s"; + // } + // return out; } -std::string canonical(const eckit::Time& time, TimeUnit unit) { - switch (unit) { - case TimeUnit::Second: - return std::to_string(time.seconds()) + "s"; - case TimeUnit::Minute: - return std::to_string(time.minutes()) + "m"; - case TimeUnit::Day: - case TimeUnit::Hour: - default: - return std::to_string(time.hours()); - } -} +// std::string canonical(const eckit::Time& time, TimeUnit unit) { +// return metkit::mars::StepRange(time/3600.); + +// switch (unit) { +// case TimeUnit::Second: +// return std::to_string(time.seconds()+60*time.minutes()+3600*time.hours()) + "s"; +// case TimeUnit::Minute: +// return std::to_string(time.minutes()+60*time.hours()) + "m"; +// case TimeUnit::Day: +// case TimeUnit::Hour: +// default: +// return std::to_string(time.hours()); +// } +// } } namespace metkit::mars { @@ -107,7 +112,8 @@ bool TypeRange::expand(const MarsExpandContext& ctx, std::string& value) const { switch (result.size()) { case 1: { eckit::Time start = eckit::Time(result[0], true); - value = canonical(start, maxUnit(start)); + // value = canonical(start, maxUnit(start)); + value = canonical(start); return true; } case 2: { @@ -115,12 +121,14 @@ bool TypeRange::expand(const MarsExpandContext& ctx, std::string& value) const { eckit::Time end = eckit::Time(result[1], true); if (start > end) { std::ostringstream oss; + std::cout << result[0] << " - " << result[1] << std::endl; oss << name_ + ": initial value " << start << " cannot be greater that final value " << end; throw eckit::BadValue(oss.str()); } - TimeUnit unit = std::max(maxUnit(start), maxUnit(end)); - value = canonical(start, unit) + "-" + canonical(end, unit); + // TimeUnit unit = std::max(maxUnit(start), maxUnit(end)); + // value = canonical(start, unit) + "-" + canonical(end, unit); + value = canonical(start) + "-" + canonical(end); return true; } default: @@ -140,8 +148,7 @@ void TypeRange::expand(const MarsExpandContext& ctx, std::vector& v const std::string& s = values[i]; if (eckit::StringTools::lower(s) == "to" || eckit::StringTools::lower(s) == "t0") { - std::vector tmpval; - TimeUnit unit; + // TimeUnit unit; if (newval.size() == 0) { std::ostringstream oss; @@ -155,8 +162,7 @@ void TypeRange::expand(const MarsExpandContext& ctx, std::vector& v } eckit::Time from = eckit::Time(values[i - 1], true); - tmpval.push_back(from); - unit = maxUnit(from); + // unit = maxUnit(from); eckit::Time to = eckit::Time(values[i + 1], true); eckit::Time by = by_; @@ -172,7 +178,6 @@ void TypeRange::expand(const MarsExpandContext& ctx, std::vector& v i += 2; } -// std::cout << from << " " << to << " " << by << std::endl; if (from > to) { std::ostringstream oss; @@ -184,15 +189,19 @@ void TypeRange::expand(const MarsExpandContext& ctx, std::vector& v oss << name_ + ": 'by' value " << by << " must be a positive number"; throw eckit::BadValue(name_ + ": 'by' value must be a positive number"); } - for (long j = from + by; j <= to; j += by) { - unit = std::min(unit, maxUnit(j)); - } - for (long j = from + by; j <= to; j += by) { - if (unit >= TimeUnit::Hour) { - newval.emplace_back(canonical(j, unit)); - } else { + eckit::Time j = from; + // j += by; + // for (; j <= to; j += by) { + // unit = std::min(unit, maxUnit(j)); + // } + // j = from; + j += by; + for (; j <= to; j += by) { + // if (unit >= TimeUnit::Hour) { + // newval.emplace_back(canonical(j, unit)); + // } else { newval.emplace_back(canonical(j)); - } + // } } i++; diff --git a/src/metkit/mars/TypeTime.cc b/src/metkit/mars/TypeTime.cc index 818fe692..21328188 100644 --- a/src/metkit/mars/TypeTime.cc +++ b/src/metkit/mars/TypeTime.cc @@ -33,7 +33,7 @@ TypeTime::~TypeTime() { bool TypeTime::expand(const MarsExpandContext&, std::string &value) const { - eckit::Time time(value, true); + eckit::Time time(value); std::ostringstream oss; if (time.seconds() != 0) { @@ -77,7 +77,7 @@ void TypeTime::expand(const MarsExpandContext& ctx, std::vector& va i += 2; } - for (long j = from + by; j <= to; j += by) { + for (long j = from + by; j <= to; j += by) { newval.push_back(eckit::Time(j)); } diff --git a/tests/test_codes_decoder.cc b/tests/test_codes_decoder.cc index 7f046c4a..26c36eab 100644 --- a/tests/test_codes_decoder.cc +++ b/tests/test_codes_decoder.cc @@ -211,8 +211,7 @@ CASE("test codessplitter unstr_latlot.tmpl Native") { MD_EXPECT_LONG(md, "forecastTime", 0); MD_EXPECT_LONG(md, "startStep", 0); MD_EXPECT_LONG(md, "endStep", 0); -// MD_EXPECT_STRING(md, "stepRange", "0"); - MD_EXPECT_STRING(md, "stepRange", "0h"); + MD_EXPECT_STRING(md, "stepRange", "0"); MD_EXPECT_LONG(md, "validityDate", 10101); MD_EXPECT_LONG(md, "validityTime", 0); MD_EXPECT_STRING(md, "typeOfFirstFixedSurface", "168"); @@ -396,8 +395,7 @@ CASE("test codessplitter unstr_latlot.tmpl String") { MD_EXPECT_STRING(md, "forecastTime", "0"); MD_EXPECT_STRING(md, "startStep", "0"); MD_EXPECT_STRING(md, "endStep", "0"); -// MD_EXPECT_STRING(md, "stepRange", "0"); - MD_EXPECT_STRING(md, "stepRange", "0h"); + MD_EXPECT_STRING(md, "stepRange", "0"); MD_EXPECT_STRING(md, "validityDate", "10101"); MD_EXPECT_STRING(md, "validityTime", "0"); MD_EXPECT_STRING(md, "typeOfFirstFixedSurface", "168"); diff --git a/tests/test_expand.cc b/tests/test_expand.cc index 30642adb..360f9f8c 100644 --- a/tests/test_expand.cc +++ b/tests/test_expand.cc @@ -263,16 +263,37 @@ void step(std::vector values, std::vector expected) { } CASE( "test_metkit_expand_13_step" ) { -// stepThrows({"-1"}); stepThrows({"0:70"}); - step({"0:20"}, {"20m"}); +// step({"0:20"}, {"20m"}); + step({"0"}, {"0"}); + step({"1"}, {"1"}); + step({"24"}, {"24"}); + step({"144"}, {"144"}); + step({"012"}, {"12"}); + step({"1230"}, {"12.5"}); step({"1:00"}, {"1"}); step({"1:0:0"}, {"1"}); step({"1h"}, {"1"}); step({"60m"}, {"1"}); step({"1h60m"}, {"2"}); + step({"0:5"}, {"0.0833333"}); + step({"0:05"}, {"0.0833333"}); + step({"0:05:0"}, {"0.0833333"}); + step({"0:06"}, {"0.1"}); + step({"0:10"}, {"0.166667"}); + step({"0:12"}, {"0.2"}); + step({"0:15"}, {"0.25"}); + step({"0:20"}, {"0.333333"}); + step({"0:25"}, {"0.416667"}); + step({"0:30"}, {"0.5"}); + step({"0:35"}, {"0.583333"}); + step({"0:40"}, {"0.666667"}); + step({"0:45"}, {"0.75"}); + step({"0:50"}, {"0.833333"}); + step({"0:55"}, {"0.916667"}); step({"1-2"}, {"1-2"}); - step({"30m-1"}, {"30m-60m"}); + // step({"30m-1"}, {"30m-60m"}); + step({"30m-1"}, {"0.5-1"}); // quantileThrows({"6:5"}); // quantileThrows({"0:12"}); // quantile({"2:5"}, {"2:5"}); diff --git a/tests/test_time.cc b/tests/test_time.cc index 13cc94bc..b8612854 100644 --- a/tests/test_time.cc +++ b/tests/test_time.cc @@ -27,7 +27,7 @@ namespace test { //----------------------------------------------------------------------------- -CASE("Test TypeType expansions") { +CASE("Test TypeTime expansions") { TypeTime ttime("time", Value()); Type& tt(ttime); From e8fabc90d5a34683184d54af96714ac7e4168c95 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Wed, 27 Sep 2023 14:43:34 +0100 Subject: [PATCH 05/17] fix unit test --- tests/test_expand.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_expand.cc b/tests/test_expand.cc index 360f9f8c..f51b899d 100644 --- a/tests/test_expand.cc +++ b/tests/test_expand.cc @@ -270,7 +270,7 @@ CASE( "test_metkit_expand_13_step" ) { step({"24"}, {"24"}); step({"144"}, {"144"}); step({"012"}, {"12"}); - step({"1230"}, {"12.5"}); + step({"12:30"}, {"12.5"}); step({"1:00"}, {"1"}); step({"1:0:0"}, {"1"}); step({"1h"}, {"1"}); From 893c0ff9a350255b0f07b5e6542c0cafd17c860f Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Thu, 28 Sep 2023 14:59:10 +0100 Subject: [PATCH 06/17] METK-112 updated canonical representation of step: hours (for back compatibility) or hours + minutes/seconds with unit --- src/metkit/mars/StepRange.cc | 99 +++++++++++++++++++++++++++++------- src/metkit/mars/StepRange.h | 28 +++++----- src/metkit/mars/TypeRange.cc | 83 ++---------------------------- tests/test_expand.cc | 62 +++++++--------------- 4 files changed, 118 insertions(+), 154 deletions(-) diff --git a/src/metkit/mars/StepRange.cc b/src/metkit/mars/StepRange.cc index a05b6fa8..1763f547 100644 --- a/src/metkit/mars/StepRange.cc +++ b/src/metkit/mars/StepRange.cc @@ -10,6 +10,7 @@ #include "metkit/mars/StepRange.h" #include "metkit/mars/TypeTime.h" +#include "metkit/mars/TypeRange.h" #include "eckit/exception/Exceptions.h" #include "eckit/persist/DumpLoad.h" @@ -17,8 +18,71 @@ using namespace eckit; -namespace metkit { -namespace mars { + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { + +enum TimeUnit { + Second = 0, + Minute = 1, + Hour = 2, + Day = 3 +}; + +TimeUnit maxUnit(const eckit::Time& t) { + if (t.seconds() == 0) { + if (t.minutes() == 0) { + if (t.hours() == 0) { + return TimeUnit::Day; + } + return TimeUnit::Hour; + } + return TimeUnit::Minute; + } + return TimeUnit::Second; +} + +std::string canonical(const eckit::Time& time) { + + long h = time.hours(); + long m = time.minutes(); + long s = time.seconds(); + + // std::cout << h << "h" << m << "m" << s << "s\n"; + std::string out = ""; + if (h!=0 || (m==0 && s==0)) { + out += std::to_string(h); + if (m!=0 || s!=0) { + out += "h"; + } + } + if (m!=0) { + out += std::to_string(m) + "m"; + } + if (s!=0) { + out += std::to_string(s) + "s"; + } + return out; +} + +std::string canonical(const eckit::Time& time, TimeUnit unit) { + switch (unit) { + case TimeUnit::Second: + return std::to_string(time.seconds()+60*time.minutes()+3600*time.hours()) + "s"; + case TimeUnit::Minute: + return std::to_string(time.minutes()+60*time.hours()) + "m"; + case TimeUnit::Day: + case TimeUnit::Hour: + default: + return std::to_string(time.hours()); + } +} + +} + +namespace metkit::mars { + //---------------------------------------------------------------------------------------------------------------------- @@ -32,11 +96,11 @@ StepRange::operator std::string() const void StepRange::print(std::ostream& s) const { if(from_ == to_) { - s << from_; + s << canonical(from_); } else { - s << from_ << '-'; - s << to_; + TimeUnit unit = std::min(maxUnit(from_), maxUnit(to_)); + s << canonical(from_,unit) << '-' << canonical(to_,unit); } } @@ -48,20 +112,16 @@ StepRange::StepRange(const std::string& s): std::vector result; parse(s,result); - eckit::Second from, to; switch(result.size()) { case 1: - from = eckit::Time(result[0], true); - from_ = to_ = from/3600.; + to_ = from_ = eckit::Time(result[0], true); break; case 2: - from = eckit::Time(result[0], true); - to = eckit::Time(result[1], true); - from_ = from/3600.; - to_ = to/3600.; + from_ = eckit::Time(result[0], true); + to_ = eckit::Time(result[1], true); break; default: @@ -74,16 +134,19 @@ StepRange::StepRange(const std::string& s): void StepRange::dump(DumpLoad& a) const { - a.dump(from_); - a.dump(to_); + a.dump(from_.seconds()/3600.); + a.dump(to_.seconds()/3600.); } void StepRange::load(DumpLoad& a) { - a.load(from_); - a.load(to_); + double from, to; + a.load(from); + a.load(to); + + from_ = eckit::Time(from*3600., true); + to_ = eckit::Time(to*3600., true); } //---------------------------------------------------------------------------------------------------------------------- -} // namespace mars -} // namespace metkit +} // namespace metkit::mars diff --git a/src/metkit/mars/StepRange.h b/src/metkit/mars/StepRange.h index f4e64b77..72b56714 100644 --- a/src/metkit/mars/StepRange.h +++ b/src/metkit/mars/StepRange.h @@ -16,11 +16,11 @@ #include "eckit/persist/Bless.h" #include "eckit/types/Types.h" +#include "eckit/types/Time.h" namespace eckit { class DumpLoad; } -namespace metkit { -namespace mars { +namespace metkit::mars { //---------------------------------------------------------------------------------------------------------------------- @@ -34,12 +34,17 @@ class StepRange { StepRange(const std::string&); - StepRange(double from = 0,double to = 0): + StepRange(eckit::Time from = eckit::Time(0), eckit::Time to = eckit::Time(0)): from_(from),to_(to) { - if (from_ != 0 && to_ == 0) { - to_ = from_; - } + + if (from_ != eckit::Time(0) && to_ == eckit::Time(0)) { + to_ = from_; } + } + + StepRange(double from, double to = 0): + StepRange(eckit::Time(from*3600, true), eckit::Time(to*3600, true)) {} + #include "metkit/mars/StepRange.b" @@ -69,8 +74,8 @@ class StepRange { // -- Methods - double from() const { return from_; } - double to() const { return to_; } + double from() const { return from_/3600.; } + double to() const { return to_/3600.; } void dump(eckit::DumpLoad&) const; void load(eckit::DumpLoad&); @@ -110,8 +115,8 @@ class StepRange { // -- Members - double from_; - double to_; + eckit::Time from_; + eckit::Time to_; // -- Methods // None @@ -134,7 +139,6 @@ class StepRange { //---------------------------------------------------------------------------------------------------------------------- -} // namespace mars -} // namespace metkit +} // namespace metkit::mars #endif diff --git a/src/metkit/mars/TypeRange.cc b/src/metkit/mars/TypeRange.cc index eb77fb08..27e03b41 100644 --- a/src/metkit/mars/TypeRange.cc +++ b/src/metkit/mars/TypeRange.cc @@ -22,68 +22,6 @@ #include "metkit/mars/TypeTime.h" #include "metkit/mars/StepRange.h" -namespace { - -// enum TimeUnit { -// Second = 0, -// Minute = 1, -// Hour = 2, -// Day = 3 -// }; - -// TimeUnit maxUnit(const eckit::Time& t) { -// if (t.seconds() == 0) { -// if (t.minutes() == 0) { -// if (t.hours() == 0) { -// return TimeUnit::Day; -// } -// return TimeUnit::Hour; -// } -// return TimeUnit::Minute; -// } -// return TimeUnit::Second; -// } - -std::string canonical(const eckit::Time& time) { - return metkit::mars::StepRange(time/3600.); - - // long d = time.hours()/24; - // long h = time.hours()%24; - // long m = time.minutes(); - // long s = time.seconds(); - - // std::string out = ""; - // if (d!=0) { - // out += std::to_string(d) + "D"; - // } - // if (h!=0) { - // out += std::to_string(h) + "h"; - // } - // if (m!=0) { - // out += std::to_string(m) + "m"; - // } - // if (s!=0) { - // out = std::to_string(s) + "s"; - // } - // return out; -} - -// std::string canonical(const eckit::Time& time, TimeUnit unit) { -// return metkit::mars::StepRange(time/3600.); - -// switch (unit) { -// case TimeUnit::Second: -// return std::to_string(time.seconds()+60*time.minutes()+3600*time.hours()) + "s"; -// case TimeUnit::Minute: -// return std::to_string(time.minutes()+60*time.hours()) + "m"; -// case TimeUnit::Day: -// case TimeUnit::Hour: -// default: -// return std::to_string(time.hours()); -// } -// } - -} namespace metkit::mars { //---------------------------------------------------------------------------------------------------------------------- @@ -95,7 +33,6 @@ TypeRange::TypeRange(const std::string &name, const eckit::Value& settings) : multiple_ = true; } - TypeRange::~TypeRange() { } @@ -111,9 +48,7 @@ bool TypeRange::expand(const MarsExpandContext& ctx, std::string& value) const { parse(value, result); switch (result.size()) { case 1: { - eckit::Time start = eckit::Time(result[0], true); - // value = canonical(start, maxUnit(start)); - value = canonical(start); + value = StepRange(eckit::Time(result[0], true)); return true; } case 2: { @@ -125,10 +60,7 @@ bool TypeRange::expand(const MarsExpandContext& ctx, std::string& value) const { oss << name_ + ": initial value " << start << " cannot be greater that final value " << end; throw eckit::BadValue(oss.str()); } - - // TimeUnit unit = std::max(maxUnit(start), maxUnit(end)); - // value = canonical(start, unit) + "-" + canonical(end, unit); - value = canonical(start) + "-" + canonical(end); + value = StepRange(start, end); return true; } default: @@ -190,18 +122,9 @@ void TypeRange::expand(const MarsExpandContext& ctx, std::vector& v throw eckit::BadValue(name_ + ": 'by' value must be a positive number"); } eckit::Time j = from; - // j += by; - // for (; j <= to; j += by) { - // unit = std::min(unit, maxUnit(j)); - // } - // j = from; j += by; for (; j <= to; j += by) { - // if (unit >= TimeUnit::Hour) { - // newval.emplace_back(canonical(j, unit)); - // } else { - newval.emplace_back(canonical(j)); - // } + newval.emplace_back(StepRange(j)); } i++; diff --git a/tests/test_expand.cc b/tests/test_expand.cc index f51b899d..ac22bced 100644 --- a/tests/test_expand.cc +++ b/tests/test_expand.cc @@ -263,62 +263,36 @@ void step(std::vector values, std::vector expected) { } CASE( "test_metkit_expand_13_step" ) { - stepThrows({"0:70"}); -// step({"0:20"}, {"20m"}); +// stepThrows({"0:70"}); step({"0"}, {"0"}); step({"1"}, {"1"}); step({"24"}, {"24"}); step({"144"}, {"144"}); step({"012"}, {"12"}); - step({"12:30"}, {"12.5"}); + step({"12:30"}, {"12h30m"}); step({"1:00"}, {"1"}); step({"1:0:0"}, {"1"}); step({"1h"}, {"1"}); step({"60m"}, {"1"}); step({"1h60m"}, {"2"}); - step({"0:5"}, {"0.0833333"}); - step({"0:05"}, {"0.0833333"}); - step({"0:05:0"}, {"0.0833333"}); - step({"0:06"}, {"0.1"}); - step({"0:10"}, {"0.166667"}); - step({"0:12"}, {"0.2"}); - step({"0:15"}, {"0.25"}); - step({"0:20"}, {"0.333333"}); - step({"0:25"}, {"0.416667"}); - step({"0:30"}, {"0.5"}); - step({"0:35"}, {"0.583333"}); - step({"0:40"}, {"0.666667"}); - step({"0:45"}, {"0.75"}); - step({"0:50"}, {"0.833333"}); - step({"0:55"}, {"0.916667"}); + step({"0:5"}, {"5m"}); + step({"0:05"}, {"5m"}); + step({"0:05:0"}, {"5m"}); + step({"0:06"}, {"6m"}); + step({"0:10"}, {"10m"}); + step({"0:12"}, {"12m"}); + step({"0:15"}, {"15m"}); + step({"0:20"}, {"20m"}); + step({"0:25"}, {"25m"}); + step({"0:30"}, {"30m"}); + step({"0:35"}, {"35m"}); + step({"0:40"}, {"40m"}); + step({"0:45"}, {"45m"}); + step({"0:50"}, {"50m"}); + step({"0:55"}, {"55m"}); step({"1-2"}, {"1-2"}); - // step({"30m-1"}, {"30m-60m"}); - step({"30m-1"}, {"0.5-1"}); - // quantileThrows({"6:5"}); - // quantileThrows({"0:12"}); - // quantile({"2:5"}, {"2:5"}); - // quantile({"0:2","1:2","2:2"}, {"0:2","1:2","2:2"}); - // quantile({"0:2","1:3","2:5"}, {"0:2","1:3","2:5"}); - - // quantileThrows({"to","5:10"}); - // quantileThrows({"3:5","to"}); - // quantileThrows({"3:5","to","5:10"}); - // quantileThrows({"3:5","to","2:5"}); - // quantileThrows({"1:5","to","3:5","by"}); - // quantileThrows({"1:5","to","3:5","by","1:5"}); + step({"30m-1"}, {"30m-60m"}); - // quantile({"0:5","to","0:5"}, {"0:5"}); - // quantile({"3:3","to","3:3"}, {"3:3"}); - // quantile({"0:5","to","5:5"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); - // quantile({"0:5","to","5:5","by","1"}, {"0:5","1:5","2:5","3:5","4:5","5:5"}); - // quantile({"0:5","to","5:5","by","2"}, {"0:5","2:5","4:5"}); - // quantile({"0:5","to","5:5","by","3"}, {"0:5","3:5"}); - // quantile({"0:5","to","5:5","by","5"}, {"0:5","5:5"}); - // quantile({"0:5","to","5:5","by","6"}, {"0:5"}); - // quantile({"2:5","to","5:5","by","2"}, {"2:5","4:5"}); - // quantile({"3:5","to","5:5","by","2"}, {"3:5","5:5"}); - // quantile({"4:5","to","5:5","by","2"}, {"4:5"}); - // quantile({"0:10","3:10","to","7:10","by","2","10:10"}, {"0:10","3:10","5:10","7:10","10:10"}); } //----------------------------------------------------------------------------- From 54cd4e3af41b78021459878ac10b260578acf689 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Fri, 20 Oct 2023 11:33:36 +0200 Subject: [PATCH 07/17] version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0e73a4b8..e5c453e2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.17 +1.10.18 From ee46514f74b7279cbbc5e1107681884f5018bd00 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Sat, 21 Oct 2023 11:28:36 +0200 Subject: [PATCH 08/17] fix unit test - added support for new validityTime encoding format (hhmm) --- tests/test_codes_decoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_codes_decoder.cc b/tests/test_codes_decoder.cc index bf84226e..224ca574 100644 --- a/tests/test_codes_decoder.cc +++ b/tests/test_codes_decoder.cc @@ -219,7 +219,7 @@ CASE("test codessplitter unstr_latlot.tmpl Native") { MD_EXPECT_LONG(md, "endStep", 0); MD_EXPECT_STRING(md, "stepRange", "0"); MD_EXPECT_LONG(md, "validityDate", 10101); - MD_EXPECT_LONG(md, "validityTime", 0); + MD_EXPECT_STRINGS(md, "validityTime", "0", "0000"); MD_EXPECT_STRING(md, "typeOfFirstFixedSurface", "168"); MD_EXPECT_STRING(md, "unitsOfFirstFixedSurface", "Numeric"); MD_EXPECT_STRING(md, "nameOfFirstFixedSurface", "Ocean model level"); From 63ae476b7ac1ebc907495dccd8ecb7f351e124c6 Mon Sep 17 00:00:00 2001 From: Sebastien Villaume Date: Thu, 26 Oct 2023 11:16:19 +0100 Subject: [PATCH 09/17] adding new class and few mars types to language file --- share/metkit/language.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/share/metkit/language.yaml b/share/metkit/language.yaml index be63e201..063541fc 100644 --- a/share/metkit/language.yaml +++ b/share/metkit/language.yaml @@ -57,6 +57,7 @@ _field: &_field - [nl, netherlands] - ['no', norway] - [nr, ncep 20cr, 20cr] + [o6, 'ocean 6 reanalysis'] - [od, operations] - [pe, permanent experiment] - [pt, portugal] @@ -128,9 +129,11 @@ _field: &_field - [fu, fill-up] - [fx, flux forcing] - [ga, gfas analysis] + - [gbf, bias-corrected gridbox] - [gai, gridded analysis input] - [go, gridded observations] - [gsd, gridded satellite data] + - [gwt, weather type gridbox] - [hcmean, hindcast mean] - [ia, init. analysis] - [icp, initial condition perturbation] @@ -149,6 +152,8 @@ _field: &_field - [pb, probability boundary] - [pd, probability distribution] - [pf, perturbed forecast] + - [pfc, point values] + - [ppm, point value metrics] - [s3, climate 30 days simulation] - [ses, scaled ensemble standard deviation] - [sf, sensitivity forecast] From 23d83507981aa09d1f3ff39fdcd0ce5f734e4320 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Fri, 27 Oct 2023 13:16:58 +0100 Subject: [PATCH 10/17] version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e5c453e2..b1d488f1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.18 +1.10.19 From 64174bd47a99813d3b7211f91189382adcb78905 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Mon, 30 Oct 2023 11:06:19 +0000 Subject: [PATCH 11/17] fix typo --- VERSION | 2 +- share/metkit/language.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index b1d488f1..6323875d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.19 +1.10.20 diff --git a/share/metkit/language.yaml b/share/metkit/language.yaml index 0b607792..faf0271b 100644 --- a/share/metkit/language.yaml +++ b/share/metkit/language.yaml @@ -57,7 +57,7 @@ _field: &_field - [nl, netherlands] - ['no', norway] - [nr, ncep 20cr, 20cr] - [o6, 'ocean 6 reanalysis'] + - [o6, 'ocean 6 reanalysis'] - [od, operations] - [pe, permanent experiment] - [pt, portugal] From 82f33a9ca42cb517723e31b5bfacd71f4024d469 Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Tue, 21 Nov 2023 13:19:06 +0100 Subject: [PATCH 12/17] fix typo --- src/metkit/mars/TypeToByListFloat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metkit/mars/TypeToByListFloat.cc b/src/metkit/mars/TypeToByListFloat.cc index 24fbce3d..b7eedd27 100644 --- a/src/metkit/mars/TypeToByListFloat.cc +++ b/src/metkit/mars/TypeToByListFloat.cc @@ -61,7 +61,7 @@ void TypeToByListFloat::expand(const MarsExpandContext& ctx, std::vector 0, name_ + ": 'by' value must be a positive number"); for (float j = from + by; j <= to; j += by) { newval.push_back(l2s(j)); From dd3f2bed20a9f3889d9ea5d3297c0dd58aae56bf Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Tue, 21 Nov 2023 13:23:29 +0100 Subject: [PATCH 13/17] add detail to assert msg --- src/metkit/mars/TypeToByListFloat.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/metkit/mars/TypeToByListFloat.cc b/src/metkit/mars/TypeToByListFloat.cc index b7eedd27..3450cb0b 100644 --- a/src/metkit/mars/TypeToByListFloat.cc +++ b/src/metkit/mars/TypeToByListFloat.cc @@ -61,8 +61,9 @@ void TypeToByListFloat::expand(const MarsExpandContext& ctx, std::vector 0, name_ + ": 'by' value must be a positive number"); + ASSERT_MSG(from <= to, name_ + ": [" + std::to_string(from) + "] value must be less than [" + + std::to_string(to) + "] value!"); + ASSERT_MSG(by > 0, name_ + ": [" + std::to_string(by) + "] value must be a positive number!"); for (float j = from + by; j <= to; j += by) { newval.push_back(l2s(j)); } From 98440cba734ae198a813f078a2f81efafefa8725 Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Tue, 21 Nov 2023 14:19:46 +0100 Subject: [PATCH 14/17] add support for by < 0 --- src/metkit/mars/TypeToByListFloat.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/metkit/mars/TypeToByListFloat.cc b/src/metkit/mars/TypeToByListFloat.cc index 3450cb0b..ee7a9dec 100644 --- a/src/metkit/mars/TypeToByListFloat.cc +++ b/src/metkit/mars/TypeToByListFloat.cc @@ -61,11 +61,14 @@ void TypeToByListFloat::expand(const MarsExpandContext& ctx, std::vector 0, name_ + ": [" + std::to_string(by) + "] value must be a positive number!"); - for (float j = from + by; j <= to; j += by) { - newval.push_back(l2s(j)); + if (by > 0) { + ASSERT_MSG(from <= to, name_ + ": [" + std::to_string(from) + "] value must be less than [" + + std::to_string(to) + "] value!"); + for (float j = from + by; j <= to; j += by) { newval.push_back(l2s(j)); } + } else if (by < 0) { + ASSERT_MSG(from >= to, name_ + ": [" + std::to_string(from) + "] value must be greater than [" + + std::to_string(to) + "] value!"); + for (float j = from + by; j >= to; j += by) { newval.push_back(l2s(j)); } } i++; From efde4c90618f13a9eeac9df05f4d4490ddc40d00 Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Tue, 21 Nov 2023 14:21:08 +0100 Subject: [PATCH 15/17] add test for levelist --- tests/CMakeLists.txt | 2 +- tests/test_type_levelist.cc | 78 +++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tests/test_type_levelist.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 05a781a3..af06050d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -61,7 +61,7 @@ ecbuild_add_test( TARGET metkit_test_odbsplitter NO_AS_NEEDED LIBS metkit ) -list(APPEND testFileSuffixes typesfactory expand param_axis steprange_axis time hypercube ) +list(APPEND testFileSuffixes typesfactory expand param_axis steprange_axis time hypercube type_levelist ) foreach(test IN LISTS testFileSuffixes) ecbuild_add_test( TARGET "metkit_test_${test}" diff --git a/tests/test_type_levelist.cc b/tests/test_type_levelist.cc new file mode 100644 index 00000000..c5109154 --- /dev/null +++ b/tests/test_type_levelist.cc @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation nor + * does it submit to any jurisdiction. + */ + +/// @file test_levelist.cc +/// @author Metin Cakircali +/// @date November 2023 + +#include "metkit/mars/TypesFactory.h" +#include "metkit/mars/TypeToByListFloat.h" +#include "metkit/mars/MarsParser.h" +#include "metkit/mars/MarsLanguage.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/testing/Test.h" + +using namespace eckit::testing; + +namespace metkit { +namespace mars { +namespace test { + +//----------------------------------------------------------------------------- + +CASE("test_metkit_exists_to-by-list-float") { + std::stringstream ss; + TypesFactory::list(ss); + const std::string str(ss.str()); + std::cout << "types=" << str << std::endl; + EXPECT(str.find_first_of("to-by-list-float")); +} + +void assertTypeExpansion(const std::string& name, std::vector values, + const std::vector& expected) { + static MarsLanguage language("retrieve"); + language.type(name)->expand(DummyContext(), values); + ASSERT(values == expected); +} + +CASE("test_metkit_expand_levelist") { + // by > 0 + assertTypeExpansion("levelist", {"-1", "to", "2", "by", "0.5"}, {"-1", "-0.5", "0", ".5", "1", "1.5", "2"}); + // by > 0 + assertTypeExpansion("levelist", {"-10.0", "to", "2.0", "by", "1"}, + {"-10", "-9", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0", "1", "2"}); + // by > 0 && from < to + assertTypeExpansion("levelist", {"4", "to", "20", "by", "4"}, {"4", "8", "12", "16", "20"}); + // by > 0 && from > to + EXPECT_THROWS(assertTypeExpansion("levelist", {"20", "to", "4", "by", "4"}, {"4", "8", "12", "16", "20"})); + // by = 0 + assertTypeExpansion("levelist", {"4", "to", "20", "by", "0"}, {"4"}); + assertTypeExpansion("levelist", {"-1", "to", "2", "by", "0"}, {"-1"}); + // by < 0 && from > to + assertTypeExpansion("levelist", {"10", "to", "4", "by", "-2"}, {"10", "8", "6", "4"}); + assertTypeExpansion("levelist", {"-2", "to", "-4", "by", "-0.5"}, {"-2", "-2.5", "-3", "-3.5", "-4"}); + assertTypeExpansion("levelist", {"0", "to", "-2", "by", "-0.5"}, {"0", "-0.5", "-1", "-1.5", "-2"}); + // by < 0 && from < to + EXPECT_THROWS(assertTypeExpansion("levelist", {"4", "to", "10", "by", "-4"}, {"4", "8", "12", "16", "20"})); + EXPECT_THROWS(assertTypeExpansion("levelist", {"-4", "to", "2", "by", "-0.5"}, {"0", "-0.5", "-1", "-1.5", "-2"})); + // by < 0 && from < to + EXPECT_THROWS(assertTypeExpansion("levelist", {"-1", "to", "2", "by", "-0.5"}, {"-1"})); +} + +} // namespace test +} // namespace mars +} // namespace metkit + +//----------------------------------------------------------------------------- + +int main(int argc, char** argv) { + return run_tests(argc, argv); +} From 81161baa8572d3ff443ad727d27b6c93c85da97f Mon Sep 17 00:00:00 2001 From: Metin Cakircali Date: Tue, 21 Nov 2023 15:02:09 +0100 Subject: [PATCH 16/17] remove redundant check --- tests/test_type_levelist.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_type_levelist.cc b/tests/test_type_levelist.cc index c5109154..1f32a1c0 100644 --- a/tests/test_type_levelist.cc +++ b/tests/test_type_levelist.cc @@ -63,8 +63,6 @@ CASE("test_metkit_expand_levelist") { // by < 0 && from < to EXPECT_THROWS(assertTypeExpansion("levelist", {"4", "to", "10", "by", "-4"}, {"4", "8", "12", "16", "20"})); EXPECT_THROWS(assertTypeExpansion("levelist", {"-4", "to", "2", "by", "-0.5"}, {"0", "-0.5", "-1", "-1.5", "-2"})); - // by < 0 && from < to - EXPECT_THROWS(assertTypeExpansion("levelist", {"-1", "to", "2", "by", "-0.5"}, {"-1"})); } } // namespace test From 9d1f9bb35c696cb1a05fc379f4987ffd9abb2559 Mon Sep 17 00:00:00 2001 From: Emanuele Danovaro Date: Fri, 8 Dec 2023 14:09:41 +0000 Subject: [PATCH 17/17] version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6323875d..1cac385c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.20 +1.11.0