def test_fields3(): # %% Second FD (no FA is default) mg3 = RasterModelGrid((8, 8), xy_spacing=(1, 1)) mg3.add_field("topographic__elevation", mg3.node_x + mg3.node_y, at="node") fa3 = PriorityFloodFlowRouter(mg3, separate_hill_flow=True, suppress_out=True) fa3.run_one_step() assert sorted(list(mg3.at_node.keys())) == [ "depression_free_elevation", "drainage_area", "flood_status_code", "flow__link_to_receiver_node", "flow__receiver_node", "flow__receiver_proportions", "flow__upstream_node_order", "hill_flow__receiver_node", "hill_flow__receiver_proportions", "hill_flow__upstream_node_order", "hill_topographic__steepest_slope", "squared_length_adjacent", "surface_water__discharge", "topographic__elevation", "topographic__steepest_slope", "water__unit_flux_in", ]
def test_fields1(): # %% """ Check to make sure the right fields have been created. Check that the sizes are also correct. """ # %% Default configuration mg1 = RasterModelGrid((6, 6), xy_spacing=(1, 1)) mg1.add_field("topographic__elevation", mg1.node_x + mg1.node_y, at="node") fa1 = PriorityFloodFlowRouter(mg1, suppress_out=True) fa1.run_one_step() assert sorted(list(mg1.at_node.keys())) == [ "depression_free_elevation", "drainage_area", "flood_status_code", "flow__link_to_receiver_node", "flow__receiver_node", "flow__receiver_proportions", "flow__upstream_node_order", "squared_length_adjacent", "surface_water__discharge", "topographic__elevation", "topographic__steepest_slope", "water__unit_flux_in", ]
def test_sliding_plain(): """ Test that if BedrockLandslider maths are sound and follow the Culmann theory """ # Make a raster model grid and create a plateau n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) z = mg.add_zeros("topographic__elevation", at="node") s = mg.add_zeros("soil__depth", at="node") b = mg.add_zeros("bedrock__elevation", at="node") # make plateau at 10m b += 10 # Lower boundary cell to 0 b[2] = 0 z[:] = b + s fd = PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) hy = BedrockLandslider(mg, landslides_return_time=1) # run flow director and BedrockLandslider for one timestep fd.run_one_step() hy.run_one_step(dt=1) # After one timestep, we can predict eactly where the landslide will occur. # The return time is set to 1 year so that probability for sliding is 100% # The angle of internal driction is 1m/m, the topographical gradient is 10 m/m # At cardinal cells, the sliding plain will be at (1+10)/2 = 5.5 m/m. # With a dx of 1, the cardial cell next to the critical sliding node must # be 5.5 m and the diagonal one at 5.5 * sqrt(2) = 7.8 m err_msg = "Error in the calculation of the sliding plain" testing.assert_almost_equal( [5.5 * np.sqrt(2), 5.5, 5.5 * np.sqrt(2)], z[6:9], decimal=5, err_msg=err_msg )
def test_fields4(): """ Second FD (with FA ) """ mg4 = RasterModelGrid((9, 9), xy_spacing=(1, 1)) mg4.add_field("topographic__elevation", mg4.node_x + mg4.node_y, at="node") fa4 = PriorityFloodFlowRouter(mg4, separate_hill_flow=True, accumulate_flow_hill=True, suppress_out=True) fa4.run_one_step() assert sorted(list(mg4.at_node.keys())) == [ "depression_free_elevation", "drainage_area", "flood_status_code", "flow__link_to_receiver_node", "flow__receiver_node", "flow__receiver_proportions", "flow__upstream_node_order", "hill_drainage_area", "hill_flow__receiver_node", "hill_flow__receiver_proportions", "hill_flow__upstream_node_order", "hill_surface_water__discharge", "hill_topographic__steepest_slope", "squared_length_adjacent", "surface_water__discharge", "topographic__elevation", "topographic__steepest_slope", "water__unit_flux_in", ]
def test_flow_accumulator_properties_D4_varying_water__unit_flux_in(): # %% mg = RasterModelGrid((4, 4), xy_spacing=(1, 1)) _ = mg.add_field("topographic__elevation", mg.node_x * 2 + mg.node_y, at="node") mg.add_field("water__unit_flux_in", mg.node_x * 0 + 2, at="node") fa = PriorityFloodFlowRouter( mg, flow_metric="D4", suppress_out=True, separate_hill_flow=True, hill_flow_metric="D4", accumulate_flow_hill=True, ) # from landlab.components.flow_accum import FlowAccumulator # fa = FlowAccumulator(mg) fa.run_one_step() node_drainage_area = np.array([ 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 1.0, 0.0, 2.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]) assert_array_equal(fa.node_water_discharge, 2 * node_drainage_area.flatten()) assert_array_equal(fa.node_drainage_area, node_drainage_area.flatten()) # Hill flow accumulation should be similar assert_array_equal(mg.at_node["hill_surface_water__discharge"], 2 * node_drainage_area.flatten()) assert_array_equal(mg.at_node["hill_drainage_area"], node_drainage_area.flatten())
def test_flow_accumulator_properties_breach(): # %% mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x * 2 + mg.node_y, at="node") fa = PriorityFloodFlowRouter(mg, flow_metric="D8", suppress_out=True, depression_handler="breach") # from landlab.components.flow_accum import FlowAccumulator # fa = FlowAccumulator(mg) fa.run_one_step() node_drainage_area = np.array([ [3.0, 2.0, 1.0, 0.0, 0.0], [2.0, 3.0, 2.0, 1.0, 0.0], [1.0, 2.0, 2.0, 1.0, 0.0], [0.0, 1.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], ]) assert_array_equal(fa.node_water_discharge, node_drainage_area.flatten()) assert_array_equal(fa.node_drainage_area, node_drainage_area.flatten())
def test_mass_balance_porosity_suspension(): """ Test is mass balance is conserved during sliding events. Test for soils with given porosity phi and where none of the sediment is evacuated as suspended sediment. """ # %% # Make a raster model grid and create a plateau n_rows = 9 n_columns = 9 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) z = mg.add_zeros("topographic__elevation", at="node") s = mg.add_zeros("soil__depth", at="node") b = mg.add_zeros("bedrock__elevation", at="node") # make plateau at 10m b += 10 # Elevate central node b[40] = 10 # Create slope at margin so that sediment will be evacuated b[mg.boundary_nodes] = 0 z[:] = b + s fd = PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) # Instanciate the slider, but this time provide the node at which landslides # should occur (node 2) phi = 0.3 fraction_fines_LS = 0.5 hy = BedrockLandslider( mg, angle_int_frict=1, landslides_return_time=1, landslides_on_boundary_nodes=True, phi=phi, fraction_fines_LS=fraction_fines_LS, ) # Assume equal bulk density for rock and soil total_vol_before = np.sum(b) + np.sum(s) * (1 - phi) # Keep track of total volumes evacuated vol_SSY_tot = 0 V_leaving_tot = 0 # Run for some time for _ in range(5): fd.run_one_step() vol_SSY, V_leaving = hy.run_one_step(dt=1) vol_SSY_tot += vol_SSY V_leaving_tot += V_leaving total_vol_after = np.sum(b) + np.sum(s) * (1 - phi) + vol_SSY_tot + V_leaving_tot # Check mass balance err_msg = "Mass balance not okey" testing.assert_almost_equal( total_vol_before, total_vol_after, decimal=5, err_msg=err_msg )
def test_sliding_evolution(): """ Test that if BedrockLandslider is run for a long enough time, slopes evolve to the angle of internal friction """ # Make a raster model grid and create a plateau n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) z = mg.add_zeros("topographic__elevation", at="node") s = mg.add_zeros("soil__depth", at="node") b = mg.add_zeros("bedrock__elevation", at="node") # make plateau at 10m b += 10 # Lower boundary cell to 0 b[2] = 0 z[:] = b + s fd = PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) # Instanciate the slider, but this time provide the node at which landslides # should occur (node 2) hy = BedrockLandslider( mg, angle_int_frict=1, landslides_return_time=0.01, landslides_on_boundary_nodes=True, critical_sliding_nodes=[2], ) # run flow director and BedrockLandslider for long enough so that surface evolves # towards the angle of internal friction timestep for _ in range(50): fd.run_one_step() hy.run_one_step(dt=1) # After 50 iterations, landslide erosion starting fromnode 2 evolves to a # known slope, equal to the angle of internal friction, multiplied by the # distance from node 2 giving: topo_cal = np.array( [ [2.0, 1.0, 0.0, 1.0, 2.0], [2.23606798, 1.41421356, 1.0, 1.41421356, 2.23606798], [2.82842712, 2.23606798, 2.0, 2.23606798, 2.82842712], [3.60555128, 3.16227766, 3.0, 3.16227766, 3.60555128], [4.47213595, 4.12310563, 4.0, 4.12310563, 4.47213595], ] ).flatten() err_msg = "Slope is not evolving to theoretical value" testing.assert_almost_equal(topo_cal, z, decimal=5, err_msg=err_msg)
def test_accumulated_area_closes(): """Check that accumulated area is area of core nodes.""" mg = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") fa = PriorityFloodFlowRouter(mg, suppress_out=True) fa.run_one_step() drainage_area = mg.at_node["drainage_area"] drained_area = np.sum(drainage_area[mg.boundary_nodes]) core_area = np.sum(mg.cell_area_at_node[mg.core_nodes]) assert drained_area == core_area # %% multiple flow """Check that accumulated area is area of core nodes.""" mg3 = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg3.add_field("topographic__elevation", mg3.node_x + mg3.node_y, at="node") fa3 = PriorityFloodFlowRouter( mg3, separate_hill_flow=True, accumulate_flow_hill=True, hill_flow_metric="Quinn", suppress_out=True, ) fa3.run_one_step() drainage_area_hill = mg3.at_node["hill_drainage_area"] drainage_area_hill = np.sum(drainage_area_hill[mg3.boundary_nodes]) core_area = np.sum(mg3.cell_area_at_node[mg3.core_nodes]) assert drainage_area_hill == core_area
def test_check_fields(): """Check to make sure the right fields have been created.""" # %% mg = RasterModelGrid((10, 10), xy_spacing=(1, 1)) z = mg.add_field("topographic__elevation", mg.node_x**2 + mg.node_y**2, at="node") PriorityFloodFlowRouter(mg) assert_array_equal(z, mg.at_node["topographic__elevation"]) assert_array_equal(np.zeros(100), mg.at_node["drainage_area"]) assert_array_equal(np.ones(100), mg.at_node["water__unit_flux_in"]) PriorityFloodFlowRouter(mg, runoff_rate=2.0) assert_array_equal(np.full(100, 2.0), mg.at_node["water__unit_flux_in"])
def input_values(): # %% """ PriorityFloodFlowRouter should throw an error when wrong input values are provided """ # %% Default configuration mg1 = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg1.add_field("topographic__elevation", mg1.node_x + mg1.node_y, at="node") with pytest.raises(ValueError): _ = PriorityFloodFlowRouter(mg1, suppress_out=True, flow_metric="Oops") with pytest.raises(ValueError): _ = PriorityFloodFlowRouter(mg1, suppress_out=True, depression_handler="Oops")
def test_properties_phi_fraction_fines_LS(): """ BedrockLandslider should throw an error when phi/fraction_fines_LS < 0 or phi > 0 """ # Make a raster model grid and create a plateau n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) mg.add_zeros("topographic__elevation", at="node") mg.add_zeros("soil__depth", at="node") mg.add_zeros("bedrock__elevation", at="node") PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) # instantiate the slider with pytest.raises(ValueError): BedrockLandslider(mg, phi=-0.2) # instantiate the slider with pytest.raises(ValueError): BedrockLandslider(mg, phi=1.2) # instantiate the slider with pytest.raises(ValueError): BedrockLandslider(mg, fraction_fines_LS=-0.2) # instantiate the slider with pytest.raises(ValueError): BedrockLandslider(mg, fraction_fines_LS=1.2)
def test_specifying_routing_method_wrong(): # %% """Test specifying incorrect method for routing compatability""" mg = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") with pytest.raises(TypeError): PriorityFloodFlowRouter(mg, flow_director="D2")
def test_boundary_nodes(): # %% """ Test that if BedrockLandslider cannot make or initate landslides at boundary nodes, it doesn't """ # Make a raster model grid and create a plateau n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) z = mg.add_zeros("topographic__elevation", at="node") s = mg.add_zeros("soil__depth", at="node") b = mg.add_zeros("bedrock__elevation", at="node") # make plateau at 10m b += 10 # Lower boundary cell to 0 b[2] = 0 z[:] = b + s ini_topo_bd = z[mg.boundary_nodes] fd = PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) # Instanciate the slider, but this time provide the node at which landslides # should occur (node 2) hy = BedrockLandslider( mg, angle_int_frict=1, landslides_return_time=0.01, landslides_on_boundary_nodes=False, critical_sliding_nodes=[2], ) # run flow director and BedrockLandslider for long enough so that surface evolves # towards the angle of internal friction timestep for _ in range(5): fd.run_one_step() hy.run_one_step(dt=1) # Final topo at boundary nodes should be inital topo err_msg = "No landslide erosion allowed at boundary nodes" testing.assert_almost_equal( ini_topo_bd, z[mg.boundary_nodes], decimal=5, err_msg=err_msg )
def test_fields2(): # %% No flow accumulation mg2 = RasterModelGrid((7, 7), xy_spacing=(1, 1)) mg2.add_field("topographic__elevation", mg2.node_x + mg2.node_y, at="node") fa2 = PriorityFloodFlowRouter(mg2, suppress_out=True, accumulate_flow=False) fa2.run_one_step() assert sorted(list(mg2.at_node.keys())) == [ "depression_free_elevation", "flood_status_code", "flow__link_to_receiver_node", "flow__receiver_node", "flow__receiver_proportions", "flow__upstream_node_order", "squared_length_adjacent", "topographic__elevation", "topographic__steepest_slope", "water__unit_flux_in", ]
def test_fields5(): # %% Verify multiple flow mg5 = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg5.add_field("topographic__elevation", mg5.node_x + mg5.node_y, at="node") _ = PriorityFloodFlowRouter(mg5, suppress_out=True, flow_metric="Quinn") assert mg5.at_node["topographic__steepest_slope"].shape[1] == 8 assert mg5.at_node["flow__receiver_node"].shape[1] == 8 assert mg5.at_node["flow__receiver_proportions"].shape[1] == 8 assert mg5.at_node["flow__link_to_receiver_node"].shape[1] == 8
def test_D8_metric(): # %% """Test D8 routing functionality""" topographic__elevation = np.array( [ [0.0, 0.0, 0.0, 0.0], [0.0, 21.0, 10.0, 0.0], [0.0, 31.0, 30.8, 0.0], [0.0, 32.0, 30.9, 0.0], [0.0, 0.0, 0.0, 0.0], ] ) mg2 = RasterModelGrid((5, 4), xy_spacing=(1, 1)) mg2.add_field("topographic__elevation", topographic__elevation, at="node") mg2.set_closed_boundaries_at_grid_edges(True, True, True, False) fa2 = PriorityFloodFlowRouter(mg2, flow_metric="D8", suppress_out=True) fa2.run_one_step() pf_r = mg2.at_node["flow__receiver_node"] reciever = np.array( [ [0, 1, 2, 3], [4, 1, 2, 7], [8, 6, 6, 11], [12, 14, 10, 15], [16, 17, 18, 19], ] ) assert_array_equal(reciever.flatten(), pf_r) # Uncomment to compare with default Landlab flow accumulator mg1 = RasterModelGrid((5, 4), xy_spacing=(1, 1)) from landlab.components.flow_accum import FlowAccumulator mg1.add_field("topographic__elevation", topographic__elevation, at="node") mg1.set_closed_boundaries_at_grid_edges(True, True, True, False) fa1 = FlowAccumulator(mg1, flow_director="D8") fa1.run_one_step() defaultLandl_r = mg1.at_node["flow__receiver_node"] assert_array_equal(defaultLandl_r, pf_r)
def test_flow_accumulator_varying_Runoff_rate(): """ There are two options to provide a runoff value The first one is to provide a weight array as a runoff_value input argument """ mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x * 2 + mg.node_y, at="node") runoff_rate = mg.node_x * 0 + 2 fa = PriorityFloodFlowRouter( mg, flow_metric="D8", suppress_out=True, runoff_rate=runoff_rate, separate_hill_flow=True, hill_flow_metric="D8", accumulate_flow_hill=True, ) # from landlab.components.flow_accum import FlowAccumulator # fa = FlowAccumulator(mg) fa.run_one_step() node_drainage_area = np.array([ [3.0, 2.0, 1.0, 0.0, 0.0], [2.0, 3.0, 2.0, 1.0, 0.0], [1.0, 2.0, 2.0, 1.0, 0.0], [0.0, 1.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], ]) assert_array_equal(fa.node_water_discharge, 2 * node_drainage_area.flatten()) assert_array_equal(fa.node_drainage_area, node_drainage_area.flatten()) # Hill flow accumulation should be similar assert_array_equal(mg.at_node["hill_surface_water__discharge"], 2 * node_drainage_area.flatten()) assert_array_equal(mg.at_node["hill_drainage_area"], node_drainage_area.flatten())
def test_inputFields_bedrock(): """ BedrockLandslider should create the bedrock__elevation field when not provided """ n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) mg.add_zeros("topographic__elevation", at="node") mg.add_zeros("soil__depth", at="node") # mg.add_zeros("bedrock__elevation", at='node') PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) BedrockLandslider(mg) # instantiate the slider assert "bedrock__elevation" in mg.at_node
def test_inputFields_soil(): """ BedrockLandslider should throw an error when the soil__depth field is not provided """ n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) mg.add_zeros("topographic__elevation", at="node") # mg.add_zeros("soil__depth", at='node') mg.add_zeros("bedrock__elevation", at="node") PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) # instantiate the slider with pytest.raises(FieldError): BedrockLandslider(mg)
def test_seperate_hillflow_update(): # %% """ Hillflow fields cannot be updated if not initialized """ # %% Default configuration mg1 = RasterModelGrid((6, 6), xy_spacing=(1, 1)) mg1.add_field("topographic__elevation", mg1.node_x + mg1.node_y, at="node") fa1 = PriorityFloodFlowRouter(mg1, suppress_out=True) fa1.run_one_step() with pytest.raises(ValueError): fa1.update_hill_fdfa()
def test_inputFields_flowRouter(): """ BedrockLandslider should throw an error when topograhy is not equal to the sum of bedrock and soil thickness """ # Make a raster model grid and create a plateau n_rows = 5 n_columns = 5 spacing = 1 mg = RasterModelGrid((n_rows, n_columns), xy_spacing=spacing) mg.add_zeros("topographic__elevation", at="node") mg.add_zeros("soil__depth", at="node") b = mg.add_zeros("bedrock__elevation", at="node") # make plateau at 10m b += 10 PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) # instantiate the slider with pytest.raises(RuntimeError): BedrockLandslider(mg)
def test_matches_detachment_solution_PF(): # %% """ Test that model matches the detachment-limited analytical solution for slope/area relationship at steady state: S=(U/K_br)^(1/n)*A^(-m/n). """ # set up a 5x5 grid with one open outlet node and low initial elevations. nr = 5 nc = 5 mg = RasterModelGrid((nr, nc), xy_spacing=10.0) z = mg.add_zeros("topographic__elevation", at="node") br = mg.add_zeros("bedrock__elevation", at="node") soil = mg.add_zeros("soil__depth", at="node") mg["node"]["topographic__elevation"] += ( mg.node_y / 10000 + mg.node_x / 10000 + np.random.rand(len(mg.node_y)) / 10000) mg.set_closed_boundaries_at_grid_edges( bottom_is_closed=True, left_is_closed=True, right_is_closed=True, top_is_closed=True, ) mg.set_watershed_boundary_condition_outlet_id( 0, mg["node"]["topographic__elevation"], -9999.0) br[:] = z[:] - soil[:] fa = PriorityFloodFlowRouter(mg, surface="topographic__elevation", flow_metric="D8", suppress_out=True) fa.run_one_step() # Parameter values for detachment-limited test K_br = 0.01 U = 0.0001 dt = 1.0 F_f = 1.0 # all detached rock disappears; detachment-ltd end-member m_sp = 0.5 n_sp = 1.0 # Instantiate the SpaceLargeScaleEroder component... sp = SpaceLargeScaleEroder( mg, K_sed=0.00001, K_br=K_br, F_f=F_f, phi=0.1, H_star=1.0, v_s=0.001, v_s_lake=0.001, m_sp=m_sp, n_sp=n_sp, sp_crit_sed=0, sp_crit_br=0, ) # ... and run it to steady state (2000x1-year timesteps). for _ in range(2000): fa.run_one_step() sp.run_one_step(dt=dt) z[mg.core_nodes] += U * dt # m br[mg.core_nodes] = z[mg.core_nodes] - soil[mg.core_nodes] # compare numerical and analytical slope solutions num_slope = mg.at_node["topographic__steepest_slope"][mg.core_nodes] analytical_slope = np.power(U / K_br, 1.0 / n_sp) * np.power( mg.at_node["drainage_area"][mg.core_nodes], -m_sp / n_sp) # test for match with analytical slope-area relationship testing.assert_array_almost_equal( num_slope, analytical_slope, decimal=8, err_msg="SpaceLargeScaleEroder detachment-limited test failed", verbose=True, )
def test_matches_bedrock_alluvial_solution_PF(): """ Test that model matches the bedrock-alluvial analytical solution for slope/area relationship at steady state: S=((U * v_s * (1 - F_f)) / (K_sed * A^m) + U / (K_br * A^m))^(1/n). Also test that the soil depth everywhere matches the bedrock-alluvial analytical solution at steady state: H = -H_star * ln(1 - (v_s / (K_sed / (K_br * (1 - F_f)) + v_s))). """ # %% # set up a 5x5 grid with one open outlet node and low initial elevations. nr = 5 nc = 5 mg = RasterModelGrid((nr, nc), xy_spacing=10.0) z = mg.add_zeros("topographic__elevation", at="node") br = mg.add_zeros("bedrock__elevation", at="node") soil = mg.add_zeros("soil__depth", at="node") mg["node"]["topographic__elevation"] += ( mg.node_y / 100000 + mg.node_x / 100000 + np.random.rand(len(mg.node_y)) / 10000) mg.set_closed_boundaries_at_grid_edges( bottom_is_closed=True, left_is_closed=True, right_is_closed=True, top_is_closed=True, ) mg.set_watershed_boundary_condition_outlet_id( 0, mg["node"]["topographic__elevation"], -9999.0) soil[:] += 0.0 # initial condition of no soil depth. br[:] = z[:] z[:] += soil[:] # Create a D8 flow handler fa = PriorityFloodFlowRouter(mg, surface="topographic__elevation", flow_metric="D8", suppress_out=True) fa.run_one_step() # Parameter values for detachment-limited test K_br = 0.002 K_sed = 0.002 U = 0.0001 dt = 10.0 F_f = 0.2 # all detached rock disappears; detachment-ltd end-member m_sp = 0.5 n_sp = 1.0 v_s = 0.25 H_star = 0.1 # Instantiate the SpaceLargeScaleEroder component... sp = SpaceLargeScaleEroder( mg, K_sed=K_sed, K_br=K_br, F_f=F_f, phi=0.0, H_star=H_star, v_s=v_s, m_sp=m_sp, n_sp=n_sp, sp_crit_sed=0, sp_crit_br=0, ) # ... and run it to steady state (10000x1-year timesteps). for _ in range(10000): fa.run_one_step() sp.run_one_step(dt=dt) br[mg.core_nodes] += U * dt # m soil[ 0] = 0.0 # enforce 0 soil depth at boundary to keep lowering steady z[:] = br[:] + soil[:] # compare numerical and analytical slope solutions num_slope = mg.at_node["topographic__steepest_slope"][mg.core_nodes] analytical_slope = np.power( ((U * v_s * (1 - F_f)) / (K_sed * np.power(mg.at_node["drainage_area"][mg.core_nodes], m_sp))) + (U / (K_br * np.power(mg.at_node["drainage_area"][mg.core_nodes], m_sp))), 1.0 / n_sp, ) # test for match with analytical slope-area relationship testing.assert_array_almost_equal( num_slope, analytical_slope, decimal=8, err_msg="SpaceLargeScaleEroder bedrock-alluvial slope-area test failed", verbose=True, ) # compare numerical and analytical soil depth solutions num_h = mg.at_node["soil__depth"][mg.core_nodes] analytical_h = -H_star * np.log(1 - (v_s / (K_sed / (K_br * (1 - F_f)) + v_s))) # test for match with analytical sediment depth testing.assert_array_almost_equal( num_h, analytical_h, decimal=5, err_msg= "SpaceLargeScaleEroder bedrock-alluvial soil thickness test failed", verbose=True, )
def test_sum_prop_is_one(): # %% mg = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") fa = PriorityFloodFlowRouter(mg, separate_hill_flow=True, suppress_out=True) fa.run_one_step() # Single flow props_Pf = mg.at_node["flow__receiver_proportions"] testing.assert_array_almost_equal( props_Pf, np.ones_like(props_Pf), decimal=5, err_msg="Sum of flow proportions is not equal to one", verbose=True, ) # Multiple flow props_Pf = mg.at_node["hill_flow__receiver_proportions"] props_Pf[props_Pf == -1] = 0 props_Pf = props_Pf.sum(axis=1) testing.assert_array_almost_equal( props_Pf, np.ones_like(props_Pf), decimal=5, err_msg="Sum of flow proportions is not equal to one", verbose=True, ) # %% multiple flow with D8 over hills mg = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") fa = PriorityFloodFlowRouter(mg, separate_hill_flow=True, hill_flow_metric="D8", suppress_out=True) fa.run_one_step() # Multiple flow props_Pf = mg.at_node["hill_flow__receiver_proportions"] testing.assert_array_almost_equal( props_Pf, np.ones_like(props_Pf), decimal=5, err_msg="Sum of flow proportions is not equal to one", verbose=True, ) # %% multiple flow with D8 over rivers mg = RasterModelGrid((10, 10), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") fa = PriorityFloodFlowRouter(mg, flow_metric="Quinn", suppress_out=True) fa.run_one_step() # Multiple flow props_Pf = mg.at_node["flow__receiver_proportions"] props_Pf[props_Pf == -1] = 0 props_Pf = np.sum(props_Pf, axis=1) testing.assert_array_almost_equal( props_Pf, np.ones_like(props_Pf), decimal=5, err_msg="Sum of flow proportions is not equal to one", verbose=True, )
def test_hex_mfd(): # %% mg = HexModelGrid((5, 3)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") with pytest.raises(FieldError): PriorityFloodFlowRouter(mg, flow_metric="MFD", suppress_out=True)
def test_bad_metric_name(): # %% mg = RasterModelGrid((5, 5), xy_spacing=(1, 1)) mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") with pytest.raises(Exception): PriorityFloodFlowRouter(mg, flow_metric="spam", suppress_out=True)