diff --git a/src/metkit/grib2mars/mappings/rules/coeffindex.h b/src/metkit/grib2mars/mappings/rules/coeffindex.h new file mode 100644 index 000000000..78308fd21 --- /dev/null +++ b/src/metkit/grib2mars/mappings/rules/coeffindex.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "metkit/codes/api/CodesAPI.h" + +#include "metkit/grib2mars/utils/dictionary_traits/dictionary_access_traits.h" +#include "metkit/grib2mars/utils/grib2marsExceptions.h" + +namespace metkit::grib2mars::rules::impl { + +template +void extractCoeffindex(const std::string& keyword, const metkit::codes::CodesHandle& grib, MarsDict& mars, + MiscDict& misc) { + using metkit::grib2mars::utils::dict_traits::set_or_throw; + using metkit::grib2mars::utils::exceptions::Grib2MarsGenericException; + + try { + if (!grib.has(keyword)) { + throw Grib2MarsGenericException( + "Missing GRIB key `" + keyword + "` required to extract MARS keyword `" + keyword + "`", Here()); + } + + const long value = grib.getLong(keyword); + set_or_throw(mars, keyword, value); + + if (grib.has("numberOfFourierCoefficients")) { + const long numberOfFourierCoefficients = grib.getLong("numberOfFourierCoefficients"); + misc.set("numberOfFourierCoefficients", numberOfFourierCoefficients); + } + } + catch (...) { + std::throw_with_nested(Grib2MarsGenericException("Failed to extract MARS keyword `" + keyword + "`", Here())); + } +} + +} // namespace metkit::grib2mars::rules::impl diff --git a/src/metkit/grib2mars/mappings/rules/extract.h b/src/metkit/grib2mars/mappings/rules/extract.h index 453b922c0..af04c0d37 100644 --- a/src/metkit/grib2mars/mappings/rules/extract.h +++ b/src/metkit/grib2mars/mappings/rules/extract.h @@ -14,6 +14,7 @@ #include "metkit/grib2mars/mappings/rules/anoffset.h" #include "metkit/grib2mars/mappings/rules/channel.h" #include "metkit/grib2mars/mappings/rules/class.h" +#include "metkit/grib2mars/mappings/rules/coeffindex.h" #include "metkit/grib2mars/mappings/rules/dataset.h" #include "metkit/grib2mars/mappings/rules/date.h" #include "metkit/grib2mars/mappings/rules/direction.h" @@ -25,6 +26,7 @@ #include "metkit/grib2mars/mappings/rules/hdate.h" #include "metkit/grib2mars/mappings/rules/ident.h" #include "metkit/grib2mars/mappings/rules/instrument.h" +#include "metkit/grib2mars/mappings/rules/iteration.h" #include "metkit/grib2mars/mappings/rules/levelist.h" #include "metkit/grib2mars/mappings/rules/levtype.h" #include "metkit/grib2mars/mappings/rules/method.h" @@ -88,6 +90,8 @@ const std::unordered_map>& extrac {"resolution", extractResolution}, {"model", extractModel}, {"wavelength", extractWavelength}, + {"iteration", extractIteration}, + {"coeffindex", extractCoeffindex}, }; return registry; diff --git a/src/metkit/grib2mars/mappings/rules/iteration.h b/src/metkit/grib2mars/mappings/rules/iteration.h new file mode 100644 index 000000000..6618ec729 --- /dev/null +++ b/src/metkit/grib2mars/mappings/rules/iteration.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "metkit/codes/api/CodesAPI.h" + +#include "metkit/grib2mars/utils/dictionary_traits/dictionary_access_traits.h" +#include "metkit/grib2mars/utils/grib2marsExceptions.h" + +namespace metkit::grib2mars::rules::impl { + +template +void extractIteration(const std::string& keyword, const metkit::codes::CodesHandle& grib, MarsDict& mars, + MiscDict& misc) { + using metkit::grib2mars::utils::dict_traits::set_or_throw; + using metkit::grib2mars::utils::exceptions::Grib2MarsGenericException; + + try { + if (!grib.has(keyword)) { + throw Grib2MarsGenericException( + "Missing GRIB key `" + keyword + "` required to extract MARS keyword `" + keyword + "`", Here()); + } + + const long value = grib.getLong(keyword); + set_or_throw(mars, keyword, value); + + if (grib.getString("type") == "4i" && grib.has("totalNumberOfIterations")) { + const long totalNumberOfIterations = grib.getLong("totalNumberOfIterations"); + misc.set("totalNumberOfIterations", totalNumberOfIterations); + } + } + catch (...) { + std::throw_with_nested(Grib2MarsGenericException("Failed to extract MARS keyword `" + keyword + "`", Here())); + } +} + +} // namespace metkit::grib2mars::rules::impl diff --git a/src/metkit/grib2mars/mappings/rules/misc.h b/src/metkit/grib2mars/mappings/rules/misc.h index 2f1f19dac..cbf1c76da 100644 --- a/src/metkit/grib2mars/mappings/rules/misc.h +++ b/src/metkit/grib2mars/mappings/rules/misc.h @@ -10,16 +10,45 @@ namespace metkit::grib2mars::rules::impl { template void extractMisc(const metkit::codes::CodesHandle& grib, MarsDict& mars, MiscDict& misc) { + using metkit::grib2mars::utils::dict_traits::get_or_throw; using metkit::grib2mars::utils::dict_traits::set_or_throw; using metkit::grib2mars::utils::exceptions::Grib2MarsGenericException; try { - (void)mars; - if (grib.has("generatingProcessIdentifier")) { const auto generatingProcessIdentifier = grib.getLong("generatingProcessIdentifier"); misc.set("generatingProcessIdentifier", generatingProcessIdentifier); } + + if (grib.getString("type") != "ai" && grib.has("typeOfProcessedData")) { + const auto typeOfProcessedData = grib.getString("typeOfProcessedData"); + if (typeOfProcessedData != "missing") { + misc.set("typeOfProcessedData", typeOfProcessedData); + } + } + + const auto type = get_or_throw(mars, "type"); + + if (type == "eme" || type == "me") { + if (grib.has("numberOfComponents")) { + const auto numberOfComponents = grib.getLong("numberOfComponents"); + misc.set("numberOfComponents", numberOfComponents); + } + + if (grib.has("modelErrorType")) { + const auto modelErrorType = grib.getLong("modelErrorType"); + misc.set("modelErrorType", modelErrorType); + } + } + + if (type == "es" || type == "em" || type == "ses") { + if (!grib.has("numberOfForecastsInEnsemble")) { + throw Grib2MarsGenericException( + "Missing GRIB key `numberOfForecastsInEnsemble` required for derived ensemble forecast", Here()); + } + const long numberOfForecastsInEnsemble = grib.getLong("numberOfForecastsInEnsemble"); + misc.set("numberOfForecastsInEnsemble", numberOfForecastsInEnsemble); + } } catch (...) { std::throw_with_nested(Grib2MarsGenericException("Failed to extract MISC keywords", Here())); diff --git a/src/metkit/grib2mars/mappings/rules/number.h b/src/metkit/grib2mars/mappings/rules/number.h index 01e376dd0..550db7b88 100644 --- a/src/metkit/grib2mars/mappings/rules/number.h +++ b/src/metkit/grib2mars/mappings/rules/number.h @@ -15,68 +15,36 @@ void extractNumber(const std::string& keyword, const metkit::codes::CodesHandle& using metkit::grib2mars::utils::exceptions::Grib2MarsGenericException; try { - if (!grib.has("type")) { + if (!grib.has(keyword)) { throw Grib2MarsGenericException( - "Missing GRIB key `type` required to extract MARS keyword `" + keyword + "`", Here()); + "Missing GRIB key `" + keyword + "` required to extract MARS keyword `" + keyword + "`", Here()); } - const std::string type = grib.getString("type"); - - if (type == "es" || type == "em") { - if (!grib.has("numberOfForecastsInEnsemble")) { - throw Grib2MarsGenericException( - "Missing GRIB key `numberOfForecastsInEnsemble` required " - "for derived ensemble forecast", - Here()); - } + const long value = grib.getLong(keyword); + set_or_throw(mars, keyword, value); + if (grib.has("numberOfForecastsInEnsemble")) { const long numberOfForecastsInEnsemble = grib.getLong("numberOfForecastsInEnsemble"); - misc.set("numberOfForecastsInEnsemble", numberOfForecastsInEnsemble); - - return; - } - - if (!grib.has("number") || !grib.has("numberOfForecastsInEnsemble")) { - return; - } - - const long number = grib.getLong("number"); - const long numberOfForecastsInEnsemble = grib.getLong("numberOfForecastsInEnsemble"); - - if (number != 0 && numberOfForecastsInEnsemble == 0) { - throw Grib2MarsGenericException("The value for key `numberOfForecastsInEnsemble` must not be 0", Here()); - } - - if (numberOfForecastsInEnsemble == 0) { - return; - } - - set_or_throw(mars, keyword, number); - - misc.set("numberOfForecastsInEnsemble", numberOfForecastsInEnsemble); - - if (grib.has("class")) { - const std::string klass = grib.getString("class"); - - if (klass == "ai") { - // Handled in the encoder, matching the original tool logic. - return; + if (numberOfForecastsInEnsemble != 0) { + misc.set("numberOfForecastsInEnsemble", numberOfForecastsInEnsemble); + + if (grib.getString("class") != "ai") { + if (grib.has("typeOfEnsembleForecast")) { + const long typeOfEnsembleForecast = grib.getLong("typeOfEnsembleForecast"); + misc.set("typeOfEnsembleForecast", typeOfEnsembleForecast); + } + else if (grib.has("eps")) { + const long typeOfEnsembleForecast = grib.getLong("eps"); + misc.set("typeOfEnsembleForecast", typeOfEnsembleForecast); + } + } } } - - if (grib.has("typeOfEnsembleForecast")) { - const long typeOfEnsembleForecast = grib.getLong("typeOfEnsembleForecast"); - - misc.set("typeOfEnsembleForecast", typeOfEnsembleForecast); - - return; - } - - if (grib.has("eps")) { - const long eps = grib.getLong("eps"); - - misc.set("typeOfEnsembleForecast", eps); + else if (grib.getString("type") != "me") { + throw Grib2MarsGenericException( + "Missing GRIB key `numberOfForecastsInEnsemble` required to extract MARS keyword `" + keyword + "`", + Here()); } } catch (...) { diff --git a/src/metkit/grib2mars/mappings/rules/packing.h b/src/metkit/grib2mars/mappings/rules/packing.h index 98959bdff..a4d9dbb04 100644 --- a/src/metkit/grib2mars/mappings/rules/packing.h +++ b/src/metkit/grib2mars/mappings/rules/packing.h @@ -64,7 +64,7 @@ void extractPacking(const std::string& keyword, const metkit::codes::CodesHandle } if (grib.has("bitmapPresent")) { - const long bitmapPresent = grib.getLong("bitmapPresent"); + const bool bitmapPresent = grib.getLong("bitmapPresent") == 1; misc.set("bitmapPresent", bitmapPresent); } diff --git a/src/metkit/grib2mars/mappings/rules/step.h b/src/metkit/grib2mars/mappings/rules/step.h index faea378f8..3d287ad32 100644 --- a/src/metkit/grib2mars/mappings/rules/step.h +++ b/src/metkit/grib2mars/mappings/rules/step.h @@ -15,59 +15,35 @@ void extractStep(const std::string& keyword, const metkit::codes::CodesHandle& g using metkit::grib2mars::utils::exceptions::Grib2MarsGenericException; try { - if (!grib.has("stepType")) { - throw Grib2MarsGenericException( - "Missing GRIB key `stepType` required to extract MARS keyword `" + keyword + "`", Here()); - } - - if (!grib.has("endStep")) { - throw Grib2MarsGenericException( - "Missing GRIB key `endStep` required to extract MARS keyword `" + keyword + "`", Here()); - } + const bool isInstant = grib.getString("stepType") == "instant"; + const bool hasTimespan = grib.has("timespan"); - const std::string stepType = grib.getString("stepType"); - const long endStep = grib.getLong("endStep"); - - set_or_throw(mars, keyword, endStep); -#if 0 - if (stepType != "instant") { - if (!grib.has("startStep")) { + if (isInstant || hasTimespan) { + if (!grib.has("endStep")) { throw Grib2MarsGenericException( - "Missing GRIB key `startStep` required to extract " - "`timespan` for statistical GRIB message with stepType `" + - stepType + "`", - Here()); + "Missing GRIB key `endStep` required to extract MARS keyword `" + keyword + "`", Here()); } - const long startStep = grib.getLong("startStep"); - const long timespan = endStep - startStep; + const long endStep = grib.getLong("endStep"); - if (timespan == 0) { + set_or_throw(mars, keyword, endStep); + } + else { + if (!grib.has("startStep")) { throw Grib2MarsGenericException( - "Invalid zero statistical window while extracting `timespan`: " - "stepType=`" + - stepType + - "`, startStep=" + std::to_string(startStep) + - ", endStep=" + std::to_string(endStep), - Here()); + "Missing GRIB key `startStep` required to extract MARS keyword `" + keyword + "`", Here()); } - if (timespan < 0) { + if (!grib.has("endStep")) { throw Grib2MarsGenericException( - "Invalid negative statistical window while extracting `timespan`: " - "stepType=`" + - stepType + - "`, startStep=" + std::to_string(startStep) + - ", endStep=" + std::to_string(endStep), - Here()); + "Missing GRIB key `endStep` required to extract MARS keyword `" + keyword + "`", Here()); } - set_or_throw(mars, "timespan", timespan); - } -#endif - if (grib.has("initialStep")) { - const long initialStep = grib.getLong("initialStep"); - misc.set("initialStep", initialStep); + const long startStep = grib.getLong("startStep"); + const long endStep = grib.getLong("endStep"); + const std::string stepRange = std::to_string(startStep) + "-" + std::to_string(endStep); + + set_or_throw(mars, keyword, stepRange); } if (grib.has("timeIncrement")) { diff --git a/src/metkit/grib2mars/mappings/rules/truncation.h b/src/metkit/grib2mars/mappings/rules/truncation.h index 07a597fdb..6a5432610 100644 --- a/src/metkit/grib2mars/mappings/rules/truncation.h +++ b/src/metkit/grib2mars/mappings/rules/truncation.h @@ -39,12 +39,6 @@ void extractTruncation(const std::string& keyword, const metkit::codes::CodesHan const long truncation = grib.getLong("J"); set_or_throw(mars, keyword, truncation); - - if (grib.has("laplacianOperator")) { - const long laplacianOperator = grib.getLong("laplacianOperator"); - - misc.set("laplacianOperator", laplacianOperator); - } } catch (...) { std::throw_with_nested(Grib2MarsGenericException("Failed to extract MARS keyword `" + keyword + "`", Here())); diff --git a/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h b/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h index 65ffaaca9..e43695938 100644 --- a/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h +++ b/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h @@ -130,9 +130,9 @@ constexpr bool needLevel() { Variant == LevelType::HeightAboveSeaAt2M || Variant == LevelType::HeightAboveSea || Variant == LevelType::ModelSingleLevel || Variant == LevelType::ModelMultipleLevel || Variant == LevelType::IsobaricInHpa || Variant == LevelType::IsobaricInPa || - Variant == LevelType::Isothermal || Variant == LevelType::PotentialVorticity || - Variant == LevelType::Theta || Variant == LevelType::OceanModel || - Variant == LevelType::AbstractLevel || Variant == LevelType::FlightLevel) { + Variant == LevelType::PotentialVorticity || Variant == LevelType::Theta || + Variant == LevelType::OceanModel || Variant == LevelType::AbstractLevel || + Variant == LevelType::FlightLevel) { return true; } diff --git a/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h b/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h index 3320c9999..8a2182421 100644 --- a/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h +++ b/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h @@ -92,9 +92,6 @@ inline std::size_t matchSFC(const long param) { if (matchAny(param, 228007, 228011)) { return static_cast(LevelType::EntireLake); } - if (matchAny(param, 129172)) { - return static_cast(LevelType::HeightAboveGround); - } if (matchAny(param, 49, 123, 165, 166, 207, 228005, 228028, 228029, 228131, 228132, 235165, 235166, 237165, 237166, 237207, 237318, 238165, 238166, 238207, 239165, 239166, 239207, 260260)) { return static_cast(LevelType::HeightAboveGroundAt10M); @@ -172,26 +169,26 @@ inline std::size_t matchSFC(const long param) { if (matchAny(param, 8, 9, range(15, 18), 20, range(26, 45), 47, 50, 57, 58, 66, 67, 74, 129, 134, 139, range(141, 148), range(159, 163), 169, 170, range(172, 177), range(180, 182), 189, range(195, 198), 205, 210, 211, 213, range(228, 232), range(234, 236), range(238, 240), range(243, 245), 3020, 3062, - 3067, 3099, range(140098, 140105), 140112, 140113, range(140121, 140129), range(140131, 140134), - range(140207, 140209), 140211, 140212, range(140214, 140232), range(140234, 140239), 140244, - range(140246, 140248), range(140252, 140254), range(141101, 141105), 141208, 141209, 141215, - 141216, 141220, 141229, 141232, range(143101, 143105), 143208, 143209, 143215, 143216, 143220, - 143229, 143232, range(144101, 144105), 144208, 144209, 144215, 144216, 144220, 144229, 144232, - range(145101, 145105), 145208, 145209, 145215, 145216, 145220, 145229, 145232, 160198, - range(162100, 162113), 200199, range(210186, 210191), range(210198, 210202), range(210260, 210264), - range(222001, 222256), 228002, 228003, 228012, range(228015, 228022), 228024, 228026, 228027, - 228032, 228035, 228036, range(228046, 228048), 228051, 228053, range(228057, 228060), 228129, - 228130, 228141, 228143, 228144, range(228216, 228228), 228251, 229001, 229007, - range(231001, 231003), 231005, 231010, 231012, 231057, 231058, range(233000, 233031), 235020, - 235021, range(235029, 235031), range(235033, 235038), range(235041, 235043), 235048, 235051, - 235052, 235055, 235058, range(235078, 235080), 235083, 235084, 235093, 235134, 235159, 235189, - 235263, 235283, 235339, 237013, 237041, 237042, 237055, 237078, 237080, 237083, 237084, 237093, - 237117, 237134, 237159, 237263, 237321, 238013, 238041, 238042, 238055, 238078, 238080, 238083, - 238084, 238093, 238134, 238159, 238263, 239041, 239042, 239078, 239080, 239083, 239084, 239093, - 239134, 239159, 239263, 260004, 260005, 260015, 260038, 260048, 260109, 260121, 260123, 260255, - 260259, 260289, 260292, 260293, range(260318, 260321), 260338, 260339, 260509, 260682, 260683, - 260688, 261001, 261002, range(261014, 261016), 261018, 261023, 262000, 262100, 262124, 262139, - 262140, 262144)) { + 3067, 3099, 129172, range(140098, 140105), 140112, 140113, range(140121, 140129), + range(140131, 140134), range(140207, 140209), 140211, 140212, range(140214, 140232), + range(140234, 140239), 140244, range(140246, 140248), range(140252, 140254), range(141101, 141105), + 141208, 141209, 141215, 141216, 141220, 141229, 141232, range(143101, 143105), 143208, 143209, + 143215, 143216, 143220, 143229, 143232, range(144101, 144105), 144208, 144209, 144215, 144216, + 144220, 144229, 144232, range(145101, 145105), 145208, 145209, 145215, 145216, 145220, 145229, + 145232, 160198, range(162100, 162113), 200199, range(210186, 210191), range(210198, 210202), + range(210260, 210264), range(222001, 222256), 228002, 228003, 228012, range(228015, 228022), + 228024, 228026, 228027, 228032, 228035, 228036, range(228046, 228048), 228051, 228053, + range(228057, 228060), 228129, 228130, 228141, 228143, 228144, range(228216, 228228), 228251, + 229001, 229007, range(231001, 231003), 231005, 231010, 231012, 231057, 231058, + range(233000, 233031), 235020, 235021, range(235029, 235031), range(235033, 235038), + range(235041, 235043), 235048, 235051, 235052, 235055, 235058, range(235078, 235080), 235083, + 235084, 235093, 235134, 235159, 235189, 235263, 235283, 235339, 237013, 237041, 237042, 237055, + 237078, 237080, 237083, 237084, 237093, 237117, 237134, 237159, 237263, 237321, 238013, 238041, + 238042, 238055, 238078, 238080, 238083, 238084, 238093, 238134, 238159, 238263, 239041, 239042, + 239078, 239080, 239083, 239084, 239093, 239134, 239159, 239263, 260004, 260005, 260015, 260038, + 260048, 260109, 260121, 260123, 260255, 260259, 260289, 260292, 260293, range(260318, 260321), + 260338, 260339, 260509, 260682, 260683, 260688, 261001, 261002, range(261014, 261016), 261018, + 261023, 262000, 262100, 262124, 262139, 262140, 262144)) { return static_cast(LevelType::Surface); } // Strike-probability @@ -576,6 +573,7 @@ inline std::size_t matchO2D(const long param) { return static_cast(LevelType::OceanSurface); } if (matchAny(param, range(262102, 262106))) { + // Note: We assume that these fields already have the level encoded as soon as the paramId is set! return static_cast(LevelType::Isothermal); } if (matchAny(param, range(262113, 262115))) { diff --git a/src/metkit/mars2grib/backend/concepts/model-error/modelErrorEncoding.h b/src/metkit/mars2grib/backend/concepts/model-error/modelErrorEncoding.h index 57940521e..b1d5f7b00 100644 --- a/src/metkit/mars2grib/backend/concepts/model-error/modelErrorEncoding.h +++ b/src/metkit/mars2grib/backend/concepts/model-error/modelErrorEncoding.h @@ -49,8 +49,10 @@ // Deductions #include "metkit/mars2grib/backend/deductions/componentIndex.h" +#include "metkit/mars2grib/backend/deductions/fourierCoefficientIndex.h" #include "metkit/mars2grib/backend/deductions/modelErrorType.h" #include "metkit/mars2grib/backend/deductions/numberOfComponents.h" +#include "metkit/mars2grib/backend/deductions/numberOfFourierCoefficients.h" // checks #include "metkit/mars2grib/backend/checks/matchLocalDefinitionNumber.h" @@ -151,9 +153,9 @@ void ModelErrorOp(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& validation::match_LocalDefinitionNumber_or_throw(opt, out, {25L, 39L}); // Deductions - auto componentIndexVal = deductions::resolve_ComponentIndex_or_throw(mars, par, opt); - auto numberOfComponentsVal = deductions::resolve_NumberOfComponents_or_throw(mars, par, opt); - auto modelErrorTypeVal = deductions::resolve_ModelErrorType_or_throw(mars, par, opt); + const auto componentIndexVal = deductions::resolve_ComponentIndex_or_throw(mars, par, opt); + const auto numberOfComponentsVal = deductions::resolve_NumberOfComponents_or_throw(mars, par, opt); + const auto modelErrorTypeVal = deductions::resolve_ModelErrorType_or_throw(mars, par, opt); // Encoding set_or_throw(out, "componentIndex", componentIndexVal); @@ -163,7 +165,17 @@ void ModelErrorOp(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& else if (Variant == ModelErrorType::FourierCoefficients) { validation::match_LocalDefinitionNumber_or_throw(opt, out, {45L}); - MARS2GRIB_CONCEPT_THROW(modelError, "Variant not implemented..."); + // Deductions + const auto fourierCoefficientIndex = + deductions::resolve_FourierCoefficientIndex_or_throw(mars, par, opt); + const auto numberOfFourierCoefficients = + deductions::resolve_NumberOfFourierCoefficients_or_throw(mars, par, opt); + const auto modelErrorTypeVal = deductions::resolve_ModelErrorType_or_throw(mars, par, opt); + + // Encoding + set_or_throw(out, "fourierCoefficientIndex", fourierCoefficientIndex); + set_or_throw(out, "numberOfFourierCoefficients", numberOfFourierCoefficients); + set_or_throw(out, "modelErrorType", modelErrorTypeVal); } else { MARS2GRIB_CONCEPT_THROW(modelError, "Unknown variant..."); diff --git a/src/metkit/mars2grib/backend/concepts/model-error/modelErrorMatcher.h b/src/metkit/mars2grib/backend/concepts/model-error/modelErrorMatcher.h index abd5e28f3..404cf4a8f 100644 --- a/src/metkit/mars2grib/backend/concepts/model-error/modelErrorMatcher.h +++ b/src/metkit/mars2grib/backend/concepts/model-error/modelErrorMatcher.h @@ -63,15 +63,15 @@ std::size_t modelErrorMatcher(const MarsDict_t& mars, const OptDict_t& opt) { return compile_time_registry_engine::MISSING; } + if (has(mars, "coeffindex")) { + return static_cast(ModelErrorType::FourierCoefficients); + } + // At this point the request is a model-error request: "number" is mandatory if (has(mars, "number")) { return static_cast(ModelErrorType::ComponentIndex); } - if (has(mars, "coeffindex")) { - return static_cast(ModelErrorType::FourierCoefficients); - } - return compile_time_registry_engine::MISSING; } catch (...) { diff --git a/src/metkit/mars2grib/backend/concepts/packing/packingEncoding.h b/src/metkit/mars2grib/backend/concepts/packing/packingEncoding.h index 18cd8491d..e2dc81d2b 100644 --- a/src/metkit/mars2grib/backend/concepts/packing/packingEncoding.h +++ b/src/metkit/mars2grib/backend/concepts/packing/packingEncoding.h @@ -55,7 +55,6 @@ // Deductions #include "metkit/mars2grib/backend/deductions/bitsPerValue.h" -#include "metkit/mars2grib/backend/deductions/laplacianOperator.h" #include "metkit/mars2grib/backend/deductions/subSetTrunc.h" // Utils @@ -188,9 +187,7 @@ void PackingOp(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& op long bitsPerValue = deductions::resolve_BitsPerValueSpectral_or_throw(mars, par, opt); set_or_throw(out, "bitsPerValue", bitsPerValue); - // double laplacianOperator = deductions::resolve_LaplacianOperator_or_throw(mars, par, opt); long subSetTruncation = deductions::resolve_SubSetTruncation_or_throw(mars, par, opt); - // set_or_throw(out, "laplacianOperator", laplacianOperator); set_or_throw(out, "subSetJ", subSetTruncation); set_or_throw(out, "subSetK", subSetTruncation); set_or_throw(out, "subSetM", subSetTruncation); diff --git a/src/metkit/mars2grib/backend/deductions/bitsPerValue.h b/src/metkit/mars2grib/backend/deductions/bitsPerValue.h index d990d9406..cec0e789e 100644 --- a/src/metkit/mars2grib/backend/deductions/bitsPerValue.h +++ b/src/metkit/mars2grib/backend/deductions/bitsPerValue.h @@ -51,7 +51,6 @@ /// - @ref packingEncoding.h /// /// Related deductions: -/// - @ref laplacianOperator.h /// - @ref subSetTrunc.h /// /// @ingroup mars2grib_backend_deductions diff --git a/src/metkit/mars2grib/backend/deductions/fourierCoefficientIndex.h b/src/metkit/mars2grib/backend/deductions/fourierCoefficientIndex.h new file mode 100644 index 000000000..03e7fb8e2 --- /dev/null +++ b/src/metkit/mars2grib/backend/deductions/fourierCoefficientIndex.h @@ -0,0 +1,147 @@ +/* + * (C) Copyright 2026- ECMWF and individual contributors. + * + * 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 fourierCoefficientIndex.h +/// @brief Deduction of the fourier coefficient index. +/// +/// This header defines deduction utilities used by the mars2grib backend +/// to resolve the **fourier coefficient index** (`fourierCoefficientIndex`) +/// from MARS metadata. +/// +/// The deduction retrieves the coefficient index explicitly from the MARS +/// dictionary (key `coeffindex`) and returns it verbatim, without applying +/// inference, defaulting, or semantic interpretation. +/// +/// Deductions are responsible for: +/// - extracting values from MARS, parameter, and option dictionaries +/// - enforcing deterministic resolution rules +/// - returning strongly typed values to concept operations +/// +/// Deductions: +/// - do NOT encode GRIB keys directly +/// - do NOT apply heuristic or data-driven inference +/// - do NOT validate against GRIB code tables unless explicitly required +/// +/// Error handling follows a strict fail-fast strategy: +/// - missing or invalid inputs cause immediate failure +/// - errors are reported using domain-specific deduction exceptions +/// - original errors are preserved via nested exception propagation +/// +/// Logging follows the mars2grib deduction policy: +/// - RESOLVE: value resolved directly from input dictionaries +/// +/// @section References +/// Concept: +/// - @ref modelErrorEncoding.h +/// +/// Related deductions: +/// - @ref numberOfFourierCoefficients.h +/// - @ref modelErrorType.h +/// +/// @ingroup mars2grib_backend_deductions +/// + +#pragma once + +#include + +#include "eckit/log/Log.h" +#include "metkit/mars2grib/utils/generalUtils.h" + +#include "metkit/config/LibMetkit.h" +#include "metkit/mars2grib/utils/logUtils.h" +#include "metkit/mars2grib/utils/mars2gribExceptions.h" + +namespace metkit::mars2grib::backend::deductions { + +/// +/// @brief Resolve the fourier coefficient index. +/// +/// @section Deduction contract +/// - Reads: `mars["coeffindex"]` +/// - Writes: none +/// - Side effects: logging (RESOLVE) +/// - Failure mode: throws +/// +/// This deduction retrieves the fourier coefficient index from the +/// MARS dictionary. For model-error Fourier-coefficients products, the +/// MARS key `coeffindex` identifies the Fourier coefficient encoded in +/// the field. +/// +/// The value is treated as mandatory and is returned verbatim as a +/// numeric identifier. No inference, defaulting, or validation against +/// GRIB code tables is performed. +/// +/// @tparam MarsDict_t +/// Type of the MARS dictionary. Must provide the key `coeffindex`. +/// +/// @tparam ParDict_t +/// Type of the parameter dictionary (unused). +/// +/// @tparam OptDict_t +/// Type of the options dictionary (unused). +/// +/// @param[in] mars +/// MARS dictionary from which the fourier coefficient index is +/// retrieved. +/// +/// @param[in] par +/// Parameter dictionary (unused). +/// +/// @param[in] opt +/// Options dictionary (unused). +/// +/// @return +/// The fourier coefficient index. +/// +/// @throws metkit::mars2grib::utils::exceptions::Mars2GribDeductionException +/// If the key `coeffindex` is missing from the MARS dictionary, cannot +/// be converted to `long`, or if any unexpected error occurs during +/// deduction. +/// +/// @note +/// This deduction does not infer or default the value. Absence of the +/// key in the MARS dictionary is considered a contract violation by +/// the upstream tool. +/// +template +long resolve_FourierCoefficientIndex_or_throw(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& opt) { + + using metkit::mars2grib::utils::dict_traits::get_or_throw; + using metkit::mars2grib::utils::exceptions::Mars2GribDeductionException; + + try { + + // Retrieve MARS coeffindex (fourier coefficient index) + long fourierCoefficientIndex = get_or_throw(mars, "coeffindex"); + + // Emit RESOLVE log entry + MARS2GRIB_LOG_RESOLVE([&]() { + std::string logMsg = "`fourierCoefficientIndex` resolved from input dictionaries: value="; + logMsg += std::to_string(fourierCoefficientIndex); + return logMsg; + }()); + + // Success exit point + return fourierCoefficientIndex; + } + catch (...) { + + // Rethrow nested exceptions + std::throw_with_nested( + Mars2GribDeductionException("Failed to resolve `fourierCoefficientIndex` from input dictionaries", Here())); + }; + + // Remove compiler warning + mars2gribUnreachable(); +}; + +} // namespace metkit::mars2grib::backend::deductions diff --git a/src/metkit/mars2grib/backend/deductions/laplacianOperator.h b/src/metkit/mars2grib/backend/deductions/laplacianOperator.h deleted file mode 100644 index 0a098e224..000000000 --- a/src/metkit/mars2grib/backend/deductions/laplacianOperator.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * (C) Copyright 2025- ECMWF and individual contributors. - * - * 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 laplacianOperator.h -/// @brief Deduction of the Laplacian operator coefficient. -/// -/// This header defines deduction utilities used by the mars2grib backend -/// to resolve the **Laplacian operator coefficient** from the parameter -/// dictionary. -/// -/// The deduction retrieves the coefficient explicitly from user-provided -/// parameters and exposes it to the encoding layer without transformation -/// or interpretation. -/// -/// Deductions are responsible for: -/// - extracting values from MARS, parameter, and option dictionaries -/// - applying minimal, explicit deduction logic -/// - returning strongly typed values to concept operations -/// -/// Deductions: -/// - do NOT encode GRIB keys directly -/// - do NOT apply inference or defaulting -/// - do NOT perform GRIB table validation -/// -/// Error handling follows a strict fail-fast strategy: -/// - missing or malformed inputs cause immediate failure -/// - errors are reported using domain-specific deduction exceptions -/// - original errors are preserved via nested exception propagation -/// -/// Logging follows the mars2grib deduction policy: -/// - RESOLVE: value derived via deduction logic from input dictionaries -/// - OVERRIDE: value provided by parameter dictionary overriding deduction logic -/// -/// @section References -/// Concept: -/// - @ref packingEncoding.h -/// -/// Related deductions: -/// - @ref bitsPerValue.h -/// - @ref subSetTrunc.h -/// -/// @ingroup mars2grib_backend_deductions -/// -#pragma once - -// System includes -#include - -// Core deduction includes -#include "metkit/config/LibMetkit.h" -#include "metkit/mars2grib/utils/generalUtils.h" -#include "metkit/mars2grib/utils/logUtils.h" -#include "metkit/mars2grib/utils/mars2gribExceptions.h" - -namespace metkit::mars2grib::backend::deductions { - -/// -/// @brief Resolve the Laplacian operator coefficient from input dictionaries. -/// -/// @section Deduction contract -/// - Reads: `par["laplacianOperator"]` -/// - Writes: none -/// - Side effects: logging (RESOLVE) -/// - Failure mode: throws -/// -/// This deduction resolves the Laplacian operator coefficient by retrieving -/// the mandatory parameter dictionary key `laplacianOperator` and returning -/// its value as a `double`. -/// -/// The value is taken verbatim from the parameter dictionary and overrides -/// any implicit or default behavior. No validation beyond type conversion -/// is performed. -/// -/// @tparam MarsDict_t -/// Type of the MARS dictionary (unused by this deduction). -/// -/// @tparam ParDict_t -/// Type of the parameter dictionary. Must support keyed access to -/// `laplacianOperator` and conversion to `double`. -/// -/// @tparam OptDict_t -/// Type of the options dictionary (unused by this deduction). -/// -/// @param[in] mars -/// MARS dictionary (unused). -/// -/// @param[in] par -/// Parameter dictionary from which the Laplacian operator coefficient -/// is resolved. -/// -/// @param[in] opt -/// Options dictionary (unused). -/// -/// @return -/// The resolved Laplacian operator coefficient. -/// -/// @throws metkit::mars2grib::utils::exceptions::Mars2GribDeductionException -/// If the key `laplacianOperator` is missing, cannot be converted to -/// `double`, or if any unexpected error occurs during deduction. -/// -template -double resolve_LaplacianOperator_or_throw(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& opt) { - - using metkit::mars2grib::utils::dict_traits::get_or_throw; - using metkit::mars2grib::utils::exceptions::Mars2GribDeductionException; - - try { - - // Retrieve mandatory Laplacian operator coefficient - double laplacianOperator = get_or_throw(par, "laplacianOperator"); - - // Emit RESOLVE log entry - MARS2GRIB_LOG_RESOLVE([&]() { - std::string logMsg = "`laplacianOperator` resolved from input dictionaries: value='"; - logMsg += std::to_string(laplacianOperator); - logMsg += "'"; - return logMsg; - }()); - - // Success exit point - return laplacianOperator; - } - catch (...) { - - // Rethrow nested exceptions - std::throw_with_nested( - Mars2GribDeductionException("Failed to resolve `laplacianOperator` from input dictionaries", Here())); - }; - - // Remove compiler warning - mars2gribUnreachable(); -}; - -} // namespace metkit::mars2grib::backend::deductions diff --git a/src/metkit/mars2grib/backend/deductions/numberOfFourierCoefficients.h b/src/metkit/mars2grib/backend/deductions/numberOfFourierCoefficients.h new file mode 100644 index 000000000..211fab947 --- /dev/null +++ b/src/metkit/mars2grib/backend/deductions/numberOfFourierCoefficients.h @@ -0,0 +1,147 @@ +/* + * (C) Copyright 2026- ECMWF and individual contributors. + * + * 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 numberOfFourierCoefficients.h +/// @brief Deduction of the total number of Fourier coefficients. +/// +/// This header defines deduction utilities used by the mars2grib backend +/// to resolve the **total number of Fourier coefficients** +/// (`numberOfFourierCoefficients`) from the parameter dictionary. +/// +/// The value is not derivable from MARS alone. It must be supplied via +/// the parameter dictionary by the upstream tool, typically read from +/// the input GRIB1 handle being re-encoded. +/// +/// Deductions are responsible for: +/// - extracting values from MARS, parameter, and option dictionaries +/// - enforcing deterministic resolution rules +/// - returning strongly typed values to concept operations +/// +/// Deductions: +/// - do NOT encode GRIB keys directly +/// - do NOT apply heuristic or data-driven inference +/// - do NOT validate against GRIB code tables unless explicitly required +/// +/// Error handling follows a strict fail-fast strategy: +/// - missing or invalid inputs cause immediate failure +/// - errors are reported using domain-specific deduction exceptions +/// - original errors are preserved via nested exception propagation +/// +/// Logging follows the mars2grib deduction policy: +/// - RESOLVE: value resolved directly from input dictionaries +/// +/// @section References +/// Concept: +/// - @ref modelErrorEncoding.h +/// +/// Related deductions: +/// - @ref fourierCoefficientIndex.h +/// - @ref modelErrorType.h +/// +/// @ingroup mars2grib_backend_deductions +/// + +#pragma once + +#include + +#include "eckit/log/Log.h" +#include "metkit/mars2grib/utils/generalUtils.h" + +#include "metkit/config/LibMetkit.h" +#include "metkit/mars2grib/utils/logUtils.h" +#include "metkit/mars2grib/utils/mars2gribExceptions.h" + +namespace metkit::mars2grib::backend::deductions { + +/// +/// @brief Resolve the total number of Fourier coefficients. +/// +/// @section Deduction contract +/// - Reads: `par["numberOfFourierCoefficients"]` +/// - Writes: none +/// - Side effects: logging (RESOLVE) +/// - Failure mode: throws +/// +/// This deduction retrieves the total number of Fourier coefficients +/// from the parameter dictionary. +/// +/// The value is treated as mandatory: it cannot be derived from MARS +/// metadata alone and must be supplied by the upstream tool that +/// populates the parameter dictionary (typically read from the input +/// GRIB1 handle being re-encoded). +/// +/// @tparam MarsDict_t +/// Type of the MARS dictionary (unused). +/// +/// @tparam ParDict_t +/// Type of the parameter dictionary. Must provide the key +/// `numberOfFourierCoefficients`. +/// +/// @tparam OptDict_t +/// Type of the options dictionary (unused). +/// +/// @param[in] mars +/// MARS dictionary (unused). +/// +/// @param[in] par +/// Parameter dictionary from which the total number of Fourier +/// coefficients is retrieved. +/// +/// @param[in] opt +/// Options dictionary (unused). +/// +/// @return +/// The total number of Fourier coefficients. +/// +/// @throws metkit::mars2grib::utils::exceptions::Mars2GribDeductionException +/// If the key `numberOfFourierCoefficients` is missing from the parameter +/// dictionary, cannot be converted to `long`, or if any unexpected error +/// occurs during deduction. +/// +/// @note +/// This deduction does not infer or default the value. Absence of the +/// key in the parameter dictionary is considered a contract violation +/// by the upstream tool. +/// +template +long resolve_NumberOfFourierCoefficients_or_throw(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& opt) { + + using metkit::mars2grib::utils::dict_traits::get_or_throw; + using metkit::mars2grib::utils::exceptions::Mars2GribDeductionException; + + try { + + // Retrieve mandatory parameter-dictionary numberOfFourierCoefficients + long numberOfFourierCoefficients = get_or_throw(par, "numberOfFourierCoefficients"); + + // Emit RESOLVE log entry + MARS2GRIB_LOG_RESOLVE([&]() { + std::string logMsg = "`numberOfFourierCoefficients` resolved from input dictionaries: value="; + logMsg += std::to_string(numberOfFourierCoefficients); + return logMsg; + }()); + + // Success exit point + return numberOfFourierCoefficients; + } + catch (...) { + + // Rethrow nested exceptions + std::throw_with_nested(Mars2GribDeductionException( + "Failed to resolve `numberOfFourierCoefficients` from input dictionaries", Here())); + }; + + // Remove compiler warning + mars2gribUnreachable(); +}; + +} // namespace metkit::mars2grib::backend::deductions diff --git a/src/metkit/mars2grib/backend/deductions/subSetTrunc.h b/src/metkit/mars2grib/backend/deductions/subSetTrunc.h index 4ec09d933..8ef6063ce 100644 --- a/src/metkit/mars2grib/backend/deductions/subSetTrunc.h +++ b/src/metkit/mars2grib/backend/deductions/subSetTrunc.h @@ -37,7 +37,6 @@ /// /// Related deductions: /// - @ref bitsPerValue.h -/// - @ref laplacianOperator.h /// /// @ingroup mars2grib_backend_deductions /// diff --git a/src/metkit/mars2grib/backend/encodeValues.h b/src/metkit/mars2grib/backend/encodeValues.h index cf02e7163..ffded3c8f 100644 --- a/src/metkit/mars2grib/backend/encodeValues.h +++ b/src/metkit/mars2grib/backend/encodeValues.h @@ -91,6 +91,8 @@ template void encodeValues(Span values, const MiscDict_t& misc, const OptDict_t& opt, OutDict_t& handle) { using metkit::mars2grib::utils::dict_traits::get_opt; + using metkit::mars2grib::utils::dict_traits::get_or_throw; + using metkit::mars2grib::utils::dict_traits::has; using metkit::mars2grib::utils::dict_traits::set_or_throw; using metkit::mars2grib::utils::exceptions::Mars2GribGenericException; @@ -126,6 +128,17 @@ void encodeValues(Span values, const MiscDict_t& misc, const OptDic set_or_throw(handle, "values", Span{dValues}); } + + // 3. Set operation(s) to be applied on the values + if (has(misc, "scaleValuesBy")) { + const double scaleValuesBy = get_or_throw(misc, "scaleValuesBy"); + set_or_throw(handle, "scaleValuesBy", scaleValuesBy); + } + + if (has(misc, "offsetValuesBy")) { + const double offsetValuesBy = get_or_throw(misc, "offsetValuesBy"); + set_or_throw(handle, "offsetValuesBy", offsetValuesBy); + } } catch (...) { std::throw_with_nested(Mars2GribGenericException("Critical failure in SpecializedEncoder execution", Here())); @@ -181,6 +194,7 @@ void encodeValuesGridSpec(Span values, const MarsDict_t& mars, cons using metkit::mars2grib::utils::dict_traits::get_opt; using metkit::mars2grib::utils::dict_traits::get_or_throw; + using metkit::mars2grib::utils::dict_traits::has; using metkit::mars2grib::utils::dict_traits::set_or_throw; using metkit::mars2grib::utils::exceptions::Mars2GribGenericException; @@ -222,6 +236,17 @@ void encodeValuesGridSpec(Span values, const MarsDict_t& mars, cons set_or_throw(handle, "values", Span{dValues}); } + + // 3. Set operation(s) to be applied on the values + if (has(misc, "scaleValuesBy")) { + const double scaleValuesBy = get_or_throw(misc, "scaleValuesBy"); + set_or_throw(handle, "scaleValuesBy", scaleValuesBy); + } + + if (has(misc, "offsetValuesBy")) { + const double offsetValuesBy = get_or_throw(misc, "offsetValuesBy"); + set_or_throw(handle, "offsetValuesBy", offsetValuesBy); + } } catch (...) { std::throw_with_nested(Mars2GribGenericException("Critical failure in SpecializedEncoder execution", Here())); diff --git a/src/metkit/mars2grib/backend/sections/initializers/sectionRegistry.h b/src/metkit/mars2grib/backend/sections/initializers/sectionRegistry.h index b6a4c66cf..d5eac901e 100644 --- a/src/metkit/mars2grib/backend/sections/initializers/sectionRegistry.h +++ b/src/metkit/mars2grib/backend/sections/initializers/sectionRegistry.h @@ -84,6 +84,7 @@ inline constexpr Entry Sec2Reg[] = {37, &allocateTemplateNumber2<2, 37, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, {38, &allocateTemplateNumber2<2, 38, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, {39, &allocateTemplateNumber2<2, 39, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, + {45, &allocateTemplateNumber2<2, 45, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, {1000, &allocateTemplateNumber2<2, 1000, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, {1001, &allocateTemplateNumber2<2, 1001, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, {1002, &allocateTemplateNumber2<2, 1002, MarsDict_t, ParDict_t, OptDict_t, OutDict_t>}, diff --git a/src/metkit/mars2grib/docs/doxygen/mars2grib.config.in b/src/metkit/mars2grib/docs/doxygen/mars2grib.config.in index b8abf04c7..9a3addcb6 100644 --- a/src/metkit/mars2grib/docs/doxygen/mars2grib.config.in +++ b/src/metkit/mars2grib/docs/doxygen/mars2grib.config.in @@ -1139,7 +1139,6 @@ INPUT = \@MARS2GRIB_SOURCE_DIRECTORY@/utils/configConverter.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/class.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/subSetTrunc.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/timeIncrementInSeconds.h \ -@MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/laplacianOperator.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/channel.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/chemId.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/firstWavelength.h \ @@ -1157,6 +1156,8 @@ INPUT = \@MARS2GRIB_SOURCE_DIRECTORY@/utils/configConverter.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/numberOfFrequencies.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/type.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/satelliteNumber.h \ +@MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/fourierCoefficientIndex.h \ +@MARS2GRIB_SOURCE_DIRECTORY@/backend/deductions/numberOfFourierCoefficients.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/checks/matchDataRepresentationTemplateNumber.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/checks/matchProductDefinitionTemplateNumber.h \ @MARS2GRIB_SOURCE_DIRECTORY@/backend/checks/checkLocalUseSection.h \ diff --git a/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section2Recipes.h b/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section2Recipes.h index 56a5be063..6ec2ca6d8 100644 --- a/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section2Recipes.h +++ b/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section2Recipes.h @@ -46,11 +46,11 @@ inline const Recipe S2_R24 = Select >(); -// Model-error products +// 4DVar model errors inline const Recipe S2_R25 = make_recipe<25, Select, - Select + Select >(); // Analysis-related products @@ -84,12 +84,20 @@ inline const Recipe S2_R38 = Select >(); -// Analysis model-error products +// 4DVar model errors for long window 4Dvar system inline const Recipe S2_R39 = make_recipe<39, Select, Select, - Select + Select + >(); + +// Model error fourier coefficients +// Note: Template 45 has the analysis concept, but it's unused (and unmatched) for stream oper +inline const Recipe S2_R45 = + make_recipe<45, + Select, + Select >(); //------------------------------------------------------------------------------ @@ -133,6 +141,7 @@ inline const Recipes Section2Recipes{ 2, &S2_R37B, &S2_R38, &S2_R39, + &S2_R45, &S2_R1001, &S2_R1002 } diff --git a/src/metkit/mars2mars/mappings/mappings.h b/src/metkit/mars2mars/mappings/mappings.h index c856fb857..d6ad5137f 100644 --- a/src/metkit/mars2mars/mappings/mappings.h +++ b/src/metkit/mars2mars/mappings/mappings.h @@ -14,17 +14,19 @@ #pragma once #include "metkit/mars2mars/mappings/Mars2MarsReturnValue.h" -#include "metkit/mars2mars/mappings/rules/wave2oper.h" +#include "metkit/mars2mars/mappings/rules/removeNumber.h" #include "metkit/mars2mars/utils/dictionary_traits/dictionary_access_traits.h" #include "metkit/mars2mars/utils/mars2marsExceptions.h" // All the rules #include "metkit/mars2mars/mappings/rules/chemical.h" #include "metkit/mars2mars/mappings/rules/ecc-1806.h" +#include "metkit/mars2mars/mappings/rules/incremental.h" #include "metkit/mars2mars/mappings/rules/local2wmo.h" +#include "metkit/mars2mars/mappings/rules/misc-params.h" #include "metkit/mars2mars/mappings/rules/sfc2sol.h" #include "metkit/mars2mars/mappings/rules/timespan.h" -#include "metkit/mars2mars/mappings/rules/wave2oper.h" +#include "metkit/mars2mars/mappings/rules/waveStreams.h" #include "metkit/mars2mars/mappings/rules/windspeed.h" namespace metkit::mars2mars::rules { @@ -41,13 +43,16 @@ Mars2MarsResult convertAll(const InDict_t& in) { std::unique_ptr misc = std::make_unique(); // Apply all conversions in sequence - impl::convertWave2Oper(in, *out, *misc); + impl::convertWaveStreams(in, *out, *misc); impl::convertECC1806(in, *out, *misc); impl::convertSFC2SOL(in, *out, *misc); impl::convertLocal2WMO(in, *out, *misc); impl::fixTimespan(in, *out, *misc); impl::fixWindspeed(in, *out, *misc); impl::convertChemical(in, *out, *misc); + impl::convertIncremental(in, *out, *misc); + impl::convertMiscParams(in, *out, *misc); + impl::removeNumber(in, *out, *misc); return Mars2MarsResult{std::move(*out), std::move(*misc)}; } diff --git a/src/metkit/mars2mars/mappings/rules/incremental.h b/src/metkit/mars2mars/mappings/rules/incremental.h new file mode 100644 index 000000000..afd6dc038 --- /dev/null +++ b/src/metkit/mars2mars/mappings/rules/incremental.h @@ -0,0 +1,70 @@ +/* + * (C) Copyright 2026- ECMWF and individual contributors. + * + * 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 incremental.h +/// @brief Conversion rules used by the mars2mars mapper. +#pragma once + +#include +#include "eckit/config/LocalConfiguration.h" +#include "metkit/mars2mars/utils/dictionary_traits/dictionary_access_traits.h" +#include "metkit/mars2mars/utils/mars2marsExceptions.h" + +namespace metkit::mars2mars::rules::impl { + + +/// @brief Convert incremental fields +template +inline void convertIncremental(const InDict_t& in, OutDict_t& out, eckit::LocalConfiguration& misc) { + + using metkit::mars2mars::utils::dict_traits::get_or_throw; + using metkit::mars2mars::utils::dict_traits::set_or_throw; + using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; + + try { + const auto param = get_or_throw(in, "param"); + switch (param) { + case 200130: + set_or_throw(out, "param", 130); + break; + + case 200133: + set_or_throw(out, "param", 133); + break; + + case 200138: + set_or_throw(out, "param", 138); + break; + + case 200152: + set_or_throw(out, "param", 152); + break; + + case 200155: + set_or_throw(out, "param", 155); + break; + + case 200203: + set_or_throw(out, "param", 203); + break; + + default: + break; + } + } + catch (...) { + // Rethrow nested exceptions + std::throw_with_nested( + Mars2marsGenericException("Failed to convert input dictionary in convertIncremental", Here())); + } +} + +} // namespace metkit::mars2mars::rules::impl diff --git a/src/metkit/mars2mars/mappings/rules/local2wmo.h b/src/metkit/mars2mars/mappings/rules/local2wmo.h index 729e56c34..2037c3203 100644 --- a/src/metkit/mars2mars/mappings/rules/local2wmo.h +++ b/src/metkit/mars2mars/mappings/rules/local2wmo.h @@ -24,14 +24,14 @@ namespace metkit::mars2mars::rules::impl { /// @brief Assign `param`, and `scaleFactor` together. template -inline void setParamScale(OutDict_t& out, eckit::LocalConfiguration& misc, long param, double scaleFactor) { +inline void setParamScale(OutDict_t& out, eckit::LocalConfiguration& misc, long param, double scaleValuesBy) { using metkit::mars2mars::utils::dict_traits::set_or_throw; using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; try { set_or_throw(out, "param", param); - set_or_throw(misc, "scaleFactor", scaleFactor); + set_or_throw(misc, "scaleValuesBy", scaleValuesBy); } catch (...) { // Rethrow nested exceptions @@ -83,7 +83,7 @@ inline void convertLocal2WMO(const InDict_t& in, OutDict_t& out, eckit::LocalCon case 9: return setParamScale(out, misc, 231012, 1000.0); case 141: - return setParamScale(out, misc, 231141, 1000.0); + return setParamScale(out, misc, 228141, 1000.0); case 142: return setParamScale(out, misc, 3062, 1000.0); case 182: diff --git a/src/metkit/mars2mars/mappings/rules/misc-params.h b/src/metkit/mars2mars/mappings/rules/misc-params.h new file mode 100644 index 000000000..cc468b033 --- /dev/null +++ b/src/metkit/mars2mars/mappings/rules/misc-params.h @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2026- ECMWF and individual contributors. + * + * 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 misc-params.h +/// @brief Conversion rules used by the mars2mars mapper. +#pragma once + +#include "eckit/config/LocalConfiguration.h" +#include "metkit/mars2mars/utils/dictionary_traits/dictionary_access_traits.h" +#include "metkit/mars2mars/utils/mars2marsExceptions.h" + +namespace metkit::mars2mars::rules::impl { + + +/// @brief Convert miscellaneous params +template +inline void convertMiscParams(const InDict_t& in, OutDict_t& out, eckit::LocalConfiguration& misc) { + + using metkit::mars2mars::utils::dict_traits::get_or_throw; + using metkit::mars2mars::utils::dict_traits::set_or_throw; + using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; + + try { + const auto param = get_or_throw(in, "param"); + + switch (param) { + case 151130: // Practical salinity (psu to g/kg) + set_or_throw(out, "param", 262100); + break; + + case 151131: // Eastward surface sea water velocity (m/s) + set_or_throw(out, "param", 262140); + break; + + case 151145: // Sea surface height (m) + set_or_throw(out, "param", 262124); + break; + + case 151148: // Mixed layer depth (m) + set_or_throw(out, "param", 3067); + break; + + case 151164: // Average potential temperature in the upper 300m (deg' C to K) + set_or_throw(out, "param", 262144); + misc.set("offsetValuesBy", 273.15); + break; + + case 151175: // Average sea water practical salinity in the upper 300m (psu to g/kg) + set_or_throw(out, "param", 262118); + break; + + default: + break; + } + } + catch (...) { + // Rethrow nested exceptions + std::throw_with_nested( + Mars2marsGenericException("Failed to convert input dictionary in convertMiscParams", Here())); + } +} + +} // namespace metkit::mars2mars::rules::impl diff --git a/src/metkit/mars2mars/mappings/rules/removeNumber.h b/src/metkit/mars2mars/mappings/rules/removeNumber.h new file mode 100644 index 000000000..74e7f5648 --- /dev/null +++ b/src/metkit/mars2mars/mappings/rules/removeNumber.h @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2026- ECMWF and individual contributors. + * + * 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 removeNumber.h +/// @brief Conversion rules used by the mars2mars mapper. +#pragma once + +#include +#include "eckit/config/LocalConfiguration.h" +#include "metkit/mars2mars/utils/dictionary_traits/dictionary_access_traits.h" +#include "metkit/mars2mars/utils/mars2marsExceptions.h" + +namespace metkit::mars2mars::rules::impl { + + +/// @brief Remove MARS key number if no longer used +template +inline void removeNumber(const InDict_t& in, OutDict_t& out, eckit::LocalConfiguration& misc) { + + using metkit::mars2mars::utils::dict_traits::get_or_throw; + using metkit::mars2mars::utils::dict_traits::setMissing_or_throw; + using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; + + try { + if (get_or_throw(in, "type") == "me") { + setMissing_or_throw(out, "number"); + } + } + catch (...) { + // Rethrow nested exceptions + std::throw_with_nested(Mars2marsGenericException("Failed to convert input dictionary in removeNumber", Here())); + } +} + +} // namespace metkit::mars2mars::rules::impl diff --git a/src/metkit/mars2mars/mappings/rules/timespan.h b/src/metkit/mars2mars/mappings/rules/timespan.h index 93e1b1a6c..8d7b86544 100644 --- a/src/metkit/mars2mars/mappings/rules/timespan.h +++ b/src/metkit/mars2mars/mappings/rules/timespan.h @@ -13,6 +13,12 @@ /// @brief Conversion rules used by the mars2mars mapper. #pragma once +#include +#include +#include +#include +#include + #include "eckit/config/LocalConfiguration.h" #include "metkit/mars2mars/mappings/Mars2MarsReturnValue.h" #include "metkit/mars2mars/mappings/rules/common.h" @@ -40,6 +46,106 @@ inline void setParamTimespan(OutDict_t& out, long param, const std::string& time } } +/// @brief Detect a `step` of the form "-" and rewrite +/// `step` + `timespan` on `out`. When `step` is a single value, default the +/// output `timespan` to "none" if it is not already set on `in`. +template +inline void convertStepRangeToTimespan(const InDict_t& in, OutDict_t& out) { + using metkit::mars2mars::utils::dict_traits::get_or_throw; + using metkit::mars2mars::utils::dict_traits::has; + using metkit::mars2mars::utils::dict_traits::set_or_throw; + using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; + + try { + + if (!has(in, "step")) { + return; + } + + const std::string step = has(in, "step") ? std::to_string(get_or_throw(in, "step")) + : get_or_throw(in, "step"); + + // Strict range detection: "-" + const auto dash = step.find('-'); + const auto isAllDigits = [](std::string_view v) { + return !v.empty() && std::all_of(v.begin(), v.end(), [](unsigned char c) { return std::isdigit(c) != 0; }); + }; + const bool isRange = dash != std::string::npos && step.find('-', dash + 1) == std::string::npos && + isAllDigits(std::string_view{step.data(), dash}) && + isAllDigits(std::string_view{step.data() + dash + 1, step.size() - dash - 1}); + + if (!isRange) { + // Single-value step: leave step untouched. Default timespan to + // "none" only when the input has no timespan yet. + if (!has(in, "timespan")) { + set_or_throw(out, "timespan", "none"); + } + return; + } + + const long startStep = std::stol(std::string(step, 0, dash)); + const long endStep = std::stol(std::string(step, dash + 1)); + + if (endStep < startStep) { + throw Mars2marsGenericException("Invalid step range `" + step + "`: endStep < startStep (" + + std::to_string(endStep) + " < " + std::to_string(startStep) + ")", + Here()); + } + + if (endStep == startStep && endStep != 0) { + throw Mars2marsGenericException("Invalid step range `" + step + "`: endStep == startStep (" + + std::to_string(endStep) + " == " + std::to_string(startStep) + + ") is only allowed for step 0", + Here()); + } + + set_or_throw(out, "step", endStep); + set_or_throw(out, "timespan", std::to_string(endStep - startStep) + "h"); + } + catch (...) { + // Rethrow nested exceptions + std::throw_with_nested( + Mars2marsGenericException("Failed to apply step-range timespan rule in output dictionary", Here())); + } +} + +/// @brief Fix timespan of statistical fields that have been wrongly encoded as instant at step 0. +template +inline void fixStep0Timespan(const InDict_t& in, OutDict_t& out) { + using metkit::mars2mars::utils::dict_traits::get_or_throw; + using metkit::mars2mars::utils::dict_traits::has; + using metkit::mars2mars::utils::dict_traits::set_or_throw; + using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; + + static const std::unordered_set paramIdsWithTimespan{ + 8, 9, 20, 44, 45, 47, 49, 50, 57, 58, 121, 122, + 123, 142, 143, 144, 146, 145, 147, 169, 175, 176, 177, 178, + 179, 180, 181, 182, 189, 195, 196, 197, 201, 202, 205, 208, + 209, 210, 211, 212, 213, 228, 228021, 228022, 228080, 228081, 228082, 228129, + 228130, 228216, 228222, 228223, 228224, 228225, 228226, 228227, 228026, 228027, 228028, 228251}; + + try { + + // This fix should only be applied if step == 0. + // Note that when step is the range 0-0, timespan is already set to 0 in convertStepRangeToTimespan. + if (has(in, "step") && get_or_throw(in, "step") != 0) { + return; + } + + const long paramId = get_or_throw(in, "param"); + + if (paramIdsWithTimespan.find(paramId) == paramIdsWithTimespan.end()) { + return; + } + + set_or_throw(out, "timespan", "0h"); + } + catch (...) { + // Rethrow nested exceptions + std::throw_with_nested( + Mars2marsGenericException("Failed to apply step 0 timespan fix in output dictionary", Here())); + } +} /// @brief Convert surface-like legacy requests into sol layer output. template @@ -50,6 +156,12 @@ inline void fixTimespan(const InDict_t& in, OutDict_t& out, eckit::LocalConfigur using metkit::mars2mars::utils::exceptions::Mars2marsGenericException; try { + // Handle step ranges (e.g. "0-6") and default timespan to "none" for single-value steps. + convertStepRangeToTimespan(in, out); + + // Fix statistical fields that are wrongly encoded as instant fields at step 0. + fixStep0Timespan(in, out); + const auto param = get_or_throw(in, "param"); switch (param) { diff --git a/src/metkit/mars2mars/mappings/rules/wave2oper.h b/src/metkit/mars2mars/mappings/rules/waveStreams.h similarity index 73% rename from src/metkit/mars2mars/mappings/rules/wave2oper.h rename to src/metkit/mars2mars/mappings/rules/waveStreams.h index ac8364f2a..86751c2c0 100644 --- a/src/metkit/mars2mars/mappings/rules/wave2oper.h +++ b/src/metkit/mars2mars/mappings/rules/waveStreams.h @@ -9,7 +9,7 @@ * does it submit to any jurisdiction. */ -/// @file wave2oper.h +/// @file waveStreams.h /// @brief Conversion rules used by the mars2mars mapper. #pragma once @@ -21,9 +21,9 @@ namespace metkit::mars2mars::rules::impl { -/// @brief Convert surface-like legacy requests into sol layer output. +/// @brief Convert wave streams template -inline void convertWave2Oper(const InDict_t& in, OutDict_t& out, eckit::LocalConfiguration& misc) { +inline void convertWaveStreams(const InDict_t& in, OutDict_t& out, eckit::LocalConfiguration& misc) { using metkit::mars2mars::utils::dict_traits::get_or_throw; using metkit::mars2mars::utils::dict_traits::set_or_throw; @@ -34,10 +34,14 @@ inline void convertWave2Oper(const InDict_t& in, OutDict_t& out, eckit::LocalCon if (get_or_throw(in, "stream") == "wave") { set_or_throw(out, "stream", "oper"); } + else if (get_or_throw(in, "stream") == "waef") { + set_or_throw(out, "stream", "enfo"); + } } catch (...) { // Rethrow nested exceptions - std::throw_with_nested(Mars2marsGenericException("Failed to convert input dictionary in wave2oper", Here())); + std::throw_with_nested( + Mars2marsGenericException("Failed to convert input dictionary in convertWaveStreams", Here())); } } diff --git a/src/metkit/mars2mars/mappings/rules/windspeed.h b/src/metkit/mars2mars/mappings/rules/windspeed.h index 90c2daac1..53139589d 100644 --- a/src/metkit/mars2mars/mappings/rules/windspeed.h +++ b/src/metkit/mars2mars/mappings/rules/windspeed.h @@ -34,7 +34,7 @@ inline void fixWindspeed(const InDict_t& in, OutDict_t& out, eckit::LocalConfigu try { const auto levtype = get_opt(in, "levtype"); - if (levtype && *levtype == "SFC") { + if (levtype && *levtype == "sfc") { const auto param = get_or_throw(in, "param"); switch (param) { case 228246: // 100u diff --git a/src/metkit/mars2mars/utils/dictionary_traits/dictaccess_eckit_configuration.h b/src/metkit/mars2mars/utils/dictionary_traits/dictaccess_eckit_configuration.h index 951932c8c..2ea3bde1e 100644 --- a/src/metkit/mars2mars/utils/dictionary_traits/dictaccess_eckit_configuration.h +++ b/src/metkit/mars2mars/utils/dictionary_traits/dictaccess_eckit_configuration.h @@ -269,6 +269,49 @@ struct DictHas { } }; +// ----------------------------------------------------------------------------- +// DictMissing +// ----------------------------------------------------------------------------- +template <> +struct DictMissing { + static bool isMissing(const eckit::LocalConfiguration& cfg, std::string_view key) noexcept(false) { + const std::string k{key}; + + try { + return !cfg.has(k); + } + catch (const exceptions::Mars2marsGenericException&) { + throw; + } + catch (...) { + std::throw_with_nested(exceptions::Mars2marsDictException( + "Internal error while checking absence of key `"s + k + "` in dictionary type `"s + + std::string(type_name()) + "`", + Here())); + } + mars2marsUnreachable(); + } + + static void setMissing(eckit::LocalConfiguration& cfg, std::string_view key) noexcept(false) { + const std::string k{key}; + cfg.remove(k); + + try { + cfg.remove(k); + } + catch (const exceptions::Mars2marsGenericException&) { + throw; + } + catch (...) { + std::throw_with_nested(exceptions::Mars2marsDictException( + "Internal error while removing key `"s + k + "` in dictionary type `"s + + std::string(type_name()) + "`", + Here())); + } + mars2marsUnreachable(); + } +}; + // ============================================================ // eckit::LocalConfiguration specializations via macros // ============================================================ diff --git a/src/tools/grib1-to-grib2.cc b/src/tools/grib1-to-grib2.cc index 183928786..6156dfd0d 100644 --- a/src/tools/grib1-to-grib2.cc +++ b/src/tools/grib1-to-grib2.cc @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include "eckit/config/LocalConfiguration.h" @@ -33,6 +35,7 @@ #include "eckit/message/Reader.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" #include "metkit/codes/api/CodesAPI.h" #include "metkit/grib2mars/api/Grib2Mars.h" @@ -56,18 +59,47 @@ class Grib1ToGrib2Tool final : public eckit::EckitTool { void init(const CmdArgs& args) override; void execute(const CmdArgs& args) override; void usage(const std::string& tool) const override; + + bool skipDiscipline192_ = false; + std::optional expver_ = std::nullopt; + std::optional generatingProcessIdentifier_ = std::nullopt; }; //---------------------------------------------------------------------------------------------------------------------- -Grib1ToGrib2Tool::Grib1ToGrib2Tool(int argc, char** argv) : eckit::EckitTool(argc, argv) {} +Grib1ToGrib2Tool::Grib1ToGrib2Tool(int argc, char** argv) : eckit::EckitTool(argc, argv) { + options_.push_back(new eckit::option::SimpleOption("help", "Print this help message")); + + // Input handling + options_.push_back( + new eckit::option::SimpleOption("skip-discipline-192", "Skip discipline 192 input messages")); + + // Override values + options_.push_back(new eckit::option::SimpleOption("expver", "Override expver")); + options_.push_back( + new eckit::option::SimpleOption("generatingProcessIdentifier", "Override generatingProcessIdentifier")); +} + +void Grib1ToGrib2Tool::init(const CmdArgs& args) { + skipDiscipline192_ = args.has("skip-discipline-192"); -void Grib1ToGrib2Tool::init(const CmdArgs& args) {} + if (args.has("expver")) { + std::string expver; + args.get("expver", expver); + expver_ = expver; + } + + if (args.has("generatingProcessIdentifier")) { + long generatingProcessIdentifier; + args.get("generatingProcessIdentifier", generatingProcessIdentifier); + generatingProcessIdentifier_ = generatingProcessIdentifier; + } +} void Grib1ToGrib2Tool::usage(const std::string& tool) const { Log::info() << "Usage: " << tool << " [options] input output" << std::endl << std::endl - << "Convert GRIB1 to GRIB2" << std::endl + << "Convert (pre-MTG2) GRIB1 to (post-MTG2) GRIB2" << std::endl << std::endl; } @@ -101,6 +133,9 @@ eckit::LocalConfiguration mergeLocalConfigs(const eckit::LocalConfiguration& bas else if (overwrite.isFloatingPoint(key)) { result.set(key, overwrite.getDouble(key)); } + else if (overwrite.isBoolean(key)) { + result.set(key, overwrite.getBool(key)); + } else if (overwrite.isFloatingPointList(key)) { result.set(key, overwrite.getDoubleVector(key)); } @@ -113,6 +148,263 @@ eckit::LocalConfiguration mergeLocalConfigs(const eckit::LocalConfiguration& bas //---------------------------------------------------------------------------------------------------------------------- +bool isDiscipline192(const long param, const bool ignoreIfMappable = true) { + static const std::unordered_set discipline192Params{ + 4, 5, 6, 7, 11, 12, 13, 14, 19, 24, 25, 35, 36, 37, + 38, 39, 40, 41, 42, 46, 62, 63, 64, 65, 70, 71, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 123, 125, 126, + 127, 128, 139, 140, 153, 154, 158, 170, 171, 183, 184, 185, 190, 191, + 192, 193, 199, 200, 204, 214, 215, 216, 217, 218, 219, 220, 221, 222, + 223, 224, 225, 226, 227, 233, 236, 237, 241, 242, 249, 250, 251, 252, + 253, 254, 129001, 129002, 129003, 129004, 129005, 129011, 129012, 129013, 129014, 129021, 129022, 129023, + 129024, 129025, 129026, 129027, 129028, 129029, 129030, 129031, 129032, 129033, 129034, 129035, 129036, 129037, + 129038, 129039, 129040, 129041, 129042, 129043, 129044, 129045, 129046, 129047, 129048, 129049, 129050, 129051, + 129052, 129053, 129054, 129057, 129058, 129059, 129060, 129061, 129062, 129063, 129064, 129065, 129066, 129067, + 129070, 129071, 129078, 129079, 129080, 129081, 129082, 129083, 129084, 129085, 129086, 129087, 129088, 129089, + 129090, 129091, 129092, 129093, 129094, 129095, 129096, 129097, 129098, 129099, 129100, 129101, 129102, 129103, + 129104, 129105, 129106, 129107, 129108, 129109, 129110, 129111, 129112, 129113, 129114, 129115, 129116, 129117, + 129118, 129119, 129120, 129121, 129122, 129123, 129125, 129126, 129127, 129128, 129129, 129130, 129131, 129132, + 129133, 129134, 129135, 129136, 129137, 129138, 129139, 129140, 129141, 129142, 129143, 129144, 129145, 129146, + 129147, 129148, 129149, 129150, 129151, 129152, 129153, 129154, 129155, 129156, 129157, 129158, 129159, 129160, + 129161, 129162, 129163, 129164, 129165, 129166, 129167, 129168, 129169, 129170, 129171, 129172, 129173, 129174, + 129175, 129176, 129177, 129178, 129179, 129180, 129181, 129182, 129183, 129184, 129185, 129186, 129187, 129188, + 129189, 129190, 129191, 129192, 129193, 129194, 129195, 129196, 129197, 129198, 129199, 129200, 129201, 129202, + 129203, 129204, 129205, 129206, 129207, 129208, 129209, 129210, 129211, 129212, 129214, 129215, 129216, 129217, + 129218, 129219, 129220, 129221, 129222, 129223, 129224, 129225, 129226, 129227, 129228, 129229, 129230, 129231, + 129232, 129233, 129234, 129235, 129236, 129237, 129238, 129239, 129240, 129241, 129242, 129243, 129244, 129245, + 129246, 129247, 129248, 129249, 129250, 129251, 129252, 129253, 129254, 129255, 130208, 130209, 130210, 130211, + 130212, 130213, 130214, 130215, 130216, 130217, 130218, 130219, 130220, 130221, 130224, 130225, 130226, 130228, + 130229, 130230, 130231, 131001, 131002, 131003, 131004, 131005, 131006, 131007, 131008, 131009, 131010, 131015, + 131016, 131017, 131018, 131020, 131021, 131022, 131023, 131024, 131025, 131049, 131059, 131064, 131065, 131066, + 131067, 131068, 131069, 131073, 131078, 131079, 131080, 131081, 131129, 131130, 131139, 131144, 131151, 131164, + 131165, 131167, 131201, 131202, 131228, 131229, 131232, 131255, 133001, 133002, 133003, 133004, 133005, 133006, + 133007, 133008, 133009, 133010, 133011, 133012, 133013, 133014, 133015, 133016, 133017, 133018, 133019, 133020, + 133021, 133022, 133023, 133024, 133025, 133026, 133027, 133028, 133029, 133030, 133031, 133032, 133033, 133034, + 133035, 133036, 133037, 133038, 133039, 133040, 133041, 133042, 133043, 133044, 133045, 133046, 133047, 133048, + 133049, 133050, 133051, 133052, 133053, 133054, 133055, 133056, 133057, 133058, 133059, 133060, 133061, 133062, + 133063, 133064, 133065, 133066, 133067, 133068, 133069, 133070, 133071, 133072, 133073, 133074, 133075, 133076, + 133077, 133078, 133079, 133080, 133081, 133082, 133083, 133084, 133085, 133086, 133087, 133088, 133089, 133090, + 133091, 133092, 140200, 140250, 140255, 150129, 150130, 150131, 150133, 150134, 150135, 150137, 150139, 150140, + 150141, 150142, 150143, 150144, 150145, 150146, 150147, 150148, 150152, 150153, 150154, 150155, 150168, 150169, + 150170, 150171, 150172, 150173, 150180, 150181, 150182, 150183, 150255, 151128, 151129, 151130, 151133, 151134, + 151135, 151136, 151137, 151138, 151139, 151140, 151141, 151142, 151143, 151144, 151146, 151147, 151148, 151150, + 151151, 151152, 151153, 151154, 151155, 151156, 151157, 151158, 151159, 151160, 151161, 151162, 151164, 151165, + 151166, 151167, 151168, 151169, 151170, 151176, 151177, 151178, 151179, 151180, 151181, 151182, 151183, 151184, + 151185, 151186, 151187, 151188, 151190, 151191, 151192, 151193, 151194, 151199, 151200, 151201, 151202, 151203, + 151204, 151205, 151206, 151207, 151208, 151209, 151210, 151211, 151212, 151255, 160049, 160135, 160137, 160140, + 160142, 160143, 160144, 160156, 160157, 160171, 160180, 160181, 160182, 160184, 160199, 160205, 160207, 160209, + 160210, 160212, 160213, 160214, 160216, 160217, 160218, 160219, 160221, 160222, 160223, 160224, 160225, 160231, + 160239, 160240, 160241, 160242, 160243, 160246, 160247, 160249, 160254, 162051, 162054, 162056, 162057, 162058, + 162064, 162065, 162066, 162067, 162068, 162073, 162074, 162075, 162076, 162077, 162078, 162081, 162082, 162083, + 162085, 162086, 162087, 162114, 162115, 162116, 162117, 162118, 162119, 162120, 162121, 162122, 162123, 162124, + 162125, 162126, 162127, 162128, 162129, 162130, 162131, 162132, 162133, 162134, 162135, 162136, 162137, 162138, + 162139, 162140, 162141, 162206, 162207, 162208, 162209, 162210, 162211, 162212, 162213, 162214, 162215, 162216, + 162217, 162218, 162219, 162220, 162221, 162222, 162223, 162224, 162225, 162226, 162227, 162229, 162230, 162231, + 162232, 162233, 162255, 170149, 170171, 170179, 171001, 171002, 171003, 171004, 171005, 171006, 171007, 171011, + 171012, 171013, 171014, 171021, 171022, 171023, 171026, 171027, 171028, 171029, 171030, 171031, 171032, 171033, + 171034, 171035, 171036, 171037, 171038, 171039, 171040, 171041, 171042, 171043, 171044, 171045, 171046, 171047, + 171048, 171049, 171050, 171051, 171052, 171053, 171054, 171055, 171056, 171057, 171058, 171059, 171060, 171061, + 171062, 171063, 171064, 171065, 171078, 171079, 171121, 171122, 171125, 171126, 171127, 171128, 171129, 171130, + 171131, 171132, 171133, 171134, 171135, 171136, 171137, 171138, 171139, 171140, 171141, 171142, 171143, 171144, + 171145, 171146, 171147, 171148, 171149, 171150, 171151, 171152, 171153, 171154, 171155, 171156, 171157, 171158, + 171159, 171160, 171161, 171162, 171163, 171164, 171165, 171166, 171167, 171168, 171169, 171170, 171171, 171173, + 171174, 171175, 171176, 171177, 171178, 171179, 171180, 171181, 171182, 171183, 171184, 171185, 171186, 171187, + 171188, 171189, 171190, 171191, 171192, 171193, 171194, 171195, 171196, 171197, 171198, 171199, 171200, 171201, + 171202, 171203, 171204, 171205, 171206, 171207, 171208, 171209, 171210, 171211, 171212, 171214, 171215, 171216, + 171217, 171218, 171219, 171220, 171221, 171222, 171223, 171224, 171225, 171226, 171227, 171228, 171229, 171230, + 171231, 171232, 171233, 171234, 171235, 171236, 171237, 171238, 171239, 171240, 171241, 171242, 171243, 171244, + 171245, 171246, 171247, 171248, 171249, 171250, 171251, 171252, 171253, 171254, 171255, 172044, 172045, 172153, + 172154, 172239, 172240, 172255, 173044, 173045, 173048, 173050, 173142, 173143, 173144, 173145, 173146, 173147, + 173149, 173153, 173154, 173169, 173175, 173176, 173177, 173178, 173179, 173180, 173181, 173182, 173189, 173195, + 173196, 173197, 173205, 173208, 173209, 173210, 173211, 173212, 173228, 173239, 173240, 173255, 174006, 174031, + 174034, 174039, 174040, 174041, 174042, 174049, 174055, 174083, 174085, 174086, 174087, 174088, 174089, 174090, + 174094, 174095, 174099, 174110, 174111, 174139, 174164, 174167, 174168, 174170, 174175, 174183, 174236, 174255, + 175006, 175031, 175034, 175039, 175040, 175041, 175042, 175049, 175055, 175083, 175085, 175086, 175087, 175088, + 175089, 175090, 175110, 175111, 175139, 175164, 175167, 175168, 175170, 175175, 175183, 175236, 175255, 180149, + 180176, 180177, 180178, 180179, 190170, 190171, 190173, 190229, 200001, 200002, 200003, 200004, 200005, 200011, + 200012, 200013, 200014, 200021, 200022, 200023, 200024, 200025, 200026, 200027, 200028, 200029, 200030, 200031, + 200032, 200033, 200034, 200035, 200036, 200037, 200038, 200039, 200040, 200041, 200042, 200043, 200044, 200045, + 200046, 200047, 200048, 200049, 200050, 200051, 200052, 200053, 200054, 200055, 200056, 200057, 200058, 200059, + 200060, 200061, 200062, 200063, 200064, 200065, 200066, 200067, 200070, 200071, 200078, 200079, 200080, 200081, + 200082, 200083, 200084, 200085, 200086, 200087, 200088, 200089, 200090, 200091, 200092, 200093, 200094, 200095, + 200096, 200097, 200098, 200099, 200100, 200101, 200102, 200103, 200104, 200105, 200106, 200107, 200108, 200109, + 200110, 200111, 200112, 200113, 200114, 200115, 200116, 200117, 200118, 200119, 200120, 200121, 200122, 200123, + 200125, 200126, 200127, 200128, 200129, 200130, 200131, 200132, 200133, 200134, 200135, 200136, 200137, 200138, + 200139, 200140, 200141, 200142, 200143, 200144, 200145, 200146, 200147, 200148, 200149, 200150, 200151, 200152, + 200153, 200154, 200155, 200156, 200157, 200158, 200159, 200160, 200161, 200162, 200163, 200164, 200165, 200166, + 200167, 200168, 200169, 200170, 200171, 200172, 200173, 200174, 200175, 200176, 200177, 200178, 200179, 200180, + 200181, 200182, 200183, 200184, 200185, 200186, 200187, 200188, 200189, 200190, 200191, 200192, 200193, 200194, + 200195, 200196, 200197, 200198, 200199, 200200, 200201, 200202, 200203, 200204, 200205, 200206, 200207, 200208, + 200209, 200210, 200211, 200212, 200214, 200215, 200216, 200217, 200218, 200219, 200220, 200221, 200222, 200223, + 200224, 200225, 200226, 200227, 200228, 200229, 200230, 200231, 200232, 200233, 200234, 200235, 200236, 200237, + 200238, 200239, 200240, 200241, 200242, 200243, 200244, 200245, 200246, 200247, 200248, 200249, 200250, 200251, + 200252, 200253, 200254, 200255, 201001, 201002, 201003, 201004, 201005, 201006, 201007, 201008, 201009, 201010, + 201011, 201012, 201013, 201014, 201015, 201016, 201017, 201029, 201030, 201031, 201032, 201033, 201034, 201035, + 201036, 201037, 201038, 201041, 201042, 201050, 201051, 201052, 201053, 201054, 201055, 201056, 201060, 201061, + 201062, 201063, 201064, 201065, 201066, 201067, 201068, 201069, 201070, 201071, 201072, 201073, 201074, 201075, + 201076, 201077, 201078, 201079, 201080, 201081, 201082, 201083, 201084, 201085, 201099, 201100, 201101, 201102, + 201111, 201112, 201113, 201150, 201200, 201203, 201215, 201241, 201255, 210001, 210002, 210003, 210004, 210005, + 210006, 210007, 210008, 210009, 210010, 210011, 210012, 210013, 210014, 210015, 210016, 210017, 210018, 210019, + 210020, 210021, 210022, 210023, 210024, 210025, 210026, 210027, 210028, 210029, 210030, 210031, 210032, 210033, + 210034, 210035, 210036, 210037, 210038, 210039, 210040, 210041, 210042, 210043, 210044, 210045, 210046, 210047, + 210048, 210049, 210050, 210051, 210052, 210053, 210054, 210055, 210056, 210057, 210058, 210059, 210060, 210061, + 210062, 210063, 210064, 210065, 210066, 210067, 210068, 210069, 210070, 210071, 210079, 210080, 210081, 210082, + 210083, 210084, 210085, 210086, 210087, 210088, 210089, 210090, 210091, 210092, 210093, 210094, 210095, 210096, + 210097, 210098, 210099, 210100, 210101, 210102, 210103, 210104, 210105, 210106, 210107, 210108, 210109, 210110, + 210111, 210112, 210113, 210114, 210115, 210116, 210117, 210118, 210119, 210120, 210124, 210125, 210126, 210127, + 210128, 210129, 210130, 210131, 210132, 210133, 210134, 210135, 210136, 210137, 210138, 210139, 210140, 210141, + 210142, 210143, 210144, 210145, 210146, 210147, 210148, 210149, 210150, 210151, 210152, 210153, 210154, 210155, + 210156, 210157, 210158, 210159, 210160, 210161, 210162, 210163, 210164, 210165, 210166, 210167, 210169, 210177, + 210179, 210181, 210182, 210183, 210184, 210185, 210206, 210207, 210208, 210209, 210210, 210211, 210212, 210213, + 210214, 210215, 210216, 210217, 210218, 210219, 210220, 210221, 210222, 210223, 210224, 210225, 210226, 210227, + 210228, 210229, 210230, 210231, 210232, 210233, 210234, 210235, 210236, 210237, 210238, 210239, 210240, 210241, + 210242, 210243, 210244, 210245, 210246, 211001, 211002, 211003, 211004, 211005, 211006, 211007, 211008, 211009, + 211010, 211011, 211012, 211013, 211014, 211015, 211016, 211017, 211018, 211019, 211020, 211021, 211022, 211023, + 211024, 211025, 211026, 211027, 211028, 211029, 211030, 211031, 211032, 211033, 211034, 211035, 211036, 211037, + 211038, 211039, 211040, 211041, 211042, 211043, 211044, 211045, 211046, 211047, 211048, 211049, 211050, 211051, + 211052, 211053, 211054, 211055, 211056, 211061, 211062, 211063, 211064, 211065, 211066, 211067, 211068, 211069, + 211070, 211071, 211092, 211093, 211094, 211095, 211096, 211097, 211098, 211099, 211100, 211101, 211119, 211120, + 211124, 211125, 211126, 211127, 211128, 211129, 211130, 211131, 211132, 211133, 211134, 211135, 211136, 211137, + 211138, 211139, 211140, 211141, 211142, 211143, 211144, 211145, 211146, 211147, 211148, 211149, 211150, 211151, + 211152, 211153, 211154, 211155, 211156, 211157, 211158, 211159, 211160, 211161, 211162, 211163, 211164, 211165, + 211166, 211181, 211182, 211183, 211184, 211185, 211206, 211207, 211208, 211209, 211210, 211211, 211212, 211213, + 211214, 211215, 211216, 212001, 212002, 212003, 212004, 212005, 212006, 212007, 212008, 212009, 212010, 212011, + 212012, 212013, 212014, 212015, 212016, 212017, 212018, 212019, 212020, 212021, 212022, 212023, 212024, 212025, + 212026, 212027, 212028, 212029, 212030, 212031, 212032, 212033, 212034, 212035, 212036, 212037, 212038, 212039, + 212040, 212041, 212042, 212043, 212044, 212045, 212046, 212047, 212048, 212049, 212050, 212051, 212052, 212053, + 212054, 212055, 212056, 212057, 212058, 212059, 212060, 212061, 212062, 212063, 212064, 212065, 212066, 212067, + 212068, 212069, 212070, 212071, 212072, 212073, 212074, 212075, 212076, 212077, 212078, 212079, 212080, 212081, + 212082, 212083, 212084, 212085, 212086, 212087, 212088, 212089, 212090, 212091, 212092, 212093, 212094, 212095, + 212096, 212097, 212098, 212099, 212100, 212101, 212102, 212103, 212104, 212105, 212106, 212107, 212108, 212109, + 212110, 212111, 212112, 212113, 212114, 212115, 212116, 212117, 212118, 212119, 212120, 212121, 212122, 212123, + 212124, 212125, 212126, 212127, 212128, 212129, 212130, 212131, 212132, 212133, 212134, 212135, 212136, 212137, + 212138, 212139, 212140, 212141, 212142, 212143, 212144, 212145, 212146, 212147, 212148, 212149, 212150, 212151, + 212152, 212153, 212154, 212155, 212156, 212157, 212158, 212159, 212160, 212161, 212162, 212163, 212164, 212165, + 212166, 212167, 212168, 212169, 212170, 212171, 212172, 212173, 212174, 212175, 212176, 212177, 212178, 212179, + 212180, 212181, 212182, 212183, 212184, 212185, 212186, 212187, 212188, 212189, 212190, 212191, 212192, 212193, + 212194, 212195, 212196, 212197, 212198, 212199, 212200, 212201, 212202, 212203, 212204, 212205, 212206, 212207, + 212208, 212209, 212210, 212211, 212212, 212213, 212214, 212215, 212216, 212217, 212218, 212219, 212220, 212221, + 212222, 212223, 212224, 212225, 212226, 212227, 212228, 212229, 212230, 212231, 212232, 212233, 212234, 212235, + 212236, 212237, 212238, 212239, 212240, 212241, 212242, 212243, 212244, 212245, 212246, 212247, 212248, 212249, + 212250, 212251, 212252, 212253, 212254, 212255, 213001, 213002, 213003, 213004, 213005, 213101, 213102, 213103, + 213104, 213105, 213106, 213107, 213108, 213109, 213110, 213111, 213112, 213113, 213114, 213115, 213116, 213117, + 213118, 213119, 213120, 213121, 213122, 213123, 213124, 213125, 213126, 213127, 213128, 213129, 213130, 213131, + 213132, 213133, 213134, 213135, 213136, 213137, 213138, 213139, 213140, 213141, 213142, 213143, 213144, 213145, + 213146, 213147, 213148, 213149, 213150, 213151, 213152, 213153, 213154, 213155, 213156, 213157, 213158, 213159, + 213160, 213161, 213162, 213163, 213164, 213165, 213166, 213167, 213168, 213169, 213170, 213171, 213172, 213173, + 213174, 213175, 213176, 213177, 213178, 213179, 213180, 213181, 213182, 213183, 213184, 213185, 213186, 213187, + 213188, 213189, 213190, 213191, 213192, 213193, 213194, 213195, 213196, 213197, 213198, 213199, 213200, 213201, + 213202, 213203, 213204, 213205, 213206, 213207, 213208, 213209, 213210, 213211, 213212, 213213, 213214, 213215, + 213216, 213217, 213218, 213219, 213220, 213221, 214002, 214003, 214004, 214005, 214006, 214007, 214008, 214009, + 214010, 214011, 214012, 214013, 214014, 214015, 214016, 214017, 214018, 214019, 214020, 214021, 214022, 214023, + 214024, 214025, 214026, 214027, 214028, 214029, 214030, 214031, 214032, 214033, 214034, 214035, 214036, 214037, + 214038, 214039, 214040, 214041, 214042, 214043, 214044, 214045, 214046, 214047, 214048, 214049, 214050, 214051, + 214052, 215001, 215002, 215003, 215004, 215005, 215006, 215007, 215008, 215009, 215010, 215011, 215012, 215013, + 215014, 215015, 215016, 215017, 215018, 215019, 215020, 215021, 215022, 215023, 215024, 215025, 215026, 215027, + 215028, 215029, 215030, 215031, 215032, 215033, 215034, 215035, 215036, 215037, 215038, 215039, 215040, 215041, + 215042, 215043, 215044, 215045, 215046, 215047, 215048, 215049, 215050, 215051, 215052, 215053, 215054, 215055, + 215056, 215057, 215058, 215059, 215060, 215061, 215062, 215063, 215064, 215065, 215066, 215067, 215068, 215069, + 215070, 215071, 215072, 215073, 215074, 215075, 215076, 215077, 215078, 215079, 215080, 215081, 215082, 215083, + 215084, 215085, 215086, 215087, 215088, 215089, 215090, 215091, 215092, 215093, 215094, 215095, 215096, 215097, + 215098, 215099, 215100, 215101, 215102, 215103, 215104, 215105, 215106, 215107, 215108, 215109, 215110, 215111, + 215112, 215113, 215114, 215115, 215116, 215117, 215118, 215119, 215120, 215121, 215122, 215123, 215124, 215125, + 215126, 215127, 215128, 215129, 215130, 215131, 215132, 215133, 215134, 215135, 215136, 215137, 215138, 215139, + 215140, 215141, 215142, 215143, 215144, 215145, 215146, 215147, 215148, 215149, 215150, 215151, 215152, 215153, + 215154, 215155, 215156, 215157, 215158, 215159, 215160, 215161, 215162, 215163, 215164, 215165, 215166, 215167, + 215168, 215169, 215170, 215171, 215172, 215173, 215174, 215175, 215176, 215177, 215178, 215179, 215180, 215181, + 215182, 215183, 215184, 215185, 215186, 215187, 215188, 216001, 216002, 216003, 216004, 216005, 216006, 216007, + 216008, 216009, 216010, 216011, 216012, 216013, 216014, 216015, 216016, 216017, 216018, 216019, 216020, 216021, + 216022, 216023, 216024, 216025, 216026, 216027, 216028, 216029, 216030, 216031, 216032, 216033, 216034, 216035, + 216036, 216037, 216038, 216039, 216040, 216041, 216042, 216043, 216044, 216045, 216046, 216047, 216048, 216049, + 216050, 216051, 216052, 216053, 216054, 216055, 216056, 216057, 216058, 216059, 216060, 216061, 216062, 216063, + 216064, 216065, 216066, 216067, 216068, 216069, 216070, 216071, 216072, 216073, 216074, 216075, 216076, 216077, + 216078, 216079, 216080, 216081, 216082, 216083, 216084, 216085, 216086, 216087, 216088, 216089, 216090, 216091, + 216092, 216093, 216094, 216095, 216096, 216097, 216098, 216099, 216100, 216101, 216102, 216103, 216104, 216105, + 216106, 216107, 216108, 216109, 216110, 216111, 216112, 216113, 216114, 216115, 216116, 216117, 216118, 216119, + 216120, 216121, 216122, 216123, 216124, 216125, 216126, 216127, 216128, 216129, 216130, 216131, 216132, 216133, + 216134, 216135, 216136, 216137, 216138, 216139, 216140, 216141, 216142, 216143, 216144, 216145, 216146, 216147, + 216148, 216149, 216150, 216151, 216152, 216153, 216154, 216155, 216156, 216157, 216158, 216159, 216160, 216161, + 216162, 216163, 216164, 216165, 216166, 216167, 216168, 216169, 216170, 216171, 216172, 216173, 216174, 216175, + 216176, 216177, 216178, 216179, 216180, 216181, 216182, 216183, 216184, 216185, 216186, 216187, 216188, 216189, + 216190, 216191, 216192, 216193, 216194, 216195, 216196, 216197, 216198, 216199, 216200, 216201, 216202, 216203, + 216204, 216205, 216206, 216207, 216208, 216209, 216210, 216211, 216212, 216213, 216214, 216215, 216216, 216217, + 216218, 216219, 216220, 216221, 216222, 216223, 216224, 216225, 216226, 216227, 216228, 216229, 216230, 216231, + 216232, 216233, 216234, 216235, 216236, 216237, 216238, 216239, 216240, 216241, 216242, 216243, 216244, 216245, + 216246, 216247, 216248, 216249, 216250, 216251, 216252, 216253, 216254, 216255, 217003, 217004, 217006, 217007, + 217009, 217010, 217011, 217012, 217013, 217014, 217015, 217016, 217018, 217020, 217021, 217022, 217023, 217024, + 217026, 217028, 217029, 217030, 217032, 217033, 217034, 217035, 217036, 217037, 217038, 217039, 217040, 217041, + 217042, 217043, 217044, 217045, 217046, 217047, 217048, 217049, 217050, 217051, 217052, 217053, 217054, 217055, + 217056, 217057, 217058, 217059, 217060, 217061, 217062, 217063, 217064, 217065, 217066, 217067, 217068, 217069, + 217070, 217071, 217072, 217073, 217074, 217075, 217076, 217077, 217078, 217079, 217080, 217081, 217082, 217083, + 217084, 217085, 217086, 217087, 217088, 217089, 217090, 217091, 217092, 217093, 217094, 217095, 217096, 217097, + 217098, 217099, 217100, 217101, 217102, 217103, 217104, 217105, 217106, 217107, 217108, 217109, 217110, 217111, + 217112, 217113, 217114, 217115, 217116, 217117, 217118, 217119, 217120, 217121, 217122, 217123, 217124, 217125, + 217126, 217127, 217128, 217129, 217130, 217131, 217132, 217133, 217134, 217135, 217136, 217137, 217138, 217139, + 217140, 217141, 217142, 217143, 217144, 217145, 217146, 217147, 217148, 217149, 217150, 217151, 217152, 217153, + 217154, 217155, 217156, 217157, 217158, 217159, 217160, 217161, 217162, 217163, 217164, 217165, 217166, 217167, + 217168, 217169, 217170, 217171, 217172, 217173, 217174, 217175, 217176, 217177, 217178, 217179, 217180, 217181, + 217182, 217183, 217184, 217185, 217186, 217187, 217188, 217189, 217190, 217191, 217192, 217193, 217194, 217195, + 217196, 217197, 217198, 217199, 217200, 217201, 217202, 217203, 217204, 217205, 217206, 218003, 218004, 218006, + 218007, 218009, 218010, 218011, 218012, 218013, 218014, 218015, 218016, 218018, 218019, 218020, 218021, 218022, + 218023, 218024, 218026, 218027, 218028, 218029, 218030, 218032, 218033, 218034, 218035, 218036, 218037, 218038, + 218039, 218040, 218041, 218042, 218043, 218044, 218045, 218046, 218047, 218048, 218049, 218050, 218051, 218052, + 218053, 218054, 218055, 218056, 218057, 218058, 218059, 218060, 218061, 218062, 218063, 218064, 218065, 218066, + 218067, 218068, 218069, 218070, 218071, 218072, 218073, 218074, 218075, 218076, 218077, 218078, 218079, 218080, + 218081, 218082, 218083, 218084, 218085, 218086, 218087, 218088, 218089, 218090, 218091, 218092, 218093, 218094, + 218095, 218096, 218097, 218098, 218099, 218100, 218101, 218102, 218103, 218104, 218105, 218106, 218107, 218108, + 218109, 218110, 218111, 218112, 218113, 218114, 218115, 218116, 218117, 218118, 218119, 218120, 218121, 218122, + 218123, 218124, 218125, 218126, 218127, 218128, 218129, 218130, 218131, 218132, 218133, 218134, 218135, 218136, + 218137, 218138, 218139, 218140, 218141, 218142, 218143, 218144, 218145, 218146, 218147, 218148, 218149, 218150, + 218151, 218152, 218153, 218154, 218155, 218156, 218157, 218158, 218159, 218160, 218161, 218162, 218163, 218164, + 218165, 218166, 218167, 218168, 218169, 218170, 218171, 218172, 218173, 218174, 218175, 218176, 218177, 218178, + 218179, 218180, 218181, 218182, 218183, 218184, 218185, 218186, 218187, 218188, 218189, 218190, 218191, 218192, + 218193, 218194, 218195, 218196, 218197, 218198, 218199, 218200, 218201, 218202, 218203, 218204, 218205, 218206, + 219001, 219002, 219003, 219004, 219005, 219006, 219007, 219008, 219009, 219010, 219011, 219012, 219013, 219014, + 219015, 219016, 219017, 219018, 219019, 219020, 219021, 219022, 219023, 219024, 219025, 219026, 219027, 219028, + 219029, 219030, 219031, 219032, 219033, 219034, 219035, 219036, 219037, 219038, 219039, 219040, 219041, 219042, + 219043, 219044, 219045, 219046, 219047, 219048, 219049, 219050, 219051, 219052, 219053, 219054, 219055, 219056, + 219057, 219058, 219059, 219060, 219061, 219062, 219063, 219064, 219065, 219066, 219067, 219068, 219069, 219070, + 219071, 219072, 219073, 219074, 219075, 219076, 219077, 219078, 219079, 219080, 219081, 219082, 219083, 219084, + 219085, 219086, 219087, 219088, 219089, 219090, 219091, 219092, 219093, 219094, 219095, 219096, 219097, 219098, + 219099, 219100, 219101, 219102, 219103, 219104, 219105, 219106, 219107, 219108, 219109, 219110, 219111, 219112, + 219113, 219114, 219115, 219116, 219117, 219118, 219119, 219120, 219121, 219122, 219123, 219124, 219125, 219126, + 219127, 219128, 219129, 219130, 219131, 219132, 219133, 219134, 219135, 219136, 219137, 219138, 219139, 219140, + 219141, 219142, 219143, 219144, 219145, 219146, 219147, 219148, 219149, 219150, 219151, 219152, 219153, 219154, + 219155, 219156, 219157, 219158, 219159, 219160, 219161, 219162, 219163, 219164, 219165, 219166, 219167, 219168, + 219169, 219170, 219171, 219172, 219173, 219174, 219175, 219176, 219177, 219178, 219179, 219180, 219181, 219182, + 219183, 219184, 219185, 219186, 219187, 219188, 219189, 219190, 219191, 219192, 219193, 219194, 219195, 219196, + 219197, 219198, 219199, 219200, 219201, 219202, 219203, 219204, 219205, 219206, 219207, 219208, 219209, 219210, + 219211, 219212, 219213, 219214, 219215, 219216, 219217, 219218, 219219, 219220, 220228, 221001, 221002, 221003, + 221004, 221005, 221006, 221007, 221008, 221009, 221010, 221011, 221012, 221013, 221014, 221015, 221016, 221017, + 221018, 221019, 221020, 221021, 221022, 221023, 221024, 221025, 221026, 221027, 221028, 221029, 221030, 221031, + 221032, 221033, 221034, 221035, 221036, 221037, 221038, 221039, 221040, 221041, 221042, 221043, 221044, 221045, + 221046, 221047, 221048, 221049, 221050, 221051, 221052, 221053, 221054, 221055, 221056, 221057, 221058, 221059, + 221060, 221061, 221062, 221063, 221064, 221065, 221066, 221067, 221068, 221069, 221070, 221071, 221072, 221073, + 221074, 221075, 221076, 221077, 221078, 221079, 221080, 221081, 221082, 221083, 221084, 221085, 221086, 221087, + 221088, 221089, 221090, 221091, 221092, 221093, 221094, 221095, 221096, 221097, 221098, 221099, 221100, 221101, + 221102, 221103, 221104, 221105, 221106, 221107, 221108, 221109, 221110, 221111, 221112, 221113, 221114, 221115, + 221116, 221117, 221118, 221119, 221120, 221121, 221122, 221123, 221124, 221125, 221126, 221127, 221128, 221129, + 221130, 221131, 221132, 221133, 221134, 221135, 221136, 221137, 221138, 221139, 221140, 221141, 221142, 221143, + 221144, 221145, 221146, 221147, 221148, 221149, 221150, 221151, 221152, 221153, 221154, 221155, 221156, 221157, + 221158, 221159, 221160, 221161, 221162, 221163, 221164, 221165, 221166, 221167, 221168, 221169, 221170, 221171, + 221172, 221173, 221174, 221175, 221176, 221177, 221178, 221179, 221180, 221181, 221182, 221183, 221184, 221185, + 221186, 221187, 221188, 221189, 221190, 221191, 221192, 221193, 221194, 221195, 221196, 221197, 221198, 221199, + 221200, 221201, 221202, 221203, 221204, 221205, 221206, 228025, 228040, 228041, 228042, 228043, 228091, 228092, + 228093, 228100, 228101, 228102, 228103, 228248, 228250, 228252, 228253, 228254, 228255, 234139, 234151, 234167, + 234228, + }; + + static const std::unordered_set discipline192MappableParams{35, 36, 37, 38, 39, 40, 41, 42, + 123, 139, 170, 183, 236, 151130, 151148, 151164}; + + return (discipline192Params.find(param) != discipline192MappableParams.end()) && + (!ignoreIfMappable || (discipline192MappableParams.find(param) == discipline192MappableParams.end())); +} + +//---------------------------------------------------------------------------------------------------------------------- + void Grib1ToGrib2Tool::execute(const CmdArgs& args) { // Handles to conversion libraries @@ -140,6 +432,12 @@ void Grib1ToGrib2Tool::execute(const CmdArgs& args) { while ((msg = msgReader.next())) { auto codesHandle = readCodesHandle(msg); + if (skipDiscipline192_ && + ((codesHandle->getLong("edition") == 1 && isDiscipline192(codesHandle->getLong("paramId"))) || + codesHandle->getLong("discipline") == 192)) { + continue; + } + // Read the MARS/Misc dictionary from the input GRIB sample const auto originalMarsMisc = grib2mars.convert(*codesHandle); @@ -152,6 +450,14 @@ void Grib1ToGrib2Tool::execute(const CmdArgs& args) { auto mars = mappedMarsMisc.mars; auto misc = mergeLocalConfigs(mappedMarsMisc.misc, originalMarsMisc.misc); + // Override values if specified by the user in the arguments + if (expver_) { + mars.set("expver", *expver_); + } + if (generatingProcessIdentifier_) { + misc.set("generatingProcessIdentifier", *generatingProcessIdentifier_); + } + // Encode into GRIB2 using mars2grib encoder const auto newSample = mars2grib.encode(values, mars, misc);