def seaice_drag_scaling(grid_path, output_file, rd_scale=1, bb_scale=1, ft_scale=1, prec=64): # Longitude bounds on each region rd_bounds = [-80, -58] # Western bound is well into land bb_bounds = [-49, -45] ft_bounds = [-42, -38] # Max distance from the ice front (km) max_dist = 100 print 'Building grid' grid = Grid(grid_path) lon, lat = grid.get_lon_lat() print 'Selecting regions' # First find ice shelf front points front_points = ice_shelf_front_points(grid, ice_mask=grid.fris_mask) # Also coastal points for Berkner Island bi_front_points = ice_shelf_front_points(grid, ice_mask=grid.get_bi_mask()) # Combine the two arrays front_points = np.maximum(front_points, bi_front_points) # Now get i and j indices of these points i_vals, j_vals = np.meshgrid(range(grid.nx), range(grid.ny)) i_front = i_vals[front_points] j_front = j_vals[front_points] num_points = len(i_front) # Find the distance from each point in the domain to the closest ice shelf front point, by looping over all the ice shelf front points. # Start with an array of infinity, and update it with any smaller values each iteration. So the first iteration will fully overwrite it. dist_to_front = np.zeros([grid.ny, grid.nx]) + np.inf for posn in range(num_points): # Calculate the distance of each point to this point, and convert to km dist_to_point = dist_btw_points( (grid.lon_1d[i_front[posn]], grid.lat_1d[j_front[posn]]), (lon, lat)) * 1e-3 dist_to_front = np.minimum(dist_to_front, dist_to_point) # Now select the three regions # Must be between the given longitude bounds and not more than max_dist km away from the ice shelf front rd_mask = (lon >= rd_bounds[0]) * (lon <= rd_bounds[1]) * ( dist_to_front <= max_dist) bb_mask = (lon >= bb_bounds[0]) * (lon <= bb_bounds[1]) * ( dist_to_front <= max_dist) ft_mask = (lon >= ft_bounds[0]) * (lon <= ft_bounds[1]) * ( dist_to_front <= max_dist) print 'Setting scaling factors' scale = np.ones([grid.ny, grid.nx]) scale[rd_mask] = rd_scale scale[bb_mask] = bb_scale scale[ft_mask] = ft_scale # Smooth scale = smooth_xy(scale, sigma=2) # Reset ice shelf points scale[grid.ice_mask] = 1 # Write to file write_binary(scale, output_file, prec=prec)
def sose_sss_restoring (grid_path, sose_dir, output_salt_file, output_mask_file, nc_out=None, h0=-1250, obcs_sponge=0, split=180, prec=64): sose_dir = real_dir(sose_dir) print 'Building grids' # First build the model grid and check that we have the right value for split model_grid = grid_check_split(grid_path, split) # Now build the SOSE grid sose_grid = SOSEGrid(sose_dir+'grid/', model_grid=model_grid, split=split) # Extract surface land mask sose_mask = sose_grid.hfac[0,:] == 0 print 'Building mask' mask_surface = np.ones([model_grid.ny, model_grid.nx]) # Mask out land and ice shelves mask_surface[model_grid.hfac[0,:]==0] = 0 # Save this for later mask_land_ice = np.copy(mask_surface) # Mask out continental shelf mask_surface[model_grid.bathy > h0] = 0 # Smooth, and remask the land and ice shelves mask_surface = smooth_xy(mask_surface, sigma=2)*mask_land_ice if obcs_sponge > 0: # Also mask the cells affected by OBCS and/or its sponge mask_surface[:obcs_sponge,:] = 0 mask_surface[-obcs_sponge:,:] = 0 mask_surface[:,:obcs_sponge] = 0 mask_surface[:,-obcs_sponge:] = 0 # Make a 3D version with zeros in deeper layers mask_3d = np.zeros([model_grid.nz, model_grid.ny, model_grid.nx]) mask_3d[0,:] = mask_surface print 'Reading SOSE salinity' # Just keep the surface layer sose_sss = sose_grid.read_field(sose_dir+'SALT_climatology.data', 'xyzt')[:,0,:,:] # Figure out which SOSE points we need for interpolation # Restoring mask interpolated to the SOSE grid fill = np.ceil(interp_reg(model_grid, sose_grid, mask_3d[0,:], dim=2, fill_value=1)) # Extend into the mask a few times to make sure there are no artifacts near the coast fill = extend_into_mask(fill, missing_val=0, num_iters=3) # Process one month at a time sss_interp = np.zeros([12, model_grid.nz, model_grid.ny, model_grid.nx]) for month in range(12): print 'Month ' + str(month+1) print '...filling missing values' sose_sss_filled = discard_and_fill(sose_sss[month,:], sose_mask, fill, use_3d=False) print '...interpolating' # Mask out land and ice shelves sss_interp[month,0,:] = interp_reg(sose_grid, model_grid, sose_sss_filled, dim=2)*mask_land_ice write_binary(sss_interp, output_salt_file, prec=prec) write_binary(mask_3d, output_mask_file, prec=prec) if nc_out is not None: print 'Writing ' + nc_out ncfile = NCfile(nc_out, model_grid, 'xyzt') ncfile.add_time(np.arange(12)+1, units='months') ncfile.add_variable('salinity', sss_interp, 'xyzt', units='psu') ncfile.add_variable('restoring_mask', mask_3d, 'xyz') ncfile.close()
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)