From 00040561745ea47bd6d4197ed484d437cb1c945a Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Mon, 8 Dec 2014 12:27:58 +0000 Subject: [PATCH 1/2] Improve grib saving of shape of the earth key --- lib/iris/fileformats/grib/_save_rules.py | 17 ++- lib/iris/tests/integration/test_grib2.py | 2 +- ..._forecast_plev.grib_compare.post1-12-0.txt | 1 - ...rotated_latlon.grib_compare.post1-12-0.txt | 1 - .../time_mean.grib_compare.post1-12-0.txt | 1 - .../test_grid_definition_template_0.py | 19 --- .../test_grid_definition_template_1.py | 24 ---- .../test_grid_definition_template_12.py | 8 -- .../test_grid_definition_template_5.py | 23 ---- .../save_rules/test_shape_of_the_earth.py | 115 ++++++++++++++++++ 10 files changed, 129 insertions(+), 82 deletions(-) create mode 100644 lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py diff --git a/lib/iris/fileformats/grib/_save_rules.py b/lib/iris/fileformats/grib/_save_rules.py index 4dc9b94c7e..acb1c95f5c 100644 --- a/lib/iris/fileformats/grib/_save_rules.py +++ b/lib/iris/fileformats/grib/_save_rules.py @@ -178,7 +178,6 @@ def identification(cube, grib): 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). @@ -200,13 +199,23 @@ def shape_of_the_earth(cube, grib): # Spherical earth. if ellipsoid.inverse_flattening == 0.0: - gribapi.grib_set_long(grib, "shapeOfTheEarth", 1) - gribapi.grib_set_long(grib, "scaleFactorOfRadiusOfSphericalEarth", 0) + # Set shapeOfTheEarth key based on value of spherical earth radius. + if int(ellipsoid.semi_major_axis) == 6367470: + gribapi.grib_set_long(grib, "shapeOfTheEarth", 0) + elif int(ellipsoid.semi_major_axis) == 6371229: + gribapi.grib_set_long(grib, "shapeOfTheEarth", 6) + else: + gribapi.grib_set_long(grib, "shapeOfTheEarth", 1) + gribapi.grib_set_long(grib, + "scaleFactorOfRadiusOfSphericalEarth", 0) gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth", ellipsoid.semi_major_axis) # Oblate spheroid earth. else: - gribapi.grib_set_long(grib, "shapeOfTheEarth", 7) + if isinstance(cs, iris.coord_systems.OSGB): + gribapi.grib_set_long(grib, "shapeOfTheEarth", 9) + else: + gribapi.grib_set_long(grib, "shapeOfTheEarth", 7) gribapi.grib_set_long(grib, "scaleFactorOfEarthMajorAxis", 0) gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis", ellipsoid.semi_major_axis) diff --git a/lib/iris/tests/integration/test_grib2.py b/lib/iris/tests/integration/test_grib2.py index 8b9e86982d..d9782fe033 100644 --- a/lib/iris/tests/integration/test_grib2.py +++ b/lib/iris/tests/integration/test_grib2.py @@ -140,7 +140,7 @@ def test_save_load(self): 'gridDefinitionTemplateNumber = 5', 'Ni = {:d}'.format(cube.shape[-1]), 'Nj = {:d}'.format(cube.shape[-2]), - 'shapeOfTheEarth = 1', + 'shapeOfTheEarth = 6', 'scaledValueOfRadiusOfSphericalEarth = {:d}'.format( int(UM_DEFAULT_EARTH_RADIUS)), 'resolutionAndComponentFlags = 0', diff --git a/lib/iris/tests/results/grib_save/latlon_forecast_plev.grib_compare.post1-12-0.txt b/lib/iris/tests/results/grib_save/latlon_forecast_plev.grib_compare.post1-12-0.txt index 2a0880c2b7..e5c06ce24c 100644 --- a/lib/iris/tests/results/grib_save/latlon_forecast_plev.grib_compare.post1-12-0.txt +++ b/lib/iris/tests/results/grib_save/latlon_forecast_plev.grib_compare.post1-12-0.txt @@ -6,7 +6,6 @@ long [productionStatusOfProcessedData]: [0] != [255] [section2Length] not found in 2nd field long [numberOfSection] 6 out of 7 different long [numberOfSection] 5 out of 7 different -long [shapeOfTheEarth]: [0] != [1] scaleFactorOfRadiusOfSphericalEarth is set to missing in 1st field is not missing in 2nd field scaledValueOfRadiusOfSphericalEarth is set to missing in 1st field is not missing in 2nd field long [numberOfSection] 6 out of 7 different diff --git a/lib/iris/tests/results/grib_save/rotated_latlon.grib_compare.post1-12-0.txt b/lib/iris/tests/results/grib_save/rotated_latlon.grib_compare.post1-12-0.txt index 1e61b1596c..8705ecacff 100644 --- a/lib/iris/tests/results/grib_save/rotated_latlon.grib_compare.post1-12-0.txt +++ b/lib/iris/tests/results/grib_save/rotated_latlon.grib_compare.post1-12-0.txt @@ -6,7 +6,6 @@ long [productionStatusOfProcessedData]: [0] != [255] [section2Length] not found in 2nd field long [numberOfSection] 6 out of 7 different long [numberOfSection] 5 out of 7 different -long [shapeOfTheEarth]: [0] != [1] scaleFactorOfRadiusOfSphericalEarth is set to missing in 1st field is not missing in 2nd field scaledValueOfRadiusOfSphericalEarth is set to missing in 1st field is not missing in 2nd field long [latitudeOfLastGridPoint]: [19419996] != [19419285] diff --git a/lib/iris/tests/results/grib_save/time_mean.grib_compare.post1-12-0.txt b/lib/iris/tests/results/grib_save/time_mean.grib_compare.post1-12-0.txt index a016399ae1..519a02c39b 100644 --- a/lib/iris/tests/results/grib_save/time_mean.grib_compare.post1-12-0.txt +++ b/lib/iris/tests/results/grib_save/time_mean.grib_compare.post1-12-0.txt @@ -6,7 +6,6 @@ long [productionStatusOfProcessedData]: [0] != [255] [section2Length] not found in 2nd field long [numberOfSection] 6 out of 7 different long [numberOfSection] 5 out of 7 different -long [shapeOfTheEarth]: [0] != [1] scaleFactorOfRadiusOfSphericalEarth is set to missing in 1st field is not missing in 2nd field scaledValueOfRadiusOfSphericalEarth is set to missing in 1st field is not missing in 2nd field long [latitudeOfLastGridPoint]: [-89999938] != [-89999944] diff --git a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_0.py b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_0.py index be81d18a24..ad5fd285a9 100644 --- a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_0.py +++ b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_0.py @@ -42,25 +42,6 @@ def test__template_number(self): grid_definition_template_0(self.test_cube, self.mock_grib) self._check_key('gridDefinitionTemplateNumber', 0) - def test__shape_of_earth_spherical(self): - cs = GeogCS(semi_major_axis=1.23) - test_cube = self._make_test_cube(cs=cs) - grid_definition_template_0(test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 1) - self._check_key('scaleFactorOfRadiusOfSphericalEarth', 0) - self._check_key('scaledValueOfRadiusOfSphericalEarth', 1.23) - - def test__shape_of_earth_flattened(self): - cs = GeogCS(semi_major_axis=1.456, - semi_minor_axis=1.123) - test_cube = self._make_test_cube(cs=cs) - grid_definition_template_0(test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 7) - self._check_key('scaleFactorOfEarthMajorAxis', 0) - self._check_key('scaledValueOfEarthMajorAxis', 1.456) - self._check_key('scaleFactorOfEarthMinorAxis', 0) - self._check_key('scaledValueOfEarthMinorAxis', 1.123) - def test__grid_shape(self): test_cube = self._make_test_cube(x_points=np.arange(13), y_points=np.arange(6)) diff --git a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_1.py b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_1.py index aca748f966..48267ea02e 100644 --- a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_1.py +++ b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_1.py @@ -52,30 +52,6 @@ def test__template_number(self): grid_definition_template_1(self.test_cube, self.mock_grib) self._check_key('gridDefinitionTemplateNumber', 1) - def test__shape_of_earth_spherical(self): - ellipsoid = GeogCS(1.23) - cs = RotatedGeogCS(grid_north_pole_latitude=90.0, - grid_north_pole_longitude=0.0, - ellipsoid=ellipsoid) - test_cube = self._make_test_cube(cs=cs) - grid_definition_template_1(test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 1) - self._check_key('scaleFactorOfRadiusOfSphericalEarth', 0) - self._check_key('scaledValueOfRadiusOfSphericalEarth', 1.23) - - def test__shape_of_earth_flattened(self): - ellipsoid = GeogCS(semi_major_axis=1.456, semi_minor_axis=1.123) - cs = RotatedGeogCS(grid_north_pole_latitude=90.0, - grid_north_pole_longitude=0.0, - ellipsoid=ellipsoid) - test_cube = self._make_test_cube(cs=cs) - grid_definition_template_1(test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 7) - self._check_key('scaleFactorOfEarthMajorAxis', 0) - self._check_key('scaledValueOfEarthMajorAxis', 1.456) - self._check_key('scaleFactorOfEarthMinorAxis', 0) - self._check_key('scaledValueOfEarthMinorAxis', 1.123) - def test__grid_shape(self): test_cube = self._make_test_cube(x_points=np.arange(13), y_points=np.arange(6)) diff --git a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_12.py b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_12.py index 9492b50b26..176535e72c 100644 --- a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_12.py +++ b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_12.py @@ -61,14 +61,6 @@ def test__template_number(self): grid_definition_template_12(self.test_cube, self.mock_grib) self._check_key('gridDefinitionTemplateNumber', 12) - def test__shape_of_earth(self): - grid_definition_template_12(self.test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 7) - self._check_key('scaleFactorOfEarthMajorAxis', 0) - self._check_key('scaledValueOfEarthMajorAxis', 6377563.396) - self._check_key('scaleFactorOfEarthMinorAxis', 0) - self._check_key('scaledValueOfEarthMinorAxis', 6356256.909) - def test__grid_shape(self): test_cube = self._make_test_cube(x_points=np.arange(13), y_points=np.arange(6)) diff --git a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_5.py b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_5.py index ca820c1a83..cb7e9e5fa2 100644 --- a/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_5.py +++ b/lib/iris/tests/unit/fileformats/grib/save_rules/test_grid_definition_template_5.py @@ -56,29 +56,6 @@ def test__template_number(self): grid_definition_template_5(self.test_cube, self.mock_grib) self._check_key('gridDefinitionTemplateNumber', 5) - def test__shape_of_earth_spherical(self): - cs = RotatedGeogCS(grid_north_pole_latitude=90.0, - grid_north_pole_longitude=0.0, - ellipsoid=GeogCS(52431.0)) - test_cube = self._make_test_cube(cs=cs) - grid_definition_template_5(test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 1) - self._check_key('scaleFactorOfRadiusOfSphericalEarth', 0) - self._check_key('scaledValueOfRadiusOfSphericalEarth', 52431.0) - - def test__shape_of_earth_flattened(self): - ellipsoid = GeogCS(semi_major_axis=1456.0, semi_minor_axis=1123.0) - cs = RotatedGeogCS(grid_north_pole_latitude=90.0, - grid_north_pole_longitude=0.0, - ellipsoid=ellipsoid) - test_cube = self._make_test_cube(cs=cs) - grid_definition_template_5(test_cube, self.mock_grib) - self._check_key('shapeOfTheEarth', 7) - self._check_key('scaleFactorOfEarthMajorAxis', 0) - self._check_key('scaledValueOfEarthMajorAxis', 1456.0) - self._check_key('scaleFactorOfEarthMinorAxis', 0) - self._check_key('scaledValueOfEarthMinorAxis', 1123.0) - def test__grid_shape(self): test_cube = self._make_test_cube(x_points=np.arange(13), y_points=np.arange(6)) diff --git a/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py b/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py new file mode 100644 index 0000000000..27aff045d6 --- /dev/null +++ b/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py @@ -0,0 +1,115 @@ +# (C) British Crown Copyright 2014, Met Office +# +# This file is part of Iris. +# +# Iris is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Iris. If not, see . +""" +Unit tests for +:meth:`iris.fileformats.grib._save_rules.shape_of_the_earth`. + +""" + +from __future__ import (absolute_import, division, print_function) + +# Import iris.tests first so that some things can be initialised before +# importing anything else. +import iris.tests as tests + +import numpy as np + +from iris.coord_systems import GeogCS, TransverseMercator, OSGB +from iris.exceptions import TranslationError +from iris.tests.unit.fileformats.grib.save_rules import GdtTestMixin + +from iris.fileformats.grib._save_rules import shape_of_the_earth + + +class Test(tests.IrisTest, GdtTestMixin): + def setUp(self): + GdtTestMixin.setUp(self) + + def _spherical_earth_test_common(self, radius): + self._check_key('scaleFactorOfRadiusOfSphericalEarth', 0) + self._check_key('scaledValueOfRadiusOfSphericalEarth', radius) + + def _oblate_spheroid_earth_test_common(self, semi_major_axis, + semi_minor_axis): + self._check_key('scaleFactorOfEarthMajorAxis', 0) + self._check_key('scaledValueOfEarthMajorAxis', semi_major_axis) + self._check_key('scaleFactorOfEarthMinorAxis', 0) + self._check_key('scaledValueOfEarthMinorAxis', semi_minor_axis) + + def test_radius_of_earth_6367470(self): + # Test setting shapeOfTheEarth = 0 + radius = 6367470 + cs = GeogCS(semi_major_axis=radius) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 0) + self._spherical_earth_test_common(radius) + + def test_radius_of_earth_6371229(self): + # Test setting shapeOfTheEarth = 6 + radius = 6371229 + cs = GeogCS(semi_major_axis=radius) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 6) + self._spherical_earth_test_common(radius) + + def test_spherical_earth(self): + # Test setting shapeOfTheEarth = 1 + radius = 1.23 + cs = GeogCS(semi_major_axis=radius) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 1) + self._spherical_earth_test_common(radius) + + def test_oblate_spheroid_earth(self): + # Test setting shapeOfTheEarth = 7 + semi_major_axis = 1.456 + semi_minor_axis = 1.123 + cs = GeogCS(semi_major_axis=semi_major_axis, + semi_minor_axis=semi_minor_axis) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 7) + self._oblate_spheroid_earth_test_common(semi_major_axis, + semi_minor_axis) + + def test_OSGB(self): + # Test setting shapeOfTheEarth = 9 + cs = OSGB() + # The following are fixed for the OSGB coord system. + semi_major_axis, semi_minor_axis = (6377563.396, 6356256.909) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 9) + self._oblate_spheroid_earth_test_common(semi_major_axis, + semi_minor_axis) + + def test_TransverseMercator_spherical(self): + # Test setting shapeOfTheEarth = 1 with a non-GeogCS coord system. + cs = TransverseMercator(49, -2, 400000, -100000, 0.9996012717, + ellipsoid=GeogCS(6377563.396)) + radius = 6377563.396 + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 1) + self._spherical_earth_test_common(radius) + + +if __name__ == "__main__": + tests.main() From 9e89b198e53cc993e851060bdc0b7a157c84bdc0 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Wed, 11 Feb 2015 12:07:43 +0000 Subject: [PATCH 2/2] Review actions --- lib/iris/fileformats/grib/_save_rules.py | 8 ++--- .../save_rules/test_shape_of_the_earth.py | 33 +++++++++++++++++-- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/iris/fileformats/grib/_save_rules.py b/lib/iris/fileformats/grib/_save_rules.py index acb1c95f5c..d85be0b06e 100644 --- a/lib/iris/fileformats/grib/_save_rules.py +++ b/lib/iris/fileformats/grib/_save_rules.py @@ -206,10 +206,10 @@ def shape_of_the_earth(cube, grib): gribapi.grib_set_long(grib, "shapeOfTheEarth", 6) else: gribapi.grib_set_long(grib, "shapeOfTheEarth", 1) - gribapi.grib_set_long(grib, - "scaleFactorOfRadiusOfSphericalEarth", 0) - gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth", - ellipsoid.semi_major_axis) + gribapi.grib_set_long(grib, + "scaleFactorOfRadiusOfSphericalEarth", 0) + gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth", + ellipsoid.semi_major_axis) # Oblate spheroid earth. else: if isinstance(cs, iris.coord_systems.OSGB): diff --git a/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py b/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py index 27aff045d6..9ffd138ec6 100644 --- a/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py +++ b/lib/iris/tests/unit/fileformats/grib/save_rules/test_shape_of_the_earth.py @@ -28,7 +28,7 @@ import numpy as np -from iris.coord_systems import GeogCS, TransverseMercator, OSGB +from iris.coord_systems import GeogCS, RotatedGeogCS, TransverseMercator, OSGB from iris.exceptions import TranslationError from iris.tests.unit.fileformats.grib.save_rules import GdtTestMixin @@ -57,7 +57,8 @@ def test_radius_of_earth_6367470(self): test_cube = self._make_test_cube(cs=cs) shape_of_the_earth(test_cube, self.mock_grib) self._check_key('shapeOfTheEarth', 0) - self._spherical_earth_test_common(radius) + self._check_key('scaleFactorOfRadiusOfSphericalEarth', 255) + self._check_key('scaledValueOfRadiusOfSphericalEarth', -1) def test_radius_of_earth_6371229(self): # Test setting shapeOfTheEarth = 6 @@ -66,7 +67,8 @@ def test_radius_of_earth_6371229(self): test_cube = self._make_test_cube(cs=cs) shape_of_the_earth(test_cube, self.mock_grib) self._check_key('shapeOfTheEarth', 6) - self._spherical_earth_test_common(radius) + self._check_key('scaleFactorOfRadiusOfSphericalEarth', 255) + self._check_key('scaledValueOfRadiusOfSphericalEarth', -1) def test_spherical_earth(self): # Test setting shapeOfTheEarth = 1 @@ -110,6 +112,31 @@ def test_TransverseMercator_spherical(self): self._check_key('shapeOfTheEarth', 1) self._spherical_earth_test_common(radius) + def test_RotatedGeogCS_spherical(self): + # Test setting shapeOfTheEarth = 1 with a RotatedGeogCS coord system. + radius = 52431.0 + cs = RotatedGeogCS(grid_north_pole_latitude=90.0, + grid_north_pole_longitude=0.0, + ellipsoid=GeogCS(radius)) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 1) + self._spherical_earth_test_common(radius) + + def test_RotatedGeogCS_oblate_spheroid(self): + # Test setting shapeOfTheEarth = 7 with a RotatedGeogCS coord system. + semi_major_axis = 1456.0 + semi_minor_axis = 1123.0 + ellipsoid = GeogCS(semi_major_axis=semi_major_axis, + semi_minor_axis=semi_minor_axis) + cs = RotatedGeogCS(grid_north_pole_latitude=90.0, + grid_north_pole_longitude=0.0, + ellipsoid=ellipsoid) + test_cube = self._make_test_cube(cs=cs) + shape_of_the_earth(test_cube, self.mock_grib) + self._check_key('shapeOfTheEarth', 7) + self._oblate_spheroid_earth_test_common(semi_major_axis, + semi_minor_axis) if __name__ == "__main__": tests.main()