def read_process_data (file_path, var_name, grid, mask_option='3d', gtype='t', lev_option=None, ismr=False, psi=False): data = read_netcdf(file_path, var_name) if mask_option == '3d': data = mask_3d(data, grid, gtype=gtype, time_dependent=True) elif mask_option == 'except_ice': data = mask_except_ice(data, grid, gtype=gtype, time_dependent=True) elif mask_option == 'land': data = mask_land(data, grid, gtype=gtype, time_dependent=True) elif mask_option == 'land_ice': data = mask_land_ice(data, grid, gtype=gtype, time_dependent=True) else: print 'Error (read_process_data): invalid mask_option ' + mask_option sys.exit() if lev_option is not None: if lev_option == 'top': data = select_top(data) elif lev_option == 'bottom': data = select_bottom(data) else: print 'Error (read_process_data): invalid lev_option ' + lev_option sys.exit() if ismr: data = convert_ismr(data) if psi: data = np.sum(data, axis=-3)*1e-6 return data
def timeseries_area_sfc(option, file_path, var_name, grid, gtype='t', time_index=None, t_start=None, t_end=None, time_average=False): # Read the data data = read_netcdf(file_path, var_name, time_index=time_index, t_start=t_start, t_end=t_end, time_average=time_average) if len(data.shape) == 2: # Just one timestep; add a dummy time dimension data = np.expand_dims(data, 0) # Process one time index at a time to save memory timeseries = [] for t in range(data.shape[0]): # Mask data_tmp = mask_land_ice(data[t, :], grid, gtype=gtype) # Area-average or integrate timeseries.append(over_area(option, data_tmp, grid, gtype=gtype)) return np.array(timeseries)
def iceberg_meltwater(grid_path, input_dir, output_file, nc_out=None, prec=32): from plot_latlon import latlon_plot input_dir = real_dir(input_dir) file_head = 'icebergs_' file_tail = '.nc' print 'Building grids' # Read the NEMO grid from the first file # It has longitude in the range -180 to 180 file_path = input_dir + file_head + '01' + file_tail nemo_lon = read_netcdf(file_path, 'nav_lon') nemo_lat = read_netcdf(file_path, 'nav_lat') # Build the model grid model_grid = Grid(grid_path, max_lon=180) print 'Interpolating' icebergs_interp = np.zeros([12, model_grid.ny, model_grid.nx]) for month in range(12): print '...month ' + str(month + 1) # Read the data file_path = input_dir + file_head + '{0:02d}'.format(month + 1) + file_tail icebergs = read_netcdf(file_path, 'berg_total_melt', time_index=0) # Interpolate icebergs_interp_tmp = interp_nonreg_xy(nemo_lon, nemo_lat, icebergs, model_grid.lon_1d, model_grid.lat_1d, fill_value=0) # Make sure the land and ice shelf cavities don't get any iceberg melt icebergs_interp_tmp[model_grid.land_mask + model_grid.ice_mask] = 0 # Save to the master array icebergs_interp[month, :] = icebergs_interp_tmp write_binary(icebergs_interp, output_file, prec=prec) print 'Plotting' # Make a nice plot of the annual mean latlon_plot(mask_land_ice(np.mean(icebergs_interp, axis=0), model_grid), model_grid, include_shelf=False, vmin=0, title=r'Annual mean iceberg melt (kg/m$^2$/s)') if nc_out is not None: # Also write to NetCDF file print 'Writing ' + nc_out ncfile = NCfile(nc_out, model_grid, 'xyt') ncfile.add_time(np.arange(12) + 1, units='months') ncfile.add_variable('iceberg_melt', icebergs_interp, 'xyt', units='kg/m^2/s') ncfile.close()
def polynya_mask(grid_path, polynya, mask_file, prec=64): from plot_latlon import latlon_plot # Define the centre and radii of the ellipse bounding the polynya if polynya == 'maud_rise': # Area 2.6 x 10^5 km^2 lon0 = 0. lat0 = -65. rlon = 8. rlat = 2. elif polynya == 'near_shelf': # Area 2.6 x 10^5 km^2 lon0 = -30. lat0 = -70. rlon = 9. rlat = 2.2 elif polynya == 'maud_rise_big': # Area 6.2 x 10^5 km^2 lon0 = 0. lat0 = -65. rlon = 15. rlat = 2.5 elif polynya == 'maud_rise_small': # Area 0.34 x 10^5 km^2 lon0 = 0 lat0 = -65. rlon = 2.8 rlat = 0.75 else: print 'Error (polynya_mask): invalid polynya option ' + polynya sys.exit() # Build the grid grid = Grid(grid_path) # Set up the mask mask = np.zeros([grid.ny, grid.nx]) # Select the polynya region index = (grid.lon_2d - lon0)**2 / rlon**2 + (grid.lat_2d - lat0)**2 / rlat**2 <= 1 mask[index] = 1 # Print the area of the polynya print 'Polynya area is ' + str(area_integral(mask, grid) * 1e-6) + ' km^2' # Plot the mask latlon_plot(mask_land_ice(mask, grid), grid, include_shelf=False, title='Polynya mask', figsize=(10, 6)) # Write to file write_binary(mask, mask_file, prec=prec)
def interp_grid(data, grid, gtype_in, gtype_out, time_dependent=False, mask=True, mask_shelf=False, mask_with_zeros=False, periodic=False): depth_dependent = is_depth_dependent(data, time_dependent=time_dependent) # Make sure we're not trying to mask the ice shelf from a depth-dependent field if mask_shelf and depth_dependent: print "Error (interp_grid): can't set mask_shelf=True for a depth-dependent field." sys.exit() if mask and gtype_in in ['u', 'v', 'psi', 'w']: # Fill the mask with zeros (okay because no-slip boundary condition) data_tmp = np.copy(data) data_tmp[data.mask] = 0.0 else: # Tracer land mask is the least restrictive, so it doesn't matter what the masked values are - they will definitely get re-masked at the end. data_tmp = data # Interpolate data_interp = np.empty(data_tmp.shape) if gtype_in == 'u' and gtype_out == 't': # Midpoints in the x direction data_interp[..., :-1] = 0.5 * (data_tmp[..., :-1] + data_tmp[..., 1:]) # Extend/wrap the easternmost column if periodic: data_interp[..., -1] = data_interp[..., 0] else: data_interp[..., -1] = data_tmp[..., -1] elif gtype_in == 'v' and gtype_out == 't': # Midpoints in the y direction data_interp[..., :-1, :] = 0.5 * (data_tmp[..., :-1, :] + data_tmp[..., 1:, :]) # Extend the northernmost row data_interp[..., -1, :] = data_tmp[..., -1, :] elif gtype_in == 't' and gtype_out == 'u': # Midpoints in the x direction data_interp[..., 1:] = 0.5 * (data_tmp[..., :-1] + data_tmp[..., 1:]) # Extend/wrap the westernmost column if periodic: data_interp[..., 0] = data_interp[..., -1] else: data_interp[..., 0] = data_tmp[..., 0] elif gtype_in == 't' and gtype_out == 'v': # Midpoints in the y direction data_interp[..., 1:, :] = 0.5 * (data_tmp[..., :-1, :] + data_tmp[..., :-1, :]) # Extend the southernmost row data_interp[..., 0, :] = data_tmp[..., 0, :] else: print 'Error (interp_grid): interpolation from the ' + gtype_in + '-grid to the ' + gtype_out + '-grid is not yet supported' sys.exit() if mask: # Now apply the mask if depth_dependent: data_interp = mask_3d(data_interp, grid, gtype=gtype_out, time_dependent=time_dependent) else: if mask_shelf: data_interp = mask_land_ice(data_interp, grid, gtype=gtype_out, time_dependent=time_dependent) else: data_interp = mask_land(data_interp, grid, gtype=gtype_out, time_dependent=time_dependent) if mask_with_zeros: # Remove mask and fill with zeros data_interp[data_interp.mask] = 0 data_interp = data_interp.data return data_interp
def seaice_drag_scaling (grid_path, output_file, rd_scale=1, bb_scale=1, ft_scale=1, prec=64): from plot_latlon import latlon_plot # Cutoff latitude max_lat = -74 # Longitude bounds on each region rd_bounds = [-62, -58] bb_bounds = [-57, -49] ft_bounds = [-48, -35] bounds = [rd_bounds, bb_bounds, ft_bounds] scale_factors = [rd_scale, bb_scale, ft_scale] # Max distance from the coast (km) scale_dist = 150 # Sigma for smoothing sigma = 2 print 'Building grid' grid = Grid(grid_path) print 'Selecting coastal points' coast_mask = grid.get_coast_mask(ignore_iceberg=True) lon_coast = grid.lon_2d[coast_mask].ravel() lat_coast = grid.lat_2d[coast_mask].ravel() print 'Selecting regions' scale_coast = np.ones(lon_coast.shape) for n in range(3): index = (lon_coast >= bounds[n][0])*(lon_coast <= bounds[n][1])*(lat_coast <= max_lat) scale_coast[index] = scale_factors[n] print 'Calculating distance from the coast' min_dist = None nearest_scale = None # Loop over all the coastal points for i in range(lon_coast.size): # Calculate distance of every point in the model grid to this specific coastal point, in km dist_to_pt = dist_btw_points([lon_coast[i], lat_coast[i]], [grid.lon_2d, grid.lat_2d])*1e-3 if min_dist is None: # Initialise the arrays min_dist = dist_to_pt nearest_scale = np.zeros(min_dist.shape) + scale_coast[i] else: # Figure out which cells have this coastal point as the closest one yet, and update the arrays index = dist_to_pt < min_dist min_dist[index] = dist_to_pt[index] nearest_scale[index] = scale_coast[i] # Smooth the result, and mask out the land and ice shelves min_dist = mask_land_ice(min_dist, grid) nearest_scale = mask_land_ice(smooth_xy(nearest_scale, sigma=sigma), grid) print 'Extending scale factors offshore' # Cosine function moving from scaling factor to 1 over distance of 300 km offshore scale_extend = (min_dist < scale_dist)*(nearest_scale - 1)*np.cos(np.pi/2*min_dist/scale_dist) + 1 print 'Plotting' latlon_plot(scale_extend, grid, ctype='ratio', include_shelf=False, title='Scaling factor', figsize=(10,6)) latlon_plot(scale_extend, grid, ctype='ratio', include_shelf=False, title='Scaling factor', zoom_fris=True) print 'Writing to file' # Replace mask with zeros mask = scale_extend.mask scale_extend = scale_extend.data scale_extend[mask] = 0 write_binary(scale_extend, output_file, prec=prec)
def katabatic_correction(grid_dir, cmip_file, era5_file, out_file_scale, out_file_rotate, scale_cap=3, xmin=None, xmax=None, ymin=None, ymax=None, prec=64): var_names = ['uwind', 'vwind'] scale_dist = 150. # Radius for smoothing sigma = 2 print 'Building grid' grid = Grid(grid_dir) print 'Selecting coastal points' coast_mask = grid.get_coast_mask(ignore_iceberg=True) lon_coast = grid.lon_2d[coast_mask].ravel() lat_coast = grid.lat_2d[coast_mask].ravel() if xmin is None: xmin = np.amin(grid.lon_2d) if xmax is None: xmax = np.amax(grid.lon_2d) if ymin is None: ymin = np.amin(grid.lat_2d) if ymax is None: ymax = np.amax(grid.lat_2d) print 'Calculating winds in polar coordinates' magnitudes = [] angles = [] for fname in [cmip_file, era5_file]: u = read_netcdf(fname, var_names[0]) v = read_netcdf(fname, var_names[1]) magnitudes.append(np.sqrt(u**2 + v**2)) angle = np.arctan2(v, u) angles.append(angle) print 'Calculating corrections' # Take minimum of the ratio of ERA5 to CMIP wind magnitude, and the scale cap scale = np.minimum(magnitudes[1] / magnitudes[0], scale_cap) # Smooth and mask the land and ice shelf scale = mask_land_ice(smooth_xy(scale, sigma=sigma), grid) # Take difference in angles rotate = angles[1] - angles[0] # Take mod 2pi when necessary index = rotate < -np.pi rotate[index] += 2 * np.pi index = rotate > np.pi rotate[index] -= 2 * np.pi # Smoothing would be weird with the periodic angle, so just mask rotate = mask_land_ice(rotate, grid) print 'Calculating distance from the coast' min_dist = None # Loop over all the coastal points for i in range(lon_coast.size): # Skip over any points that are out of bounds if lon_coast[i] < xmin or lon_coast[i] > xmax or lat_coast[ i] < ymin or lat_coast[i] > ymax: continue # Calculate distance of every point in the model grid to this specific coastal point, in km dist_to_pt = dist_btw_points([lon_coast[i], lat_coast[i]], [grid.lon_2d, grid.lat_2d]) * 1e-3 if min_dist is None: # Initialise the array min_dist = dist_to_pt else: # Figure out which cells have this coastal point as the closest one yet, and update the array index = dist_to_pt < min_dist min_dist[index] = dist_to_pt[index] print 'Tapering function offshore' # Cosine function moving from scaling factor to 1 over distance of scale_dist km offshore scale_tapered = (min_dist < scale_dist) * (scale - 1) * np.cos( np.pi / 2 * min_dist / scale_dist) + 1 # For the rotation, move from scaling factor to 0 rotate_tapered = (min_dist < scale_dist) * rotate * np.cos( np.pi / 2 * min_dist / scale_dist) print 'Plotting' data_to_plot = [min_dist, scale_tapered, rotate_tapered] titles = ['Distance to coast (km)', 'Scaling factor', 'Rotation factor'] ctype = ['basic', 'ratio', 'plusminus'] fig_names = ['min_dist.png', 'scale.png', 'rotate.png'] for i in range(len(data_to_plot)): for fig_name in [None, fig_names[i]]: latlon_plot(data_to_plot[i], grid, ctype=ctype[i], include_shelf=False, title=titles[i], figsize=(10, 6), fig_name=fig_name) print 'Writing to file' fields = [scale_tapered, rotate_tapered] out_files = [out_file_scale, out_file_rotate] for n in range(len(fields)): # Replace mask with zeros mask = fields[n].mask data = fields[n].data data[mask] = 0 write_binary(data, out_files[n], prec=prec)