def test_director_adding_methods_are_equivalent_D8(): """Check that different methods to specifying the director are the same.""" mg0 = RasterModelGrid((10,10), spacing=(1, 1)) z0 = mg0.add_field('topographic__elevation', mg0.node_x**2 + mg0.node_y**2, at = 'node') fa0 = FlowAccumulator(mg0, flow_director='D8') fa0.run_one_step() mg1 = RasterModelGrid((10,10), spacing=(1, 1)) z1 = mg1.add_field('topographic__elevation', mg1.node_x**2 + mg1.node_y**2, at = 'node') fa1 = FlowAccumulator(mg1, flow_director='FlowDirectorD8') fa1.run_one_step() mg2 = RasterModelGrid((10,10), spacing=(1, 1)) z2 = mg2.add_field('topographic__elevation', mg2.node_x**2 + mg2.node_y**2, at = 'node') fa2 = FlowAccumulator(mg2, flow_director=FlowDirectorD8) fa2.run_one_step() mg3 = RasterModelGrid((10,10), spacing=(1, 1)) z3 = mg3.add_field('topographic__elevation', mg3.node_x**2 + mg3.node_y**2, at = 'node') fd = FlowDirectorD8(mg3) fa3 = FlowAccumulator(mg3, flow_director=fd) fa3.run_one_step() for key in mg0.at_node.keys(): assert_array_equal(mg0.at_node[key], mg1.at_node[key]) assert_array_equal(mg1.at_node[key], mg2.at_node[key]) assert_array_equal(mg2.at_node[key], mg3.at_node[key])
def test_netcdf_write(): """Test generic write_netcdf.""" if not WITH_NETCDF4: raise SkipTest('netCDF4 package not installed') field = RasterModelGrid(4, 3) field.add_field('node', 'topographic__elevation', np.arange(12.)) with cdtemp() as _: write_netcdf('test.nc', field, format='NETCDF4') root = nc.Dataset('test.nc', 'r', format='NETCDF4') assert_equal(set(root.dimensions), set(['ni', 'nj', 'nt'])) assert_equal(len(root.dimensions['ni']), 3) assert_equal(len(root.dimensions['nj']), 4) assert_true(len(root.dimensions['nt']), 1) assert_true(root.dimensions['nt'].isunlimited()) assert_equal(set(root.variables), set(['x', 'y', 'topographic__elevation'])) assert_array_equal(root.variables['x'][:].flat, np.array([0., 1., 2., 0., 1., 2., 0., 1., 2., 0., 1., 2., ])) assert_array_equal(root.variables['y'][:].flat, np.array([0., 0., 0., 1., 1., 1., 2., 2., 2., 3., 3., 3., ])) assert_array_equal(root.variables['topographic__elevation'][:].flat, field.at_node['topographic__elevation']) root.close()
def test_save_esri_ascii(tmpdir): grid = RasterModelGrid((4, 5), xy_spacing=2.0) grid.add_field("node", "air__temperature", np.arange(20.0)) with tmpdir.as_cwd(): grid.save("test.asc", format="esri-ascii") assert os.path.isfile("test.asc")
def test_netcdf_write_at_cells(tmpdir): """Test write_netcdf using with cell fields""" field = RasterModelGrid((4, 3)) field.add_field("cell", "topographic__elevation", np.arange(field.number_of_cells)) field.add_field("cell", "uplift_rate", np.arange(field.number_of_cells)) with tmpdir.as_cwd(): write_netcdf("test-cells.nc", field, format="NETCDF4") root = nc.Dataset("test-cells.nc", "r", format="NETCDF4") for name in ["topographic__elevation", "uplift_rate"]: assert name in root.variables assert_array_equal(root.variables[name][:].flatten(), field.at_cell[name]) assert set(root.dimensions) == set(["nv", "ni", "nj", "nt"]) assert len(root.dimensions["nv"]) == 4 assert len(root.dimensions["ni"]) == 1 assert len(root.dimensions["nj"]) == 2 assert len(root.dimensions["nt"]) == 1 assert root.dimensions["nt"].isunlimited() assert set(root.variables) == set( ["x_bnds", "y_bnds", "topographic__elevation", "uplift_rate"] ) root.close()
def test_append_with_time(tmpdir): field = RasterModelGrid(4, 3) field.add_field("node", "topographic__elevation", np.ones(12, dtype=np.int64)) with tmpdir.as_cwd(): write_raster_netcdf("test.nc", field, append=False, format="NETCDF4", time=0) field.at_node["topographic__elevation"] *= 2 write_raster_netcdf("test.nc", field, append=True, format="NETCDF4", time=1.) root = nc.Dataset("test.nc", "r", format="NETCDF4") for name in ["topographic__elevation"]: assert name in root.variables assert_array_equal( root.variables[name][:], [ [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]], ], ) assert root.variables[name][:].dtype == "int64" assert "nt" in root.dimensions assert len(root.dimensions["nt"]) == 2 assert "t" in root.variables assert_array_equal(root.variables["t"][:], [0., 1.]) root.close()
def sink_grid4(): """ Create a 10x10 test grid with two well defined holes in it, into an inclined surface. This time, one of the holes is a stupid shape, which will require the component to arrange flow back "uphill". """ sink_grid = RasterModelGrid((10, 10), xy_spacing=1.0) lake1 = np.array([34, 35, 36, 44, 45, 46, 54, 55, 56, 65, 74]) lake2 = np.array([78, 87, 88]) guard_nodes = np.array([23, 33, 53, 63, 73, 83]) lake = np.concatenate((lake1, lake2)) # outlet = 35 # shouldn't be needed # outlet_array = np.array([outlet]) z = np.ones(100, dtype=float) # add slope z += sink_grid.node_x z[guard_nodes] += 0.001 # forces the flow out of a particular node z[lake] = 0.0 # depr_outlet_target = np.empty(100, dtype=float) # depr_outlet_target.fill(XX) # depr_outlet_target = XX # not well defined in this simplest case...? sink_grid.add_field("node", "topographic__elevation", z, units="-") sink_grid.lake1 = lake1 sink_grid.lake2 = lake2 return sink_grid
def test_netcdf_write(): if not WITH_NETCDF4: raise SkipTest("netCDF4 package not installed") field = RasterModelGrid(4, 3) field.add_field("node", "topographic__elevation", np.arange(12.0)) with cdtemp() as _: write_netcdf("test.nc", field, format="NETCDF4") root = nc.Dataset("test.nc", "r", format="NETCDF4") assert_equal(set(root.dimensions), set(["ni", "nj", "nt"])) assert_equal(len(root.dimensions["ni"]), 3) assert_equal(len(root.dimensions["nj"]), 4) assert_true(len(root.dimensions["nt"]), 1) assert_true(root.dimensions["nt"].isunlimited()) assert_equal(set(root.variables), set(["x", "y", "topographic__elevation"])) assert_array_equal( root.variables["x"][:].flat, np.array([0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0]) ) assert_array_equal( root.variables["y"][:].flat, np.array([0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0]) ) assert_array_equal(root.variables["topographic__elevation"][:].flat, field.at_node["topographic__elevation"]) root.close()
def test_netcdf_write(tmpdir): """Test generic write_netcdf.""" field = RasterModelGrid(4, 3) field.add_field("node", "topographic__elevation", np.arange(12.)) with tmpdir.as_cwd(): write_netcdf("test.nc", field, format="NETCDF4") root = nc.Dataset("test.nc", "r", format="NETCDF4") assert set(root.dimensions) == set(["ni", "nj", "nt"]) assert len(root.dimensions["ni"]) == 3 assert len(root.dimensions["nj"]) == 4 assert len(root.dimensions["nt"]) == 1 assert root.dimensions["nt"].isunlimited() assert set(root.variables) == set(["x", "y", "topographic__elevation"]) assert_array_equal( root.variables["x"][:].flatten(), np.array([0., 1., 2., 0., 1., 2., 0., 1., 2., 0., 1., 2.]), ) assert_array_equal( root.variables["y"][:].flatten(), np.array([0., 0., 0., 1., 1., 1., 2., 2., 2., 3., 3., 3.]), ) assert_array_equal( root.variables["topographic__elevation"][:].flatten(), field.at_node["topographic__elevation"], ) root.close()
def test_names_keyword_with_bad_name(tmpdir): grid = RasterModelGrid((4, 5), spacing=(2., 2.)) grid.add_field('node', 'air__temperature', np.arange(20.)) with tmpdir.as_cwd(): with pytest.raises(ValueError): write_esri_ascii('test.asc', grid, names='not_a_name')
def test_netcdf_write_at_cells(): """Test write_netcdf using with cell fields""" if not WITH_NETCDF4: raise SkipTest("netCDF4 package not installed") field = RasterModelGrid((4, 3)) field.add_field("cell", "topographic__elevation", np.arange(field.number_of_cells)) field.add_field("cell", "uplift_rate", np.arange(field.number_of_cells)) with cdtemp() as _: write_netcdf("test-cells.nc", field, format="NETCDF4") root = nc.Dataset("test-cells.nc", "r", format="NETCDF4") for name in ["topographic__elevation", "uplift_rate"]: assert_true(name in root.variables) assert_array_equal(root.variables[name][:].flat, field.at_cell[name]) assert_equal(set(root.dimensions), set(["nv", "ni", "nj", "nt"])) assert_equal(len(root.dimensions["nv"]), 4) assert_equal(len(root.dimensions["ni"]), 1) assert_equal(len(root.dimensions["nj"]), 2) assert_true(len(root.dimensions["nt"]), 1) assert_true(root.dimensions["nt"].isunlimited()) assert_equal(set(root.variables), set(["x_bnds", "y_bnds", "topographic__elevation", "uplift_rate"])) root.close()
def test_error_for_to_many_with_depression(): """Check that an error is thrown when to_many methods started DF.""" mg0 = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg0.add_field( "topographic__elevation", mg0.node_x ** 2 + mg0.node_y ** 2, at="node" ) mg1 = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg1.add_field( "topographic__elevation", mg1.node_x ** 2 + mg1.node_y ** 2, at="node" ) with pytest.raises(NotImplementedError): LossyFlowAccumulator( mg0, flow_director="MFD", depression_finder="DepressionFinderAndRouter" ) with pytest.raises(NotImplementedError): LossyFlowAccumulator( mg0, flow_director="DINF", depression_finder="DepressionFinderAndRouter" ) fa0 = LossyFlowAccumulator(mg0, flow_director="MFD") fa0.run_one_step() with pytest.raises(NotImplementedError): DepressionFinderAndRouter(mg0) fa1 = LossyFlowAccumulator(mg1, flow_director="DINF") fa1.run_one_step() with pytest.raises(NotImplementedError): DepressionFinderAndRouter(mg1)
def test_save_esri_ascii(tmpdir): grid = RasterModelGrid(4, 5, 2.) grid.add_field('node', 'air__temperature', np.arange(20.)) with tmpdir.as_cwd(): grid.save('test.asc', format='esri-ascii') assert os.path.isfile('test.asc')
def test_netcdf_write(): field = RasterModelGrid(4, 3) #field.new_field_location('node', 12.) values = np.arange(12.) field.add_field('node', 'planet_surface__elevation', values) write_netcdf('test.nc', field) import netCDF4 as nc root = nc.Dataset('test.nc', 'r', format='NETCDF4') assert_equal(set(root.dimensions), set(['ni', 'nj', 'nt'])) assert_equal(len(root.dimensions['ni']), 3) assert_equal(len(root.dimensions['nj']), 4) assert_true(len(root.dimensions['nt']), 1) assert_true(root.dimensions['nt'].isunlimited()) assert_equal(set(root.variables), set(['x', 'y', 'planet_surface__elevation'])) assert_list_equal(list(root.variables['x'][:].flat), [0., 1., 2., 0., 1., 2., 0., 1., 2., 0., 1., 2., ]) assert_list_equal(list(root.variables['y'][:].flat), [0., 0., 0., 1., 1., 1., 2., 2., 2., 3., 3., 3., ]) assert_list_equal( list(root.variables['planet_surface__elevation'][:].flat), range(12)) root.close()
def test_run_with_2_fn_args(): mg = RasterModelGrid((3, 5), xy_spacing=(2, 1)) mg.set_closed_boundaries_at_grid_edges(True, True, False, True) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") def mylossfunction(qw, nodeID): return 0.5 * qw fa = LossyFlowAccumulator( mg, "topographic__elevation", flow_director=FlowDirectorSteepest, routing="D4", loss_function=mylossfunction, ) fa.run_one_step() assert np.allclose( mg.at_node["drainage_area"].reshape(mg.shape), np.array([[0., 0., 0., 0., 0.], [6., 6., 4., 2., 0.], [0., 0., 0., 0., 0.]]), ) assert np.allclose( mg.at_node["surface_water__discharge"].reshape(mg.shape), np.array( [ [0.00, 0.00, 0.00, 0.00, 0.00], [1.75, 3.50, 3.00, 2.00, 0.00], [0.00, 0.00, 0.00, 0.00, 0.00], ] ), )
def setup_dans_grid2(): """ Create a 10x10 test grid with a well defined hole in it, from a flat surface. """ global hf, mg global z, depr_outlet_target global lake, outlet, lake_code, outlet_array lake = np.array([44, 45, 46, 54, 55, 56, 64, 65, 66]) outlet = 35 # shouldn't be needed lake_code = 44 outlet_array = np.array([outlet]) mg = RasterModelGrid(10, 10, 1.) z = np.ones(100, dtype=float) z[lake] = 0. depr_outlet_target = np.empty(100, dtype=float) depr_outlet_target.fill(XX) depr_outlet_target = XX # not well defined in this simplest case...? mg.add_field('node', 'topographic__elevation', z, units='-') hf = SinkFiller(mg)
def setup_dans_grid3(): """ Create a 10x10 test grid with two well defined holes in it, into an inclined surface. """ global hf, fr, mg global z, depr_outlet_target global lake, lake1, lake2, outlet, outlet_array, rcvr lake1 = np.array([34, 35, 36, 44, 45, 46, 54, 55, 56]) lake2 = np.array([77, 78, 87, 88]) guard_nodes = np.array([23, 33, 53, 63]) lake = np.concatenate((lake1, lake2)) outlet = 35 # shouldn't be needed outlet_array = np.array([outlet]) mg = RasterModelGrid(10, 10, 1.) z = np.ones(100, dtype=float) # add slope z += mg.node_x z[guard_nodes] += 0.001 z[lake] = 0. depr_outlet_target = np.empty(100, dtype=float) depr_outlet_target.fill(XX) depr_outlet_target = XX # not well defined in this simplest case...? mg.add_field('node', 'topographic__elevation', z, units='-') fr = FlowRouter(mg)
def setup_dans_grid4(): """ Create a 10x10 test grid with two well defined holes in it, into an inclined surface. This time, one of the holes is a stupid shape, which will require the component to arrange flow back "uphill". """ global hf, fr, mg global z, depr_outlet_target global lake, lake1, lake2, outlet, outlet_array lake1 = np.array([34, 35, 36, 44, 45, 46, 54, 55, 56, 65, 74]) lake2 = np.array([78, 87, 88]) guard_nodes = np.array([23, 33, 53, 63, 73, 83]) lake = np.concatenate((lake1, lake2)) outlet = 35 # shouldn't be needed outlet_array = np.array([outlet]) mg = RasterModelGrid(10, 10, 1.) z = np.ones(100, dtype=float) # add slope z += mg.node_x z[guard_nodes] += 0.001 # forces the flow out of a particular node z[lake] = 0. depr_outlet_target = np.empty(100, dtype=float) depr_outlet_target.fill(XX) depr_outlet_target = XX # not well defined in this simplest case...? mg.add_field('node', 'topographic__elevation', z, units='-') fr = FlowRouter(mg)
def test_names_keyword_with_bad_name(tmpdir): grid = RasterModelGrid((4, 5), xy_spacing=(2.0, 2.0)) grid.add_field("node", "air__temperature", np.arange(20.0)) with tmpdir.as_cwd(): with pytest.raises(ValueError): write_esri_ascii("test.asc", grid, names="not_a_name")
def test_names_keyword_with_bad_name(): grid = RasterModelGrid((4, 5), spacing=(2., 2.)) grid.add_field('node', 'air__temperature', np.arange(20.)) with cdtemp() as _: assert_raises(ValueError, write_esri_ascii, 'test.asc', grid, names='not_a_name')
def read_netcdf(nc_file, reshape=False, just_grid=False): """ Reads the NetCDF file *nc_file*, and writes it to the fields of a new RasterModelGrid, which it then returns. Check the names of the fields in the returned grid with grid.at_nodes.keys(). """ try: root = nc.netcdf_file(nc_file, 'r', version=2) except TypeError: root = nc4.Dataset(nc_file, 'r', format='NETCDF4') shape = _read_netcdf_grid_shape(root) spacing = _read_netcdf_grid_spacing(root) assert(len(shape) == 2) assert(len(spacing) == 2) if spacing[0] != spacing[1]: raise NotRasterGridError() grid = RasterModelGrid(num_rows=shape[0], num_cols=shape[1], dx=spacing[0]) if not just_grid: fields = _read_netcdf_structured_data(root) for (name, values) in fields.items(): grid.add_field('node', name, values) root.close() return grid
def test_with_time_netcdf3(tmpdir): field = RasterModelGrid((4, 3)) field.add_field("node", "topographic__elevation", 2.0 * np.arange(12.0)) field.add_field("node", "uplift_rate", 2.0 * np.arange(12.0)) with tmpdir.as_cwd(): write_raster_netcdf("test.nc", field, format="NETCDF3_64BIT", time=10.0) root = nc.Dataset("test.nc", "r", format="NETCDF3_64BIT") for name in ["uplift_rate", "topographic__elevation"]: assert name in root.variables assert_array_equal( root.variables[name][:], [ [ [0.0, 2.0, 4.0], [6.0, 8.0, 10.0], [12.0, 14.0, 16.0], [18.0, 20.0, 22.0], ] ], ) assert "nt" in root.dimensions assert len(root.dimensions["nt"]) == 1 assert "t" in root.variables assert_array_equal(root.variables["t"][:], [10.0]) root.close()
def setup_D4_grid(): """ Test functionality of routing when D4 is specified. The elevation field in this test looks like: 1 2 3 4 5 6 7 1 2 3 0 5 0 7 1 2 3 4 0 0 7 1 2 3 0 5 6 7 1 2 0 0 0 6 7 1 2 3 0 5 6 7 1 2 3 4 5 6 7 """ global frD8, frD4, lfD8, lfD4, mg1, mg2 global z, lake_nodes mg1 = RasterModelGrid(7, 7, 1.) mg2 = RasterModelGrid(7, 7, 1.) z = mg1.node_x.copy() + 1. lake_nodes = np.array([10, 16, 17, 18, 24, 32, 33, 38, 40]) z[lake_nodes] = 0. mg1.add_field('node', 'topographic__elevation', z, units='-') mg2.add_field('node', 'topographic__elevation', z, units='-') frD8 = FlowRouter(mg1, method='D8') frD4 = FlowRouter(mg2, method='D4') lfD8 = DepressionFinderAndRouter(mg1, routing='D8') lfD4 = DepressionFinderAndRouter(mg2, routing='D4')
def test_add_field_at_corners(): """Test add a field to corners.""" grid = RasterModelGrid((4, 5)) x = np.arange(grid.number_of_corners) grid.add_field('z', x, at='corner') assert_array_equal(grid.at_corner['z'], x)
def test_MFD_S_slope_w_diag(): mg = RasterModelGrid((10, 10)) mg.add_field("topographic__elevation", mg.node_y, at="node") fa = FlowAccumulator(mg, flow_director="FlowDirectorMFD", diagonals=True) fa.run_one_step() # this one should part to south west, part to south, and part to southeast sw_diags = mg.diagonal_adjacent_nodes_at_node[:, 2] se_diags = mg.diagonal_adjacent_nodes_at_node[:, 3] s_links = mg.adjacent_nodes_at_node[:, 3] node_ids = np.arange(mg.number_of_nodes) true_recievers = -1 * np.ones(fa.flow_director.receivers.shape) true_recievers[mg.core_nodes, 3] = s_links[mg.core_nodes] true_recievers[mg.core_nodes, 6] = sw_diags[mg.core_nodes] true_recievers[mg.core_nodes, 7] = se_diags[mg.core_nodes] true_recievers[mg.boundary_nodes, 0] = node_ids[mg.boundary_nodes] true_proportions = np.zeros(fa.flow_director.proportions.shape) true_proportions[mg.boundary_nodes, 0] = 1 total_sum_of_slopes = 1. + 2. * (1. / 2. ** 0.5) true_proportions[mg.core_nodes, 3] = 1.0 / total_sum_of_slopes true_proportions[mg.core_nodes, 6] = (1. / 2. ** 0.5) / total_sum_of_slopes true_proportions[mg.core_nodes, 7] = (1. / 2. ** 0.5) / total_sum_of_slopes assert_array_equal(true_recievers, fa.flow_director.receivers) assert_array_almost_equal(true_proportions, fa.flow_director.proportions)
def setup_dans_grid1(): """ Create a 7x7 test grid with a well defined hole in it. """ global hf, mg global z, r_new, r_old, A_new, A_old, s_new, depr_outlet_target global lake, outlet, lake_code, outlet_array mg = RasterModelGrid(7, 7, 1.) z = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.0, 2.0, 1.6, 1.5, 1.6, 2.0, 0.0, 0.0, 2.0, 1.7, 1.6, 1.7, 2.0, 0.0, 0.0, 2.0, 1.8, 2.0, 2.0, 2.0, 0.0, 0.0, 1.0, 0.6, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0]).flatten() depr_outlet_target = np.array([XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 30, 30, 30, XX, XX, XX, XX, 30, 30, 30, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX]).flatten() lake = np.array([16, 17, 18, 23, 24, 25]) outlet = 30 lake_code = 17 outlet_array = np.array([outlet]) mg.add_field('node', 'topographic__elevation', z, units='-') hf = SinkFiller(mg)
def test_grid_with_one_field(): grid = RasterModelGrid((4, 5), spacing=(2., 2.)) grid.add_field('node', 'air__temperature', np.arange(20.)) with cdtemp() as _: files = write_esri_ascii('test.asc', grid) assert_list_equal(files, ['test.asc']) for fname in files: assert_true(os.path.isfile(fname))
def test_grid_with_one_field(tmpdir): grid = RasterModelGrid((4, 5), xy_spacing=(2.0, 2.0)) grid.add_field("node", "air__temperature", np.arange(20.0)) with tmpdir.as_cwd(): files = write_esri_ascii("test.asc", grid) assert files == ["test.asc"] for fname in files: assert os.path.isfile(fname)
def test_grid_with_one_field(tmpdir): grid = RasterModelGrid((4, 5), spacing=(2., 2.)) grid.add_field('node', 'air__temperature', np.arange(20.)) with tmpdir.as_cwd(): files = write_esri_ascii('test.asc', grid) assert files == ['test.asc'] for fname in files: assert os.path.isfile(fname)
def test_instantiated_depression_finder_with_kwargs(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") df = DepressionFinderAndRouter(mg) with pytest.raises(ValueError): LossyFlowAccumulator( mg, flow_director="D8", depression_finder=df, routing="eggs" )
def test_flow__distance_regular_grid_d8(): """Test to demonstrate that flow__distance utility works as expected with regular grids""" # instantiate a model grid mg = RasterModelGrid((5, 4), spacing=(1, 1)) # instantiate an elevation array z = np.array([[0, 0, 0, 0], [0, 21, 10, 0], [0, 31, 20, 0], [0, 32, 30, 0], [0, 0, 0, 0]], dtype='float64') # add the elevation field to the grid mg.add_field('node', 'topographic__elevation', z) # instantiate the expected flow__distance array # considering flow directions calculated with D8 algorithm flow__distance_expected = np.array([[0, 0, 0, 0], [0, 1, 0, 0], [0, math.sqrt(2), 1, 0], [0, 1+math.sqrt(2), 2, 0], [0, 0, 0, 0]], dtype='float64') flow__distance_expected = np.reshape(flow__distance_expected, mg.number_of_node_rows * mg.number_of_node_columns) #setting boundary conditions mg.set_closed_boundaries_at_grid_edges(bottom_is_closed=True, left_is_closed=True, right_is_closed=True, top_is_closed=True) # calculating flow directions with FlowAccumulator component fr = FlowAccumulator(mg, flow_director='D8') fr.run_one_step() # calculating flow distance map flow__distance = calculate_flow__distance(mg, add_to_grid=True, noclobber=False) flow__distance = np.reshape(flow__distance, mg.number_of_node_rows * mg.number_of_node_columns) # modifying the flow distance map because boundary and outlet nodes should # not have flow__distance value different from 0 flow__distance[mg.boundary_nodes] = 0 outlet_id = 6 flow__distance[outlet_id] = 0 # test that the flow distance utility works as expected assert_array_equal(flow__distance_expected, flow__distance)
def test_check_fields(): """Check to make sure the right fields have been created. Check that the sizes of at least one are also correct (they are at node so if one is the right size, then they all should be) """ mg0 = RasterModelGrid((10, 10), spacing=(1, 1)) mg0.add_field("topographic__elevation", mg0.node_x**2 + mg0.node_y**2, at="node") _FlowDirector(mg0, "topographic__elevation") assert sorted(list(mg0.at_node.keys())) == [ "flow__sink_flag", "topographic__elevation", ] assert np.size( mg0.at_node["topographic__elevation"]) == mg0.number_of_nodes mg1 = RasterModelGrid((10, 10), spacing=(1, 1)) mg1.add_field("topographic__elevation", mg1.node_x**2 + mg1.node_y**2, at="node") _FlowDirectorToMany(mg1, "topographic__elevation") assert sorted(list(mg1.at_node.keys())) == [ "flow__sink_flag", "topographic__elevation", ] assert np.size( mg1.at_node["topographic__elevation"]) == mg1.number_of_nodes mg2 = RasterModelGrid((10, 10), spacing=(1, 1)) mg2.add_field("topographic__elevation", mg2.node_x**2 + mg2.node_y**2, at="node") _FlowDirectorToOne(mg2, "topographic__elevation") assert sorted(list(mg2.at_node.keys())) == [ "flow__link_to_receiver_node", "flow__receiver_node", "flow__sink_flag", "topographic__elevation", "topographic__steepest_slope", ] assert np.size( mg2.at_node["topographic__elevation"]) == mg2.number_of_nodes mg3 = RasterModelGrid((10, 10), spacing=(1, 1)) mg3.add_field("topographic__elevation", mg3.node_x**2 + mg3.node_y**2, at="node") FlowDirectorMFD(mg3, "topographic__elevation") assert sorted(list(mg3.at_node.keys())) == [ "flow__link_to_receiver_node", "flow__receiver_node", "flow__receiver_proportions", "flow__sink_flag", "topographic__elevation", "topographic__steepest_slope", ] assert np.size( mg3.at_node["topographic__elevation"]) == mg3.number_of_nodes mg4 = RasterModelGrid((10, 10), spacing=(1, 1)) mg4.add_field("topographic__elevation", mg4.node_x**2 + mg4.node_y**2, at="node") FlowDirectorDINF(mg4, "topographic__elevation") assert sorted(list(mg4.at_node.keys())) == [ "flow__link_to_receiver_node", "flow__receiver_node", "flow__receiver_proportions", "flow__sink_flag", "topographic__elevation", "topographic__steepest_slope", ] assert np.size( mg4.at_node["topographic__elevation"]) == mg4.number_of_nodes mg5 = RasterModelGrid((10, 10), spacing=(1, 1)) mg5.add_field("topographic__elevation", mg5.node_x**2 + mg5.node_y**2, at="node") FlowDirectorSteepest(mg5, "topographic__elevation") assert sorted(list(mg5.at_node.keys())) == [ "flow__link_to_receiver_node", "flow__receiver_node", "flow__sink_flag", "topographic__elevation", "topographic__steepest_slope", ] assert np.size( mg5.at_node["topographic__elevation"]) == mg5.number_of_nodes mg6 = RasterModelGrid((10, 10), spacing=(1, 1)) mg6.add_field("topographic__elevation", mg6.node_x**2 + mg6.node_y**2, at="node") FlowDirectorD8(mg6, "topographic__elevation") assert sorted(list(mg6.at_node.keys())) == [ "flow__link_to_receiver_node", "flow__receiver_node", "flow__sink_flag", "topographic__elevation", "topographic__steepest_slope", ] assert np.size( mg6.at_node["topographic__elevation"]) == mg6.number_of_nodes
def dans_grid1(): """ Create a 5x5 test grid. This is a sheet flow test. """ mg = RasterModelGrid((5, 5), spacing=(10., 10.)) this_dir = os.path.abspath(os.path.dirname(__file__)) infile = os.path.join(this_dir, "test_fr_input.txt") z = mg.node_x.copy() Q_in = np.full(25, 2.) A_target = (np.array([ [0., 0., 0., 0., 0.], [3., 3., 2., 1., 0.], [3., 3., 2., 1., 0.], [3., 3., 2., 1., 0.], [0., 0., 0., 0., 0.], ]).flatten() * 100.) frcvr_target = np.array([ [0, 1, 2, 3, 4], [5, 5, 6, 7, 9], [10, 10, 11, 12, 14], [15, 15, 16, 17, 19], [20, 21, 22, 23, 24], ]).flatten() upids_target = np.array([ [0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24], ]).flatten() links2rcvr_target = np.full(25, XX) links2rcvr_target[mg.core_nodes] = np.array( [9, 10, 11, 18, 19, 20, 27, 28, 29]) Q_target = A_target * 2. # only once Q_in is used steepest_target = np.array([ [0., 0., 0., 0., 0.], [0., 1., 1., 1., 0.], [0., 1., 1., 1., 0.], [0., 1., 1., 1., 0.], [0., 0., 0., 0., 0.], ]).flatten() mg.add_field("node", "topographic__elevation", z, units="-") class DansGrid(object): pass dans_grid = DansGrid() dans_grid.mg = mg dans_grid.z = z dans_grid.infile = infile dans_grid.A_target = A_target dans_grid.frcvr_target = frcvr_target dans_grid.upids_target = upids_target dans_grid.Q_target = Q_target dans_grid.steepest_target = steepest_target dans_grid.links2rcvr_target = links2rcvr_target return dans_grid
def setup_dans_grid(): """ Create a 7x7 test grid with a well defined hole in it. """ from landlab import RasterModelGrid from landlab.components.flow_routing import (FlowRouter, DepressionFinderAndRouter) global fr, lf, mg global z, r_new, r_old, A_new, A_old, s_new, depr_outlet_target global links_old, links_new mg = RasterModelGrid(7, 7, 1.) z = np.array([ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.0, 2.0, 1.6, 1.5, 1.6, 2.0, 0.0, 0.0, 2.0, 1.7, 1.6, 1.7, 2.0, 0.0, 0.0, 2.0, 1.8, 2.0, 2.0, 2.0, 0.0, 0.0, 1.0, 0.6, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0 ]).flatten() r_old = np.array([ 0, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 13, 14, 14, 17, 17, 17, 20, 20, 21, 21, 17, 17, 17, 27, 27, 28, 28, 37, 38, 39, 34, 34, 35, 44, 44, 44, 46, 41, 41, 42, 43, 44, 45, 46, 47, 48 ]).flatten() # r_new = np.array([0, 1, 2, 3, 4, 5, 6, # 7, 1, 2, 3, 4, 5, 13, # 14, 14, 23, 23, 24, 20, 20, # 21, 21, 30, 30, 24, 27, 27, # 28, 28, 37, 38, 39, 34, 34, # 35, 44, 44, 44, 46, 41, 41, # 42, 43, 44, 45, 46, 47, 48]).flatten() r_new = np.array([ 0, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 13, 14, 14, 23, 24, 24, 20, 20, 21, 21, 30, 30, 24, 27, 27, 28, 28, 37, 38, 39, 34, 34, 35, 44, 44, 44, 46, 41, 41, 42, 43, 44, 45, 46, 47, 48 ]).flatten() A_old = np.array([[ 0., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 0., 1., 1., 1., 6., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 2., 2., 2., 1., 1., 0., 0., 5., 0., 2., 0., 0. ]]).flatten() # A_new = np.array([[0., 1., 1., 1., 1., 1., 0., # 0., 1., 1., 1., 1., 1., 0., # 1., 1., 1., 1., 1., 1., 1., # 1., 1., 3., 3., 1., 1., 1., # 1., 1., 7., 1., 1., 1., 1., # 0., 1., 8., 2., 2., 1., 1., # 0., 0., 11., 0., 2., 0., 0.]]).flatten() A_new = np.array([[ 0., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 2., 4., 1., 1., 1., 1., 1., 7., 1., 1., 1., 1., 0., 1., 8., 2., 2., 1., 1., 0., 0., 11., 0., 2., 0., 0. ]]).flatten() # s_new = np.array([0, 1, 8, 2, 9, 3, 10, # 4, 11, 5, 12, 6, 7, 13, # 14, 15, 20, 19, 21, 22, 27, # 26, 28, 29, 34, 33, 35, 41, # 40, 42, 43, 44, 36, 37, 30, # 23, 16, 17, 24, 18, 25, 38, # 31, 45, 46, 39, 32, 47, 48]).flatten() s_new = np.array([ 0, 1, 8, 2, 9, 3, 10, 4, 11, 5, 12, 6, 7, 13, 14, 15, 20, 19, 21, 22, 27, 26, 28, 29, 34, 33, 35, 41, 40, 42, 43, 44, 36, 37, 30, 23, 16, 24, 17, 18, 25, 38, 31, 45, 46, 39, 32, 47, 48 ]).flatten() links_old = np.array([ -1, -1, -1, -1, -1, -1, -1, -1, 7, 8, 9, 10, 11, -1, -1, 26, 28, -1, 29, 31, -1, -1, 39, 113, 35, 114, 44, -1, -1, 52, 60, 61, 62, 57, -1, -1, 146, 73, 149, 75, 70, -1, -1, -1, -1, -1, -1, -1, -1 ]).flatten() # links_new = np.array([-1, -1, -1, -1, -1, -1, -1, # -1, 7, 8, 9, 10, 11, -1, # -1, 26, 34, 113, 115, 31, -1, # -1, 39, 47, 125, 42, 44, -1, # -1, 52, 60, 61, 62, 57, -1, # -1, 146, 73, 149, 75, 70, -1, # -1, -1, -1, -1, -1, -1, -1]).flatten() links_new = np.array([ -1, -1, -1, -1, -1, -1, -1, -1, 7, 8, 9, 10, 11, -1, -1, 26, 34, 35, 115, 31, -1, -1, 39, 47, 125, 42, 44, -1, -1, 52, 60, 61, 62, 57, -1, -1, 146, 73, 149, 75, 70, -1, -1, -1, -1, -1, -1, -1, -1 ]).flatten() depr_outlet_target = np.array([ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 30, 30, 30, XX, XX, XX, XX, 30, 30, 30, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX ]).flatten() mg.add_field('node', 'topographic__elevation', z, units='-') fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg)
def test_flow_accumulator_properties(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") fa = LossyFlowAccumulator(mg) fa.run_one_step() node_drainage_area = np.array( [ 0., 3., 3., 3., 0., 0., 3., 3., 3., 0., 0., 2., 2., 2., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., ] ) node_order_upstream = np.array( [ 0, 1, 6, 11, 16, 2, 7, 12, 17, 3, 8, 13, 18, 4, 5, 9, 10, 14, 15, 19, 20, 21, 22, 23, 24, ] ) assert_array_equal(fa.node_order_upstream, node_order_upstream) assert_array_equal(fa.node_water_discharge, node_drainage_area) assert_array_equal(fa.node_drainage_area, node_drainage_area)
def test_field_name_array_float_case4(): """Topography as array, runoff rate as float""" mg = RasterModelGrid((5, 4), xy_spacing=(1, 1)) topographic__elevation = np.array( [ 0., 0., 0., 0., 0., 21., 10., 0., 0., 31., 20., 0., 0., 32., 30., 0., 0., 0., 0., 0., ] ) mg.add_field("node", "topographic__elevation", topographic__elevation) mg.set_closed_boundaries_at_grid_edges(True, True, True, False) fa = LossyFlowAccumulator(mg, topographic__elevation, runoff_rate=10.) assert_array_equal( mg.at_node["water__unit_flux_in"], 10. * np.ones(mg.size("node")) ) fa.run_one_step() reciever = np.array( [0, 1, 2, 3, 4, 1, 2, 7, 8, 10, 6, 11, 12, 14, 10, 15, 16, 17, 18, 19] ) da = np.array( [0., 1., 5., 0., 0., 1., 5., 0., 0., 1., 4., 0., 0., 1., 2., 0., 0., 0., 0., 0.] ) q = np.array( [ 0., 10., 50., 0., 0., 10., 50., 0., 0., 10., 40., 0., 0., 10., 20., 0., 0., 0., 0., 0., ] ) assert_array_equal(mg.at_node["flow__receiver_node"], reciever) assert_array_equal(mg.at_node["drainage_area"], da) assert_array_equal(mg.at_node["surface_water__discharge"], q)
def dans_grid3(): """ Create a 7x7 test grid with a well defined hole in it. """ mg = RasterModelGrid(7, 7, 1.) z = np.array([ [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0], [0.0, 2.0, 1.6, 1.5, 1.6, 2.0, 0.0], [0.0, 2.0, 1.7, 1.6, 1.7, 2.0, 0.0], [0.0, 2.0, 1.8, 2.0, 2.0, 2.0, 0.0], [0.0, 1.0, 0.6, 1.0, 1.0, 1.0, 0.0], [0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.0], ]).flatten() r_old = np.array([ [0, 1, 2, 3, 4, 5, 6], [7, 1, 2, 3, 4, 5, 13], [14, 14, 17, 17, 17, 20, 20], [21, 21, 17, 17, 17, 27, 27], [28, 28, 37, 38, 39, 34, 34], [35, 44, 44, 44, 46, 41, 41], [42, 43, 44, 45, 46, 47, 48], ]).flatten() r_new = np.array([ [0, 1, 2, 3, 4, 5, 6], [7, 1, 2, 3, 4, 5, 13], [14, 14, 23, 24, 24, 20, 20], [21, 21, 30, 30, 24, 27, 27], [28, 28, 37, 38, 39, 34, 34], [35, 44, 44, 44, 46, 41, 41], [42, 43, 44, 45, 46, 47, 48], ]).flatten() A_old = np.array([ [0., 1., 1., 1., 1., 1., 0.], [0., 1., 1., 1., 1., 1., 0.], [1., 1., 1., 6., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.], [0., 1., 2., 2., 2., 1., 1.], [0., 0., 5., 0., 2., 0., 0.], ]).flatten() A_new = np.array([ [0., 1., 1., 1., 1., 1., 0.], [0., 1., 1., 1., 1., 1., 0.], [1., 1., 1., 1., 1., 1., 1.], [1., 1., 2., 4., 1., 1., 1.], [1., 1., 7., 1., 1., 1., 1.], [0., 1., 8., 2., 2., 1., 1.], [0., 0., 11., 0., 2., 0., 0.], ]).flatten() s_new = np.array([ [0, 1, 8, 2, 9, 3, 10], [4, 11, 5, 12, 6, 7, 13], [14, 15, 20, 19, 21, 22, 27], [26, 28, 29, 34, 33, 35, 41], [40, 42, 43, 44, 36, 37, 30], [23, 16, 24, 17, 18, 25, 38], [31, 45, 46, 39, 32, 47, 48], ]).flatten() links_old = np.array([ [-1, -1, -1, -1, -1, -1, -1], [-1, 7, 8, 9, 10, 11, -1], [-1, 26, 28, -1, 29, 31, -1], [-1, 39, 113, 35, 114, 44, -1], [-1, 52, 60, 61, 62, 57, -1], [-1, 146, 73, 149, 75, 70, -1], [-1, -1, -1, -1, -1, -1, -1], ]).flatten() links_new = np.array([ [-1, -1, -1, -1, -1, -1, -1], [-1, 7, 8, 9, 10, 11, -1], [-1, 26, 34, 35, 115, 31, -1], [-1, 39, 47, 125, 42, 44, -1], [-1, 52, 60, 61, 62, 57, -1], [-1, 146, 73, 149, 75, 70, -1], [-1, -1, -1, -1, -1, -1, -1], ]).flatten() depr_outlet_target = np.array([ [XX, XX, XX, XX, XX, XX, XX], [XX, XX, XX, XX, XX, XX, XX], [XX, XX, 30, 30, 30, XX, XX], [XX, XX, 30, 30, 30, XX, XX], [XX, XX, XX, XX, XX, XX, XX], [XX, XX, XX, XX, XX, XX, XX], [XX, XX, XX, XX, XX, XX, XX], ]).flatten() mg.add_field("node", "topographic__elevation", z, units="-") fr = FlowAccumulator(mg, flow_director='D8') lf = DepressionFinderAndRouter(mg) class DansGrid(object): pass dans_grid = DansGrid() dans_grid.mg = mg dans_grid.fr = fr dans_grid.lf = lf dans_grid.z = z dans_grid.r_new = r_new dans_grid.r_old = r_old dans_grid.A_new = A_new dans_grid.A_old = A_old dans_grid.s_new = s_new dans_grid.depr_outlet_target = depr_outlet_target dans_grid.links_old = links_old dans_grid.links_new = links_new return dans_grid
def read_netcdf(nc_file, just_grid=False): """Create a :class:`~.RasterModelGrid` from a netcdf file. Create a new :class:`~.RasterModelGrid` from the netcdf file, *nc_file*. If the netcdf file also contains data, add that data to the grid's fields. To create a new grid without any associated data from the netcdf file, set the *just_grid* keyword to ``True``. Parameters ---------- nc_file : str Name of a netcdf file. just_grid : boolean, optional Create a new grid but don't add value data. Returns ------- :class:`~.RasterModelGrid` A newly-created :class:`~.RasterModelGrid`. Examples -------- Import :func:`read_netcdf` and the path to an example netcdf file included with landlab. >>> from landlab.io.netcdf import read_netcdf >>> from landlab.io.netcdf import NETCDF4_EXAMPLE_FILE Create a new grid from the netcdf file. The example grid is a uniform rectilinear grid with 4 rows and 3 columns of nodes with unit spacing. The data file also contains data defined at the nodes for the grid for a variable called, *surface__elevation*. >>> grid = read_netcdf(NETCDF4_EXAMPLE_FILE) >>> grid.shape == (4, 3) True >>> grid.dy, grid.dx (1.0, 1.0) >>> [str(k) for k in grid.at_node.keys()] ['surface__elevation'] >>> grid.at_node['surface__elevation'] array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.]) :func:`read_netcdf` will try to determine the format of the netcdf file. For example, the same call will also work for *netcdf3*-formatted files. >>> from landlab.io.netcdf import NETCDF3_64BIT_EXAMPLE_FILE >>> grid = read_netcdf(NETCDF3_64BIT_EXAMPLE_FILE) >>> grid.shape == (4, 3) True >>> grid.dy, grid.dx (1.0, 1.0) """ from landlab import RasterModelGrid try: root = nc.netcdf_file(nc_file, 'r', version=2) except TypeError: root = nc4.Dataset(nc_file, 'r', format='NETCDF4') node_coords = _read_netcdf_structured_grid(root) assert len(node_coords) == 2 spacing = _get_raster_spacing(node_coords) shape = node_coords[0].shape grid = RasterModelGrid(shape, spacing=spacing) if not just_grid: fields = _read_netcdf_structured_data(root) for (name, values) in fields.items(): grid.add_field('node', name, values) root.close() return grid
dt = inputs.read_float('dt') run_time = inputs.read_float('run_time') uplift = inputs.read_float('uplift_rate') initial_slope = inputs.read_float('initial_slope') nt = int(run_time//dt) #this is how many loops we'll need #Build the grid mg = RasterModelGrid(x, y, dx) #sp # Load topography output rotated from WRF-Hydro and add to topography field # Since the discharge files were created on the WRF-Hydro topography, we use that topography as our input. The original Landlab topography and the WRF-Hydro topography are almost identical, with only slight differences created by the rotation. topo=Dataset('topography_wrf_hydro.nc') topography=topo.variables['TOPOGRAPHY'][:] topographic__elevation=np.asarray(topography, dtype=float).ravel() mg.add_field('node', 'topographic__elevation', topographic__elevation) #create the field #set boundary conditions -- these should match those used in the topography creation driver for edge in (mg.nodes_at_left_edge, mg.nodes_at_right_edge): mg.status_at_node[edge] = CLOSED_BOUNDARY for edge in (mg.nodes_at_top_edge, mg.nodes_at_bottom_edge): mg.status_at_node[edge] = FIXED_VALUE_BOUNDARY #instantiate the components fr = FlowRouter(mg) sp = StreamPowerEroder(mg, input_file) lin_diffuse = LinearDiffuser(mg, input_file) print( 'Running ...' ) time_on = time.time()
def test_degenerate_drainage(): """ This "hourglass" configuration should be one of the hardest to correctly re-route. """ mg = RasterModelGrid((9, 5)) z_init = mg.node_x.copy() * 0.0001 + 1.0 lake_pits = np.array([7, 11, 12, 13, 17, 27, 31, 32, 33, 37]) z_init[lake_pits] = -1.0 z_init[22] = 0.0 # the common spill pt for both lakes z_init[21] = 0.1 # an adverse bump in the spillway z_init[20] = -0.2 # the spillway mg.add_field("topographic__elevation", z_init, at="node") fr = FlowAccumulator(mg, flow_director="D8") lf = DepressionFinderAndRouter(mg) fr.run_one_step() lf.map_depressions() # correct_A = np.array([ 0., 0., 0., 0., 0., # 0., 1., 3., 1., 0., # 0., 5., 1., 2., 0., # 0., 1., 10., 1., 0., # 21., 21., 1., 1., 0., # 0., 1., 9., 1., 0., # 0., 3., 1., 2., 0., # 0., 1., 1., 1., 0., # 0., 0., 0., 0., 0.]) correct_A = np.array([ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 1.0, 0.0, 0.0, 2.0, 4.0, 2.0, 0.0, 0.0, 1.0, 10.0, 1.0, 0.0, 21.0, 21.0, 1.0, 1.0, 0.0, 0.0, 1.0, 9.0, 1.0, 0.0, 0.0, 2.0, 2.0, 2.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ]) assert mg.at_node["drainage_area"] == approx(correct_A)
def test_three_pits(): """ A test to ensure the component correctly handles cases where there are multiple pits. """ mg = RasterModelGrid(10, 10, 1.) z = mg.add_field("node", "topographic__elevation", mg.node_x.copy()) # a sloping plane # np.random.seed(seed=0) # z += np.random.rand(100)/10000. # punch some holes z[33] = 1. z[43] = 1. z[37] = 4. z[74:76] = 1. fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() flow_sinks_target = np.zeros(100, dtype=bool) flow_sinks_target[mg.boundary_nodes] = True # no internal sinks now: assert_array_equal(mg.at_node["flow__sink_flag"], flow_sinks_target) # test conservation of mass: assert mg.at_node["drainage_area"].reshape((10, 10))[1:-1, 1].sum() == approx( 8. ** 2 ) # ^all the core nodes # test the actual flow field: nA = np.array( [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., 2., 2., 1., 1., 2., 1., 1., 1., 1., 0., 26., 26., 25., 15., 11., 10., 9., 8., 1., 0., 2., 2., 1., 9., 2., 1., 1., 1., 1., 0., 2., 2., 1., 1., 5., 4., 3., 2., 1., 0., 2., 2., 1., 1., 1., 1., 3., 2., 1., 0., 20., 20., 19., 18., 17., 12., 3., 2., 1., 0., 2., 2., 1., 1., 1., 1., 3., 2., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., ] ) assert_array_equal(mg.at_node["drainage_area"], nA) # test a couple more properties: lc = np.empty(100, dtype=int) lc.fill(XX) lc[33] = 33 lc[43] = 33 lc[37] = 37 lc[74:76] = 74 assert_array_equal(lf.lake_map, lc) assert_array_equal(lf.lake_codes, [33, 37, 74]) assert lf.number_of_lakes == 3 assert lf.lake_areas == approx([2., 1., 2.]) assert lf.lake_volumes == approx([2., 2., 4.])
def test_degenerate_drainage(): """ This "hourglass" configuration should be one of the hardest to correctly re-route. """ mg = RasterModelGrid(9, 5) z_init = mg.node_x.copy() * 0.0001 + 1. lake_pits = np.array([7, 11, 12, 13, 17, 27, 31, 32, 33, 37]) z_init[lake_pits] = -1. z_init[22] = 0. # the common spill pt for both lakes z_init[21] = 0.1 # an adverse bump in the spillway z_init[20] = -0.2 # the spillway z = mg.add_field("node", "topographic__elevation", z_init) fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() # correct_A = np.array([ 0., 0., 0., 0., 0., # 0., 1., 3., 1., 0., # 0., 5., 1., 2., 0., # 0., 1., 10., 1., 0., # 21., 21., 1., 1., 0., # 0., 1., 9., 1., 0., # 0., 3., 1., 2., 0., # 0., 1., 1., 1., 0., # 0., 0., 0., 0., 0.]) correct_A = np.array( [ 0., 0., 0., 0., 0., 0., 1., 3., 1., 0., 0., 2., 4., 2., 0., 0., 1., 10., 1., 0., 21., 21., 1., 1., 0., 0., 1., 9., 1., 0., 0., 2., 2., 2., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., ] ) thelake = np.concatenate((lake_pits, [22])).sort() assert mg.at_node["drainage_area"] == approx(correct_A)
def test_composite_pits(): """ A test to ensure the component correctly handles cases where there are multiple pits, inset into each other. """ mg = RasterModelGrid((10, 10)) z = mg.add_field("topographic__elevation", mg.node_x.copy(), at="node") # a sloping plane # np.random.seed(seed=0) # z += np.random.rand(100)/10000. # punch one big hole z.reshape((10, 10))[3:8, 3:8] = 0.0 # dig a couple of inset holes z[57] = -1.0 z[44] = -2.0 z[54] = -10.0 # make an outlet z[71] = 0.9 fr = FlowAccumulator(mg, flow_director="D8") lf = DepressionFinderAndRouter(mg) fr.run_one_step() lf.map_depressions() flow_sinks_target = np.zeros(100, dtype=bool) flow_sinks_target[mg.boundary_nodes] = True # no internal sinks now: assert_array_equal(mg.at_node["flow__sink_flag"], flow_sinks_target) # test conservation of mass: assert mg.at_node["drainage_area"].reshape( (10, 10))[1:-1, 1].sum() == approx(8.0**2) # ^all the core nodes # test the actual flow field: # nA = np.array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., # 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., # 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., # 1., 1., 1., 4., 2., 2., 8., 4., 1., 0., # 1., 1., 1., 8., 3., 15., 3., 2., 1., 0., # 1., 1., 1., 13., 25., 6., 3., 2., 1., 0., # 1., 1., 1., 45., 3., 3., 5., 2., 1., 0., # 50., 50., 49., 3., 2., 2., 2., 4., 1., 0., # 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., # 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) nA = np.array([ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 4.0, 2.0, 2.0, 6.0, 4.0, 1.0, 0.0, 1.0, 1.0, 1.0, 6.0, 3.0, 12.0, 3.0, 2.0, 1.0, 0.0, 1.0, 1.0, 1.0, 8.0, 20.0, 4.0, 3.0, 2.0, 1.0, 0.0, 1.0, 1.0, 1.0, 35.0, 5.0, 4.0, 3.0, 2.0, 1.0, 0.0, 50.0, 50.0, 49.0, 13.0, 10.0, 8.0, 6.0, 4.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ]) assert_array_equal(mg.at_node["drainage_area"], nA) # the lake code map: lc = np.array([ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, ]) # test the remaining properties: assert lf.lake_outlets.size == 1 assert lf.lake_outlets[0] == 72 outlets_in_map = np.unique(lf.depression_outlet_map) assert outlets_in_map.size == 2 assert outlets_in_map[1] == 72 assert lf.number_of_lakes == 1 assert lf.lake_codes[0] == 57 assert_array_equal(lf.lake_map, lc) assert lf.lake_areas[0] == approx(25.0) assert lf.lake_volumes[0] == approx(63.0)
def test_in_network(): # a valley network produced by stream power: z = np.array([ 3.12900830e-04, 3.66462671e-04, 9.44438515e-04, 1.45006772e-04, 1.91406099e-04, 4.42053204e-04, 2.99818052e-04, 5.45267467e-04, 4.12129514e-04, 7.43816953e-04, 1.59251681e-04, 7.39577249e+01, 6.68718419e+01, 2.95535987e+01, 7.69715256e+01, 4.61083179e+01, 5.70611522e+01, 6.99664564e+01, 8.29355817e+01, 5.85563532e-04, 2.60300016e-04, 8.99636726e+01, 1.11946320e+02, 5.16553709e+01, 1.38432251e+02, 1.02903579e+02, 1.27601424e+02, 8.59469601e+01, 4.77495429e+01, 8.00781223e-04, 4.13095981e-04, 7.41309307e+01, 1.31747968e+02, 1.11724617e+02, 1.71687943e+02, 1.93482716e+02, 1.61044205e+02, 1.34775824e+02, 7.63077925e+01, 8.85837646e-04, 6.94907676e-04, 5.53654246e+01, 9.95405009e+01, 1.81345288e+02, 1.88975196e+02, 1.78104180e+02, 1.75231160e+02, 1.14932425e+02, 5.12018382e+01, 1.26501797e-04, 8.34527300e-04, 8.80562940e+01, 1.24009142e+02, 1.55635807e+02, 1.56683637e+02, 1.62398410e+02, 1.04070282e+02, 6.99665030e+01, 6.41256897e+01, 5.50951003e-04, 2.02545919e-04, 3.05799760e+01, 5.02285119e+01, 8.31442034e+01, 1.75898080e+02, 1.80095770e+02, 1.23416767e+02, 6.97604901e+01, 3.04864568e+01, 4.42047775e-04, 5.75778629e-04, 8.13990441e+01, 1.17362500e+02, 1.35317452e+02, 1.78842796e+02, 9.65391990e+01, 1.16520146e+02, 1.59289373e+02, 8.29784784e+01, 4.21911459e-04, 7.83145812e-04, 8.44510235e+01, 6.85512072e+01, 3.99258990e+01, 9.07740020e+01, 4.47116751e+01, 1.05333999e+02, 1.04965376e+02, 6.42615041e+01, 8.48184002e-04, 9.92952214e-04, 5.44805365e-04, 6.83657298e-04, 4.27967811e-04, 4.40101095e-04, 5.47248461e-04, 5.77178429e-06, 4.39642103e-04, 4.80194778e-04, 9.24014550e-04 ]) flux = np.array([ 0.71259633, 1.8368437, 7.98879652, 9.29556375, 10.55574455, 7.24717392, 7.35872882, 4.50198662, 1.97243346, 0.54930274, 1.71629518, 4.0949232, 4.50641349, 19.45300944, 5.73451891, 10.2200909, 8.84475793, 5.62433494, 3.63816461, 3.2288009, 3.64720491, 4.08050742, 3.55208345, 12.80703452, 4.51455295, 7.22640241, 4.82518478, 6.0364361, 8.21399889, 4.89790743, 6.37085345, 7.20139071, 3.66063349, 6.65749537, 4.5201495, 3.16880878, 4.56500213, 4.47976874, 5.91287906, 7.65823897, 6.75481467, 10.33585975, 7.95868492, 3.44967745, 3.30272455, 3.79822256, 3.72583825, 5.35268783, 11.33346169, 7.61218948, 13.23332132, 5.52663873, 4.71401637, 5.25380598, 6.32221242, 5.21692832, 9.95021529, 12.12012981, 9.62887235, 12.51966215, 12.20119879, 28.07778172, 21.69415422, 13.44016311, 3.42523128, 3.16880878, 5.79132165, 11.8326263, 20.62850507, 10.58826741, 10.25347039, 3.76593706, 3.58815683, 4.10381596, 3.23987285, 7.32040184, 4.62625103, 3.16880878, 4.05801502, 8.29763076, 1.42053684, 3.54385495, 4.9815377, 7.32862308, 5.884002, 12.71539344, 4.14640372, 4.17838374, 4.74896355, 1.84587995, 0.57901706, 1.94727505, 4.37381493, 5.18582678, 7.70532408, 6.86738548, 6.04728603, 2.94714791, 2.00238741, 0.88296836 ]) potnt = np.array([ 7.12596329e+23, 1.83684370e+24, 7.98879652e+24, 9.29556375e+24, 1.05557446e+25, 7.24717392e+24, 7.35872882e+24, 4.50198662e+24, 1.97243346e+24, 5.49302741e+23, 1.71629518e+24, 3.11607783e+00, 4.55006629e+00, 4.21948454e+01, 4.51089464e+00, 1.77476721e+01, 1.18679201e+01, 5.93094410e+00, 2.26828834e+00, 3.22880090e+24, 3.64720491e+24, 3.44492074e+00, 2.99141371e+00, 8.61459830e+01, 3.22150654e+00, 1.30493764e+01, 4.51470413e+00, 1.01713137e+01, 1.40167801e+01, 4.89790743e+24, 6.37085345e+24, 8.30460195e+00, 2.72370114e+00, 1.97019871e+01, 4.81322624e+00, 2.37203116e+00, 4.76156755e+00, 3.84190281e+00, 5.53509619e+00, 7.65823897e+24, 6.75481467e+24, 1.63796499e+01, 1.83238435e+01, 2.62626616e+00, 3.21546392e+00, 5.36483147e+00, 3.18817285e+00, 5.90189403e+00, 1.86765515e+01, 7.61218948e+24, 1.32333213e+25, 4.00510836e+00, 3.72650975e+00, 5.71530086e+00, 2.42783091e+01, 1.07981219e+01, 2.92283301e+01, 3.24892464e+01, 9.86359779e+00, 1.25196622e+25, 1.22011988e+25, 5.98718495e+01, 1.54766737e+02, 7.40803538e+01, 3.21059221e+00, 2.38746227e+00, 7.36767180e+00, 4.52838697e+01, 4.40547155e+01, 1.05882674e+25, 1.02534704e+25, 3.05098779e+00, 2.45849055e+00, 3.12955438e+00, 1.87486164e+00, 2.51124463e+01, 6.21239889e+00, 1.64106832e+00, 3.28554137e+00, 8.29763076e+24, 1.42053684e+24, 2.36944471e+00, 5.71708702e+00, 1.36764251e+01, 4.71435055e+00, 2.24231064e+01, 3.41364652e+00, 3.49569086e+00, 4.14217801e+00, 1.84587995e+24, 5.79017064e+23, 1.94727505e+24, 4.37381493e+24, 5.18582678e+24, 7.70532408e+24, 6.86738548e+24, 6.04728603e+24, 2.94714791e+24, 2.00238741e+24, 8.82968356e+23 ]) mg = RasterModelGrid((NROWS, NCOLS), (DX, DX)) mg.add_field('node', 'topographic__elevation', z) Qin = np.ones_like(z) * 100. / (60. * 60. * 24. * 365.25) # ^remember, flux is /s, so this is a small number! mg.add_field('node', 'water__unit_flux_in', Qin) pfr = PotentialityFlowRouter(mg, flow_equation='Manning') pfr.route_flow() assert_allclose(mg.at_node['surface_water__discharge'], flux) assert_allclose(mg.at_node['flow__potential'][mg.core_nodes], potnt[mg.core_nodes])
def read_netcdf(nc_file, grid=None, name=None, just_grid=False, halo=0, nodata_value=-9999.0): """Create a :class:`~.RasterModelGrid` from a netcdf file. Create a new :class:`~.RasterModelGrid` from the netcdf file, *nc_file*. If the netcdf file also contains data, add that data to the grid's fields. To create a new grid without any associated data from the netcdf file, set the *just_grid* keyword to ``True``. A halo can be added with the keyword *halo*. If you want the fields to be added to an existing grid, it can be passed to the keyword argument *grid*. Parameters ---------- nc_file : str Name of a netcdf file. grid : *grid* , optional Adds data to an existing *grid* instead of creating a new one. name : str, optional Add only fields with NetCDF variable name to the grid. Default is to add all NetCDF varibles to the grid. just_grid : boolean, optional Create a new grid but don't add value data. halo : integer, optional Adds outer border of depth halo to the *grid*. nodata_value : float, optional Value that indicates an invalid value. Default is -9999. Returns ------- :class:`~.RasterModelGrid` A newly-created :class:`~.RasterModelGrid`. Examples -------- Import :func:`read_netcdf` and the path to an example netcdf file included with landlab. >>> from landlab.io.netcdf import read_netcdf Create a new grid from the netcdf file. The example grid is a uniform rectilinear grid with 4 rows and 3 columns of nodes with unit spacing. The data file also contains data defined at the nodes for the grid for a variable called, *surface__elevation*. >>> grid = read_netcdf("test-netcdf4.nc") # doctest: +SKIP >>> grid.shape == (4, 3) # doctest: +SKIP True >>> grid.dy, grid.dx # doctest: +SKIP (1.0, 1.0) >>> list(grid.at_node.keys()) # doctest: +SKIP ['surface__elevation'] >>> grid.at_node['surface__elevation'] # doctest: +SKIP array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.]) :func:`read_netcdf` will try to determine the format of the netcdf file. For example, the same call will also work for *netcdf3*-formatted files. >>> grid = read_netcdf("test-netcdf3-64bit.nc") # doctest: +SKIP >>> grid.shape == (4, 3) # doctest: +SKIP True >>> grid.dy, grid.dx # doctest: +SKIP (1.0, 1.0) A more complicated example might add data with a halo to an existing grid. Note that the lower left corner must be specified correctly for the data and the grid to align correctly. >>> from landlab import RasterModelGrid >>> grid = RasterModelGrid((6, 5), xy_of_lower_left=(-1., -1.)) # doctest: +SKIP >>> grid = read_netcdf( ... "test-netcdf4.nc", ... grid=grid, ... halo=1, ... nodata_value=-1, ... ) # doctest: +SKIP >>> grid.at_node['surface__elevation'].reshape(grid.shape) # doctest: +SKIP array([[ -1., -1., -1., -1., -1.], [ -1., 0., 1., 2., -1.], [ -1., 3., 4., 5., -1.], [ -1., 6., 7., 8., -1.], [ -1., 9., 10., 11., -1.], [ -1., -1., -1., -1., -1.]]) """ from landlab import RasterModelGrid try: root = nc.netcdf_file(nc_file, "r", version=2) except TypeError: root = nc4.Dataset(nc_file, "r", format="NETCDF4") try: node_coords = _read_netcdf_structured_grid(root) except ValueError: if (len(root.variables["x"].dimensions) == 1) and (len( root.variables["y"].dimensions) == 1): node_coords = _read_netcdf_raster_structured_grid(root) else: assert ValueError("x and y dimensions must both either be 2D " "(nj, ni) or 1D (ni,) and (nj).") assert len(node_coords) == 2 dx = _get_raster_spacing(node_coords) xy_spacing = (dx, dx) shape = node_coords[0].shape xy_of_lower_left = ( node_coords[0].min() - halo * dx, node_coords[1].min() - halo * dx, ) if grid is not None: if (grid.number_of_node_rows != shape[0] + 2 * halo) or ( grid.number_of_node_columns != shape[1] + 2 * halo): raise MismatchGridDataSizeError( shape[0] + 2 * halo * shape[1] + 2 * halo, grid.number_of_node_rows * grid.number_of_node_columns, ) if (grid.dx, grid.dy) != xy_spacing: raise MismatchGridXYSpacing((grid.dx, grid.dy), xy_spacing) if grid.xy_of_lower_left != xy_of_lower_left: raise MismatchGridXYLowerLeft(grid.xy_of_lower_left, xy_of_lower_left) if grid is None: grid = RasterModelGrid(shape, xy_spacing=xy_spacing, xy_of_lower_left=xy_of_lower_left) if not just_grid: fields, grid_mapping_dict = _read_netcdf_structured_data(root) for (field_name, values) in fields.items(): # add halo if necessary if halo > 0: values = add_halo(values.reshape(shape), halo=halo, halo_value=nodata_value).reshape((-1, )) # add only the requested fields. if (name is None) or (field_name == name): add_field = True else: add_field = False if add_field: grid.add_field(field_name, values, at="node", clobber=True) if (name is not None) and (name not in grid.at_node): raise ValueError( "Specified field {name} was not in provided NetCDF.".format( name=name)) # save grid mapping if grid_mapping_dict is not None: grid.grid_mapping = grid_mapping_dict root.close() return grid
def test_depression_finder_bad_instance(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") ld = LinearDiffuser(mg, linear_diffusivity=1.) with pytest.raises(ValueError): LossyFlowAccumulator(mg, flow_director="D8", depression_finder=ld)
y_distance_from_center = mg.node_y - mg.node_y.mean() x_distance_from_edge = np.amin(np.vstack( (mg.node_x.max() - mg.node_x, mg.node_x - mg.node_x.min())), axis=0) y_distance_from_edge = np.amin(np.vstack( (mg.node_y.max() - mg.node_y, mg.node_y - mg.node_y.min())), axis=0) # make the "hole" hole_elev = np.sqrt(x_distance_from_center**2 + y_distance_from_center**2) # make the rim: rim_elev = np.sqrt(x_distance_from_edge**2 + y_distance_from_edge**2) # assemble z = np.amin(np.vstack((hole_elev, rim_elev)), axis=0) z += np.random.rand(nx * ny) / 1000. mg.add_field("node", "topographic__elevation", z, copy=False) fr = FlowAccumulator(mg, flow_director="D8") lf = DepressionFinderAndRouter(mg) fr.run_one_step() figure("old drainage area") imshow_node_grid(mg, "drainage_area") lf.map_depressions(pits=mg.at_node["flow__sink_flag"]) figure("depression depth") imshow_node_grid(mg, "depression__depth") figure("new drainage area")
def test_depression_finder_bad_uninstantiated_component(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") with pytest.raises(ValueError): LossyFlowAccumulator(mg, flow_director="D8", depression_finder=LinearDiffuser)
def test_bad_director_name(): mg = RasterModelGrid((5, 5), spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") with pytest.raises(ValueError): LossyFlowAccumulator(mg, flow_director="spam")
def dans_grid2(): """ Create a 5x5 test grid. This tests more complex routing, with diffs between D4 & D8. """ mg = RasterModelGrid((5, 5), spacing=(10., 10.)) this_dir = os.path.abspath(os.path.dirname(__file__)) infile = os.path.join(this_dir, "test_fr_input.txt") z = np.array([ [7., 7., 7., 7., 7.], [7., 5., 3.2, 6., 7.], [7., 2., 3., 5., 7.], [7., 1., 1.9, 4., 7.], [7., 0., 7., 7., 7.], ]).flatten() A_target_D8 = np.array([ [0., 0., 0., 0., 0.], [0., 100., 200., 100., 0.], [0., 400., 100., 100., 0.], [0., 600., 300., 100., 0.], [0., 900., 0., 0., 0.], ]).flatten() A_target_D4 = np.array([ [0., 0., 0., 0., 0.], [0., 100., 200., 100., 0.], [0., 200., 400., 100., 0.], [0., 900., 600., 100., 0.], [0., 900., 0., 0., 0.], ]).flatten() frcvr_target_D8 = np.array([ [0, 1, 2, 3, 4], [5, 11, 11, 7, 9], [10, 16, 16, 17, 14], [15, 21, 21, 17, 19], [20, 21, 22, 23, 24], ]).flatten() frcvr_target_D4 = np.array([ [0, 1, 2, 3, 4], [5, 11, 12, 7, 9], [10, 16, 17, 12, 14], [15, 21, 16, 17, 19], [20, 21, 22, 23, 24], ]).flatten() upids_target_D8 = np.array([ [0, 1, 2, 3, 4], [5, 9, 10, 14, 15], [19, 20, 21, 16, 11], [6, 7, 8, 12, 17], [13, 18, 22, 23, 24], ]).flatten() upids_target_D4 = np.array([ [0, 1, 2, 3, 4], [5, 9, 10, 14, 15], [19, 20, 21, 16, 11], [6, 17, 12, 7, 8], [13, 18, 22, 23, 24], ]).flatten() links2rcvr_target_D8 = np.full(25, XX) links2rcvr_target_D8[mg.core_nodes] = np.array( [14, 51, 11, 23, 59, 61, 32, 67, 29]) links2rcvr_target_D4 = np.full(25, XX) links2rcvr_target_D4[mg.core_nodes] = np.array( [14, 15, 11, 23, 24, 20, 32, 28, 29]) steepest_target_D8 = np.array([ [0., 0., 0., 0., 0.], [0., 0.3, 0.08485281, 0.28, 0.], [0., 0.1, 0.14142136, 0.21920310, 0.], [0., 0.1, 0.13435029, 0.21, 0.], [0., 0., 0., 0., 0.], ]).flatten() steepest_target_D4 = np.array([ [0., 0., 0., 0., 0.], [0., 0.3, 0.02, 0.28, 0.], [0., 0.1, 0.11, 0.2, 0.], [0., 0.1, 0.09, 0.21, 0.], [0., 0., 0., 0., 0.], ]).flatten() mg.add_field("node", "topographic__elevation", z, units="-") class DansGrid(object): pass dans_grid = DansGrid() dans_grid.mg = mg dans_grid.z = z dans_grid.infile = infile dans_grid.A_target_D8 = A_target_D8 dans_grid.A_target_D4 = A_target_D4 dans_grid.frcvr_target_D8 = frcvr_target_D8 dans_grid.frcvr_target_D4 = frcvr_target_D4 dans_grid.upids_target_D8 = upids_target_D8 dans_grid.upids_target_D4 = upids_target_D4 dans_grid.steepest_target_D8 = steepest_target_D8 dans_grid.steepest_target_D4 = steepest_target_D4 dans_grid.links2rcvr_target_D8 = links2rcvr_target_D8 dans_grid.links2rcvr_target_D4 = links2rcvr_target_D4 return dans_grid
def internal_closed(): """ Create a 6x5 test grid, but with two internal nodes closed. This is a sheet flow test. """ mg = RasterModelGrid((6, 5), spacing=(10., 10.)) mg.set_closed_boundaries_at_grid_edges(True, True, False, True) mg.status_at_node[7] = CLOSED_BOUNDARY mg.status_at_node[16] = CLOSED_BOUNDARY z = mg.node_x.copy() Q_in = np.full(25, 2.) A_target = (np.array([ [0., 0., 0., 0., 0.], [1., 1., 0., 1., 0.], [6., 6., 3., 1., 0.], [0., 0., 2., 1., 0.], [3., 3., 2., 1., 0.], [0., 0., 0., 0., 0.], ]).flatten() * 100.) frcvr_target = np.array([ [0, 1, 2, 3, 4], [5, 5, 7, 12, 9], [10, 10, 11, 12, 14], [15, 16, 11, 17, 19], [20, 20, 21, 22, 24], [25, 26, 27, 28, 29], ]).flatten() links2rcvr_target = np.full(mg.number_of_nodes, XX) links2rcvr_target[mg.core_nodes] = np.array( [9, 62, 18, 19, 20, 67, 29, 36, 37, 38]) steepest_target = np.array([ [0., 0., 0., 0., 0.], [0., 1., 0., 0., 0.], [0., 1., 1., 1., 0.], [0., 0., 0., 1., 0.], [0., 1., 1., 1., 0.], [0., 0., 0., 0., 0.], ]).flatten() steepest_target[np.array([8, 17])] = 1. / np.sqrt(2.) mg.add_field("node", "topographic__elevation", z, units="-") class DansGrid(object): pass dans_grid = DansGrid() dans_grid.mg = mg dans_grid.z = z dans_grid.Q_in = Q_in dans_grid.A_target = A_target dans_grid.frcvr_target = frcvr_target dans_grid.steepest_target = steepest_target dans_grid.links2rcvr_target = links2rcvr_target return dans_grid
def test_field_name_array_float_case6(): """Topography as array, runoff rate as array""" mg = RasterModelGrid((5, 4), xy_spacing=(1, 1)) topographic__elevation = np.array( [ 0., 0., 0., 0., 0., 21., 10., 0., 0., 31., 20., 0., 0., 32., 30., 0., 0., 0., 0., 0., ] ) runoff_rate = [ 1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3., 4., 4., 4., 4., 5., 5., 5., 5., ] mg.add_field("node", "topographic__elevation", topographic__elevation) mg.set_closed_boundaries_at_grid_edges(True, True, True, False) fa = LossyFlowAccumulator(mg, topographic__elevation, runoff_rate=runoff_rate) fa.run_one_step() reciever = np.array( [0, 1, 2, 3, 4, 1, 2, 7, 8, 10, 6, 11, 12, 14, 10, 15, 16, 17, 18, 19] ) da = np.array( [0., 1., 5., 0., 0., 1., 5., 0., 0., 1., 4., 0., 0., 1., 2., 0., 0., 0., 0., 0.] ) q = np.array( [ 0., 2., 16., 0., # KRB double checked these numbers by hand 5/15/18 - OK 0., 2., 16., 0., 0., 3., 14., 0., 0., 4., 8., 0., 0., 0., 0., 0., ] ) assert_array_equal(mg.at_node["flow__receiver_node"], reciever) assert_array_equal(mg.at_node["drainage_area"], da) assert_array_equal(mg.at_node["surface_water__discharge"], q)
def test_MS_params(): # This commented code block ingests MS's grid setup to come close to a # version of this topo (DEJH believes there may be a bug in the STORM # code's allocation of elevations, which precludes a precise replication) # a = shp.Reader(os.path.join(datapath, 'boundary', 'boundary.shp')) # # This is shapefile of the watershed boundary # b = shp.Reader(os.path.join( # datapath, 'point_elevations', 'point_elevations', # 'point_elevations.shp')) # # This is shapefile of the elevations at each 'gauging' point on the # # grid within the watershed boundary # coords = a.shapeRecords()[0].shape.__geo_interface__['coordinates'][0] # Yy = [Y for (X, Y) in coords] # Xx = [X for (X, Y) in coords] # polypts_xy = [[X, Y] for (X, Y) in coords] # (X1, Y1) = np.meshgrid( # np.linspace(min(Xx), max(Xx), # int(round((max(Xx)-min(Xx))/1000.))), # np.linspace(min(Yy), max(Yy), # int(round((max(Yy)-min(Yy))/1000.)))) # # creates a mesh with 1000m spacings # isin = Path(polypts_xy).contains_points( # [(zx, zy) for (zx, zy) in zip(X1.flat, Y1.flat)]).reshape(X1.shape) # # isin=inpolygon(X1(:),Y1(:),Xx,Yy) # Yin = Y1[isin] # Xin = X1[isin] # # Easting = np.loadtxt(os.path.join(_THIS_DIR, 'model_input', 'Easting.csv')) # # This is the Longitudinal data for each gauge. # Northing = np.loadtxt(os.path.join(_THIS_DIR, 'model_input', 'Northing.csv')) # # This is the Latitudinal data for each gauge. It will be sampled # # below. # vdg = VoronoiDelaunayGrid(Easting, Northing) # gauges = np.loadtxt(os.path.join(_THIS_DIR, 'model_input', 'gauges.csv')) # # This is the list of gauge numbers. It will be sampled below. # gauge_elev = np.loadtxt(os.path.join(_THIS_DIR, 'model_input', 'gauge_elev.csv')) # # This is the list of gauge numbers. It will be sampled below. # # put the elevs on the grid. Mind the ordering # vdg_z = vdg.add_field('node', 'topographic__elevation', # gauge_elev[np.argsort(Northing)]) # numgauges = len(gauges) # # mg = RasterModelGrid((12, 26), (1042.3713, 1102.0973)) # mg.status_at_node[:] = 4 # mg.status_at_node[isin.flatten()] = 0 # z = mg.add_zeros('node', 'topographic__elevation') # # closest_core_node_in_vdg = [] # for E, N in zip(Xin, Yin): # closest_core_node_in_vdg.append( # np.argmin(vdg.calc_distances_of_nodes_to_point((E, N)))) # z[mg.status_at_node == 0] = vdg_z[np.array(closest_core_node_in_vdg)] mg = RasterModelGrid((12, 26), (1042.3713, 1102.0973)) mg.status_at_node = np.loadtxt(os.path.join(_THIS_DIR, "BCs_Singer.txt")) mg.add_field( "node", "topographic__elevation", np.loadtxt(os.path.join(_THIS_DIR, "elevs_Singer.txt")), ) np.random.seed(10) rain = SpatialPrecipitationDistribution(mg, number_of_years=2, orographic_scenario="Singer") max_intensity = [] storm_dur = [] istorm_dur = [] rec = [] depth = [] count = 0 for (storm, istorm) in rain.yield_storms( # style='monsoonal', limit='total_rainfall'): style="whole_year", limit="total_rainfall", ): # print('storm dur:', storm, rain.storm_duration_last_storm) # print('istorm dur:', istorm) # print('intensity:', rain.storm_intensity_last_storm) # print('recession:', rain.storm_recession_value_last_storm) # print('depth:', rain.storm_depth_last_storm) # # print('accum depth:', rain.total_rainfall_this_season) # print('target depth:', rain.target_median_total_rainfall_this_season) # print('***') max_intensity.append(rain.storm_intensity_last_storm) storm_dur.append(storm) istorm_dur.append(istorm) rec.append(rain.storm_recession_value_last_storm) depth.append(rain.storm_depth_last_storm) count += 1 # print('Total number of storms:', count) # print('Target_depth:', rain.target_median_total_rainfall_this_season) assert np.isclose(np.mean(max_intensity), 35.84806631859928) # mm/hr assert np.isclose(np.mean(storm), 0.40865380457460571) # hrs assert np.isclose(np.mean(istorm), 85.258871894485694) # hrs
def setup_dans_grid2(): """ Create a 5x5 test grid. This tests more complex routing, with diffs between D4 & D8. """ global fr, mg, infile global z, A_target_D8, A_target_D4, frcvr_target_D8, frcvr_target_D4, \ upids_target_D8, upids_target_D4, steepest_target_D8, \ steepest_target_D4, links2rcvr_target_D8, links2rcvr_target_D4 mg = RasterModelGrid((5, 5), spacing=(10., 10.)) infile = os.path.join(_THIS_DIR, 'test_fr_input.txt') z = np.array([7., 7., 7., 7., 7., 7., 5., 3.2, 6., 7., 7., 2., 3., 5., 7., 7., 1., 1.9, 4., 7., 7., 0., 7., 7., 7.]) A_target_D8 = np.array([0., 0., 0., 0., 0., 0., 100., 200., 100., 0., 0., 400., 100., 100., 0., 0., 600., 300., 100., 0., 0., 900., 0., 0., 0.]) A_target_D4 = np.array([0., 0., 0., 0., 0., 0., 100., 200., 100., 0., 0., 200., 400., 100., 0., 0., 900., 600., 100., 0., 0., 900., 0., 0., 0.]) frcvr_target_D8 = np.array([0, 1, 2, 3, 4, 5, 11, 11, 7, 9, 10, 16, 16, 17, 14, 15, 21, 21, 17, 19, 20, 21, 22, 23, 24]) frcvr_target_D4 = np.array([ 0, 1, 2, 3, 4, 5, 11, 12, 7, 9, 10, 16, 17, 12, 14, 15, 21, 16, 17, 19, 20, 21, 22, 23, 24]) upids_target_D8 = np.array([0, 1, 2, 3, 4, 5, 9, 10, 14, 15, 19, 20, 21, 16, 11, 6, 7, 8, 12, 17, 13, 18, 22, 23, 24]) upids_target_D4 = np.array([0, 1, 2, 3, 4, 5, 9, 10, 14, 15, 19, 20, 21, 16, 11, 6, 17, 12, 7, 8, 13, 18, 22, 23, 24]) links2rcvr_target_D8 = np.full(25, XX) links2rcvr_target_D8[mg.core_nodes] = np.array([14, 51, 11, 23, 59, 61, 32, 67, 29]) links2rcvr_target_D4 = np.full(25, XX) links2rcvr_target_D4[mg.core_nodes] = np.array([14, 15, 11, 23, 24, 20, 32, 28, 29]) steepest_target_D8 = np.array([0., 0., 0., 0., 0., 0., 0.3, 0.08485281, 0.28, 0., 0., 0.1, 0.14142136, 0.21920310, 0., 0., 0.1, 0.13435029, 0.21, 0., 0., 0., 0., 0., 0.]) steepest_target_D4 = np.array([0., 0., 0., 0., 0., 0., 0.3, 0.02, 0.28, 0., 0., 0.1, 0.11, 0.2, 0., 0., 0.1, 0.09, 0.21, 0., 0., 0., 0., 0., 0.]) mg.add_field('node', 'topographic__elevation', z, units='-')
def test_water_discharge_in_supplied(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") mg.add_field("water__discharge_in", mg.node_x + mg.node_y, at="node") with pytest.deprecated_call(): LossyFlowAccumulator(mg)
def test_composite_pits(): """ A test to ensure the component correctly handles cases where there are multiple pits, inset into each other. """ mg = RasterModelGrid(10, 10, 1.) z = mg.add_field('node', 'topographic__elevation', mg.node_x.copy()) # a sloping plane #np.random.seed(seed=0) #z += np.random.rand(100)/10000. # punch one big hole z.reshape((10, 10))[3:8, 3:8] = 0. # dig a couple of inset holes z[57] = -1. z[44] = -2. z[54] = -10. # make an outlet z[71] = 0.9 fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() flow_sinks_target = np.zeros(100, dtype=bool) flow_sinks_target[mg.boundary_nodes] = True # no internal sinks now: assert_array_equal(mg.at_node['flow__sink_flag'], flow_sinks_target) # test conservation of mass: assert_almost_equal( mg.at_node['drainage_area'].reshape((10, 10))[1:-1, 1].sum(), 8.**2) # ^all the core nodes # test the actual flow field: # nA = np.array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., # 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., # 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., # 1., 1., 1., 4., 2., 2., 8., 4., 1., 0., # 1., 1., 1., 8., 3., 15., 3., 2., 1., 0., # 1., 1., 1., 13., 25., 6., 3., 2., 1., 0., # 1., 1., 1., 45., 3., 3., 5., 2., 1., 0., # 50., 50., 49., 3., 2., 2., 2., 4., 1., 0., # 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., # 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) nA = np.array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 4., 2., 2., 6., 4., 1., 0., 1., 1., 1., 6., 3., 12., 3., 2., 1., 0., 1., 1., 1., 8., 20., 4., 3., 2., 1., 0., 1., 1., 1., 35., 5., 4., 3., 2., 1., 0., 50., 50., 49., 13., 10., 8., 6., 4., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ]) assert_array_equal(mg.at_node['drainage_area'], nA) # the lake code map: lc = np.array([ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX ]) #test the remaining properties: assert_equal(lf.lake_outlets.size, 1) assert_equal(lf.lake_outlets[0], 72) outlets_in_map = np.unique(lf.depression_outlet_map) assert_equal(outlets_in_map.size, 2) assert_equal(outlets_in_map[1], 72) assert_equal(lf.number_of_lakes, 1) assert_equal(lf.lake_codes[0], 57) assert_array_equal(lf.lake_map, lc) assert_almost_equal(lf.lake_areas[0], 25.) assert_almost_equal(lf.lake_volumes[0], 63.)
def test_instantiated_director_with_kwargs(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") fd = FlowDirectorSteepest(mg) with pytest.raises(ValueError): LossyFlowAccumulator(mg, flow_director=fd, partition_method="eggs")
def test_depression_finder_as_bad_string(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") with pytest.raises(ValueError): LossyFlowAccumulator(mg, flow_director="D8", depression_finder="spam")
def test_depression_finder_as_instance(): mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") df = DepressionFinderAndRouter(mg) LossyFlowAccumulator(mg, flow_director="D8", depression_finder=df)
def test_edge_draining(): """ This tests when the lake attempts to drain from an edge, where an issue is suspected. """ # Create a 7x7 test grid with a well defined hole in it, AT THE EDGE. mg = RasterModelGrid((7, 7), (1., 1.)) z = mg.node_x.copy() guard_sides = np.concatenate((np.arange(7, 14), np.arange(35, 42))) edges = np.concatenate((np.arange(7), np.arange(42, 49))) hole_here = np.array(([15, 16, 22, 23, 29, 30])) z[guard_sides] = z[13] z[edges] = -2. # force flow outwards from the tops of the guards z[hole_here] = -1. A_new = np.array( [ [ [ 0., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 0., 15., 5., 4., 3., 2., 1., 0., 0., 10., 4., 3., 2., 1., 0., 0., 1., 4., 3., 2., 1., 0., 0., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 0., ] ] ] ).flatten() depr_outlet_target = np.array( [ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 14, 14, XX, XX, XX, XX, XX, 14, 14, XX, XX, XX, XX, XX, 14, 14, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, ] ).flatten() mg.add_field("node", "topographic__elevation", z, units="-") fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() assert mg.at_node["drainage_area"] == approx(A_new) assert lf.depression_outlet_map == approx(depr_outlet_target)
print("Running fastscaper") print(datetime.datetime.now().time()) spr.run_one_step(dt) # erosion: stream power zrnew = zr[mg.nodes] # post-incision elevations incise = zrold - zrnew # incision per cell qs = incise * cell_area # Volume sediment produced per cell qsflat = qs.ravel() # flatten qs for flow routing calculation # extract cumulative flux (q) as function of flow length. a, q = find_drainage_area_and_discharge( mg.at_node['flow__upstream_node_order'], mg.at_node['flow__receiver_node'], runoff=qsflat) # a is number of nodes area = mg.at_node['drainage_area'] mg.add_field('node', 'flux', q, noclobber=False) area_threshold = 25 #float(sys.argv[1]) #km2 is_drainage = area > (area_threshold * 1000000) #km2 to m2 q_rate = q / dt incise_rate = (incise / dt) * 0.001 #mm/yr # Update fields print("Updating fields") print(datetime.datetime.now().time()) mg.add_field('node', 'elevation', zrold, noclobber=False) # Outputs present day elevation mg.add_field('node', 'incision', incise_rate, noclobber=False) # Channels mg.add_field('node', 'channels', is_drainage, noclobber=False) # Incision rate mg.add_field('node', 'sedflux', q_rate, noclobber=False)