diff --git a/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h b/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h index 9efdb362..3d004351 100644 --- a/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h +++ b/src/metkit/mars2grib/backend/concepts/level/levelEncoding.h @@ -106,7 +106,8 @@ constexpr bool needLevel() { Variant == LevelType::HeightAboveSeaAt2M || Variant == LevelType::HeightAboveSea || Variant == LevelType::Hybrid || Variant == LevelType::IsobaricInHpa || Variant == LevelType::IsobaricInPa || Variant == LevelType::Isothermal || - Variant == LevelType::PotentialVorticity || Variant == LevelType::Theta) { + Variant == LevelType::PotentialVorticity || Variant == LevelType::Theta || + Variant == LevelType::OceanModel) { return true; } else { @@ -131,7 +132,7 @@ constexpr bool needLevel() { template constexpr bool needTopBottomLevel() { if constexpr (Variant == LevelType::SoilLayer || Variant == LevelType::SeaIceLayer || - Variant == LevelType::SnowLayer) { + Variant == LevelType::SnowLayer || Variant == LevelType::OceanModelLayer) { return true; } else { @@ -291,10 +292,6 @@ void LevelOp(const MarsDict_t& mars, const ParDict_t& par, const OptDict_t& opt, long levelVal = deductions::resolve_Level_or_throw(mars, par, opt); set_or_throw(out, "level", levelVal); } - if constexpr (needLevel()) { - long levelVal = deductions::resolve_Level_or_throw(mars, par, opt); - set_or_throw(out, "level", levelVal); - } if constexpr (needTopBottomLevel()) { long levelVal = deductions::resolve_Level_or_throw(mars, par, opt); long topLevel = levelVal - 1; diff --git a/src/metkit/mars2grib/backend/concepts/level/levelEnum.h b/src/metkit/mars2grib/backend/concepts/level/levelEnum.h index 66b20af2..c88dc368 100644 --- a/src/metkit/mars2grib/backend/concepts/level/levelEnum.h +++ b/src/metkit/mars2grib/backend/concepts/level/levelEnum.h @@ -109,11 +109,20 @@ enum class LevelType : std::size_t { SnowLayer, SoilLayer, SeaIceLayer, + OceanSurface, DepthBelowSeaLayer, + OceanSurfaceToBottom, LakeBottom, MixingLayer, + OceanModel, + OceanModelLayer, + MixedLayerDepthByDensity, + MixedLayerDepthByTemperature, + SnowLayerOverIceOnWater, IceTopOnWater, IceLayerOnWater, + EntireMeltPond, + WaterSurfaceToIsothermalOceanLayer, AbstractSingleLevel, AbstractMultipleLevel, HeightAboveSeaAt10M, @@ -142,11 +151,14 @@ using LevelList = LevelType::Isothermal, LevelType::IsobaricInPa, LevelType::IsobaricInHpa, LevelType::LowCloudLayer, LevelType::MediumCloudLayer, LevelType::HighCloudLayer, LevelType::MeanSea, LevelType::HeightAboveSea, LevelType::HeightAboveGround, LevelType::Hybrid, LevelType::Theta, LevelType::PotentialVorticity, - LevelType::SnowLayer, LevelType::SoilLayer, LevelType::SeaIceLayer, LevelType::DepthBelowSeaLayer, - LevelType::LakeBottom, LevelType::MixingLayer, LevelType::IceTopOnWater, LevelType::IceLayerOnWater, - LevelType::AbstractSingleLevel, LevelType::AbstractMultipleLevel, LevelType::HeightAboveSeaAt10M, - LevelType::HeightAboveSeaAt2M, LevelType::HeightAboveGroundAt10M, LevelType::HeightAboveGroundAt2M, - LevelType::Default>; + LevelType::SnowLayer, LevelType::SoilLayer, LevelType::SeaIceLayer, LevelType::OceanSurface, + LevelType::DepthBelowSeaLayer, LevelType::OceanSurfaceToBottom, LevelType::LakeBottom, + LevelType::MixingLayer, LevelType::OceanModel, LevelType::OceanModelLayer, + LevelType::MixedLayerDepthByDensity, LevelType::MixedLayerDepthByTemperature, + LevelType::SnowLayerOverIceOnWater, LevelType::IceTopOnWater, LevelType::IceLayerOnWater, + LevelType::EntireMeltPond, LevelType::WaterSurfaceToIsothermalOceanLayer, LevelType::AbstractSingleLevel, + LevelType::AbstractMultipleLevel, LevelType::HeightAboveSeaAt10M, LevelType::HeightAboveSeaAt2M, + LevelType::HeightAboveGroundAt10M, LevelType::HeightAboveGroundAt2M, LevelType::Default>; /// @@ -199,11 +211,20 @@ DEF(LevelType::PotentialVorticity, "potentialVorticity"); DEF(LevelType::SnowLayer, "snowLayer"); DEF(LevelType::SoilLayer, "soilLayer"); DEF(LevelType::SeaIceLayer, "seaIceLayer"); +DEF(LevelType::OceanSurface, "oceanSurface"); DEF(LevelType::DepthBelowSeaLayer, "depthBelowSeaLayer"); +DEF(LevelType::OceanSurfaceToBottom, "oceanSurfaceToBottom"); DEF(LevelType::LakeBottom, "lakeBottom"); DEF(LevelType::MixingLayer, "mixingLayer"); +DEF(LevelType::OceanModel, "oceanModel"); +DEF(LevelType::OceanModelLayer, "oceanModelLayer"); +DEF(LevelType::MixedLayerDepthByDensity, "mixedLayerDepthByDensity"); +DEF(LevelType::MixedLayerDepthByTemperature, "mixedLayerDepthByTemperature"); +DEF(LevelType::SnowLayerOverIceOnWater, "snowLayerOverIceOnWater"); DEF(LevelType::IceTopOnWater, "iceTopOnWater"); DEF(LevelType::IceLayerOnWater, "iceLayerOnWater"); +DEF(LevelType::EntireMeltPond, "entireMeltPond"); +DEF(LevelType::WaterSurfaceToIsothermalOceanLayer, "waterSurfaceToIsothermalOceanLayer"); DEF(LevelType::AbstractSingleLevel, "abstractSingleLevel"); DEF(LevelType::AbstractMultipleLevel, "abstractMultipleLevel"); DEF(LevelType::HeightAboveSeaAt10M, "heightAboveSeaAt10m"); diff --git a/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h b/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h index 560cfec9..a7941125 100644 --- a/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h +++ b/src/metkit/mars2grib/backend/concepts/level/levelMatcher.h @@ -239,10 +239,66 @@ inline std::size_t matchAL(const long param) { if (matchAny(param, range(213101, 213160))) { return static_cast(LevelType::AbstractSingleLevel); } - else { - throw utils::exceptions::Mars2GribMatcherException( - "No mapping exists for param \"" + std::to_string(param) + "\" on levtype AL", Here()); + + throw utils::exceptions::Mars2GribMatcherException( + "No mapping exists for param \"" + std::to_string(param) + "\" on levtype AL", Here()); +} + +inline std::size_t matchO2D(const long param) { + using metkit::mars2grib::util::param_matcher::matchAny; + using metkit::mars2grib::util::param_matcher::range; + + if (matchAny(param, 262000, 262003, 262004, 262008, 262014, 262023)) { + return static_cast(LevelType::IceLayerOnWater); + } + if (matchAny(param, 262001, 262005, 262006)) { + return static_cast(LevelType::IceTopOnWater); + } + if (matchAny(param, 262002, 262009, 262011, 262015)) { + return static_cast(LevelType::SnowLayerOverIceOnWater); + } + if (matchAny(param, 262017, 262018)) { + return static_cast(LevelType::EntireMeltPond); + } + if (matchAny(param, 262100, 262101, 262108, 262124, 262125, 262130, 262139, 262140, 262143)) { + return static_cast(LevelType::OceanSurface); + } + if (matchAny(param, range(262102, 262106))) { + return static_cast(LevelType::Isothermal); + } + if (matchAny(param, range(262113, 262115))) { + return static_cast(LevelType::MixedLayerDepthByDensity); + } + if (matchAny(param, 262116)) { + return static_cast(LevelType::MixedLayerDepthByTemperature); } + if (matchAny(param, 262118, 262119, 262121, 262122)) { + return static_cast(LevelType::DepthBelowSeaLayer); + } + if (matchAny(param, 262120, 262123)) { + return static_cast(LevelType::OceanSurfaceToBottom); + } + if (matchAny(param, 262141)) { + return static_cast(LevelType::WaterSurfaceToIsothermalOceanLayer); + } + + throw utils::exceptions::Mars2GribMatcherException( + "No mapping exists for param \"" + std::to_string(param) + "\" on levtype O2D", Here()); +} + +inline std::size_t matchO3D(const long param) { + using metkit::mars2grib::util::param_matcher::matchAny; + using metkit::mars2grib::util::param_matcher::range; + + if (matchAny(param, range(262500, 262502), 262505, 262506)) { + return static_cast(LevelType::OceanModelLayer); + } + if (matchAny(param, 262507)) { + return static_cast(LevelType::OceanModel); + } + + throw utils::exceptions::Mars2GribMatcherException( + "No mapping exists for param \"" + std::to_string(param) + "\" on levtype O3D", Here()); } } // namespace impl @@ -287,6 +343,12 @@ std::size_t levelMatcher(const MarsDict_t& mars, const OptDict_t& opt) { if (levtype == "al") { return impl::matchAL(param); } + if (levtype == "o2d") { + return impl::matchO2D(param); + } + if (levtype == "o3d") { + return impl::matchO3D(param); + } throw utils::exceptions::Mars2GribMatcherException("Unknown levtype \"" + levtype + "\"", Here()); }; diff --git a/src/metkit/mars2grib/backend/concepts/point-in-time/pointInTimeMatcher.h b/src/metkit/mars2grib/backend/concepts/point-in-time/pointInTimeMatcher.h index dd53ad8d..daa51a72 100644 --- a/src/metkit/mars2grib/backend/concepts/point-in-time/pointInTimeMatcher.h +++ b/src/metkit/mars2grib/backend/concepts/point-in-time/pointInTimeMatcher.h @@ -31,8 +31,10 @@ std::size_t pointInTimeMatcher(const MarsDict_t& mars, const OptDict_t& opt) { range(228044, 228048), 228050, 228052, range(228088, 228090), 228131, 228132, 228141, 228164, range(228217, 228221), range(228231, 228237), 229001, 260004, 260005, 260015, 260038, 260048, 260109, 260121, 260123, 260132, 260199, 260242, 260255, 260260, 260289, 260290, 260292, 260293, 260360, 260509, - 260688, 261001, 261002, range(261014, 261016), 261018, 261023, 262000, 262024, 262100, 262104, 262118, - 262124, 262139, 262140, 262144)) { + 260688, 261001, 261002, range(261014, 261016), 261018, 261023, range(262000, 262009), 262011, 262014, + 262015, 262017, 262018, 262023, 262024, range(262100, 262106), 262108, range(262113, 262116), + range(262118, 262125), 262130, range(262139, 262141), 262143, 262144, range(262500, 262502), + range(262505, 262507))) { return static_cast(PointInTimeType::Default); } diff --git a/src/metkit/mars2grib/backend/concepts/representation/representationEncoding.h b/src/metkit/mars2grib/backend/concepts/representation/representationEncoding.h index 400261c2..f3c969ad 100644 --- a/src/metkit/mars2grib/backend/concepts/representation/representationEncoding.h +++ b/src/metkit/mars2grib/backend/concepts/representation/representationEncoding.h @@ -127,6 +127,7 @@ // Eckit::geo includes #include "eckit/geo/Grid.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/grid/ORCA.h" #include "eckit/geo/grid/reduced/HEALPix.h" #include "eckit/geo/grid/reduced/ReducedGaussian.h" #include "eckit/geo/grid/regular/RegularGaussian.h" @@ -302,8 +303,8 @@ void RepresentationOp(const MarsDict_t& mars, const ParDict_t& par, const OptDic // Checks/Validation validation::match_GridDefinitionTemplateNumber_or_throw(opt, out, {101}); - // Not implemented error - MARS2GRIB_CONCEPT_THROW(representation, "Support for Orca representation not implemented..."); + // Encoding + set_or_throw(out, "gridType", "unstructured_grid"); } else if constexpr (Variant == RepresentationType::Fesom) { @@ -348,6 +349,7 @@ void RepresentationOp(const MarsDict_t& mars, const ParDict_t& par, const OptDic const auto jDirectionIncrementInDegrees = std::abs(grid->dlat()); // Encoding + set_or_throw(out, "resolutionAndComponentFlags", 0); // Flag table 3.3 set_or_throw(out, "Ni", Ni); set_or_throw(out, "Nj", Nj); set_or_throw(out, "latitudeOfFirstGridPointInDegrees", latitudeOfFirstGridPointInDegrees); @@ -379,6 +381,7 @@ void RepresentationOp(const MarsDict_t& mars, const ParDict_t& par, const OptDic // TODO (GEOM): numberOfParallelsBetweenAPoleAndTheEquator, and numberOfPointsAlongAMeridian ? // Encoding + set_or_throw(out, "resolutionAndComponentFlags", 0); // Flag table 3.3 set_or_throw(out, "latitudeOfFirstGridPointInDegrees", latitudeOfFirstGridPointInDegrees); set_or_throw(out, "longitudeOfFirstGridPointInDegrees", longitudeOfFirstGridPointInDegrees); set_or_throw(out, "latitudeOfLastGridPointInDegrees", latitudeOfLastGridPointInDegrees); @@ -407,6 +410,7 @@ void RepresentationOp(const MarsDict_t& mars, const ParDict_t& par, const OptDic // TODO (GEOM): numberOfPointsAlongAMeridian ? // Encoding + set_or_throw(out, "resolutionAndComponentFlags", 0); // Flag table 3.3 set_or_throw(out, "latitudeOfFirstGridPointInDegrees", latitudeOfFirstGridPointInDegrees); set_or_throw(out, "longitudeOfFirstGridPointInDegrees", longitudeOfFirstGridPointInDegrees); set_or_throw(out, "latitudeOfLastGridPointInDegrees", latitudeOfLastGridPointInDegrees); @@ -441,12 +445,27 @@ void RepresentationOp(const MarsDict_t& mars, const ParDict_t& par, const OptDic std::get(grid->first_point()).lon(); // Encoding + set_or_throw(out, "resolutionAndComponentFlags", 0); // Flag table 3.3 set_or_throw(out, "nside", nside); set_or_throw(out, "orderingConvention", orderingConvention); set_or_throw(out, "longitudeOfFirstGridPointInDegrees", longitudeOfFirstGridPointInDegrees); } else if constexpr (Variant == RepresentationType::Orca) { - MARS2GRIB_CONCEPT_THROW(representation, "Support for Orca representation not implemented..."); + + // Deductions + const auto marsGrid = get_or_throw(mars, "grid"); + const eckit::spec::Custom gridSpec = {{"grid", marsGrid}}; + const std::unique_ptr genericGrid(eckit::geo::GridFactory::build(gridSpec)); + const auto* grid = dynamic_cast(genericGrid.get()); + + const auto gridType = grid->name(); + const auto gridSubType = grid->arrangement(); + const auto uuid = grid->uid(); + + // Encoding + set_or_throw(out, "unstructuredGridType", gridType); + set_or_throw(out, "unstructuredGridSubtype", gridSubType); + set_or_throw(out, "uuidOfHGrid", uuid); } else if constexpr (Variant == RepresentationType::Fesom) { MARS2GRIB_CONCEPT_THROW(representation, "Support for Fesom representation not implemented..."); diff --git a/src/metkit/mars2grib/backend/concepts/representation/representationMatcher.h b/src/metkit/mars2grib/backend/concepts/representation/representationMatcher.h index 08cabf17..ab226695 100644 --- a/src/metkit/mars2grib/backend/concepts/representation/representationMatcher.h +++ b/src/metkit/mars2grib/backend/concepts/representation/representationMatcher.h @@ -33,6 +33,9 @@ std::size_t representationMatcher(const MarsDict_t& mars, const OptDict_t& opt) else if (gridType == "regular-ll") { return static_cast(RepresentationType::Latlon); } + else if (gridType == "ORCA") { + return static_cast(RepresentationType::Orca); + } throw utils::exceptions::Mars2GribMatcherException( "Cannot match grid \"" + marsGrid + "\" with grid type \"" + gridType + "\"! ", Here()); diff --git a/src/metkit/mars2grib/backend/sections/initializers/sectionInitializer3.h b/src/metkit/mars2grib/backend/sections/initializers/sectionInitializer3.h index 32150fb0..7ba8a822 100644 --- a/src/metkit/mars2grib/backend/sections/initializers/sectionInitializer3.h +++ b/src/metkit/mars2grib/backend/sections/initializers/sectionInitializer3.h @@ -108,7 +108,6 @@ void allocateTemplateNumber3(const MarsDict_t& mars, const ParDict_t& par, const // Standard grid definition template long drt = static_cast(TemplateNumber); set_or_throw(out, "gridDefinitionTemplateNumber", drt); - set_or_throw(out, "resolutionAndComponentFlags", 0L); } return; diff --git a/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section3Recipes.h b/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section3Recipes.h index 4364abf1..557c1200 100644 --- a/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section3Recipes.h +++ b/src/metkit/mars2grib/frontend/resolution/section-recipes/impl/section3Recipes.h @@ -51,6 +51,13 @@ inline const Recipe S3_R101 = RepresentationType::GeneralUnstructured> >(); +inline const Recipe S3_R101_ORCA = + make_recipe<101, + Select, + Select + >(); + // HEALPix grid inline const Recipe S3_R150 = make_recipe<150, @@ -69,6 +76,7 @@ inline const Recipes Section3Recipes{ 3, &S3_R40, &S3_R50, &S3_R101, + &S3_R101_ORCA, &S3_R150 } };