Exemple #1
0
def test_detachment_steady_no_precip_changer(clock_simple, grid_1, m_sp, n_sp,
                                             depression_finder, U, K):
    ncnblh = NotCoreNodeBaselevelHandler(grid_1,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    params = {
        "grid": grid_1,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": 0.001,
        "hydraulic_conductivity": 1.0,
        "depression_finder": depression_finder,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }
    # construct and run model
    model = BasicVs(**params)
    for _ in range(300):
        model.run_one_step(1000)

    # construct actual and predicted slopes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    predicted_slopes = (U / (params["water_erodibility"] *
                             (actual_areas**params["m_sp"])))**(1.0 /
                                                                params["n_sp"])

    # assert actual and predicted slopes are the same.
    assert_array_almost_equal(
        actual_slopes[model.grid.core_nodes[1:-1]],
        predicted_slopes[model.grid.core_nodes[1:-1]],
    )
Exemple #2
0
def test_two_class_writers(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)
    # construct and run model
    model = Basic(
        clock_08,
        almost_default_grid,
        save_first_timestep=False,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "class": [output_writer_class_a, output_writer_class_b]
        },
    )
    model.run()

    # assert things were done correctly
    truth_file = os.path.join(_TEST_DATA_DIR, "truth_ow_class_a.20.0.txt")
    test_file = get_output_filepath("ow_class_a.20.0.txt")
    assert filecmp(test_file, truth_file) is True

    truth_file = os.path.join(_TEST_DATA_DIR, "truth_ow_class_b.20.0.txt")
    test_file = get_output_filepath("ow_class_b.20.0.txt")
    assert filecmp(test_file, truth_file) is True

    model.remove_output_netcdfs()
    cleanup_files("ow_class_*.txt")
Exemple #3
0
def test_diffusion_only(clock_simple, grid_1, U, Model):
    total_time = 5.0e6
    step = 1000
    ncnblh = NotCoreNodeBaselevelHandler(grid_1,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    params = {
        "grid": grid_1,
        "clock": clock_simple,
        "regolith_transport_parameter": 1,
        "water_erodibility": 0,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }
    # construct and run model
    model = Model(**params)

    nts = int(total_time / step)
    for _ in range(nts):
        model.run_one_step(1000)
    reference_node = 9
    predicted_z = model.z[model.grid.core_nodes[reference_node]] - (
        U / (2.0 * params["regolith_transport_parameter"])) * (
            (model.grid.x_of_node -
             model.grid.x_of_node[model.grid.core_nodes[reference_node]])**2)

    # assert actual and predicted elevations are the same.
    assert_array_almost_equal(
        predicted_z[model.grid.core_nodes],
        model.z[model.grid.core_nodes],
        decimal=2,
    )
def test_channel_erosion(clock_simple, grid_2, m_sp, n_sp, depression_finder,
                         U, solver):
    ncnblh = NotCoreNodeBaselevelHandler(grid_2,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    phi = 0.1
    F_f = 0.0
    v_sc = 0.001
    Kr = 0.001
    Kt = 0.005
    # construct dictionary. note that D is turned off here
    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility_upper": Kt,
        "water_erodibility_lower": Kr,
        "settling_velocity": v_sc,
        "sediment_porosity": phi,
        "fraction_fines": F_f,
        "solver": solver,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicHyRt(**params)
    for _ in range(4000):
        model.run_one_step(10)

    # construct actual and predicted slopes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["drainage_area"]
    rock_predicted_slopes = np.power(
        ((U * v_sc) / (Kr * np.power(actual_areas, m_sp))) +
        (U / (Kr * np.power(actual_areas, m_sp))),
        1.0 / n_sp,
    )
    till_predicted_slopes = np.power(
        ((U * v_sc) / (Kt * np.power(actual_areas, m_sp))) +
        (U / (Kt * np.power(actual_areas, m_sp))),
        1.0 / n_sp,
    )

    # assert actual and predicted slopes are the same for rock and till
    # portions.
    assert_array_almost_equal(actual_slopes[22:37],
                              rock_predicted_slopes[22:37],
                              decimal=3)

    # assert actual and predicted slopes are the same for rock and till
    # portions.
    assert_array_almost_equal(actual_slopes[82:97],
                              till_predicted_slopes[82:97],
                              decimal=3)
Exemple #5
0
def test_steady_Ksp_no_precip_changer(clock_simple, grid_2, depression_finder,
                                      m_sp, n_sp):
    U = 0.0001
    ncnblh = NotCoreNodeBaselevelHandler(grid_2,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)

    Kr = 0.001
    Kt = 0.005
    Tr = 0.0001
    Tt = 0.0005

    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility_lower": Kr,
        "water_erodibility_upper": Kt,
        "water_erosion_rule_upper__threshold": Tt,
        "water_erosion_rule_lower__threshold": Tr,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicRtTh(**params)
    for _ in range(200):
        model.run_one_step(1000)

    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]

    # note that since we have a smooth threshold, we do not have a true
    # analytical solution, but a bracket within wich we expect the actual
    # slopes to fall.
    rock_predicted_slopes_upper = ((U + Tr) /
                                   (Kr * (actual_areas**m_sp)))**(1.0 / n_sp)
    till_predicted_slopes_upper = ((U + Tt) /
                                   (Kt * (actual_areas**m_sp)))**(1.0 / n_sp)

    rock_predicted_slopes_lower = ((U + 0.0) /
                                   (Kr * (actual_areas**m_sp)))**(1.0 / n_sp)
    till_predicted_slopes_lower = ((U + 0.0) /
                                   (Kt * (actual_areas**m_sp)))**(1.0 / n_sp)

    # assert actual and predicted slopes are the same for rock and till
    # portions.
    assert np.all(actual_slopes[22:37] > rock_predicted_slopes_lower[22:37])
    assert np.all(actual_slopes[22:37] < rock_predicted_slopes_upper[22:37])

    assert np.all(actual_slopes[82:97] > till_predicted_slopes_lower[82:97])

    assert np.all(actual_slopes[82:97] < till_predicted_slopes_upper[82:97])
Exemple #6
0
def test_diffusion_only(clock_08, grid_4):
    U = 0.001
    max_soil_production_rate = 0.002
    soil_production_decay_depth = 0.2
    regolith_transport_parameter = 1.0
    soil_transport_decay_depth = 0.5
    S_c = 0.2

    ncnblh = NotCoreNodeBaselevelHandler(
        grid_4, modify_core_nodes=True, lowering_rate=-U
    )

    # Construct dictionary. Note that stream power is turned off
    params = {
        "grid": grid_4,
        "clock": clock_08,
        "regolith_transport_parameter": regolith_transport_parameter,
        "soil_transport_decay_depth": soil_transport_decay_depth,
        "soil_production__maximum_rate": max_soil_production_rate,
        "soil_production__decay_depth": soil_production_decay_depth,
        "critical_slope": S_c,
        "water_erodibility": 0,
        "boundary_handlers": {"NotCoreNodeBaselevelHandler": ncnblh},
    }

    # Construct and run model
    model = BasicChSa(**params)
    for _ in range(30000):
        model.run_one_step(clock_08.step)

    # test steady state soil depth
    actual_depth = model.grid.at_node["soil__depth"][30]
    predicted_depth = -soil_production_decay_depth * np.log(
        U / max_soil_production_rate
    )
    assert_array_almost_equal(actual_depth, predicted_depth, decimal=2)

    # Construct actual and predicted slope at right edge of domain
    x = 8.5 * grid_4.dx
    qs = U * x
    nterms = 11
    p = np.zeros(2 * nterms - 1)
    for k in range(1, nterms + 1):
        p[2 * k - 2] = (
            regolith_transport_parameter
            * soil_transport_decay_depth
            * (1 - np.exp(-predicted_depth / soil_transport_decay_depth))
            * (1 / (S_c ** (2 * (k - 1))))
        )
    p = np.fliplr([p])[0]
    p = np.append(p, qs)
    p_roots = np.roots(p)
    predicted_slope = np.abs(np.real(p_roots[-1]))
    actual_slope = np.abs(
        model.grid.at_node["topographic__steepest_slope"][39]
    )
    assert_array_almost_equal(actual_slope, predicted_slope, decimal=1)
def test_channel_erosion(
    clock_simple,
    grid_1,
    m_sp,
    n_sp,
    depression_finder,
    U,
    K,
    solver,
    Model,
    param_name,
):
    ncnblh = NotCoreNodeBaselevelHandler(grid_1,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    phi = 0.1
    F_f = 0.0
    v_sc = 0.001
    # construct dictionary. note that D is turned off here
    params = {
        "grid": grid_1,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        param_name: K,
        "settling_velocity": v_sc,
        "sediment_porosity": phi,
        "fraction_fines": F_f,
        "solver": solver,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = Model(**params)
    for _ in range(2000):
        model.run_one_step(10)

    # construct actual and predicted slopes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    predicted_slopes = np.power(
        ((U * v_sc) / (K * np.power(actual_areas, m_sp))) +
        (U / (K * np.power(actual_areas, m_sp))),
        1.0 / n_sp,
    )

    # assert actual and predicted slopes are the same.
    assert_array_almost_equal(
        actual_slopes[model.grid.core_nodes[1:-1]],
        predicted_slopes[model.grid.core_nodes[1:-1]],
        decimal=4,
    )
Exemple #8
0
def test_stochastic_duration_rainfall_means():
    """Test option with stochastic duration.

    Test is simply to get the correct total cumulative rain depth.
    """
    U = 0.0001
    K = 0.0001
    m = 1.0
    n = 1.0

    grid = RasterModelGrid((3, 6), xy_spacing=100.0)
    grid.set_closed_boundaries_at_grid_edges(True, False, True, False)
    grid.add_zeros("node", "topographic__elevation")

    ncnblh = NotCoreNodeBaselevelHandler(grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)

    clock = Clock(step=200, stop=400)
    # construct dictionary. note that D is turned off here
    params = {
        "grid": grid,
        "clock": clock,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": K,
        "m_sp": m,
        "n_sp": n,
        "opt_stochastic_duration": True,
        "record_rain": True,
        "mean_storm_duration": 1.0,
        "mean_interstorm_duration": 1.0,
        "infiltration_capacity": 1.0,
        "random_seed": 3141,
        "mean_storm_depth": 1.0,
        "output_interval": 401,
        "depression_finder": "DepressionFinderAndRouter",
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicSt(**params)
    model.run()

    cum_rain_depth = np.sum(
        np.array(model.rain_record["event_duration"]) *
        np.array(model.rain_record["rainfall_rate"]))
    assert_equal(np.round(cum_rain_depth), 200.0)

    os.remove("storm_sequence.txt")
    fs = glob.glob(model._out_file_name + "*.nc")
    for f in fs:
        os.remove(f)
Exemple #9
0
def test_multiple_frequencies(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    common_interval = 2.0
    uncommon_interval = 5.0
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "common-ow": {
                "class": OWStaticWrapper,
                "kwargs": {
                    "add_id": False,
                    "intervals": common_interval,
                },
            },
            "uncommon-ow": {
                "class": OWStaticWrapper,
                "kwargs": {
                    "add_id": False,
                    "intervals": uncommon_interval,
                },
            },
        },
        # output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        output_prefix="",
        save_first_timestep=True,
        save_last_timestep=True,
    )
    model.run()

    for name, interval in [
        ("common-ow", common_interval),
        ("uncommon-ow", uncommon_interval),
    ]:
        for output_time in itertools.count(0.0, interval):
            if output_time > clock_08.stop:
                # Break the infinite iterator at the clock stop time
                break
            # assert things were done correctly
            filename = f"{name}_time-{output_time:012.1f}.txt"
            truth_file = os.path.join(_TEST_DATA_DIR, f"truth_{filename}")
            test_file = get_output_filepath(filename)
            assert filecmp(test_file, truth_file) is True

    model.remove_output()
Exemple #10
0
def test_steady_Ksp_no_precip_changer_no_thresh_change(
    clock_simple,
    grid_2,
    U,
    K,
    m_sp,
    n_sp,
    depression_finder,
    threshold,
    thresh_change_per_depth,
):

    ncnblh = NotCoreNodeBaselevelHandler(grid_2,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": K,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "water_erosion_rule__threshold": threshold,
        "water_erosion_rule__thresh_depth_derivative": thresh_change_per_depth,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicDd(**params)
    for _ in range(200):
        model.run_one_step(1000)

    # construct actual and predicted slopes
    # note that since we have a smooth threshold, we do not have a true
    # analytical solution, but a bracket within wich we expect the actual
    # slopes to fall.
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    predicted_slopes_upper = ((U + threshold) /
                              (K * (actual_areas**m_sp)))**(1.0 / n_sp)
    predicted_slopes_lower = ((U + 0.0) / (K * (actual_areas**m_sp)))**(1.0 /
                                                                        n_sp)

    # assert actual and predicted slopes are in the correct range for the
    # slopes.
    assert np.all(actual_slopes[model.grid.core_nodes[1:-1]] >
                  predicted_slopes_lower[model.grid.core_nodes[1:-1]])

    assert np.all(actual_slopes[model.grid.core_nodes[1:-1]] <
                  predicted_slopes_upper[model.grid.core_nodes[1:-1]])
def test_rock_till_steady_no_precip_changer_ChRtTh(
    clock_simple,
    Model,
    grid_2,
    m_sp,
    n_sp,
    depression_finder,
    U,
    Kr,
    Kt,
    flow_director,
):
    ncnblh = NotCoreNodeBaselevelHandler(grid_2,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility_lower": Kr,
        "water_erodibility_upper": Kt,
        "depression_finder": depression_finder,
        "flow_director": flow_director,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "water_erosion_rule_upper__threshold": 0.0000001,
        "water_erosion_rule_lower__threshold": 0.0000001,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = Model(**params)
    for _ in range(200):
        model.run_one_step(1000)

    # construct actual and predicted slopes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    rock_predicted_slopes = (U / (Kr * (actual_areas**m_sp)))**(1.0 / n_sp)
    till_predicted_slopes = (U / (Kt * (actual_areas**m_sp)))**(1.0 / n_sp)

    # assert actual and predicted slopes are the same for rock and till
    # portions.
    assert_array_almost_equal(actual_slopes[22:37],
                              rock_predicted_slopes[22:37],
                              decimal=4)

    assert_array_almost_equal(actual_slopes[82:97],
                              till_predicted_slopes[82:97],
                              decimal=4)
Exemple #12
0
def test_static_default(
    clock_08,
    almost_default_grid,
    times,
    intervals,
    correct_times,
):
    static_kwargs = {
        "add_id": False,
        "save_first_timestep": True,
        "save_last_timestep": True,
    }
    if times is not None:
        static_kwargs["times"] = times

    if intervals is not None:
        static_kwargs["intervals"] = intervals

    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "out-of-phase-ow": {
                "class": OWStaticWrapper,
                "kwargs": static_kwargs,
            },
        },
        output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        output_prefix="",
        save_first_timestep=True,
        save_last_timestep=True,
    )

    static_ow = model.get_output_writer("out-of-phase-ow")[0]
    for t_int in correct_times:
        if t_int is None:
            print(f"checking: {t_int} is {static_ow.next_output_time}")
            assert static_ow.next_output_time is None
        else:
            print(f"checking: {float(t_int)} == {static_ow.next_output_time}")
            assert static_ow.next_output_time == float(t_int)
        static_ow.advance_iter()

    model.remove_output()
Exemple #13
0
def test_steady_Kss_no_precip_changer(
    clock_simple, grid_2, U, K, m_sp, n_sp, depression_finder
):

    hydraulic_conductivity = 0.1
    threshold = 0.01

    ncnblh = NotCoreNodeBaselevelHandler(
        grid_2, modify_core_nodes=True, lowering_rate=-U
    )

    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": K,
        "hydraulic_conductivity": hydraulic_conductivity,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "water_erosion_rule__threshold": threshold,
        "depression_finder": depression_finder,
        "boundary_handlers": {"NotCoreNodeBaselevelHandler": ncnblh},
    }

    # construct and run model
    model = BasicThVs(**params)
    for _ in range(200):
        model.run_one_step(1000)

    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    predicted_slopes_upper = (
        (U + threshold) / (K * (actual_areas ** m_sp))
    ) ** (1.0 / n_sp)
    predicted_slopes_lower = ((U + 0.0) / (K * (actual_areas ** m_sp))) ** (
        1.0 / n_sp
    )

    # assert actual and predicted slopes are in the correct range for the
    # slopes.
    assert np.all(
        actual_slopes[model.grid.core_nodes[1:-1]]
        > predicted_slopes_lower[model.grid.core_nodes[1:-1]]
    )

    assert np.all(
        actual_slopes[model.grid.core_nodes[1:-1]]
        < predicted_slopes_upper[model.grid.core_nodes[1:-1]]
    )
Exemple #14
0
def test_out_of_phase_interval_last(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    interval = 19.5
    warning_msg_sample = "time that is not divisible by the model step"
    with pytest.warns(UserWarning, match=warning_msg_sample):
        model = Basic(
            clock_08,
            almost_default_grid,
            water_erodibility=0.0,
            regolith_transport_parameter=0.0,
            boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
            output_writers={
                "out-of-phase-ow": {
                    "class": OWStaticWrapper,
                    "kwargs": {
                        "add_id": False,
                        "intervals": interval,
                    },
                },
            },
            # output_interval=6.0,
            output_dir=_TEST_OUTPUT_DIR,
            output_prefix="",
            save_first_timestep=True,
            save_last_timestep=True,
        )
        model.run()

    # The model should still run fine, but any out of phase output times are
    # delayed to the next step.

    # Check that there is no file for t=19.5
    bad_filename = f"out-of-phase-ow_time-{19.5:012.1f}.txt"
    bad_filepath = get_output_filepath(bad_filename)
    assert not os.path.isfile(bad_filepath), f"{bad_filepath} should not exist"

    # Check that the output that should exist
    for time_int in [0, 20]:  # instead of [0, 19.5, 20]
        filename = f"out-of-phase-ow_time-{float(time_int):012.1f}.txt"
        truth_file = os.path.join(_TEST_DATA_DIR, f"truth_{filename}")
        test_file = get_output_filepath(filename)
        assert filecmp(test_file, truth_file) is True

    model.remove_output()
Exemple #15
0
def test_steady_Ksp_no_precip_changer_no_thresh_change(
    clock_simple,
    grid_2,
    U,
    Kr,
    Kt,
    m_sp,
    n_sp,
    depression_finder,
    threshold,
    thresh_change_per_depth,
):

    ncnblh = NotCoreNodeBaselevelHandler(grid_2,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility_lower": Kr,
        "water_erodibility_upper": Kt,
        "water_erosion_rule__threshold": threshold,
        "water_erosion_rule__thresh_depth_derivative": thresh_change_per_depth,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicDdRt(**params)
    for _ in range(100):
        model.run_one_step(1000)

    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["drainage_area"]
    rock_predicted_slopes = (U / (Kr * (actual_areas**m_sp)))**(1.0 / n_sp)
    till_predicted_slopes = (U / (Kt * (actual_areas**m_sp)))**(1.0 / n_sp)

    # assert actual slopes are steeper than simple stream power prediction
    assert np.all(actual_slopes[22:37] > rock_predicted_slopes[22:37])
    # assert actual slopes are steeper than simple stream power prediction
    assert np.all(actual_slopes[82:97] > till_predicted_slopes[82:97])
Exemple #16
0
def test_Aeff(clock_simple, grid_2, K, U, Model):
    m_sp = 0.5
    n_sp = 1.0
    ncnblh = NotCoreNodeBaselevelHandler(
        grid_2, modify_core_nodes=True, lowering_rate=-U
    )
    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": K,
        "hydraulic_conductivity": 0.02,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "depression_finder": "DepressionFinderAndRouter",
        "boundary_handlers": {"NotCoreNodeBaselevelHandler": ncnblh},
    }

    # construct and run model
    model = Model(**params)
    for _ in range(1000):
        model.run_one_step(10)

    # construct actual and predicted slopes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["drainage_area"]

    alpha = (
        params["hydraulic_conductivity"]
        * grid_2.at_node["soil__depth"][0]
        * grid_2.dx
        / grid_2.at_node["rainfall__flux"][0]
    )

    A_eff_predicted = actual_areas * np.exp(
        -(-alpha * actual_slopes) / actual_areas
    )

    # assert aeff internally calculated correclty
    assert_array_almost_equal(
        model.grid.at_node["surface_water__discharge"][model.grid.core_nodes],
        A_eff_predicted[model.grid.core_nodes],
        decimal=1,
    )
def test_diffusion_only(clock_09, grid_4, Model):
    U = 0.0005
    D = 1.0
    S_c = 0.3

    ncnblh = NotCoreNodeBaselevelHandler(grid_4,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)

    params = {
        "grid": grid_4,
        "clock": clock_09,
        "regolith_transport_parameter": D,
        "water_erodibility_lower": 0,
        "water_erodibility_upper": 0,
        "critical_slope": S_c,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # Construct and run model
    model = Model(**params)
    for _ in range(20000):
        model.run_one_step(clock_09.step)

    # Construct actual and predicted slope at right edge of domain
    x = 8.5 * grid_4.dx

    qs = U * x
    nterms = 7
    p = np.zeros(2 * nterms - 1)
    for k in range(1, nterms + 1):
        p[2 * k - 2] = D * (1 / (S_c**(2 * (k - 1))))
    p = np.fliplr([p])[0]
    p = np.append(p, qs)
    p_roots = np.roots(p)
    predicted_slope = np.abs(np.real(p_roots[-1]))
    # print(predicted_slope)

    actual_slope = np.abs(
        model.grid.at_node["topographic__steepest_slope"][39])
    assert_array_almost_equal(actual_slope, predicted_slope, decimal=2)
Exemple #18
0
def test_steady_Kss_no_precip_changer(clock_simple, grid_2, U, Kr, Kt, m_sp,
                                      n_sp, depression_finder):

    hydraulic_conductivity = 0.1

    ncnblh = NotCoreNodeBaselevelHandler(grid_2,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)

    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility_lower": Kr,
        "water_erodibility_upper": Kt,
        "hydraulic_conductivity": hydraulic_conductivity,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicRtVs(**params)
    for _ in range(100):
        model.run_one_step(1000)

    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    rock_predicted_slopes = (U / (Kr * (actual_areas**m_sp)))**(1.0 / n_sp)
    till_predicted_slopes = (U / (Kt * (actual_areas**m_sp)))**(1.0 / n_sp)

    # assert actual and predicted slopes are the same for rock and till.
    assert_array_almost_equal(actual_slopes[22:37],
                              rock_predicted_slopes[22:37])

    # assert actual and predicted slopes are the same for rock and till.
    assert_array_almost_equal(actual_slopes[82:97],
                              till_predicted_slopes[82:97])
Exemple #19
0
def test_save_first_last_and_multiple_times(clock_08, almost_default_grid):
    """Test save_first_timestep, save_last_timestep, and saving at multiple
    timesteps."""
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "function": [output_writer_function_a, output_writer_function_b],
            "class": [output_writer_class_a, output_writer_class_b],
        },
        output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        save_first_timestep=True,
        save_last_timestep=True,
    )
    model.run()

    for t in ["0.0", "6.0", "12.0", "18.0", "20.0"]:
        # assert things were done correctly
        filename_bases = [
            f"ow_func_a.{t}.txt",
            f"ow_func_b.{t}.txt",
            f"ow_class_a.{t}.txt",
            f"ow_class_b.{t}.txt",
        ]
        for filename_base in filename_bases:
            truth_file = os.path.join(_TEST_DATA_DIR, f"truth_{filename_base}")
            test_file = os.path.join(os.curdir, "output", filename_base)
            assert filecmp(test_file, truth_file) is True

    model.remove_output_netcdfs()
    cleanup_files(get_output_filepath("ow_func_*.txt"))
    cleanup_files(get_output_filepath("ow_class_*.txt"))
Exemple #20
0
def test_custom_iter(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "fibonnaci": {
                "class": OWGenericWrapper,
                "kwargs": {
                    "add_id": False,
                    "times_iter": fibonnaci(),
                },
            },
        },
        # output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        output_prefix="",
        save_first_timestep=True,
        save_last_timestep=True,
    )
    with pytest.warns(OutputIteratorSkipWarning):
        model.run()

    for time_int in [0, 1, 2, 3, 5, 8, 13, 20]:
        # Note: the second 1 in the fib sequence will be skipped

        # assert things were done correctly
        filename = f"fibonnaci_time-{float(time_int):012.1f}.txt"
        truth_file = os.path.join(_TEST_DATA_DIR, f"truth_{filename}")
        test_file = get_output_filepath(filename)
        assert filecmp(test_file, truth_file) is True

    model.remove_output()
Exemple #21
0
def test_steady_without_stochastic_duration(
    clock_simple, depression_finder, U, K, grid_2, m_sp, n_sp
):
    ncnblh = NotCoreNodeBaselevelHandler(
        grid_2, modify_core_nodes=True, lowering_rate=-U
    )
    grid_2.at_node["soil__depth"][:] = 1.0e-9
    # construct dictionary. note that D is turned off here
    params = {
        "grid": grid_2,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": K,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "hydraulic_conductivity": 1.0e-9,
        "number_of_sub_time_steps": 100,
        "rainfall_intermittency_factor": 1.0,
        "rainfall__mean_rate": 1.0,
        "rainfall__shape_factor": 1.0,
        "random_seed": 3141,
        "depression_finder": depression_finder,
        "boundary_handlers": {"NotCoreNodeBaselevelHandler": ncnblh},
    }

    # construct and run model
    model = BasicStVs(**params)
    for _ in range(100):
        model.run_one_step(1.0)

    # construct actual and predicted slopes
    ic = model.grid.core_nodes[1:-1]  # "inner" core nodes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    predicted_slopes = (U / (K * (actual_areas ** m_sp))) ** (1.0 / n_sp)
    assert_array_almost_equal(
        actual_slopes[ic], predicted_slopes[ic], decimal=4
    )
Exemple #22
0
def test_out_of_phase_interval_warns(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    times = [
        0.0,
        1.0,
        1.01,  # next time is set to 2. Divisible warning
        1.02,  # new time < 2. Starting skips. Skipping warning
        1.10,
        1.11,
        1.12,
        1.13,
        1.14,
        1.15,
        1.16,
        1.17,
        1.18,
        3.00,  # Finds suitable time on 10th skip.
    ]
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "out-of-phase-skipping-ow": {
                "class": OWStaticWrapper,
                "kwargs": {
                    "add_id": False,
                    "times": times,
                },
            },
        },
        # output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        output_prefix="",
        save_first_timestep=True,
        save_last_timestep=True,
    )
    skip_warning_msg = "next time that is less than or equal to the current"
    divisible_warning_msg = "time that is not divisible by the model step"

    # Copied from ErosionModel.run() so I can control the steps
    model._itters = []
    if model.save_first_timestep:
        model.iteration = 0
        model._itters.append(0)
        model.write_output()
    model.iteration = 1

    def run_one_iteration():
        time_now = model._model_time
        next_run_pause = min(
            model.next_output_time,
            model.clock.stop,
        )
        assert next_run_pause > time_now
        print(f"Iteration {model.iteration:05d} Model time {model.model_time}")
        print(
            f"  Run for {next_run_pause - time_now}, (step = {model.clock.step})"
        )
        model.run_for(model.clock.step, next_run_pause - time_now)
        time_now = model._model_time
        model._itters.append(model.iteration)
        model.write_output()
        model.iteration += 1

    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 0.0 and model.next_output_time == 1.0

    warning_msg_sample = "time that is not divisible by the model step"
    with pytest.warns(UserWarning, match=warning_msg_sample):
        run_one_iteration()
    # times_iter returns 1.01, which is then delayed to 2.0
    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 1.00 and model.next_output_time == 2.0

    # time_iter returns 1.02, which triggers skips but eventually finds 3.0
    with pytest.warns(UserWarning) as all_warnings:
        run_one_iteration()
    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 2.0 and model.next_output_time == 3.0
    ignored_warnings = [RuntimeWarning]
    for warn_info in all_warnings:
        warn_type = warn_info.category
        if warn_type in ignored_warnings:
            continue
        try:
            assert warn_type == UserWarning
            message = warn_info.message.args[0]
            is_skip_warning = skip_warning_msg in message
            is_divisible_warning = divisible_warning_msg in message
            assert is_skip_warning or is_divisible_warning
        except AssertionError:
            print(warn_info)  # So I can see other warnings
            raise

    run_one_iteration()
    # times_iter returns 20.0
    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 3.0 and model.next_output_time == 20.0

    run_one_iteration()
    # Model finishes
    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 20.0 and model.next_output_time == np.inf

    # now that the model is finished running, execute finalize.
    model.finalize()

    # Check that there is a file for t=3.0
    good_filename = f"out-of-phase-skipping-ow_time-{3.0:012.1f}.txt"
    good_filepath = get_output_filepath(good_filename)
    assert os.path.isfile(good_filepath), f"{good_filepath} should exist"

    model.remove_output()
Exemple #23
0
def test_diffusion_only(clock_simple, grid_4_smaller, Model, water_params):
    grid_4 = grid_4_smaller
    U = 0.001
    max_soil_production_rate = 0.002
    soil_production_decay_depth = 0.2
    regolith_transport_parameter = 1.0
    soil_transport_decay_depth = 0.5

    grid_4.at_node["soil__depth"][:] = 0.0

    ncnblh = NotCoreNodeBaselevelHandler(
        grid_4, modify_core_nodes=True, lowering_rate=-U
    )

    params = {
        "grid": grid_4,
        "clock": clock_simple,
        "regolith_transport_parameter": regolith_transport_parameter,
        "soil_transport_decay_depth": soil_transport_decay_depth,
        "soil_production__maximum_rate": max_soil_production_rate,
        "soil_production__decay_depth": soil_production_decay_depth,
        "boundary_handlers": {"NotCoreNodeBaselevelHandler": ncnblh},
    }
    dx = grid_4.dx

    for p in water_params:
        params[p] = water_params[p]

    # make predicted depth:
    predicted_depth = -soil_production_decay_depth * np.log(
        U / max_soil_production_rate
    )

    # maek predicted profile.
    domain = np.arange(0, max(grid_4.x_of_node + dx), dx)

    half_domain = np.arange(0, max(domain) / 2.0 + dx, dx)

    one_minus_h_hstar = 1 - np.exp(
        -predicted_depth / soil_transport_decay_depth
    )

    half_domain_z = (
        -(half_domain ** 2)
        * U
        / (
            regolith_transport_parameter
            * soil_transport_decay_depth
            * 2.0
            * one_minus_h_hstar
        )
    )

    steady_z_profile = np.concatenate(
        (np.flipud(half_domain_z), half_domain_z[1:])
    )

    predicted_profile = steady_z_profile - np.min(steady_z_profile)

    test_dt = 1000

    # construct and run model
    model = Model(**params)
    for i in range(20000):
        model.run_one_step(15)

        # at intervals of test_dt, see if tests pass, thus we break out of loop
        # once the tests pass.
        if i % test_dt == 0:

            try:
                # test steady state soil depthf
                actual_depth = model.grid.at_node["soil__depth"][14]
                assert_array_almost_equal(
                    actual_depth, predicted_depth, decimal=2
                )

                # test steady state slope
                actual_profile = model.grid.at_node["topographic__elevation"][
                    11:22
                ]
                assert_array_almost_equal(
                    actual_profile, predicted_profile, decimal=1
                )

                # if pass, then break.
                break

            except AssertionError:
                pass
def test_diffusion_only(clock_simple, grid_4, Model, water_params):

    U = 0.001
    max_soil_production_rate = 0.002
    soil_production_decay_depth = 0.2
    regolith_transport_parameter = 1.0
    soil_transport_decay_depth = 0.5

    grid_4.at_node["soil__depth"][:] = 0.0

    ncnblh = NotCoreNodeBaselevelHandler(grid_4,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)

    params = {
        "grid": grid_4,
        "clock": clock_simple,
        "regolith_transport_parameter": regolith_transport_parameter,
        "soil_transport_decay_depth": soil_transport_decay_depth,
        "soil_production__maximum_rate": max_soil_production_rate,
        "soil_production__decay_depth": soil_production_decay_depth,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }
    for p in water_params:
        params[p] = water_params[p]

    # construct and run model
    model = Model(**params)
    for _ in range(20000):
        model.run_one_step(15)

    dx = grid_4.dx

    # test steady state soil depthf
    actual_depth = model.grid.at_node["soil__depth"][28]
    predicted_depth = -soil_production_decay_depth * np.log(
        U / max_soil_production_rate)
    assert_array_almost_equal(actual_depth, predicted_depth, decimal=2)

    # test steady state slope
    actual_profile = model.grid.at_node["topographic__elevation"][21:42]

    domain = np.arange(0, max(model.grid.node_x + dx), dx)

    half_domain = np.arange(0, max(domain) / 2.0 + dx, dx)

    one_minus_h_hstar = 1 - np.exp(
        -predicted_depth / soil_transport_decay_depth)

    half_domain_z = (-half_domain**2 * U /
                     (regolith_transport_parameter *
                      soil_transport_decay_depth * 2.0 * one_minus_h_hstar))

    steady_z_profile = np.concatenate(
        (np.flipud(half_domain_z), half_domain_z[1:]))

    predicted_profile = steady_z_profile - np.min(steady_z_profile)

    assert_array_almost_equal(actual_profile, predicted_profile, decimal=1)
Exemple #25
0
def test_out_of_phase_interval_fails(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    times = [
        0.0,
        1.0,
        1.01,  # next time is set to 2. Divisible warning
        1.02,  # new time < 2. Starting skips. Skipping warning
        1.10,
        1.11,
        1.12,
        1.13,
        1.14,
        1.15,
        1.16,
        1.17,
        1.18,
        2.00,  # 10 skips. Loop exits. Raises Assertion Error
        3.0,  # Does not get this far
    ]
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "out-of-phase-ow-fails": {
                "class": OWStaticWrapper,
                "kwargs": {
                    "add_id": False,
                    "times": times,
                },
            },
        },
        # output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        output_prefix="",
        save_first_timestep=True,
        save_last_timestep=True,
    )
    skip_warning_msg = "next time that is less than or equal to the current"
    divisible_warning_msg = "time that is not divisible by the model step"

    # Copied from ErosionModel.run() so I can control the steps
    model._itters = []

    if model.save_first_timestep:
        model.iteration = 0
        model._itters.append(0)
        model.write_output()
    model.iteration = 1

    def run_one_iteration():
        time_now = model._model_time
        next_run_pause = min(
            # time_now + model.output_interval, model.clock.stop,
            model.next_output_time,
            model.clock.stop,
        )
        assert next_run_pause > time_now
        print(f"Iteration {model.iteration:05d} Model time {model.model_time}")
        print(
            f"  Run for {next_run_pause - time_now}, (step = {model.clock.step})"
        )
        model.run_for(model.clock.step, next_run_pause - time_now)
        time_now = model._model_time
        model._itters.append(model.iteration)
        model.write_output()
        model.iteration += 1

    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 0.0 and model.next_output_time == 1.0

    warning_msg_sample = "time that is not divisible by the model step"
    with pytest.warns(UserWarning, match=warning_msg_sample):
        run_one_iteration()
    # times_iter returns 1.01, which is then delayed to 2.0
    print(f"t={model.model_time}, nt={model.next_output_time}")
    assert model.model_time == 1.00 and model.next_output_time == 2.0

    # time_iter returns 1.02, which triggers skips and eventually fails
    with pytest.warns(UserWarning) as all_warnings, pytest.raises(
            AssertionError):
        run_one_iteration()
    ignored_warnings = [RuntimeWarning]
    for warn_info in all_warnings:
        warn_type = warn_info.category
        if warn_type in ignored_warnings:
            continue
        try:
            assert warn_type == UserWarning
            message = warn_info.message.args[0]
            is_skip_warning = skip_warning_msg in message
            is_divisible_warning = divisible_warning_msg in message
            assert is_skip_warning or is_divisible_warning
        except AssertionError:
            print(warn_info)  # So I can see other warnings
            raise

    model.remove_output()
Exemple #26
0
def test_channel_erosion(clock_simple, grid_1, m_sp, n_sp, depression_finder,
                         U, solver):
    ncnblh = NotCoreNodeBaselevelHandler(grid_1,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    phi = 0.1
    F_f = 0.0
    v_sc = 0.001
    K_rock_sp = 0.001
    K_sed_sp = 0.005
    sp_crit_br = 0
    sp_crit_sed = 0
    H_star = 0.1
    soil_transport_decay_depth = 1
    soil_production__maximum_rate = 0
    soil_production__decay_depth = 0.5
    # construct dictionary. note that D is turned off here
    params = {
        "grid": grid_1,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility_rock": K_rock_sp,
        "water_erodibility_sediment": K_sed_sp,
        "sp_crit_br": sp_crit_br,
        "sp_crit_sed": sp_crit_sed,
        "m_sp": m_sp,
        "n_sp": n_sp,
        "settling_velocity": v_sc,
        "sediment_porosity": phi,
        "fraction_fines": F_f,
        "roughness__length_scale": H_star,
        "solver": solver,
        "soil_transport_decay_depth": soil_transport_decay_depth,
        "soil_production__maximum_rate": soil_production__maximum_rate,
        "soil_production__decay_depth": soil_production__decay_depth,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    # construct and run model
    model = BasicHySa(**params)
    for _ in range(2000):
        model.run_one_step(10)

    # construct actual and predicted slopes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"]
    actual_areas = model.grid.at_node["surface_water__discharge"]
    predicted_slopes = np.power(
        ((U * v_sc) / (K_sed_sp * np.power(actual_areas, m_sp))) +
        (U / (K_rock_sp * np.power(actual_areas, m_sp))),
        1.0 / n_sp,
    )

    # assert actual and predicted slopes are the same.
    assert_array_almost_equal(
        actual_slopes[model.grid.core_nodes[1:-1]],
        predicted_slopes[model.grid.core_nodes[1:-1]],
        decimal=4,
    )

    with pytest.raises(SystemExit):
        for _ in range(800):
            model.run_one_step(100000)
Exemple #27
0
def test_steady_without_stochastic_duration(clock_simple, Model, extra_params,
                                            depression_finder):
    r"""Test steady profile solution with fixed duration.

    Notes
    -----
    We use m=1 because the integral that averages over storm events has an
    analytical solution; it evaluates to 1/2 when mean rain intensity and
    infiltration capacity are both equal to unity. This is where the factor of
    2 in the predicted-slope calculation below comes from.

    The derivation is as follows.

    Instantaneous erosion rate, :math:E_i:

    ..math::

        E_i = K Q^m S^n

    Instantaneous water discharge depends on drainage area, :math:A, rain
    intensity, :math:P, and infiltration capacity, :math:I_m:

    ..math::

        Q = R A
        R = P - I_m (1 - e^{-P/I_m})

    Average erosion rate, :math:E, is the integral of instantaneous erosion
    rate over all possible rain rates times the PDF of rain rate, :math:f(P):

    ..math::

        E = \int_0^\infty f(P) K A^m S^n [P-I_m(1-e^{-P/I_m})]^m dP
          = K A^m S^n \int_0^\infty f(P) [P-I_m(1-e^{-P/I_m})]^m dP
          = K A^m S^n \Phi

    where :math:\Phi represents the integral. For testing purposes, we seek an
    analytical solution to the integral. Take :math:`m=n=1` and :math:`P=I_m=1`. Also
    assume that the distribution shape factor is 1, so that
    :math:`f(P) = (1/Pbar) e^{-P/Pbar}`.

    According to the online integrator, the indefinite integral solution under
    these assumptions is

    ..math::

        \Phi = e^{-P} (-\frac{1}{2} e^{-P} - P)

    The definite integral should therefore be 1/2.

    The slope-area relation is therefore

    ..math::

        S = \frac{2U}{K A}
    """
    U = 0.0001
    K = 0.001
    m = 1.0
    n = 1.0

    grid = RasterModelGrid((3, 6), xy_spacing=100.0)
    grid.set_closed_boundaries_at_grid_edges(False, True, False, True)
    grid.add_zeros("node", "topographic__elevation")
    s = grid.add_zeros("node", "soil__depth")
    s[:] = 1e-9

    ncnblh = NotCoreNodeBaselevelHandler(grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)

    # construct dictionary. note that D is turned off here
    params = {
        "grid": grid,
        "clock": clock_simple,
        "regolith_transport_parameter": 0.0,
        "water_erodibility": K,
        "m_sp": m,
        "n_sp": n,
        "number_of_sub_time_steps": 100,
        "rainfall_intermittency_factor": 1.0,
        "rainfall__mean_rate": 1.0,
        "rainfall__shape_factor": 1.0,
        "random_seed": 3141,
        "depression_finder": depression_finder,
        "boundary_handlers": {
            "NotCoreNodeBaselevelHandler": ncnblh
        },
    }

    for p in extra_params:
        params[p] = extra_params[p]

    # construct and run model
    model = Model(**params)
    for _ in range(100):
        model.run_one_step(1.0)

    # construct actual and predicted slopes
    ic = model.grid.core_nodes[1:-1]  # "inner" core nodes
    actual_slopes = model.grid.at_node["topographic__steepest_slope"][ic]
    actual_areas = model.grid.at_node["drainage_area"][ic]
    predicted_slopes = 2 * U / (K * (actual_areas))

    # assert actual and predicted slopes are the same.
    assert_array_almost_equal(actual_slopes, predicted_slopes)
Exemple #28
0
def test_deleting_output(clock_08, almost_default_grid):
    ncnblh = NotCoreNodeBaselevelHandler(almost_default_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-1)

    # construct and run model
    model = Basic(
        clock_08,
        almost_default_grid,
        water_erodibility=0.0,
        regolith_transport_parameter=0.0,
        boundary_handlers={"NotCoreNodeBaselevelHandler": ncnblh},
        output_writers={
            "fibonnaci-1": {
                "class": OWGenericWrapper,
                "kwargs": {
                    "add_id": False,
                    "times_iter": fibonnaci(),
                    "verbose": True,
                },
            },
            "fibonnaci-2": {
                "class": OWGenericWrapper,
                "kwargs": {
                    "add_id": False,
                    "times_iter": fibonnaci(),
                    "verbose": True,
                },
            },
            "fibonnaci-3": {
                "class": OWGenericWrapper,
                "kwargs": {
                    "add_id": False,
                    "times_iter": fibonnaci(),
                    "verbose": True,
                },
            },
            "netcdf-1": {
                "class": OWSimpleNetCDF,
                "args": ["topographic__elevation"],
                "kwargs": {
                    "intervals": 5.0,
                    "add_id": False,
                    "verbose": True
                },
            },
            "netcdf-2": {
                "class": OWSimpleNetCDF,
                "args": ["topographic__elevation"],
                "kwargs": {
                    "intervals": 5.0,
                    "add_id": False,
                    "verbose": True
                },
            },
            "netcdf-3": {
                "class": OWSimpleNetCDF,
                "args": ["topographic__elevation"],
                "kwargs": {
                    "intervals": 5.0,
                    "add_id": False,
                    "verbose": True
                },
            },
        },
        # output_interval=6.0,
        output_dir=_TEST_OUTPUT_DIR,
        output_prefix="",
        output_default_netcdf=False,
        save_first_timestep=True,
        save_last_timestep=True,
    )
    with pytest.warns(OutputIteratorSkipWarning):
        model.run()

    class NotAWriter:
        pass

    not_a_writer = NotAWriter()
    with pytest.raises(TypeError):
        model.remove_output(writer=not_a_writer)
    with pytest.raises(TypeError):
        model.remove_output(extension=not_a_writer)

    def all_exist(filepaths):
        assert all([os.path.isfile(fp) for fp in filepaths])

    def all_deleted(filepaths):
        assert all([not os.path.isfile(fp) for fp in filepaths])

    ow_fib_1 = model.get_output_writer("fibonnaci-1")[0]
    ow_fib_2 = model.get_output_writer("fibonnaci-2")[0]
    ow_fib_3 = model.get_output_writer("fibonnaci-3")[0]
    ow_nc_all = model.get_output_writer("netcdf-")
    ow_nc_1, ow_nc_2, ow_nc_3 = ow_nc_all
    assert ow_fib_1 and ow_fib_1.name == "fibonnaci-1"
    assert ow_fib_2 and ow_fib_2.name == "fibonnaci-2"
    assert ow_fib_3 and ow_fib_3.name == "fibonnaci-3"
    assert ow_nc_1 and ow_nc_1.name == "netcdf-1"
    assert ow_nc_2 and ow_nc_2.name == "netcdf-2"
    assert ow_nc_3 and ow_nc_3.name == "netcdf-3"

    out_fib_1 = model.get_output(writer=ow_fib_1)
    out_fib_2 = model.get_output(writer="fibonnaci-2")
    out_fib_3 = model.get_output(writer=["fibonnaci-3"])
    out_nc_1 = model.get_output(writer=ow_nc_1)
    out_nc_2 = model.get_output(writer=ow_nc_2)
    out_nc_3 = model.get_output(writer=ow_nc_3)
    out_nc_2_and_3 = model.get_output(writer=["netcdf-2", "netcdf-3"])
    out_nc_all = model.get_output(writer=ow_nc_all)
    assert (out_nc_1 + out_nc_2 + out_nc_3) == out_nc_all
    assert (out_nc_1 + out_nc_2_and_3) == out_nc_all
    assert model.get_output(extension="txt", writer=ow_nc_all) == []
    all_exist(out_fib_1 + out_fib_2 + out_fib_3)
    all_exist(out_nc_1 + out_nc_2 + out_nc_3)

    # Attempt to delete a file type that the writer never made
    model.remove_output(extension=".pdf", writer=None)
    model.remove_output(extension="pdf", writer=None)
    model.remove_output(extension="pdf", writer=ow_fib_1)
    model.remove_output(extension="pdf", writer=[ow_fib_1])
    all_exist(out_fib_1 + out_fib_2 + out_fib_3)
    all_exist(out_nc_1 + out_nc_2 + out_nc_3)

    # Delete with variations of the writer arg
    model.remove_output(extension=".txt", writer=ow_fib_1)  # test the period
    all_exist(out_fib_2 + out_fib_3)
    all_deleted(out_fib_1)
    model.remove_output(extension="txt", writer=[ow_fib_2])
    all_exist(out_fib_3)
    all_deleted(out_fib_1 + out_fib_2)
    model.remove_output(extension="txt", writer=None)
    all_deleted(out_fib_1 + out_fib_2 + out_fib_3)
    all_exist(out_nc_1 + out_nc_2 + out_nc_3)

    # Delete with variations of the extension arg
    model.remove_output(extension="nc", writer=ow_nc_1)
    all_exist(out_nc_2 + out_nc_3)
    all_deleted(out_nc_1)
    model.remove_output(extension=["nc"], writer=ow_nc_2)
    all_exist(out_nc_3)
    all_deleted(out_nc_1 + out_nc_2)
    model.remove_output(extension=None, writer=ow_nc_3)
    all_deleted(out_nc_1 + out_nc_2 + out_nc_3)