Example #1
0
def test_create_setup(model, in_dataset):
    expected = xr.Dataset()
    actual = create_setup(model=model)
    xr.testing.assert_identical(actual, expected)

    ds = create_setup(model=model,
                      input_vars={
                          'init_profile': {
                              'n_points': 5
                          },
                          ('roll', 'shift'): 1,
                          'add__offset': ('clock', [1, 2, 3, 4, 5])
                      },
                      clocks={
                          'clock': [0, 2, 4, 6, 8],
                          'out': [0, 4, 8],
                      },
                      master_clock='clock',
                      output_vars={
                          'clock': 'profile__u',
                          'out': [('roll', 'u_diff'), ('add', 'u_diff')],
                          None: {
                              'profile': 'u_opp'
                          }
                      })
    xr.testing.assert_identical(ds, in_dataset)
Example #2
0
def test_create_setup(model, in_dataset):
    expected = xr.Dataset()
    actual = create_setup(model=model, fill_default=False)
    xr.testing.assert_identical(actual, expected)

    expected = xr.Dataset({"roll__shift": 2})
    actual = create_setup(model=model, fill_default=True)
    xr.testing.assert_equal(actual, expected)

    ds = create_setup(
        model=model,
        input_vars={
            "init_profile": {
                "n_points": 5
            },
            ("roll", "shift"): 1,
            "add__offset": ("clock", [1, 2, 3, 4, 5]),
        },
        clocks={
            "clock": [0, 2, 4, 6, 8],
            "out": [0, 4, 8]
        },
        main_clock="clock",
        output_vars={
            "profile__u": "clock",
            ("roll", "u_diff"): "out",
            ("add", "u_diff"): "out",
            "profile": {
                "u_opp": None
            },
        },
    )
    xr.testing.assert_identical(ds, in_dataset)
Example #3
0
def test_runtime_hook_instance(model, given_as):
    flag = [False]

    @runtime_hook("run_step", "model", "pre")
    def test_hook(_model, context, state):
        flag[0] = True

    rd = RuntimeHook(test_hook)

    in_ds = xs.create_setup(model=model, clocks={"c": [0, 1]})

    if given_as == "argument":
        in_ds.xsimlab.run(model=model, hooks=[rd])

    elif given_as == "context":
        with rd:
            in_ds.xsimlab.run(model=model)

    elif given_as == "register":
        rd.register()
        in_ds.xsimlab.run(model=model)

    assert flag[0] is True

    if given_as == "register":
        flag[0] = False
        rd.unregister()
        in_ds.xsimlab.run(model=model)
        assert flag[0] is False
    def test_write_global_vars(self):
        # ensure that variable metadata (dims, etc.) is properly accessed for global references

        @xs.process
        class Foo:
            var = xs.variable(dims="x", global_name="global_var", intent="out")

        @xs.process
        class Bar:
            var = xs.global_ref("global_var")

        model = xs.Model({"foo": Foo, "bar": Bar})

        in_ds = xs.create_setup(
            model=model,
            clocks={"clock": [0, 1]},
            output_vars={"bar__var": None},
        )

        store = ZarrSimulationStore(in_ds, model)

        model.state[("foo", "var")] = np.array([1, 2, 3])
        store.write_output_vars(-1, -1)

        ztest = zarr.open_group(store.zgroup.store, mode="r")
        np.testing.assert_array_equal(ztest.bar__var, np.array([1, 2, 3]))
    def test_encoding(self):
        @xs.process
        class P:
            v1 = xs.variable(dims="x",
                             intent="out",
                             encoding={"dtype": np.int32})
            v2 = xs.on_demand(dims="x", encoding={"fill_value": 0})
            v3 = xs.index(dims="x")
            v4 = xs.variable(
                dims="x",
                intent="out",
                encoding={
                    "dtype": object,
                    "object_codec": zarr.codecs.Pickle()
                },
            )

            @v2.compute
            def _get_v2(self):
                return [0]

        model = xs.Model({"p": P})

        in_ds = xs.create_setup(
            model=model,
            clocks={"clock": [0]},
            output_vars={
                "p__v1": None,
                "p__v2": None,
                "p__v3": None,
                "p__v4": None
            },
        )

        store = ZarrSimulationStore(
            in_ds,
            model,
            encoding={
                "p__v2": {
                    "fill_value": -1
                },
                "p__v3": {
                    "chunks": (10, )
                }
            },
        )

        model.state[("p", "v1")] = [0]
        model.state[("p", "v3")] = [0]
        model.state[("p", "v4")] = [{"foo": "bar"}]
        store.write_output_vars(-1, -1)

        ztest = zarr.open_group(store.zgroup.store, mode="r")

        assert ztest.p__v1.dtype == np.int32
        # test encoding precedence ZarrSimulationStore > model variable
        assert ztest.p__v2.fill_value == -1
        assert ztest.p__v3.chunks == (10, )
        assert ztest.p__v4[0] == {"foo": "bar"}
Example #6
0
    def test_output_vars_by_clock(self, model):
        o_vars = {("roll", "u_diff"): "clock", ("add", "u_diff"): None}

        ds = xs.create_setup(
            model=model,
            clocks={"clock": [0, 2, 4, 6, 8]},
            output_vars=o_vars,
        )

        expected = {"clock": [("roll", "u_diff")], None: [("add", "u_diff")]}

        assert ds.xsimlab.output_vars_by_clock == expected
Example #7
0
def test_runtime_hook_subclass(model):
    flag = [False]

    class TestHook(RuntimeHook):
        @runtime_hook("run_step", "model", "pre")
        def test_hook(self, _model, context, state):
            flag[0] = True

    in_ds = xs.create_setup(model=model, clocks={"c": [0, 1]})

    with TestHook():
        in_ds.xsimlab.run(model=model)

    assert flag[0] is True
Example #8
0
def test_create_setup_masterclock_warning(model, in_dataset):
    expected = xr.Dataset()
    actual = create_setup(model=model, fill_default=False)
    xr.testing.assert_identical(actual, expected)

    expected = xr.Dataset({"roll__shift": 2})
    actual = create_setup(model=model, fill_default=True)
    xr.testing.assert_equal(actual, expected)

    with pytest.warns(
            FutureWarning,
            match="master_clock is to be deprecated in favour of main_clock"):
        ds = create_setup(
            model=model,
            input_vars={
                "init_profile": {
                    "n_points": 5
                },
                ("roll", "shift"): 1,
                "add__offset": ("clock", [1, 2, 3, 4, 5]),
            },
            clocks={
                "clock": [0, 2, 4, 6, 8],
                "out": [0, 4, 8]
            },
            master_clock="clock",
            output_vars={
                "profile__u": "clock",
                ("roll", "u_diff"): "out",
                ("add", "u_diff"): "out",
                "profile": {
                    "u_opp": None
                },
            },
        )

    xr.testing.assert_identical(ds, in_dataset)
Example #9
0
def test_runtime_hook_call_frozen(model):
    in_ds = xs.create_setup(model=model, clocks={"c": [0, 1]})

    @runtime_hook("run_step", "model", "pre")
    def change_context(model, context, state):
        context["step"] = 0

    with pytest.raises(TypeError, match=".*not support item assignment"):
        in_ds.xsimlab.run(model=model, hooks=[change_context])

    @runtime_hook("run_step", "model", "pre")
    def change_state(model, context, state):
        state[("p", "u")] = 0

    with pytest.raises(TypeError, match=".*not support item assignment"):
        in_ds.xsimlab.run(model=model, hooks=[change_state])
Example #10
0
def test_runtime_hook_calls(model, event, expected_ncalls, expected_u):
    inc = [0]

    @runtime_hook(*event)
    def test_hook(_model, context, state):
        inc[0] += 1

        assert "step" in context
        assert _model is model

        # TODO: get name of current process executed in context?
        if expected_u is not None:
            assert state[("p", "u")] == expected_u

    in_ds = xs.create_setup(model=model, clocks={"c": [0, 1]})
    # safe mode disabled so that we can assert _model is model above
    in_ds.xsimlab.run(model=model, hooks=[test_hook], safe_mode=False)

    assert inc[0] == expected_ncalls
Example #11
0
    def test_run_decoding(self, decoding, expected):
        @xs.process
        class P:
            var = xs.variable(dims="x",
                              intent="out",
                              encoding={"fill_value": -1})

            def initialize(self):
                self.var = [-1, -1]

        m = xs.Model({"p": P})

        in_ds = xs.create_setup(
            model=m,
            clocks={"clock": [0, 1]},
            output_vars={"p__var": None},
        )

        out_ds = in_ds.xsimlab.run(model=m, decoding=decoding)

        np.testing.assert_array_equal(out_ds.p__var, expected)
Example #12
0
    def test_output_vars(self, model):
        o_vars = {
            ("profile", "u_opp"): None,
            ("profile", "u"): "clock",
            ("roll", "u_diff"): "out",
            ("add", "u_diff"): "out",
        }

        ds = xs.create_setup(
            model=model,
            clocks={
                "clock": [0, 2, 4, 6, 8],
                "out": [0, 4, 8],
                # snapshot clock with no output variable
                "out2": [0, 8],
            },
            main_clock="clock",
            output_vars=o_vars,
        )

        assert ds.xsimlab.output_vars == o_vars
Example #13
0
    def test_run_check_dims(self):
        @xs.process
        class P:
            var = xs.variable(dims=["x", ("x", "y")])

        m = xs.Model({"p": P})

        arr = np.array([[1, 2], [3, 4]])

        in_ds = xs.create_setup(
            model=m,
            clocks={"clock": [1, 2]},
            input_vars={"p__var": (("y", "x"), arr)},
            output_vars={"p__var": None},
        )

        out_ds = in_ds.xsimlab.run(model=m, check_dims=None)
        actual = out_ds.p__var.values
        np.testing.assert_array_equal(actual, arr)

        with pytest.raises(ValueError, match=r"Invalid dimension.*"):
            in_ds.xsimlab.run(model=m, check_dims="strict")

        out_ds = in_ds.xsimlab.run(model=m,
                                   check_dims="transpose",
                                   safe_mode=False)
        actual = out_ds.p__var.values
        np.testing.assert_array_equal(actual, arr)
        np.testing.assert_array_equal(m.p.var, arr.transpose())

        in_ds2 = in_ds.xsimlab.update_vars(model=m,
                                           output_vars={"p__var": "clock"})
        # TODO: fix update output vars time-independet -> dependent
        # currently need the workaround below
        in_ds2.attrs = {}

        out_ds = in_ds2.xsimlab.run(model=m, check_dims="transpose")
        actual = out_ds.p__var.isel(clock=-1).values
        np.testing.assert_array_equal(actual, arr)
    def test_fill_values(self):
        @xs.process
        class Foo:
            v_int64 = xs.variable(dims="x", intent="out")
            v_float64 = xs.variable(dims="x", intent="out")
            v_uint8 = xs.variable(dims="x",
                                  intent="out",
                                  encoding={"dtype": np.uint8})
            v_string = xs.variable(dims="x", intent="out")
            v_bool = xs.variable(dims="x", intent="out")

            def initialize(self):
                self.v_int64 = [0, np.iinfo("int64").max]
                self.v_float64 = [0.0, np.nan]
                self.v_uint8 = [0, 255]
                self.v_string = ["hello", ""]
                self.v_bool = [True, False]

        model = xs.Model({"foo": Foo})
        in_ds = xs.create_setup(
            model=model,
            clocks={"clock": [0, 1]},
            output_vars={
                "foo__v_int64": None,
                "foo__v_float64": None,
                "foo__v_uint8": None,
                "foo__v_string": None,
                "foo__v_bool": None,
            },
        )
        out_ds = in_ds.xsimlab.run(model=model)
        np.testing.assert_equal(out_ds["foo__v_int64"].data, [0, np.nan])
        np.testing.assert_equal(out_ds["foo__v_float64"].data, [0.0, np.nan])
        np.testing.assert_equal(out_ds["foo__v_uint8"].data, [0, np.nan])
        # np.testing.assert_equal does not work for "object" dtypes, so test each value explicitly:
        assert out_ds["foo__v_string"].data[0] == "hello"
        assert np.isnan(out_ds["foo__v_string"].data[1])
        assert out_ds["foo__v_bool"].data[0] == True
        assert np.isnan(out_ds["foo__v_bool"].data[1])
def test_finalize_always_called():
    @xs.process
    class P:
        var = xs.variable(intent="out")

        def initialize(self):
            self.var = "initialized"
            raise RuntimeError()

        def finalize(self):
            self.var = "finalized"

    model = xs.Model({"p": P})
    in_dataset = xs.create_setup(model=model, clocks={"clock": [0, 1]})
    driver = XarraySimulationDriver(in_dataset, model)

    try:
        driver.run_model()
    except RuntimeError:
        pass

    assert model.state[("p", "var")] == "finalized"
Example #16
0
    def test_run_batch_dim(self, dims, data, clock, parallel, scheduler):
        @xs.process
        class P:
            in_var = xs.variable(dims=[(), "x"])
            out_var = xs.variable(dims=[(), "x"], intent="out")
            idx_var = xs.index(dims="x")

            def initialize(self):
                self.idx_var = [0, 1]

            def run_step(self):
                self.out_var = self.in_var * 2

        m = xs.Model({"p": P})

        in_ds = xs.create_setup(
            model=m,
            clocks={"clock": [0, 1, 2]},
            input_vars={"p__in_var": (dims, data)},
            output_vars={"p__out_var": clock},
        )

        out_ds = in_ds.xsimlab.run(
            model=m,
            batch_dim="batch",
            parallel=parallel,
            scheduler=scheduler,
            store=zarr.TempStore(),
        )

        if clock is None:
            coords = {}
        else:
            coords = {"clock": in_ds["clock"]}

        expected = xr.DataArray(data, dims=dims, coords=coords) * 2
        xr.testing.assert_equal(out_ds["p__out_var"], expected)
Example #17
0
def test_signal_model_level(trigger, signal, expected):
    @xs.process
    class Foo:
        v = xs.variable(intent="out")
        vv = xs.variable(intent="out")

        def initialize(self):
            self.v = 0.0
            self.vv = 10.0

        def run_step(self):
            self.v += 1.0

        def finalize_step(self):
            self.v += 1.0

    @xs.runtime_hook("run_step", level="model", trigger=trigger)
    def hook_func(model, context, state):
        if context["step"] == 1:
            return signal

    model = xs.Model({"foo": Foo})
    ds_in = xs.create_setup(
        model=model,
        clocks={"clock": range(4)},
        output_vars={
            "foo__v": "clock",
            "foo__vv": None
        },
    )
    ds_out = ds_in.xsimlab.run(model=model, hooks=[hook_func])

    np.testing.assert_equal(ds_out.foo__v.values, expected)

    # ensure that clock-independent output variables are properly
    # saved even when the simulation stops early
    assert ds_out.foo__vv == 10.0
    def test_resize_zarr_dataset(self):
        @xs.process
        class P:
            arr = xs.variable(dims="x", intent="out")

        model = xs.Model({"p": P})

        in_ds = xs.create_setup(
            model=model,
            clocks={"clock": [0, 1, 2]},
            output_vars={"p__arr": "clock"},
        )

        store = ZarrSimulationStore(in_ds, model)

        for step, size in zip([0, 1, 2], [1, 3, 2]):
            model.state[("p", "arr")] = np.ones(size)
            store.write_output_vars(-1, step)

        ztest = zarr.open_group(store.zgroup.store, mode="r")

        expected = np.array([[1.0, np.nan, np.nan], [1.0, 1.0, 1.0],
                             [1.0, 1.0, np.nan]])
        np.testing.assert_array_equal(ztest.p__arr, expected)
in_ds = xsimlab.create_setup(
    model=custom_model,
    clocks={
        'time': time,
        'out': time,
    },
    master_clock='time',
    input_vars={
        'grid__shape': ('shape_yx', [ny, nx]),
        'grid__length': ('shape_yx', [lenghty, lenghtx]),
        'boundary__status':
        ('border',
         ['fixed_value', 'fixed_value', 'fixed_value', 'fixed_value']),
        'uplift_func': {
            'uplift_rate': ('time', U),
            'coeff': 1,
            'axis': 2
        },
        'square_basement': {
            'x_origin_position': 80,
            'y_origin_position': 45,
            'x_lenght': 100,
            'y_lenght': 20,
            'basement_k_coef': ('time', K_basement),
            'rock_k_coef': 2e-6,
            'basement_diff': 0.1,
            'rock_diff': 0.1
        },
        #        'circle_basement': {
        #                'x_origin_position': 100,
        #                'y_origin_position': 60,
        #                'radius': 25,
        #                'basement_k_coef': ('time', K_basement),
        #                'rock_k_coef': 2e-6,
        #                'basement_diff': 0.1,
        #                'rock_diff': 0.1
        #        },
        'spl': {
            'area_exp': 0.6,
            'slope_exp': 1.5
        },
    },
    output_vars={
        'out': [
            'topography__elevation', 'drainage__area', 'flow__basin',
            'terrain__slope', 'spl__erosion'
        ],
        None: ['boundary__border', 'grid__x', 'grid__y', 'grid__spacing'],
    })
def test_main_clock_access():
    @xs.process
    class Foo:
        a = xs.variable(intent="out", dims=xs.MAIN_CLOCK)
        b = xs.variable(intent="out", dims=xs.MAIN_CLOCK)

        @xs.runtime(args=["main_clock_values", "main_clock_dataarray"])
        def initialize(self, clock_values, clock_array):
            self.a = clock_values * 2
            np.testing.assert_equal(self.a, [0, 2, 4, 6])
            self.b = clock_array * 2
            assert clock_array.dims[0] == "clock"
            assert all(clock_array[clock_array.dims[0]].data == [0, 1, 2, 3])

        @xs.runtime(args=["step_delta", "step"])
        def run_step(self, dt, n):
            assert self.a[n] == 2 * n
            self.a[n] += 1

    model = xs.Model({"foo": Foo})
    ds_in = xs.create_setup(
        model=model,
        clocks={"clock": range(4)},
        input_vars={},
        output_vars={"foo__a": None},
    )
    ds_out = ds_in.xsimlab.run(model=model)
    assert all(ds_out.foo__a.data == [1, 3, 5, 6])

    # test for error when another dim has the same name as xs.MAIN_CLOCK
    @xs.process
    class DoubleMainClockDim:
        a = xs.variable(intent="out", dims=("clock", xs.MAIN_CLOCK))

        def initialize(self):
            self.a = [[1, 2, 3], [3, 4, 5]]

        def run_step(self):
            self.a += self.a

    model = xs.Model({"foo": DoubleMainClockDim})
    with pytest.raises(ValueError, match=r"Main clock:*"):
        xs.create_setup(
            model=model,
            clocks={
                "clock": [0, 1, 2, 3]
            },
            input_vars={},
            output_vars={
                "foo__a": None
            },
        ).xsimlab.run(model)

    # test for error when trying to put xs.MAIN_CLOCK as a dim in an input var
    with pytest.raises(
            ValueError,
            match="Do not pass xs.MAIN_CLOCK into input vars dimensions"):
        a = xs.variable(intent="in", dims=xs.MAIN_CLOCK)

    with pytest.raises(
            ValueError,
            match="Do not pass xs.MAIN_CLOCK into input vars dimensions"):
        b = xs.variable(intent="in", dims=(xs.MAIN_CLOCK, ))
    with pytest.raises(
            ValueError,
            match="Do not pass xs.MAIN_CLOCK into input vars dimensions"):
        c = xs.variable(intent="in", dims=["a", ("a", xs.MAIN_CLOCK)])
Example #21
0
def test_hook_arg_type(model):
    in_ds = xs.create_setup(model=model, clocks={"c": [0, 1]})

    with pytest.raises(TypeError, match=".*not a RuntimeHook.*"):
        in_ds.xsimlab.run(model=model, hooks=[1])
Example #22
0
def run_fastscape(k_sp,
                  k_diff,
                  u_rate,
                  x_size=601,
                  y_size=401,
                  spacing=200.,
                  time_step=1e5,
                  time_total=1e7):
    """
    Run "Fastscape" landscape evolution model.

    This version of Fastscape includes the following processes:

    - uniform, block uplift at a constant rate through time ;
    - bedrock channel erosion using the stream power law ;
    - hillslope erosion using linear diffusion.

    The total simulation time is 10 Myr.

    The simulation start with a random, nearly flat topography.
    Topographic elevation remains fixed at the domain boundary.

    Parameters
    ----------
    k_sp : float
        Stream power law coefficient. The drainage area and slope
        exponents of the stream power law are fixed to 0.4 and 1,
        respectively.
    k_diff : float
        Hillslope diffusivity (units: m**2/yr).
    u_rate : float
        Uplift rate (units: m/yr).

    Other parameters
    ----------------
    x_size : int, optional
        Grid size in x (i.e., number of columns).
    y_size : int, optional
        Grid size in y (i.e., number of rows).
    spacing : float, optional
        Uniform grid spacing in x and y (units: m).
    time_step : float, optional
        Simulation time step (units: yr).
    time_total : float, optional
        Total simulation duration (units: yr).

    Returns
    -------
    elevation : numpy.ndarray
        Topographic elevation at the end of the simulation (units: m).
        Array shape is (`y_size`, `x_size`).

    """
    in_ds = xsimlab.create_setup(
        model=fastscape_base_model,
        clocks={'time': {
            'end': time_total,
            'step': time_step
        }},
        input_vars={
            'grid': {
                'x_size': x_size,
                'y_size': y_size,
                'x_spacing': spacing,
                'y_spacing': spacing
            },
            'flow_routing': {
                'pit_method': 'mst_linear'
            },
            'block_uplift': {
                'u_coef': u_rate
            },
            'spower': {
                'k_coef': k_sp,
                'm_exp': 0.4,
                'n_exp': 1
            },
            'diffusion': {
                'k_coef': k_diff
            },
            'topography': {
                'elevation': (('y', 'x'), np.random.rand(y_size, x_size))
            }
        },
        snapshot_vars={
            None: {
                'grid': ('x', 'y'),
                'topography': 'elevation'
            },
        })

    out_ds = (in_ds.xsimlab.run(model=fastscape_base_model).set_index(
        y='grid__y', x='grid__x'))

    return out_ds.topography__elevation.values