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"])
示例#11
0
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")
示例#12
0
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")
示例#14
0
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
    )
示例#15
0
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
示例#17
0
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())
示例#19
0
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
示例#20
0
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()
示例#22
0
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)
示例#23
0
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,
    )
示例#24
0
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)