예제 #1
0
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)
예제 #2
0
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()
예제 #3
0
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)
예제 #4
0
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)