def test_make_ibound(all_layers): top = all_layers[0].copy() botm = all_layers[1:].copy() nodata = -9999 botm[-1, 0, 0] = nodata botm[-2] = 2 botm[-2, 2, 2] = np.nan botm[:, 3, 3] = np.arange(1, 10)[::-1] # column of cells all eq. to min thickness filled_top, filled_botm = fill_cells_vertically(top, botm) ibound = make_ibound(top, botm, nodata=nodata, minimum_layer_thickness=1, drop_thin_cells=True, tol=1e-4) # test ibound based on nans assert np.array_equal(ibound[:, 2, 2].astype(bool), ~np.isnan(botm[:, 2, 2])) # test ibound based on nodata assert ibound[-1, 0, 0] == 0 # test ibound based on layer thickness # unlike for idomain, individual cells < min thickness are not deactivated # (unless all cells at i, j location are < min thickness + tol) assert ibound[-1].sum() == 98 assert ibound[-2].sum() == 98 # test that nans in the model top result in the highest active botms being excluded # (these cells have valid botms, but no tops) assert ibound[:, 0, 0].sum() == 1 # in all_layers, cells with valid tops are idomain=0 # because all botms in layer 1 are nans assert ibound[0].sum() == 0 # test edge case of values that match the layer thickness when tol=0 ibound = make_ibound(top, botm, nodata=nodata, minimum_layer_thickness=1, drop_thin_cells=True, tol=0) assert ibound[-1].sum() == 99
def rasters_to_grid(modelgrid, dem, rasters, dem_elevation_units='meters', raster_elevation_units='meters', dest_elevation_units='meters'): """Sample a sequence of rasters onto the i, j locations of a modelgrid, returning a 3D numpy array of the sampled elevations. Fill places with nodata using the next valid surface above. Parameters ---------- modelgrid : Modflow-setup :class:`~mfsetup.grid.MFsetupGrid` instance Modflow-setup grid instance describing the model grid dem : str (filepath) Raster representing the land surface, at the highest resolution being contemplated for the model. Usually this is derived by sampling a higher resolution DEM using zonal statistics, taking the mean DEM value for each model cell. rasters : list of strings (filepaths) Raster surfaces describing hydrogelogic contacts surrounding the voxel data. dem_elevation_units : str, optional Elevation units of dem_means_raster, by default 'meters' framework_raster_elevation_units : str, optional Elevation units of the framework_rasters, by default 'meters' model_length_units : str, optional Length units used in the model, by default 'meters' References ---------- See the documentation for the :func:`fill_cells_vertically <mfsetup.discretization.fill_cells_vertically>` function in Modflow-setup for an explanation of the filling process. """ grid = modelgrid dem_elevations = get_values_at_points(dem, grid.xcellcenters, grid.ycellcenters, method='linear') # convert to model units dem_elevations *= convert_length_units(dem_elevation_units, dest_elevation_units) raster_elevations = [] for raster in rasters: grid_cell_values = get_values_at_points(raster, grid.xcellcenters, grid.ycellcenters, method='linear') # convert to model units grid_cell_values *= convert_length_units(raster_elevation_units, dest_elevation_units) raster_elevations.append(grid_cell_values) raster_elevations = np.array(raster_elevations) # fill nans in the sampled original framework elevations # (nans are where a layer surface is absent) # fill the nans with the next surface above # see https://github.com/aleaf/modflow-setup/blob/develop/mfsetup/discretization.py model_top_filled, filled_raster_elevations = fill_cells_vertically(dem_elevations, raster_elevations) above_land_surface = filled_raster_elevations > dem_elevations # reset any values above land surface to land surface dem_means_3d = np.tile(dem_elevations, (filled_raster_elevations.shape[0], 1, 1)) filled_raster_elevations[above_land_surface] = dem_means_3d[above_land_surface] del dem_means_3d filled_raster_elevations = np.vstack([np.reshape(dem_elevations, (1, *dem_elevations.shape)), filled_raster_elevations]) return filled_raster_elevations
def test_fill_na(all_layers): top = all_layers[0].copy() botm = all_layers[1:].copy() botm[-2] = 2 botm[-2, 2, 2] = np.nan top, botm = fill_cells_vertically(top, botm) filled = all_layers.copy() filled[0] = top filled[1:] = botm assert filled[:, 2, 2].tolist() == [10., 10., 8., 8., 8., 5., 5., 5., 5, 1.] assert filled[:, 0, 0].tolist() == [8] * 8 + [2, 1]