From d84b006a92472b0bbc7da4ab5a46d334cfb136b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domokos=20S=C3=A1rm=C3=A1ny?= Date: Tue, 31 Mar 2026 16:25:05 +0000 Subject: [PATCH 1/4] grib1-to-grib2: Add option to set type=fc,strem=oper as a control forecast --- src/multio/tools/grib1-to-grib2.cc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/multio/tools/grib1-to-grib2.cc b/src/multio/tools/grib1-to-grib2.cc index e15889313..1966bd6d5 100644 --- a/src/multio/tools/grib1-to-grib2.cc +++ b/src/multio/tools/grib1-to-grib2.cc @@ -823,6 +823,8 @@ class Grib1ToGrib2 final : public multio::MultioTool { std::optional setModel_ = {}; bool mapWMOUnits_ = false; bool noOutput_ = false; + bool control_ = false; + std::optional> mappingRules_ = mars2mars::allRulesNoWMOMapping(); Discipline192Handling discipline192Handling_ = Discipline192Handling::LogAndIgnore; }; @@ -836,6 +838,8 @@ Grib1ToGrib2::Grib1ToGrib2(int argc, char** argv) : multio::MultioTool{argc, arg options_.push_back(new eckit::option::SimpleOption( "wmo-units", "If specified params with local units will be mapped to params with WMO units")); options_.push_back(new eckit::option::SimpleOption("verbose", "Sets verbosity to 2")); + options_.push_back( + new eckit::option::SimpleOption("control", "If set, this is treated as a control forecast (number=0)")); options_.push_back( new eckit::option::SimpleOption("verbosity", "Verbosity level: 0 (print nothing), 1 (print mars keys per message), 2 " @@ -873,8 +877,8 @@ void Grib1ToGrib2::init(const eckit::option::CmdArgs& args) { args.get("all", all); copyGrib2Messages_ = !all; - noOutput_ = false; args.get("no-output", noOutput_); + args.get("control", control_); std::string packing; args.get("packing", packing); @@ -886,7 +890,6 @@ void Grib1ToGrib2::init(const eckit::option::CmdArgs& args) { throw std::runtime_error(std::string("Unsupported packing: ") + packing); } } - std::string model; args.get("model", model); if (!model.empty()) { @@ -1052,6 +1055,18 @@ void Grib1ToGrib2::execute(const eckit::option::CmdArgs& args) { misc.generatingProcessIdentifier.set(ncycle_); } + // TODO: Move this logic into the encoder + // TODO: numberOfForecastsInEnsemble needs a default in the encoder + if (control_) { + if (not(mars.stream.get() == "oper") and (mars.type.get() == "fc")) { + throw eckit::UserError( + "Setting forecast member to control is only supported for stream=oper and type=fc", Here()); + } + mars.number.set(0); + misc.typeOfEnsembleForecast.set(1); + misc.numberOfForecastsInEnsemble.set(51); + } + if (verbosity_ > 2) { util::PrintStream ps{std::cout}; ps << "Extracted mars dict:" << std::endl; From 908481330f65fd408a3548b0e9ea6634d2d6801b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domokos=20S=C3=A1rm=C3=A1ny?= <66944306+dsarmany@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:32:40 +0100 Subject: [PATCH 2/4] Fix logic for checking if forecast should be a control forecast Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/multio/tools/grib1-to-grib2.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multio/tools/grib1-to-grib2.cc b/src/multio/tools/grib1-to-grib2.cc index 1966bd6d5..fcfd2c060 100644 --- a/src/multio/tools/grib1-to-grib2.cc +++ b/src/multio/tools/grib1-to-grib2.cc @@ -1058,7 +1058,7 @@ void Grib1ToGrib2::execute(const eckit::option::CmdArgs& args) { // TODO: Move this logic into the encoder // TODO: numberOfForecastsInEnsemble needs a default in the encoder if (control_) { - if (not(mars.stream.get() == "oper") and (mars.type.get() == "fc")) { + if ((mars.stream.get() != "oper") || (mars.type.get() != "fc")) { throw eckit::UserError( "Setting forecast member to control is only supported for stream=oper and type=fc", Here()); } From 152a0f18409c2a80740d1dfeb4adea14d7224506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domokos=20S=C3=A1rm=C3=A1ny?= <66944306+dsarmany@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:40:35 +0100 Subject: [PATCH 3/4] Improve error message Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/multio/tools/grib1-to-grib2.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/multio/tools/grib1-to-grib2.cc b/src/multio/tools/grib1-to-grib2.cc index fcfd2c060..a37e48c7c 100644 --- a/src/multio/tools/grib1-to-grib2.cc +++ b/src/multio/tools/grib1-to-grib2.cc @@ -1060,7 +1060,9 @@ void Grib1ToGrib2::execute(const eckit::option::CmdArgs& args) { if (control_) { if ((mars.stream.get() != "oper") || (mars.type.get() != "fc")) { throw eckit::UserError( - "Setting forecast member to control is only supported for stream=oper and type=fc", Here()); + "Setting forecast member to control is only supported for stream=oper and type=fc; got stream=" + + mars.stream.get() + ", type=" + mars.type.get(), + Here()); } mars.number.set(0); misc.typeOfEnsembleForecast.set(1); From 08f2ff0fc5960f0477bb09b464fc276e0d3bf6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domokos=20S=C3=A1rm=C3=A1ny?= <66944306+dsarmany@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:41:43 +0100 Subject: [PATCH 4/4] Improve `--control` option description Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/multio/tools/grib1-to-grib2.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/multio/tools/grib1-to-grib2.cc b/src/multio/tools/grib1-to-grib2.cc index a37e48c7c..e507234f4 100644 --- a/src/multio/tools/grib1-to-grib2.cc +++ b/src/multio/tools/grib1-to-grib2.cc @@ -838,8 +838,10 @@ Grib1ToGrib2::Grib1ToGrib2(int argc, char** argv) : multio::MultioTool{argc, arg options_.push_back(new eckit::option::SimpleOption( "wmo-units", "If specified params with local units will be mapped to params with WMO units")); options_.push_back(new eckit::option::SimpleOption("verbose", "Sets verbosity to 2")); - options_.push_back( - new eckit::option::SimpleOption("control", "If set, this is treated as a control forecast (number=0)")); + options_.push_back(new eckit::option::SimpleOption( + "control", + "Treat input as a control forecast: sets number=0, adjusts ensemble-related keys, and may enforce " + "specific stream/type constraints")); options_.push_back( new eckit::option::SimpleOption("verbosity", "Verbosity level: 0 (print nothing), 1 (print mars keys per message), 2 "