def mit_ics (grid_path, source_file, output_dir, nc_out=None, prec=64): from file_io import NCfile, read_netcdf from interpolation import interp_reg output_dir = real_dir(output_dir) # Fields to interpolate fields = ['THETA', 'SALT', 'SIarea', 'SIheff', 'SIhsnow'] # Flag for 2D or 3D dim = [3, 3, 2, 2, 2] # End of filenames for output outfile_tail = '_MIT.ini' print 'Building grids' source_grid = Grid(source_file) model_grid = Grid(grid_path) # Extract land mask of source grid source_mask = source_grid.hfac==0 print 'Building mask for points to fill' # Select open cells according to the model, interpolated to the source grid fill = np.ceil(interp_reg(model_grid, source_grid, np.ceil(model_grid.hfac), fill_value=0)).astype(bool) # Extend into mask a few times to make sure there are no artifacts near the coast fill = extend_into_mask(fill, missing_val=0, use_3d=True, num_iters=3) # Set up a NetCDF file so the user can check the results if nc_out is not None: ncfile = NCfile(nc_out, model_grid, 'xyz') # Process fields for n in range(len(fields)): print 'Processing ' + fields[n] out_file = output_dir + fields[n] + outfile_tail # Read the January climatology source_data = read_netcdf(source_file, fields[n], time_index=0) # Discard the land mask, and extrapolate slightly into missing regions so the interpolation doesn't get messed up. print '...extrapolating into missing regions' if dim[n] == 3: source_data = discard_and_fill(source_data, source_mask, fill) else: # Just care about the surface layer source_data = discard_and_fill(source_data, source_mask[0,:], fill[0,:], use_3d=False) print '...interpolating to model grid' data_interp = interp_reg(source_grid, model_grid, source_data, dim=dim[n]) # Fill the land mask with zeros if dim[n] == 3: data_interp[model_grid.hfac==0] = 0 else: data_interp[model_grid.hfac[0,:]==0] = 0 write_binary(data_interp, out_file, prec=prec) if nc_out is not None: print '...adding to ' + nc_out if dim[n] == 3: ncfile.add_variable(fields[n], data_interp, 'xyz') else: ncfile.add_variable(fields[n], data_interp, 'xy') if nc_out is not None: ncfile.close()
def sose_ics (grid_path, sose_dir, output_dir, nc_out=None, constant_t=-1.9, constant_s=34.4, split=180, prec=64): from grid import SOSEGrid from file_io import NCfile from interpolation import interp_reg sose_dir = real_dir(sose_dir) output_dir = real_dir(output_dir) # Fields to interpolate fields = ['THETA', 'SALT', 'SIarea', 'SIheff'] # Flag for 2D or 3D dim = [3, 3, 2, 2] # Constant values for ice shelf cavities constant_value = [constant_t, constant_s, 0, 0] # End of filenames for input infile_tail = '_climatology.data' # End of filenames for output outfile_tail = '_SOSE.ini' print 'Building grids' # First build the model grid and check that we have the right value for split model_grid = grid_check_split(grid_path, split) # Now build the SOSE grid sose_grid = SOSEGrid(sose_dir+'grid/', model_grid=model_grid, split=split) # Extract land mask sose_mask = sose_grid.hfac == 0 print 'Building mask for SOSE points to fill' # Figure out which points we need for interpolation # Find open cells according to the model, interpolated to SOSE grid model_open = np.ceil(interp_reg(model_grid, sose_grid, np.ceil(model_grid.hfac), fill_value=1)) # Find ice shelf cavity points according to model, interpolated to SOSE grid model_cavity = np.ceil(interp_reg(model_grid, sose_grid, xy_to_xyz(model_grid.ice_mask, model_grid), fill_value=0)).astype(bool) # Select open, non-cavity cells fill = model_open*np.invert(model_cavity) # Extend into the mask a few times to make sure there are no artifacts near the coast fill = extend_into_mask(fill, missing_val=0, use_3d=True, num_iters=3) # Set up a NetCDF file so the user can check the results if nc_out is not None: ncfile = NCfile(nc_out, model_grid, 'xyz') # Process fields for n in range(len(fields)): print 'Processing ' + fields[n] in_file = sose_dir + fields[n] + infile_tail out_file = output_dir + fields[n] + outfile_tail print '...reading ' + in_file # Just keep the January climatology if dim[n] == 3: sose_data = sose_grid.read_field(in_file, 'xyzt')[0,:] else: # Fill any missing regions with zero sea ice, as we won't be extrapolating them later sose_data = sose_grid.read_field(in_file, 'xyt', fill_value=0)[0,:] # Discard the land mask, and extrapolate slightly into missing regions so the interpolation doesn't get messed up. print '...extrapolating into missing regions' if dim[n] == 3: sose_data = discard_and_fill(sose_data, sose_mask, fill) # Fill cavity points with constant values sose_data[model_cavity] = constant_value[n] else: # Just care about surface layer sose_data = discard_and_fill(sose_data, sose_mask[0,:], fill[0,:], use_3d=False) print '...interpolating to model grid' data_interp = interp_reg(sose_grid, model_grid, sose_data, dim=dim[n]) # Fill the land mask with zeros if dim[n] == 3: data_interp[model_grid.hfac==0] = 0 else: data_interp[model_grid.hfac[0,:]==0] = 0 write_binary(data_interp, out_file, prec=prec) if nc_out is not None: print '...adding to ' + nc_out if dim[n] == 3: ncfile.add_variable(fields[n], data_interp, 'xyz') else: ncfile.add_variable(fields[n], data_interp, 'xy') if nc_out is not None: ncfile.close()
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"
def sose_sss_restoring (grid_path, sose_dir, output_salt_file, output_mask_file, nc_out=None, h0=-1250, obcs_sponge=0, split=180, prec=64): sose_dir = real_dir(sose_dir) print 'Building grids' # First build the model grid and check that we have the right value for split model_grid = grid_check_split(grid_path, split) # Now build the SOSE grid sose_grid = SOSEGrid(sose_dir+'grid/', model_grid=model_grid, split=split) # Extract surface land mask sose_mask = sose_grid.hfac[0,:] == 0 print 'Building mask' mask_surface = np.ones([model_grid.ny, model_grid.nx]) # Mask out land and ice shelves mask_surface[model_grid.hfac[0,:]==0] = 0 # Save this for later mask_land_ice = np.copy(mask_surface) # Mask out continental shelf mask_surface[model_grid.bathy > h0] = 0 # Smooth, and remask the land and ice shelves mask_surface = smooth_xy(mask_surface, sigma=2)*mask_land_ice if obcs_sponge > 0: # Also mask the cells affected by OBCS and/or its sponge mask_surface[:obcs_sponge,:] = 0 mask_surface[-obcs_sponge:,:] = 0 mask_surface[:,:obcs_sponge] = 0 mask_surface[:,-obcs_sponge:] = 0 # Make a 3D version with zeros in deeper layers mask_3d = np.zeros([model_grid.nz, model_grid.ny, model_grid.nx]) mask_3d[0,:] = mask_surface print 'Reading SOSE salinity' # Just keep the surface layer sose_sss = sose_grid.read_field(sose_dir+'SALT_climatology.data', 'xyzt')[:,0,:,:] # Figure out which SOSE points we need for interpolation # Restoring mask interpolated to the SOSE grid fill = np.ceil(interp_reg(model_grid, sose_grid, mask_3d[0,:], dim=2, fill_value=1)) # Extend into the mask a few times to make sure there are no artifacts near the coast fill = extend_into_mask(fill, missing_val=0, num_iters=3) # Process one month at a time sss_interp = np.zeros([12, model_grid.nz, model_grid.ny, model_grid.nx]) for month in range(12): print 'Month ' + str(month+1) print '...filling missing values' sose_sss_filled = discard_and_fill(sose_sss[month,:], sose_mask, fill, use_3d=False) print '...interpolating' # Mask out land and ice shelves sss_interp[month,0,:] = interp_reg(sose_grid, model_grid, sose_sss_filled, dim=2)*mask_land_ice write_binary(sss_interp, output_salt_file, prec=prec) write_binary(mask_3d, output_mask_file, prec=prec) if nc_out is not None: print 'Writing ' + nc_out ncfile = NCfile(nc_out, model_grid, 'xyzt') ncfile.add_time(np.arange(12)+1, units='months') ncfile.add_variable('salinity', sss_interp, 'xyzt', units='psu') ncfile.add_variable('restoring_mask', mask_3d, 'xyz') ncfile.close()