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
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
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
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()
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()
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()
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')
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')
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])
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()
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
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')
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()
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()
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'
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()
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()
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()
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')
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()
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')
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()
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()
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'
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()
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')
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
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()
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()
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
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()
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