Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6b58f97
mars2mars: Fix wrong param conversion for 141
tweska Jul 20, 2026
40b987e
grib2mars: Set bitmapPresent as boolean
tweska Jul 20, 2026
83e87fa
grib2mars: Default initialStep to 0, and timeIncrementInSeconds to 3600
tweska Jul 20, 2026
6b50b3b
grib2mars: Read and set laplacianOperator as double
tweska Jul 21, 2026
19a6b38
mars2mars: Fix typo SFC -> sfc
tweska Jul 21, 2026
53353bf
mars2grib: Skip explicit level setting for isothermal fields
tweska Jul 21, 2026
0522024
mars2mars: Add misc param mappings lost during porting
tweska Jul 22, 2026
0431d76
grib2mars: Add extractors for iteration and coeffindex
tweska Jul 22, 2026
8c2df96
mars2mars: Add incremental param mappings lost during porting
tweska Jul 22, 2026
44413ce
grib2mars: Add extractor for typeOfProcessedData
tweska Jul 22, 2026
a8890dc
Run clang-format
tweska Jul 22, 2026
232fd37
grib2mars: Add extractor for numberOfComponents and modelErrorType
tweska Jul 22, 2026
5f04929
grib2mars: Simplify extraction of number and ensemble related keys
tweska Jul 23, 2026
26705bb
grib2mars,mars2grib: Support FourierCoefficients
tweska Jul 23, 2026
460942e
Apply suggestions from code review
tweska Jul 23, 2026
e76e6f3
grib1-to-grib2 tool: Add extra options needed for MTG2 conversion tasks
tweska Jul 24, 2026
1ea819a
mars2grib: Support scaleValuesBy and offsetValuesBy in encoder
tweska Jul 24, 2026
ca01c24
grib2mars,mars2grib: Remove laplacianOperator
tweska Jul 27, 2026
d4f24f3
grib1-to-grib2 tool: Detect discipline 192 based on paramId for GRIB1
tweska Jul 27, 2026
a6fa2d6
mars2grib: Fix level encoding of param 129172
tweska Jul 27, 2026
3c5f80a
grib2mars: Simplify step extraction
tweska Jul 27, 2026
4781488
grib2mars: Reintroduce logic to conditionally extract numberOfForecas…
tweska Jul 28, 2026
86b6da0
mars2mars: Convert stream waef to enfo
tweska Jul 28, 2026
662b570
mars2mars: Remove number from MARS dict for type=me
tweska Jul 28, 2026
4aee9a9
Run clang-format
tweska Aug 3, 2026
befc9e1
grib2mars,mars2mars: Support step ranges, and convert to step + timespan
tweska Aug 4, 2026
b627ab5
mars2mars: Set timespan to 0 for statistical fields as instant fields…
tweska Aug 4, 2026
19a7e8d
mars2mars: Avoid reading step with the wrong type
tweska Aug 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/metkit/grib2mars/mappings/rules/coeffindex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <string>

#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 <class MarsDict, class MiscDict>
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<long>(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
4 changes: 4 additions & 0 deletions src/metkit/grib2mars/mappings/rules/extract.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -88,6 +90,8 @@ const std::unordered_map<std::string, MarsExtractor<MarsDict, MiscDict>>& extrac
{"resolution", extractResolution<MarsDict, MiscDict>},
{"model", extractModel<MarsDict, MiscDict>},
{"wavelength", extractWavelength<MarsDict, MiscDict>},
{"iteration", extractIteration<MarsDict, MiscDict>},
{"coeffindex", extractCoeffindex<MarsDict, MiscDict>},
};

return registry;
Expand Down
37 changes: 37 additions & 0 deletions src/metkit/grib2mars/mappings/rules/iteration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include <string>

#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 <class MarsDict, class MiscDict>
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<long>(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
33 changes: 31 additions & 2 deletions src/metkit/grib2mars/mappings/rules/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,45 @@ namespace metkit::grib2mars::rules::impl {

template <class MarsDict, class MiscDict>
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);
}
Comment thread
tweska marked this conversation as resolved.

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<std::string>(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);
}
Comment thread
tweska marked this conversation as resolved.
}
catch (...) {
std::throw_with_nested(Grib2MarsGenericException("Failed to extract MISC keywords", Here()));
Expand Down
76 changes: 22 additions & 54 deletions src/metkit/grib2mars/mappings/rules/number.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<long>(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<long>(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());
}
}
Comment on lines 17 to 49

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that number must already be in the MARS namespace before this extractor is triggered.

catch (...) {
Expand Down
2 changes: 1 addition & 1 deletion src/metkit/grib2mars/mappings/rules/packing.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
60 changes: 18 additions & 42 deletions src/metkit/grib2mars/mappings/rules/step.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<long>(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<long>(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<long>(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<std::string>(mars, keyword, stepRange);
}

if (grib.has("timeIncrement")) {
Expand Down
6 changes: 0 additions & 6 deletions src/metkit/grib2mars/mappings/rules/truncation.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ void extractTruncation(const std::string& keyword, const metkit::codes::CodesHan
const long truncation = grib.getLong("J");

set_or_throw<long>(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()));
Expand Down
6 changes: 3 additions & 3 deletions src/metkit/mars2grib/backend/concepts/level/levelEncoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading
Loading