def check_final_grid (grid_path): grid = Grid(grid_path) problem = False # Check there are no isolated bottom cells # Find points which are open, their neighbour below is closed (i.e. they're at the seafloor), and their horizontal neighoburs are all closed hfac = grid.hfac num_valid_neighbours = neighbours(hfac, missing_val=0)[-1] valid_below = neighbours_z(hfac, missing_val=0)[3] num_isolated = np.count_nonzero((hfac!=0)*(valid_below==0)*(num_valid_neighbours==0)) if num_isolated > 0: problem = True print 'Problem!! There are ' + str(num_isolated) + ' locations with isolated bottom cells.' # Check that every water column has at least 2 open cells (partial cells count) open_cells = np.ceil(grid.hfac) num_pinched = np.count_nonzero(np.sum(open_cells, axis=0)==1) if num_pinched > 0: problem = True print 'Problem!! There are ' + str(num_pinched) + ' locations with only one open cell in the water column.' # Check that neighbouring ocean cells have at least 2 open faces between open_cells_w, open_cells_e, open_cells_s, open_cells_n = neighbours(open_cells)[:4] open_cells_neighbours = [open_cells_w, open_cells_e, open_cells_s, open_cells_n] loc_strings = ['western', 'eastern', 'southern', 'northern'] for i in range(len(loc_strings)): problem = check_one_direction(open_cells, open_cells_neighbours[i], loc_strings[i], problem) if problem: print 'Something went wrong with the filling or digging. Are you sure that your values of hFacMin and hFacMinDr are correct? Are you working with a version of MITgcm that calculates Ro_sfc and R_low differently?' else: print 'Everything looks good!'
def ice_shelf_front_points(grid, ice_mask=None, gtype='t', xmin=None, xmax=None, ymin=None, ymax=None): from interpolation import neighbours # Build masks if ice_mask is None: ice_mask = grid.get_ice_mask(gtype=gtype) open_ocean = grid.get_open_ocean_mask(gtype=gtype) # Set any remaining bounds lon, lat = grid.get_lon_lat(gtype=gtype) if xmin is None: xmin = np.amin(lon) if xmax is None: xmax = np.amax(lon) if ymin is None: ymin = np.amin(lat) if ymax is None: ymax = np.amax(lat) # Find number of open-ocean neighbours for each point num_open_ocean_neighbours = neighbours(open_ocean, missing_val=0)[-1] # Find all ice shelf points within bounds that have at least 1 open-ocean neighbour return ice_mask * (lon >= xmin) * (lon <= xmax) * (lat >= ymin) * ( lat <= ymax) * (num_open_ocean_neighbours > 0)
def check_final_grid(grid_path): grid = Grid(grid_path) problem = False # Check that every water column has at least 2 open cells (partial cells count) open_cells = np.ceil(grid.hfac) num_pinched = np.count_nonzero(np.sum(open_cells, axis=0) == 1) if num_pinched > 0: problem = True print 'Problem!! There are ' + str( num_pinched ) + ' locations with only one open cell in the water column.' # Check that neighbouring ocean cells have at least 2 open faces between open_cells_w, open_cells_e, open_cells_s, open_cells_n = neighbours( open_cells)[:4] open_cells_neighbours = [ open_cells_w, open_cells_e, open_cells_s, open_cells_n ] loc_strings = ['western', 'eastern', 'southern', 'northern'] for i in range(len(loc_strings)): problem = check_one_direction(open_cells, open_cells_neighbours[i], loc_strings[i], problem) if problem: print 'Something went wrong with the digging. Are you sure that your values of hFacMin and hFacMinDr are correct? Are you working with a version of MITgcm that calculates Ro_sfc and R_low differently?' else: print 'Everything looks good!'
def get_coast_mask(self, gtype='t', ignore_iceberg=True): from interpolation import neighbours open_ocean = self.get_open_ocean_mask(gtype=gtype) land_ice = 1 - open_ocean num_coast_neighbours = neighbours(land_ice, missing_val=0)[-1] coast_mask = (open_ocean * (num_coast_neighbours > 0)).astype(bool) if ignore_iceberg: # Grounded iceberg A23A should not be considered the coast lon, lat = self.get_lon_lat(gtype=gtype) [xmin, xmax, ymin, ymax] = a23a_bounds index = (lon >= xmin) * (lon <= xmax) * (lat >= ymin) * (lat <= ymax) coast_mask[index] = False return coast_mask
def do_filling (bathy, dz, z_edges, hFacMin=0.1, hFacMinDr=20.): # Find the actual bathymetry as the model will see it (based on hFac constraints) model_bathy = single_model_bdry(bathy, dz, z_edges, option='bathy', hFacMin=hFacMin, hFacMinDr=hFacMinDr) # Find the depth of the z-level below each bathymetry point level_below = level_vars(model_bathy, dz, z_edges, include_edge='bottom')[2] # Also find this value at the deepest horizontal neighbour for every point level_below_w, level_below_e, level_below_s, level_below_n = neighbours(level_below)[:4] level_below_neighbours = np.stack((level_below_w, level_below_e, level_below_s, level_below_n)) level_below_deepest_neighbour = np.amin(level_below_neighbours, axis=0) # Find cells which are in a deeper vertical layer than all their neighbours, and build them up by the minimum amount necessary print '...' + str(np.count_nonzero(bathy < level_below_deepest_neighbour)) + ' cells to fill' bathy = np.maximum(bathy, level_below_deepest_neighbour) return bathy
def do_digging (bathy, draft, dz, z_edges, hFacMin=0.1, hFacMinDr=20., dig_option='bathy'): # Figure out which field will be modified, which the other field is, which edge should be included in call to level_vars, and whether we are making the field deeper (-1) or shallower (1). if dig_option == 'bathy': field = bathy other_option = 'draft' other_field = draft include_edge = 'top' direction_flag = -1 elif dig_option == 'draft': field = draft other_option = 'bathy' other_field = bathy include_edge = 'bottom' direction_flag = 1 else: print 'Error (do_digging): invalid dig_option ' + dig_option sys.exit() # Find the other field as the model will see it (based on hFac constraints) model_other_field = single_model_bdry(other_field, dz, z_edges, option=other_option, hFacMin=hFacMin, hFacMinDr=hFacMinDr) # Get some variables about the vertical grid layer_number, level_above, level_below, dz_layer, dz_layer_above, dz_layer_below = level_vars(model_other_field, dz, z_edges, include_edge=include_edge) # Figure out which ones we care about if dig_option == 'bathy': level_next = level_below # Depth of the z-level below the draft dz_next = dz_layer_below # Thickness of the layer below that elif dig_option == 'draft': level_next = level_above # Depth of the z-level above the bathymetry dz_next = dz_layer_above # Thickness of the layer above that # Also make sure the bathymetry itself is deep enough if (layer_number == 1).any(): print "Error (do_digging): some bathymetry points are within the first vertical layer. If this is a coupled simulation, you need to set up the initial domain using bathymetry digging. If this is not a coupled simulation, use dig_option='bathy'." sys.exit() # Figure out the shallowest acceptable bathymetry OR the deepest acceptable ice shelf draft of each point and its neighbours. We want 2 (at least partially) open cells. # The first open cell is between the draft and the z-level below it, OR the bathymetry and the z-level above it. limit = level_next # The second open cell digs into the layer below OR above that by the minimum amount (based on hFac constraints). hfac_limit = np.maximum(hFacMin, np.minimum(hFacMinDr/dz_next, 1)) limit += direction_flag*dz_next*hfac_limit # In the land mask, there is no limit. if dig_option == 'bathy': # Shallowest acceptable bathymetry is zero limit[bathy==0] = 0 elif dig_option == 'draft': # Deepest acceptable ice shelf draft is the bottom of the grid limit[bathy==0] = z_edges[-1] # Get limit at each point's 4 neighbours limit_w, limit_e, limit_s, limit_n = neighbours(limit)[:4] # Inner function to apply limits to the field (based on each point itself, or each point's neighbour in a single direction eg. west). def dig_one_direction (limit): # Mask out the land either way if dig_option == 'bathy': # Find bathymetry that's too shallow index = (bathy != 0)*(field > limit) elif dig_option == 'draft': # Find ice shelf draft that's too deep index = (bathy != 0)*(field < limit) print '...' + str(np.count_nonzero(index)) + ' cells to dig' field[index] = limit[index] return field field = dig_one_direction(limit) limit_neighbours = [limit_w, limit_e, limit_s, limit_n] loc_strings = ['west', 'east', 'south', 'north'] for i in range(len(loc_strings)): print 'Digging based on field to ' + loc_strings[i] field = dig_one_direction(limit_neighbours[i]) # Error checking if (dig_option == 'bathy' and (field < z_edges[-1]).any()) or (dig_option == 'draft' and (field > 0).any()): print 'Error (do_digging): we have dug off the edge of the grid!!' sys.exit() return field
def edit_mask (nc_in, nc_out, key='WSK'): # Read all the variables lon_2d, lat_2d, bathy, draft, omask, imask = read_nc_grid(nc_in) # Edit the ocean mask based on the domain type if key == 'WSK': # Big Weddell Sea domain # Block out everything west of the peninsula, and extend the peninsula north to 61S # First, close a big box omask = mask_box(omask, lon_2d, lat_2d, xmax=-66, ymin=-74) # Now close everything north of a piecewise line defined by these points points = [[-66, -67], [-62, -65], [-60, -64.5], [-52, -61]] for i in range(len(points)-1): omask = mask_above_line(omask, lon_2d, lat_2d, points[i], points[i+1]) # Now close a couple of little channels near the peninsula, with a few more boxes defined by [xmin, xmax, ymin, ymax] boxes = [[-59, -58, -64.3, -63.6], [-58.5, -57, -63.8, -63.4], [-57, -56.3, -63.4, -63]] for box in boxes: omask = mask_box(omask, lon_2d, lat_2d, xmin=box[0], xmax=box[1], ymin=box[2], ymax=box[3]) # Close a disconnected region near Foundation Ice Stream omask = mask_box(omask, lon_2d, lat_2d, xmin=-65.5, xmax=-63.5, ymin=-81.8, ymax=-81.6) # Turn the Baudouin Ice Shelf into land so there are no ice shelves on the open boundaries omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=24) elif key == 'SO-WISE-GYRE': # SO-WISE (gyre configuration) # Block out everything west of South America omask = mask_box(omask, lon_2d, lat_2d, xmin=-85.0, xmax=-70.0, ymin=-50.0, ymax=-30.0) # Close a disconnected region in the Falkland Islands omask = mask_box(omask, lon_2d, lat_2d, xmin=-60.4, xmax=-58.9, ymin=-52.1, ymax=-51.2) # Close disconnected regions in South America boxes = [[-65.1, -63.9, -43.0, -42.3],[-65.6, -64.6, -40.8, -39.9],[-72.4, -68.6, -54.5, -51.8]] for box in boxes: omask = mask_box(omask, lon_2d, lat_2d, xmin=box[0], xmax=box[1], ymin=box[2], ymax=box[3]) # Turn a few small, isolated ice shelves into land, fill a few other small shelves omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmax=-80, ymin=-75) omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=-65.1, xmax=-63.4, ymin=-81.8, ymax=-81.7) omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=-36.0, xmax=-34.0, ymin=-78.2, ymax=-77.4) omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=45.0, xmax=60.0, ymin=-69.0, ymax=-66.0) omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=80.0, xmax=90.0, ymin=-68.0, ymax=-66.0) # Fill in everything deeper than 6000 m (e.g. South Sandwich Trench) bathy[bathy<-6000] = -6000 elif key == 'WSS': # Small Weddell Sea domain used for coupling # Block out everything west of the peninsula omask = mask_box(omask, lon_2d, lat_2d, xmax=-65, ymin=-75) # Fill all non-FRIS ice shelves with land omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmax=-55, ymin=-74.5) omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=-40, ymin=-78) # Also a few 1-cell ocean points surrounded by ice shelf draft. Fill them with the ice shelf draft of their neighbours. draft_w, draft_e, draft_s, draft_n = neighbours(draft)[:4] imask_w, imask_e, imask_s, imask_n, valid_w, valid_e, valid_s, valid_n, num_valid_neighbours = neighbours(imask, missing_val=0) index = (imask==0)*(num_valid_neighbours==4) imask[index] = 1 draft[index] = 0.25*(draft_w+draft_e+draft_s+draft_n)[index] elif key == 'WSFRIS': # Big Weddell Sea domain used for coupling # Similar to WSK # Block out everything west of the peninsula, and extend the peninsula north to 61S omask = mask_box(omask, lon_2d, lat_2d, xmax=-66, ymin=-74) points = [[-66, -67], [-62, -65], [-60, -64.5], [-52, -61]] for i in range(len(points)-1): omask = mask_above_line(omask, lon_2d, lat_2d, points[i], points[i+1]) boxes = [[-59, -58, -64.3, -63.6], [-58.5, -57, -63.8, -63.4], [-57, -56.3, -63.4, -63]] for box in boxes: omask = mask_box(omask, lon_2d, lat_2d, xmin=box[0], xmax=box[1], ymin=box[2], ymax=box[3]) # Turn the Baudouin Ice Shelf into land so there are no ice shelves on the open boundaries omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=24) # Also a few 1-cell ocean points surrounded by ice shelf draft. Fill them with the ice shelf draft of their neighbours. draft_w, draft_e, draft_s, draft_n = neighbours(draft)[:4] num_valid_neighbours = neighbours(imask, missing_val=0)[-1] index = (imask==0)*(num_valid_neighbours==4) imask[index] = 1 draft[index] = 0.25*(draft_w+draft_e+draft_s+draft_n)[index] # There is one 1-cell open-ocean ocean point surrounded by ice shelf and land. Fill it with land. oomask = omask-imask num_valid_neighbours = neighbours(oomask, missing_val=0)[-1] index = (oomask==1)*(num_valid_neighbours==0) omask[index] = 0 bathy[index] = 0 elif key == 'WSS_old_smaller': # Small Weddell Sea domain - temporary before coupling # Block out everything west of the peninsula omask = mask_box(omask, lon_2d, lat_2d, xmax=-65, ymin=-75) # Remove Larsen D which intersects the open boundary omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, ymin=-73) # There are a few 1-cell islands; fill them with the bathymetry and ice shelf draft of their neighbours omask_w, omask_e, omask_s, omask_n, valid_w, valid_e, valid_s, valid_n, num_valid_neighbours = neighbours(omask, missing_val=0) index = (omask==0)*(num_valid_neighbours==4) omask[index] = 1 bathy_w, bathy_e, bathy_s, bathy_n = neighbours(bathy)[:4] bathy[index] = 0.25*(bathy_w+bathy_e+bathy_s+bathy_n)[index] imask_w, imask_e, imask_s, imask_n = neighbours(imask)[:4] imask[index] = np.ceil(0.25*(imask_w+imask_e+imask_s+imask_n))[index] draft_w, draft_e, draft_s, draft_n = neighbours(draft)[:4] draft[index] = 0.25*(draft_w+draft_e+draft_s+draft_n)[index] # Also a few 1-cell ocean points surrounded by ice shelf draft. Fill them with the ice shelf draft of their neighbours. imask_w, imask_e, imask_s, imask_n, valid_w, valid_e, valid_s, valid_n, num_valid_neighbours = neighbours(imask, missing_val=0) index = (imask==0)*(num_valid_neighbours==4) imask[index] = 1 draft[index] = 0.25*(draft_w+draft_e+draft_s+draft_n)[index] else: raise Exception("Key not found. No edits have been applied") # Make the other fields consistent with this new mask index = omask == 0 bathy[index] = 0 draft[index] = 0 imask[index] = 0 # Copy the NetCDF file to a new name shutil.copyfile(nc_in, nc_out) # Update the variables update_nc_grid(nc_out, bathy, draft, omask, imask) print "Fields updated successfully. The deepest bathymetry is now " + str(abs(np.amin(bathy))) + " m."
def edit_mask(nc_in, nc_out, key='WSK'): # Read all the variables lon_2d, lat_2d, bathy, draft, omask, imask = read_nc_grid(nc_in) # Edit the ocean mask based on the domain type if key == 'WSK': # Big Weddell Sea domain # Block out everything west of the peninsula, and extend the peninsula north to 61S # First, close a big box omask = mask_box(omask, lon_2d, lat_2d, xmax=-66, ymin=-74) # Now close everything north of a piecewise line defined by these points points = [[-66, -67], [-62, -65], [-60, -64.5], [-52, -61]] for i in range(len(points) - 1): omask = mask_above_line(omask, lon_2d, lat_2d, points[i], points[i + 1]) # Now close a couple of little channels near the peninsula, with a few more boxes defined by [xmin, xmax, ymin, ymax] boxes = [[-59, -58, -64.3, -63.6], [-58.5, -57, -63.8, -63.4], [-57, -56.3, -63.4, -63]] for box in boxes: omask = mask_box(omask, lon_2d, lat_2d, xmin=box[0], xmax=box[1], ymin=box[2], ymax=box[3]) # Close a disconnected region near Foundation Ice Stream omask = mask_box(omask, lon_2d, lat_2d, xmin=-65.5, xmax=-63.5, ymin=-81.8, ymax=-81.6) # Turn the Baudouin Ice Shelf into land so there are no ice shelves on the open boundaries omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=24) elif key == 'WSS': # Small Weddell Sea domain used for coupling # Block out everything west of the peninsula omask = mask_box(omask, lon_2d, lat_2d, xmax=-65, ymin=-75) # Fill all non-FRIS ice shelves with land omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmax=-55, ymin=-74.5) omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, xmin=-40, ymin=-78) elif key == 'WSS_old_smaller': # Small Weddell Sea domain - temporary before coupling # Block out everything west of the peninsula omask = mask_box(omask, lon_2d, lat_2d, xmax=-65, ymin=-75) # Remove Larsen D which intersects the open boundary omask = mask_iceshelf_box(omask, imask, lon_2d, lat_2d, ymin=-73) # There are a few 1-cell islands; fill them with the bathymetry and ice shelf draft of their neighbours omask_w, omask_e, omask_s, omask_n, valid_w, valid_e, valid_s, valid_n, num_valid_neighbours = neighbours( omask, missing_val=0) index = (omask == 0) * (num_valid_neighbours == 4) omask[index] = 1 bathy_w, bathy_e, bathy_s, bathy_n = neighbours(bathy)[:4] bathy[index] = 0.25 * (bathy_w + bathy_e + bathy_s + bathy_n)[index] imask_w, imask_e, imask_s, imask_n = neighbours(imask)[:4] imask[index] = np.ceil(0.25 * (imask_w + imask_e + imask_s + imask_n))[index] draft_w, draft_e, draft_s, draft_n = neighbours(draft)[:4] draft[index] = 0.25 * (draft_w + draft_e + draft_s + draft_n)[index] # Also a few 1-cell ocean points surrounded by ice shelf draft. Fill them with the ice shelf draft of their neighbours. imask_w, imask_e, imask_s, imask_n, valid_w, valid_e, valid_s, valid_n, num_valid_neighbours = neighbours( imask, missing_val=0) index = (imask == 0) * (num_valid_neighbours == 4) imask[index] = 1 draft[index] = 0.25 * (draft_w + draft_e + draft_s + draft_n)[index] # Make the other fields consistent with this new mask index = omask == 0 bathy[index] = 0 draft[index] = 0 imask[index] = 0 # Copy the NetCDF file to a new name shutil.copyfile(nc_in, nc_out) # Update the variables update_nc_grid(nc_out, bathy, draft, omask, imask) print "Fields updated successfully. The deepest bathymetry is now " + str( abs(np.amin(bathy))) + " m."
def remove_grid_problems(nc_in, nc_out, dz_file, hFacMin=0.1, hFacMinDr=20.): # Read all the variables lon_2d, lat_2d, bathy, draft, omask, imask = read_nc_grid(nc_in) # Generate the vertical grid dz, z_edges = vertical_layers(dz_file) if z_edges[-1] > np.amin(bathy): print 'Error (remove_grid_problems): deepest bathymetry is ' + str( abs(np.amin(bathy)) ) + ' m, but your vertical levels only go down to ' + str( abs(z_edges[-1]) ) + ' m. Adjust your vertical layer thicknesses and try again.' sys.exit() # Find the actual draft as the model will see it (based on hFac constraints) model_draft = np.copy(draft) # Get some intermediate variables level_below_draft, dz_at_draft = draft_level_vars(draft, dz, z_edges)[:2] # Calculate the hFac of the partial cell below the draft hfac_below_draft = (draft - level_below_draft) / dz_at_draft # Now, modify the draft based on hFac constraints hfac_limit = np.maximum(hFacMin, np.minimum(hFacMinDr / dz_at_draft, 1)) # Find cells which should be fully closed index = hfac_below_draft < hfac_limit / 2 model_draft[index] = level_below_draft[index] # Find cells which should be fully open index = (hfac_below_draft < hfac_limit) * (hfac_below_draft >= hfac_limit / 2) model_draft[index] = level_below_draft[index] + dz_at_draft[index] # Update the intermediate variables (as the layers might have changed now), and also get dz of the layer below the draft level_below_draft, dz_at_draft, dz_below_draft = draft_level_vars( model_draft, dz, z_edges) # Figure out the shallowest acceptable depth of each point and its neighbours, based on the ice shelf draft. We want 2 (at least partially) open cells. # The first open cell is between the draft and the z-level below it. bathy_limit = level_below_draft # The second open cell digs into the level below that by the minimum amount (based on hFac constraints). hfac_limit = np.maximum(hFacMin, np.minimum(hFacMinDr / dz_below_draft, 1)) bathy_limit -= dz_below_draft * hfac_limit # Get bathy_limit at each point's 4 neighbours bathy_limit_w, bathy_limit_e, bathy_limit_s, bathy_limit_n = neighbours( bathy_limit)[:4] # Make a copy of the original bathymetry for comparison later bathy_orig = np.copy(bathy) print 'Digging based on local ice shelf draft' bathy = dig_one_direction(bathy, bathy_limit) bathy_limit_neighbours = [ bathy_limit_w, bathy_limit_e, bathy_limit_s, bathy_limit_n ] loc_strings = ['west', 'east', 'south', 'north'] for i in range(len(loc_strings)): print 'Digging based on ice shelf draft to ' + loc_strings[i] bathy = dig_one_direction(bathy, bathy_limit_neighbours[i]) # Plot how the results have changed plot_tmp_domain(lon_2d, lat_2d, np.ma.masked_where(omask == 0, bathy), title='Bathymetry (m) after digging') plot_tmp_domain(lon_2d, lat_2d, np.ma.masked_where(omask == 0, bathy - bathy_orig), title='Change in bathymetry (m)\ndue to digging') if hFacMinDr >= dz[0]: print 'Zapping ice shelf drafts which are too shallow' # Find any points which are less than half the depth of the surface layer index = (draft != 0) * (abs(draft) < 0.5 * dz[0]) print '...' + str(np.count_nonzero(index)) + ' cells to zap' draft[index] = 0 imask[index] = 0 # Plot how the results have changed plot_tmp_domain(lon_2d, lat_2d, np.ma.masked_where(omask == 0, index.astype(int)), title='Ice shelf points which were zapped') # Copy the NetCDF file to a new name shutil.copyfile(nc_in, nc_out) # Update the variables update_nc_grid(nc_out, bathy, draft, omask, imask) print "The updated grid has been written into " + nc_out + ". Take a look and make sure everything looks okay. If you're happy, run write_topo_files to generate the binary files for MITgcm input."
def get_boundary(condition_mask): num_neighbours_violate = neighbours(condition_mask, missing_val=0)[-1] return mask * (num_neighbours_violate > 0)