def test_bad_field_location(): dict_like = { "grid": {"RasterModelGrid": [(4, 5)]}, "fields": {"at_bad_location": {"foo": "bar"}}, } with pytest.raises(ValueError): create_grid(dict_like)
def test_bad_field_function(): dict_like = { "grid": {"RasterModelGrid": [(4, 5)]}, "fields": {"at_node": {"new_field_name": {"not_a_function": ["bar", "spam"]}}}, } with pytest.raises(ValueError): create_grid(dict_like)
def test_two_boundary_condition_dicts(): dict_like = { "grid": {"RasterModelGrid": [(4, 3)]}, "boundary_conditions": [ { "set_closed_boundaries_at_grid_edges": [True, True, True, True], "not_a_function": [True, False], } ], } with pytest.raises(ValueError): create_grid(dict_like)
def test_esri_ascii_create(): filename = os.path.join(_TEST_DATA_DIR, "4_x_3_no_nodata_value.asc") dict_like = { "grid": { "RasterModelGrid": [(4, 3), {"xy_spacing": 10, "xy_of_lower_left": (1, 2)}] }, "fields": { "at_node": {"topographic__elevation": {"read_esri_ascii": [filename]}} }, } mg = create_grid(dict_like) x_of_node = np.array( [1.0, 11.0, 21.0, 1.0, 11.0, 21.0, 1.0, 11.0, 21.0, 1.0, 11.0, 21.0] ) y_of_node = np.array( [2.0, 2.0, 2.0, 12.0, 12.0, 12.0, 22.0, 22.0, 22.0, 32.0, 32.0, 32.0] ) status_at_node = np.array([1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1], dtype=np.uint8) topographic__elevation = np.array( [9.0, 10.0, 11.0, 6.0, 7.0, 8.0, 3.0, 4.0, 5.0, 0.0, 1.0, 2.0] ) assert_array_equal(mg.x_of_node, x_of_node) assert_array_equal(mg.y_of_node, y_of_node) assert_array_equal(status_at_node, mg.status_at_node) assert_array_equal(topographic__elevation, mg.at_node["topographic__elevation"])
def test_read_netcdf_create(): filename = os.path.join(_TEST_DATA_DIR, "test-netcdf4.nc") dict_like = { "grid": { "RasterModelGrid": [(4, 3)] }, "fields": { "at_node": { "surface__elevation": { "read_netcdf": [filename] } } }, } mg = create_grid(dict_like) x_of_node = np.array([0., 1., 2., 0., 1., 2., 0., 1., 2., 0., 1., 2.]) y_of_node = np.array([0., 0., 0., 1., 1., 1., 2., 2., 2., 3., 3., 3.]) status_at_node = np.array([1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1], dtype=np.uint8) surface__elevation = np.array( [0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.]) assert_array_equal(mg.x_of_node, x_of_node) assert_array_equal(mg.y_of_node, y_of_node) assert_array_equal(status_at_node, mg.status_at_node) assert_array_equal(surface__elevation, mg.at_node["surface__elevation"])
def test_simple_create(tmpdir): """Load parameters from YAML-formatted file.""" with tmpdir.as_cwd(): with open("params.yaml", "w") as fp: fp.write(SIMPLE_PARAMS_STR) mg = create_grid("./params.yaml") assert mg.number_of_nodes == 20 assert "topographic__elevation" in mg.at_node x_of_node = np.array( [ 0., 3., 6., 9., 12., 0., 3., 6., 9., 12., 0., 3., 6., 9., 12., 0., 3., 6., 9., 12., ] ) status_at_node = np.array( [4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4], dtype=np.uint8 ) topographic__elevation = np.array( [ [-2., 4., 10., 16., 22.], [2., 8., 14., 20., 26.], [6., 12., 18., 24., 30.], [10., 16., 22., 28., 34.], ] ) assert_array_equal(mg.x_of_node, x_of_node) assert_array_equal(status_at_node, mg.status_at_node) assert_array_equal( topographic__elevation, np.round(mg.at_node["topographic__elevation"].reshape(mg.shape), decimals=2), )
def test_simple_create(tmpdir): """Load parameters from YAML-formatted file.""" with tmpdir.as_cwd(): with open("params.yaml", "w") as fp: fp.write(SIMPLE_PARAMS_STR) mg = create_grid("./params.yaml") assert mg.number_of_nodes == 20 assert "topographic__elevation" in mg.at_node x_of_node = np.array( [ 0.0, 3.0, 6.0, 9.0, 12.0, 0.0, 3.0, 6.0, 9.0, 12.0, 0.0, 3.0, 6.0, 9.0, 12.0, 0.0, 3.0, 6.0, 9.0, 12.0, ] ) status_at_node = np.array( [4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4], dtype=np.uint8 ) topographic__elevation = np.array( [ [-2.0, 4.0, 10.0, 16.0, 22.0], [2.0, 8.0, 14.0, 20.0, 26.0], [6.0, 12.0, 18.0, 24.0, 30.0], [10.0, 16.0, 22.0, 28.0, 34.0], ] ) assert_array_equal(mg.x_of_node, x_of_node) assert_array_equal(status_at_node, mg.status_at_node) assert_array_equal( topographic__elevation, np.round(mg.at_node["topographic__elevation"].reshape(mg.shape), decimals=2), )
def test_read_netcdf_create(): filename = os.path.join(_TEST_DATA_DIR, "test-netcdf4.nc") dict_like = { "grid": {"RasterModelGrid": [(4, 3)]}, "fields": {"at_node": {"surface__elevation": {"read_netcdf": [filename]}}}, } mg = create_grid(dict_like) x_of_node = np.array([0., 1., 2., 0., 1., 2., 0., 1., 2., 0., 1., 2.]) y_of_node = np.array([0., 0., 0., 1., 1., 1., 2., 2., 2., 3., 3., 3.]) status_at_node = np.array([1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1], dtype=np.uint8) surface__elevation = np.array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.]) assert_array_equal(mg.x_of_node, x_of_node) assert_array_equal(mg.y_of_node, y_of_node) assert_array_equal(status_at_node, mg.status_at_node) assert_array_equal(surface__elevation, mg.at_node["surface__elevation"])
def test_esri_ascii_create(): filename = os.path.join(_TEST_DATA_DIR, "4_x_3_no_nodata_value.asc") dict_like = { "grid": { "RasterModelGrid": [(4, 3), {"xy_spacing": 10, "xy_of_lower_left": (1, 2)}] }, "fields": { "at_node": {"topographic__elevation": {"read_esri_ascii": [filename]}} }, } mg = create_grid(dict_like) x_of_node = np.array([1., 11., 21., 1., 11., 21., 1., 11., 21., 1., 11., 21.]) y_of_node = np.array([2., 2., 2., 12., 12., 12., 22., 22., 22., 32., 32., 32.]) status_at_node = np.array([1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1], dtype=np.uint8) topographic__elevation = np.array( [9., 10., 11., 6., 7., 8., 3., 4., 5., 0., 1., 2.] ) assert_array_equal(mg.x_of_node, x_of_node) assert_array_equal(mg.y_of_node, y_of_node) assert_array_equal(status_at_node, mg.status_at_node) assert_array_equal(topographic__elevation, mg.at_node["topographic__elevation"])
def from_dict(cls, params): """Create an umami ``Residual`` from a dictionary. Parameters ---------- params : dict or OrderedDict This dict must contain a key *grid*, the values of which will be passed to the `Landlab` function ``create_grid`` to create the model grid. It will be convereted to an OrderedDict before residuals are added so as to preserve residual order. Examples -------- >>> import numpy as np >>> from io import StringIO >>> from umami import Residual >>> np.random.seed(42) >>> params = { ... "model": { ... "RasterModelGrid": [ ... [10, 10], ... { ... "fields": { ... "node": { ... "topographic__elevation": { ... "plane": [ ... {"point": [0, 0, 0]}, ... {"normal": [-1, -1, 1]}, ... ] ... } ... } ... } ... }, ... ] ... }, ... "data": { ... "RasterModelGrid": [ ... [10, 10], ... { ... "fields": { ... "node": { ... "topographic__elevation": { ... "plane": [ ... {"point": [0, 0, 0]}, ... {"normal": [-1, -1, 1]}, ... ], ... "random" : [ ... {"where": "CORE_NODE"}, ... {"distribution": "standard_normal"}, ... ] ... } ... } ... } ... }, ... ] ... }, ... "residuals": { ... "me": { ... "_func": "aggregate", ... "method": "mean", ... "field": "topographic__elevation", ... }, ... "ep10": { ... "_func": "aggregate", ... "method": "percentile", ... "field": "topographic__elevation", ... "q": 10, ... }, ... "oid1_mean": { ... "_func": "watershed_aggregation", ... "field": "topographic__elevation", ... "method": "mean", ... "outlet_id": 1, ... }, ... "sn1": { ... "_func": "count_equal", ... "field": "drainage_area", ... "value": 1, ... }, ... }, ... } >>> residual = Residual.from_dict(params) >>> residual.names ['me', 'ep10', 'oid1_mean', 'sn1'] >>> residual.calculate() >>> np.testing.assert_array_almost_equal( ... residual.value("me"), ... 0.158, ... decimal=3) >>> np.testing.assert_array_almost_equal( ... residual.values, ... np.array([ 0.158, 0.67 , 4.138, -20. ]), ... decimal=3) """ model = create_grid(params.pop("model")) data = create_grid(params.pop("data")) return cls(model, data, **params)
def from_dict(cls, params, output_writers=None): """Construct a terrainbento model from an input parameter dictionary. The input parameter dictionary portion associated with the "grid" keword will be passed directly to the Landlab `create_grid <https://landlab.readthedocs.io/en/master/reference/grid/create.html#landlab.grid.create.create_grid>`_. function. Parameters ---------- params : dict Dictionary of input parameters. output_writers : dictionary of output writers. Classes or functions used to write incremental output (e.g. make a diagnostic plot). There are two formats for the dictionary entries: 1) Items can have a key of "class" or "function" and a value of a list of simple output classes (uninstantiated) or functions, respectively. All output writers defined this way will use the `output_interval` provided to the ErosionModel constructor. 2) Items can have a key with any unique string representing the output writer's name and a value containing a dict with the uninstantiated class and arguments. The value follows the format: .. code-block:: python { 'class' : MyWriter, 'args' : [], # optional 'kwargs' : {}, # optional } where `args` and `kwargs` are passed to the constructor for `MyWriter`. `MyWriter` must be a child class of GenericOutputWriter. The two formats can be present simultaneously. See the Jupyter notebook examples for more details. Examples -------- >>> params = { ... "grid": { ... "RasterModelGrid": [ ... (4, 5), ... { ... "fields": { ... "node": { ... "topographic__elevation": { ... "constant": [{"value": 0.0}] ... } ... } ... } ... }, ... ] ... }, ... "clock": {"step": 1, "stop": 200}, ... } >>> model = ErosionModel.from_dict(params) >>> model.clock.step 1.0 >>> model.clock.stop 200.0 >>> model.grid.shape (4, 5) """ cls._validate(params) # grid, clock grid = create_grid(params.pop("grid")) clock = Clock.from_dict(params.pop("clock")) # precipitator precip_params = params.pop("precipitator", _DEFAULT_PRECIPITATOR) precipitator = _setup_precipitator_or_runoff(grid, precip_params, _SUPPORTED_PRECIPITATORS) # runoff_generator runoff_params = params.pop("runoff_generator", _DEFAULT_RUNOFF_GENERATOR) runoff_generator = _setup_precipitator_or_runoff( grid, runoff_params, _SUPPORTED_RUNOFF_GENERATORS) # boundary_handlers boundary_handlers = params.pop("boundary_handlers", {}) bh_dict = {} for name in boundary_handlers: bh_params = boundary_handlers[name] bh_dict[name] = _setup_boundary_handlers(grid, name, bh_params) # create instance return cls( clock, grid, precipitator=precipitator, runoff_generator=runoff_generator, boundary_handlers=bh_dict, output_writers=output_writers, **params, )
def from_dict(cls, params, output_writers=None): """Construct a terrainbento model from an input parameter dictionary. The input parameter dictionary portion associated with the "grid" keword will be passed directly to the Landlab `create_grid <https://landlab.readthedocs.io/en/latest/landlab.grid.create.html>`_. function. Parameters ---------- params : dict Dictionary of input parameters. output_writers : dictionary of output writers. Classes or functions used to write incremental output (e.g. make a diagnostic plot). These should be passed in a dictionary with two keys: "class" and "function". The value associated with each of these should be a list containing the uninstantiated output writers. See the Jupyter notebook examples for more details. Examples -------- >>> params = { ... "grid": { ... "RasterModelGrid": [ ... (4, 5), ... { ... "fields": { ... "node": { ... "topographic__elevation": { ... "constant": [{"value": 0}] ... } ... } ... } ... }, ... ] ... }, ... "clock": {"step": 1, "stop": 200}, ... } >>> model = ErosionModel.from_dict(params) >>> model.clock.step 1.0 >>> model.clock.stop 200.0 >>> model.grid.shape (4, 5) """ cls._validate(params) # grid, clock grid = create_grid(params.pop("grid")) clock = Clock.from_dict(params.pop("clock")) # precipitator precip_params = params.pop("precipitator", _DEFAULT_PRECIPITATOR) precipitator = _setup_precipitator_or_runoff(grid, precip_params, _SUPPORTED_PRECIPITATORS) # runoff_generator runoff_params = params.pop("runoff_generator", _DEFAULT_RUNOFF_GENERATOR) runoff_generator = _setup_precipitator_or_runoff( grid, runoff_params, _SUPPORTED_RUNOFF_GENERATORS) # boundary_handlers boundary_handlers = params.pop("boundary_handlers", {}) bh_dict = {} for name in boundary_handlers: bh_params = boundary_handlers[name] bh_dict[name] = _setup_boundary_handlers(grid, name, bh_params) # create instance return cls(clock, grid, precipitator=precipitator, runoff_generator=runoff_generator, boundary_handlers=bh_dict, output_writers=output_writers, **params)
def test_two_grid_types(): dict_like = {"grid": {"RasterModelGrid": [(4, 5)], "HexModelGrid": [6, 7]}} with pytest.raises(ValueError): create_grid(dict_like)
def test_bad_grid_name(): dict_like = {"grid": "MagicModelGrid"} with pytest.raises(ValueError): create_grid(dict_like)
def test_no_grid_value(): dict_like = {"foo": "bar"} with pytest.raises(ValueError): create_grid(dict_like)
def test_bad_boundary_condition_functions(): filename = os.path.join(_TEST_DATA_DIR, "bad_boundary.yaml") with pytest.raises(ValueError): create_grid(filename)
def from_dict(cls, params): """Create an umami ``Metric`` from a dictionary. Parameters ---------- params : dict or OrderedDict This dict must contain a key *grid*, the values of which will be passed to the `Landlab` function ``create_grid`` to create the model grid. It will be convereted to an OrderedDict before metrics are added so as to preserve metric order. Examples -------- >>> from io import StringIO >>> from umami import Metric >>> params = { ... "grid": { ... "RasterModelGrid": [ ... [10, 10], ... { ... "fields": { ... "node": { ... "topographic__elevation": { ... "plane": [ ... {"point": [0, 0, 0]}, ... {"normal": [-1, -1, 1]}, ... ] ... } ... } ... } ... }, ... ] ... }, ... "metrics": { ... "me": { ... "_func": "aggregate", ... "method": "mean", ... "field": "topographic__elevation", ... }, ... "ep10": { ... "_func": "aggregate", ... "method": "percentile", ... "field": "topographic__elevation", ... "q": 10, ... }, ... "oid1_mean": { ... "_func": "watershed_aggregation", ... "field": "topographic__elevation", ... "method": "mean", ... "outlet_id": 1, ... }, ... "sn1": { ... "_func": "count_equal", ... "field": "drainage_area", ... "value": 1, ... }, ... }, ... } >>> metric = Metric.from_dict(params) >>> metric.names ['me', 'ep10', 'oid1_mean', 'sn1'] >>> metric.calculate() >>> metric.value('me') 9.0 >>> metric.values [9.0, 5.0, 5.0, 8] """ # create grid grid = create_grid(params.pop("grid")) return cls(grid, **params)