Example #1
0
def test_generic_bch(clock_simple, simple_square_grid):
    gfblh = GenericFuncBaselevelHandler(
        simple_square_grid,
        modify_core_nodes=True,
        function=lambda grid, t: -(grid.x_of_node + grid.y_of_node + (0 * t)),
    )
    params = {
        "grid": simple_square_grid,
        "clock": clock_simple,
        "boundary_handlers": {
            "mynew_bh": gfblh
        },
    }

    model = Basic(**params)
    bh = model.boundary_handlers["mynew_bh"]

    # assertion tests
    assert "mynew_bh" in model.boundary_handlers
    assert_array_equal(np.where(bh.nodes_to_lower)[0], model.grid.core_nodes)

    step = 10.0
    model.run_one_step(step)

    dzdt = -(model.grid.x_of_node + model.grid.y_of_node)
    truth_z = -1.0 * dzdt * step
    assert_array_equal(model.z[model.grid.core_nodes],
                       truth_z[model.grid.core_nodes])
Example #2
0
def test_pass_two_boundary_handlers(clock_simple, simple_square_grid, U):
    ncnblh = NotCoreNodeBaselevelHandler(simple_square_grid,
                                         modify_core_nodes=True,
                                         lowering_rate=-U)
    snblh = SingleNodeBaselevelHandler(simple_square_grid,
                                       modify_outlet_node=False,
                                       lowering_rate=-U)
    params = {
        "grid": simple_square_grid,
        "clock": clock_simple,
        "boundary_handlers": {
            "mybh1": ncnblh,
            "mybh2": snblh
        },
    }
    model = Basic(**params)
    model.run_one_step(1.0)

    truth = np.zeros(model.z.size)
    truth[0] -= U
    truth[model.grid.core_nodes] += U
    assert_array_equal(model.z, truth)

    status_at_node = np.zeros(model.z.size)
    status_at_node[model.grid.boundary_nodes] = CLOSED_BOUNDARY
    status_at_node[0] = FIXED_VALUE_BOUNDARY
    assert_array_equal(model.grid.status_at_node, status_at_node)
Example #3
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()
Example #4
0
def test_capture_node(clock_simple, simple_square_grid):
    cnblh = CaptureNodeBaselevelHandler(
        simple_square_grid,
        capture_node=1,
        capture_incision_rate=-3.0,
        capture_start_time=10,
        capture_stop_time=20,
        post_capture_incision_rate=-0.1,
    )

    params = {
        "grid": simple_square_grid,
        "clock": clock_simple,
        "boundary_handlers": {
            "CaptureNodeBaselevelHandler": cnblh
        },
    }

    model = Basic(**params)
    # assertion tests
    assert "CaptureNodeBaselevelHandler" in model.boundary_handlers
    assert model.z[1] == 0
    model.run_one_step(10.0)
    assert model.z[1] == 0
    model.run_one_step(10)
    assert model.z[1] == -30.0
    model.run_one_step(10)
    assert model.z[1] == -31.0
Example #5
0
def test_write_synthesis_netcdf(tmpdir, basic_raster_inputs_for_nc_yaml):
    truth = os.path.join(_TEST_DATA_DIR, "truth.nc")
    with tmpdir.as_cwd():
        basic_raster_inputs_for_nc_yaml += "".join([
            "\n",
            "    output_prefix: tb_synth_output\n",
            f"    output_dir: {tmpdir}\n",
        ])
        with open("params.yaml", "w") as fp:
            fp.write(basic_raster_inputs_for_nc_yaml)
        model = Basic.from_file("./params.yaml")

        model.run()

        ds = model.to_xarray_dataset(time_unit="years", space_unit="meter")

        out_fn = "tb_output.nc"
        model.save_to_xarray_dataset(filename=out_fn,
                                     time_unit="years",
                                     space_unit="meter")

        output = xr.open_dataset(out_fn, decode_times=False)
        truth = xr.open_dataset(truth, decode_times=False)

        assert truth.dims == output.dims
        assert truth.dims == ds.dims

        assert truth.equals(output) is True
        assert truth.equals(ds) is True

        output.close()
        truth.close()
        ds.close()

        model.remove_output_netcdfs()
def test_write_synthesis_netcdf_one_field(tmpdir, basic_raster_inputs_yaml):
    with tmpdir.as_cwd():
        with open("params.yaml", "w") as fp:
            fp.write(basic_raster_inputs_yaml)
        model = Basic.from_file("./params.yaml")

        truth = os.path.join(_TEST_DATA_DIR, "truth_one_field.nc")

        model._out_file_name = "tb_synth_output_one_field"
        model.run()

        ds = model.to_xarray_dataset(time_unit="years", space_unit="meter")

        out_fn = "tb_output_one_field.nc"
        model.save_to_xarray_dataset(filename=out_fn,
                                     time_unit="years",
                                     space_unit="meter")

        output = xr.open_dataset(out_fn, decode_times=False)
        truth = xr.open_dataset(truth, decode_times=False)

        assert truth.dims == output.dims
        assert truth.dims == ds.dims

        assert truth.equals(output) is True
        assert truth.equals(ds) is True

        output.close()
        truth.close()
        ds.close()
Example #7
0
def test_run_for(tmpdir, basic_inputs_yaml):
    with tmpdir.as_cwd():
        with open("params.yaml", "w") as fp:
            fp.write(basic_inputs_yaml)
        model = Basic.from_file("./params.yaml")
    model._out_file_name = "run_for_output"
    model.run_for(10.0, 100.0)
    assert model.model_time == 100.0
Example #8
0
def test_run(tmpdir, basic_inputs_yaml):
    with tmpdir.as_cwd():
        with open("params.yaml", "w") as fp:
            fp.write(basic_inputs_yaml)
        model = Basic.from_file("./params.yaml")
    model._out_file_name = "run_output"
    model.run()
    assert model.model_time == 200.0
    model.remove_output_netcdfs()
def test_write_output_hex(tmpdir, basic_inputs_yaml):
    with tmpdir.as_cwd():
        with open("params.yaml", "w") as fp:
            fp.write(basic_inputs_yaml)
        model = Basic.from_file("./params.yaml")

        model._out_file_name = "tb_hex_output"
        model.run()
        fs = glob.glob(model._out_file_name + "*.nc")

        assert len(fs) == 5
Example #10
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")
def test_write_output_raster(tmpdir, basic_raster_inputs_yaml):
    with tmpdir.as_cwd():
        with open("params.yaml", "w") as fp:
            fp.write(basic_raster_inputs_yaml)
        model = Basic.from_file("./params.yaml")
        model._out_file_name = "tb_raster_output"
        model.run()
        fs = glob.glob(model._out_file_name + "*.nc")

        assert len(fs) == 5

        ds = xr.open_dataset(fs[0])
        ds.close()
Example #12
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()
Example #13
0
def test_single_node_blh_with_closed_boundaries(clock_simple,
                                                simple_square_grid):
    snblh = SingleNodeBaselevelHandler(
        simple_square_grid,
        modify_outlet_node=False,
        lowering_rate=-0.0005,
        outlet_id=3,
    )

    params = {
        "clock": clock_simple,
        "grid": simple_square_grid,
        "boundary_handlers": {
            "SingleNodeBaselevelHandler": snblh
        },
    }
    model = Basic(**params)
    assert model.grid.status_at_node[3] == FIXED_VALUE_BOUNDARY
Example #14
0
def test_write_output_hex(tmpdir, basic_inputs_yaml):
    with tmpdir.as_cwd():
        basic_inputs_yaml += "".join([
            "\n",
            "    output_prefix: tb_hex_output\n",
            f"    output_dir: {tmpdir}\n",
        ])
        with open("params.yaml", "w") as fp:
            fp.write(basic_inputs_yaml)
        model = Basic.from_file("./params.yaml")

        model.run()
        name_pattern = model.output_prefix + "*.nc"
        fs = glob.glob(os.path.join(model.output_dir, name_pattern))

        assert len(fs) == 5
        # ds = xr.open_dataset(fs[0])

        # todo assess hex output

        model.remove_output_netcdfs()
Example #15
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()
Example #16
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"))
Example #17
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()
Example #18
0
def test_finalize(tmpdir, basic_inputs_yaml):
    with tmpdir.as_cwd():
        with open("params.yaml", "w") as fp:
            fp.write(basic_inputs_yaml)
        model = Basic.from_file("./params.yaml")
    model.finalize()
Example #19
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)
Example #20
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()
Example #21
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()