Skip to content

Commit

Permalink
Get iris-grib working with latest versions of its dependencies (Iris,…
Browse files Browse the repository at this point in the history
… eccodes, cftime, cartopy, proj) (#288)
  • Loading branch information
lbdreyer authored Mar 8, 2022
1 parent 832b526 commit ac658b4
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 312 deletions.
12 changes: 3 additions & 9 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,10 @@ linux_task_template: &LINUX_TASK_TEMPLATE

tests_task:
matrix:
# TODO: iris-grib does not currently work with iris-main, see Github issue
# #288 and #277.
#- name: "${CIRRUS_OS} tests: iris=repo-main python=3.8"
# env:
# PY_VER: 3.8
# IRIS_SOURCE: "source"
- name: "${CIRRUS_OS} tests: iris=conda-release python=3.7"
- name: "${CIRRUS_OS} tests: iris=repo-main python=3.8"
env:
PY_VER: 3.7
IRIS_SOURCE: "conda-forge"
PY_VER: 3.8
IRIS_SOURCE: "source"
- name: "${CIRRUS_OS} tests: iris=conda-release python=3.8"
env:
PY_VER: 3.8
Expand Down
12 changes: 8 additions & 4 deletions iris_grib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,12 @@ def phenomenon_points(self, time_unit):
"""
time_reference = '%s since epoch' % time_unit
return cf_units.date2num(self._phenomenonDateTime, time_reference,
cf_units.CALENDAR_GREGORIAN)
return float(
cf_units.date2num(
self._phenomenonDateTime, time_reference,
cf_units.CALENDAR_GREGORIAN
)
)

def phenomenon_bounds(self, time_unit):
"""
Expand All @@ -630,8 +634,8 @@ def phenomenon_bounds(self, time_unit):
# TODO #576 Investigate when it's valid to get phenomenon_bounds
time_reference = '%s since epoch' % time_unit
unit = cf_units.Unit(time_reference, cf_units.CALENDAR_GREGORIAN)
return [unit.date2num(self._periodStartDateTime),
unit.date2num(self._periodEndDateTime)]
return [float(unit.date2num(self._periodStartDateTime)),
float(unit.date2num(self._periodEndDateTime))]


def _longitude_is_cyclic(points):
Expand Down
6 changes: 3 additions & 3 deletions iris_grib/_load_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def reference_time_coord(section):
# Current GRIBAPI does not cover GRIB Section 1 - Octets 22-nn (optional)
# which are part of GRIB spec v12.
unit = Unit('hours since epoch', calendar=CALENDAR_GREGORIAN)
point = unit.date2num(dt)
point = float(unit.date2num(dt))

# Reference Code Table 1.2.
significanceOfReferenceTime = section['significanceOfReferenceTime']
Expand Down Expand Up @@ -1839,15 +1839,15 @@ def coord_timedelta(coord, value):
# Calculate validity (phenomenon) time in forecast-reference-time units.
frt_point = frt_coord.units.num2date(frt_coord.points[0])
point_delta = coord_timedelta(fp_coord, fp_coord.points[0])
point = frt_coord.units.date2num(frt_point + point_delta)
point = float(frt_coord.units.date2num(frt_point + point_delta))

# Calculate bounds (if any) in the same way.
if fp_coord.bounds is None:
bounds = None
else:
bounds_deltas = [coord_timedelta(fp_coord, bound_point)
for bound_point in fp_coord.bounds[0]]
bounds = [frt_coord.units.date2num(frt_point + delta)
bounds = [float(frt_coord.units.date2num(frt_point + delta))
for delta in bounds_deltas]

# Create the time scalar coordinate.
Expand Down
22 changes: 14 additions & 8 deletions iris_grib/_save_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import cf_units
import gribapi
from gribapi import GRIB_MISSING_LONG
import numpy as np
import numpy.ma as ma

Expand Down Expand Up @@ -180,13 +181,16 @@ def shape_of_the_earth(cube, grib):
# assume latlon
cs = cube.coord(dimensions=[0]).coord_system

# Initially set shape_of_earth keys to missing (255 for byte, -1 for long).
# Initially set shape_of_earth keys to missing (255 for byte).
gribapi.grib_set_long(grib, "scaleFactorOfRadiusOfSphericalEarth", 255)
gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth", -1)
gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth",
GRIB_MISSING_LONG)
gribapi.grib_set_long(grib, "scaleFactorOfEarthMajorAxis", 255)
gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis", -1)
gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis",
GRIB_MISSING_LONG)
gribapi.grib_set_long(grib, "scaleFactorOfEarthMinorAxis", 255)
gribapi.grib_set_long(grib, "scaledValueOfEarthMinorAxis", -1)
gribapi.grib_set_long(grib, "scaledValueOfEarthMinorAxis",
GRIB_MISSING_LONG)

if isinstance(cs, GeogCS):
ellipsoid = cs
Expand Down Expand Up @@ -923,9 +927,10 @@ def set_fixed_surfaces(cube, grib, full3d_cube=None):
gribapi.grib_set(grib, "scaleFactorOfFirstFixedSurface", 0)
gribapi.grib_set(grib, "scaledValueOfFirstFixedSurface", 0)
# Set secondary surface = 'missing'.
gribapi.grib_set(grib, "typeOfSecondFixedSurface", -1)
gribapi.grib_set(grib, "typeOfSecondFixedSurface", 255)
gribapi.grib_set(grib, "scaleFactorOfSecondFixedSurface", 255)
gribapi.grib_set(grib, "scaledValueOfSecondFixedSurface", -1)
gribapi.grib_set(grib, "scaledValueOfSecondFixedSurface",
GRIB_MISSING_LONG)
elif not v_coord.has_bounds():
# No second surface
output_v = v_coord.units.convert(v_coord.points[0], output_unit)
Expand All @@ -936,9 +941,10 @@ def set_fixed_surfaces(cube, grib, full3d_cube=None):
gribapi.grib_set(grib, "typeOfFirstFixedSurface", grib_v_code)
gribapi.grib_set(grib, "scaleFactorOfFirstFixedSurface", 0)
gribapi.grib_set(grib, "scaledValueOfFirstFixedSurface", output_v)
gribapi.grib_set(grib, "typeOfSecondFixedSurface", -1)
gribapi.grib_set(grib, "typeOfSecondFixedSurface", 255)
gribapi.grib_set(grib, "scaleFactorOfSecondFixedSurface", 255)
gribapi.grib_set(grib, "scaledValueOfSecondFixedSurface", -1)
gribapi.grib_set(grib, "scaledValueOfSecondFixedSurface",
GRIB_MISSING_LONG)
else:
# bounded : set lower+upper surfaces
output_v = v_coord.units.convert(v_coord.bounds[0], output_unit)
Expand Down
11 changes: 11 additions & 0 deletions iris_grib/tests/integration/format_interop/test_name_grib.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def name_cb(cube, field, filename):
if z_coord:
z_coord[0].standard_name = "height"
z_coord[0].long_name = "height above ground level"
z_coord[0].attributes = {'positive': 'up'}


class TestNameToGRIB(tests.IrisGribTest):
Expand Down Expand Up @@ -71,6 +72,11 @@ def test_name2_field(self):
warnings.warn(msg.format(i, name_cube.name()))
continue

# Iris>=3.2 loads in an extra 'z' coordinate which cannot currently
# be save to GRIB.
if name_cube.coords('z'):
name_cube.remove_coord('z')

with self.temp_filename(".grib2") as temp_filename:
iris.save(name_cube, temp_filename)
grib_cube = iris.load_cube(temp_filename, callback=name_cb)
Expand All @@ -92,6 +98,11 @@ def test_name3_field(self):
filepath = tests.get_data_path(("NAME", "NAMEIII_field.txt"))
name_cubes = iris.load(filepath)
for i, name_cube in enumerate(name_cubes):
# Iris>=3.2 loads in an extra 'z' coordinate which cannot currently
# be save to GRIB.
if name_cube.coord('z') is not None:
name_cube.remove_coord('z')

with self.temp_filename(".grib2") as temp_filename:
iris.save(name_cube, temp_filename)
grib_cube = iris.load_cube(temp_filename, callback=name_cb)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
<dimCoord bounds="[[0.0, 3.0]]" id="1d45e087" points="[3.0]" shape="(1,)" standard_name="forecast_period" units="Unit('hours')" value_type="float64"/>
</coord>
<coord>
<dimCoord bounds="[[0.0, 100.0]]" id="c87e380b" long_name="height above ground level" points="[50.0]" shape="(1,)" standard_name="height" units="Unit('m')" value_type="float64"/>
<dimCoord bounds="[[0.0, 100.0]]" id="1a539915" long_name="height above ground level" points="[50.0]" shape="(1,)" standard_name="height" units="Unit('m')" value_type="float64">
<attributes>
<attribute name="positive" value="up"/>
</attributes>
</dimCoord>
</coord>
<coord datadims="[0]">
<dimCoord id="77a50eb5" points="[52.367102, 52.368208, 52.369314, ..., 52.584984,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
<dimCoord bounds="[[0.0, 3.0]]" id="1d45e087" points="[3.0]" shape="(1,)" standard_name="forecast_period" units="Unit('hours')" value_type="float64"/>
</coord>
<coord>
<dimCoord bounds="[[0.0, 100.0]]" id="c87e380b" long_name="height above ground level" points="[50.0]" shape="(1,)" standard_name="height" units="Unit('m')" value_type="float64"/>
<dimCoord bounds="[[0.0, 100.0]]" id="1a539915" long_name="height above ground level" points="[50.0]" shape="(1,)" standard_name="height" units="Unit('m')" value_type="float64">
<attributes>
<attribute name="positive" value="up"/>
</attributes>
</dimCoord>
</coord>
<coord datadims="[0]">
<dimCoord id="77a50eb5" points="[52.367102, 52.368208, 52.369314, ..., 52.584984,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ def expected(self, y_dim, x_dim):
units='m',
coord_system=cs)
ny = 213
y_origin = 253793.10903714446
y_origin = 253793.10903714459

dy = 12000
y = iris.coords.DimCoord(np.arange(ny) * dy + y_origin,
'projection_y_coordinate',
Expand Down
15 changes: 9 additions & 6 deletions iris_grib/tests/unit/save_rules/test_set_fixed_surfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from unittest import mock

import gribapi
from gribapi import GRIB_MISSING_LONG
import numpy as np

import iris.cube
Expand Down Expand Up @@ -99,11 +100,11 @@ def test_altitude_point(self, mock_set):
mock_set.assert_any_call(grib, "scaleFactorOfFirstFixedSurface", 0)
mock_set.assert_any_call(grib, "scaledValueOfFirstFixedSurface",
12345)
mock_set.assert_any_call(grib, "typeOfSecondFixedSurface", -1)
mock_set.assert_any_call(grib, "typeOfSecondFixedSurface", 255)
mock_set.assert_any_call(grib, "scaleFactorOfSecondFixedSurface",
255)
mock_set.assert_any_call(grib, "scaledValueOfSecondFixedSurface",
-1)
GRIB_MISSING_LONG)

@mock.patch.object(gribapi, "grib_set")
def test_height_point(self, mock_set):
Expand All @@ -116,9 +117,10 @@ def test_height_point(self, mock_set):
mock_set.assert_any_call(grib, "typeOfFirstFixedSurface", 103)
mock_set.assert_any_call(grib, "scaleFactorOfFirstFixedSurface", 0)
mock_set.assert_any_call(grib, "scaledValueOfFirstFixedSurface", 12345)
mock_set.assert_any_call(grib, "typeOfSecondFixedSurface", -1)
mock_set.assert_any_call(grib, "typeOfSecondFixedSurface", 255)
mock_set.assert_any_call(grib, "scaleFactorOfSecondFixedSurface", 255)
mock_set.assert_any_call(grib, "scaledValueOfSecondFixedSurface", -1)
mock_set.assert_any_call(grib, "scaledValueOfSecondFixedSurface",
GRIB_MISSING_LONG)

@mock.patch.object(gribapi, "grib_set")
def test_no_vertical(self, mock_set):
Expand All @@ -128,9 +130,10 @@ def test_no_vertical(self, mock_set):
mock_set.assert_any_call(grib, "typeOfFirstFixedSurface", 1)
mock_set.assert_any_call(grib, "scaleFactorOfFirstFixedSurface", 0)
mock_set.assert_any_call(grib, "scaledValueOfFirstFixedSurface", 0)
mock_set.assert_any_call(grib, "typeOfSecondFixedSurface", -1)
mock_set.assert_any_call(grib, "typeOfSecondFixedSurface", 255)
mock_set.assert_any_call(grib, "scaleFactorOfSecondFixedSurface", 255)
mock_set.assert_any_call(grib, "scaledValueOfSecondFixedSurface", -1)
mock_set.assert_any_call(grib, "scaledValueOfSecondFixedSurface",
GRIB_MISSING_LONG)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _session_lockfile(session: nox.sessions.Session) -> Path:
"""
lockfile_name = f"py{session.python.replace('.', '')}-linux-64.lock"
return Path("requirements/nox.lock") / lockfile_name
return Path("requirements/ci/nox.lock") / lockfile_name


def _file_content(file_path: Path) -> str:
Expand Down
2 changes: 1 addition & 1 deletion requirements/ci/iris-grib.yml
Loading

0 comments on commit ac658b4

Please sign in to comment.