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 _clean_loaded_data(self): for i in range(len(self.data)): self.data[i].metadata.attributes.clear() self.data[i].coord("latitude").points=\ self.data[i].coord("latitude").points.astype(np.float32) self.data[i].coord("longitude").points=\ self.data[i].coord("longitude").points.astype(np.float32) self.data=self.data.concatenate_cube() try: self.data.coord(self.T).convert_units(self.U) except: print(f"Warning: could not convert {self.T} to {self.U}, simply renaming calendar.") new_T=cf_units.Unit(self.data.coord(self.T).units.origin,self.U.calendar) self.data.coord(self.T).units=new_T try: self.data.coord(self.T).convert_units(self.U) except: raise(ValueError("Unsuccesful attempt to change time units.")) iccat.add_hour(self.data,self.T) self.data=self.data.extract(self.constraints["hour"]) iccat.add_day_of_year(self.data,self.T) self.data=self.data.extract(self.constraints["calendar"]) self.data=iris.cube.CubeList([self.data])
def _clean_loaded_data(self): CL=iris.cube.CubeList() for i,cube in enumerate(self.data): for entry in cube.slices_over(self.T): entry.coord(self.T).convert_units(self.U) entry.coord(self.S).convert_units(cf_units.Unit("Days")) T_ref=entry.coord(self.T) S=entry.coord(self.S).points t_coord=iris.coords.AuxCoord(S+T_ref.points[0],standard_name="time") t_coord.units=T_ref.units entry.add_aux_coord(t_coord,data_dims=1) iccat.add_hour(entry,"time") iccat.add_day_of_year(entry,"time") CL.append(entry) CL.sort(key=lambda cube:cube.coord(self.T).points[0]) self.data=CL self.data=self.data.extract(self.constraints["calendar"]) self.data=self.data.extract(self.constraints["lead"]) self.data=self.data.extract(self.constraints["hour"]) self.data=self.data.extract(self.constraints["ens"])
def test_calendars(self): for calendar in calendars: cube = self.make_cube(calendar) add_day_of_year(cube, 'time') points = cube.coord('day_of_year').points expected_points = self.expected[calendar] msg = 'Test failed for the following calendar: {}.' self.assertArrayEqual(points, expected_points, err_msg=msg.format(calendar))
def test_calendars(self): for calendar in calendars: # Skip the Julian calendar due to # https://github.com/Unidata/netcdftime/issues/13 # Remove this if block once the issue is resolved. if calendar == 'julian': continue cube = self.make_cube(calendar) add_day_of_year(cube, 'time') points = cube.coord('day_of_year').points expected_points = self.expected[calendar] msg = 'Test failed for the following calendar: {}.' self.assertArrayEqual(points, expected_points, err_msg=msg.format(calendar))
def test_calendars(self): for calendar in calendars: # Skip the Julian calendar due to # https://github.com/Unidata/netcdftime/issues/13 # Remove this if block once the issue is resolved. if calendar == "julian": continue cube = self.make_cube(calendar) add_day_of_year(cube, "time") points = cube.coord("day_of_year").points expected_points = self.expected[calendar] msg = "Test failed for the following calendar: {}." self.assertArrayEqual(points, expected_points, err_msg=msg.format(calendar))
def _add_nan_timesteps(cube, total_days): add_day_of_year(cube, 'time') cubes = CubeList(cube.slices_over('time')) model_cube = cubes[0].copy() model_cube.remove_coord('day_of_year') for day_of_year in range(total_days): day_constraint = iris.Constraint(day_of_year=day_of_year + 1) if cubes.extract(day_constraint): continue nan_cube = OSICmorizer._create_nan_cube(model_cube, day_of_year, month=False) add_day_of_year(nan_cube, 'time') cubes.append(nan_cube) del model_cube return cubes
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 fix_sst_based_on_siconc(sst, ice, mean_freq_sice, im): ''' Loop through ice concentration bins Find points in which ice concentration is near to this bin Only do this when the sea-ice conc is > 60% (we don't whant to effect the edge, just the Arctic to remove the stripes ''' lat_size = ice.shape[1] ice_min_change_nh = 75.0 ice_min_change_sh = 75.0 start_bin = int(ice_min_change_nh / BIN['SICE']['SIZE']) - 1 coord_names = [coord.name() for coord in sst.coords()] print coord_names if 'day_of_year' not in coord_names: icc.add_day_of_year(sst, 'time', name='day_of_year') ndays = sst.shape[0] day_of_year = sst.coord('day_of_year').points print 'in fix_sst ', day_of_year for day in range(ndays): day_number = day_of_year[day] - 1 print('process day, month ', day, im) for ib, bin in enumerate(BIN['SICE']['XBINS'][:-1]): if bin < ice_min_change_nh - 1: continue ice_range = np.where( (np.abs(ice.data[day, :, :] - bin) < BIN['SICE']['SIZE']) & (ice.data[day, :, :] > ice_min_change_nh) & (ice.data.mask[day, :, :] == False)) nhemi = np.where(ice_range[0] > lat_size / 2) print 'nhemi ', nhemi, ib, bin sst.data[day, ice_range[0][nhemi], ice_range[1][nhemi]] = mean_freq_sice[ib, 0, day_number] ice_range_sh = np.where( (np.abs(ice.data[day, :, :] - bin) < BIN['SICE']['SIZE']) & (ice.data[day, :, :] > ice_min_change_sh) & (ice.data.mask[day, :, :] == False)) shemi = np.where(ice_range_sh[0] < lat_size / 2) print 'shemi ', shemi, ib, bin sst.data[day, ice_range_sh[0][shemi], ice_range_sh[1][shemi]] = mean_freq_sice[ib, 1, day_number] return sst
def add_time_names(cube, year=False, month_number=False, day_of_year=False): ''' Add additional coordiate names to time dimension ''' if year: icc.add_year(cube, 'time', name='year') if month_number: try: icc.add_month_number(cube, 'time', name='month') except: pass if day_of_year: try: icc.add_day_of_year(cube, 'time', name='day_of_year') except: pass
def vortex_clim(self): coord_cat.add_day_of_year(self.U_day, self.tname, name='day_number') ## quick find nearest latitude to 60 function def find_nearest(array, value): array = np.asarray(array) idx = (np.abs(array - value)).argmin() return array[idx] lat = find_nearest(self.U_day.coord('latitude').points, 60) U_vortex = self.U_day.extract(iris.Constraint(latitude=lat)) plt.plot(np.arange(365), U_vortex[0:365].data) plt.show() self.vortex_clim = U_vortex.aggregated_by('day_number', iris.analysis.MEAN) self.vortex_climSTD = U_vortex.aggregated_by('day_number', iris.analysis.STD_DEV) return
def hourly2daily(hourly_cube): ''' Aggregates the hourly precipitation cube into daily_cube :param iris.cube: hourly cube to be aggregated in daily ''' # raise exception is not only one year in a cube? icat.add_day_of_year(hourly_cube, 'time') hourly_cube.coord('time').bounds = None #print(hourly_cube.coord('day_of_year')) print(hourly_cube.coord('day_of_year').points[-80:]) print(hourly_cube.coord('day_of_year').points[:80]) #print(hourly_cube.coord('day_of_year').bounds) if hourly_cube.units in ['kg/m2/s', 'kg m-2 s-1', 'mm day-1', 'mm/day']: daily_data = hourly_cube.aggregated_by('day_of_year', iana.MEAN) elif hourly_cube.units in ['mm', 'mm/h', 'mm h-1', 'mm/3hr', 'mm hour-1']: print('summing hourly') daily_data = hourly_cube.aggregated_by('day_of_year', iana.SUM) daily_data.units = cf_units.as_unit('mm day-1') else: raise ValueError('wrong units: {}'.format(hourly_cube.units)) # daily_data.name = 'precipitation_rate' return daily_data
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"))
uwnd10m = uwnd10m.concatenate_cube() vwnd10m = vwnd10m.concatenate_cube() max_wndgust10m = max_wndgust10m.concatenate_cube() # Regrid U onto V print('Regridding U onto V (so they align in space)...') interpolator = iris.analysis.Linear() vwnd10m = vwnd10m.regrid(uwnd10m, interpolator) # Create a cube of wind speed print('Calculating wind speed...') windspeed = (uwnd10m**2 + vwnd10m**2)**0.5 windspeed.rename('windspeed') # Create extra coordinate for daily statistics ct.add_day_of_year(windspeed, 'time') ct.add_day_of_year(max_wndgust10m, 'time') print('Calculating max wind speed...') max_speed = windspeed.aggregated_by(['day_of_year'], iris.analysis.MAX) print('Calculating max (max) gust...') max_gust = max_wndgust10m.aggregated_by(['day_of_year'], iris.analysis.MAX) # Event maximum print('Calculating event maxima...') event_max_speed = max_speed.collapsed('time', iris.analysis.MAX) event_max_gust = max_gust.collapsed('time', iris.analysis.MAX) # Save the calculation print('Saving calculations...')
hadisst2_dir = '/home/users/mjrobert/hrcm/cache/malcolm/HadISST2/1x1/' cmip_1x1 = os.path.join(hadisst2_dir, 'cmip5_trend_1x1.nc') if not os.path.exists(cmip_1x1): trend_025 = iris.load_cube(cmip_file) trend_025.coord('longitude').circular = True c_ref = iris.load(datafile)[0] for coord in ['latitude','longitude']: c_ref.coord(coord).guess_bounds() trend_025.coord(coord).guess_bounds() trend_1x1 = trend_025.regrid(c_ref, iris.analysis.AreaWeighted()) iris.save(trend_1x1, cmip_1x1) trend = iris.load_cube(cmip_1x1) icc.add_day_of_year(trend, 'time') icc.add_year(trend, 'time') hadisst2_files = glob.glob(os.path.join(hadisst2_dir, 'HadISST2_1x1_regrid_sst*')) ''' for each year, read in the HadISST2 daily data read in the monthly data, dec year-1 to jan year +1 do time interpolation from one time to the other ''' hadisst_data = iris.load_cube(os.path.join(hadisst2_dir, 'HadISST2_1x1_regrid_sst_2002.nc')) icc.add_day_of_year(hadisst_data, 'time') YEARS = iris.Constraint(coord_values = {'year' : lambda l : l == 2002}) sub_trend = trend.extract(YEARS) print sub_trend
plot_SEB_composites() # Find daily means, maxes, climatologies and anomalies Ts_clim = iris.load_cube( '/gws/nopw/j04/bas_climate/users/ellgil82/hindcast/output/alloutput/Ts_climatology.nc' ) Ts_clim.convert_units('celsius') Ts_clim = np.concatenate((Ts_clim[244:].data, Ts_clim[:90].data), axis=0) Tair_clim = iris.load_cube( '/gws/nopw/j04/bas_climate/users/ellgil82/hindcast/output/alloutput/Tair_1p5m_climatology.nc' ) Tair_clim.convert_units('celsius') Tair_clim = np.concatenate((Tair_clim[244:].data, Tair_clim[:90].data), axis=0) import iris.coord_categorisation as cat cat.add_day_of_year(var_dict['Ts'], 't', name='day') cat.add_day_of_year(var_dict['Tair'], 't', name='day') Ts_daymax = var_dict['Ts'].aggregated_by('day', iris.analysis.MAX) Ts_daily = var_dict['Ts'].aggregated_by('day', iris.analysis.MEAN) Ts_anom = Ts_daily - Ts_clim[:, 0, :, :] Tair_daymax = var_dict['Tair'].aggregated_by('day', iris.analysis.MAX) Tair_daily = var_dict['Tair'].aggregated_by('day', iris.analysis.MEAN) Tair_anom = Tair_daily - Tair_clim[:, 0, :, :] def plot_synop_composite(cf_var, c_var, u_var, v_var): fig = plt.figure(frameon=False, figsize=( 9, 10)) # !!change figure dimensions when you have a larger model domain fig.patch.set_visible(False) ax = fig.add_subplot(111) #, projection=ccrs.PlateCarree())
def add_time_coord_cats(cube): """ This function takes in an iris cube, and adds a range of numeric co-ordinate categorisations to it. Depending on the data, not all of the coords added will be relevant. args ---- cube: iris cube that has a coordinate called 'time' Returns ------- Cube: cube that has new time categorisation coords added Notes ----- test A simple example: >>> file = os.path.join(conf.DATA_DIR, 'mslp.daily.rcm.viet.nc') >>> cube = iris.load_cube(file) >>> coord_names = [coord.name() for coord in cube.coords()] >>> print((', '.join(coord_names))) time, grid_latitude, grid_longitude >>> ccube = add_time_coord_cats(cube) >>> coord_names = [coord.name() for coord in ccube.coords()] >>> print((', '.join(coord_names))) time, grid_latitude, grid_longitude, day_of_month, day_of_year, month, \ month_number, season, season_number, year >>> # print every 50th value of the added time cat coords ... for c in coord_names[3:]: ... print(ccube.coord(c).long_name) ... print(ccube.coord(c).points[::50]) ... day_of_month [ 1 21 11 1 21 11 1 21] day_of_year [ 1 51 101 151 201 251 301 351] month ['Jan' 'Feb' 'Apr' 'Jun' 'Jul' 'Sep' 'Nov' 'Dec'] month_number [ 1 2 4 6 7 9 11 12] season ['djf' 'djf' 'mam' 'jja' 'jja' 'son' 'son' 'djf'] season_number [0 0 1 2 2 3 3 0] year [2000 2000 2000 2000 2000 2000 2000 2000] """ # most errors pop up when you try to add a coord that has # previously been added, or the cube doesn't contain the # necessary attribute. ccube = cube.copy() # numeric try: iccat.add_day_of_year(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) try: iccat.add_day_of_month(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) try: iccat.add_month_number(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) try: iccat.add_season_number(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) try: iccat.add_year(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) # strings try: iccat.add_month(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) try: iccat.add_season(ccube, "time") except AttributeError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) except ValueError as err: print(("add_time_coord_cats: {}, skipping . . . ".format(err))) return ccube
def generate_future_siconc_from_sst(mean_freq_days, year, months, ice_mask, ice_mask_min, ice_ref): ''' Use the maximum ice extent, the SST and the pdf relationship between SST and sea-ice to generate a future sea ice concentration ''' #dir_in = '/group_workspaces/jasmin2/primavera1/WP6/forcing/HadISST2_submit/v1.2/' if year >= 2016: #future_sst_file = os.path.join(DATADIR, 'future', 'full_sst_1950_2100_025_daily_fixed.nc') future_sst_file = os.path.join( savedir, 'sst', 'future_sst_' + str(year) + '_025_daily_v1.nc') else: if len(months) == 12: future_sst_file = os.path.join( DATADIR, 'hadisst2_tos_daily_' + str(year) + '_fixed_day_v1_monthly_under_ice.nc') elif len(months) == 1: future_sst_file = os.path.join( DATADIR, 'hadisst2_tos_daily_' + str(year) + '_fixed_' + str(months[0] + 1).zfill(2) + '.nc') else: raise Exception('Must be either 12 months or 1 ' + str(len(months))) future_siconc_file = os.path.join(savedir_ice, 'siconc', 'future_siconc_{}_025_daily_v1.nc') print 'read sst ', future_sst_file full_sst = iris.load_cube(future_sst_file) try: #icc.add_month_number(full_siconc, 'time', name = 'month') icc.add_month_number(full_sst, 'time', name='month') except: pass try: #icc.add_year(full_siconc, 'time', name = 'year') icc.add_year(full_sst, 'time', name='year') except: pass #print 'full cube ',full_siconc.coord('year') new_sice_year = iris.cube.CubeList() print 'YEAR ', year fout_year = future_siconc_file.format(str(year)) new_sice_month = iris.cube.CubeList() year_con = iris.Constraint(coord_values={'year': lambda l: l == int(year)}) sst_this_year = full_sst.extract(year_con) full_siconc = sst_this_year.copy() print 'cube year ', sst_this_year lat_shape = sst_this_year.shape[1] for im in months: if im > 0 and im < 11: mm1 = im - 1 mp1 = im + 1 elif im == 0: mm1 = 11 mp1 = im + 1 elif im == 11: mm1 = im - 1 mp1 = 0 month = im + 1 month_con = iris.Constraint( coord_values={'month': lambda l: l == int(month)}) sst_this_month = sst_this_year.extract(month_con) if im == 0: month_con_m1 = iris.Constraint( coord_values={'month': lambda l: l == 1}) else: month_con_m1 = iris.Constraint( coord_values={'month': lambda l: l == int(month - 1)}) sst_last_month = sst_this_year.extract(month_con_m1) if im == 11: month_con_p1 = iris.Constraint( coord_values={'month': lambda l: l == 11}) else: month_con_p1 = iris.Constraint( coord_values={'month': lambda l: l == int(month + 1)}) sst_next_month = sst_this_year.extract(month_con_p1) siconc_template = full_siconc.extract(month_con) coord_names = [coord.name() for coord in siconc_template.coords()] print coord_names if 'day_of_year' not in coord_names: icc.add_day_of_year(siconc_template, 'time', name='day_of_year') siconc_template.data[...] = 0.0 ndays = sst_this_month.shape[0] day_of_year = siconc_template.coord('day_of_year').points for day in range(ndays): day_number = day_of_year[day] - 1 print 'process ', day, month, year, day_number for ib, bin in enumerate(BIN['SST']['XBINS'][:-1]): sst_range = np.where((bin < sst_this_month.data[day, :, :]) & ( bin + 1 >= sst_this_month.data[day, :, :]) & (ice_mask.data[im, :, :] == 1)) nhemi = np.where(sst_range[0] > lat_shape / 2) shemi = np.where(sst_range[0] < lat_shape / 2) siconc_template.data[ day, sst_range[0][nhemi], sst_range[1][nhemi]] = mean_freq_days[year][ib, 0, day_number] siconc_template.data[ day, sst_range[0][shemi], sst_range[1][shemi]] = mean_freq_days[year][ib, 1, day_number] print 'completed ', day, month, year siconc_template.data.mask[:, sst_this_month[0].data.mask] = True siconc_template.data.mask[:, ice_ref.data.mask] = True new_sice_month.append(siconc_template) new_sice_cube = new_sice_month.concatenate_cube() add_metadata(new_sice_cube) print 'write to ', fout_year iris.save(new_sice_cube, fout_year, unlimited_dimensions=['time'], fill_value=1.0e20) return fout_year
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_day_of_year(cube, 'time', name='day_of_year') 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', 'day_of_year']: cube.coord(coord_name).points = \ cube.coord(coord_name).points.astype(np.int64) # check values self.assertCML(cube, ('categorisation', 'quickcheck.cml'))
elif unit.name[:3] == 'day': thirty_mins = 0.5 / 24 else: raise ValueError(f"Don't know how to deal with: '{unit.name}'") print('Subtracting half an hour from time coord first') new_points = cube.coord('time').points - thirty_mins cube.coord('time').points = new_points iccat.add_year(cube, 'time') if freq == 'mon': iccat.add_month_number(cube, 'time') agg_by = ['month_number', 'year'] remove_later = 'month_number' elif freq == 'day': iccat.add_day_of_year(cube, 'time') agg_by = ['day_of_year', 'year'] remove_later = 'day_of_year' else: raise ValueError('Unrecognised frequency') # compute averages print(f'Computing {freq} average') means = cube.aggregated_by(agg_by, iris.analysis.MEAN) # remove no longer needed aux coords means.remove_coord(remove_later) means.remove_coord('year') # make sure standard names are being used if means.var_name == 'pr':
def adjust_bias(obs_hist, sim_hist, sim_fut, realize_cubes=False, anonymous_dimension_name=None, halfwin_upper_bound_climatology=0, n_processes=1, **kwargs): """ Adjusts biases grid cell by grid cell. Parameters ---------- obs_hist : iris cube Cube of observed climate data representing the historical or training time period. sim_hist : iris cube Cube of simulated climate data representing the historical or training time period. sim_fut : iris cube Cube of simulated climate data representing the future or application time period. realize_cubes : boolean, optional Realize data of obs_hist, sim_hist, and sim_fut before beginning the bias adjustment grid cell by grid cell. anonymous_dimension_name : str, optional Used to name the first anonymous dimension of obs_hist, sim_hist, and sim_fut. halfwin_upper_bound_climatology : int, optional Determines the length of running windows used in the calculations of climatologies of upper bounds that is used to rescale all values of obs_hist, sim_hist, and sim_fut to values <= 1 before bias adjustment. The window length is set to halfwin_upper_bound_climatology * 2 + 1 time steps. If halfwin_upper_bound_climatology == 0 then no rescaling is done. n_processes : int, optional Number of processes used for parallel processing. Returns ------- sim_fut_ba : iris cube Result of bias adjustment. Other Parameters ---------------- **kwargs : Passed on to adjust_bias_one_location. """ # put iris cubes into dictionary cubes = {'obs_hist': obs_hist, 'sim_hist': sim_hist, 'sim_fut': sim_fut} space_shape = None for key, cube in cubes.items(): # get cube shape beyond time axis if space_shape is None: space_shape = cube.shape[1:] else: assert space_shape == cube.shape[1:], 'cube shapes not compatible' # load iris cube data into memory if realize_cubes: d = cube.data # make sure the proleptic gregorian calendar is used in all input files uf.assert_calendar(cube, 'proleptic_gregorian') # make sure that time is the leading coordinate uf.assert_coord_axis(cube, 'time', 0) # name the first anonymous dimension uf.name_first_anonymous_dimension(cube, anonymous_dimension_name) # prepare scaling by upper bound climatology if halfwin_upper_bound_climatology: icc.add_day_of_year(cube, 'time') # prepare bias adjustment calendar month by calendar month icc.add_month_number(cube, 'time') # prepare detrending and cube concatenation icc.add_year(cube, 'time') # adjust every location individually using multiprocessing print('adjusting at location ...') abol = partial( adjust_bias_one_location, halfwin_upper_bound_climatology=halfwin_upper_bound_climatology, **kwargs) pool = mp.Pool(n_processes, maxtasksperchild=1000) time_series_adjusted = pool.imap( abol, zip(obs_hist.slices('time'), sim_hist.slices('time'), sim_fut.slices('time'))) pool.close() # replace time series in sim_fut by the adjusted time series sim_fut_ba = sim_fut d = sim_fut_ba.data for i_location, tsa in zip(np.ndindex(space_shape), time_series_adjusted): d[(slice(None, None), ) + i_location] = tsa print(i_location) # remove auxiliary coordinates sim_fut_ba.remove_coord('year') sim_fut_ba.remove_coord('month_number') if halfwin_upper_bound_climatology: sim_fut_ba.remove_coord('day_of_year') return sim_fut_ba