def _lbproc_rules(cube, pp): """ Rules for setting the horizontal grid and pole location of the PP field. Note: `pp.lbproc` must be set to 0 before these rules are run. Args: cube: the cube being saved as a series of PP fields. pp: the current PP field having save rules applied. Returns: The PP field with updated metadata. """ # Basic setting (this may be overridden by subsequent rules). pp.lbproc = 0 if cube.attributes.get("ukmo__process_flags", None): pp.lbproc += sum( [ LBPROC_MAP[name] for name in cube.attributes["ukmo__process_flags"] ] ) # Zonal-mean: look for a CellMethod which is a "mean" over "longitude" or # "grid_longitude". if ( scalar_cell_method(cube, "mean", "longitude") is not None or scalar_cell_method(cube, "mean", "grid_longitude") is not None ): pp.lbproc += 64 # Time-mean: look for a CellMethod which is a "mean" over "time". if scalar_cell_method(cube, "mean", "time") is not None: pp.lbproc += 128 # Time-minimum: look for a CellMethod which is a "minimum" over "time". if scalar_cell_method(cube, "minimum", "time") is not None: pp.lbproc += 4096 # Time-maximum: look for a CellMethod which is a "maximum" over "time". if scalar_cell_method(cube, "maximum", "time") is not None: pp.lbproc += 8192 return pp
def _lbproc_rules(cube, pp): """ Rules for setting the horizontal grid and pole location of the PP field. Note: `pp.lbproc` must be set to 0 before these rules are run. Args: cube: the cube being saved as a series of PP fields. pp: the current PP field having save rules applied. Returns: The PP field with updated metadata. """ # Basic setting (this may be overridden by subsequent rules). pp.lbproc = 0 if cube.attributes.get("ukmo__process_flags", None): pp.lbproc += sum([LBPROC_MAP[name] for name in cube.attributes["ukmo__process_flags"]]) # Zonal-mean: look for a CellMethod which is a "mean" over "longitude" or # "grid_longitude". if (scalar_cell_method(cube, 'mean', 'longitude') is not None or scalar_cell_method(cube, 'mean', 'grid_longitude') is not None): pp.lbproc += 64 # Time-mean: look for a CellMethod which is a "mean" over "time". if scalar_cell_method(cube, 'mean', 'time') is not None: pp.lbproc += 128 # Time-minimum: look for a CellMethod which is a "minimum" over "time". if scalar_cell_method(cube, 'minimum', 'time') is not None: pp.lbproc += 4096 # Time-maximum: look for a CellMethod which is a "maximum" over "time". if scalar_cell_method(cube, 'maximum', 'time') is not None: pp.lbproc += 8192 return pp
def test_double_coord_fails(self): self.cube.cell_methods = (CellMethod("mean", ("foo", "bar"), ("1 hour", "1 hour")), ) actual = scalar_cell_method(self.cube, "mean", "foo") self.assertIsNone(actual)
def test_coord_name_different(self): actual = scalar_cell_method(self.cube, "average", "bar") self.assertIsNone(actual)
def test_method_different(self): actual = scalar_cell_method(self.cube, "average", "foo") self.assertIsNone(actual)
def test_cell_method_found(self): actual = scalar_cell_method(self.cube, "mean", "foo") self.assertEqual(actual, self.cm)
def _general_time_rules(cube, pp): """ Rules for setting time metadata of the PP field. Args: cube: the cube being saved as a series of PP fields. pp: the current PP field having save rules applied. Returns: The PP field with updated metadata. """ time_coord = scalar_coord(cube, 'time') fp_coord = scalar_coord(cube, 'forecast_period') frt_coord = scalar_coord(cube, 'forecast_reference_time') clim_season_coord = scalar_coord(cube, 'clim_season') cm_time_mean = scalar_cell_method(cube, 'mean', 'time') cm_time_min = scalar_cell_method(cube, 'minimum', 'time') cm_time_max = scalar_cell_method(cube, 'maximum', 'time') # No forecast. if time_coord is not None and fp_coord is None and frt_coord is None: pp.lbtim.ia = 0 pp.lbtim.ib = 0 pp.t1 = time_coord.units.num2date(time_coord.points[0]) pp.t2 = netcdftime.datetime(0, 0, 0) # Forecast. if (time_coord is not None and not time_coord.has_bounds() and fp_coord is not None): pp.lbtim.ia = 0 pp.lbtim.ib = 1 pp.t1 = time_coord.units.num2date(time_coord.points[0]) pp.t2 = time_coord.units.num2date(time_coord.points[0] - fp_coord.points[0]) pp.lbft = fp_coord.points[0] # Time mean (non-climatological). # XXX This only works when we have a single timestep. if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and 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_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and 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_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) stop = time_coord.units.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 (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and cm_time_mean is not None and cm_time_mean.intervals != () and cm_time_mean.intervals[0].endswith('hour')): pp.lbtim.ia = int(cm_time_mean.intervals[0][:-5]) if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and (cm_time_mean is None or cm_time_mean.intervals == () or not cm_time_mean.intervals[0].endswith('hour'))): pp.lbtim.ia = 0 # If the cell methods contain a minimum then overwrite lbtim.ia with this # interval. if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and cm_time_min is not None and cm_time_min.intervals != () and cm_time_min.intervals[0].endswith('hour')): # Set lbtim.ia with the integer part of the cell method's interval # e.g. if interval is '24 hour' then lbtim.ia becomes 24. pp.lbtim.ia = int(cm_time_min.intervals[0][:-5]) # If the cell methods contain a maximum then overwrite lbtim.ia with this # interval. if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and cm_time_max is not None and cm_time_max.intervals != () and cm_time_max.intervals[0].endswith('hour')): # Set lbtim.ia with the integer part of the cell method's interval # e.g. if interval is '1 hour' then lbtim.ia becomes 1. pp.lbtim.ia = int(cm_time_max.intervals[0][:-5]) if time_coord is not None and time_coord.has_bounds(): lower_bound_yr =\ time_coord.units.num2date(time_coord.bounds[0, 0]).year upper_bound_yr =\ time_coord.units.num2date(time_coord.bounds[0, 1]).year else: lower_bound_yr = None upper_bound_yr = None # Climatological time means. if (time_coord is not None and time_coord.has_bounds() and lower_bound_yr == upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names): # Climatological time mean - single year. pp.lbtim.ia = 0 pp.lbtim.ib = 2 pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'djf'): # Climatological time mean - spanning years - djf. pp.lbtim.ia = 0 pp.lbtim.ib = 3 pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) if pp.t1.month == 12: pp.t1 = netcdftime.datetime(pp.t1.year) else: pp.t1 = netcdftime.datetime(pp.t1.year - 1, 12, 1, 0, 0, 0) pp.t2 = netcdftime.datetime(pp.t2.year, 3, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'mam'): # Climatological time mean - spanning years - mam. pp.lbtim.ia = 0 pp.lbtim.ib = 3 # TODO: wut? pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.t1 = netcdftime.datetime(pp.t1.year, 3, 1, 0, 0, 0) pp.t2 = netcdftime.datetime(pp.t2.year, 6, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'jja'): # Climatological time mean - spanning years - jja. pp.lbtim.ia = 0 pp.lbtim.ib = 3 # TODO: wut? pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.t1 = netcdftime.datetime(pp.t1.year, 6, 1, 0, 0, 0) pp.t2 = netcdftime.datetime(pp.t2.year, 9, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'son'): # Climatological time mean - spanning years - son. pp.lbtim.ia = 0 pp.lbtim.ib = 3 # TODO: wut? pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.t1 = netcdftime.datetime(pp.t1.year, 9, 1, 0, 0, 0) pp.t2 = netcdftime.datetime(pp.t2.year, 12, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') return pp
def _general_time_rules(cube, pp): """ Rules for setting time metadata of the PP field. Args: cube: the cube being saved as a series of PP fields. pp: the current PP field having save rules applied. Returns: The PP field with updated metadata. """ time_coord = scalar_coord(cube, 'time') fp_coord = scalar_coord(cube, 'forecast_period') frt_coord = scalar_coord(cube, 'forecast_reference_time') clim_season_coord = scalar_coord(cube, 'clim_season') cm_time_mean = scalar_cell_method(cube, 'mean', 'time') cm_time_min = scalar_cell_method(cube, 'minimum', 'time') cm_time_max = scalar_cell_method(cube, 'maximum', 'time') # No forecast. if time_coord is not None and fp_coord is None and frt_coord is None: pp.lbtim.ia = 0 pp.lbtim.ib = 0 pp.t1 = time_coord.units.num2date(time_coord.points[0]) pp.t2 = cftime.datetime(0, 0, 0) # Forecast. if (time_coord is not None and not time_coord.has_bounds() and fp_coord is not None): pp.lbtim.ia = 0 pp.lbtim.ib = 1 pp.t1 = time_coord.units.num2date(time_coord.points[0]) pp.t2 = time_coord.units.num2date(time_coord.points[0] - fp_coord.points[0]) pp.lbft = fp_coord.points[0] # Time mean (non-climatological). # XXX This only works when we have a single timestep. if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and 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_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and 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_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) stop = time_coord.units.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 (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and cm_time_mean is not None): pp.lbtim.ib = 2 pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and cm_time_mean is not None and cm_time_mean.intervals != () and cm_time_mean.intervals[0].endswith('hour')): pp.lbtim.ia = int(cm_time_mean.intervals[0][:-5]) if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and (cm_time_mean is None or cm_time_mean.intervals == () or not cm_time_mean.intervals[0].endswith('hour'))): pp.lbtim.ia = 0 # If the cell methods contain a minimum then overwrite lbtim.ia with this # interval. if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and cm_time_min is not None and cm_time_min.intervals != () and cm_time_min.intervals[0].endswith('hour')): # Set lbtim.ia with the integer part of the cell method's interval # e.g. if interval is '24 hour' then lbtim.ia becomes 24. pp.lbtim.ia = int(cm_time_min.intervals[0][:-5]) # If the cell methods contain a maximum then overwrite lbtim.ia with this # interval. if (time_coord is not None and time_coord.has_bounds() and clim_season_coord is None and (fp_coord is not None or frt_coord is not None) and cm_time_max is not None and cm_time_max.intervals != () and cm_time_max.intervals[0].endswith('hour')): # Set lbtim.ia with the integer part of the cell method's interval # e.g. if interval is '1 hour' then lbtim.ia becomes 1. pp.lbtim.ia = int(cm_time_max.intervals[0][:-5]) if time_coord is not None and time_coord.has_bounds(): lower_bound_yr =\ time_coord.units.num2date(time_coord.bounds[0, 0]).year upper_bound_yr =\ time_coord.units.num2date(time_coord.bounds[0, 1]).year else: lower_bound_yr = None upper_bound_yr = None # Climatological time means. if (time_coord is not None and time_coord.has_bounds() and lower_bound_yr == upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names): # Climatological time mean - single year. pp.lbtim.ia = 0 pp.lbtim.ib = 2 pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'djf'): # Climatological time mean - spanning years - djf. pp.lbtim.ia = 0 pp.lbtim.ib = 3 pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) if pp.t1.month == 12: pp.t1 = cftime.datetime(pp.t1.year) else: pp.t1 = cftime.datetime(pp.t1.year-1, 12, 1, 0, 0, 0) pp.t2 = cftime.datetime(pp.t2.year, 3, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'mam'): # Climatological time mean - spanning years - mam. pp.lbtim.ia = 0 pp.lbtim.ib = 3 # TODO: wut? pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.t1 = cftime.datetime(pp.t1.year, 3, 1, 0, 0, 0) pp.t2 = cftime.datetime(pp.t2.year, 6, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'jja'): # Climatological time mean - spanning years - jja. pp.lbtim.ia = 0 pp.lbtim.ib = 3 # TODO: wut? pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.t1 = cftime.datetime(pp.t1.year, 6, 1, 0, 0, 0) pp.t2 = cftime.datetime(pp.t2.year, 9, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') elif (time_coord is not None and time_coord.has_bounds() and lower_bound_yr != upper_bound_yr and fp_coord is not None and fp_coord.has_bounds() and clim_season_coord is not None and 'clim_season' in cube.cell_methods[-1].coord_names and clim_season_coord.points[0] == 'son'): # Climatological time mean - spanning years - son. pp.lbtim.ia = 0 pp.lbtim.ib = 3 # TODO: wut? pp.t1 = time_coord.units.num2date(time_coord.bounds[0, 0]) pp.t2 = time_coord.units.num2date(time_coord.bounds[0, 1]) pp.t1 = cftime.datetime(pp.t1.year, 9, 1, 0, 0, 0) pp.t2 = cftime.datetime(pp.t2.year, 12, 1, 0, 0, 0) _conditional_warning( time_coord.bounds[0, 0] != time_coord.units.date2num(pp.t1), "modified t1 for climatological seasonal mean") _conditional_warning( time_coord.bounds[0, 1] != time_coord.units.date2num(pp.t2), "modified t2 for climatological seasonal mean") pp.lbft = fp_coord.units.convert(fp_coord.bounds[0, 1], 'hours') return pp
def test_double_coord_fails(self): self.cube.cell_methods = (CellMethod('mean', ('foo', 'bar'), ('1 hour', '1 hour')), ) actual = scalar_cell_method(self.cube, 'mean', 'foo') self.assertIsNone(actual)
def test_method_different(self): actual = scalar_cell_method(self.cube, 'average', 'foo') self.assertIsNone(actual)
def test_cell_method_found(self): actual = scalar_cell_method(self.cube, 'mean', 'foo') self.assertEqual(actual, self.cm)
def test_coord_name_different(self): actual = scalar_cell_method(self.cube, 'average', 'bar') self.assertIsNone(actual)