Skip to content

Commit

Permalink
Adopt tests + enhance rules as-per SciTools#3132.
Browse files Browse the repository at this point in the history
  • Loading branch information
pp-mo committed Aug 15, 2018
1 parent 2649ed1 commit 6e6410c
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 14 deletions.
28 changes: 17 additions & 11 deletions lib/iris/fileformats/pp_save_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,33 +155,39 @@ def _general_time_rules(cube, pp):
# Time mean (non-climatological).
# XXX This only works when we have a single timestep.
if clim_season_coord is None:
time_period = False
time_interval_cm = None

if fp_coord is not None and fp_coord.has_bounds():
# XXX How do we know *which* time to use if there are more
# than one? *Can* there be more than one?
pp.lbtim.ib = 2
pp.t1 = time_unit.num2date(time_coord.bounds[0, 0])
pp.t2 = time_unit.num2date(time_coord.bounds[0, 1])
time_period = True
pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1],
'hours')

if fp_coord is None and frt_coord is not None:
# Handle missing forecast period, using time and forecast
# ref time.
pp.lbtim.ib = 2
pp.t1 = time_unit.num2date(time_coord.bounds[0, 0])
pp.t2 = time_unit.num2date(time_coord.bounds[0, 1])
time_period = True
stop = time_unit.convert(time_coord.bounds[0, 1],
'hours since epoch')
start = frt_coord.units.convert(frt_coord.points[0],
'hours since epoch')
pp.lbft = stop - start

if fp_coord is not None or frt_coord is not None:
for cm in (cm_time_mean, cm_time_min, cm_time_max):
if (cm is not None and
cm.intervals != () and
for cm in (cm_time_mean, cm_time_min, cm_time_max):
if cm is not None:
time_period = True
if (cm.intervals != () and
cm.intervals[0].endswith('hour')):
pp.lbtim.ia = int(cm.intervals[0][:-5])
time_interval_cm = cm

if time_period:
pp.lbtim.ib = 2
pp.t1 = time_unit.num2date(time_coord.bounds[0, 0])
pp.t2 = time_unit.num2date(time_coord.bounds[0, 1])
if time_interval_cm is not None:
pp.lbtim.ia = int(time_interval_cm.intervals[0][:-5])

elif ('clim_season' in cube.cell_methods[-1].coord_names and
fp_coord is not None and fp_coord.has_bounds()):
Expand Down
143 changes: 140 additions & 3 deletions lib/iris/tests/test_cube_to_pp.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# (C) British Crown Copyright 2010 - 2017, Met Office
# (C) British Crown Copyright 2010 - 2018, Met Office
#
# This file is part of Iris.
#
Expand Down Expand Up @@ -26,6 +26,7 @@
import tempfile

import cf_units
import cftime
import numpy as np

import iris.coords
Expand Down Expand Up @@ -294,8 +295,144 @@ def test_lbvc(self):
self.assertEqual(field.lbvc, lbvc)
self.assertEqual(field.lblev, lblev)
self.assertEqual(field.blev, blev)




class TestTimeMean(tests.IrisTest):
'''
Tests that time mean cell method is converted to pp appropriately.
Pattern is pairs of tests - one with time mean method, and one without, to
show divergent behaviour.
'''
def test_t1_time_mean(self):
cube = _get_single_time_cube(set_time_mean=True)
tc = cube.coord(axis='t')
expected = tc.units.num2date(0)

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.t1

self.assertEqual(expected, actual)

def test_t1_no_time_mean(self):
cube = _get_single_time_cube()
tc = cube.coord(axis='t')
expected = tc.units.num2date(15)

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.t1

self.assertEqual(expected, actual)

def test_t2_time_mean(self):
cube = _get_single_time_cube(set_time_mean=True)
tc = cube.coord(axis='t')
expected = tc.units.num2date(30)

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.t2

self.assertEqual(expected, actual)

def test_t2_no_time_mean(self):
cube = _get_single_time_cube(set_time_mean=False)
expected = cftime.datetime(0, 0, 0)

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.t2
self.assertEqual(expected, actual)

def test_lbft_no_forecast_time(self):
# Different pattern here: checking that lbft hasn't been changed from
# the default value.
cube = _get_single_time_cube()
mock_lbft = mock.sentinel.lbft

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
pp_field.lbft = mock_lbft
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.lbft

assert(mock_lbft is actual)

def test_lbtim_no_time_mean(self):
cube = _get_single_time_cube()
expected_ic = 2 # 360 day calendar

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
# Check that lbtim.ib is not set : in reality, this defaults to 0.
expected_ib = pp_field.lbtim.ib
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual_ib = pp_field.lbtim.ib
actual_ic = pp_field.lbtim.ic

self.assertEqual(expected_ib, actual_ib)
self.assertEqual(expected_ic, actual_ic)

def test_lbtim_time_mean(self):
cube = _get_single_time_cube(set_time_mean=True)
expected_ib = 2 # Time mean
expected_ic = 2 # 360 day calendar

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual_ib = pp_field.lbtim.ib
actual_ic = pp_field.lbtim.ic

self.assertEqual(expected_ib, actual_ib)
self.assertEqual(expected_ic, actual_ic)

def test_lbproc_no_time_mean(self):
cube = _get_single_time_cube()
expected = 0

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.lbproc

self.assertEqual(expected, actual)

def test_lbproc_time_mean(self):
cube = _get_single_time_cube(set_time_mean=True)
expected = 128

with mock.patch('iris.fileformats.pp.PPField3',
autospec=True) as pp_field:
iris.fileformats.pp_save_rules.verify(cube, pp_field)
actual = pp_field.lbproc

self.assertEqual(expected, actual)


def _get_single_time_cube(set_time_mean=False):
cube = stock.realistic_3d()[0:1, :, :]
cube.remove_coord('time')
cube.remove_coord('forecast_period')
tc = iris.coords.DimCoord(
points=[15, ],
standard_name='time',
units=cf_units.Unit('days since epoch', calendar='360_day'),
bounds=[[0, 30], ],
)
cube.add_dim_coord(tc, 0)
if set_time_mean:
cube.cell_methods = (iris.coords.CellMethod("mean", coords='time'), )
return cube


def fields_from_cube(cubes):
"""
Return an iterator of PP fields generated from saving the given cube(s)
Expand Down

0 comments on commit 6e6410c

Please sign in to comment.