def seasonal_mean(cube): seasons = ['winter', 'summer'] icc.add_season(cube, 'time', 'clim_season') icc.add_season_year(cube, 'time', 'season_year') season_mean_cube_list = iris.cube.CubeList([]) season_max_cube_list = iris.cube.CubeList([]) season_min_cube_list = iris.cube.CubeList([]) for season in seasons: if season == 'winter': months = 'djf' if season == 'spring': months = 'mam' if season == 'summer': months = 'jja' if season == 'autumn': months = 'son' single_season_cube = cube.extract(iris.Constraint(clim_season=months)) season_mean_cube = single_season_cube.aggregated_by( ['clim_season', 'season_year'], iris.analysis.MEAN) season_mean_cube.rename(season_mean_cube.name() + '_' + season + '_mean') season_mean_cube_list.append(season_mean_cube) season_max = single_season_cube.aggregated_by( ['clim_season', 'season_year'], iris.analysis.MAX) season_max.rename(season_max.name() + '_' + season + '_max') season_max_cube_list.append(season_max) season_min = single_season_cube.aggregated_by( ['clim_season', 'season_year'], iris.analysis.MIN) season_min.rename(season_min.name() + '_' + season + '_min') season_min_cube_list.append(season_min) return [season_mean_cube_list, season_max_cube_list, season_min_cube_list]
def add_times(cube, time): coord_cat.add_month(cube, time, name='month') coord_cat.add_season(cube, time, name='clim_season') coord_cat.add_year(cube, time, name='year') coord_cat.add_day_of_year(cube, time, name='day_number') coord_cat.add_season_year(cube, time, name='season_year') return cube
def test_add_custom_season_year(self): # custom season years match standard season years? seasons = ('djf', 'mam', 'jja', 'son') ccat.add_season_year(self.cube, 'time', name='year_std') ccat.add_custom_season_year(self.cube, 'time', seasons, name='year_custom') coord_std = self.cube.coord('year_std') coord_custom = self.cube.coord('year_custom') self.assertArrayEqual(coord_custom.points, coord_std.points)
def test_add_season_nonstandard(self): # season categorisations work for non-standard seasons? cube = self.cube time_coord = self.time_coord seasons = ['djfm', 'amjj', 'ason'] ccat.add_season(cube, time_coord, name='seasons', seasons=seasons) ccat.add_season_number(cube, time_coord, name='season_numbers', seasons=seasons) ccat.add_season_year(cube, time_coord, name='season_years', seasons=seasons) self.assertCML(cube, ('categorisation', 'customcheck.cml'))
def test_add_season_nonstandard(self): # season categorisations work for non-standard seasons? cube = self.cube time_coord = self.time_coord seasons = ["djfm", "amjj", "ason"] ccat.add_season(cube, time_coord, name="seasons", seasons=seasons) ccat.add_season_number( cube, time_coord, name="season_numbers", seasons=seasons ) ccat.add_season_year( cube, time_coord, name="season_years", seasons=seasons ) self.assertCML(cube, ("categorisation", "customcheck.cml"))
def select_certain_months(cubes, lbmon): """ Select data from CubeList that matches the specified months. :param CubeList cubes: Iris CubeList. :param list lbmon: List with month numbers, e.g. lbmon=[5,6,7] for Mai, June, and July. :returns: CubeList with Cubes containing only data for the specified mnth. :rtype: CubeList :raises: `AssertionError` if `cubes` is not an `iris.cube.CubeList`. """ # add 'month number' coordinate add_time_coord = { 'monthly': lambda cube: coord_cat.add_month_number( cube, 'time', name='month_number'), 'seasonal': lambda cube: coord_cat.add_season(cube, 'time', name='clim_season'), 'annual': lambda cube: coord_cat.add_season_year( cube, 'time', name='season_year') } assert isinstance(cubes, iris.cube.CubeList) for cube in cubes: add_time_coord['monthly'](cube) # filter by month number month_constraint = iris.Constraint(month_number=lbmon) return cubes.extract( month_constraint) # CubeList.extract returns always CubeList
def test_basic(self): cube = self.cube time_coord = self.time_coord ccat.add_year(cube, time_coord, 'my_year') ccat.add_day_of_month(cube, time_coord, 'my_day_of_month') ccat.add_day_of_year(cube, time_coord, 'my_day_of_year') ccat.add_month(cube, time_coord, 'my_month') with warnings.catch_warnings(record=True): ccat.add_month_shortname(cube, time_coord, 'my_month_shortname') ccat.add_month_fullname(cube, time_coord, 'my_month_fullname') ccat.add_month_number(cube, time_coord, 'my_month_number') ccat.add_weekday(cube, time_coord, 'my_weekday') ccat.add_weekday_number(cube, time_coord, 'my_weekday_number') with warnings.catch_warnings(record=True): ccat.add_weekday_shortname(cube, time_coord, 'my_weekday_shortname') ccat.add_weekday_fullname(cube, time_coord, 'my_weekday_fullname') ccat.add_season(cube, time_coord, 'my_season') ccat.add_season_number(cube, time_coord, 'my_season_number') with warnings.catch_warnings(record=True): ccat.add_season_month_initials(cube, time_coord, 'my_season_month_initials') ccat.add_season_year(cube, time_coord, 'my_season_year') # also test 'generic' categorisation interface def _month_in_quarter(coord, pt_value): date = coord.units.num2date(pt_value) return (date.month - 1) % 3 ccat.add_categorised_coord(cube, 'my_month_in_quarter', time_coord, _month_in_quarter) # To ensure consistent results between 32-bit and 64-bit # platforms, ensure all the numeric categorisation coordinates # are always stored as int64. for coord in cube.coords(): if coord.long_name is not None and coord.points.dtype.kind == 'i': coord.points = coord.points.astype(np.int64) # check values self.assertCML(cube, ('categorisation', 'quickcheck.cml'))
def test_basic(self): #make a series of 'day numbers' for the time, that slide across month boundaries day_numbers = np.arange(0, 600, 27, dtype=np.int32) cube = iris.cube.Cube(day_numbers, long_name='test cube', units='metres') #use day numbers as data values also (don't actually use this for anything) cube.data = day_numbers time_coord = iris.coords.DimCoord( day_numbers, standard_name='time', units=iris.unit.Unit('days since epoch', 'gregorian')) cube.add_dim_coord(time_coord, 0) #add test coordinates for examples wanted ccat.add_year(cube, time_coord) ccat.add_day_of_month(cube, 'time') #NB test passing coord-name instead of coord itself ccat.add_month(cube, time_coord) ccat.add_month_shortname(cube, time_coord, name='month_short') ccat.add_month_fullname(cube, time_coord, name='month_full') ccat.add_month_number(cube, time_coord, name='month_number') ccat.add_weekday(cube, time_coord) ccat.add_weekday_number(cube, time_coord, name='weekday_number') ccat.add_weekday_shortname(cube, time_coord, name='weekday_short') ccat.add_weekday_fullname(cube, time_coord, name='weekday_full') ccat.add_season(cube, time_coord) ccat.add_season_number(cube, time_coord, name='season_number') ccat.add_season_month_initials(cube, time_coord, name='season_months') ccat.add_season_year(cube, time_coord, name='year_ofseason') #also test 'generic' categorisation interface def _month_in_quarter(coord, pt_value): date = coord.units.num2date(pt_value) return (date.month - 1) % 3 ccat.add_categorised_coord(cube, 'month_in_quarter', time_coord, _month_in_quarter) for coord_name in ['month_number', 'month_in_quarter', 'weekday_number', 'season_number', 'year_ofseason', 'year', 'day']: cube.coord(coord_name).points = cube.coord(coord_name).points.astype(np.int64) #check values self.assertCML(cube, ('categorisation', 'quickcheck.cml'))
def seasonal_mean(mycube): """ Function to compute seasonal means with MEAN. Chunks time in 3-month periods and computes means over them; Returns a cube. """ if 'clim_season' not in mycube.coords(): coord_cat.add_season(mycube, 'time', name='clim_season') if 'season_year' not in mycube.coords(): coord_cat.add_season_year(mycube, 'time', name='season_year') annual_seasonal_mean = mycube.aggregated_by(['clim_season', 'season_year'], iris.analysis.MEAN) def spans_three_months(time): """Check for three months.""" return (time.bound[1] - time.bound[0]) == 90 # days three_months_bound = iris.Constraint(time=spans_three_months) return annual_seasonal_mean.extract(three_months_bound)
def test_basic(self): cube = self.cube time_coord = self.time_coord ccat.add_year(cube, time_coord, "my_year") ccat.add_day_of_month(cube, time_coord, "my_day_of_month") ccat.add_day_of_year(cube, time_coord, "my_day_of_year") ccat.add_month(cube, time_coord, "my_month") ccat.add_month_fullname(cube, time_coord, "my_month_fullname") ccat.add_month_number(cube, time_coord, "my_month_number") ccat.add_weekday(cube, time_coord, "my_weekday") ccat.add_weekday_number(cube, time_coord, "my_weekday_number") ccat.add_weekday_fullname(cube, time_coord, "my_weekday_fullname") ccat.add_season(cube, time_coord, "my_season") ccat.add_season_number(cube, time_coord, "my_season_number") ccat.add_season_year(cube, time_coord, "my_season_year") # also test 'generic' categorisation interface def _month_in_quarter(coord, pt_value): date = coord.units.num2date(pt_value) return (date.month - 1) % 3 ccat.add_categorised_coord( cube, "my_month_in_quarter", time_coord, _month_in_quarter ) # To ensure consistent results between 32-bit and 64-bit # platforms, ensure all the numeric categorisation coordinates # are always stored as int64. for coord in cube.coords(): if coord.long_name is not None and coord.points.dtype.kind == "i": coord.points = coord.points.astype(np.int64) # check values self.assertCML(cube, ("categorisation", "quickcheck.cml"))
def derive_variability(cube, runid, lon_range_pdo, lon_range_amo, savedir, remove_global_means, neofs, period_title=''): sst_cube = cube.copy() # mask the sea-ice regions sst_cube = mask_ice(sst_cube) sst_cube_monthanom, tmp_avg = remove_monthly_avg(sst_cube) tpi_ts = tpi_timeseries(sst_cube_monthanom) tpi_smooth = tpi_ts['tpi'].copy() smooth_data = utilities_mr.smooth(tpi_ts['tpi'].data, window_len=156, window = 'hanning') print len(smooth_data) tpi_smooth.data[:len(smooth_data)] = smooth_data #print 'tpi', tpi_ts['tpi'] #print 'reg2', tpi_ts['reg2'] file_out = os.path.join(savedir, runid+'_tpi_timeseries.nc') tpi_ts['tpi'].long_name = 'TPI timeseries' iris.save(tpi_ts['tpi'], file_out, netcdf_format="NETCDF3_CLASSIC") #print 'sst cube for nino ',sst_cube try: icc.add_season(sst_cube, 'time', name='clim_season') icc.add_season_year(sst_cube, 'time', name='season_year') except: pass #print 'sst cube for nino ',sst_cube #print 'sst cube for nino ',sst_cube.coord('clim_season') sst_djf = sst_cube.extract(DJF_constraint) nino_timeseries = nino34_timeseries(sst_djf) nino_timeseries.long_name = 'NINO3.4 timeseries' file_out = os.path.join(savedir, runid+'_nino34_timeseries'+period_title+'.nc') iris.io.save(nino_timeseries,file_out, netcdf_format="NETCDF3_CLASSIC") # calculate annual means sst_ann = sst_cube.aggregated_by('year', iris.analysis.MEAN) # mask out land when using surface temperature if remove_global_means: sst_ann = remove_glob_avg(sst_ann) # calculate PDO EOfs, timeseries and regression pdo_pc = calculate_pdo_eof_timeseries(runid, sst_ann, savedir, lat_range_pdo, lon_range_pdo, neofs, remove_global_means, period_title) #print 'pdo_pc ',pdo_pc # calculate PDO SST regression and write file pltdir = os.path.join(savedir, 'pdo_patterns/plts/gc2/') if not os.path.exists(pltdir): os.makedirs(pltdir) pdofile = runid+'_pdo_eof1_pc_time_series_glob_mean_sst_removed'+period_title+'.nc' pdo_cube = iris.load(savedir + pdofile)[0] calc_regression(sst_ann, pltdir, pdo_cube, runid, 'PDO', period_title) #calculate AMO timeseries amo_timeseries = calc_amo_timeseries(sst_ann, runid, lon_range_amo, lat_range_amo) amo_timeseries.long_name='AMO timeseries' file_out = os.path.join(savedir, runid+'_amo_timeseries_trenberth'+period_title+'.nc') iris.io.save(amo_timeseries,file_out, netcdf_format="NETCDF3_CLASSIC") #calculate AMO regression and write files amodir = os.path.join(savedir, 'amo') if not os.path.exists(amodir): os.makedirs(amodir) calculate_amo_regression(sst_ann, amo_timeseries, lon_range_amo, lat_range_amo, amodir, runid, period_title) resol_model = ['HadISST']; title = 'HadISST'; desc_model = ['Nino3.4','AMO','PDO','TPI']; ymin = [-3, -0.3, -0.2, -1.] ymax = [3, 0.3, 0.2, 1.] fig = plt.figure(figsize=(8,11),dpi=100)#dpi=300 for i, ts in enumerate([nino_timeseries, amo_timeseries, pdo_pc, tpi_ts['tpi']]): subpl=fig.add_subplot(4,1,i+1) period = 'year' if i == 3: period = 'month' plot_timeseries(i, runid, ts, resol_model[0], desc_model[i], title, \ subpl, ymin[i], ymax[i], period = period) plt.savefig(os.path.join(savedir,runid+'_modes_timeseries'+period_title+'.png')) plt.show() del sst_cube
def consecutive_dry_days(cube, period='year', length=6, threshold=1.): """ calculate consecutive dry days within an iris.cube.Cube Args: * cube (iris.cube.Cube): An iris.cube.Cube holding precipiation amount in mm/day * period (string): Period over that the CDD will be calculated. Can be 'year', 'season' or 'month'. If period is 'season' or 'month' the CDD will be averaged over the years Kwargs: * length (int): The number of days without rainfall that define a dry period * threshold (float): The upper limit of daily rainfall in mm that indicates 'no precipitation' Returns: An iris.cube.CubeList that holds two iris.cube.Cubes with the longest period of dry days in the given period and the mean of the number of dry periods with respect to the given length """ def _cdd_index(array, axis, threshold): """ Calculate the consecutive dry days index. This function is used as an iris.analysis.Aggregator Args: * array (numpy.array or numpy.ma.array): array that holds the precipitation data * axis (int): the number of the time-axis * threshold (float): the threshold that indicates a precipiation-less day Returns: the aggregation result, collapsing the 'axis' dimension of the 'data' argument """ from pycat.analysis.utils import (_get_max_true_block_length, _get_true_block_lengths) up_down = _get_true_block_lengths(array < threshold, axis) return _get_max_true_block_length(up_down) def _cdd_periods(array, axis, threshold, length): """ Calculate the number of consecutive dry days periods. This function is used as an iris.analysis.Aggregator Args: * array (numpy.array or numpy.ma.array): array that holds the precipitation data * axis (int): the number of the time-axis * threshold (float): the threshold that indicates a precipiation-less day * length (int): number of days that a dry period must last Returns: the aggregation result, collapsing the 'axis' dimension of the 'data' argument """ from pycat.analysis.utils import (_get_len_true_block_length, _get_true_block_lengths) up_down = _get_true_block_lengths(array < threshold, axis) return _get_len_true_block_length(up_down, length) # build the iris.analysis.Aggregators cdd_index = Aggregator('cdd_index', _cdd_index) cdd_periods = Aggregator('cdd_periods', _cdd_periods) # check if the cube already has the needed auxiliary coordinates if period == 'season': # add the season_year auxiliary coordinate try: years = np.unique(cube.coord('season_year').points) except CoordinateNotFoundError: ccat.add_season_year(cube, 'time') years = np.unique(cube.coord('season_year').points) constraint_year_key = 'season_year' else: # add calendar years try: years = np.unique(cube.coord('year').points) except CoordinateNotFoundError: ccat.add_year(cube, 'time') years = np.unique(cube.coord('year').points) constraint_year_key = 'year' if period in ['season', 'month']: try: index_period = np.unique(cube.coord('%s_number' % period).points) except CoordinateNotFoundError: cat = getattr(ccat, 'add_%s_number' % period) cat(cube, 'time') index_period = np.unique(cube.coord('%s_number' % period).points) # create time-axis of resulting cubes time_dimension = _make_time_dimension( cube.coord('time').units.num2date(cube.coord('time').points[0]), cube.coord('time').units.num2date(cube.coord('time').points[-1]), period=period) # create the empty resulting cubes dim_coords_and_dims = [] slices = [] for coord in cube.dim_coords: if coord.units.is_time_reference(): dim_coords_and_dims.append( (time_dimension, cube.coord_dims(coord))) slices.append(0) time_axis = cube.coord_dims(coord)[0] else: dim_coords_and_dims.append((coord, cube.coord_dims(coord))) slices.append(slice(None, None, None)) cdd_index_cube = _create_cube( long_name='Consecutive dry days is the greatest number of ' 'consecutive days per time period with daily ' 'precipitation amount below %s mm.' % threshold, var_name='consecutive_dry_days_index_per_time_period', units=iris.unit.Unit('1'), dim_coords_and_dims=dim_coords_and_dims) cdd_periods_cube = _create_cube( long_name='Number of cdd periods in given time period ' 'with more than %d days.' % length, var_name='number_of_cdd_periods_with_more_than_' '%ddays_per_time_period' % length, units=iris.unit.Unit('1'), dim_coords_and_dims=dim_coords_and_dims) # differentiate between the considered period if period == 'year': # just run the aggregation over all given years resulting in # the maximum cdd length and the number of cdd periods for each year for year in years: tmp_cube = cube.extract(iris.Constraint(year=year)) slices[time_axis] = year - years[0] cdd_index_data = tmp_cube.collapsed('time', cdd_index, threshold=threshold).data cdd_periods_data = tmp_cube.collapsed('time', cdd_periods, threshold=threshold, length=length).data cdd_index_cube.data[slices] = cdd_index_data cdd_periods_cube.data[slices] = cdd_periods_data return iris.cube.CubeList((cdd_index_cube, cdd_periods_cube)) else: # run the aggregation over all seasons/months of all years # afterwards aggregate the seasons/month by MAX Aggregator # for the cdd_index and the MEAN Aggregator for cdd_periods for year in years: for p in index_period: constraint_dict = { '%s_number' % period: p, constraint_year_key: year } tmp_cube = cube.extract(iris.Constraint(**constraint_dict)) if tmp_cube: # the extraction can lead to empty cubes for seasons # in the last year time_index = (year - years[0]) * len(index_period) + p # months numbers start at 1 if period == 'month': time_index -= 1 slices[time_axis] = time_index cdd_index_data = tmp_cube.collapsed( 'time', cdd_index, threshold=threshold).data cdd_periods_data = tmp_cube.collapsed('time', cdd_periods, threshold=threshold, length=length).data cdd_index_cube.data[slices] = cdd_index_data cdd_periods_cube.data[slices] = cdd_periods_data # aggregate over seasons/months cat = getattr(ccat, 'add_%s' % period) cat(cdd_index_cube, 'time') cat(cdd_periods_cube, 'time') cdd_index_mean = cdd_index_cube.aggregated_by(period, iris.analysis.MEAN) cdd_periods_mean = cdd_periods_cube.aggregated_by( period, iris.analysis.MEAN) cdd_index_mean.remove_coord('time') cdd_periods_mean.remove_coord('time') return iris.cube.CubeList((cdd_index_mean, cdd_periods_mean))
def consecutive_dry_days(cube, period='year', length=6, threshold=1.): """ calculate consecutive dry days within an iris.cube.Cube Args: * cube (iris.cube.Cube): An iris.cube.Cube holding precipiation amount in mm/day * period (string): Period over that the CDD will be calculated. Can be 'year', 'season' or 'month'. If period is 'season' or 'month' the CDD will be averaged over the years Kwargs: * length (int): The number of days without rainfall that define a dry period * threshold (float): The upper limit of daily rainfall in mm that indicates 'no precipitation' Returns: An iris.cube.CubeList that holds two iris.cube.Cubes with the longest period of dry days in the given period and the mean of the number of dry periods with respect to the given length """ def _cdd_index(array, axis, threshold): """ Calculate the consecutive dry days index. This function is used as an iris.analysis.Aggregator Args: * array (numpy.array or numpy.ma.array): array that holds the precipitation data * axis (int): the number of the time-axis * threshold (float): the threshold that indicates a precipiation-less day Returns: the aggregation result, collapsing the 'axis' dimension of the 'data' argument """ from pycat.analysis.utils import _get_max_true_block_length, _get_true_block_lengths up_down = _get_true_block_lengths(array<threshold, axis) return _get_max_true_block_length(up_down) def _cdd_periods(array, axis, threshold, length): """ Calculate the number of consecutive dry days periods. This function is used as an iris.analysis.Aggregator Args: * array (numpy.array or numpy.ma.array): array that holds the precipitation data * axis (int): the number of the time-axis * threshold (float): the threshold that indicates a precipiation-less day * length (int): number of days that a dry period must last Returns: the aggregation result, collapsing the 'axis' dimension of the 'data' argument """ from pycat.analysis.utils import _get_len_true_block_length, _get_true_block_lengths up_down = _get_true_block_lengths(array<threshold, axis) return _get_len_true_block_length(up_down, length) # build the iris.analysis.Aggregators cdd_index = Aggregator('cdd_index', _cdd_index) cdd_periods = Aggregator('cdd_periods', _cdd_periods) # check if the cube already has the needed auxiliary coordinates if period == 'season': # add the season_year auxiliary coordinate try: years = np.unique(cube.coord('season_year').points) except CoordinateNotFoundError: ccat.add_season_year(cube, 'time') years = np.unique(cube.coord('season_year').points) constraint_year_key = 'season_year' else: # add calendar years try: years = np.unique(cube.coord('year').points) except CoordinateNotFoundError: ccat.add_year(cube, 'time') years = np.unique(cube.coord('year').points) constraint_year_key = 'year' if period in ['season', 'month']: try: index_period = np.unique(cube.coord('%s_number'%period).points) except CoordinateNotFoundError: cat = getattr(ccat, 'add_%s_number' % period) cat(cube, 'time') index_period = np.unique(cube.coord('%s_number'%period).points) # create time-axis of resulting cubes time_dimension = _make_time_dimension( cube.coord('time').units.num2date(cube.coord('time').points[0]), cube.coord('time').units.num2date(cube.coord('time').points[-1]), period=period) # create the empty resulting cubes dim_coords_and_dims = [] slices = [] for coord in cube.dim_coords: if coord.units.is_time_reference(): dim_coords_and_dims.append((time_dimension, cube.coord_dims(coord))) slices.append(0) time_axis = cube.coord_dims(coord)[0] else: dim_coords_and_dims.append((coord, cube.coord_dims(coord))) slices.append(slice(None,None,None)) cdd_index_cube = _create_cube( long_name='Consecutive dry days is the greatest number of consecutive days per time period with daily precipitation amount below %s mm.' % threshold, var_name='consecutive_dry_days_index_per_time_period', units=iris.unit.Unit('1'), dim_coords_and_dims=dim_coords_and_dims) cdd_periods_cube = _create_cube( long_name='Number of cdd periods in given time period with more than %d days.' % length, var_name='number_of_cdd_periods_with_more_than_%ddays_per_time_period' % length, units=iris.unit.Unit('1'), dim_coords_and_dims=dim_coords_and_dims) # differentiate between the considered period if period == 'year': # just run the aggregation over all given years resulting in # the maximum cdd length and the number of cdd periods for each year for year in years: tmp_cube = cube.extract(iris.Constraint(year=year)) slices[time_axis] = year-years[0] cdd_index_data = tmp_cube.collapsed( 'time', cdd_index, threshold=threshold).data cdd_periods_data = tmp_cube.collapsed( 'time', cdd_periods, threshold=threshold, length=length).data cdd_index_cube.data[slices] = cdd_index_data cdd_periods_cube.data[slices] = cdd_periods_data return iris.cube.CubeList( (cdd_index_cube, cdd_periods_cube) ) else: # run the aggregation over all seasons/months of all years # afterwards aggregate the seasons/month by MAX Aggregator # for the cdd_index and the MEAN Aggregator for cdd_periods for year in years: for p in index_period: constraint_dict = {'%s_number' % period: p, constraint_year_key: year} tmp_cube = cube.extract(iris.Constraint(**constraint_dict)) if tmp_cube: # the extraction can lead to empty cubes for seasons # in the last year time_index = (year-years[0])*len(index_period) + p # months numbers start at 1 if period == 'month': time_index -= 1 slices[time_axis] = time_index cdd_index_data = tmp_cube.collapsed( 'time', cdd_index, threshold=threshold).data cdd_periods_data = tmp_cube.collapsed( 'time', cdd_periods, threshold=threshold, length=length).data cdd_index_cube.data[slices] = cdd_index_data cdd_periods_cube.data[slices] = cdd_periods_data # aggregate over seasons/months cat = getattr(ccat, 'add_%s' % period) cat(cdd_index_cube, 'time') cat(cdd_periods_cube, 'time') cdd_index_mean = cdd_index_cube.aggregated_by(period, iris.analysis.MEAN) cdd_periods_mean = cdd_periods_cube.aggregated_by(period, iris.analysis.MEAN) cdd_index_mean.remove_coord('time') cdd_periods_mean.remove_coord('time') return iris.cube.CubeList( (cdd_index_mean, cdd_periods_mean) )