Skip to content

Commit 50bb9bf

Browse files
authored
Merge pull request ecmwf#371 from Metamess/issue-370-endstep-not-integer
Explicitly request value for 'endStep' as integer
2 parents a7ccd26 + cc5e3c4 commit 50bb9bf

6 files changed

+38
-5
lines changed

CHANGELOG.rst

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
Changelog for cfgrib
33
====================
44

5+
x.x.x.x (xxxx-xx-xx)
6+
--------------------
7+
8+
- fixed issue where GRIB messages with non-hourly steps could not be read
9+
See `#370 <https://github.com/ecmwf/cfgrib/pull/370>`_.
10+
11+
512
0.9.11.0 (2024-04-05)
613
---------------------
714

cfgrib/cfmessage.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def to_grib_date_time(
8787
message[time_key] = int(datetime_iso[11:16].replace(":", ""))
8888

8989

90-
def from_grib_step(message, step_key="endStep", step_unit_key="stepUnits"):
90+
def from_grib_step(message, step_key="endStep:int", step_unit_key="stepUnits:int"):
9191
# type: (abc.Field, str, str) -> float
9292
step_unit = message[step_unit_key]
9393
to_seconds = GRIB_STEP_UNITS_TO_SECONDS[step_unit]
@@ -97,7 +97,7 @@ def from_grib_step(message, step_key="endStep", step_unit_key="stepUnits"):
9797
return int(message[step_key]) * to_seconds / 3600.0
9898

9999

100-
def to_grib_step(message, step_ns, step_unit=1, step_key="endStep", step_unit_key="stepUnits"):
100+
def to_grib_step(message, step_ns, step_unit=1, step_key="endStep:int", step_unit_key="stepUnits:int"):
101101
# type: (abc.MutableField, int, int, str, str) -> None
102102
step_s = step_ns * 1e-9
103103
to_seconds = GRIB_STEP_UNITS_TO_SECONDS[step_unit]
@@ -107,6 +107,17 @@ def to_grib_step(message, step_ns, step_unit=1, step_key="endStep", step_unit_ke
107107
message[step_unit_key] = step_unit
108108

109109

110+
def from_grib_step_units(message):
111+
# type: (abc.Field) -> float
112+
# we always index steps in hours
113+
return 1
114+
115+
116+
def to_grib_step_units(message, step_unit=1, step_unit_key="stepUnits:int"):
117+
# type: (abc.MutableField, int, str) -> None
118+
message[step_unit_key] = step_unit
119+
120+
110121
def from_grib_month(message, verifying_month_key="verifyingMonth", epoch=DEFAULT_EPOCH):
111122
# type: (abc.Field, str, datetime.datetime) -> int
112123
date = message[verifying_month_key]
@@ -149,6 +160,8 @@ def build_valid_time(time, step):
149160
COMPUTED_KEYS = {
150161
"time": (from_grib_date_time, to_grib_date_time),
151162
"step": (from_grib_step, to_grib_step),
163+
"endStep": (from_grib_step, to_grib_step),
164+
"stepUnits": (from_grib_step_units, to_grib_step_units),
152165
"valid_time": (
153166
functools.partial(from_grib_date_time, date_key="validityDate", time_key="validityTime"),
154167
functools.partial(to_grib_date_time, date_key="validityDate", time_key="validityTime"),

tests/sample-data/step_60m.grib

17.1 KB
Binary file not shown.

tests/test_25_cfmessage.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_to_grib_date_time() -> None:
2828

2929

3030
def test_from_grib_step() -> None:
31-
message = {"endStep": 1, "stepUnits": 1}
31+
message = {"endStep:int": 1, "stepUnits:int": 1}
3232
step_seconds = cfmessage.from_grib_step(message)
3333

3434
assert step_seconds == 1
@@ -40,8 +40,8 @@ def test_to_grib_step() -> None:
4040

4141
cfmessage.to_grib_step(message, step_ns, step_unit=1)
4242

43-
assert message["endStep"] == 1
44-
assert message["stepUnits"] == 1
43+
assert message["endStep:int"] == 1
44+
assert message["stepUnits:int"] == 1
4545

4646
with pytest.raises(ValueError):
4747
cfmessage.to_grib_step(message, 0, step_unit=3)

tests/test_40_xarray_store.py

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import gribapi # type: ignore
44
import numpy as np
5+
import pandas as pd
56
import pytest
67

78
xr = pytest.importorskip("xarray") # noqa
@@ -17,6 +18,7 @@
1718
TEST_DATA_MULTIPLE_FIELDS = os.path.join(SAMPLE_DATA_FOLDER, "regular_gg_ml_g2.grib")
1819
TEST_DATA_DIFFERENT_STEP_TYPES = os.path.join(SAMPLE_DATA_FOLDER, "cfrzr_and_cprat.grib")
1920
TEST_DATA_DIFFERENT_STEP_TYPES_ZEROS = os.path.join(SAMPLE_DATA_FOLDER, "cfrzr_and_cprat_0s.grib")
21+
TEST_DATA_STEPS_IN_MINUTES = os.path.join(SAMPLE_DATA_FOLDER, "step_60m.grib")
2022
TEST_DATA_ALTERNATE_ROWS_MERCATOR = os.path.join(SAMPLE_DATA_FOLDER, "ds.waveh.5.grib")
2123

2224

@@ -157,6 +159,16 @@ def test_open_datasets_differet_step_types_zeros() -> None:
157159
assert res[1].cfrzr.attrs["GRIB_stepType"] == "avg"
158160

159161

162+
def test_open_dataset_steps_in_minutes() -> None:
163+
res = xarray_store.open_dataset(TEST_DATA_STEPS_IN_MINUTES)
164+
165+
var = res["t2m"]
166+
steps = var.step
167+
assert steps[0] == pd.Timedelta("0 hours")
168+
assert steps[1] == pd.Timedelta("1 hours")
169+
assert steps[5] == pd.Timedelta("5 hours")
170+
171+
160172
def test_alternating_scanning_mercator() -> None:
161173
ds = xarray_store.open_dataset(TEST_DATA_ALTERNATE_ROWS_MERCATOR)
162174
values = ds.variables["shww"].data

tests/test_50_sample_data.py

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"single_gridpoint",
3030
"spherical_harmonics",
3131
"t_analysis_and_fc_0",
32+
"step_60m",
3233
],
3334
)
3435
def test_open_dataset(grib_name: str) -> None:

0 commit comments

Comments
 (0)