def add_grounded_iceberg (rtopo_file, lon, lat, bathy, omask): import netCDF4 as nc print 'Adding grounded iceberg A-23A' print 'Reading data' id = nc.Dataset(rtopo_file, 'r') lon_rtopo = id.variables['lon'][:] lat_rtopo = id.variables['lat'][:] [xmin, xmax, ymin, ymax] = region_bounds['a23a'] # Select the region we care about i_start = np.nonzero(lon_rtopo >= xmin)[0][0] - 1 i_end = np.nonzero(lon_rtopo >= xmax)[0][0] j_start = np.nonzero(lat_rtopo >= ymin)[0][0] - 1 j_end = np.nonzero(lat_rtopo >= ymax)[0][0] # Read mask just from this section mask_rtopo = id.variables['amask'][j_start:j_end, i_start:i_end] id.close() # Trim the grid too lon_rtopo = lon_rtopo[i_start:i_end] lat_rtopo = lat_rtopo[j_start:j_end] print 'Interpolating mask' lon_2d, lat_2d = np.meshgrid(lon, lat) mask_rtopo_interp = interp_topo(lon_rtopo, lat_rtopo, mask_rtopo, lon_2d, lat_2d) # The mask is 1 in the grounded iceberg region and 0 elsewhere. Take a threshold of 0.5 for interpolation errors. Treat it as land. index = mask_rtopo_interp >= 0.5 bathy[index] = 0 omask[index] = 0 return bathy, omask
def interp_bedmap2 (lon, lat, topo_dir, nc_out, bed_file=None, grounded_iceberg=False, rtopo_file=None): import netCDF4 as nc from plot_latlon import plot_tmp_domain topo_dir = real_dir(topo_dir) # BEDMAP2 file names surface_file = topo_dir+'bedmap2_surface.flt' thickness_file = topo_dir+'bedmap2_thickness.flt' mask_file = topo_dir+'bedmap2_icemask_grounded_and_shelves.flt' if bed_file is None: bed_file = topo_dir+'bedmap2_bed.flt' # GEBCO file name gebco_file = topo_dir+'GEBCO_2014_2D.nc' if grounded_iceberg and (rtopo_file is None): # RTopo-2 file name (auxiliary file including masks) rtopo_file = topo_dir+'RTopo-2.0.1_30sec_aux.nc' if np.amin(lat) > -60: print "Error (interp_bedmap2): this domain doesn't go south of 60S, so it's not covered by BEDMAP2." sys.exit() if np.amax(lat) > -60: use_gebco = True # Find the first index north of 60S j_split = np.nonzero(lat >= -60)[0][0] # Split grid into a BEDMAP2 section and a GEBCO section (remembering lat is edges, not centres, so lat[j_split-1] is in both sections) lat_b = lat[:j_split] lat_g = lat[j_split-1:] else: use_gebco = False lat_b = lat # Set up BEDMAP grid (polar stereographic) x = np.arange(-bedmap_bdry, bedmap_bdry+bedmap_res, bedmap_res) y = np.arange(-bedmap_bdry, bedmap_bdry+bedmap_res, bedmap_res) print 'Reading data' # Have to flip it vertically so lon0=0 in polar stereographic projection # Otherwise, lon0=180 which makes x_interp and y_interp strictly decreasing when we call polar_stereo later, and the interpolation chokes bathy = np.flipud(np.fromfile(bed_file, dtype='<f4').reshape([bedmap_dim, bedmap_dim])) surf = np.flipud(np.fromfile(surface_file, dtype='<f4').reshape([bedmap_dim, bedmap_dim])) thick = np.flipud(np.fromfile(thickness_file, dtype='<f4').reshape([bedmap_dim, bedmap_dim])) mask = np.flipud(np.fromfile(mask_file, dtype='<f4').reshape([bedmap_dim, bedmap_dim])) if np.amax(lat_b) > -61: print 'Extending bathymetry past 60S' # Bathymetry has missing values north of 60S. Extend into that mask so there are no artifacts in the splines near 60S. bathy = extend_into_mask(bathy, missing_val=bedmap_missing_val, num_iters=5) print 'Calculating ice shelf draft' # Calculate ice shelf draft from ice surface and ice thickness draft = surf - thick print 'Calculating ocean and ice masks' # Mask: -9999 is open ocean, 0 is grounded ice, 1 is ice shelf # Make an ocean mask and an ice mask. Ice shelves are in both. omask = (mask!=0).astype(float) imask = (mask!=-9999).astype(float) # Convert lon and lat to polar stereographic coordinates lon_2d, lat_2d = np.meshgrid(lon, lat_b) x_interp, y_interp = polar_stereo(lon_2d, lat_2d) # Interpolate fields print 'Interpolating bathymetry' bathy_interp = interp_topo(x, y, bathy, x_interp, y_interp) print 'Interpolating ice shelf draft' draft_interp = interp_topo(x, y, draft, x_interp, y_interp) print 'Interpolating ocean mask' omask_interp = interp_topo(x, y, omask, x_interp, y_interp) print 'Interpolating ice mask' imask_interp = interp_topo(x, y, imask, x_interp, y_interp) if use_gebco: print 'Filling in section north of 60S with GEBCO data' print 'Reading data' id = nc.Dataset(gebco_file, 'r') lat_gebco_grid = id.variables['lat'][:] lon_gebco_grid = id.variables['lon'][:] # Figure out which indices we actually care about - buffer zone of 5 cells so the splines have room to breathe j_start = max(np.nonzero(lat_gebco_grid >= lat_g[0])[0][0] - 1 - 5, 0) j_end = min(np.nonzero(lat_gebco_grid >= lat_g[-1])[0][0] + 5, lat_gebco_grid.size-1) i_start = max(np.nonzero(lon_gebco_grid >= lon[0])[0][0] - 1 - 5, 0) i_end = min(np.nonzero(lon_gebco_grid >= lon[-1])[0][0] + 5, lon_gebco_grid.size-1) # Read GEBCO bathymetry just from this section bathy_gebco = id.variables['elevation'][j_start:j_end, i_start:i_end] id.close() # Trim the grid too lat_gebco_grid = lat_gebco_grid[j_start:j_end] lon_gebco_grid = lon_gebco_grid[i_start:i_end] print 'Interpolating bathymetry' lon_2d, lat_2d = np.meshgrid(lon, lat_g) bathy_gebco_interp = interp_topo(lon_gebco_grid, lat_gebco_grid, bathy_gebco, lon_2d, lat_2d) print 'Combining BEDMAP2 and GEBCO sections' # Deep copy the BEDMAP2 section of each field bathy_bedmap_interp = np.copy(bathy_interp) draft_bedmap_interp = np.copy(draft_interp) omask_bedmap_interp = np.copy(omask_interp) imask_bedmap_interp = np.copy(imask_interp) # Now combine them (remember we interpolated to the centres of grid cells, but lat and lon arrays define the edges, so minus 1 in each dimension) bathy_interp = np.empty([lat.size-1, lon.size-1]) bathy_interp[:j_split-1,:] = bathy_bedmap_interp bathy_interp[j_split-1:,:] = bathy_gebco_interp # Ice shelf draft will be 0 in GEBCO region draft_interp = np.zeros([lat.size-1, lon.size-1]) draft_interp[:j_split-1,:] = draft_bedmap_interp # Set ocean mask to 1 in GEBCO region; any land points will be updated later based on bathymetry > 0 omask_interp = np.ones([lat.size-1, lon.size-1]) omask_interp[:j_split-1,:] = omask_bedmap_interp # Ice mask will be 0 in GEBCO region imask_interp = np.zeros([lat.size-1, lon.size-1]) imask_interp[:j_split-1,:] = imask_bedmap_interp print 'Processing masks' # Deal with values interpolated between 0 and 1 omask_interp[omask_interp < 0.5] = 0 omask_interp[omask_interp >= 0.5] = 1 imask_interp[imask_interp < 0.5] = 0 imask_interp[imask_interp >= 0.5] = 1 # Zero out bathymetry and ice shelf draft on land bathy_interp[omask_interp==0] = 0 draft_interp[omask_interp==0] = 0 # Zero out ice shelf draft in the open ocean draft_interp[imask_interp==0] = 0 # Update masks due to interpolation changing their boundaries # Anything with positive bathymetry should be land index = bathy_interp > 0 omask_interp[index] = 0 bathy_interp[index] = 0 draft_interp[index] = 0 # Anything with negative or zero water column thickness should be land index = draft_interp - bathy_interp <= 0 omask_interp[index] = 0 bathy_interp[index] = 0 draft_interp[index] = 0 # Anything with positive ice shelf draft should be land index = draft_interp > 0 omask_interp[index] = 0 bathy_interp[index] = 0 draft_interp[index] = 0 # Any points with zero ice shelf draft should not be in the ice mask # (This will also remove grounded ice, and ice shelves with total thickness (draft + freeboard) thinner than firn_air) index = draft_interp == 0 imask_interp[index] = 0 print 'Removing isolated ocean cells' omask_interp = remove_isolated_cells(omask_interp) bathy_interp[omask_interp==0] = 0 draft_interp[omask_interp==0] = 0 imask_interp[omask_interp==0] = 0 print 'Removing isolated ice shelf cells' imask_interp = remove_isolated_cells(imask_interp) draft_interp[imask_interp==0] = 0 if grounded_iceberg: bathy_interp, omask_interp = add_grounded_iceberg(rtopo_file, lon, lat, bathy_interp, omask_interp) print 'Plotting' if use_gebco: # Remesh the grid, using the full latitude array lon_2d, lat_2d = np.meshgrid(lon, lat) plot_tmp_domain(lon_2d, lat_2d, bathy_interp, title='Bathymetry (m)') plot_tmp_domain(lon_2d, lat_2d, draft_interp, title='Ice shelf draft (m)') plot_tmp_domain(lon_2d, lat_2d, draft_interp - bathy_interp, title='Water column thickness (m)') plot_tmp_domain(lon_2d, lat_2d, omask_interp, title='Ocean mask') plot_tmp_domain(lon_2d, lat_2d, imask_interp, title='Ice mask') # Write to NetCDF file (at cell centres not edges!) ncfile = NCfile_basiclatlon(nc_out, 0.5*(lon[1:] + lon[:-1]), 0.5*(lat[1:] + lat[:-1])) ncfile.add_variable('bathy', bathy_interp, units='m') ncfile.add_variable('draft', draft_interp, units='m') ncfile.add_variable('omask', omask_interp) ncfile.add_variable('imask', imask_interp) ncfile.close() print 'The results have been written into ' + nc_out print 'Take a look at this file and make whatever edits you would like to the mask (eg removing everything west of the peninsula; you can use edit_mask if you like)' print "Then set your vertical layer thicknesses in a plain-text file, one value per line (make sure they clear the deepest bathymetry of " + str(abs(np.amin(bathy_interp))) + " m), and run remove_grid_problems"