예제 #1
0
def cartesian_grid_3d (lon, lat, h, zice, theta_s, theta_b, hc, N, zeta=None):

    # Calculate 2D dx and dy in another script
    dx, dy = cartesian_grid_2d(lon, lat)
    # Copy into 3D arrays, same at each depth level
    dx = tile(dx, (N,1,1))
    dy = tile(dy, (N,1,1))
    # Save horizontal dimensions
    num_lat = size(lon, 0)
    num_lon = size(lon, 1)

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused
    z, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
    # We have z at the midpoint of each cell, now find it on the top and
    # bottom edges of each cell
    z_edges = zeros((N+1, num_lat, num_lon))
    z_edges[1:-1,:,:] = 0.5*(z[0:-1,:,:] + z[1:,:,:])
    # At surface, z=zice
    z_edges[-1,:,:] = zice[:,:]
    # Add zeta if it exists
    if zeta is not None:
        z_edges[-1,:,:] += zeta[:,:]
    # At bottom, extrapolate
    z_edges[0,:,:] = 2*z[0,:,:] - z_edges[1,:,:]
    # Now find dz
    dz = z_edges[1:,:,:] - z_edges[0:-1,:,:]    

    return dx, dy, dz, z
예제 #2
0
def cartesian_grid_3d(lon, lat, h, zice, theta_s, theta_b, hc, N, zeta=None):

    # Calculate 2D dx and dy in another script
    dx, dy = cartesian_grid_2d(lon, lat)
    # Copy into 3D arrays, same at each depth level
    dx = tile(dx, (N, 1, 1))
    dy = tile(dy, (N, 1, 1))
    # Save horizontal dimensions
    num_lat = size(lon, 0)
    num_lon = size(lon, 1)

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused
    z, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
    # We have z at the midpoint of each cell, now find it on the top and
    # bottom edges of each cell
    z_edges = zeros((N + 1, num_lat, num_lon))
    z_edges[1:-1, :, :] = 0.5 * (z[0:-1, :, :] + z[1:, :, :])
    # At surface, z=zice
    z_edges[-1, :, :] = zice[:, :]
    # Add zeta if it exists
    if zeta is not None:
        z_edges[-1, :, :] += zeta[:, :]
    # At bottom, extrapolate
    z_edges[0, :, :] = 2 * z[0, :, :] - z_edges[1, :, :]
    # Now find dz
    dz = z_edges[1:, :, :] - z_edges[0:-1, :, :]

    return dx, dy, dz, z
예제 #3
0
def plot_vslice(file_path, timestep, variable, depth_min, depth_max, i_min,
                j_min, i_max, j_max, Vstretching, theta_s, theta_b, hc, N,
                lbound, ubound):

    #read grid and variable at timestep
    id = Dataset(file_path, 'r')
    h = id.variables['h'][:, :]
    zice = id.variables['zice'][:, :]
    mask = id.variables['mask_rho'][:, :]
    var = id.variables[variable]
    data = var[timestep, :, :, :]
    if hasattr(var, 'units'):
        unit = var.units
    else:
        unit = 'nondimensional'
    name = var.long_name
    id.close()

    #calc 3D field of depth values
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, None,
                              Vstretching)

    #get a 3D land mask
    mask_3d = tile(mask, (N, 1, 1))

    #mask out land
    data_3d = ma.masked_where(mask_3d == 0, data)

    #simple index array for later plotting
    idx_4d = np.indices(shape(data_3d), int)

    #extract values along this line (from stackoverflow)
    #make a line with num points
    num = int(sqrt(square(i_max - i_min) + square(j_max - j_min))) + 1
    x, y = np.linspace(i_min, i_max, num), np.linspace(j_min, j_max, num)

    #extract values of 3d arrays along this line
    z_2d = z_3d[:, y.astype(np.int), x.astype(np.int)]
    idx_3d = idx_4d[:, :, y.astype(np.int), x.astype(np.int)]
    data_2d = data_3d[:, y.astype(np.int), x.astype(np.int)]

    #convert index value to distance
    dist_2d = sqrt(square(idx_3d[1]) + square(idx_3d[2]))

    #contour levels
    #lev=range(1,N)

    #Plot
    fig = figure(figsize=(18, 6))
    pcolormesh(dist_2d, z_2d, data_2d, vmin=lbound, vmax=ubound)
    colorbar()
    title(name + " (" + unit + ") at timestep " + str(timestep + 1) +
          " \n along the line " + str([i_min, j_min]) + " to " +
          str([i_max, j_max]) + " (grid coords [i,j])",
          fontsize=24)
    xlabel('Distance (km)')
    ylabel('Depth (m)')
    ylim([depth_min, depth_max])
    #fig.show()
    return fig
예제 #4
0
def plot_layers(grid_path, depth_min, depth_max, i_min, j_min, i_max, j_max,
                Vstretching, theta_s, theta_b, hc, N):

    #read grid
    id = Dataset(grid_path, 'r')
    h = id.variables['h'][:, :]
    zice = id.variables['zice'][:, :]
    mask = id.variables['mask_rho'][:, :]
    id.close()

    #calc 3D field of depth values
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, None,
                              Vstretching)

    #get a 3D land mask
    mask_3d = tile(mask, (N, 1, 1))

    #simple array containing layer numbers
    layer_3d_tmp = zeros(shape(z_3d))
    for k in range(N):
        layer_3d_tmp[k, :] = k + 1

    #mask out land
    layer_3d = ma.masked_where(mask_3d == 0, layer_3d_tmp)

    #simple index array
    idx_4d = np.indices(shape(layer_3d), int)

    #extract values along this line (from stackoverflow)
    #make a line with num points
    num = int(sqrt(square(i_max - i_min) + square(j_max - j_min))) + 1
    x, y = np.linspace(i_min, i_max, num), np.linspace(j_min, j_max, num)

    #extract values of 3d arrays along this line
    z_2d = z_3d[:, y.astype(np.int), x.astype(np.int)]
    idx_3d = idx_4d[:, :, y.astype(np.int), x.astype(np.int)]
    layer_2d = layer_3d[:, y.astype(np.int), x.astype(np.int)]

    #convert index value to distance
    dist_2d = sqrt(square(idx_3d[1]) + square(idx_3d[2])) * 10.0

    #contour levels
    lev = range(1, N)

    #Plot
    fig = figure(figsize=(18, 6))
    contour(dist_2d, z_2d, layer_2d, lev, colors='k')
    title(
        "ROMS Vertical coordinates along the line from \n [i_min, j_min] = " +
        str([i_min, j_min]) + "  to   [i_max, j_max] = " + str([i_max, j_max]),
        fontsize=24)
    xlabel('Distance (km)')
    ylabel('Depth (m)')
    ylim([depth_min, depth_max])
    fig.show()
예제 #5
0
def calc_rx1(grid_path, theta_s, theta_b, hc, N, Vstretching, out_file):

    # Read grid
    id = Dataset(grid_path, 'r')
    lon_2d = id.variables['lon_rho'][:, :]
    lat_2d = id.variables['lat_rho'][:, :]
    h = id.variables['h'][:, :]
    zice = id.variables['zice'][:, :]
    mask_rho = id.variables['mask_rho'][:, :]
    id.close()

    # Calculate 3D field of depth values
    z, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, None, Vstretching)
    # Mask out land
    for k in range(N):
        tmp = z[k, :, :]
        tmp[mask_rho == 0] = NaN
        z[k, :, :] = tmp

    # Calculate rx1 in each dimension
    rx1_3d_i = abs(
        (z[1:, 1:, 1:] - z[1:, 1:, :-1] + z[:-1, 1:, 1:] - z[:-1, 1:, :-1]) /
        (z[1:, 1:, 1:] + z[1:, 1:, :-1] - z[:-1, 1:, 1:] - z[:-1, 1:, :-1]))
    rx1_3d_j = abs(
        (z[1:, 1:, 1:] - z[1:, :-1, 1:] + z[:-1, 1:, 1:] - z[:-1, :-1, 1:]) /
        (z[1:, 1:, 1:] + z[1:, :-1, 1:] - z[:-1, 1:, 1:] - z[:-1, :-1, 1:]))
    # Save the larger of the two
    rx1_3d = maximum(rx1_3d_i, rx1_3d_j)
    # Take maximum along depth to get a 2D field
    rx1_tmp = amax(rx1_3d, axis=0)

    # This only worked for interior points; copy the boundary in each dimesion
    rx1 = zeros(shape(lon_2d))
    rx1[1:, 1:] = rx1_tmp
    rx1[0, :] = rx1[1, :]
    rx1[:, 0] = rx1[:, 1]
    # Mask out NaNs
    rx1 = ma.masked_where(isnan(rx1), rx1)

    # Write output file
    id = Dataset(out_file, 'w')
    id.createDimension('xi_rho', size(lon_2d, 1))
    id.createDimension('eta_rho', size(lon_2d, 0))
    id.createVariable('rx1', 'f8', ('eta_rho', 'xi_rho'))
    id.variables['rx1'][:, :] = rx1
    id.close()
예제 #6
0
def calc_rx1 (grid_path, theta_s, theta_b, hc, N, Vstretching, out_file):

    # read grid variables
    id = Dataset(grid_path, 'r')
    lon_2d = id.variables['lon_rho'][:,:]
    lat_2d = id.variables['lat_rho'][:,:]
    h = id.variables['h'][:,:]
    zice = id.variables['zice'][:,:]
    mask_rho = id.variables['mask_rho'][:,:]
    id.close()

    # calculate s-level depth and stretching curves
    z, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, None, Vstretching)
    for k in range(N):
        tmp = z[k,:,:]
        tmp[mask_rho==0] = NaN
        z[k,:,:] = tmp

    # calculate rx1
    rx1_3d_i = abs((z[1:,1:,1:]-z[1:,1:,:-1]+z[:-1,1:,1:]-z[:-1,1:,:-1])/(z[1:,1:,1:]+z[1:,1:,:-1]-z[:-1,1:,1:]-z[:-1,1:,:-1]))
    rx1_3d_j = abs((z[1:,1:,1:]-z[1:,:-1,1:]+z[:-1,1:,1:]-z[:-1,:-1,1:])/(z[1:,1:,1:]+z[1:,:-1,1:]-z[:-1,1:,1:]-z[:-1,:-1,1:]))
    rx1_3d = maximum(rx1_3d_i, rx1_3d_j)
    rx1_tmp = amax(rx1_3d, axis=0)

    rx1 = zeros(shape(lon_2d))
    rx1[1:,1:] = rx1_tmp
    rx1[0,:] = rx1[1,:]
    rx1[:,0] = rx1[:,1]
    rx1 = ma.masked_where(isnan(rx1), rx1)

    # save as netcdf
    id = Dataset(out_file, 'w')
    id.createDimension('xi_rho', size(lon_2d,1))
    id.createDimension('eta_rho', size(lon_2d,0))
    id.createVariable('rx1', 'f8', ('eta_rho', 'xi_rho'))
    id.variables['rx1'][:,:] = rx1
    id.close()
예제 #7
0
def mip_zonal_cavity_ts (roms_grid, roms_file, fesom_mesh_path_lr, fesom_file_lr, fesom_mesh_path_hr, fesom_file_hr):

    # Name of each ice shelf
    shelf_names = ['Larsen D Ice Shelf', 'Larsen C Ice Shelf', 'Wilkins & George VI & Stange Ice Shelves', 'Ronne-Filchner Ice Shelf', 'Abbot Ice Shelf', 'Pine Island Glacier Ice Shelf', 'Thwaites Ice Shelf', 'Dotson Ice Shelf', 'Getz Ice Shelf', 'Nickerson Ice Shelf', 'Sulzberger Ice Shelf', 'Mertz Ice Shelf', 'Totten & Moscow University Ice Shelves', 'Shackleton Ice Shelf', 'West Ice Shelf', 'Amery Ice Shelf', 'Prince Harald Ice Shelf', 'Baudouin & Borchgrevink Ice Shelves', 'Lazarev Ice Shelf', 'Nivl Ice Shelf', 'Fimbul & Jelbart & Ekstrom Ice Shelves', 'Brunt & Riiser-Larsen Ice Shelves', 'Ross Ice Shelf']
    # Beginnings of filenames for figures
    fig_heads = ['larsen_d', 'larsen_c', 'wilkins_georgevi_stange', 'ronne_filchner', 'abbot', 'pig', 'thwaites', 'dotson', 'getz', 'nickerson', 'sulzberger', 'mertz', 'totten_moscowuni', 'shackleton', 'west', 'amery', 'prince_harald', 'baudouin_borchgrevink', 'lazarev', 'nivl', 'fimbul_jelbart_ekstrom', 'brunt_riiser_larsen', 'ross']
    # Longitudes intersecting each ice shelf
    lon0 = [-60, -62, -68, -55, -93, -101, -106, -113, -120, -145, -150, 145, 116, 96, 85, 71, 36, 25, 15, 11, -1, -20, 180]
    # Latitude bounds for each ice shelf
    lat_min = [-73.1, -69.35, -73.1, -82.6, -73.28, -75.4, -75.5, -75, -74.9, -75.9, -77.8, -67.7, -67.17, -66.67, -67.25, -72, -69.7, -71, -70.4, -70.75, -71.83, -75.6, -84.6]
    lat_max = [-72, -66.13, -70, -75.5, -72.3, -74.4, -74.67, -74, -73.5, -75.3, -76.41, -67, -66.5, -64.83, -66.25, -68.5, -68.7, -69.9, -69.33, -69.83, -69.33, -72.9, -77]
    num_shelves = len(shelf_names)
    # ROMS grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31

    print 'Setting up ROMS'
    # Start with grid
    id = Dataset(roms_grid, 'r')
    h = id.variables['h'][:,:]
    zice = id.variables['zice'][:,:]
    lon_2d = id.variables['lon_rho'][:,:]
    lat_2d = id.variables['lat_rho'][:,:]
    id.close()
    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Read temperature and salinity
    id = Dataset(roms_file, 'r')
    roms_temp_3d = id.variables['temp'][0,:,:,:]
    roms_salt_3d = id.variables['salt'][0,:,:,:]
    id.close()

    print 'Setting up low-res FESOM'
    # Build the regular FESOM grid
    elm2D_lr = fesom_grid(fesom_mesh_path_lr)
    # Read temperature and salinity at every node
    id = Dataset(fesom_file_lr, 'r')
    fesom_temp_nodes_lr = id.variables['temp'][0,:]
    fesom_salt_nodes_lr = id.variables['salt'][0,:]
    id.close()

    print 'Setting up high-res FESOM'
    elm2D_hr = fesom_grid(fesom_mesh_path_hr)
    id = Dataset(fesom_file_hr, 'r')
    fesom_temp_nodes_hr = id.variables['temp'][0,:]
    fesom_salt_nodes_hr = id.variables['salt'][0,:]
    id.close()

    # Loop over ice shelves
    for index in range(num_shelves):
        print 'Processing ' + shelf_names[index]
        # Figure out what to write on the title about longitude
        if lon0[index] < 0:
            lon_string = ' ('+str(-lon0[index])+r'$^{\circ}$W)'
        else:
            lon_string = ' ('+str(lon0[index])+r'$^{\circ}$E)'

        # MetROMS
        # Make sure longitude is between 0 and 360
        roms_lon0 = lon0[index]
        if roms_lon0 < 0:
            roms_lon0 += 360
        # Interpolate to given longitude
        roms_temp, roms_z, roms_lat = interp_lon_roms(roms_temp_3d, z_3d, lat_2d, lon_2d, roms_lon0)
        roms_salt, roms_z, roms_lat = interp_lon_roms(roms_salt_3d, z_3d, lat_2d, lon_2d, roms_lon0)
        # Figure out deepest depth
        flag = (roms_lat >= lat_min[index])*(roms_lat <= lat_max[index])
        depth_min_tmp = amin(roms_z[flag])
        # Round down to nearest 50 metres
        depth_min = floor(depth_min_tmp/50)*50

        # FESOM low-res
        # Build arrays of SideElements making up zonal slices
        selements_temp_lr = fesom_sidegrid(elm2D_lr, fesom_temp_nodes_lr, lon0[index], lat_max[index])
        selements_salt_lr = fesom_sidegrid(elm2D_lr, fesom_salt_nodes_lr, lon0[index], lat_max[index])
        # Build array of quadrilateral patches for the plots, and data values
        # corresponding to each SideElement
        patches_lr = []
        fesom_temp_lr = []
        for selm in selements_temp_lr:
            # Make patch
            coord = transpose(vstack((selm.y, selm.z)))
            patches_lr.append(Polygon(coord, True, linewidth=0.))
            # Save data value
            fesom_temp_lr.append(selm.var)
        fesom_temp_lr = array(fesom_temp_lr)
        # Salinity has same patches but different values
        fesom_salt_lr = []
        for selm in selements_salt_lr:
            fesom_salt_lr.append(selm.var)
        fesom_salt_lr = array(fesom_salt_lr)

        # FESOM high-res
        selements_temp_hr = fesom_sidegrid(elm2D_hr, fesom_temp_nodes_hr, lon0[index], lat_max[index])
        selements_salt_hr = fesom_sidegrid(elm2D_hr, fesom_salt_nodes_hr, lon0[index], lat_max[index])
        patches_hr = []
        fesom_temp_hr = []
        for selm in selements_temp_hr:
            coord = transpose(vstack((selm.y, selm.z)))
            patches_hr.append(Polygon(coord, True, linewidth=0.))
            fesom_temp_hr.append(selm.var)
        fesom_temp_hr = array(fesom_temp_hr)
        fesom_salt_hr = []
        for selm in selements_salt_hr:
            fesom_salt_hr.append(selm.var)
        fesom_salt_hr = array(fesom_salt_hr)

        # Find bounds on each variable
        temp_min = amin(array([amin(roms_temp[flag]), amin(fesom_temp_lr), amin(fesom_temp_hr)]))
        temp_max = amax(array([amax(roms_temp[flag]), amax(fesom_temp_lr), amax(fesom_temp_hr)]))
        salt_min = amin(array([amin(roms_salt[flag]), amin(fesom_salt_lr), amin(fesom_salt_hr)]))
        salt_max = amax(array([amax(roms_salt[flag]), amax(fesom_salt_lr), amax(fesom_salt_hr)]))
        # Plot
        fig = figure(figsize=(24,12))
        # MetROMS temperature
        ax = fig.add_subplot(2, 3, 1)
        pcolor(roms_lat, roms_z, roms_temp, vmin=temp_min, vmax=temp_max, cmap='jet')
        title(r'MetROMS temperature ($^{\circ}$C)', fontsize=20)
        ylabel('Depth (m)', fontsize=16)
        xlim([lat_min[index], lat_max[index]])
        ylim([depth_min, 0])
        # FESOM low-res temperature
        ax = fig.add_subplot(2, 3, 2)
        img = PatchCollection(patches_lr, cmap='jet')
        img.set_array(fesom_temp_lr)
        img.set_edgecolor('face')
        img.set_clim(vmin=temp_min, vmax=temp_max)
        ax.add_collection(img)
        title(r'FESOM (low-res) temperature ($^{\circ}$C)', fontsize=20)
        xlim([lat_min[index], lat_max[index]])
        ylim([depth_min, 0])
        # FESOM high-res temperature
        ax = fig.add_subplot(2, 3, 3)
        img = PatchCollection(patches_hr, cmap='jet')
        img.set_array(fesom_temp_hr)
        img.set_edgecolor('face')
        img.set_clim(vmin=temp_min, vmax=temp_max)
        ax.add_collection(img)
        title(r'FESOM (high-res) temperature ($^{\circ}$C)', fontsize=20)
        xlim([lat_min[index], lat_max[index]])
        ylim([depth_min, 0])
        # Add colorbar for temperature
        cbaxes = fig.add_axes([0.92, 0.575, 0.01, 0.3])
        cbar = colorbar(img, cax=cbaxes)
        cbar.ax.tick_params(labelsize=16)
        # MetROMS salinity
        ax = fig.add_subplot(2, 3, 4)
        pcolor(roms_lat, roms_z, roms_salt, vmin=salt_min, vmax=salt_max, cmap='jet')
        title('MetROMS salinity (psu)', fontsize=20)    
        xlabel('Latitude', fontsize=16)
        ylabel('Depth (m)', fontsize=16)
        xlim([lat_min[index], lat_max[index]])
        ylim([depth_min, 0])
        # FESOM low-res salinity
        ax = fig.add_subplot(2, 3, 5)
        img = PatchCollection(patches_lr, cmap='jet')
        img.set_array(fesom_salt_lr)
        img.set_edgecolor('face') 
        img.set_clim(vmin=salt_min, vmax=salt_max)
        ax.add_collection(img)
        title(r'FESOM (low-res) salinity (psu)', fontsize=20)
        xlabel('Latitude', fontsize=16)
        xlim([lat_min[index], lat_max[index]])
        ylim([depth_min, 0])
        # FESOM high-res salinity
        ax = fig.add_subplot(2, 3, 6)
        img = PatchCollection(patches_hr, cmap='jet')
        img.set_array(fesom_salt_hr)
        img.set_edgecolor('face') 
        img.set_clim(vmin=salt_min, vmax=salt_max)
        ax.add_collection(img)
        title(r'FESOM (high-res) salinity (psu)', fontsize=20)
        xlabel('Latitude', fontsize=16)
        xlim([lat_min[index], lat_max[index]])
        ylim([depth_min, 0])
        # Add colorbar for salinity
        cbaxes = fig.add_axes([0.92, 0.125, 0.01, 0.3])
        cbar = colorbar(img, cax=cbaxes)
        cbar.ax.tick_params(labelsize=16)
        # Main title
        suptitle(shelf_names[index] + lon_string, fontsize=28)
        #fig.show()
        fig.savefig(fig_heads[index] + '_zonal_ts.png')
예제 #8
0
def mip_drift_slices(roms_grid, roms_file, fesom_mesh_path_lr, fesom_file_lr,
                     fesom_mesh_path_hr, fesom_file_hr):

    # Paths to ECCO2 files with initial conditions for temp and salt
    ecco_temp_file = '/short/m68/kaa561/metroms_iceshelf/data/originals/ECCO2/THETA.1440x720x50.199201.nc'
    ecco_salt_file = '/short/m68/kaa561/metroms_iceshelf/data/originals/ECCO2/SALT.1440x720x50.199201.nc'
    # Longitude to interpolate to (OE)
    lon0 = 0
    # Bounds on plot
    lat_min = -73
    lat_max = -30
    depth_min = -6000
    depth_max = 0
    # ROMS grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31
    # Bounds on colour scales for temperature and salinity
    temp_min = -2
    temp_max = 6
    salt_min = 33.9
    salt_max = 34.9
    # Contours to overlay
    temp_contour = 0.75
    salt_contour = 34.5
    # Parameters for FESOM regular grid interpolation (needed for contours)
    num_lat = 500
    num_depth = 250

    # Get longitude for the title
    if lon0 < 0:
        lon_string = str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = str(int(round(lon0))) + r'$^{\circ}$E'

    print 'Processing ECCO2'
    id = Dataset(ecco_temp_file, 'r')
    # Read grid variables
    ecco_lat = id.variables['LATITUDE_T'][:]
    ecco_depth = -1 * id.variables['DEPTH_T'][:]
    if lon0 == 0:
        # Hard-coded lon0 = 0E: average between the first (0.125 E) and last
        # (359.875 E = -0.125 W) indices in the regular ECCO2 grid
        ecco_temp = 0.5 * (id.variables['THETA'][0, :, :, 0] +
                           id.variables['THETA'][0, :, :, -1])
        id.close()
        id = Dataset(ecco_salt_file, 'r')
        ecco_salt = 0.5 * (id.variables['SALT'][0, :, :, 0] +
                           id.variables['SALT'][0, :, :, -1])
        id.close()
    else:
        print 'lon0 is only coded for 0E at this time'
        #return

    print 'Processing ROMS'
    # Read grid variables we need
    id = Dataset(roms_grid, 'r')
    roms_lon_2d = id.variables['lon_rho'][:, :]
    roms_lat_2d = id.variables['lat_rho'][:, :]
    roms_h = id.variables['h'][:, :]
    roms_zice = id.variables['zice'][:, :]
    id.close()
    # Read temperature and salinity
    id = Dataset(roms_file, 'r')
    roms_temp_3d = id.variables['temp'][0, :, :, :]
    roms_salt_3d = id.variables['salt'][0, :, :, :]
    id.close()
    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    roms_z_3d, sc_r, Cs_r = calc_z(roms_h, roms_zice, theta_s, theta_b, hc, N)
    # Make sure we are in the range 0-360
    if lon0 < 0:
        lon0 += 360
    # Interpolate to lon0
    roms_temp, roms_z, roms_lat = interp_lon_roms(roms_temp_3d, roms_z_3d,
                                                  roms_lat_2d, roms_lon_2d,
                                                  lon0)
    roms_salt, roms_z, roms_lat = interp_lon_roms(roms_salt_3d, roms_z_3d,
                                                  roms_lat_2d, roms_lon_2d,
                                                  lon0)
    # Switch back to range -180-180
    if lon0 > 180:
        lon0 -= 360

    print 'Processing low-res FESOM'
    # Build regular elements
    elements_lr = fesom_grid(fesom_mesh_path_lr)
    # Read temperature and salinity
    id = Dataset(fesom_file_lr, 'r')
    fesom_temp_nodes_lr = id.variables['temp'][0, :]
    fesom_salt_nodes_lr = id.variables['salt'][0, :]
    id.close()
    # Make SideElements
    selements_temp_lr = fesom_sidegrid(elements_lr, fesom_temp_nodes_lr, lon0,
                                       lat_max)
    selements_salt_lr = fesom_sidegrid(elements_lr, fesom_salt_nodes_lr, lon0,
                                       lat_max)
    # Build an array of quadrilateral patches for the plot, and of data values
    # corresponding to each SideElement
    patches_lr = []
    fesom_temp_lr = []
    for selm in selements_temp_lr:
        # Make patch
        coord = transpose(vstack((selm.y, selm.z)))
        patches_lr.append(Polygon(coord, True, linewidth=0.))
        # Save data value
        fesom_temp_lr.append(selm.var)
    # Repeat for salinity
    fesom_salt_lr = []
    for selm in selements_salt_lr:
        fesom_salt_lr.append(selm.var)
    # Interpolate to regular grid so we can overlay contours
    lat_reg = linspace(lat_min, lat_max, num_lat)
    depth_reg = linspace(-depth_max, -depth_min, num_depth)
    temp_reg_lr = zeros([num_depth, num_lat])
    salt_reg_lr = zeros([num_depth, num_lat])
    temp_reg_lr[:, :] = NaN
    salt_reg_lr[:, :] = NaN
    # For each element, check if a point on the regular grid lies
    # within. If so, do barycentric interpolation to that point, at each
    # depth on the regular grid.
    for elm in elements_lr:
        # Check if this element crosses lon0
        if amin(elm.lon) < lon0 and amax(elm.lon) > lon0:
            # Check if we are within the latitude bounds
            if amax(elm.lat) > lat_min and amin(elm.lat) < lat_max:
                # Find largest regular latitude value south of Element
                tmp = nonzero(lat_reg > amin(elm.lat))[0]
                if len(tmp) == 0:
                    # Element crosses the southern boundary
                    jS = 0
                else:
                    jS = tmp[0] - 1
                # Find smallest regular latitude north of Element
                tmp = nonzero(lat_reg > amax(elm.lat))[0]
                if len(tmp) == 0:
                    # Element crosses the northern boundary
                    jN = num_lat
                else:
                    jN = tmp[0]
                for j in range(jS + 1, jN):
                    # There is a chance that the regular gridpoint at j
                    # lies within this element
                    lat0 = lat_reg[j]
                    if in_triangle(elm, lon0, lat0):
                        # Yes it does
                        # Get area of entire triangle
                        area = triangle_area(elm.lon, elm.lat)
                        # Get area of each sub-triangle formed by (lon0, lat0)
                        area0 = triangle_area([lon0, elm.lon[1], elm.lon[2]],
                                              [lat0, elm.lat[1], elm.lat[2]])
                        area1 = triangle_area([lon0, elm.lon[0], elm.lon[2]],
                                              [lat0, elm.lat[0], elm.lat[2]])
                        area2 = triangle_area([lon0, elm.lon[0], elm.lon[1]],
                                              [lat0, elm.lat[0], elm.lat[1]])
                        # Find fractional area of each
                        cff = [area0 / area, area1 / area, area2 / area]
                        # Interpolate each depth value
                        for k in range(num_depth):
                            # Linear interpolation in the vertical for the
                            # value at each corner of the triangle
                            node_vals_temp = []
                            node_vals_salt = []
                            for n in range(3):
                                id1, id2, coeff1, coeff2 = elm.nodes[
                                    n].find_depth(depth_reg[k])
                                if any(isnan(array([id1, id2, coeff1,
                                                    coeff2]))):
                                    # No ocean data here (seafloor or ice shelf)
                                    node_vals_temp.append(NaN)
                                    node_vals_salt.append(NaN)
                                else:
                                    node_vals_temp.append(
                                        coeff1 * fesom_temp_nodes_lr[id1] +
                                        coeff2 * fesom_temp_nodes_lr[id2])
                                    node_vals_salt.append(
                                        coeff1 * fesom_salt_nodes_lr[id1] +
                                        coeff2 * fesom_salt_nodes_lr[id2])
                            if any(isnan(node_vals_temp)):
                                pass
                            else:
                                # Barycentric interpolation for the value at
                                # lon0, lat0
                                temp_reg_lr[k, j] = sum(
                                    array(cff) * array(node_vals_temp))
                                salt_reg_lr[k, j] = sum(
                                    array(cff) * array(node_vals_salt))
    temp_reg_lr = ma.masked_where(isnan(temp_reg_lr), temp_reg_lr)
    salt_reg_lr = ma.masked_where(isnan(salt_reg_lr), salt_reg_lr)

    print 'Processing high-res FESOM'
    elements_hr = fesom_grid(fesom_mesh_path_hr)
    id = Dataset(fesom_file_hr, 'r')
    fesom_temp_nodes_hr = id.variables['temp'][0, :]
    fesom_salt_nodes_hr = id.variables['salt'][0, :]
    id.close()
    selements_temp_hr = fesom_sidegrid(elements_hr, fesom_temp_nodes_hr, lon0,
                                       lat_max)
    selements_salt_hr = fesom_sidegrid(elements_hr, fesom_salt_nodes_hr, lon0,
                                       lat_max)
    patches_hr = []
    fesom_temp_hr = []
    for selm in selements_temp_hr:
        coord = transpose(vstack((selm.y, selm.z)))
        patches_hr.append(Polygon(coord, True, linewidth=0.))
        fesom_temp_hr.append(selm.var)
    fesom_salt_hr = []
    for selm in selements_salt_hr:
        fesom_salt_hr.append(selm.var)
    lat_reg = linspace(lat_min, lat_max, num_lat)
    temp_reg_hr = zeros([num_depth, num_lat])
    salt_reg_hr = zeros([num_depth, num_lat])
    temp_reg_hr[:, :] = NaN
    salt_reg_hr[:, :] = NaN
    for elm in elements_hr:
        if amin(elm.lon) < lon0 and amax(elm.lon) > lon0:
            if amax(elm.lat) > lat_min and amin(elm.lat) < lat_max:
                tmp = nonzero(lat_reg > amin(elm.lat))[0]
                if len(tmp) == 0:
                    jS = 0
                else:
                    jS = tmp[0] - 1
                tmp = nonzero(lat_reg > amax(elm.lat))[0]
                if len(tmp) == 0:
                    jN = num_lat
                else:
                    jN = tmp[0]
                for j in range(jS + 1, jN):
                    lat0 = lat_reg[j]
                    if in_triangle(elm, lon0, lat0):
                        area = triangle_area(elm.lon, elm.lat)
                        area0 = triangle_area([lon0, elm.lon[1], elm.lon[2]],
                                              [lat0, elm.lat[1], elm.lat[2]])
                        area1 = triangle_area([lon0, elm.lon[0], elm.lon[2]],
                                              [lat0, elm.lat[0], elm.lat[2]])
                        area2 = triangle_area([lon0, elm.lon[0], elm.lon[1]],
                                              [lat0, elm.lat[0], elm.lat[1]])
                        cff = [area0 / area, area1 / area, area2 / area]
                        for k in range(num_depth):
                            node_vals_temp = []
                            node_vals_salt = []
                            for n in range(3):
                                id1, id2, coeff1, coeff2 = elm.nodes[
                                    n].find_depth(depth_reg[k])
                                if any(isnan(array([id1, id2, coeff1,
                                                    coeff2]))):
                                    node_vals_temp.append(NaN)
                                    node_vals_salt.append(NaN)
                                else:
                                    node_vals_temp.append(
                                        coeff1 * fesom_temp_nodes_hr[id1] +
                                        coeff2 * fesom_temp_nodes_hr[id2])
                                    node_vals_salt.append(
                                        coeff1 * fesom_salt_nodes_hr[id1] +
                                        coeff2 * fesom_salt_nodes_hr[id2])
                            if any(isnan(node_vals_temp)):
                                pass
                            else:
                                temp_reg_hr[k, j] = sum(
                                    array(cff) * array(node_vals_temp))
                                salt_reg_hr[k, j] = sum(
                                    array(cff) * array(node_vals_salt))
    temp_reg_hr = ma.masked_where(isnan(temp_reg_hr), temp_reg_hr)
    salt_reg_hr = ma.masked_where(isnan(salt_reg_hr), salt_reg_hr)

    depth_reg = -1 * depth_reg

    # Set up axis labels the way we want them
    lat_ticks = arange(lat_min + 3, lat_max + 10, 10)
    lat_labels = []
    for val in lat_ticks:
        lat_labels.append(str(int(round(-val))) + r'$^{\circ}$S')
    depth_ticks = range(depth_min + 1000, 0 + 1000, 1000)
    depth_labels = []
    for val in depth_ticks:
        depth_labels.append(str(int(round(-val))))

    print 'Plotting'
    fig = figure(figsize=(14, 24))
    # ECCO2
    gs1 = GridSpec(1, 2)
    gs1.update(left=0.1, right=0.95, bottom=0.7575, top=0.94, wspace=0.08)
    # Temperature
    ax = subplot(gs1[0, 0])
    pcolor(ecco_lat,
           ecco_depth,
           ecco_temp,
           vmin=temp_min,
           vmax=temp_max,
           cmap='jet')
    # Overlay contour
    contour(ecco_lat,
            ecco_depth,
            ecco_temp,
            levels=[temp_contour],
            color='black')
    title(r'Temperature ($^{\circ}$C)', fontsize=24)
    ylabel('Depth (m)', fontsize=18)
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels(depth_labels, fontsize=16)
    text(-64,
         1000,
         'a) ECCO2 initial conditions at ' + lon_string + ', January 1992',
         fontsize=28)
    # Salinity
    ax = subplot(gs1[0, 1])
    pcolor(ecco_lat,
           ecco_depth,
           ecco_salt,
           vmin=salt_min,
           vmax=salt_max,
           cmap='jet')
    contour(ecco_lat,
            ecco_depth,
            ecco_salt,
            levels=[salt_contour],
            color='black')
    title('Salinity (psu)', fontsize=24)
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels([])
    # MetROMS
    gs2 = GridSpec(1, 2)
    gs2.update(left=0.1, right=0.95, bottom=0.525, top=0.7075, wspace=0.08)
    # Temperature
    ax = subplot(gs2[0, 0])
    pcolor(roms_lat,
           roms_z,
           roms_temp,
           vmin=temp_min,
           vmax=temp_max,
           cmap='jet')
    contour(roms_lat, roms_z, roms_temp, levels=[temp_contour], color='black')
    ylabel('Depth (m)', fontsize=18)
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels(depth_labels, fontsize=16)
    text(-49, 300, 'b) MetROMS, January 2016', fontsize=28)
    # Salinity
    ax = subplot(gs2[0, 1])
    pcolor(roms_lat,
           roms_z,
           roms_salt,
           vmin=salt_min,
           vmax=salt_max,
           cmap='jet')
    contour(roms_lat, roms_z, roms_salt, levels=[salt_contour], color='black')
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels([])
    # FESOM low-res
    gs3 = GridSpec(1, 2)
    gs3.update(left=0.1, right=0.95, bottom=0.2925, top=0.475, wspace=0.08)
    # Temperature
    ax = subplot(gs3[0, 0])
    img = PatchCollection(patches_lr, cmap='jet')
    img.set_array(array(fesom_temp_lr))
    img.set_edgecolor('face')
    img.set_clim(vmin=temp_min, vmax=temp_max)
    ax.add_collection(img)
    # Overlay contour on regular grid
    contour(lat_reg,
            depth_reg,
            temp_reg_lr,
            levels=[temp_contour],
            color='black')
    ylabel('Depth (m)', fontsize=18)
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels(depth_labels, fontsize=16)
    text(-53, 300, 'c) FESOM (low-res), January 2016', fontsize=28)
    # Salinity
    ax = subplot(gs3[0, 1])
    img = PatchCollection(patches_lr, cmap='jet')
    img.set_array(array(fesom_salt_lr))
    img.set_edgecolor('face')
    img.set_clim(vmin=salt_min, vmax=salt_max)
    ax.add_collection(img)
    contour(lat_reg,
            depth_reg,
            salt_reg_lr,
            levels=[salt_contour],
            color='black')
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels([])
    # FESOM high-res
    gs4 = GridSpec(1, 2)
    gs4.update(left=0.1, right=0.95, bottom=0.06, top=0.2425, wspace=0.08)
    # Temperature
    ax = subplot(gs4[0, 0])
    img = PatchCollection(patches_hr, cmap='jet')
    img.set_array(array(fesom_temp_hr))
    img.set_edgecolor('face')
    img.set_clim(vmin=temp_min, vmax=temp_max)
    ax.add_collection(img)
    contour(lat_reg,
            depth_reg,
            temp_reg_hr,
            levels=[temp_contour],
            color='black')
    ylabel('Depth (m)', fontsize=18)
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels(depth_labels, fontsize=16)
    text(-53, 300, 'd) FESOM (high-res), January 2016', fontsize=28)
    # Add a colorbar for temperature
    cbaxes = fig.add_axes([0.17, 0.015, 0.3, 0.015])
    cbar = colorbar(img,
                    orientation='horizontal',
                    cax=cbaxes,
                    extend='both',
                    ticks=arange(temp_min, temp_max + 2, 2))
    cbar.ax.tick_params(labelsize=16)
    # Salinity
    ax = subplot(gs4[0, 1])
    img = PatchCollection(patches_hr, cmap='jet')
    img.set_array(array(fesom_salt_hr))
    img.set_edgecolor('face')
    img.set_clim(vmin=salt_min, vmax=salt_max)
    ax.add_collection(img)
    contour(lat_reg,
            depth_reg,
            salt_reg_hr,
            levels=[salt_contour],
            color='black')
    xlim([lat_min, lat_max])
    ylim([depth_min, depth_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels([])
    # Add a colorbar for salinity
    cbaxes = fig.add_axes([0.6, 0.015, 0.3, 0.02])
    cbar = colorbar(img,
                    orientation='horizontal',
                    cax=cbaxes,
                    extend='both',
                    ticks=arange(salt_min + 0.1, salt_max + 0.1, 0.2))
    cbar.ax.tick_params(labelsize=16)
    fig.show()
    fig.savefig('ts_drift.png')
예제 #9
0
def adv_amery_tsplots ():

    num_simulations = 6
    # Paths to simulation directories
    paths = ['/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/c4_lowdif/', '/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/c4_highdif/', '/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/a4_lowdif/', '/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/a4_highdif/', '/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/u3_lowdif/', '/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/u3_highdif/']
    # End of figure names for each simulation
    labels = ['_c4_lowdif.png', '_c4_highdif.png', '_a4_lowdif.png', '_a4_highdif.png', '_u3_lowdif.png', '_u3_highdif.png']
    # Name of ocean output file to read
    ocn_file = 'ocean_avg_0001.nc'
    # Timestep to plot (average over last day in 1992)
    tstep = 366
    # Longitude to plot
    lon0 = 71
    # Deepest depth to plot
    depth_min = -500
    # Bounds on colour scale for each variable
    temp_bounds = [-2, 3]
    salt_bounds = [33.8, 34.8]
    # Bounds on latitudes to plot
    lat_min = -72
    lat_max = -50

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Build titles for each variable based on longitude
    if lon0 < 0:
        temp_title = r'Temperature ($^{\circ}$C) at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
        salt_title = r'Salinity (psu) at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
        # Edit longitude to be between0 and 360, following ROMS convention
        lon0 += 360
    else:
        temp_title = r'Temperature ($^{\circ}$C) at ' + str(int(round(lon0))) + r'$^{\circ}$E'
        salt_title = r'Salinity (psu) at ' + str(int(round(lon0))) + r'$^{\circ}$E'

    # Loop over simulations
    for sim in range(num_simulations):
        # Loop over variables
        for var_name in ['temp', 'salt']:
            # Read variable, sea surface height, and grid variables
            id = Dataset(paths[sim] + ocn_file, 'r')
            data_3d = id.variables[var_name][tstep-1,:,:-15,:]
            zeta = id.variables['zeta'][tstep-1,:-15,:]
            if sim == 0 and var_name == 'temp':
                # Grid variables are the same for all simulations so we
                # only need to read them once
                h = id.variables['h'][:-15,:]
                zice = id.variables['zice'][:-15,:]
                lon_2d = id.variables['lon_rho'][:-15,:]
                lat_2d = id.variables['lat_rho'][:-15,:]
            id.close()
            # Get a 3D array of z-coordinates
            z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
            # Interpolate the variable, z, and latitude to lon0
            data, z, lat = interp_lon(data_3d, z_3d, lat_2d, lon_2d, lon0)
            # Set up colour levels for plotting
            if var_name == 'temp':
                lev = linspace(temp_bounds[0], temp_bounds[1], num=40)
            elif var_name == 'salt':
                lev = linspace(salt_bounds[0], salt_bounds[1], num=40)
            # Plot
            fig = figure(figsize=(12,6))
            contourf(lat, z, data, lev, cmap='jet', extend='both')
            colorbar()
            if var_name == 'temp':
                title(temp_title)
            elif var_name == 'salt':
                title(salt_title)
            xlabel('Latitude')
            ylabel('Depth (m)')
            xlim([lat_min, lat_max])
            ylim([depth_min, 0])
            # Save plot
            fig.savefig(var_name + labels[sim])
예제 #10
0
def convert_file (year):

    # Make sure input argument is an integer (sometimes the batch script likes
    # to pass it as a string)
    year = int(year)

    # Paths of ROMS grid file, input ECCO2 files (without the tail yyyymm.nc),
    # and output ROMS-CICE boundary condition file; other users will need to
    # change these
    grid_file = '../ROMS-CICE-MCT/apps/common/grid/circ30S_quarterdegree_good.nc'
    theta_base = '../ROMS-CICE-MCT/data/ECCO2/raw/THETA.1440x720x50.' + str(year)
    salt_base = '../ROMS-CICE-MCT/data/ECCO2/raw/SALT.1440x720x50.' + str(year)
    vvel_base = '../ROMS-CICE-MCT/data/ECCO2/raw/VVEL.1440x720x50.' + str(year)
    output_file = '../ROMS-CICE-MCT/data/ECCO2/ecco2_cube92_lbc_' + str(year) + '.nc'

    # Grid parameters; check grid_file and *.in to make sure these are correct
    Tcline = 40
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31
    # Northernmost index of ECCO2 grid to read (1-based)
    nbdry_ecco = 241

    # Read ECCO2 grid
    print 'Reading ECCO2 grid'
    ecco_fid = Dataset(theta_base + '01.nc', 'r')
    lon_ecco_raw = ecco_fid.variables['LONGITUDE_T'][:]
    lat_ecco = ecco_fid.variables['LATITUDE_T'][0:nbdry_ecco]
    depth_ecco_raw = ecco_fid.variables['DEPTH_T'][:]
    ecco_fid.close()

    # The ECCO2 longitude axis doesn't wrap around; there is a gap between
    # almost-180W and almost-180E, and the ROMS grid has points in this gap.
    # So copy the last longitude value (mod 360) to the beginning, and the
    # first longitude value (mod 360) to the end.
    lon_ecco = zeros(size(lon_ecco_raw)+2)
    lon_ecco[0] = lon_ecco_raw[-1]-360
    lon_ecco[1:-1] = lon_ecco_raw
    lon_ecco[-1] = lon_ecco_raw[0]+360

    # The shallowest ECCO2 depth value is 5 m, but ROMS needs 0 m. So add the
    # index depth = 0 m to the beginning. Later we will just copy the 5 m
    # values for theta and salt into this index. Similarly, the deepest ECCO2
    # depth value is not deep enough for ROMS, so make a 6000 m index at the end.
    depth_ecco = zeros(size(depth_ecco_raw)+2)
    depth_ecco[0] = 0.0
    depth_ecco[1:-1] = depth_ecco_raw
    depth_ecco[-1] = 6000.0

    # Read ROMS grid
    print 'Reading ROMS grid'
    grid_fid = Dataset(grid_file, 'r')
    lon_rho = grid_fid.variables['lon_rho'][:,:]
    lat_rho = grid_fid.variables['lat_rho'][:,:]
    lon_u = grid_fid.variables['lon_u'][:,:]
    lat_u = grid_fid.variables['lat_u'][:,:]
    lon_v = grid_fid.variables['lon_v'][:,:]
    lat_v = grid_fid.variables['lat_v'][:,:]
    h = grid_fid.variables['h'][:,:]    
    zice = grid_fid.variables['zice'][:,:]
    mask_rho = grid_fid.variables['mask_rho'][:,:]
    mask_zice = grid_fid.variables['mask_zice'][:,:]
    grid_fid.close()    

    # Save the lengths of the longitude axis for each grid
    num_lon_rho = size(lon_rho, 1)
    num_lon_u = size(lon_u, 1)
    num_lon_v = size(lon_v, 1)
    # Mask h and zice with zeros
    h = h*mask_rho
    zice = zice*mask_zice
    # Interpolate h and zice to u and v grids
    h_u = 0.5*(h[:,0:-1] + h[:,1:])
    h_v = 0.5*(h[0:-1,:] + h[1:,:])
    zice_u = 0.5*(zice[:,0:-1] + zice[:,1:])
    zice_v = 0.5*(zice[0:-1,:] + zice[1:,:])

    # Calculate Cartesian integrands and z-coordinates for each grid
    dx_rho, dy_rho, dz_rho, z_rho = cartesian_grid_3d(lon_rho, lat_rho, h, zice, theta_s, theta_b, hc, N)
    dx_u, dy_u, dz_u, z_u = cartesian_grid_3d(lon_u, lat_u, h_u, zice_u, theta_s, theta_b, hc, N)
    dx_v, dy_v, dz_v, z_v = cartesian_grid_3d(lon_v, lat_v, h_v, zice_v, theta_s, theta_b, hc, N)
    # Also call calc_z for the rho_grid just so we get sc_r and Cs_r
    z_rho, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)

    # Select just the northern boundary for each field
    dx_rho = dx_rho[:,-1,:]
    dy_rho = dy_rho[:,-1,:]
    dz_rho = dz_rho[:,-1,:]
    z_rho = z_rho[:,-1,:]
    dx_u = dx_u[:,-1,:]
    dy_u = dy_u[:,-1,:]
    dz_u = dz_u[:,-1,:]
    z_u = z_u[:,-1,:]
    dx_v = dx_v[:,-1,:]
    dy_v = dy_v[:,-1,:]
    dz_v = dz_v[:,-1,:]
    z_v = z_v[:,-1,:]

    # Copy longitude and latitude at the northern boundary into arrays of
    # dimension depth x longitude
    lon_rho = tile(lon_rho[-1,:], (N,1))
    lat_rho = tile(lat_rho[-1,:], (N,1))
    lon_u = tile(lon_u[-1,:], (N,1))
    lat_u = tile(lat_u[-1,:], (N,1))
    lon_v = tile(lon_v[-1,:], (N,1))
    lat_v = tile(lat_v[-1,:], (N,1))

    # Make sure ROMS longitudes are between 0 and 360
    index = lon_rho < 0
    lon_rho[index] += 360
    index = lon_rho > 360
    lon_rho[index] -= 360
    index = lon_u < 0
    lon_u[index] += 360
    index = lon_u > 360
    lon_u[index] -= 360
    index = lon_v < 0
    lon_v[index] += 360
    index = lon_v > 360
    lon_v[index] -= 360

    # Set up output file
    print 'Setting up ', output_file
    out_fid = Dataset(output_file, 'w')
    out_fid.createDimension('xi_u', num_lon_u)
    out_fid.createDimension('xi_v', num_lon_v)
    out_fid.createDimension('xi_rho', num_lon_rho)
    out_fid.createDimension('s_rho', N)
    out_fid.createDimension('ocean_time', None)
    out_fid.createDimension('one', 1);
    out_fid.createVariable('theta_s', 'f8', ('one'))
    out_fid.variables['theta_s'].long_name = 'S-coordinate surface control parameter'
    out_fid.variables['theta_s'][:] = theta_s
    out_fid.createVariable('theta_b', 'f8', ('one'))
    out_fid.variables['theta_b'].long_name = 'S-coordinate bottom control parameter'
    out_fid.variables['theta_b'].units = 'nondimensional'
    out_fid.variables['theta_b'][:] = theta_b
    out_fid.createVariable('Tcline', 'f8', ('one'))
    out_fid.variables['Tcline'].long_name = 'S-coordinate surface/bottom layer width'
    out_fid.variables['Tcline'].units = 'meter'
    out_fid.variables['Tcline'][:] = Tcline
    out_fid.createVariable('hc', 'f8', ('one'))
    out_fid.variables['hc'].long_name = 'S-coordinate parameter, critical depth'
    out_fid.variables['hc'].units = 'meter'
    out_fid.variables['hc'][:] = hc
    out_fid.createVariable('sc_r', 'f8', ('s_rho'))
    out_fid.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_fid.variables['sc_r'].units = 'nondimensional'
    out_fid.variables['sc_r'].valid_min = -1
    out_fid.variables['sc_r'].valid_max = 0
    out_fid.variables['sc_r'][:] = sc_r
    out_fid.createVariable('Cs_r', 'f8', ('s_rho'))
    out_fid.variables['Cs_r'].long_name = 'S-coordinate stretching curves at RHO-points'
    out_fid.variables['Cs_r'].units = 'nondimensional'
    out_fid.variables['Cs_r'].valid_min = -1
    out_fid.variables['Cs_r'].valid_max = 0
    out_fid.variables['Cs_r'][:] = Cs_r
    out_fid.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_fid.variables['ocean_time'].long_name = 'time since initialization'
    out_fid.variables['ocean_time'].units = 'days'
    out_fid.createVariable('temp_north', 'f8', ('ocean_time', 's_rho', 'xi_rho'))
    out_fid.variables['temp_north'].long_name = 'northern boundary potential temperature'
    out_fid.variables['temp_north'].units = 'Celsius'
    out_fid.createVariable('salt_north', 'f8', ('ocean_time', 's_rho', 'xi_rho'))
    out_fid.variables['salt_north'].long_name = 'northern boundary salinity'
    out_fid.variables['salt_north'].units = 'PSU'
    out_fid.createVariable('u_north', 'f8', ('ocean_time', 's_rho', 'xi_u'))
    out_fid.variables['u_north'].long_name = 'northern boundary u-momentum component'
    out_fid.variables['u_north'].units = 'meter second-1'
    out_fid.createVariable('v_north', 'f8', ('ocean_time', 's_rho', 'xi_v'))
    out_fid.variables['v_north'].long_name = 'northern boundary v-momentum component'
    out_fid.variables['v_north'].units = 'meter second-1'
    out_fid.createVariable('ubar_north', 'f8', ('ocean_time', 'xi_u'))
    out_fid.variables['ubar_north'].long_name = 'northern boundary vertically integrated u-momentum component'
    out_fid.variables['ubar_north'].units = 'meter second-1'
    out_fid.createVariable('vbar_north', 'f8', ('ocean_time', 'xi_v'))
    out_fid.variables['vbar_north'].long_name = 'northern boundary vertically integrated v-momentum component'
    out_fid.variables['vbar_north'].units = 'meter second-1'
    out_fid.createVariable('zeta_north', 'f8', ('ocean_time', 'xi_rho'))
    out_fid.variables['zeta_north'].long_name = 'northern boundary sea surface height'
    out_fid.variables['zeta_north'].units = 'meter'
    out_fid.close()

    # Loop through each month of this year
    for month in range(12):

        print 'Processing month ', str(month+1), ' of 12'
        # Construct the rest of the file paths
        if month+1 < 10:
            tail = '0' + str(month+1) + '.nc'
        else:
            tail = str(month+1) + '.nc'

        # Read temperature, salinity, velocity data
        theta_fid = Dataset(theta_base + tail, 'r')
        theta_raw = transpose(theta_fid.variables['THETA'][0,:,0:nbdry_ecco,:])
        theta_fid.close()
        salt_fid = Dataset(salt_base + tail, 'r')
        salt_raw = transpose(salt_fid.variables['SALT'][0,:,0:nbdry_ecco,:])
        salt_fid.close()
        vvel_fid = Dataset(vvel_base + tail, 'r')
        vvel_raw = transpose(vvel_fid.variables['VVEL'][0,:,0:nbdry_ecco,:])
        vvel_fid.close()

        # Copy the data to the new longitude and depth indices, making sure
        # to preserve the mask.
        theta = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
        theta[1:-1,:,1:-1] = ma.copy(theta_raw)
        theta[0,:,1:-1] = ma.copy(theta_raw[-1,:,:])
        theta[-1,:,1:-1] = ma.copy(theta_raw[0,:,:])
        theta[:,:,0] = ma.copy(theta[:,:,1])
        theta[:,:,-1] = ma.copy(theta[:,:,-2])
        salt = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
        salt[1:-1,:,1:-1] = ma.copy(salt_raw)
        salt[0,:,1:-1] = ma.copy(salt_raw[-1,:,:])
        salt[-1,:,1:-1] = ma.copy(salt_raw[0,:,:])
        salt[:,:,0] = ma.copy(salt[:,:,1])
        salt[:,:,-1] = ma.copy(salt[:,:,-2])
        vvel = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
        vvel[1:-1,:,1:-1] = ma.copy(vvel_raw)
        vvel[0,:,1:-1] = ma.copy(vvel_raw[-1,:,:])
        vvel[-1,:,1:-1] = ma.copy(vvel_raw[0,:,:])
        vvel[:,:,0] = ma.copy(vvel[:,:,1])
        vvel[:,:,-1] = ma.copy(vvel[:,:,-2])

        # Regridding happens here...
        print 'Interpolating temperature'
        temp_interp = interp_ecco2roms(theta, lon_ecco, lat_ecco, depth_ecco, lon_rho, lat_rho, z_rho, mean(theta), True)
        print 'Interpolating salinity'
        salt_interp = interp_ecco2roms(salt, lon_ecco, lat_ecco, depth_ecco, lon_rho, lat_rho, z_rho, mean(salt), True)
        print 'Interpolating v'
        v_interp = interp_ecco2roms(vvel, lon_ecco, lat_ecco, depth_ecco, lon_v, lat_v, z_v, 0, False)

        # Calculate vertical average of v to get vbar
        # Be sure to treat land mask carefully so we don't divide by 0
        vbar_interp = sum(v_interp*dz_v, axis=0)
        wct_v = h_v[-1,:] + zice_v[-1,:]
        index = wct_v == 0
        vbar_interp[~index] = vbar_interp[~index]/wct_v[~index]
        vbar_interp[index] = 0.0

        # Calculate time values centered in the middle of each month,
        # relative to 1992
        time = 365.25*(year-1992) + 365.25/12*(month+0.5)

        # Save data to NetCDF file
        out_fid = Dataset(output_file, 'a')
        out_fid.variables['ocean_time'][month] = time
        out_fid.variables['temp_north'][month,:,:] = temp_interp
        out_fid.variables['salt_north'][month,:,:] = salt_interp
        # Clamp u to zero
        out_fid.variables['u_north'][month,:,:] = 0.0
        out_fid.variables['v_north'][month,:,:] = v_interp
        # Clamp ubar to zero
        out_fid.variables['ubar_north'][month,:] = 0.0
        out_fid.variables['vbar_north'][month,:] = vbar_interp
        out_fid.variables['zeta_north'][month,:] = 0.0
        out_fid.close()
예제 #11
0
def zonal_plot(file_path,
               var_name,
               tstep,
               lon_key,
               lon0,
               lon_bounds,
               depth_min,
               colour_bounds=None,
               save=False,
               fig_name=None,
               grid_path=None):

    # Grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31
    if var_name in ['w', 'AKv', 'AKt', 'AKs']:
        N = 32

    # Read the variable
    id = Dataset(file_path, 'r')
    data_3d = id.variables[var_name][tstep - 1, :, :-15, :]
    # Also read sea surface height
    zeta = id.variables['zeta'][tstep - 1, :-15, :]
    if var_name == 'salt':
        units = 'psu'
    else:
        units = id.variables[var_name].units
    long_name = id.variables[var_name].long_name

    # Rotate velocity if necessary
    if var_name in ['u', 'v']:
        grid_id = Dataset(grid_path, 'r')
        angle = grid_id.variables['angle'][:-15, :]
        grid_id.close()
        if var_name == 'u':
            data_3d_ugrid = data_3d[:, :, :]
            data_3d = ma.empty([
                data_3d_ugrid.shape[0], data_3d_ugrid.shape[1],
                data_3d_ugrid.shape[2] + 1
            ])
            for k in range(N):
                u_data = data_3d_ugrid[k, :, :]
                v_data = id.variables['v'][tstep - 1, k, :-15, :]
                u_data_lonlat, v_data_lonlat = rotate_vector_roms(
                    u_data, v_data, angle)
                data_3d[k, :, :] = u_data_lonlat
        elif var_name == 'v':
            data_3d_vgrid = data_3d[:, :, :]
            data_3d = ma.empty([
                data_3d_vgrid.shape[0], data_3d_vgrid.shape[1] + 1,
                data_3d_vgrid.shape[2]
            ])
            for k in range(N):
                v_data = data_3d_vgrid[k, :, :]
                u_data = id.variables['u'][tstep - 1, k, :-15, :]
                u_data_lonlat, v_data_lonlat = rotate_vector_roms(
                    u_data, v_data, angle)
                data_3d[k, :, :] = v_data_lonlat

    # Read grid variables
    h = id.variables['h'][:-15, :]
    zice = id.variables['zice'][:-15, :]
    lon_2d = id.variables['lon_rho'][:-15, :]
    lat_2d = id.variables['lat_rho'][:-15, :]
    id.close()

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)

    # Warning message for zonal averages
    if lon_key != 0:
        print 'WARNING: this script assumes regular i-indices for zonal averages. In heavily rotated regions eg inner Weddell Sea it may not be appropriate.'

    # Choose what to write on the title about longitude
    if lon_key == 0:
        if lon0 < 0:
            lon_string = 'at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
        else:
            lon_string = 'at ' + str(int(round(lon0))) + r'$^{\circ}$E'
    elif lon_key == 1:
        lon_string = 'zonally averaged'
    elif lon_key == 2:
        lon_string = 'zonally averaged between '
        if lon_bounds[0] < 0:
            lon_string += str(int(round(-lon_bounds[0]))) + r'$^{\circ}$W and '
        else:
            lon_string += str(int(round(lon_bounds[0]))) + r'$^{\circ}$E and '
        if lon_bounds[1] < 0:
            lon_string += str(int(round(-lon_bounds[1]))) + r'$^{\circ}$W'
        else:
            lon_string += str(int(round(lon_bounds[1]))) + r'$^{\circ}$E'

    # Edit longitude bounds to be from 0 to 360, to fit with ROMS convention
    if lon_key == 0:
        if lon0 < 0:
            lon0 += 360
    elif lon_key == 2:
        if lon_bounds[0] < 0:
            lon_bounds[0] += 360
        if lon_bounds[1] < 0:
            lon_bounds[1] += 360

    # Interpolate or average data
    if lon_key == 0:
        # Interpolate to lon0
        data, z, lat = interp_lon_roms(data_3d, z_3d, lat_2d, lon_2d, lon0)
    elif lon_key == 1:
        # Zonally average over all longitudes
        # dlon is constant on this grid (0.25 degrees) so this is easy
        data = mean(data_3d, axis=2)
        z = mean(z_3d, axis=2)
        # Zonally average latitude, and copy into N depth levels
        lat = tile(mean(lat_2d, axis=1), (N, 1))
    elif lon_key == 2:
        # Zonally average between lon_bounds
        data, z, lat = average_btw_lons(data_3d, z_3d, lat_2d, lon_2d,
                                        lon_bounds)

    if colour_bounds is not None:
        # User has set bounds on colour scale
        lev = linspace(colour_bounds[0], colour_bounds[1], num=40)
        if colour_bounds[0] == -colour_bounds[1]:
            # Bounds are centered on zero, so choose a blue-to-red colourmap
            # centered on yellow
            colour_map = 'RdYlBu_r'
        else:
            colour_map = 'jet'
    else:
        # Determine bounds automatically
        if var_name in ['u', 'v']:
            # Center levels on 0 for certain variables, with a blue-to-red
            # colourmap
            max_val = amax(abs(data))
            lev = linspace(-max_val, max_val, num=40)
            colour_map = 'RdYlBu_r'
        else:
            lev = linspace(amin(data), amax(data), num=40)
            colour_map = 'jet'

    # Plot
    fig = figure(figsize=(18, 6))
    contourf(lat, z, data, lev, cmap=colour_map, extend='both')
    colorbar()

    title(long_name + ' (' + units + ')\n' + lon_string)
    xlabel('Latitude')
    ylabel('Depth (m)')

    # Choose latitude bounds based on land mask
    data_sum = sum(data, axis=0)
    # Find southernmost and northernmost unmasked j-indices
    edges = ma.flatnotmasked_edges(data_sum)
    j_min = edges[0]
    j_max = edges[1]
    if j_min == 0:
        # There are ocean points right to the southern boundary
        # Don't do anything special
        lat_min = min(lat[:, j_min])
    else:
        # There is land everywhere at the southern boundary
        # Show the last 2 degrees of this land mask
        lat_min = min(lat[:, j_min]) - 2
    if j_max == size(data_sum) - 1:
        # There are ocean points right to the northern boundary
        # Don't do anything special
        lat_max = max(lat[:, j_max])
    else:
        # There is land everywhere at the northern boundary
        # Show the first 2 degrees of this land mask
        lat_max = max(lat[:, j_max]) + 2
#    lat_max = -50
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()

    # Reset lon0 or lon_bounds to (-180, 180) range in case we
    # use them again for the next plot
    if lon_key == 0:
        if lon0 > 180:
            lon0 -= 360
    elif lon_key == 2:
        if lon_bounds[0] > 180:
            lon_bounds[0] -= 360
        if lon_bounds[1] > 180:
            lon_bounds[1] -= 360
예제 #12
0
def adv_amery_tsplots ():

    # Paths to simulation directories
    paths = ['/short/m68/kaa561/advection/u3_lim/', '/short/m68/kaa561/advection/c4_l/']
    # Titles for plotting
    labels = [r'a) Temperature ($^{\circ}$C), U3_LIM', r'b) Temperature ($^{\circ}$C), C4_LD', 'c) Salinity (psu), U3_LIM', 'd) Salinity (psu), C4_LD']
    # File name: daily average for 31 December
    file_tail = 'ocean_avg_31dec.nc'
    var_names = ['temp', 'salt']
    # If 31 December doesn't have its own file, put the time index here
    tstep = 1 #366 if all one file of daily averages for entire simulation
    # Longitude to interpolate to
    lon0 = 71
    # Deepest depth to plot
    depth_min = -500
    # Bounds and ticks for colour scales
    scale_min = [-2, 33.8]
    scale_max = [3, 34.8]    
    scale_ticks = [1, 0.2]
    # Bounds on latitude
    lat_min = -72
    lat_max = -50
    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Set up figure
    fig = figure(figsize=(18,12))
    # Loop over simulations
    for sim in range(2):
        # Loop over variables (temp and salt)
        for var in range(2):
            # Read 3D variable
            id = Dataset(paths[sim]+file_tail, 'r')
            data_3d = id.variables[var_names[var]][tstep-1,:,:,:]
            # Also read sea surface height
            zeta = id.variables['zeta'][tstep-1,:,:]
            if sim==0 and var==0:
                # For the first simulation, read grid variables
                h = id.variables['h'][:,:]
                zice = id.variables['zice'][:,:]
                lon_2d = id.variables['lon_rho'][:,:]
                lat_2d = id.variables['lat_rho'][:,:]
            id.close()
            # Calculate 3D z-coordinates
            z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
            # Interpolate temp/salt, z-coordinates, and latitude to 71E
            data, z, lat = interp_lon(data_3d, z_3d, lat_2d, lon_2d, lon0)
            ax = fig.add_subplot(2, 2, 2*var+sim+1)
            # Shade data (pcolor not contourf so we don't misrepresent the
            # model grid)
            img = pcolor(lat, z, data, vmin=scale_min[var], vmax=scale_max[var], cmap='jet')
            # Add title
            title(labels[2*var+sim], fontsize=24)
            # Label axes
            if var == 1:
                xlabel('Latitude', fontsize=16)
            if sim == 0:
                ylabel('Depth (m)', fontsize=16)
            xlim([lat_min, lat_max])
            ylim([depth_min, 0])
            if sim == 1:
                # Add colorbars for each variable
                if var == 0:
                    cbaxes = fig.add_axes([0.93, 0.575, 0.01, 0.3])
                elif var == 1:
                    cbaxes = fig.add_axes([0.93, 0.125, 0.01, 0.3])
                cbar = colorbar(img, ticks=arange(scale_min[var], scale_max[var]+scale_ticks[var], scale_ticks[var]), cax=cbaxes, extend='both')
                cbar.ax.tick_params(labelsize=14)
            # Set ticks the way we want them
            lat_ticks = arange(lat_min+2, lat_max+1, 5)
            ax.set_xticks(lat_ticks)
            lat_labels = []
            for val in lat_ticks:
                lat_labels.append(str(int(round(-val))) + r'$^{\circ}$S')
            ax.set_xticklabels(lat_labels, fontsize=14)
            depth_ticks = range(depth_min, 0+100, 100)
            ax.set_yticks(depth_ticks)
            depth_labels = []
            for val in depth_ticks:
                depth_labels.append(str(int(round(-val))))
            ax.set_yticklabels(depth_labels, fontsize=14)

    # Main title
    suptitle(r'71$^{\circ}$E (Amery Ice Shelf), 31 December', fontsize=30)
    #fig.show()
    fig.savefig('adv_amery_tsplots.png')
예제 #13
0
def run (grid_file, woa_file, output_file, Tcline, theta_s, theta_b, hc, N, nbdry_woa):

    # Read WOA data and grid
    print 'Reading World Ocean Atlas data'
    woa_id = Dataset(woa_file, 'r')
    lon_woa = woa_id.variables['longitude'][:]
    lat_woa = woa_id.variables['latitude'][:nbdry_woa]
    depth_woa = woa_id.variables['depth'][:]
    temp_woa = transpose(woa_id.variables['temp'][:,:nbdry_woa,:])
    salt_woa = transpose(woa_id.variables['salt'][:,:nbdry_woa,:])
    woa_id.close()

    # Read ROMS grid
    print 'Reading ROMS grid'
    grid_id = Dataset(grid_file, 'r')
    lon_roms = grid_id.variables['lon_rho'][:,:]
    lat_roms = grid_id.variables['lat_rho'][:,:]
    h = grid_id.variables['h'][:,:]
    zice = grid_id.variables['zice'][:,:]
    mask_rho = grid_id.variables['mask_rho'][:,:]
    mask_zice = grid_id.variables['mask_zice'][:,:]
    grid_id.close()
    num_lon = size(lon_roms, 1)
    num_lat = size(lon_roms, 0)
    # Mask h and zice with zeros
    h = h*mask_rho
    zice = zice*mask_zice

    # Get 3D array of ROMS z-coordinates, as well as 1D arrays of s-coordinates
    # and stretching curves
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Copy the latitude and longitude values into 3D arrays of the same shape
    lon_roms_3d = tile(lon_roms, (N,1,1))
    lat_roms_3d = tile(lat_roms, (N,1,1))

    # Regridding happens here
    print 'Interpolating temperature'
    temp = interp_woa2roms(temp_woa, lon_woa, lat_woa, depth_woa, lon_roms_3d, lat_roms_3d, z_roms_3d, mask_rho, mask_zice, -0.5)
    print 'Interpolating salinity'
    salt = interp_woa2roms(salt_woa, lon_woa, lat_woa, depth_woa, lon_roms_3d, lat_roms_3d, z_roms_3d, mask_rho, mask_zice, 34.5)

    # Set initial velocities and sea surface height to zero
    u = zeros((N, num_lat, num_lon-1))
    v = zeros((N, num_lat-1, num_lon))
    ubar = zeros((num_lat, num_lon-1))
    vbar = zeros((num_lat-1, num_lon))
    zeta = zeros((num_lat, num_lon))

    print 'Writing to NetCDF file'
    out_id = Dataset(output_file, 'w')
    # Define dimensions
    out_id.createDimension('xi_u', num_lon-1)
    out_id.createDimension('xi_v', num_lon)
    out_id.createDimension('xi_rho', num_lon)
    out_id.createDimension('eta_u', num_lat)
    out_id.createDimension('eta_v', num_lat-1)
    out_id.createDimension('eta_rho', num_lat)
    out_id.createDimension('s_rho', N)
    out_id.createDimension('ocean_time', None)
    out_id.createDimension('one', 1);
    # Define variables and assign values
    out_id.createVariable('tstart', 'f8', ('one'))
    out_id.variables['tstart'].long_name = 'start processing day'
    out_id.variables['tstart'].units = 'day'
    out_id.variables['tstart'][:] = 0.0
    out_id.createVariable('tend', 'f8', ('one'))
    out_id.variables['tend'].long_name = 'end processing day'
    out_id.variables['tend'].units = 'day'
    out_id.variables['tend'][:] = 0.0
    out_id.createVariable('theta_s', 'f8', ('one'))
    out_id.variables['theta_s'].long_name = 'S-coordinate surface control parameter'
    out_id.variables['theta_s'][:] = theta_s
    out_id.createVariable('theta_b', 'f8', ('one'))
    out_id.variables['theta_b'].long_name = 'S-coordinate bottom control parameter'
    out_id.variables['theta_b'].units = 'nondimensional'
    out_id.variables['theta_b'][:] = theta_b
    out_id.createVariable('Tcline', 'f8', ('one'))
    out_id.variables['Tcline'].long_name = 'S-coordinate surface/bottom layer width'
    out_id.variables['Tcline'].units = 'meter'
    out_id.variables['Tcline'][:] = Tcline
    out_id.createVariable('hc', 'f8', ('one'))
    out_id.variables['hc'].long_name = 'S-coordinate parameter, critical depth'
    out_id.variables['hc'].units = 'meter'
    out_id.variables['hc'][:] = hc
    out_id.createVariable('Cs_r', 'f8', ('s_rho'))
    out_id.variables['Cs_r'].long_name = 'S-coordinate stretching curves at RHO-points'
    out_id.variables['Cs_r'].units = 'nondimensional'
    out_id.variables['Cs_r'].valid_min = -1.0
    out_id.variables['Cs_r'].valid_max = 0.0
    out_id.variables['Cs_r'][:] = Cs_r
    out_id.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_id.variables['ocean_time'].long_name = 'time since initialization'
    out_id.variables['ocean_time'].units = 'seconds'
    out_id.variables['ocean_time'][0] = 0.0
    out_id.createVariable('u', 'f8', ('ocean_time', 's_rho', 'eta_u', 'xi_u'))
    out_id.variables['u'].long_name = 'u-momentum component'
    out_id.variables['u'].units = 'meter second-1'
    out_id.variables['u'][0,:,:,:] = u
    out_id.createVariable('v', 'f8', ('ocean_time', 's_rho', 'eta_v', 'xi_v'))
    out_id.variables['v'].long_name = 'v-momentum component'
    out_id.variables['v'].units = 'meter second-1'
    out_id.variables['v'][0,:,:,:] = v
    out_id.createVariable('ubar', 'f8', ('ocean_time', 'eta_u', 'xi_u'))
    out_id.variables['ubar'].long_name = 'vertically integrated u-momentum component'
    out_id.variables['ubar'].units = 'meter second-1'
    out_id.variables['ubar'][0,:,:] = ubar
    out_id.createVariable('vbar', 'f8', ('ocean_time', 'eta_v', 'xi_v'))
    out_id.variables['vbar'].long_name = 'vertically integrated v-momentum component'
    out_id.variables['vbar'].units = 'meter second-1'
    out_id.variables['vbar'][0,:,:] = vbar
    out_id.createVariable('zeta', 'f8', ('ocean_time', 'eta_rho', 'xi_rho'))
    out_id.variables['zeta'].long_name = 'free-surface'
    out_id.variables['zeta'].units = 'meter'
    out_id.variables['zeta'][0,:,:] = zeta
    out_id.createVariable('temp', 'f8', ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_id.variables['temp'].long_name = 'potential temperature'
    out_id.variables['temp'].units = 'Celsius'
    out_id.variables['temp'][0,:,:,:] = temp
    out_id.createVariable('salt', 'f8', ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_id.variables['salt'].long_name = 'salinity'
    out_id.variables['salt'].units = 'PSU'
    out_id.variables['salt'][0,:,:,:] = salt
    out_id.createVariable('sc_r', 'f8', ('s_rho'))
    out_id.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_id.variables['sc_r'].units = 'nondimensional'
    out_id.variables['sc_r'].valid_min = -1.0
    out_id.variables['sc_r'].valid_max = 0.0
    out_id.variables['sc_r'][:] = sc_r
    out_id.close()
예제 #14
0
def freezingpt_slice(file_path,
                     tstep,
                     i_val,
                     depth_min,
                     colour_bounds=None,
                     save=False,
                     fig_name=None):

    # Grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31

    # Read temperature, salinity, and grid variables
    id = Dataset(file_path, 'r')
    temp = id.variables['temp'][tstep - 1, :, :-15, i_val - 1]
    salt = id.variables['salt'][tstep - 1, :, :-15, i_val - 1]
    h = id.variables['h'][:-15, :]
    zice = id.variables['zice'][:-15, :]
    # Sea surface height is time-dependent
    zeta = id.variables['zeta'][tstep - 1, :-15, :]
    lon_2d = id.variables['lon_rho'][:-15, :]
    lat_2d = id.variables['lat_rho'][:-15, :]
    id.close()

    # Calculate freezing point as seen by supercooling code
    tfr = salt / (-18.48 + salt * 18.48 / 1000.0)  #-0.054*salt
    # Calculate difference from freezing point
    deltat = temp - tfr

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
    # Select depth and latitude at the given i-index
    z = z_3d[:, :, i_val - 1]
    lat = tile(lat_2d[:, i_val - 1], (N, 1))

    # Determine colour bounds
    if colour_bounds is not None:
        # Specified by user
        scale_min = colour_bounds[0]
        scale_max = colour_bounds[1]
        if scale_min == -scale_max:
            # Centered on zero; use a red-yellow-blue colour scale
            colour_map = 'RdBu_r'
        else:
            # Use a rainbow colour scale
            colour_map = 'jet'
    else:
        # Determine automatically
        scale_min = amin(deltat)
        scale_max = amax(deltat)
        colour_map = 'jet'

    # Plot (pcolor not contour to show what each individual cell is doing)
    fig = figure(figsize=(18, 6))
    pcolor(lat, z, deltat, vmin=scale_min, vmax=scale_max, cmap=colour_map)
    colorbar()
    title('Difference from freezing point (K) at i=' + str(i_val))
    xlabel('Latitude')
    ylabel('Depth (m)')

    # Determine bounds on latitude
    data_sum = sum(deltat, axis=0)
    edges = ma.flatnotmasked_edges(data_sum)
    j_min = edges[0]
    j_max = edges[1]
    if j_min == 0:
        # There are ocean points right to the southern boundary
        # Don't do anything special
        lat_min = min(lat[:, j_min])
    else:
        # There is land everywhere at the southern boundary
        # Show the last 2 degrees of this land mask
        lat_min = min(lat[:, j_min]) - 2
    if j_max == size(data_sum) - 1:
        # There are ocean points right to the northern boundary
        # Don't do anything special
        lat_max = max(lat[:, j_max])
    else:
        # There is land everywhere at the northern boundary
        # Show the first 2 degrees of this land mask
        lat_max = max(lat[:, j_max]) + 2
    lat_max = -65
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
예제 #15
0
def run (grid_file, theta_file, salt_file, output_file, theta_s, theta_b, hc, N, nbdry_ecco):

    # Read ECCO2 data and grid
    print 'Reading ECCO2 data'
    theta_fid = Dataset(theta_file, 'r')
    lon_ecco_raw = theta_fid.variables['LONGITUDE_T'][:]
    lat_ecco = theta_fid.variables['LATITUDE_T'][0:nbdry_ecco]
    depth_ecco_raw = theta_fid.variables['DEPTH_T'][:]
    theta_raw = transpose(theta_fid.variables['THETA'][0,:,0:nbdry_ecco,:])
    theta_fid.close()
    salt_fid = Dataset(salt_file, 'r')
    salt_raw = transpose(salt_fid.variables['SALT'][0,:,0:nbdry_ecco,:])
    salt_fid.close()

    # The ECCO2 longitude axis doesn't wrap around; there is a gap between
    # almost-180W and almost-180E, and the ROMS grid has points in this gap.
    # So copy the last longitude value (mod 360) to the beginning, and the
    # first longitude value (mod 360) to the end.
    lon_ecco = zeros(size(lon_ecco_raw)+2)
    lon_ecco[0] = lon_ecco_raw[-1]-360
    lon_ecco[1:-1] = lon_ecco_raw
    lon_ecco[-1] = lon_ecco_raw[0]+360

    # The shallowest ECCO2 depth value is 5 m, but ROMS needs 0 m. So add the
    # index depth = 0 m to the beginning. Later we will just copy the 5 m values
    # for theta and salt into this index. Similarly, add the index depth = 6000 m
    # to the end.
    depth_ecco = zeros(size(depth_ecco_raw)+2)
    depth_ecco[0] = 0.0
    depth_ecco[1:-1] = depth_ecco_raw
    depth_ecco[-1] = 6000.0

    # Copy the theta and salt values to the new longitude and depth indices,
    # making sure to preserve the mask.
    theta = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
    theta[1:-1,:,1:-1] = ma.copy(theta_raw)
    theta[0,:,1:-1] = ma.copy(theta_raw[-1,:,:])
    theta[-1,:,1:-1] = ma.copy(theta_raw[0,:,:])
    theta[:,:,0] = ma.copy(theta[:,:,1])
    theta[:,:,-1] = ma.copy(theta[:,:,-2])
    salt = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
    salt[1:-1,:,1:-1] = ma.copy(salt_raw)
    salt[0,:,1:-1] = ma.copy(salt_raw[-1,:,:])
    salt[-1,:,1:-1] = ma.copy(salt_raw[0,:,:])
    salt[:,:,0] = ma.copy(salt[:,:,1])
    salt[:,:,-1] = ma.copy(salt[:,:,-2])

    # Read ROMS grid
    print 'Reading ROMS grid'
    grid_fid = Dataset(grid_file, 'r')
    lon_roms = grid_fid.variables['lon_rho'][:,:]
    lat_roms = grid_fid.variables['lat_rho'][:,:]
    h = grid_fid.variables['h'][:,:]
    zice = grid_fid.variables['zice'][:,:]
    mask_rho = grid_fid.variables['mask_rho'][:,:]
    mask_zice = grid_fid.variables['mask_zice'][:,:]
    grid_fid.close()
    num_lon = size(lon_roms, 1)
    num_lat = size(lon_roms, 0)
    # Mask h and zice with zeros
    h = h*mask_rho
    zice = zice*mask_zice

    # Get a 3D array of ROMS z-coordinates, as well as 1D arrays of s-coordinates
    # and stretching curves
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Copy the latitude and longitude values into 3D arrays of the same shape
    lon_roms_3d = tile(lon_roms, (N,1,1))
    lat_roms_3d = tile(lat_roms, (N,1,1))

    # Regridding happens here...
    print 'Interpolating temperature'
    temp = interp_ecco2roms_ini(theta, lon_ecco, lat_ecco, depth_ecco, lon_roms_3d, lat_roms_3d, z_roms_3d, mask_rho, mask_zice)
    print 'Interpolating salinity'
    salt = interp_ecco2roms_ini(salt, lon_ecco, lat_ecco, depth_ecco, lon_roms_3d, lat_roms_3d, z_roms_3d, mask_rho, mask_zice)

    # Set initial velocities and sea surface height to zero
    u = zeros((N, num_lat, num_lon-1))
    v = zeros((N, num_lat-1, num_lon))
    ubar = zeros((num_lat, num_lon-1))
    vbar = zeros((num_lat-1, num_lon))
    zeta = zeros((num_lat, num_lon))

    print 'Writing to NetCDF file'
    out_fid = Dataset(output_file, 'w')
    # Define dimensions
    out_fid.createDimension('xi_u', num_lon-1)
    out_fid.createDimension('xi_v', num_lon)
    out_fid.createDimension('xi_rho', num_lon)
    out_fid.createDimension('eta_u', num_lat)
    out_fid.createDimension('eta_v', num_lat-1)
    out_fid.createDimension('eta_rho', num_lat)
    out_fid.createDimension('s_rho', N)
    out_fid.createDimension('ocean_time', None)
    out_fid.createDimension('one', 1);
    # Define variables and assign values
    out_fid.createVariable('tstart', 'f8', ('one'))
    out_fid.variables['tstart'].long_name = 'start processing day'
    out_fid.variables['tstart'].units = 'day'
    out_fid.variables['tstart'][:] = 0.0
    out_fid.createVariable('tend', 'f8', ('one'))
    out_fid.variables['tend'].long_name = 'end processing day'
    out_fid.variables['tend'].units = 'day'
    out_fid.variables['tend'][:] = 0.0
    out_fid.createVariable('theta_s', 'f8', ('one'))
    out_fid.variables['theta_s'].long_name = 'S-coordinate surface control parameter'
    out_fid.variables['theta_s'][:] = theta_s
    out_fid.createVariable('theta_b', 'f8', ('one'))
    out_fid.variables['theta_b'].long_name = 'S-coordinate bottom control parameter'
    out_fid.variables['theta_b'].units = 'nondimensional'
    out_fid.variables['theta_b'][:] = theta_b
    out_fid.createVariable('Tcline', 'f8', ('one'))
    out_fid.variables['Tcline'].long_name = 'S-coordinate surface/bottom layer width'
    out_fid.variables['Tcline'].units = 'meter'
    out_fid.variables['Tcline'][:] = hc
    out_fid.createVariable('hc', 'f8', ('one'))
    out_fid.variables['hc'].long_name = 'S-coordinate parameter, critical depth'
    out_fid.variables['hc'].units = 'meter'
    out_fid.variables['hc'][:] = hc
    out_fid.createVariable('Cs_r', 'f8', ('s_rho'))
    out_fid.variables['Cs_r'].long_name = 'S-coordinate stretching curves at RHO-points'
    out_fid.variables['Cs_r'].units = 'nondimensional'
    out_fid.variables['Cs_r'].valid_min = -1.0
    out_fid.variables['Cs_r'].valid_max = 0.0
    out_fid.variables['Cs_r'][:] = Cs_r
    out_fid.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_fid.variables['ocean_time'].long_name = 'time since initialization'
    out_fid.variables['ocean_time'].units = 'seconds'
    out_fid.variables['ocean_time'][0] = 0.0
    out_fid.createVariable('u', 'f8', ('ocean_time', 's_rho', 'eta_u', 'xi_u'))
    out_fid.variables['u'].long_name = 'u-momentum component'
    out_fid.variables['u'].units = 'meter second-1'
    out_fid.variables['u'][0,:,:,:] = u
    out_fid.createVariable('v', 'f8', ('ocean_time', 's_rho', 'eta_v', 'xi_v'))
    out_fid.variables['v'].long_name = 'v-momentum component'
    out_fid.variables['v'].units = 'meter second-1'
    out_fid.variables['v'][0,:,:,:] = v
    out_fid.createVariable('ubar', 'f8', ('ocean_time', 'eta_u', 'xi_u'))
    out_fid.variables['ubar'].long_name = 'vertically integrated u-momentum component'
    out_fid.variables['ubar'].units = 'meter second-1'
    out_fid.variables['ubar'][0,:,:] = ubar
    out_fid.createVariable('vbar', 'f8', ('ocean_time', 'eta_v', 'xi_v'))
    out_fid.variables['vbar'].long_name = 'vertically integrated v-momentum component'
    out_fid.variables['vbar'].units = 'meter second-1'
    out_fid.variables['vbar'][0,:,:] = vbar
    out_fid.createVariable('zeta', 'f8', ('ocean_time', 'eta_rho', 'xi_rho'))
    out_fid.variables['zeta'].long_name = 'free-surface'
    out_fid.variables['zeta'].units = 'meter'
    out_fid.variables['zeta'][0,:,:] = zeta
    out_fid.createVariable('temp', 'f8', ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_fid.variables['temp'].long_name = 'potential temperature'
    out_fid.variables['temp'].units = 'Celsius'
    out_fid.variables['temp'][0,:,:,:] = temp
    out_fid.createVariable('salt', 'f8', ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_fid.variables['salt'].long_name = 'salinity'
    out_fid.variables['salt'].units = 'PSU'
    out_fid.variables['salt'][0,:,:,:] = salt
    out_fid.createVariable('sc_r', 'f8', ('s_rho'))
    out_fid.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_fid.variables['sc_r'].units = 'nondimensional'
    out_fid.variables['sc_r'].valid_min = -1.0
    out_fid.variables['sc_r'].valid_max = 0.0
    out_fid.variables['sc_r'][:] = sc_r
    out_fid.close()

    print 'Finished'
예제 #16
0
def adv_freezingpt_slice ():

    # Path to ocean history file
    file_path = '/short/m68/kaa561/ROMS-CICE-MCT/tmproms/run/advection/c4_lowdif/ocean_his_0001.nc'
    # Timestep to plot
    tstep = 189
    # i-index to plot (1-based)
    i_val = 1250
    # Deepest depth to plot
    depth_min = -100
    # Bounds on colour scale
    colour_bounds = [-0.3, 0.3]
    # Bounds on latitudes to plot
    lat_min = -78
    lat_max = -72
    save = True
    fig_name = 'adv_freezingpt_slice.png'

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Read temperature, salinity, and grid variables
    id = Dataset(file_path, 'r')
    temp = id.variables['temp'][tstep-1,:,:-15,i_val-1]
    salt = id.variables['salt'][tstep-1,:,:-15,i_val-1]
    h = id.variables['h'][:-15,:]
    zice = id.variables['zice'][:-15,:]
    # Sea surface height is time-dependent
    zeta = id.variables['zeta'][tstep-1,:-15,:]
    lon_2d = id.variables['lon_rho'][:-15,:]
    lat_2d = id.variables['lat_rho'][:-15,:]
    id.close()

    # Calculate freezing point as seen by supercooling code
    tfr = -0.054*salt
    # Calculate difference from freezing point
    deltat = temp - tfr

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
    # Select depth and latitude at the given i-index
    z = z_3d[:,:,i_val-1]
    lat = tile(lat_2d[:,i_val-1], (N,1))

    # Determine colour bounds
    if colour_bounds is not None:
        # Specified by user
        scale_min = colour_bounds[0]
        scale_max = colour_bounds[1]
        if scale_min == -scale_max:
            # Centered on zero; use a red-yellow-blue colour scale
            colour_map = 'RdYlBu_r'
        else:
            # Use a rainbow colour scale
            colour_map = 'jet'
    else:
        # Determine automatically
        scale_min = amin(deltat)
        scale_max = amax(deltat)
        colour_map = 'jet'

    # Plot (pcolor not contour to show what each individual cell is doing)
    fig = figure(figsize=(12,6))
    pcolor(lat, z, deltat, vmin=scale_min, vmax=scale_max, cmap=colour_map)
    colorbar()
    title(r'Difference from freezing point ($^{\circ}$C) in Weddell Sea, 7 July')
    xlabel('Latitude')
    ylabel('Depth (m)')
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
예제 #17
0
def sose_roms_seasonal (file_path, var_name, lon0, depth_bdry, save=False, fig_name=None):

    # Path to SOSE seasonal climatology file
    sose_file = '../SOSE_seasonal_climatology.nc'

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Starting and ending months (1-based) for each season
    start_month = [12, 3, 6, 9]
    end_month = [2, 5, 8, 11]
    # Starting and ending days of the month (1-based) for each season
    # Assume no leap years, we'll fix this later if we need
    start_day = [1, 1, 1, 1]
    end_day = [28, 31, 31, 30]
    # Number of days in each season (again, ignore leap years for now)
    ndays_season = [90, 92, 92, 91]
    # Season names for titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Bounds on colour scale
    if var_name == 'temp':
        var_min = -2.5
        var_max = 7.5
        var_ticks = 1
    elif var_name == 'salt':
        var_min = 33.8
        var_max = 34.8
        var_ticks = 0.2
    else:
        print 'Unknown variable ' + var_name
        return

    # Choose what to write on the title about the variable
    if var_name == 'temp':
        var_string = r'Temperature ($^{\circ}$C)'
    elif var_name == 'salt':
        var_string = 'Salinity (psu)'
    # Choose what to write on the title about longitude
    if lon0 < 0:
        lon_string = ' at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = ' at ' + str(int(round(lon0))) + r'$^{\circ}$E'
    # Edit longitude bounds to be from 0 to 360, to fit with ROMS convention
    if lon0 < 0:
        lon0 += 360

    print 'Processing ROMS data'

    # Read grid and time values
    id = Dataset(file_path, 'r')
    h = id.variables['h'][:-15,:]
    zice = id.variables['zice'][:-15,:]
    lon_roms_2d = id.variables['lon_rho'][:-15,:]
    lat_roms_2d = id.variables['lat_rho'][:-15,:]
    time_id = id.variables['ocean_time']
    # Get the year, month, and day (all 1-based) for each output step
    # These are 5-day averages marked with the middle day's date
    time = num2date(time_id[:], units=time_id.units, calendar=time_id.calendar.lower())

    # Loop backwards through time indices to find the last one we care about
    # (which contains 30 November in its averaging period)
    end_t = -1  # Missing value flag
    for t in range(size(time)-1, -1, -1):
        if time[t].month == end_month[-1] and time[t].day in range(end_day[-1]-2, end_day[-1]+1):
            end_t = t
            break
        if time[t].month == start_month[0] and time[t].day in range(start_day[0], start_day[0]+2):
            end_t = t
            break
    # Make sure we actually found it
    if end_t == -1:
        print 'Error: ' + file_path + ' does not contain a complete Dec-Nov period'
        return

    # Continue looping backwards to find the first time index we care about
    # (which contains 1 December the previous year in its averaging period)
    start_t = -1  # Missing value falg
    for t in range(end_t-60, -1, -1):
        if time[t].month == end_month[-1] and time[t].day in range(end_day[-1]-1, end_day[-1]+1):
            start_t = t
            break
        if time[t].month == start_month[0] and time[t].day in range(start_day[0], start_day[0]+3):
            start_t = t
            break
    # Make sure we actually found it
    if start_t == -1:
        print 'Error: ' + file_path + ' does not contain a complete Dec-Nov period'
        return

    # Check if end_t occurs on a leap year
    leap_year = False
    if mod(time[end_t].year, 4) == 0:
        # Years divisible by 4 are leap years
        leap_year = True
        if mod(time[end_t].year, 100) == 0:
            # Unless they're also divisible by 100, in which case they aren't
            # leap years
            leap_year = False
            if mod(time[end_t].year, 400) == 0:
                # Unless they're also divisible by 400, in which case they are
                # leap years after all
                leap_year = True
    if leap_year:
        # Update last day in February
        end_day[0] += 1
        ndays_season[0] += 1

    # Initialise seasonal averages
    var_3d_roms = ma.empty([4, N, size(lon_roms_2d,0), size(lon_roms_2d,1)])
    var_3d_roms[:,:,:,:] = 0.0
    # Process one season at a time
    for season in range(4):
        print 'Calculating seasonal averages for ' + season_names[season]
        season_days = 0  # Number of days in season; this will be incremented
        next_season = mod(season+1, 4)

        # Find starting timestep
        start_t_season = -1
        for t in range(start_t, end_t+1):
            if time[t].month == end_month[season-1] and time[t].day in range(end_day[season-1]-1, end_day[season-1]+1):
                start_t_season = t
                break
            if time[t].month == start_month[season] and time[t].day in range(start_day[season], start_day[season]+3):
                start_t_season = t
                break
        # Make sure we actually found it
        if start_t_season == -1:
            print 'Error: could not find starting timestep for season ' + season_title[season]
            return

        # Find ending timestep
        end_t_season = -1
        for t in range(start_t_season+1, end_t+1):
            if time[t].month == end_month[season] and time[t].day in range(end_day[season]-2, end_day[season]+1):
                end_t_season = t
                break
            if time[t].month == start_month[next_season] and time[t].day in range(start_day[next_season], start_day[next_season]+2):
                end_t_season = t
                break
        # Make sure we actually found it
        if end_t_season == -1:
            print 'Error: could not find ending timestep for season ' + season_title[season]
            return

        # Figure out how many of the 5 days averaged in start_t_season are
        # actually within this season
        if time[start_t_season].month == start_month[season] and time[start_t_season].day == start_day[season]+2:
            # Starting day is in position 1 of 5; we care about all of them
            start_days = 5
        elif time[start_t_season].month == start_month[season] and time[start_t_season].day == start_day[season]+1:
            # Starting day is in position 2 of 5; we care about the last 4
            start_days = 4
        elif time[start_t_season].month == start_month[season] and time[start_t_season].day == start_day[season]:
            # Starting day is in position 3 of 5; we care about the last 3
            start_days = 3
        elif time[start_t_season].month == end_month[season-1] and time[start_t_season].day == end_day[season-1]:
            # Starting day is in position 4 of 5; we care about the last 2
            start_days = 2
        elif time[start_t_season].month == end_month[season-1] and time[start_t_season].day == end_day[season-1]-1:
            # Starting day is in position 5 of 5; we care about the last 1
            start_days = 1
        else:
            print 'Error for season ' + season_title[season] + ': starting index is month ' + str(time[start_t_season].month) + ', day ' + str(time[start_t_season].day)
            return

        # Start accumulating data weighted by days
        var_3d_roms[season,:,:,:] += id.variables[var_name][start_t_season,:,:-15,:]*start_days
        season_days += start_days

        # Between start_t_season and end_t_season, we want all the days
        for t in range(start_t_season+1, end_t_season):
            var_3d_roms[season,:,:,:] += id.variables[var_name][t,:,:-15,:]*5
            season_days += 5

        # Figure out how many of the 5 days averaged in end_t_season are
        # actually within this season
        if time[end_t_season].month == start_month[next_season] and time[end_t_season].day == start_day[next_season]+1:
            # Ending day is in position 1 of 5; we care about the first 1
            end_days = 1
        elif time[end_t_season].month == start_month[next_season] and time[end_t_season].day == start_day[next_season]:
            # Ending day is in position 2 of 5; we care about the first 2
            end_days = 2
        elif time[end_t_season].month == end_month[season] and time[end_t_season].day == end_day[season]:
            # Ending day is in position 3 of 5; we care about the first 3
            end_days = 3
        elif time[end_t_season].month == end_month[season] and time[end_t_season].day == end_day[season]-1:
            # Ending day is in position 4 of 5; we care about the first 4
            end_days = 4
        elif time[end_t_season].month == end_month[season] and time[end_t_season].day == end_day[season]-2:
            # Ending day is in position 5 of 5; we care about all 5
            end_days = 5
        else:
            print 'Error for season ' + season_title[season] + ': ending index is month ' + str(time[end_t_season].month) + ', day ' + str(time[end_t_season].day)
            return

        var_3d_roms[season,:,:,:] += id.variables[var_name][end_t_season,:,:-15,:]*end_days
        season_days += end_days

        # Check that we got the correct number of days
        if season_days != ndays_season[season]:
            print 'Error: found ' + str(season_days) + ' days instead of ' + str(ndays_season[season])
            return

        # Finished accumulating data, now convert from sum to average
        var_3d_roms[season,:,:,:] /= season_days

    # Finished reading data
    id.close()

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)

    # Calculate zonal slices for each season
    var_roms = ma.empty([4, N, size(lat_roms_2d,0)])
    var_roms[:,:,:] = 0.0
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        var_tmp, z_roms, lat_roms = interp_lon_roms(var_3d_roms[season,:,:,:], z_roms_3d, lat_roms_2d, lon_roms_2d, lon0)
        var_roms[season,:,:] = var_tmp

    print 'Processing SOSE data'

    # Read grid and 3D data (already seasonally averaged)
    id = Dataset(sose_file, 'r')
    lon_sose = id.variables['longitude'][0,:]
    lat_sose = id.variables['latitude'][:,0]
    z_sose = id.variables['depth'][:]
    var_3d_sose = id.variables[var_name][:,:,:,:]

    # Calculate zonal slices for each season
    var_sose = ma.empty([4, size(z_sose), size(lat_sose,0)])
    var_sose[:,:,:] = 0.0
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        var_sose[season,:,:] = interp_lon_sose(var_3d_sose[season,:,:,:], lon_sose, lon0)

    # Set colour levels
    lev = linspace(var_min, var_max, num=50)

    # Choose southern boundary based on extent of SOSE grid
    sbdry = amin(lat_sose)
    # Choose northern boundary based on extent of ROMS grid
    nbdry = amax(lat_roms)

    # Plot
    print 'Plotting'
    fig = figure(figsize=(20,9))
    # Loop over seasons
    for season in range(4):
        # ROMS
        fig.add_subplot(2, 4, season+1)
        img = contourf(lat_roms, z_roms, var_roms[season,:,:], lev, cmap='jet', extend='both')
        xlim([sbdry, nbdry])
        ylim([depth_bdry, 0])
        title('ROMS (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
        # SOSE
        fig.add_subplot(2, 4, season+5)
        contourf(lat_sose, z_sose, var_sose[season,:,:], lev, cmap='jet', extend='both')
        xlim([sbdry, nbdry])
        ylim([depth_bdry, 0])
        title('SOSE (' + season_names[season] + ')', fontsize=24)
        xlabel('Latitude', fontsize=18)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
    # Add colourbar
    cbaxes = fig.add_axes([0.93, 0.2, 0.015, 0.6])
    cbar = colorbar(img, cax=cbaxes, ticks=arange(var_min, var_max+var_ticks, var_ticks))
    cbar.ax.tick_params(labelsize=16)
    # Add the main title
    suptitle(var_string + lon_string, fontsize=30)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()    
예제 #18
0
def adv_freezingpt_slice():

    # Path to ocean history file
    file_path = '/short/m68/kaa561/advection/c4_l/ocean_his_0001.nc'
    # Timestep to plot
    tstep = 178
    # i-index to plot (1-based)
    i_val = 1250
    # Deepest depth to plot
    depth_min = -200
    # Bounds on colour scale
    scale_max = 0.5
    scale_tick = 0.25
    # Bounds on latitudes to plot
    lat_min = -76
    lat_max = -73
    save = True
    fig_name = 'adv_freezingpt_slice.png'

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31
    Vstretching = 2

    # Read temperature, salinity, and grid variables
    id = Dataset(file_path, 'r')
    temp = id.variables['temp'][tstep - 1, :, :-15, i_val - 1]
    salt = id.variables['salt'][tstep - 1, :, :-15, i_val - 1]
    h = id.variables['h'][:-15, :]
    zice = id.variables['zice'][:-15, :]
    # Sea surface height is time-dependent
    zeta = id.variables['zeta'][tstep - 1, :-15, :]
    lon_2d = id.variables['lon_rho'][:-15, :]
    lat_2d = id.variables['lat_rho'][:-15, :]
    id.close()

    # Calculate freezing point as seen by supercooling code
    tfr = salt / (-18.48 + salt * 18.48 / 1000.0)
    # Calculate difference from freezing point
    deltat = temp - tfr

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta,
                              Vstretching)
    # Select depth and latitude at the given i-index
    z = z_3d[:, :, i_val - 1]
    lat = tile(lat_2d[:, i_val - 1], (N, 1))

    # Plot (pcolor not contour to show what each individual cell is doing)
    fig, ax = subplots(figsize=(12, 6))
    pcolor(lat, z, deltat, vmin=-scale_max, vmax=scale_max, cmap='RdBu_r')
    cbar = colorbar(extend='both',
                    ticks=arange(-scale_max, scale_max + scale_tick,
                                 scale_tick))
    cbar.ax.tick_params(labelsize=14)
    title(
        r'Difference from freezing point ($^{\circ}$C) in Weddell Sea: C4_LD',
        fontsize=18)
    xlabel('Latitude', fontsize=16)
    ylabel('Depth (m)', fontsize=16)
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])

    lat_ticks = arange(lat_min + 1, lat_max + 1, 1)
    xticks(lat_ticks)
    lat_labels = []
    for val in lat_ticks:
        lat_labels.append(str(int(round(-val))) + r'$^{\circ}$S')
    ax.set_xticklabels(lat_labels, fontsize=14)
    depth_ticks = arange(depth_min, 0 + 50, 50)
    yticks(depth_ticks)
    depth_labels = []
    for val in depth_ticks:
        depth_labels.append(str(int(round(-val))))
    ax.set_yticklabels(depth_labels, fontsize=14)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
예제 #19
0
def mip_mld(roms_grid, roms_seasonal_file, fesom_mesh_path_lr,
            fesom_seasonal_file_lr, fesom_mesh_path_hr,
            fesom_seasonal_file_hr):

    # Path to Sallee's observations
    obs_file = '/short/m68/kaa561/Climatology_MLD003_v2017.nc'
    # Days per month
    days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    # Definition of mixed layer depth: where potential density exceeds
    # surface density by this amount (kg/m^3) as in Sallee et al 2013
    density_anom = 0.03
    # Northern boundary for ACC plot: 30S
    nbdry1 = -30 + 90
    # Northern boundary for continental shelf plot: 64S
    nbdry2 = -64 + 90
    # Degrees to radians conversion factor
    deg2rad = pi / 180.0
    # FESOM parameters
    circumpolar = True
    mask_cavities = False
    # ROMS parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31
    # Season names
    season_names = ['DJF', 'MAM', 'JJA', 'SON']
    # Maximum for colour scale in each season
    max_bound_summer = 150
    max_bound_winter = 600
    # Longitude labels for first panel
    lon_ticks = array([-120, -60, 60, 120])
    lat_ticks = array([-28, -25, -25, -28])
    lon_labels = [
        r'120$^{\circ}$W', r'60$^{\circ}$W', r'60$^{\circ}$E',
        r'120$^{\circ}$E'
    ]
    lon_rot = [-60, 60, -60, 60]

    print 'Processing MetROMS:'
    print 'Reading grid'
    id = Dataset(roms_grid, 'r')
    roms_h = id.variables['h'][:, :]
    roms_zice = id.variables['zice'][:, :]
    roms_lon = id.variables['lon_rho'][:, :]
    roms_lat = id.variables['lat_rho'][:, :]
    id.close()
    # Polar coordinates for plotting
    roms_x = -(roms_lat + 90) * cos(roms_lon * deg2rad + pi / 2)
    roms_y = (roms_lat + 90) * sin(roms_lon * deg2rad + pi / 2)
    # Longitude labels
    x_ticks = -(lat_ticks + 90) * cos(lon_ticks * deg2rad + pi / 2)
    y_ticks = (lat_ticks + 90) * sin(lon_ticks * deg2rad + pi / 2)
    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    roms_z, sc_r, Cs_r = calc_z(roms_h, roms_zice, theta_s, theta_b, hc, N)
    # Make depth positive
    roms_z = -1 * roms_z
    print 'Reading data'
    id = Dataset(roms_seasonal_file, 'r')
    roms_temp = id.variables['temp'][:, :, :, :]
    roms_salt = id.variables['salt'][:, :, :, :]
    id.close()
    print 'Calculating density'
    roms_density = unesco(roms_temp, roms_salt, zeros(shape(roms_temp)))
    print 'Calculating mixed layer depth'
    roms_mld = ma.empty([4, size(roms_lon, 0), size(roms_lon, 1)])
    # Awful triple loop here, can't find a cleaner way
    for season in range(4):
        print '...' + season_names[season]
        for j in range(size(roms_lon, 0)):
            for i in range(size(roms_lon, 1)):
                # Get surface density
                density_sfc = roms_density[season, -1, j, i]
                # Get surface depth (only nonzero in ice shelf cavities)
                depth_sfc = roms_z[-1, j, i]
                if density_sfc is ma.masked:
                    # Land
                    roms_mld[season, j, i] = ma.masked
                else:
                    # Loop downward
                    k = size(roms_density, 1) - 2
                    while True:
                        if k < 0:
                            # Reached the bottom
                            roms_mld[season, j,
                                     i] = roms_z[0, j, i] - depth_sfc
                            break
                        if roms_density[season, k, j,
                                        i] >= density_sfc + density_anom:
                            # Reached the critical density anomaly
                            roms_mld[season, j,
                                     i] = roms_z[k, j, i] - depth_sfc
                            break
                        k -= 1

    print 'Processing low-res FESOM:'
    print 'Building mesh'
    elements_lr, patches_lr = make_patches(fesom_mesh_path_lr, circumpolar,
                                           mask_cavities)
    print 'Reading data'
    id = Dataset(fesom_seasonal_file_lr, 'r')
    fesom_temp_nodes_lr = id.variables['temp'][:, :]
    fesom_salt_nodes_lr = id.variables['salt'][:, :]
    id.close()
    print 'Calculating density'
    fesom_density_nodes_lr = unesco(fesom_temp_nodes_lr, fesom_salt_nodes_lr,
                                    zeros(shape(fesom_temp_nodes_lr)))
    print 'Calculating mixed layer depth'
    # Set up array for mixed layer depth at each element, at each season
    fesom_mld_lr = zeros([4, len(elements_lr)])
    # Loop over seasons and elements to fill these in
    for season in range(4):
        print '...' + season_names[season]
        mld_season = []
        for elm in elements_lr:
            # Get mixed layer depth at each node
            mld_nodes = []
            for i in range(3):
                node = elm.nodes[i]
                density_sfc = fesom_density_nodes_lr[season, node.id]
                # Save surface depth (only nonzero in ice shelf cavities)
                depth_sfc = node.depth
                temp_depth = node.depth
                curr_node = node.below
                while True:
                    if curr_node is None:
                        # Reached the bottom
                        mld_nodes.append(temp_depth - depth_sfc)
                        break
                    if fesom_density_nodes_lr[
                            season,
                            curr_node.id] >= density_sfc + density_anom:
                        # Reached the critical density anomaly
                        mld_nodes.append(curr_node.depth - depth_sfc)
                        break
                    temp_depth = curr_node.depth
                    curr_node = curr_node.below
            # For this element, save the mean mixed layer depth
            mld_season.append(mean(array(mld_nodes)))
        fesom_mld_lr[season, :] = array(mld_season)

    print 'Processing high-res FESOM:'
    print 'Building mesh'
    elements_hr, patches_hr = make_patches(fesom_mesh_path_hr, circumpolar,
                                           mask_cavities)
    print 'Reading data'
    id = Dataset(fesom_seasonal_file_hr, 'r')
    fesom_temp_nodes_hr = id.variables['temp'][:, :]
    fesom_salt_nodes_hr = id.variables['salt'][:, :]
    id.close()
    print 'Calculating density'
    fesom_density_nodes_hr = unesco(fesom_temp_nodes_hr, fesom_salt_nodes_hr,
                                    zeros(shape(fesom_temp_nodes_hr)))
    print 'Calculating mixed layer depth'
    # Set up array for mixed layer depth at each element, at each season
    fesom_mld_hr = zeros([4, len(elements_hr)])
    # Loop over seasons and elements to fill these in
    for season in range(4):
        print '...' + season_names[season]
        mld_season = []
        for elm in elements_hr:
            # Get mixed layer depth at each node
            mld_nodes = []
            for i in range(3):
                node = elm.nodes[i]
                density_sfc = fesom_density_nodes_hr[season, node.id]
                # Save surface depth (only nonzero in ice shelf cavities)
                depth_sfc = node.depth
                temp_depth = node.depth
                curr_node = node.below
                while True:
                    if curr_node is None:
                        # Reached the bottom
                        mld_nodes.append(temp_depth - depth_sfc)
                        break
                    if fesom_density_nodes_hr[
                            season,
                            curr_node.id] >= density_sfc + density_anom:
                        # Reached the critical density anomaly
                        mld_nodes.append(curr_node.depth - depth_sfc)
                        break
                    temp_depth = curr_node.depth
                    curr_node = curr_node.below
            # For this element, save the mean mixed layer depth
            mld_season.append(mean(array(mld_nodes)))
        fesom_mld_hr[season, :] = array(mld_season)

    print 'Processing obs'
    # Read grid and monthly climatology
    id = Dataset(obs_file, 'r')
    obs_lon = id.variables['lon'][:]
    obs_lat = id.variables['lat'][:]
    obs_mld_monthly = id.variables['ML_Press'][:, :, :]
    id.close()
    # Polar coordinates for plotting
    obs_lon_2d, obs_lat_2d = meshgrid(obs_lon, obs_lat)
    obs_x = -(obs_lat_2d + 90) * cos(obs_lon_2d * deg2rad + pi / 2)
    obs_y = (obs_lat_2d + 90) * sin(obs_lon_2d * deg2rad + pi / 2)
    # Integrate seasonal averages
    obs_mld = zeros([4, size(obs_lat), size(obs_lon)])
    ndays = zeros(4)
    for month in range(12):
        if month + 1 in [12, 1, 2]:
            # DJF
            season = 0
        elif month + 1 in [3, 4, 5]:
            # MAM
            season = 1
        elif month + 1 in [6, 7, 8]:
            # JJA
            season = 2
        elif month + 1 in [9, 10, 11]:
            # SON
            season = 3
        obs_mld[season, :, :] += obs_mld_monthly[
            month, :, :] * days_per_month[month]
        ndays[season] += days_per_month[month]
    # Convert from integrals to averages
    for season in range(4):
        obs_mld[season, :, :] = obs_mld[season, :, :] / ndays[season]
    # Apply land mask
    obs_mld = ma.masked_where(isnan(obs_mld), obs_mld)

    print 'Plotting'
    # ACC
    fig1 = figure(figsize=(18, 9))
    # Summer
    # MetROMS
    ax = fig1.add_subplot(2, 4, 1, aspect='equal')
    pcolor(roms_x,
           roms_y,
           roms_mld[0, :, :],
           vmin=0,
           vmax=max_bound_summer,
           cmap='jet')
    text(-67, 0, season_names[0], fontsize=24, ha='right')
    title('MetROMS', fontsize=24)
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    # Add longitude labels
    for i in range(size(x_ticks)):
        text(x_ticks[i],
             y_ticks[i],
             lon_labels[i],
             ha='center',
             rotation=lon_rot[i],
             fontsize=12)
    ax.set_xticks([])
    ax.set_yticks([])
    # FESOM low-res
    ax = fig1.add_subplot(2, 4, 2, aspect='equal')
    img = PatchCollection(patches_lr, cmap='jet')
    img.set_array(fesom_mld_lr[0, :])
    img.set_clim(vmin=0, vmax=max_bound_summer)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    title('FESOM (low-res)', fontsize=24)
    # FESOM high-res
    ax = fig1.add_subplot(2, 4, 3, aspect='equal')
    img = PatchCollection(patches_hr, cmap='jet')
    img.set_array(fesom_mld_hr[0, :])
    img.set_clim(vmin=0, vmax=max_bound_summer)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    title('FESOM (high-res)', fontsize=24)
    # Obs
    ax = fig1.add_subplot(2, 4, 4, aspect='equal')
    img = pcolor(obs_x,
                 obs_y,
                 obs_mld[0, :, :],
                 vmin=0,
                 vmax=max_bound_summer,
                 cmap='jet')
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    title('Observations', fontsize=24)
    # Add a colorbar for summer
    cbaxes = fig1.add_axes([0.93, 0.55, 0.02, 0.3])
    cbar = colorbar(img,
                    cax=cbaxes,
                    extend='max',
                    ticks=arange(0, max_bound_summer + 50, 50))
    cbar.ax.tick_params(labelsize=20)
    # Winter
    # MetROMS
    ax = fig1.add_subplot(2, 4, 5, aspect='equal')
    pcolor(roms_x,
           roms_y,
           roms_mld[2, :, :],
           vmin=0,
           vmax=max_bound_winter,
           cmap='jet')
    text(-67, 0, season_names[2], fontsize=24, ha='right')
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    # FESOM low-res
    ax = fig1.add_subplot(2, 4, 6, aspect='equal')
    img = PatchCollection(patches_lr, cmap='jet')
    img.set_array(fesom_mld_lr[2, :])
    img.set_clim(vmin=0, vmax=max_bound_winter)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    # FESOM high-res
    ax = fig1.add_subplot(2, 4, 7, aspect='equal')
    img = PatchCollection(patches_hr, cmap='jet')
    img.set_array(fesom_mld_hr[2, :])
    img.set_clim(vmin=0, vmax=max_bound_winter)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    # Obs
    ax = fig1.add_subplot(2, 4, 8, aspect='equal')
    img = pcolor(obs_x,
                 obs_y,
                 obs_mld[2, :, :],
                 vmin=0,
                 vmax=max_bound_winter,
                 cmap='jet')
    xlim([-nbdry1, nbdry1])
    ylim([-nbdry1, nbdry1])
    ax.set_xticks([])
    ax.set_yticks([])
    # Add a colorbar for winter
    cbaxes = fig1.add_axes([0.93, 0.15, 0.02, 0.3])
    cbar = colorbar(img,
                    cax=cbaxes,
                    extend='max',
                    ticks=arange(0, max_bound_winter + 200, 200))
    cbar.ax.tick_params(labelsize=20)
    # Add the main title
    suptitle('Mixed layer depth (m), 2002-2016 average', fontsize=30)
    # Decrease space between plots
    subplots_adjust(wspace=0.025, hspace=0.025)
    fig1.show()
    fig1.savefig('mld_acc.png')

    # Continental shelf
    fig2 = figure(figsize=(13, 9))
    # Summer
    # MetROMS
    ax = fig2.add_subplot(2, 3, 1, aspect='equal')
    pcolor(roms_x,
           roms_y,
           roms_mld[0, :, :],
           vmin=0,
           vmax=max_bound_summer,
           cmap='jet')
    text(-28, 0, season_names[0], fontsize=24, ha='right')
    title('MetROMS', fontsize=24)
    xlim([-nbdry2, nbdry2])
    ylim([-nbdry2, nbdry2])
    ax.set_xticks([])
    ax.set_yticks([])
    # FESOM low-res
    ax = fig2.add_subplot(2, 3, 2, aspect='equal')
    img = PatchCollection(patches_lr, cmap='jet')
    img.set_array(fesom_mld_lr[0, :])
    img.set_clim(vmin=0, vmax=max_bound_summer)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry2, nbdry2])
    ylim([-nbdry2, nbdry2])
    ax.set_xticks([])
    ax.set_yticks([])
    title('FESOM (low-res)', fontsize=24)
    # FESOM high-res
    ax = fig2.add_subplot(2, 3, 3, aspect='equal')
    img = PatchCollection(patches_hr, cmap='jet')
    img.set_array(fesom_mld_hr[0, :])
    img.set_clim(vmin=0, vmax=max_bound_summer)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry2, nbdry2])
    ylim([-nbdry2, nbdry2])
    ax.set_xticks([])
    ax.set_yticks([])
    title('FESOM (high-res)', fontsize=24)
    # Add a colorbar for summer
    cbaxes = fig2.add_axes([0.93, 0.55, 0.02, 0.3])
    cbar = colorbar(img,
                    cax=cbaxes,
                    extend='max',
                    ticks=arange(0, max_bound_summer + 50, 50))
    cbar.ax.tick_params(labelsize=20)
    # Winter
    # MetROMS
    ax = fig2.add_subplot(2, 3, 4, aspect='equal')
    pcolor(roms_x,
           roms_y,
           roms_mld[2, :, :],
           vmin=0,
           vmax=max_bound_winter,
           cmap='jet')
    text(-28, 0, season_names[2], fontsize=24, ha='right')
    xlim([-nbdry2, nbdry2])
    ylim([-nbdry2, nbdry2])
    ax.set_xticks([])
    ax.set_yticks([])
    # FESOM low-res
    ax = fig2.add_subplot(2, 3, 5, aspect='equal')
    img = PatchCollection(patches_lr, cmap='jet')
    img.set_array(fesom_mld_lr[2, :])
    img.set_clim(vmin=0, vmax=max_bound_winter)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry2, nbdry2])
    ylim([-nbdry2, nbdry2])
    ax.set_xticks([])
    ax.set_yticks([])
    # FESOM high-res
    ax = fig2.add_subplot(2, 3, 6, aspect='equal')
    img = PatchCollection(patches_hr, cmap='jet')
    img.set_array(fesom_mld_hr[2, :])
    img.set_clim(vmin=0, vmax=max_bound_winter)
    img.set_edgecolor('face')
    ax.add_collection(img)
    xlim([-nbdry2, nbdry2])
    ylim([-nbdry2, nbdry2])
    ax.set_xticks([])
    ax.set_yticks([])
    # Add a colorbar for winter
    cbaxes = fig2.add_axes([0.93, 0.15, 0.02, 0.3])
    cbar = colorbar(img,
                    cax=cbaxes,
                    extend='max',
                    ticks=arange(0, max_bound_winter + 200, 200))
    cbar.ax.tick_params(labelsize=20)
    # Add the main title
    suptitle('Mixed layer depth (m), 2002-2016 average', fontsize=30)
    # Decrease space between plots
    subplots_adjust(wspace=0.025, hspace=0.025)
    fig2.show()
    fig2.savefig('mld_shelf.png')
예제 #20
0
def make_density_file(input_file, output_file):

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Read grid variables
    in_id = Dataset(input_file, "r")
    h = in_id.variables["h"][:, :]
    zice = in_id.variables["zice"][:, :]
    lon = in_id.variables["lon_rho"][:, :]
    lat = in_id.variables["lat_rho"][:, :]
    num_lon = size(lon, 1)
    num_lat = size(lon, 0)

    # Get a 3D array of z-coordinates (metres)
    z, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Pressure is approximately equal to |z|/10
    press = abs(z) / 10.0

    # Set up output file
    out_id = Dataset(output_file, "w")
    # Define dimensions
    out_id.createDimension("xi_rho", num_lon)
    out_id.createDimension("eta_rho", num_lat)
    out_id.createDimension("s_rho", N)
    out_id.createDimension("ocean_time", None)
    # Define variables
    out_id.createVariable("lon_rho", "f8", ("eta_rho", "xi_rho"))
    out_id.variables["lon_rho"][:, :] = lon
    out_id.createVariable("lat_rho", "f8", ("eta_rho", "xi_rho"))
    out_id.variables["lat_rho"][:, :] = lat
    out_id.createVariable("sc_r", "f8", ("s_rho"))
    out_id.variables["sc_r"].long_name = "S-coordinate at rho-points"
    out_id.variables["sc_r"][:] = sc_r
    out_id.createVariable("ocean_time", "f8", ("ocean_time"))
    out_id.variables["ocean_time"].units = "seconds"
    out_id.createVariable("rho", "f8", ("ocean_time", "s_rho", "eta_rho", "xi_rho"))
    out_id.variables["rho"].long_name = "density"
    out_id.variables["rho"].units = "kg/m^3"

    # Read time values from input file
    time = in_id.variables["ocean_time"][:]

    # Process each timestep individually to conserve memory
    for t in range(size(time)):
        print "Processing timestep " + str(t + 1) + " of " + str(size(time))
        # Set a new time value in the output file
        out_id.variables["ocean_time"][t] = time[t]
        # Read temperature and salinity (convert to float128 to prevent
        # overflow in UNESCO calculations)
        temp = ma.asarray(in_id.variables["temp"][t, :, :, :], dtype=float128)
        salt = ma.asarray(in_id.variables["salt"][t, :, :, :], dtype=float128)
        # Magic happens here
        rho = unesco(temp, salt, press)
        # Save the results for this timestep
        out_id.variables["rho"][t, :, :, :] = rho

    in_id.close()
    out_id.close()
예제 #21
0
def bugs_convection_slices():

    # Files and timesteps to plot
    file_beg = '/short/m68/kaa561/metroms_iceshelf/tmproms/run/bug_chapter/no_restoring/ocean_avg_0003.nc'
    tstep_beg = 18
    file_end = '/short/m68/kaa561/metroms_iceshelf/tmproms/run/bug_chapter/no_restoring/ocean_avg_0012.nc'
    tstep_end = 2
    # Longitude to interpolate to
    lon0 = -13
    # Deepest depth to plot
    depth_min = -250
    depth_ticks = arange(depth_min, 0 + 50, 50)
    depth_labels = []
    for depth in depth_ticks:
        depth_labels.append(str(int(-depth)))
    # Latitudes to plot
    lat_min = -74
    lat_max = -55
    lat_ticks = arange(lat_min + 4, lat_max + 5, 5)
    lat_labels = []
    for lat in lat_ticks:
        lat_labels.append(str(int(-lat)) + r'$^{\circ}$S')
    # Bounds on colour scales
    var_min = [-2, 33.9]
    var_max = [2, 34.7]
    var_tick = [1, 0.2]
    lev1 = linspace(var_min[0], var_max[0], num=50)
    lev2 = linspace(var_min[1], var_max[1], num=50)
    # Grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31
    # Month names for titles
    month_names = [
        'January', 'February', 'March', 'April', 'May', 'June', 'July',
        'August', 'September', 'October', 'November', 'December'
    ]

    # Get longitude for the title
    if lon0 < 0:
        lon_string = str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = str(int(round(lon0))) + r'$^{\circ}$E'
    # Make sure we are in the range 0-360
    if lon0 < 0:
        lon0 += 360

    # Set up figure
    fig = figure(figsize=(18, 12))
    gs = GridSpec(2, 2)
    gs.update(left=0.13,
              right=0.9,
              bottom=0.05,
              top=0.9,
              wspace=0.05,
              hspace=0.28)

    # Read 3D temperature, salinity, and grid variables at the beginning
    id = Dataset(file_beg, 'r')
    temp_3d_beg = id.variables['temp'][tstep_beg - 1, :, :, :]
    salt_3d_beg = id.variables['salt'][tstep_beg - 1, :, :, :]
    zeta_beg = id.variables['zeta'][tstep_beg - 1, :, :]
    h = id.variables['h'][:, :]
    zice = id.variables['zice'][:, :]
    lon_2d = id.variables['lon_rho'][:, :]
    lat_2d = id.variables['lat_rho'][:, :]
    # Read time axis and convert to Date objects
    time_id = id.variables['ocean_time']
    time_beg = num2date(time_id[tstep_beg - 1],
                        units=time_id.units,
                        calendar=time_id.calendar.lower())
    id.close()
    # Get a 3D array of z-coordinates
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta_beg)
    # Get the date for the title
    date_string_beg = str(
        time_beg.day) + ' ' + month_names[time_beg.month - 1] + ' ' + str(
            time_beg.year)
    # Interpolate to lon0
    temp_beg, z, lat = interp_lon_roms(temp_3d_beg, z_3d, lat_2d, lon_2d, lon0)
    salt_beg, z, lat = interp_lon_roms(salt_3d_beg, z_3d, lat_2d, lon_2d, lon0)
    # Plot temperature
    ax = subplot(gs[0, 0])
    img = contourf(lat, z, temp_beg, lev1, extend='both', cmap='jet')
    title(r'Temperature ($^{\circ}$C)', fontsize=24)
    ax.set_xlim([lat_min, lat_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels([])
    ax.set_ylim([depth_min, 0])
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels(depth_labels, fontsize=16)
    ylabel('Depth (m)', fontsize=18)
    # Plot salinity
    ax = subplot(gs[0, 1])
    img = contourf(lat, z, salt_beg, lev2, extend='both', cmap='jet')
    title('Salinity (psu)', fontsize=24)
    ax.set_xlim([lat_min, lat_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels([])
    ax.set_ylim([depth_min, 0])
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels([])
    # Label the timestep
    text(0.5,
         0.95,
         date_string_beg + ', ' + lon_string,
         ha='center',
         transform=fig.transFigure,
         fontsize=28)

    # Read 3D temperature, salinity, and sea surface height at the end
    id = Dataset(file_end, 'r')
    temp_3d_end = id.variables['temp'][tstep_end - 1, :, :, :]
    salt_3d_end = id.variables['salt'][tstep_end - 1, :, :, :]
    zeta_end = id.variables['zeta'][tstep_end - 1, :, :]
    # Read time axis and convert to Date objects
    time_id = id.variables['ocean_time']
    time_end = num2date(time_id[tstep_end - 1],
                        units=time_id.units,
                        calendar=time_id.calendar.lower())
    id.close()
    # Get a 3D array of z-coordinates
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta_end)
    # Get the date for the title
    date_string_end = str(
        time_end.day) + ' ' + month_names[time_end.month - 1] + ' ' + str(
            time_end.year)
    # Interpolate to lon0
    temp_end, z, lat = interp_lon_roms(temp_3d_end, z_3d, lat_2d, lon_2d, lon0)
    salt_end, z, lat = interp_lon_roms(salt_3d_end, z_3d, lat_2d, lon_2d, lon0)
    # Plot temperature
    ax = subplot(gs[1, 0])
    img = contourf(lat, z, temp_end, lev1, extend='both', cmap='jet')
    title(r'Temperature $^{\circ}$C)', fontsize=24)
    ax.set_xlim([lat_min, lat_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    xlabel('Latitude', fontsize=18)
    ax.set_ylim([depth_min, 0])
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels(depth_labels, fontsize=16)
    ylabel('Depth (m)', fontsize=18)
    # Colourbar
    cbaxes = fig.add_axes([0.03, 0.3, 0.02, 0.4])
    cbar = colorbar(img,
                    cax=cbaxes,
                    ticks=arange(var_min[0], var_max[0] + var_tick[0],
                                 var_tick[0]))
    cbar.ax.tick_params(labelsize=16)
    # Plot salinity
    ax = subplot(gs[1, 1])
    img = contourf(lat, z, salt_end, lev2, extend='both', cmap='jet')
    title('Salinity (psu)', fontsize=24)
    ax.set_xlim([lat_min, lat_max])
    ax.set_xticks(lat_ticks)
    ax.set_xticklabels(lat_labels, fontsize=16)
    xlabel('Latitude', fontsize=18)
    ax.set_ylim([depth_min, 0])
    ax.set_yticks(depth_ticks)
    ax.set_yticklabels([])
    # Colourbar
    cbaxes = fig.add_axes([0.93, 0.3, 0.02, 0.4])
    cbar = colorbar(img,
                    cax=cbaxes,
                    ticks=arange(var_min[1], var_max[1] + var_tick[1],
                                 var_tick[1]))
    cbar.ax.tick_params(labelsize=16)
    # Label the timestep
    text(0.5,
         0.47,
         date_string_end + ', ' + lon_string,
         ha='center',
         transform=fig.transFigure,
         fontsize=28)
    fig.show()
    fig.savefig('bugs_convection_slices.png')
예제 #22
0
def sose_roms_seasonal (file_path, var_name, lon0, depth_bdry, save=False, fig_name=None):

    # Path to SOSE seasonal climatology file
    sose_file = '../SOSE_seasonal_climatology.nc'

    # Grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31

    # Season names for titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Bounds on colour scale
    if var_name == 'temp':
        var_min = -2.5
        var_max = 7.5
        var_ticks = 1
    elif var_name == 'salt':
        var_min = 33.6 #33.8 #33.6
        var_max = 35.0 #34.8 #35.0
        var_ticks = 0.4 #0.2 #0.4
    else:
        print 'Unknown variable ' + var_name
        return

    # Choose what to write on the title about the variable
    if var_name == 'temp':
        var_string = r'Temperature ($^{\circ}$C)'
    elif var_name == 'salt':
        var_string = 'Salinity (psu)'
    # Choose what to write on the title about longitude
    if lon0 < 0:
        lon_string = ' at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = ' at ' + str(int(round(lon0))) + r'$^{\circ}$E'
    # Edit longitude bounds to be from 0 to 360, to fit with ROMS convention
    if lon0 < 0:
        lon0 += 360

    print 'Processing ROMS data'

    # Read grid
    id = Dataset(file_path, 'r')
    h = id.variables['h'][:-15,:]
    zice = id.variables['zice'][:-15,:]
    lon_roms_2d = id.variables['lon_rho'][:-15,:]
    lat_roms_2d = id.variables['lat_rho'][:-15,:]
    num_lon = id.variables['lon_rho'].shape[1]
    num_lat = id.variables['lat_rho'].shape[0]
    id.close()

    # Calculate seasonal averages of ROMS data
    var_3d_roms = seasonal_avg_roms(file_path, var_name, [N, num_lat, num_lon])
    # Chop off northern boundary
    var_3d_roms = var_3d_roms[:,:,:-15,:]

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)

    # Calculate zonal slices for each season
    var_roms = ma.empty([4, N, size(lat_roms_2d,0)])
    var_roms[:,:,:] = 0.0
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        var_tmp, z_roms, lat_roms = interp_lon_roms(var_3d_roms[season,:,:,:], z_roms_3d, lat_roms_2d, lon_roms_2d, lon0)
        var_roms[season,:,:] = var_tmp

    print 'Processing SOSE data'

    # Read grid and 3D data (already seasonally averaged)
    id = Dataset(sose_file, 'r')
    lon_sose = id.variables['longitude'][0,:]
    lat_sose = id.variables['latitude'][:,0]
    z_sose = id.variables['depth'][:]
    var_3d_sose = id.variables[var_name][:,:,:,:]

    # Calculate zonal slices for each season
    var_sose = ma.empty([4, size(z_sose), size(lat_sose,0)])
    var_sose[:,:,:] = 0.0
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        var_sose[season,:,:] = interp_lon_sose(var_3d_sose[season,:,:,:], lon_sose, lon0)

    # Set colour levels
    lev = linspace(var_min, var_max, num=50)

    # Choose southern boundary based on extent of SOSE grid
    sbdry = amin(lat_sose)
    # Choose northern boundary based on extent of ROMS grid
    nbdry = amax(lat_roms)

    # Plot
    print 'Plotting'
    fig = figure(figsize=(20,9))
    # Loop over seasons
    for season in range(4):
        # ROMS
        fig.add_subplot(2, 4, season+1)
        img = contourf(lat_roms, z_roms, var_roms[season,:,:], lev, cmap='jet', extend='both')
        xlim([sbdry, nbdry])
        ylim([depth_bdry, 0])
        title('ROMS (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
        # SOSE
        fig.add_subplot(2, 4, season+5)
        contourf(lat_sose, z_sose, var_sose[season,:,:], lev, cmap='jet', extend='both')
        xlim([sbdry, nbdry])
        ylim([depth_bdry, 0])
        title('SOSE (' + season_names[season] + ')', fontsize=24)
        xlabel('Latitude', fontsize=18)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
    # Add colourbar
    cbaxes = fig.add_axes([0.93, 0.2, 0.015, 0.6])
    cbar = colorbar(img, cax=cbaxes, ticks=arange(var_min, var_max+var_ticks, var_ticks))
    cbar.ax.tick_params(labelsize=16)
    # Add the main title
    suptitle(var_string + lon_string, fontsize=30)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()    
예제 #23
0
def make_density_file(input_file, output_file):

    # Grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31

    # Read grid variables
    in_id = Dataset(input_file, 'r')
    h = in_id.variables['h'][:, :]
    zice = in_id.variables['zice'][:, :]
    lon = in_id.variables['lon_rho'][:, :]
    lat = in_id.variables['lat_rho'][:, :]
    num_lon = size(lon, 1)
    num_lat = size(lon, 0)

    # Get a 3D array of z-coordinates (metres)
    z, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Pressure is approximately equal to |z|/10
    press = abs(z) / 10.0

    # Set up output file
    out_id = Dataset(output_file, 'w')
    # Define dimensions
    out_id.createDimension('xi_rho', num_lon)
    out_id.createDimension('eta_rho', num_lat)
    out_id.createDimension('s_rho', N)
    out_id.createDimension('ocean_time', None)
    # Define variables
    out_id.createVariable('lon_rho', 'f8', ('eta_rho', 'xi_rho'))
    out_id.variables['lon_rho'][:, :] = lon
    out_id.createVariable('lat_rho', 'f8', ('eta_rho', 'xi_rho'))
    out_id.variables['lat_rho'][:, :] = lat
    out_id.createVariable('sc_r', 'f8', ('s_rho'))
    out_id.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_id.variables['sc_r'][:] = sc_r
    out_id.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_id.variables['ocean_time'].units = 'seconds'
    out_id.createVariable('rho', 'f8',
                          ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_id.variables['rho'].long_name = 'density'
    out_id.variables['rho'].units = 'kg/m^3'

    # Read time values from input file
    time = in_id.variables['ocean_time'][:]

    # Process each timestep individually to conserve memory
    for t in range(size(time)):
        print 'Processing timestep ' + str(t + 1) + ' of ' + str(size(time))
        # Set a new time value in the output file
        out_id.variables['ocean_time'][t] = time[t]
        # Read temperature and salinity (convert to float128 to prevent
        # overflow in UNESCO calculations)
        temp = ma.asarray(in_id.variables['temp'][t, :, :, :], dtype=float128)
        salt = ma.asarray(in_id.variables['salt'][t, :, :, :], dtype=float128)
        # Magic happens here
        rho = unesco(temp, salt, press)
        # Save the results for this timestep
        out_id.variables['rho'][t, :, :, :] = rho

    in_id.close()
    out_id.close()
예제 #24
0
def run (grid_file, theta_file, salt_file, output_file, Tcline, theta_s, theta_b, hc, N, nbdry_ecco):

    # Read ECCO2 data and grid
    print 'Reading ECCO2 data'
    theta_fid = Dataset(theta_file, 'r')
    lon_ecco_raw = theta_fid.variables['LONGITUDE_T'][:]
    lat_ecco = theta_fid.variables['LATITUDE_T'][0:nbdry_ecco]
    depth_ecco_raw = theta_fid.variables['DEPTH_T'][:]
    theta_raw = transpose(theta_fid.variables['THETA'][0,:,0:nbdry_ecco,:])
    theta_fid.close()
    salt_fid = Dataset(salt_file, 'r')
    salt_raw = transpose(salt_fid.variables['SALT'][0,:,0:nbdry_ecco,:])
    salt_fid.close()

    # The ECCO2 longitude axis doesn't wrap around; there is a gap between
    # almost-180W and almost-180E, and the ROMS grid has points in this gap.
    # So copy the last longitude value (mod 360) to the beginning, and the
    # first longitude value (mod 360) to the end.
    lon_ecco = zeros(size(lon_ecco_raw)+2)
    lon_ecco[0] = lon_ecco_raw[-1]-360
    lon_ecco[1:-1] = lon_ecco_raw
    lon_ecco[-1] = lon_ecco_raw[0]+360

    # The shallowest ECCO2 depth value is 5 m, but ROMS needs 0 m. So add the
    # index depth = 0 m to the beginning. Later we will just copy the 5 m values
    # for theta and salt into this index. Similarly, add the index depth = 6000 m
    # to the end.
    depth_ecco = zeros(size(depth_ecco_raw)+2)
    depth_ecco[0] = 0.0
    depth_ecco[1:-1] = depth_ecco_raw
    depth_ecco[-1] = 6000.0

    # Copy the theta and salt values to the new longitude and depth indices,
    # making sure to preserve the mask.
    theta = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
    theta[1:-1,:,1:-1] = ma.copy(theta_raw)
    theta[0,:,1:-1] = ma.copy(theta_raw[-1,:,:])
    theta[-1,:,1:-1] = ma.copy(theta_raw[0,:,:])
    theta[:,:,0] = ma.copy(theta[:,:,1])
    theta[:,:,-1] = ma.copy(theta[:,:,-2])
    salt = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
    salt[1:-1,:,1:-1] = ma.copy(salt_raw)
    salt[0,:,1:-1] = ma.copy(salt_raw[-1,:,:])
    salt[-1,:,1:-1] = ma.copy(salt_raw[0,:,:])
    salt[:,:,0] = ma.copy(salt[:,:,1])
    salt[:,:,-1] = ma.copy(salt[:,:,-2])

    # Read ROMS grid
    print 'Reading ROMS grid'
    grid_fid = Dataset(grid_file, 'r')
    lon_roms = grid_fid.variables['lon_rho'][:,:]
    lat_roms = grid_fid.variables['lat_rho'][:,:]
    h = grid_fid.variables['h'][:,:]
    zice = grid_fid.variables['zice'][:,:]
    mask_rho = grid_fid.variables['mask_rho'][:,:]
    mask_zice = grid_fid.variables['mask_zice'][:,:]
    grid_fid.close()
    num_lon = size(lon_roms, 1)
    num_lat = size(lon_roms, 0)
    # Mask h and zice with zeros
    h = h*mask_rho
    zice = zice*mask_zice

    # Get a 3D array of ROMS z-coordinates, as well as 1D arrays of s-coordinates
    # and stretching curves
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Copy the latitude and longitude values into 3D arrays of the same shape
    lon_roms_3d = tile(lon_roms, (N,1,1))
    lat_roms_3d = tile(lat_roms, (N,1,1))

    # Regridding happens here...
    print 'Interpolating temperature'
    temp = interp_ecco2roms(theta, lon_ecco, lat_ecco, depth_ecco, lon_roms_3d, lat_roms_3d, z_roms_3d, mask_rho, mask_zice, -0.5)
    print 'Interpolating salinity'
    salt = interp_ecco2roms(salt, lon_ecco, lat_ecco, depth_ecco, lon_roms_3d, lat_roms_3d, z_roms_3d, mask_rho, mask_zice, 34.5)

    # Set initial velocities and sea surface height to zero
    u = zeros((N, num_lat, num_lon-1))
    v = zeros((N, num_lat-1, num_lon))
    ubar = zeros((num_lat, num_lon-1))
    vbar = zeros((num_lat-1, num_lon))
    zeta = zeros((num_lat, num_lon))

    print 'Writing to NetCDF file'
    out_fid = Dataset(output_file, 'w')
    # Define dimensions
    out_fid.createDimension('xi_u', num_lon-1)
    out_fid.createDimension('xi_v', num_lon)
    out_fid.createDimension('xi_rho', num_lon)
    out_fid.createDimension('eta_u', num_lat)
    out_fid.createDimension('eta_v', num_lat-1)
    out_fid.createDimension('eta_rho', num_lat)
    out_fid.createDimension('s_rho', N)
    out_fid.createDimension('ocean_time', None)
    out_fid.createDimension('one', 1);
    # Define variables and assign values
    out_fid.createVariable('tstart', 'f8', ('one'))
    out_fid.variables['tstart'].long_name = 'start processing day'
    out_fid.variables['tstart'].units = 'day'
    out_fid.variables['tstart'][:] = 0.0
    out_fid.createVariable('tend', 'f8', ('one'))
    out_fid.variables['tend'].long_name = 'end processing day'
    out_fid.variables['tend'].units = 'day'
    out_fid.variables['tend'][:] = 0.0
    out_fid.createVariable('theta_s', 'f8', ('one'))
    out_fid.variables['theta_s'].long_name = 'S-coordinate surface control parameter'
    out_fid.variables['theta_s'][:] = theta_s
    out_fid.createVariable('theta_b', 'f8', ('one'))
    out_fid.variables['theta_b'].long_name = 'S-coordinate bottom control parameter'
    out_fid.variables['theta_b'].units = 'nondimensional'
    out_fid.variables['theta_b'][:] = theta_b
    out_fid.createVariable('Tcline', 'f8', ('one'))
    out_fid.variables['Tcline'].long_name = 'S-coordinate surface/bottom layer width'
    out_fid.variables['Tcline'].units = 'meter'
    out_fid.variables['Tcline'][:] = Tcline
    out_fid.createVariable('hc', 'f8', ('one'))
    out_fid.variables['hc'].long_name = 'S-coordinate parameter, critical depth'
    out_fid.variables['hc'].units = 'meter'
    out_fid.variables['hc'][:] = hc
    out_fid.createVariable('Cs_r', 'f8', ('s_rho'))
    out_fid.variables['Cs_r'].long_name = 'S-coordinate stretching curves at RHO-points'
    out_fid.variables['Cs_r'].units = 'nondimensional'
    out_fid.variables['Cs_r'].valid_min = -1.0
    out_fid.variables['Cs_r'].valid_max = 0.0
    out_fid.variables['Cs_r'][:] = Cs_r
    out_fid.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_fid.variables['ocean_time'].long_name = 'time since initialization'
    out_fid.variables['ocean_time'].units = 'seconds'
    out_fid.variables['ocean_time'][0] = 0.0
    out_fid.createVariable('u', 'f8', ('ocean_time', 's_rho', 'eta_u', 'xi_u'))
    out_fid.variables['u'].long_name = 'u-momentum component'
    out_fid.variables['u'].units = 'meter second-1'
    out_fid.variables['u'][0,:,:,:] = u
    out_fid.createVariable('v', 'f8', ('ocean_time', 's_rho', 'eta_v', 'xi_v'))
    out_fid.variables['v'].long_name = 'v-momentum component'
    out_fid.variables['v'].units = 'meter second-1'
    out_fid.variables['v'][0,:,:,:] = v
    out_fid.createVariable('ubar', 'f8', ('ocean_time', 'eta_u', 'xi_u'))
    out_fid.variables['ubar'].long_name = 'vertically integrated u-momentum component'
    out_fid.variables['ubar'].units = 'meter second-1'
    out_fid.variables['ubar'][0,:,:] = ubar
    out_fid.createVariable('vbar', 'f8', ('ocean_time', 'eta_v', 'xi_v'))
    out_fid.variables['vbar'].long_name = 'vertically integrated v-momentum component'
    out_fid.variables['vbar'].units = 'meter second-1'
    out_fid.variables['vbar'][0,:,:] = vbar
    out_fid.createVariable('zeta', 'f8', ('ocean_time', 'eta_rho', 'xi_rho'))
    out_fid.variables['zeta'].long_name = 'free-surface'
    out_fid.variables['zeta'].units = 'meter'
    out_fid.variables['zeta'][0,:,:] = zeta
    out_fid.createVariable('temp', 'f8', ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_fid.variables['temp'].long_name = 'potential temperature'
    out_fid.variables['temp'].units = 'Celsius'
    out_fid.variables['temp'][0,:,:,:] = temp
    out_fid.createVariable('salt', 'f8', ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_fid.variables['salt'].long_name = 'salinity'
    out_fid.variables['salt'].units = 'PSU'
    out_fid.variables['salt'][0,:,:,:] = salt
    out_fid.createVariable('sc_r', 'f8', ('s_rho'))
    out_fid.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_fid.variables['sc_r'].units = 'nondimensional'
    out_fid.variables['sc_r'].valid_min = -1.0
    out_fid.variables['sc_r'].valid_max = 0.0
    out_fid.variables['sc_r'][:] = sc_r
    out_fid.close()

    print 'Finished'
예제 #25
0
def run(grid_file, woa_file, output_file, Tcline, theta_s, theta_b, hc, N,
        nbdry_woa):

    # Read WOA data and grid
    print 'Reading World Ocean Atlas data'
    woa_id = Dataset(woa_file, 'r')
    lon_woa = woa_id.variables['longitude'][:]
    lat_woa = woa_id.variables['latitude'][:nbdry_woa]
    depth_woa = woa_id.variables['depth'][:]
    temp_woa = transpose(woa_id.variables['temp'][:, :nbdry_woa, :])
    salt_woa = transpose(woa_id.variables['salt'][:, :nbdry_woa, :])
    woa_id.close()

    # Read ROMS grid
    print 'Reading ROMS grid'
    grid_id = Dataset(grid_file, 'r')
    lon_roms = grid_id.variables['lon_rho'][:, :]
    lat_roms = grid_id.variables['lat_rho'][:, :]
    h = grid_id.variables['h'][:, :]
    zice = grid_id.variables['zice'][:, :]
    mask_rho = grid_id.variables['mask_rho'][:, :]
    mask_zice = grid_id.variables['mask_zice'][:, :]
    grid_id.close()
    num_lon = size(lon_roms, 1)
    num_lat = size(lon_roms, 0)
    # Mask h and zice with zeros
    h = h * mask_rho
    zice = zice * mask_zice

    # Get 3D array of ROMS z-coordinates, as well as 1D arrays of s-coordinates
    # and stretching curves
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)
    # Copy the latitude and longitude values into 3D arrays of the same shape
    lon_roms_3d = tile(lon_roms, (N, 1, 1))
    lat_roms_3d = tile(lat_roms, (N, 1, 1))

    # Regridding happens here
    print 'Interpolating temperature'
    temp = interp_woa2roms(temp_woa, lon_woa, lat_woa, depth_woa, lon_roms_3d,
                           lat_roms_3d, z_roms_3d, mask_rho, mask_zice, -0.5)
    print 'Interpolating salinity'
    salt = interp_woa2roms(salt_woa, lon_woa, lat_woa, depth_woa, lon_roms_3d,
                           lat_roms_3d, z_roms_3d, mask_rho, mask_zice, 34.5)

    # Set initial velocities and sea surface height to zero
    u = zeros((N, num_lat, num_lon - 1))
    v = zeros((N, num_lat - 1, num_lon))
    ubar = zeros((num_lat, num_lon - 1))
    vbar = zeros((num_lat - 1, num_lon))
    zeta = zeros((num_lat, num_lon))

    print 'Writing to NetCDF file'
    out_id = Dataset(output_file, 'w')
    # Define dimensions
    out_id.createDimension('xi_u', num_lon - 1)
    out_id.createDimension('xi_v', num_lon)
    out_id.createDimension('xi_rho', num_lon)
    out_id.createDimension('eta_u', num_lat)
    out_id.createDimension('eta_v', num_lat - 1)
    out_id.createDimension('eta_rho', num_lat)
    out_id.createDimension('s_rho', N)
    out_id.createDimension('ocean_time', None)
    out_id.createDimension('one', 1)
    # Define variables and assign values
    out_id.createVariable('tstart', 'f8', ('one'))
    out_id.variables['tstart'].long_name = 'start processing day'
    out_id.variables['tstart'].units = 'day'
    out_id.variables['tstart'][:] = 0.0
    out_id.createVariable('tend', 'f8', ('one'))
    out_id.variables['tend'].long_name = 'end processing day'
    out_id.variables['tend'].units = 'day'
    out_id.variables['tend'][:] = 0.0
    out_id.createVariable('theta_s', 'f8', ('one'))
    out_id.variables[
        'theta_s'].long_name = 'S-coordinate surface control parameter'
    out_id.variables['theta_s'][:] = theta_s
    out_id.createVariable('theta_b', 'f8', ('one'))
    out_id.variables[
        'theta_b'].long_name = 'S-coordinate bottom control parameter'
    out_id.variables['theta_b'].units = 'nondimensional'
    out_id.variables['theta_b'][:] = theta_b
    out_id.createVariable('Tcline', 'f8', ('one'))
    out_id.variables[
        'Tcline'].long_name = 'S-coordinate surface/bottom layer width'
    out_id.variables['Tcline'].units = 'meter'
    out_id.variables['Tcline'][:] = Tcline
    out_id.createVariable('hc', 'f8', ('one'))
    out_id.variables['hc'].long_name = 'S-coordinate parameter, critical depth'
    out_id.variables['hc'].units = 'meter'
    out_id.variables['hc'][:] = hc
    out_id.createVariable('Cs_r', 'f8', ('s_rho'))
    out_id.variables[
        'Cs_r'].long_name = 'S-coordinate stretching curves at RHO-points'
    out_id.variables['Cs_r'].units = 'nondimensional'
    out_id.variables['Cs_r'].valid_min = -1.0
    out_id.variables['Cs_r'].valid_max = 0.0
    out_id.variables['Cs_r'][:] = Cs_r
    out_id.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_id.variables['ocean_time'].long_name = 'time since initialization'
    out_id.variables['ocean_time'].units = 'seconds'
    out_id.variables['ocean_time'][0] = 0.0
    out_id.createVariable('u', 'f8', ('ocean_time', 's_rho', 'eta_u', 'xi_u'))
    out_id.variables['u'].long_name = 'u-momentum component'
    out_id.variables['u'].units = 'meter second-1'
    out_id.variables['u'][0, :, :, :] = u
    out_id.createVariable('v', 'f8', ('ocean_time', 's_rho', 'eta_v', 'xi_v'))
    out_id.variables['v'].long_name = 'v-momentum component'
    out_id.variables['v'].units = 'meter second-1'
    out_id.variables['v'][0, :, :, :] = v
    out_id.createVariable('ubar', 'f8', ('ocean_time', 'eta_u', 'xi_u'))
    out_id.variables[
        'ubar'].long_name = 'vertically integrated u-momentum component'
    out_id.variables['ubar'].units = 'meter second-1'
    out_id.variables['ubar'][0, :, :] = ubar
    out_id.createVariable('vbar', 'f8', ('ocean_time', 'eta_v', 'xi_v'))
    out_id.variables[
        'vbar'].long_name = 'vertically integrated v-momentum component'
    out_id.variables['vbar'].units = 'meter second-1'
    out_id.variables['vbar'][0, :, :] = vbar
    out_id.createVariable('zeta', 'f8', ('ocean_time', 'eta_rho', 'xi_rho'))
    out_id.variables['zeta'].long_name = 'free-surface'
    out_id.variables['zeta'].units = 'meter'
    out_id.variables['zeta'][0, :, :] = zeta
    out_id.createVariable('temp', 'f8',
                          ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_id.variables['temp'].long_name = 'potential temperature'
    out_id.variables['temp'].units = 'Celsius'
    out_id.variables['temp'][0, :, :, :] = temp
    out_id.createVariable('salt', 'f8',
                          ('ocean_time', 's_rho', 'eta_rho', 'xi_rho'))
    out_id.variables['salt'].long_name = 'salinity'
    out_id.variables['salt'].units = 'PSU'
    out_id.variables['salt'][0, :, :, :] = salt
    out_id.createVariable('sc_r', 'f8', ('s_rho'))
    out_id.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_id.variables['sc_r'].units = 'nondimensional'
    out_id.variables['sc_r'].valid_min = -1.0
    out_id.variables['sc_r'].valid_max = 0.0
    out_id.variables['sc_r'][:] = sc_r
    out_id.close()
예제 #26
0
def adv_ross_tsplots():

    # Paths to simulation directories
    paths = [
        '/short/m68/kaa561/advection/u3_lim/',
        '/short/m68/kaa561/advection/c4_l/'
    ]
    # Titles for plotting
    labels = [
        r'a) Temperature ($^{\circ}$C), U3_LIM',
        r'b) Temperature ($^{\circ}$C), C4_LD - U3_LIM',
        'c) Salinity (psu), U3_LIM', 'd) Salinity (psu), C4_LD - U3_LIM'
    ]
    # File name: daily average for 31 December
    file_tail = 'ocean_avg_0001.nc'
    var_names = ['temp', 'salt']
    # If 31 December doesn't have its own file, put the time index here
    tstep = 366
    # Longitude to interpolate to
    lon0 = 180
    # Deepest depth to plot
    depth_min = -350
    # Bounds and ticks for colour scales
    abs_min = [-2, 33.8]
    abs_max = [3, 34.8]
    abs_ticks = [1, 0.2]
    anom_min = [-1.5, -0.15]
    anom_max = [1.5, 0.15]
    anom_ticks = [0.5, 0.05]
    # Bounds on latitude
    lat_min = -80
    lat_max = -60
    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31
    Vstretching = 2

    # Set up figure
    fig = figure(figsize=(18, 12))
    # Loop over variables (temp and salt)
    for var in range(2):
        # Read 3D variable
        id = Dataset(paths[0] + file_tail, 'r')
        data_3d = id.variables[var_names[var]][tstep - 1, :, :, :]
        # Also read sea surface height
        zeta = id.variables['zeta'][tstep - 1, :, :]
        if var == 0:
            # For the first simulation, read grid variables
            h = id.variables['h'][:, :]
            zice = id.variables['zice'][:, :]
            lon_2d = id.variables['lon_rho'][:, :]
            lat_2d = id.variables['lat_rho'][:, :]
        id.close()
        # Calculate 3D z-coordinates
        z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta,
                                  Vstretching)
        # Interpolate temp/salt, z-coordinates, and latitude to 180E
        data0, z, lat = interp_lon_roms(data_3d, z_3d, lat_2d, lon_2d, lon0)
        ax = fig.add_subplot(2, 2, 2 * var + 1)
        # Shade data (pcolor not contourf so we don't misrepresent the
        # model grid)
        img = pcolor(lat,
                     z,
                     data0,
                     vmin=abs_min[var],
                     vmax=abs_max[var],
                     cmap='jet')
        # Add title
        title(labels[2 * var], fontsize=24)
        # Label axes
        if var == 1:
            xlabel('Latitude', fontsize=18)
        ylabel('Depth (m)', fontsize=18)
        xlim([lat_min, lat_max])
        ylim([depth_min, 0])
        # Add colorbars for each variable
        if var == 0:
            cbaxes = fig.add_axes([0.02, 0.575, 0.01, 0.3])
        elif var == 1:
            cbaxes = fig.add_axes([0.02, 0.125, 0.01, 0.3])
        cbar = colorbar(img,
                        ticks=arange(abs_min[var],
                                     abs_max[var] + abs_ticks[var],
                                     abs_ticks[var]),
                        cax=cbaxes,
                        extend='both')
        cbar.ax.tick_params(labelsize=18)
        # Set ticks the way we want them
        lat_ticks = arange(lat_min + 5, lat_max + 5, 5)
        ax.set_xticks(lat_ticks)
        lat_labels = []
        for val in lat_ticks:
            lat_labels.append(str(int(round(-val))) + r'$^{\circ}$S')
        ax.set_xticklabels(lat_labels, fontsize=18)
        depth_ticks = range(depth_min + 50, 0 + 100, 100)
        ax.set_yticks(depth_ticks)
        depth_labels = []
        for val in depth_ticks:
            depth_labels.append(str(int(round(-val))))
        ax.set_yticklabels(depth_labels, fontsize=18)

        # Now calculate anomalies for C4_LD simulation
        id = Dataset(paths[1] + file_tail, 'r')
        data_3d = id.variables[var_names[var]][tstep - 1, :, :, :]
        # Also read sea surface height
        zeta = id.variables['zeta'][tstep - 1, :, :]
        id.close()
        # Calculate 3D z-coordinates
        z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta,
                                  Vstretching)
        # Interpolate temp/salt, z-coordinates, and latitude to 180E
        data1, z, lat = interp_lon_roms(data_3d, z_3d, lat_2d, lon_2d, lon0)
        # Get anomaly
        data = data1 - data0
        ax = fig.add_subplot(2, 2, 2 * var + 2)
        # Shade data (pcolor not contourf so we don't misrepresent the
        # model grid)
        img = pcolor(lat,
                     z,
                     data,
                     vmin=anom_min[var],
                     vmax=anom_max[var],
                     cmap='RdBu_r')
        # Add title
        title(labels[2 * var + 1], fontsize=24)
        # Label axes
        if var == 1:
            xlabel('Latitude', fontsize=18)
        xlim([lat_min, lat_max])
        ylim([depth_min, 0])
        # Add colorbars for each variable
        if var == 0:
            cbaxes = fig.add_axes([0.93, 0.575, 0.01, 0.3])
        elif var == 1:
            cbaxes = fig.add_axes([0.93, 0.125, 0.01, 0.3])
        cbar = colorbar(img,
                        ticks=arange(anom_min[var],
                                     anom_max[var] + anom_ticks[var],
                                     anom_ticks[var]),
                        cax=cbaxes,
                        extend='both')
        cbar.ax.tick_params(labelsize=18)
        # Set ticks the way we want them
        lat_ticks = arange(lat_min + 5, lat_max + 5, 5)
        ax.set_xticks(lat_ticks)
        lat_labels = []
        for val in lat_ticks:
            lat_labels.append(str(int(round(-val))) + r'$^{\circ}$S')
        ax.set_xticklabels(lat_labels, fontsize=18)
        depth_ticks = range(depth_min + 50, 0 + 100, 100)
        ax.set_yticks(depth_ticks)
        depth_labels = []
        for val in depth_ticks:
            depth_labels.append(str(int(round(-val))))
        ax.set_yticklabels(depth_labels, fontsize=18)

    # Main title
    suptitle(r'180$^{\circ}$E, 31 December (Ross Sea)', fontsize=30)
    #fig.show()
    fig.savefig('adv_ross_tsplots.png')
예제 #27
0
def temp_salt_slice(file_path,
                    tstep,
                    lon0,
                    depth_min,
                    save=False,
                    fig_name=None):

    # Grid parameters
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31

    # Month names for titles
    month_names = [
        'January', 'February', 'March', 'April', 'May', 'June', 'July',
        'August', 'September', 'October', 'November', 'December'
    ]

    # Bounds on colour scales for temperature and salinity
    var_min = [-2, 33.8]
    var_max = [3, 34.8]
    var_tick = [1, 0.2]

    # Read temperature, salinity, and grid variables
    id = Dataset(file_path, 'r')
    temp_3d = id.variables['temp'][tstep - 1, :, :-15, :]
    salt_3d = id.variables['salt'][tstep - 1, :, :-15, :]
    zeta = id.variables['zeta'][tstep - 1, :-15, :]
    h = id.variables['h'][:-15, :]
    zice = id.variables['zice'][:-15, :]
    lon_2d = id.variables['lon_rho'][:-15, :]
    lat_2d = id.variables['lat_rho'][:-15, :]
    # Read time axis and convert to Date objects
    time_id = id.variables['ocean_time']
    time = num2date(time_id[tstep - 1],
                    units=time_id.units,
                    calendar=time_id.calendar.lower())
    id.close()

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)

    # Get the date for the title
    date_string = str(
        time.day) + ' ' + month_names[time.month - 1] + ' ' + str(time.year)

    # Get longitude for the title
    if lon0 < 0:
        lon_string = str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = str(int(round(lon0))) + r'$^{\circ}$E'

    # Make sure we are in the range 0-360
    if lon0 < 0:
        lon0 += 360

    # Interpolate temperature, salinity, z, and latitude to lon0
    temp, z, lat = interp_lon_roms(temp_3d, z_3d, lat_2d, lon_2d, lon0)
    salt, z, lat = interp_lon_roms(salt_3d, z_3d, lat_2d, lon_2d, lon0)

    # Choose latitude bounds based on land mask
    temp_sum = sum(temp, axis=0)
    # Find southernmost and northernmost unmasked j-indices
    edges = ma.flatnotmasked_edges(temp_sum)
    j_min = edges[0]
    j_max = edges[1]
    if j_min == 0:
        # There are ocean points right to the southern boundary
        # Don't do anything special
        lat_min = min(lat[:, j_min])
    else:
        # There is land everywhere at the southern boundary
        # Show the last 2 degrees of this land mask
        lat_min = min(lat[:, j_min]) - 2
    if j_max == size(temp_sum) - 1:
        # There are ocean points right to the northern boundary
        # Don't do anything special
        lat_max = max(lat[:, j_max])
    else:
        # There is land everywhere at the northern boundary
        # Show the first 2 degrees of this land mask
        lat_max = max(lat[:, j_max]) + 2

    # Colour levels
    lev1 = linspace(var_min[0], var_max[0], num=50)
    lev2 = linspace(var_min[1], var_max[1], num=50)

    # Plot
    fig = figure(figsize=(24, 6))
    # Temperature
    ax = fig.add_subplot(1, 2, 1)
    img1 = contourf(lat, z, temp, lev1, extend='both')
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])
    xlabel('Latitude')
    ylabel('Depth (m)')
    title(r'Temperature ($^{\circ}$C)', fontsize=20)
    cbar1 = colorbar(img1,
                     ticks=arange(var_min[0], var_max[0] + var_tick[0],
                                  var_tick[0]))
    cbar1.ax.tick_params(labelsize=16)
    # Salinity
    ax = fig.add_subplot(1, 2, 2)
    img2 = contourf(lat, z, salt, lev2, extend='both')
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])
    xlabel('Latitude')
    ylabel('Depth (m)')
    title('Salinity (psu)', fontsize=20)
    cbar2 = colorbar(img2,
                     ticks=arange(var_min[1], var_max[1] + var_tick[1],
                                  var_tick[1]))
    cbar2.ax.tick_params(labelsize=16)
    suptitle(date_string + ', ' + lon_string, fontsize=24)
    subplots_adjust(wspace=0.025)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()

    # Convert back to the range -180 to 180, in case this script repeats
    if lon0 > 180:
        lon0 -= 360
예제 #28
0
def convert_file (year):

    # Make sure input argument is an integer (sometimes the batch script likes
    # to pass it as a string)
    year = int(year)

    # Paths of ROMS grid file, input ECCO2 files (without the tail yyyymm.nc),
    # and output ROMS-CICE boundary condition file; other users will need to
    # change these
    grid_file = '../metroms_iceshelf/apps/common/grid/circ30S_quarterdegree.nc'
    theta_base = '../metroms_iceshelf/data/originals/ECCO2/THETA.1440x720x50.' + str(year)
    salt_base = '../metroms_iceshelf/data/originals/ECCO2/SALT.1440x720x50.' + str(year)
    vvel_base = '../metroms_iceshelf/data/originals/ECCO2/VVEL.1440x720x50.' + str(year)
    output_file = '../metroms_iceshelf/data/ECCO2/ecco2_cube92_lbc_' + str(year) + '.nc'

    # Grid parameters; check grid_file and *.in to make sure these are correct
    theta_s = 7.0
    theta_b = 2.0
    hc = 250
    N = 31
    # Northernmost index of ECCO2 grid to read (1-based)
    nbdry_ecco = 241

    # Read ECCO2 grid
    print 'Reading ECCO2 grid'
    ecco_fid = Dataset(theta_base + '01.nc', 'r')
    lon_ecco_raw = ecco_fid.variables['LONGITUDE_T'][:]
    lat_ecco = ecco_fid.variables['LATITUDE_T'][0:nbdry_ecco]
    depth_ecco_raw = ecco_fid.variables['DEPTH_T'][:]
    ecco_fid.close()

    # The ECCO2 longitude axis doesn't wrap around; there is a gap between
    # almost-180W and almost-180E, and the ROMS grid has points in this gap.
    # So copy the last longitude value (mod 360) to the beginning, and the
    # first longitude value (mod 360) to the end.
    lon_ecco = zeros(size(lon_ecco_raw)+2)
    lon_ecco[0] = lon_ecco_raw[-1]-360
    lon_ecco[1:-1] = lon_ecco_raw
    lon_ecco[-1] = lon_ecco_raw[0]+360

    # The shallowest ECCO2 depth value is 5 m, but ROMS needs 0 m. So add the
    # index depth = 0 m to the beginning. Later we will just copy the 5 m
    # values for theta and salt into this index. Similarly, the deepest ECCO2
    # depth value is not deep enough for ROMS, so make a 6000 m index at the end.
    depth_ecco = zeros(size(depth_ecco_raw)+2)
    depth_ecco[0] = 0.0
    depth_ecco[1:-1] = depth_ecco_raw
    depth_ecco[-1] = 6000.0

    # Read ROMS grid
    print 'Reading ROMS grid'
    grid_fid = Dataset(grid_file, 'r')
    lon_rho = grid_fid.variables['lon_rho'][:,:]
    lat_rho = grid_fid.variables['lat_rho'][:,:]
    lon_u = grid_fid.variables['lon_u'][:,:]
    lat_u = grid_fid.variables['lat_u'][:,:]
    lon_v = grid_fid.variables['lon_v'][:,:]
    lat_v = grid_fid.variables['lat_v'][:,:]
    h = grid_fid.variables['h'][:,:]    
    zice = grid_fid.variables['zice'][:,:]
    mask_rho = grid_fid.variables['mask_rho'][:,:]
    mask_zice = grid_fid.variables['mask_zice'][:,:]
    grid_fid.close()    

    # Save the lengths of the longitude axis for each grid
    num_lon_rho = size(lon_rho, 1)
    num_lon_u = size(lon_u, 1)
    num_lon_v = size(lon_v, 1)
    # Mask h and zice with zeros
    h = h*mask_rho
    zice = zice*mask_zice
    # Interpolate h and zice to u and v grids
    h_u = 0.5*(h[:,0:-1] + h[:,1:])
    h_v = 0.5*(h[0:-1,:] + h[1:,:])
    zice_u = 0.5*(zice[:,0:-1] + zice[:,1:])
    zice_v = 0.5*(zice[0:-1,:] + zice[1:,:])

    # Calculate Cartesian integrands and z-coordinates for each grid
    dx_rho, dy_rho, dz_rho, z_rho = cartesian_grid_3d(lon_rho, lat_rho, h, zice, theta_s, theta_b, hc, N)
    dx_u, dy_u, dz_u, z_u = cartesian_grid_3d(lon_u, lat_u, h_u, zice_u, theta_s, theta_b, hc, N)
    dx_v, dy_v, dz_v, z_v = cartesian_grid_3d(lon_v, lat_v, h_v, zice_v, theta_s, theta_b, hc, N)
    # Also call calc_z for the rho_grid just so we get sc_r and Cs_r
    z_rho, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)

    # Select just the northern boundary for each field
    dx_rho = dx_rho[:,-1,:]
    dy_rho = dy_rho[:,-1,:]
    dz_rho = dz_rho[:,-1,:]
    z_rho = z_rho[:,-1,:]
    dx_u = dx_u[:,-1,:]
    dy_u = dy_u[:,-1,:]
    dz_u = dz_u[:,-1,:]
    z_u = z_u[:,-1,:]
    dx_v = dx_v[:,-1,:]
    dy_v = dy_v[:,-1,:]
    dz_v = dz_v[:,-1,:]
    z_v = z_v[:,-1,:]

    # Copy longitude and latitude at the northern boundary into arrays of
    # dimension depth x longitude
    lon_rho = tile(lon_rho[-1,:], (N,1))
    lat_rho = tile(lat_rho[-1,:], (N,1))
    lon_u = tile(lon_u[-1,:], (N,1))
    lat_u = tile(lat_u[-1,:], (N,1))
    lon_v = tile(lon_v[-1,:], (N,1))
    lat_v = tile(lat_v[-1,:], (N,1))

    # Make sure ROMS longitudes are between 0 and 360
    index = lon_rho < 0
    lon_rho[index] += 360
    index = lon_rho > 360
    lon_rho[index] -= 360
    index = lon_u < 0
    lon_u[index] += 360
    index = lon_u > 360
    lon_u[index] -= 360
    index = lon_v < 0
    lon_v[index] += 360
    index = lon_v > 360
    lon_v[index] -= 360

    # Set up output file
    print 'Setting up ', output_file
    out_fid = Dataset(output_file, 'w')
    out_fid.createDimension('xi_u', num_lon_u)
    out_fid.createDimension('xi_v', num_lon_v)
    out_fid.createDimension('xi_rho', num_lon_rho)
    out_fid.createDimension('s_rho', N)
    out_fid.createDimension('ocean_time', None)
    out_fid.createDimension('one', 1);
    out_fid.createVariable('theta_s', 'f8', ('one'))
    out_fid.variables['theta_s'].long_name = 'S-coordinate surface control parameter'
    out_fid.variables['theta_s'][:] = theta_s
    out_fid.createVariable('theta_b', 'f8', ('one'))
    out_fid.variables['theta_b'].long_name = 'S-coordinate bottom control parameter'
    out_fid.variables['theta_b'].units = 'nondimensional'
    out_fid.variables['theta_b'][:] = theta_b
    out_fid.createVariable('Tcline', 'f8', ('one'))
    out_fid.variables['Tcline'].long_name = 'S-coordinate surface/bottom layer width'
    out_fid.variables['Tcline'].units = 'meter'
    out_fid.variables['Tcline'][:] = hc
    out_fid.createVariable('hc', 'f8', ('one'))
    out_fid.variables['hc'].long_name = 'S-coordinate parameter, critical depth'
    out_fid.variables['hc'].units = 'meter'
    out_fid.variables['hc'][:] = hc
    out_fid.createVariable('sc_r', 'f8', ('s_rho'))
    out_fid.variables['sc_r'].long_name = 'S-coordinate at rho-points'
    out_fid.variables['sc_r'].units = 'nondimensional'
    out_fid.variables['sc_r'].valid_min = -1
    out_fid.variables['sc_r'].valid_max = 0
    out_fid.variables['sc_r'][:] = sc_r
    out_fid.createVariable('Cs_r', 'f8', ('s_rho'))
    out_fid.variables['Cs_r'].long_name = 'S-coordinate stretching curves at RHO-points'
    out_fid.variables['Cs_r'].units = 'nondimensional'
    out_fid.variables['Cs_r'].valid_min = -1
    out_fid.variables['Cs_r'].valid_max = 0
    out_fid.variables['Cs_r'][:] = Cs_r
    out_fid.createVariable('ocean_time', 'f8', ('ocean_time'))
    out_fid.variables['ocean_time'].long_name = 'time since initialization'
    out_fid.variables['ocean_time'].units = 'days'
    out_fid.createVariable('temp_north', 'f8', ('ocean_time', 's_rho', 'xi_rho'))
    out_fid.variables['temp_north'].long_name = 'northern boundary potential temperature'
    out_fid.variables['temp_north'].units = 'Celsius'
    out_fid.createVariable('salt_north', 'f8', ('ocean_time', 's_rho', 'xi_rho'))
    out_fid.variables['salt_north'].long_name = 'northern boundary salinity'
    out_fid.variables['salt_north'].units = 'PSU'
    out_fid.createVariable('u_north', 'f8', ('ocean_time', 's_rho', 'xi_u'))
    out_fid.variables['u_north'].long_name = 'northern boundary u-momentum component'
    out_fid.variables['u_north'].units = 'meter second-1'
    out_fid.createVariable('v_north', 'f8', ('ocean_time', 's_rho', 'xi_v'))
    out_fid.variables['v_north'].long_name = 'northern boundary v-momentum component'
    out_fid.variables['v_north'].units = 'meter second-1'
    out_fid.createVariable('ubar_north', 'f8', ('ocean_time', 'xi_u'))
    out_fid.variables['ubar_north'].long_name = 'northern boundary vertically integrated u-momentum component'
    out_fid.variables['ubar_north'].units = 'meter second-1'
    out_fid.createVariable('vbar_north', 'f8', ('ocean_time', 'xi_v'))
    out_fid.variables['vbar_north'].long_name = 'northern boundary vertically integrated v-momentum component'
    out_fid.variables['vbar_north'].units = 'meter second-1'
    out_fid.createVariable('zeta_north', 'f8', ('ocean_time', 'xi_rho'))
    out_fid.variables['zeta_north'].long_name = 'northern boundary sea surface height'
    out_fid.variables['zeta_north'].units = 'meter'
    out_fid.close()

    # Loop through each month of this year
    for month in range(12):

        print 'Processing month ', str(month+1), ' of 12'
        # Construct the rest of the file paths
        if month+1 < 10:
            tail = '0' + str(month+1) + '.nc'
        else:
            tail = str(month+1) + '.nc'

        # Read temperature, salinity, velocity data
        theta_fid = Dataset(theta_base + tail, 'r')
        theta_raw = transpose(theta_fid.variables['THETA'][0,:,0:nbdry_ecco,:])
        theta_fid.close()
        salt_fid = Dataset(salt_base + tail, 'r')
        salt_raw = transpose(salt_fid.variables['SALT'][0,:,0:nbdry_ecco,:])
        salt_fid.close()
        vvel_fid = Dataset(vvel_base + tail, 'r')
        vvel_raw = transpose(vvel_fid.variables['VVEL'][0,:,0:nbdry_ecco,:])
        vvel_fid.close()

        # Copy the data to the new longitude and depth indices, making sure
        # to preserve the mask.
        theta = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
        theta[1:-1,:,1:-1] = ma.copy(theta_raw)
        theta[0,:,1:-1] = ma.copy(theta_raw[-1,:,:])
        theta[-1,:,1:-1] = ma.copy(theta_raw[0,:,:])
        theta[:,:,0] = ma.copy(theta[:,:,1])
        theta[:,:,-1] = ma.copy(theta[:,:,-2])
        salt = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
        salt[1:-1,:,1:-1] = ma.copy(salt_raw)
        salt[0,:,1:-1] = ma.copy(salt_raw[-1,:,:])
        salt[-1,:,1:-1] = ma.copy(salt_raw[0,:,:])
        salt[:,:,0] = ma.copy(salt[:,:,1])
        salt[:,:,-1] = ma.copy(salt[:,:,-2])
        vvel = ma.array(zeros((size(lon_ecco), size(lat_ecco), size(depth_ecco))))
        vvel[1:-1,:,1:-1] = ma.copy(vvel_raw)
        vvel[0,:,1:-1] = ma.copy(vvel_raw[-1,:,:])
        vvel[-1,:,1:-1] = ma.copy(vvel_raw[0,:,:])
        vvel[:,:,0] = ma.copy(vvel[:,:,1])
        vvel[:,:,-1] = ma.copy(vvel[:,:,-2])

        # Regridding happens here...
        print 'Interpolating temperature'
        temp_interp = interp_ecco2roms_nbc(theta, lon_ecco, lat_ecco, depth_ecco, lon_rho, lat_rho, z_rho, mean(theta), True)
        print 'Interpolating salinity'
        salt_interp = interp_ecco2roms_nbc(salt, lon_ecco, lat_ecco, depth_ecco, lon_rho, lat_rho, z_rho, mean(salt), True)
        print 'Interpolating v'
        v_interp = interp_ecco2roms_nbc(vvel, lon_ecco, lat_ecco, depth_ecco, lon_v, lat_v, z_v, 0, False)

        # Calculate vertical average of v to get vbar
        # Be sure to treat land mask carefully so we don't divide by 0
        vbar_interp = sum(v_interp*dz_v, axis=0)
        wct_v = h_v[-1,:] + zice_v[-1,:]
        index = wct_v == 0
        vbar_interp[~index] = vbar_interp[~index]/wct_v[~index]
        vbar_interp[index] = 0.0

        # Calculate time values centered in the middle of each month,
        # relative to 1992
        time = 365.25*(year-1992) + 365.25/12*(month+0.5)

        # Save data to NetCDF file
        out_fid = Dataset(output_file, 'a')
        out_fid.variables['ocean_time'][month] = time
        out_fid.variables['temp_north'][month,:,:] = temp_interp
        out_fid.variables['salt_north'][month,:,:] = salt_interp
        # Clamp u to zero
        out_fid.variables['u_north'][month,:,:] = 0.0
        out_fid.variables['v_north'][month,:,:] = v_interp
        # Clamp ubar to zero
        out_fid.variables['ubar_north'][month,:] = 0.0
        out_fid.variables['vbar_north'][month,:] = vbar_interp
        out_fid.variables['zeta_north'][month,:] = 0.0
        out_fid.close()
예제 #29
0
def i_slice (file_path, var_name, tstep, i_val, depth_min, colour_bounds=None, save=False, fig_name=None):

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Read data and grid variables
    id = Dataset(file_path, 'r')
    data = id.variables[var_name][tstep-1,:,:-15,i_val-1]
    h = id.variables['h'][:-15,:]
    zice = id.variables['zice'][:-15,:]
    # Sea surface height is time-dependent
    zeta = id.variables['zeta'][tstep-1,:-15,:]
    lon_2d = id.variables['lon_rho'][:-15,:]
    lat_2d = id.variables['lat_rho'][:-15,:]
    id.close()

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)
    # Select depth and latitude at the given i-index
    z = z_3d[:,:,i_val-1]
    lat = tile(lat_2d[:,i_val-1], (N,1))

    # Determine colour bounds
    if colour_bounds is not None:
        # Specified by user
        scale_min = colour_bounds[0]
        scale_max = colour_bounds[1]
        if scale_min == -scale_max:
            # Centered on zero; use a red-yellow-blue colour scale
            colour_map = 'RdYlBu_r'
        else:
            # Use a rainbow colour scale
            colour_map = 'jet'
    else:
        # Determine automatically
        scale_min = amin(data)
        scale_max = amax(data)
        colour_map = 'jet'

    # Plot (pcolor not contour to show what each individual cell is doing)
    fig = figure(figsize=(18,6))
    pcolor(lat, z, data, vmin=scale_min, vmax=scale_max, cmap=colour_map)
    colorbar()
    title(var_name + ' at i=' + str(i_val))
    xlabel('Latitude')
    ylabel('Depth (m)')

    # Determine bounds on latitude
    data_sum = sum(data, axis=0)
    edges = ma.flatnotmasked_edges(data_sum)
    j_min = edges[0]
    j_max = edges[1]
    if j_min == 0:
        # There are ocean points right to the southern boundary
        # Don't do anything special
        lat_min = min(lat[:,j_min])
    else:
        # There is land everywhere at the southern boundary
        # Show the last 2 degrees of this land mask
        lat_min = min(lat[:,j_min]) - 2
    if j_max == size(data_sum) - 1:
        # There are ocean points right to the northern boundary
        # Don't do anything special
        lat_max = max(lat[:,j_max])
    else:
        # There is land everywhere at the northern boundary
        # Show the first 2 degrees of this land mask
        lat_max = max(lat[:,j_max]) + 2
    lat_max = -65
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
예제 #30
0
def plot_layers (grid_path, lon0, depth_min, Vstretching, theta_s, theta_b, hc, N):

    # Read grid
    id = Dataset(grid_path, 'r')
    lon_2d = id.variables['lon_rho'][:,:]
    lat_2d = id.variables['lat_rho'][:,:]
    h = id.variables['h'][:,:]
    zice = id.variables['zice'][:,:]
    mask = id.variables['mask_rho'][:,:]
    id.close()

    # Calculate a 3D field of depth values
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, None, Vstretching)

    # Figure out how to write longitude in the title
    if lon0 < 0:
        lon_string = str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = str(int(round(lon0))) + r'$^{\circ}$E'

    # Get longitude in the range (0,360) as per ROMS convention
    if lon0 < 0:
        lon0 += 360

    # Get a 3D land mask   
    mask_3d = tile(mask, (N,1,1))

    # Interpolate land mask, depth, longitude to the given longitude
    mask_interp, z, lat = interp_lon_roms(mask_3d, z_3d, lat_2d, lon_2d, lon0)
    # Simple array containing layer numbers, same size as z
    layer = zeros(shape(z))
    for k in range(N):        
        layer[k,:] = k+1
    # Mask out land
    layer = ma.masked_where(mask_interp==0, layer)

    # Choose latitude bounds based on land mask
    mask_sum = sum(mask_interp, axis=0)    
    # Find southernmost and northernmost unmasked j-indices
    edges = ma.flatnotmasked_edges(mask_sum)
    j_min = edges[0]
    j_max = edges[1]
    if j_min == 0:
        # There are ocean points right to the southern boundary
        # Don't do anything special
        lat_min = min(lat[:,j_min])
    else:
        # There is land everywhere at the southern boundary
        # Show the last 2 degrees of this land mask
        lat_min = min(lat[:,j_min]) - 2
    if j_max == size(mask_sum) - 1:
        # There are ocean points right to the northern boundary
        # Don't do anything special
        lat_max = max(lat[:,j_max])
    else:
        # There is land everywhere at the northern boundary
        # Show the first 2 degrees of this land mask
        lat_max = max(lat[:,j_max]) + 2

    #lat_min = -85
    #lat_max = -75

    # Contour levels
    lev = range(1, N)

    # Plot
    fig = figure(figsize=(18,6)) #(18,12))
    contour(lat, z, layer, lev, colors='k')
    title(lon_string) #(r"ROMS terrain-following levels through the Ross Ice Shelf cavity (180$^{\circ}$E)", fontsize=24)
    xlabel('Latitude')
    ylabel('Depth (m)')
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])
    #text(-82, -200, "Ice shelf", fontsize=24)
    #text(-82, -650, "Sea floor", fontsize=24)
    #fig.savefig('ross_levels.png')
    fig.show()

    # Put longitude back to original range in case the user wants to go again
    if lon0 > 180:
        lon0 -= 360
예제 #31
0
def temp_salt_seasonal(file_path, lon0, depth_bdry, save=False, fig_name=None):

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Season names for titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']

    # Bounds on colour scale
    temp_min = -2.5
    temp_max = 7.5
    temp_ticks = 2
    salt_min = 33.8
    salt_max = 34.8
    salt_ticks = 0.2

    # Choose what to write on the title about longitude
    if lon0 < 0:
        lon_string = 'T/S slices at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
    else:
        lon_string = 'T/S slices at ' + str(int(round(lon0))) + r'$^{\circ}$E'
    # Edit longitude bounds to be from 0 to 360, to fit with ROMS convention
    if lon0 < 0:
        lon0 += 360

    # Read grid
    id = Dataset(file_path, 'r')
    h = id.variables['h'][:-15, :]
    zice = id.variables['zice'][:-15, :]
    lon_roms_2d = id.variables['lon_rho'][:-15, :]
    lat_roms_2d = id.variables['lat_rho'][:-15, :]
    num_lon = id.variables['lon_rho'].shape[1]
    num_lat = id.variables['lat_rho'].shape[0]
    id.close()

    # Calculate seasonal averages of temperature and salinity
    print 'Reading temperature'
    temp_3d_roms = seasonal_avg_roms(file_path, 'temp', [N, num_lat, num_lon])
    print 'Reading salinity'
    salt_3d_roms = seasonal_avg_roms(file_path, 'salt', [N, num_lat, num_lon])
    # Chop off northern boundary
    temp_3d_roms = temp_3d_roms[:, :, :-15, :]
    salt_3d_roms = salt_3d_roms[:, :, :-15, :]

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_roms_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N)

    # Calculate zonal slices for each season
    temp_roms = ma.empty([4, N, size(lat_roms_2d, 0)])
    temp_roms[:, :, :] = 0.0
    salt_roms = ma.empty([4, N, size(lat_roms_2d, 0)])
    salt_roms[:, :, :] = 0.0
    for season in range(4):
        print 'Calculating zonal slices for ' + season_names[season]
        temp_tmp, z_roms, lat_roms = interp_lon_roms(
            temp_3d_roms[season, :, :, :], z_roms_3d, lat_roms_2d, lon_roms_2d,
            lon0)
        temp_roms[season, :, :] = temp_tmp
        salt_tmp, z_roms, lat_roms = interp_lon_roms(
            salt_3d_roms[season, :, :, :], z_roms_3d, lat_roms_2d, lon_roms_2d,
            lon0)
        salt_roms[season, :, :] = salt_tmp

    # Set colour levels
    lev1 = linspace(temp_min, temp_max, num=50)
    lev2 = linspace(salt_min, salt_max, num=50)

    # Choose boundaries based on extent of ROMS grid
    sbdry = amin(lat_roms)
    nbdry = amax(lat_roms)

    # Plot
    print 'Plotting'
    fig = figure(figsize=(20, 9))
    # Loop over seasons
    for season in range(4):
        # Temperature
        fig.add_subplot(2, 4, season + 1)
        img = contourf(lat_roms,
                       z_roms,
                       temp_roms[season, :, :],
                       lev1,
                       cmap='jet',
                       extend='both')
        xlim([sbdry, nbdry])
        ylim([depth_bdry, 0])
        title('Temperature (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
        if season == 3:
            cbaxes1 = fig.add_axes([0.92, 0.55, 0.01, 0.3])
            cbar1 = colorbar(img,
                             cax=cbaxes1,
                             ticks=arange(temp_min, temp_max + temp_ticks,
                                          temp_ticks))
            cbar1.ax.tick_params(labelsize=16)
        # Salinity
        fig.add_subplot(2, 4, season + 5)
        img = contourf(lat_roms,
                       z_roms,
                       salt_roms[season, :, :],
                       lev2,
                       cmap='jet',
                       extend='both')
        xlim([sbdry, nbdry])
        ylim([depth_bdry, 0])
        title('Salinity (' + season_names[season] + ')', fontsize=24)
        if season == 0:
            ylabel('depth (m)', fontsize=18)
        xlabel('Latitude', fontsize=18)
        if season == 3:
            cbaxes2 = fig.add_axes([0.92, 0.15, 0.01, 0.3])
            cbar2 = colorbar(img,
                             cax=cbaxes2,
                             ticks=arange(salt_min, salt_max + salt_ticks,
                                          salt_ticks))
            cbar2.ax.tick_params(labelsize=16)
    # Add the main title
    suptitle(lon_string, fontsize=30)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
예제 #32
0
def zonal_plot (file_path, var_name, tstep, lon_key, lon0, lon_bounds, depth_min, colour_bounds=None, save=False, fig_name=None, grid_path=None):

    # Grid parameters
    theta_s = 4.0
    theta_b = 0.9
    hc = 40
    N = 31

    # Read the variable
    id = Dataset(file_path, 'r')
    data_3d = id.variables[var_name][tstep-1,:,:-15,:]
    # Also read sea surface height
    zeta = id.variables['zeta'][tstep-1,:-15,:]
    if var_name == 'salt':
        units = 'psu'
    else:
        units = id.variables[var_name].units
    long_name = id.variables[var_name].long_name

    # Rotate velocity if necessary
    if var_name in ['u', 'v']:
        grid_id = Dataset(grid_path, 'r')
        angle = grid_id.variables['angle'][:-15,:]
        grid_id.close()
        if var_name == 'u':
            data_3d_ugrid = data_3d[:,:,:]
            data_3d = ma.empty([data_3d_ugrid.shape[0], data_3d_ugrid.shape[1], data_3d_ugrid.shape[2]+1])
            for k in range(N):
                u_data = data_3d_ugrid[k,:,:]
                v_data = id.variables['v'][tstep-1,k,:-15,:]
                u_data_lonlat, v_data_lonlat = rotate_vector_roms(u_data, v_data, angle)
                data_3d[k,:,:] = u_data_lonlat
        elif var_name == 'v':
            data_3d_vgrid = data_3d[:,:,:]
            data_3d = ma.empty([data_3d_vgrid.shape[0], data_3d_vgrid.shape[1]+1, data_3d_vgrid.shape[2]])
            for k in range(N):
                v_data = data_3d_vgrid[k,:,:]
                u_data = id.variables['u'][tstep-1,k,:-15,:]
                u_data_lonlat, v_data_lonlat = rotate_vector_roms(u_data, v_data, angle)
                data_3d[k,:,:] = v_data_lonlat

    # Read grid variables
    h = id.variables['h'][:-15,:]
    zice = id.variables['zice'][:-15,:]
    lon_2d = id.variables['lon_rho'][:-15,:]
    lat_2d = id.variables['lat_rho'][:-15,:]
    id.close()

    # Get a 3D array of z-coordinates; sc_r and Cs_r are unused in this script
    z_3d, sc_r, Cs_r = calc_z(h, zice, theta_s, theta_b, hc, N, zeta)

    # Choose what to write on the title about longitude
    if lon_key == 0:
        if lon0 < 0:
            lon_string = 'at ' + str(int(round(-lon0))) + r'$^{\circ}$W'
        else:
            lon_string = 'at ' + str(int(round(lon0))) + r'$^{\circ}$E'
    elif lon_key == 1:
        lon_string = 'zonally averaged'
    elif lon_key == 2:
        lon_string = 'zonally averaged between '
        if lon_bounds[0] < 0:
            lon_string += str(int(round(-lon_bounds[0]))) + r'$^{\circ}$W and '
        else:
            lon_string += str(int(round(lon_bounds[0]))) + r'$^{\circ}$E and '
        if lon_bounds[1] < 0:
            lon_string += str(int(round(-lon_bounds[1]))) + r'$^{\circ}$W'
        else:
            lon_string += str(int(round(lon_bounds[1]))) + r'$^{\circ}$E'

    # Edit longitude bounds to be from 0 to 360, to fit with ROMS convention
    if lon_key == 0:
        if lon0 < 0:
            lon0 += 360
    elif lon_key == 2:
        if lon_bounds[0] < 0:
            lon_bounds[0] += 360
        if lon_bounds[1] < 0:
            lon_bounds[1] += 360

    # Interpolate or average data
    if lon_key == 0:
        # Interpolate to lon0
        data, z, lat = interp_lon(data_3d, z_3d, lat_2d, lon_2d, lon0)
    elif lon_key == 1:
        # Zonally average over all longitudes
        # dlon is constant on this grid (0.25 degrees) so this is easy
        data = mean(data_3d, axis=2)
        z = mean(z_3d, axis=2)
        # Zonally average latitude, and copy into N depth levels
        lat = tile(mean(lat_2d, axis=1), (N,1))
    elif lon_key == 2:
        # Zonally average between lon_bounds
        data, z, lat = average_btw_lons(data_3d, z_3d, lat_2d, lon_2d, lon_bounds)

    if colour_bounds is not None:
        # User has set bounds on colour scale
        lev = linspace(colour_bounds[0], colour_bounds[1], num=40)
        if colour_bounds[0] == -colour_bounds[1]:
            # Bounds are centered on zero, so choose a blue-to-red colourmap
            # centered on yellow
            colour_map = 'RdYlBu_r'
        else:
            colour_map = 'jet'
    else:
        # Determine bounds automatically
        if var_name in ['u', 'v']:
            # Center levels on 0 for certain variables, with a blue-to-red
            # colourmap
            max_val = amax(abs(data))
            lev = linspace(-max_val, max_val, num=40)
            colour_map = 'RdYlBu_r'
        else:
            lev = linspace(amin(data), amax(data), num=40)
            colour_map = 'jet'

    # Plot
    fig = figure(figsize=(18,6))
    contourf(lat, z, data, lev, cmap=colour_map, extend='both')
    colorbar()

    title(long_name + ' (' + units + ')\n' + lon_string)
    xlabel('Latitude')
    ylabel('Depth (m)')

    # Choose latitude bounds based on land mask
    data_sum = sum(data, axis=0)    
    # Find southernmost and northernmost unmasked j-indices
    edges = ma.flatnotmasked_edges(data_sum)
    j_min = edges[0]
    j_max = edges[1]
    if j_min == 0:
        # There are ocean points right to the southern boundary
        # Don't do anything special
        lat_min = min(lat[:,j_min])
    else:
        # There is land everywhere at the southern boundary
        # Show the last 2 degrees of this land mask
        lat_min = min(lat[:,j_min]) - 2
    if j_max == size(data_sum) - 1:
        # There are ocean points right to the northern boundary
        # Don't do anything special
        lat_max = max(lat[:,j_max])
    else:
        # There is land everywhere at the northern boundary
        # Show the first 2 degrees of this land mask
        lat_max = max(lat[:,j_max]) + 2
#    lat_max = -65
    xlim([lat_min, lat_max])
    ylim([depth_min, 0])

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()

    # Reset lon0 or lon_bounds to (-180, 180) range in case we
    # use them again for the next plot
    if lon_key == 0:
        if lon0 > 180:
            lon0 -= 360
    elif lon_key == 2:
        if lon_bounds[0] > 180:
            lon_bounds[0] -= 360
        if lon_bounds[1] > 180:
            lon_bounds[1] -= 360