def test_t1_list(self): # lbtim ia = 0, ib = 0, ic = 1 # with a series of times (t1). lbcode = _lbcode(1) lbtim = _lbtim(ia=0, ib=0, ic=1) hours = np.array([0, 3, 6, 9, 12]) # Validity time - vector of different values t1 = [nc_datetime(1970, 1, 9, hour=3 + hour) for hour in hours] t1_dims = (0,) # Forecast reference time - scalar (not used) t2 = nc_datetime(1970, 1, 9, hour=3) lbft = None coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, t1_dims=t1_dims, ) # Expected coords. time_coord = DimCoord( (24 * 8) + 3 + hours, standard_name="time", units=_EPOCH_HOURS_UNIT ) expected = [(time_coord, (0,))] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected)
def test_t1_list_t2_scalar(self): # lbtim ia = 0, ib = 1, ic = 1 # with a single forecast reference time (t2) and a series # of validity times (t1). lbcode = _lbcode(1) lbtim = _lbtim(ia=0, ib=1, ic=1) forecast_period_in_hours = np.array([0, 3, 6, 9, 12]) # Validity time - vector of different values t1 = [nc_datetime(1970, 1, 9, hour=(3 + fp)) for fp in forecast_period_in_hours] t1_dims = (0,) # Forecast reference time - scalar t2 = nc_datetime(1970, 1, 9, hour=3) lbft = None # Not used. coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, t1_dims=t1_dims) # Expected coords. fp_coord = DimCoord(forecast_period_in_hours, standard_name='forecast_period', units='hours') time_coord = DimCoord((24 * 8) + 3 + forecast_period_in_hours, standard_name='time', units=_EPOCH_HOURS_UNIT) fref_time_coord = DimCoord((24 * 8) + 3, standard_name='forecast_reference_time', units=_EPOCH_HOURS_UNIT) expected = [(fp_coord, (0,)), (time_coord, (0,)), (fref_time_coord, None)] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected)
def test(self): lbcode = _lbcode(value=31323) lbtim = _lbtim(ib=2, ic=2) t1 = nc_datetime(1970, 1, 3, hour=0, minute=0, second=0) t2 = nc_datetime(1970, 1, 4, hour=0, minute=0, second=0) lbft = 24 * 4 coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, ) t2_hours = 24 * 3 expected_result = [ ( DimCoord( [t2_hours - lbft], standard_name="forecast_reference_time", units=_EPOCH_HOURS_UNIT, ), None, ) ] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected_result)
def _check_period(self, lbcode, expect_match=True): lbtim = _lbtim(ib=2, ic=1) # Start time t1 = nc_datetime(1970, 1, 9, hour=3, minute=0, second=0) # End time t2 = nc_datetime(1970, 1, 10, hour=3, minute=0, second=0) lbft = 2.0 # sample period coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft) if expect_match: expect_result = [(DimCoord(24 * 9.125 - 2.0, standard_name='forecast_reference_time', units=_EPOCH_HOURS_UNIT), None), (DimCoord(standard_name='forecast_period', units='hours', points=[-10.0], bounds=[-22.0, 2.0]), None), (DimCoord(standard_name='time', units=_EPOCH_HOURS_UNIT, points=[24 * 8.625], bounds=[24 * 8.125, 24 * 9.125]), None)] else: expect_result = [] self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result)
def _check_forecast(self, lbcode, expect_match=True): lbtim = _lbtim(ib=1, ic=1) # Validity time t1 = nc_datetime(1970, 1, 10, hour=6, minute=0, second=0) # Forecast time t2 = nc_datetime(1970, 1, 9, hour=3, minute=0, second=0) lbft = None # unused coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft) if expect_match: expect_result = [ (DimCoord(24 * 1.125, standard_name='forecast_period', units='hours'), None), (DimCoord(24 * 9.25, standard_name='time', units=_EPOCH_HOURS_UNIT), None), (DimCoord(24 * 8.125, standard_name='forecast_reference_time', units=_EPOCH_HOURS_UNIT), None)] else: expect_result = [] self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result)
def _check_yearly(self, lbcode, expect_match=True): lbtim = _lbtim(ib=3, ic=1) # Start time t1 = nc_datetime(1970, 1, 9, hour=9, minute=0, second=0) # End time t2 = nc_datetime(1972, 1, 11, hour=9, minute=0, second=0) lbft = 3.0 # sample period coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft) if expect_match: t1_hours = 24 * 8.375 t2_hours = 24 * (10.375 + 2 * 365) period_hours = 24.0 * (2 * 365 + 2) expect_result = [ (DimCoord([t2_hours - lbft], standard_name='forecast_reference_time', units=_EPOCH_HOURS_UNIT), None), (DimCoord(standard_name='forecast_period', units='hours', points=[lbft], bounds=[lbft - period_hours, lbft]), None), (DimCoord(standard_name='time', units=_EPOCH_HOURS_UNIT, points=[t2_hours], bounds=[t1_hours, t2_hours]), None)] else: expect_result = [] self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result)
def _check_timepoint(self, lbcode, expect_match=True): lbtim = _lbtim(ib=0, ic=1) t1 = nc_datetime(1970, 1, 1, hour=6, minute=0, second=0) t2 = nc_datetime(0, 0, 0) # not used in result lbft = None # unused coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, ) if expect_match: expect_result = [ ( DimCoord( 24 * 0.25, standard_name="time", units=_EPOCH_HOURS_UNIT, ), None, ) ] else: expect_result = [] self.assertCoordsAndDimsListsMatch(coords_and_dims, expect_result)
def test_lbcode3x23(self): time_bounds = np.array([[0.875, 1.125], [1.125, 1.375], [1.375, 1.625], [1.625, 1.875]]) field = mock.MagicMock( lbproc=0, bzx=0, bdx=0, lbnpt=3, lbrow=4, t1=nc_datetime(2000, 1, 2, hour=0, minute=0, second=0), t2=nc_datetime(2000, 1, 3, hour=0, minute=0, second=0), lbtim=mock.Mock(ia=1, ib=2, ic=2), lbcode=SplittableInt(31323, {'iy': slice(0, 2), 'ix': slice(2, 4)}), x_bounds=None, y_bounds=time_bounds, _x_coord_name=lambda: 'longitude', _y_coord_name=lambda: 'latitude') spec = ['lbtim', 'lbcode', 'lbrow', 'lbnpt', 'lbproc', 'lbsrce', 'lbuser', 'bzx', 'bdx', 'bdy', 'bmdi', 't1', 't2', 'stash', 'x_bounds', 'y_bounds', '_x_coord_name', '_y_coord_name'] field.mock_add_spec(spec) res = _all_other_rules(field)[DIM_COORDS_INDEX] expected_time_points = np.array([1, 1.25, 1.5, 1.75]) + (2000 * 360) expected_unit = Unit('days since 0000-01-01 00:00:00', calendar=CALENDAR_360_DAY) expected = [(DimCoord(expected_time_points, standard_name='time', units=expected_unit, bounds=time_bounds), 0)] self.assertCoordsAndDimsListsMatch(res, expected)
def test_t1_scalar_t2_list(self): lbtim = _lbtim(ib=3, ic=1) lbcode = _lbcode(1) years = np.array([1972, 1973, 1974]) # Start times - scalar t1 = nc_datetime(1970, 1, 9, hour=9) # End time - vector t2 = [nc_datetime(year, 1, 11, hour=9) for year in years] t2_dims = (0, ) lbft = 3.0 # Sample period coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, t2_dims=t2_dims, ) # Expected coords. leap_year_adjust = np.array([0, 24, 24]) points = np.ones_like(years) * lbft bounds = np.array([ lbft - ((years - 1970) * 365 * 24 + 2 * 24 + leap_year_adjust), points, ]).transpose() fp_coord = AuxCoord( points, standard_name="forecast_period", units="hours", bounds=bounds, ) points = (years - 1970) * 365 * 24 + 10 * 24 + 9 + leap_year_adjust bounds = np.array([np.ones_like(points) * (8 * 24 + 9), points]).transpose() # The time coordinate is an AuxCoord as the lower bound for each # cell is the same so it does not meet the monotonicity requirement. time_coord = AuxCoord( points, standard_name="time", units=_EPOCH_HOURS_UNIT, bounds=bounds, ) fref_time_coord = DimCoord( points - lbft, standard_name="forecast_reference_time", units=_EPOCH_HOURS_UNIT, ) expected = [ (fp_coord, (0, )), (time_coord, (0, )), (fref_time_coord, (0, )), ] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected)
def test_unrecognised(self): lbtim = _lbtim(ib=4, ic=1) t1 = nc_datetime(0, 0, 0) t2 = nc_datetime(0, 0, 0) lbft = None lbcode = _lbcode(0) coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft) self.assertEqual(coords_and_dims, [])
def test_(self): lbtim = _lbtim(ib=2, ic=1) t1 = nc_datetime(0, 1, 1) t2 = nc_datetime(0, 1, 31, 23, 59, 00) lbft = 0 lbcode = _lbcode(1) coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft) self.assertEqual(coords_and_dims, [])
def test_not_exact_hours(self): lbtim = _lbtim(ib=1, ic=1) t1 = nc_datetime(2015, 1, 20, hour=7, minute=10, second=0) t2 = nc_datetime(2015, 1, 20, hour=0, minute=0, second=0) coords_and_dims = _convert_time_coords( lbcode=_lbcode(1), lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=None) (fp, _), (t, _), (frt, _) = coords_and_dims self.assertArrayAllClose(fp.points[0], 7.1666666, atol=0.0001, rtol=0) self.assertArrayAllClose(t.points[0], 394927.166666, atol=0.01, rtol=0)
def test_exact_hours(self): lbtim = _lbtim(ib=1, ic=1) t1 = nc_datetime(2015, 1, 20, hour=7, minute=0, second=0) t2 = nc_datetime(2015, 1, 20, hour=0, minute=0, second=0) coords_and_dims = _convert_time_coords( lbcode=_lbcode(1), lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=None) (fp, _), (t, _), (frt, _) = coords_and_dims # These should both be exact whole numbers. self.assertEqual(fp.points[0], 7) self.assertEqual(t.points[0], 394927)
def test_t1_list_t2_scalar(self): lbtim = _lbtim(ib=2, ic=1) lbcode = _lbcode(1) hours = np.array([0, 3, 6, 9]) # Start times - vector t1 = [nc_datetime(1970, 1, 9, hour=9 + hour) for hour in hours] t1_dims = (0,) # End time - scalar t2 = nc_datetime(1970, 1, 11, hour=9) lbft = 3.0 # Sample period coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, t1_dims=t1_dims, ) # Expected coords. points = lbft - (48 - hours) / 2.0 bounds = np.array( [lbft - (48 - hours), np.ones_like(hours) * lbft] ).transpose() fp_coord = AuxCoord( points, standard_name="forecast_period", units="hours", bounds=bounds, ) points = 9 * 24 + 9 + (hours / 2.0) bounds = np.array( [8 * 24 + 9 + hours, np.ones_like(hours) * 10 * 24 + 9] ).transpose() time_coord = AuxCoord( points, standard_name="time", units=_EPOCH_HOURS_UNIT, bounds=bounds, ) points = 10 * 24 + 9 - lbft fref_time_coord = DimCoord( points, standard_name="forecast_reference_time", units=_EPOCH_HOURS_UNIT, ) expected = [ (fp_coord, (0,)), (time_coord, (0,)), (fref_time_coord, None), ] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected)
def test_t1_multi_dim_list_t2_scalar(self): # Another case of lbtim ia = 0, ib = 1, ic = 1 but # with a changing forecast reference time (t2) and # validity time (t1). lbcode = _lbcode(1) lbtim = _lbtim(ia=0, ib=1, ic=1) forecast_period_in_hours = np.array([0, 3, 6, 9, 12]) years = np.array([1970, 1971, 1972]) # Validity time - 2d array of different values t1 = [[ nc_datetime(year, 1, 9, hour=(3 + fp)) for fp in forecast_period_in_hours ] for year in years] t1_dims = (0, 1) # Forecast reference time - vector of different values t2 = nc_datetime(1970, 1, 9, hour=3) lbft = None # Not used. coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, t1_dims=t1_dims, ) # Expected coords. fp_coord = AuxCoord( [ forecast_period_in_hours + (year - 1970) * 365 * 24 for year in years ], standard_name="forecast_period", units="hours", ) time_coord = AuxCoord( [(24 * 8) + 3 + forecast_period_in_hours + (year - 1970) * 365 * 24 for year in years], standard_name="time", units=_EPOCH_HOURS_UNIT, ) fref_time_coord = DimCoord( (24 * 8) + 3, standard_name="forecast_reference_time", units=_EPOCH_HOURS_UNIT, ) expected = [ (fp_coord, (0, 1)), (time_coord, (0, 1)), (fref_time_coord, None), ] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected)
def test_t1_and_t2_orthogonal_lists(self): # lbtim ia = 0, ib = 1, ic = 1 # with a single repeated forecast reference time (t2) and a series # of validity times (t1). lbcode = _lbcode(1) lbtim = _lbtim(ia=0, ib=1, ic=1) years = np.array([1970, 1971, 1972]) hours = np.array([3, 6, 9, 12]) # Validity time - vector of different values t1 = [nc_datetime(year, 1, 9, hour=12) for year in years] t1_dims = (0,) # Forecast reference time - vector of different values t2 = [nc_datetime(1970, 1, 9, hour=hour) for hour in hours] t2_dims = (1,) lbft = None # Not used. coords_and_dims = _convert_time_coords( lbcode=lbcode, lbtim=lbtim, epoch_hours_unit=_EPOCH_HOURS_UNIT, t1=t1, t2=t2, lbft=lbft, t1_dims=t1_dims, t2_dims=t2_dims, ) # Expected coords. points = [ [(year - 1970) * 365 * 24 + 12 - hour for hour in hours] for year in years ] fp_coord = AuxCoord( points, standard_name="forecast_period", units="hours" ) points = (years - 1970) * 24 * 365 + (24 * 8) + 12 time_coord = DimCoord( points, standard_name="time", units=_EPOCH_HOURS_UNIT ) points = (24 * 8) + hours fref_time_coord = DimCoord( points, standard_name="forecast_reference_time", units=_EPOCH_HOURS_UNIT, ) expected = [ (fp_coord, (0, 1)), # Spans dims 0 and 1. (time_coord, (0,)), (fref_time_coord, (1,)), ] self.assertCoordsAndDimsListsMatch(coords_and_dims, expected)
def test_bad_calendar(self): # Setup a unit with an unrecognised calendar hrs_unit = Unit('hours since epoch', calendar=cf_units.CALENDAR_ALL_LEAP) # Test against a date with year=0, which requires calendar correction. test_date = nc_datetime(0, 1, 1) # Check that this causes an error. with self.assertRaisesRegexp(ValueError, 'unrecognised calendar'): epoch_hours_call(hrs_unit, test_date)
def test_bad_calendar(self): self.calendar = cf_units.CALENDAR_ALL_LEAP # Setup a unit with an unrecognised calendar hrs_unit = Unit("hours since epoch", calendar=self.calendar) # Test against a date with year=0, which requires calendar correction. test_date = nc_datetime( 0, 1, 1, calendar=self.calendar, has_year_zero=True ) # Check that this causes an error. with self.assertRaisesRegex(ValueError, "unrecognised calendar"): epoch_hours_call(hrs_unit, test_date)
def test_ymd_0_preserves_timeofday(self): hrs, mins, secs, usecs = (7, 13, 24, 335772) hours_in_day = (hrs + 1./60 * mins + 1./3600 * secs + (1.0e-6) / 3600 * usecs) test_date = nc_datetime(0, 0, 0, hour=hrs, minute=mins, second=secs, microsecond=usecs) result = epoch_hours_call(self.hrs_unit, test_date) # NOTE: the calculation is only accurate to approx +/- 0.5 seconds # in such a large number of hours -- even 0.1 seconds is too fine. absolute_tolerance = 0.5 / 3600 self.assertArrayAllClose(result, -17269488.0 + hours_in_day, rtol=0, atol=absolute_tolerance)
def test_year_0(self): test_date = nc_datetime(0, 1, 1) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, -17020800.0)
def test_ymd_1_1_1(self): test_date = nc_datetime(1, 1, 1) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, -17012160.0)
def test_1970_1_1(self): test_date = nc_datetime(1970, 1, 1) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, 0.0)
def test_ymd_0_0_0(self): test_date = nc_datetime(0, 0, 0) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, -17269488.0)
def test_ymd_0_0_0(self): test_date = nc_datetime(0, 0, 0, calendar=None, has_year_zero=True) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, -17269488.0)
def test_year_0(self): test_date = nc_datetime( 0, 1, 1, calendar=self.calendar, has_year_zero=True ) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, -17020800.0)
def test_lbcode3x23(self): time_bounds = np.array( [[0.875, 1.125], [1.125, 1.375], [1.375, 1.625], [1.625, 1.875]] ) field = mock.MagicMock( lbproc=0, bzx=0, bdx=0, lbnpt=3, lbrow=4, t1=nc_datetime(2000, 1, 2, hour=0, minute=0, second=0), t2=nc_datetime(2000, 1, 3, hour=0, minute=0, second=0), lbtim=mock.Mock(ia=1, ib=2, ic=2), lbcode=SplittableInt( 31323, {"iy": slice(0, 2), "ix": slice(2, 4)} ), x_bounds=None, y_bounds=time_bounds, _x_coord_name=lambda: "longitude", _y_coord_name=lambda: "latitude", ) spec = [ "lbtim", "lbcode", "lbrow", "lbnpt", "lbproc", "lbsrce", "lbuser", "bzx", "bdx", "bdy", "bmdi", "t1", "t2", "stash", "x_bounds", "y_bounds", "_x_coord_name", "_y_coord_name", ] field.mock_add_spec(spec) res = _all_other_rules(field)[DIM_COORDS_INDEX] expected_time_points = np.array([1, 1.25, 1.5, 1.75]) + (2000 * 360) expected_unit = Unit( "days since 0000-01-01 00:00:00", calendar=CALENDAR_360_DAY ) expected = [ ( DimCoord( expected_time_points, standard_name="time", units=expected_unit, bounds=time_bounds, ), 0, ) ] self.assertCoordsAndDimsListsMatch(res, expected)
def test_ymd_1_1_1(self): test_date = nc_datetime(1, 1, 1, calendar=self.calendar) result = epoch_hours_call(self.hrs_unit, test_date) self.assertEqual(result, -17259936.0)