2929from subprocess import check_output
3030
3131from iris import FUTURE , load_cube , save
32+ from iris .coords import CellMethod
3233from iris .coord_systems import RotatedGeogCS
3334from iris .fileformats .pp import EARTH_RADIUS as UM_DEFAULT_EARTH_RADIUS
3435from iris .util import is_regular
@@ -100,9 +101,10 @@ def test_cell_method(self):
100101 self .assertEqual (cell_method .coord_names , ('time' ,))
101102
102103
103- class TestSaveGdt5 (tests .IrisTest ):
104- def test_simple (self ):
105- # Fetch some sample UKV data (rotated variable grid)
104+ @tests .skip_data
105+ class TestGDT5 (tests .IrisTest ):
106+ def test_save_load (self ):
107+ # Load sample UKV data (variable-resolution rotated grid).
106108 path = tests .get_data_path (('PP' , 'ukV1' , 'ukVpmslont.pp' ))
107109 cube = load_cube (path )
108110
@@ -123,29 +125,92 @@ def test_simple(self):
123125 self .assertIsInstance (x_coord .coord_system , RotatedGeogCS )
124126 self .assertFalse (is_regular (x_coord ))
125127
126- # Write the data to a temporary file, and capture dump output.
127- # TODO: replace the dump with an Iris load, when we support loading.
128+ # Write to temporary file, check grib_dump output, and load back in.
128129 with self .temp_filename ('ukv_sample.grib2' ) as temp_file_path :
129130 save (cube , temp_file_path )
130- # Get a dump of the output.
131+
132+ # Get a grib_dump of the output file.
131133 dump_text = check_output (('grib_dump -O -wcount=1 ' +
132134 temp_file_path ),
133135 shell = True )
134- # Check that various aspects of the result are as expected.
135- expect_strings = (
136- 'editionNumber = 2' ,
137- 'gridDefinitionTemplateNumber = 5' ,
138- 'Ni = {:d}' .format (nn ),
139- 'Nj = {:d}' .format (nn ),
140- 'shapeOfTheEarth = 1' ,
141- 'scaledValueOfRadiusOfSphericalEarth = {:d}' .format (
142- int (UM_DEFAULT_EARTH_RADIUS )),
143- 'resolutionAndComponentFlags = 0' ,
144- 'latitudeOfSouthernPole = -37500000' ,
145- 'longitudeOfSouthernPole = 357500000' ,
146- 'angleOfRotation = 0' )
147- for expect in expect_strings :
148- self .assertIn (expect , dump_text )
136+
137+ # Check that various aspects of the saved file are as expected.
138+ expect_strings = (
139+ 'editionNumber = 2' ,
140+ 'gridDefinitionTemplateNumber = 5' ,
141+ 'Ni = {:d}' .format (cube .shape [- 1 ]),
142+ 'Nj = {:d}' .format (cube .shape [- 2 ]),
143+ 'shapeOfTheEarth = 1' ,
144+ 'scaledValueOfRadiusOfSphericalEarth = {:d}' .format (
145+ int (UM_DEFAULT_EARTH_RADIUS )),
146+ 'resolutionAndComponentFlags = 0' ,
147+ 'latitudeOfSouthernPole = -37500000' ,
148+ 'longitudeOfSouthernPole = 357500000' ,
149+ 'angleOfRotation = 0' )
150+ for expect in expect_strings :
151+ self .assertIn (expect , dump_text )
152+
153+ # Load the Grib file back into a new cube.
154+ with FUTURE .context (strict_grib_load = True ):
155+ cube_loaded_from_saved = load_cube (temp_file_path )
156+ # Also load data, before the temporary file gets deleted.
157+ cube_loaded_from_saved .data
158+
159+ # The re-loaded result will not match the original in every respect:
160+ # * cube attributes are discarded
161+ # * horizontal coordinates are rounded to an integer representation
162+ # * bounds on horizontal coords are lost
163+ # Thus the following "equivalence tests" are rather piecemeal..
164+
165+ # Check those re-loaded properties which should match the original.
166+ for test_cube in (cube , cube_loaded_from_saved ):
167+ self .assertEqual (test_cube .standard_name ,
168+ 'air_pressure_at_sea_level' )
169+ self .assertEqual (test_cube .units , 'Pa' )
170+ self .assertEqual (test_cube .shape , (744 , 744 ))
171+ self .assertEqual (test_cube .cell_methods , ())
172+
173+ # Check no cube attributes on the re-loaded cube.
174+ # Note: this does *not* match the original, but is as expected.
175+ self .assertEqual (cube_loaded_from_saved .attributes , {})
176+
177+ # Now remaining to check: coordinates + data...
178+
179+ # Check they have all the same coordinates.
180+ co_names = [coord .name () for coord in cube .coords ()]
181+ co_names_reload = [coord .name ()
182+ for coord in cube_loaded_from_saved .coords ()]
183+ self .assertEqual (sorted (co_names_reload ), sorted (co_names ))
184+
185+ # Check all the coordinates.
186+ for coord_name in co_names :
187+ try :
188+ co_orig = cube .coord (coord_name )
189+ co_load = cube_loaded_from_saved .coord (coord_name )
190+
191+ # Check shape.
192+ self .assertEqual (co_load .shape , co_orig .shape ,
193+ 'Shape of re-loaded "{}" coord is {} '
194+ 'instead of {}' .format (coord_name ,
195+ co_load .shape ,
196+ co_orig .shape ))
197+
198+ # Check coordinate points equal, within a tolerance.
199+ self .assertArrayAllClose (co_load .points , co_orig .points ,
200+ rtol = 1.0e-6 )
201+
202+ # Check all coords are unbounded.
203+ # (NOTE: this is not so for the original X and Y coordinates,
204+ # but Grib does not store those bounds).
205+ self .assertIsNone (co_load .bounds )
206+
207+ except AssertionError as err :
208+ self .assertTrue (False ,
209+ 'Failed on coordinate "{}" : {}' .format (
210+ coord_name , str (err )))
211+
212+ # Check that main data array also matches.
213+ self .assertArrayAllClose (cube .data , cube_loaded_from_saved .data )
149214
150215
151216if __name__ == '__main__' :
0 commit comments