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"