def example_parcels(example_nmg): element_id = np.array( [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6], dtype=int, ) # current link for each parcel element_id = np.expand_dims(element_id, axis=1) starting_link = np.squeeze(element_id) # starting link for each parcel np.random.seed(0) time_arrival_in_link = np.random.rand( np.size(element_id), 1 ) # time of arrival in each link -- larger numbers are younger volume = np.ones(np.shape(element_id)) # (m3) the volume of each parcel D = 0.05 * np.ones( np.shape(element_id) ) # (m) the diameter of grains in each parcel abrasion_rate = 0.0001 * np.ones( np.size(element_id) ) # 0 = no abrasion; abrasion rates are positive mass loss coefficients (mass loss / METER) active_layer = np.ones( np.shape(element_id) ) # 1 = active/surface layer; 0 = subsurface layer density = 2650 * np.ones(np.size(element_id)) # (kg/m3) location_in_link = np.zeros( np.shape(element_id) ) # [0 1], 0 is upstream end of link, 1 is downstream end D[0] = 0.075 D[5] = 0.0001 # make one of them sand volume[2] = 0.3 time = [0.0] # probably not the sensible way to do this... items = {"grid_element": "link", "element_id": element_id} variables = { "starting_link": (["item_id"], starting_link), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], density), "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link), "active_layer": (["item_id", "time"], active_layer), "location_in_link": (["item_id", "time"], location_in_link), "D": (["item_id", "time"], D), "volume": (["item_id", "time"], volume), } parcels = DataRecord( example_nmg, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) return parcels
def test_grainsize_active_layer(example_nmg, example_parcels, example_flow_director): time = [0.0] # probably not the sensible way to do this... items = {"grid_element": "link", "element_id": np.array([[6], [6]])} initial_volume = np.array([[1], [1]]) abrasion_rate = np.array([0, 0]) variables = { "starting_link": (["item_id"], np.array([6, 6])), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], np.array([2650, 2650])), "time_arrival_in_link": (["item_id", "time"], np.array([[0.5], [0]])), "active_layer": (["item_id", "time"], np.array([[1], [1]])), "location_in_link": (["item_id", "time"], np.array([[0], [0]])), "D": (["item_id", "time"], np.array([[0.05], [0.05]])), "volume": (["item_id", "time"], initial_volume), } two_parcels = DataRecord( example_nmg, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) timesteps = 8 example_nmg.at_link["flow_depth"] = (example_nmg.at_link["flow_depth"] * 5 ) # high transport rate nst = NetworkSedimentTransporter( example_nmg, two_parcels, example_flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", active_layer_method="GrainSizeDependent", active_layer_d_multiplier=3, ) dt = 60 * 60 * 24 # (seconds) daily timestep for t in range(0, (timesteps * dt), dt): nst.run_one_step(dt) # Active layer thickness should be 3*d_mean active_layer_thickness_should_be = 3 * 0.05 assert_array_almost_equal(active_layer_thickness_should_be, nst._active_layer_thickness[0])
def test_abrasion(example_nmg, example_parcels, example_flow_director): time = [0.0] # probably not the sensible way to do this... items = {"grid_element": "link", "element_id": np.array([[6], [6]])} initial_volume = np.array([[1], [1]]) abrasion_rate = np.array([0.0001, 0]) variables = { "starting_link": (["item_id"], np.array([6, 6])), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], np.array([2650, 90000])), "time_arrival_in_link": (["item_id", "time"], np.array([[0.5], [0]])), "active_layer": (["item_id", "time"], np.array([[1], [1]])), "location_in_link": (["item_id", "time"], np.array([[0], [0]])), "D": (["item_id", "time"], np.array([[0.05], [0.05]])), "volume": (["item_id", "time"], initial_volume), } two_parcels = DataRecord( example_nmg, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) timesteps = 8 example_nmg.at_link["flow_depth"] = (example_nmg.at_link["flow_depth"] * 5 ) # high transport rate nst = NetworkSedimentTransporter( example_nmg, two_parcels, example_flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) dt = 60 * 60 * 24 # (seconds) daily timestep for t in range(0, (timesteps * dt), dt): nst.run_one_step(dt) # Parcel volume should decrease according to abrasion rate volume_after_transport = np.squeeze(np.transpose(initial_volume)) * np.exp( nst._distance_traveled_cumulative * -abrasion_rate) assert_array_almost_equal(volume_after_transport, two_parcels.dataset.volume[0:2, -1])
def test_parcel_leaves(example_nmg, example_flow_director): example_nmg.at_link["reach_length"] = ([ 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0 ], ) time = [0.0] items = {"grid_element": "link", "element_id": np.array([[6]])} initial_volume = np.array([[1]]) abrasion_rate = np.array([0.0001]) variables = { "starting_link": (["item_id"], np.array([6])), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], np.array([2650])), "time_arrival_in_link": (["item_id", "time"], np.array([[0.71518937]])), "active_layer": (["item_id", "time"], np.array([[1]])), "location_in_link": (["item_id", "time"], np.array([[0]])), "D": (["item_id", "time"], np.array([[0.05]])), "volume": (["item_id", "time"], initial_volume), } one_parcel = DataRecord( example_nmg, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) timesteps = 10 example_nmg.at_link["flow_depth"] = example_nmg.at_link["flow_depth"] * 20 nst = NetworkSedimentTransporter( example_nmg, one_parcel, example_flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) dt = 60 * 60 * 24 # (seconds) daily timestep # Parcel should exit, then runtime error is raised with pytest.raises(RuntimeError): for _ in range(timesteps): nst.run_one_step(dt)
def test_bad_dummy_init(dmmy): grid = RasterModelGrid((3, 3)) element_id = [0, 0, 0, -9999, 1, 2, 3, 4, 5] volumes = [4, 5, 1, 2, 3, 4, 5, 6, 7] with pytest.raises(ValueError): DataRecord( grid, dummy_elements={"node": [dmmy]}, items={ "grid_element": "node", "element_id": np.array(element_id) }, data_vars={"volumes": (["item_id"], np.array(volumes))}, )
def dr_2dim(): time = [0.] my_items3 = { "grid_element": np.array([["node"], ["link"]]), "element_id": np.array([[1], [3]]), } my_data_vars = { "mean_elevation": (["time"], [110.]), "item_size": (["item_id", "time"], np.array([[0.3], [0.4]])), } return DataRecord(grid=grid, time=time, items=my_items3, data_vars=my_data_vars)
def dr_2dim(): time = [0.] my_items3 = { 'grid_element': np.array([['node'], ['link']]), 'element_id': np.array([[1], [3]]) } my_data_vars = { 'mean_elevation': (['time'], [110.]), 'item_size': (['item_id', 'time'], np.array([[0.3], [0.4]])) } return DataRecord(grid=grid, time=time, items=my_items3, data_vars=my_data_vars)
def test_ok_dummy(): grid = RasterModelGrid((3, 3)) element_id = [0, 0, 0, -9999, 1, 2, 3, 4, 5] volumes = [4, 5, 1, 2, 3, 4, 5, 6, 7] dr = DataRecord( grid, dummy_elements={ "link": [9999, 1234, -9999], "node": [9999, 1234, -9999] }, items={ "grid_element": "node", "element_id": np.array(element_id) }, data_vars={"volumes": (["item_id"], np.array(volumes))}, ) dr.add_item( new_item={ "grid_element": np.array(["node"]), "element_id": np.array([9999]) }, new_item_spec={"volumes": (["item_id"], [5])}, )
def dr_nodim(): return DataRecord(grid=grid)
def dr_item(): my_items2 = { 'grid_element': np.array(('node', 'link'), dtype=str), 'element_id': np.array([1, 3]) } return DataRecord(grid=grid, items=my_items2)
def test_defined_parcel_transport(): y_of_node = (0, 0, 0, 0) x_of_node = (0, 100, 200, 300) nodes_at_link = ((0, 1), (1, 2), (2, 3)) nmg_constant_slope = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link) # add variables to nmg nmg_constant_slope.at_node["topographic__elevation"] = [3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_node["bedrock__elevation"] = [3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_link["channel_slope"] = [0.001, 0.001, 0.001] nmg_constant_slope.at_link["reach_length"] = [100.0, 100.0, 100.0] # m nmg_constant_slope.at_link["channel_width"] = 15 * np.ones( nmg_constant_slope.size("link")) nmg_constant_slope.at_link["flow_depth"] = 2 * np.ones( nmg_constant_slope.size("link")) flow_director = FlowDirectorSteepest(nmg_constant_slope) flow_director.run_one_step() timesteps = 11 time = [0.0] items = {"grid_element": "link", "element_id": np.array([[0]])} initial_volume = np.array([[1]]) abrasion_rate = np.array([0]) variables = { "starting_link": (["item_id"], np.array([0])), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], np.array([2650])), "time_arrival_in_link": (["item_id", "time"], np.array([[0.71518937]])), "active_layer": (["item_id", "time"], np.array([[1]])), "location_in_link": (["item_id", "time"], np.array([[0]])), "D": (["item_id", "time"], np.array([[0.05]])), "volume": (["item_id", "time"], initial_volume), } one_parcel = DataRecord( nmg_constant_slope, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) nst = NetworkSedimentTransporter( nmg_constant_slope, one_parcel, flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) dt = 60 # (seconds) 1 min timestep distance_traveled = np.arange(0.0, timesteps) # distance_traveled = np.arange(0.,timesteps) for t in range(0, (timesteps * dt), dt): nst.run_one_step(dt) distance_traveled[np.int(t / dt)] = nst._distance_traveled_cumulative # NEED TO CALCULATE THINGS HERE. # Transport distance should match? Distance_Traveled_Should_Be = [ 21.61998527, 43.23997054, 64.85995581, 86.47994109, 108.09992636, 129.71991163, 151.3398969, 172.95988217, 194.57986744, 216.19985272, 237.81983799, ] assert_array_almost_equal(Distance_Traveled_Should_Be, distance_traveled, decimal=-1)
def methow(): example_data_dir = ExampleData("io/shapefile", case="methow").base shp_file = example_data_dir / "MethowSubBasin.shp" points_shapefile = example_data_dir / "MethowSubBasin_Nodes_4.shp" grid2 = read_shapefile( shp_file, points_shapefile=points_shapefile, node_fields=["usarea_km2", "Elev_m"], link_fields=["usarea_km2", "Length_m"], link_field_conversion={ "usarea_km2": "drainage_area", "Slope": "channel_slope", "Length_m": "reach_length", }, node_field_conversion={ "usarea_km2": "drainage_area", "Elev_m": "topographic__elevation", }, threshold=0.01, ) grid2.at_node["bedrock__elevation"] = grid2.at_node[ "topographic__elevation"].copy() grid2.at_link["channel_width"] = 1 * np.ones(grid2.number_of_links) grid2.at_link["flow_depth"] = 0.5 * np.ones(grid2.number_of_links) # element_id is the link on which the parcel begins. element_id = np.repeat(np.arange(grid2.number_of_links), 50) element_id = np.expand_dims(element_id, axis=1) volume = 1 * np.ones(np.shape(element_id)) # (m3) active_layer = np.ones(np.shape(element_id)) # 1= active, 0 = inactive density = 2650 * np.ones(np.size(element_id)) # (kg/m3) abrasion_rate = 0 * np.ones(np.size(element_id)) # (mass loss /m) # Lognormal GSD medianD = 0.15 # m mu = np.log(medianD) sigma = np.log(2) # assume that D84 = sigma*D50 np.random.seed(0) D = np.random.lognormal( mu, sigma, np.shape(element_id)) # (m) the diameter of grains in each parcel time_arrival_in_link = np.random.rand(np.size(element_id), 1) location_in_link = np.random.rand(np.size(element_id), 1) lithology = ["quartzite"] * np.size(element_id) variables = { "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], density), "lithology": (["item_id"], lithology), "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link), "active_layer": (["item_id", "time"], active_layer), "location_in_link": (["item_id", "time"], location_in_link), "D": (["item_id", "time"], D), "volume": (["item_id", "time"], volume), } items = {"grid_element": "link", "element_id": element_id} parcels2 = DataRecord( grid2, items=items, time=[0.0], data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) fd2 = FlowDirectorSteepest(grid2, "topographic__elevation") fd2.run_one_step() nst2 = NetworkSedimentTransporter( grid2, parcels2, fd2, bed_porosity=0.3, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) timesteps = 2 # total number of timesteps dt = 60 * 60 * 24 * 1 # length of timestep (seconds) for t in range(0, (timesteps * dt), dt): nst2.run_one_step(dt) return nst2
def synthetic(): y_of_node = (0, 100, 200, 200, 300, 400, 400, 125) x_of_node = (0, 0, 100, -50, -100, 50, -150, -100) nodes_at_link = ((1, 0), (2, 1), (1, 7), (3, 1), (3, 4), (4, 5), (4, 6)) grid1 = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link) grid1.at_node["topographic__elevation"] = [ 0.0, 0.08, 0.25, 0.15, 0.25, 0.4, 0.8, 0.8, ] grid1.at_node["bedrock__elevation"] = [ 0.0, 0.08, 0.25, 0.15, 0.25, 0.4, 0.8, 0.8 ] grid1.at_link["flow_depth"] = 2.5 * np.ones(grid1.number_of_links) grid1.at_link["channel_slope"] = np.ones( grid1.number_of_links) # AP ?? Does it get overwritten?? check grid1.at_link["reach_length"] = 200 * np.ones(grid1.number_of_links) # m grid1.at_link["channel_width"] = 1 * np.ones(grid1.number_of_links) # element_id is the link on which the parcel begins. element_id = np.repeat(np.arange(grid1.number_of_links), 30) element_id = np.expand_dims(element_id, axis=1) volume = 0.05 * np.ones(np.shape(element_id)) # (m3) active_layer = np.ones(np.shape(element_id)) # 1= active, 0 = inactive density = 2650 * np.ones(np.size(element_id)) # (kg/m3) abrasion_rate = 0 * np.ones(np.size(element_id)) # (mass loss /m) # Lognormal GSD medianD = 0.085 # m mu = np.log(medianD) sigma = np.log(2) # assume that D84 = sigma*D50 np.random.seed(0) D = np.random.lognormal( mu, sigma, np.shape(element_id)) # (m) the diameter of grains in each parcel time_arrival_in_link = np.random.rand(np.size(element_id), 1) location_in_link = np.random.rand(np.size(element_id), 1) lithology = ["quartzite"] * np.size(element_id) variables = { "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], density), "lithology": (["item_id"], lithology), "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link), "active_layer": (["item_id", "time"], active_layer), "location_in_link": (["item_id", "time"], location_in_link), "D": (["item_id", "time"], D), "volume": (["item_id", "time"], volume), } items = {"grid_element": "link", "element_id": element_id} parcels1 = DataRecord( grid1, items=items, time=[0.0], data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) fd1 = FlowDirectorSteepest(grid1, "topographic__elevation") fd1.run_one_step() nst1 = NetworkSedimentTransporter( grid1, parcels1, fd1, bed_porosity=0.3, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) timesteps = 2 # total number of timesteps dt = 60 * 60 * 24 * 1 # length of timestep (seconds) for t in range(0, (timesteps * dt), dt): nst1.run_one_step(dt) return nst1
def dr_item(): my_items2 = { "grid_element": np.array(("node", "link"), dtype=str), "element_id": np.array([1, 3]), } return DataRecord(grid=grid, items=my_items2)
def test_first_in_last_out(): y_of_node = (0, 0, 0, 0, 0, 0) x_of_node = (0, 100, 200, 300, 400, 500) nodes_at_link = ((0, 1), (1, 2), (2, 3), (3, 4), (4, 5)) nmg_constant_slope = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link) # add variables to nmg nmg_constant_slope.at_node["topographic__elevation"] = [ 5.0, 4.0, 3.0, 2.0, 1.0, 0.0, ] nmg_constant_slope.at_node["bedrock__elevation"] = [5.0, 4.0, 3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_link["channel_slope"] = [0.001, 0.001, 0.001, 0.001, 0.001] nmg_constant_slope.at_link["flow_depth"] = [1.75, 1.75, 1.75, 1.75, 1.75] nmg_constant_slope.at_link["reach_length"] = [ 100.0, 100.0, 100.0, 100.0, 100.0, ] # m nmg_constant_slope.at_link["channel_width"] = 15 * np.ones( nmg_constant_slope.size("link") ) flow_director = FlowDirectorSteepest(nmg_constant_slope) flow_director.run_one_step() timesteps = 20 time = [0.0] element_id = np.zeros(100, dtype=int) element_id = np.expand_dims(element_id, axis=1) items = {"grid_element": "link", "element_id": element_id} abrasion_rate = np.zeros(np.size(element_id)) initial_volume = np.ones(np.shape(element_id)) time_arrival_in_link = np.arange(0, 0.1, 0.001) time_arrival_in_link = np.expand_dims(time_arrival_in_link, axis=1) variables = { "starting_link": (["item_id"], np.squeeze(element_id)), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], 2650 * np.ones(np.size(element_id))), "time_arrival_in_link": (["item_id", "time"], time_arrival_in_link), "active_layer": (["item_id", "time"], initial_volume), "location_in_link": (["item_id", "time"], element_id), "D": (["item_id", "time"], initial_volume * 0.05), "volume": (["item_id", "time"], initial_volume), } hundred_boring_parcels = DataRecord( nmg_constant_slope, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) nst = NetworkSedimentTransporter( nmg_constant_slope, hundred_boring_parcels, flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) dt = 60 * 60 # (seconds) 1 hour timestep for t in range(0, (timesteps * dt), dt): nst.run_one_step(dt) first_in_parcel = np.argmin(time_arrival_in_link) last_in_parcel = np.argmax(time_arrival_in_link) link_of_first_in_parcel = hundred_boring_parcels.dataset.element_id.values[ first_in_parcel, : ] link_of_last_in_parcel = hundred_boring_parcels.dataset.element_id.values[ last_in_parcel, : ] First_in_lags_behind = np.greater_equal( link_of_last_in_parcel, link_of_first_in_parcel ) SO_TRUE = np.ones(np.shape(First_in_lags_behind), dtype=bool) assert_array_equal(SO_TRUE, First_in_lags_behind)
def test_misc(): grid = RasterModelGrid((3, 3)) # test bad dimension: with pytest.raises(ValueError): DataRecord( grid, time=[0.0], data_vars={"mean_elev": (["time"], [100.0]), "test": (["bad_dim"], [12])}, ) # should return ValueError('Data variable dimensions must be time and/or' # 'item_id') # test bad time format: with pytest.raises(TypeError): DataRecord(grid=grid, time="bad_time") # should return TypeError: Time must be a list or an array of length 1 # test bad datavars format: with pytest.raises(TypeError): DataRecord(grid, time=[0.0], data_vars=["not a dict"]) # should return TypeError(('Data variables (data_vars) passed to' # ' DataRecord must be a dictionary (see ' # 'documentation for valid structure)')) # test bad items format: with pytest.raises(TypeError): DataRecord( grid, time=[0.0], items=["not a dict"], data_vars={"mean_elevation": (["time"], np.array([100]))}, attrs={"time_units": "y"}, ) # Should return TypeError(('You must provide an ''items'' dictionary ' # '(see documentation for required format)')) # with pytest.raises(TypeError): """Test bad items keys""" DataRecord( grid, time=[0.0], items={ "grid_element": np.array([["node"], ["link"]]), "bad_key": np.array([[1], [3]]), }, data_vars={"mean_elevation": (["time"], np.array([100]))}, attrs={"time_units": "y"}, ) # Should return TypeError(('You must provide an ''items'' dictionary ' # '(see documentation for required format)')) with pytest.raises(TypeError): """Test bad attrs""" DataRecord( grid, time=[0.0], items={ "grid_element": np.array([["node"], ["link"]]), "element_id": np.array([[1], [3]]), }, data_vars={"mean_elevation": (["time"], np.array([100]))}, attrs=["not a dict"], ) # Should return except AttributeError: # raise TypeError(('Attributes (attrs) passed to DataRecord' # 'must be a dictionary')) # # test bad loc and id: rmg = RasterModelGrid((3, 3)) hmg = HexModelGrid((3, 2), spacing=1.0) radmg = RadialModelGrid(n_rings=1, nodes_in_first_ring=5, xy_of_center=(0.0, 0.0)) vdmg = VoronoiDelaunayGrid(np.random.rand(25), np.random.rand(25)) my_items_bad_loc = { "grid_element": np.array(["node", "bad_loc"]), "element_id": np.array([1, 3]), } my_items_bad_loc2 = {"grid_element": "bad_loc", "element_id": np.array([1, 3])} my_items_bad_loc3 = { "grid_element": np.array(["node", "node", "node"]), "element_id": np.array([1, 3]), } my_items_bad_id = { "grid_element": np.array(["node", "link"]), "element_id": np.array([1, 300]), } my_items_bad_id2 = { "grid_element": np.array(["node", "link"]), "element_id": np.array([1, -300]), } my_items_bad_id3 = { "grid_element": np.array(["node", "link"]), "element_id": np.array([1, 2.0]), } my_items_bad_id4 = { "grid_element": np.array(["node", "link"]), "element_id": np.array([1, 2, 3]), } with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_loc) with pytest.raises(ValueError): DataRecord(hmg, items=my_items_bad_loc) with pytest.raises(ValueError): DataRecord(radmg, items=my_items_bad_loc) with pytest.raises(ValueError): DataRecord(vdmg, items=my_items_bad_loc) # should return ValueError(('One or more of the grid elements provided is/are' # ' not permitted location for this grid type.')) with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_loc2) # should return ValueError: Location provided: bad_loc is not a permitted # location for this grid type. with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_loc3) # should return ValueError(('grid_element passed to DataRecord must be ' # ' the same length as the number of items or 1.')) with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_id) with pytest.raises(ValueError): DataRecord(hmg, items=my_items_bad_id) with pytest.raises(ValueError): DataRecord(radmg, items=my_items_bad_id) with pytest.raises(ValueError): DataRecord(vdmg, items=my_items_bad_id) # should return ValueError(('An item residing at ' + at + ' has an ' # 'element_id larger than the number of'+ at + 'on the grid.')) with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_id2) # should return ValueError(('An item residing at ' + at + ' has ' # 'an element id below zero. This is not permitted.')) with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_id3) # should return ValueError(('You have passed a non-integer element_id to ' # 'DataRecord, this is not permitted.')) with pytest.raises(ValueError): DataRecord(rmg, items=my_items_bad_id4)
import pytest import numpy as np from landlab import (RasterModelGrid, HexModelGrid, RadialModelGrid, VoronoiDelaunayGrid) from landlab.data_record import DataRecord grid = RasterModelGrid((3,3)) #test bad dimension: with pytest.raises(ValueError): DataRecord(grid, time=[0.], data_vars={'mean_elev' : (['time'], [100.]), 'test' : (['bad_dim'], [12])}) # should return ValueError('Data variable dimensions must be time and/or' # 'item_id') # test bad time format: with pytest.raises(TypeError): DataRecord(grid=grid, time='bad_time') #should return TypeError: Time must be a list or an array of length 1 #test bad datavars format: with pytest.raises(TypeError): DataRecord(grid, time=[0.], data_vars=['not a dict']) # should return TypeError(('Data variables (data_vars) passed to' # ' DataRecord must be a dictionary (see ' # 'documentation for valid structure)'))
def test_recycling(): y_of_node = (0, 0, 0, 0) x_of_node = (0, 100, 200, 300) nodes_at_link = ((0, 1), (1, 2), (2, 3)) nmg_constant_slope = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link) # add variables to nmg nmg_constant_slope.at_node["topographic__elevation"] = [3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_node["bedrock__elevation"] = [3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_link["channel_slope"] = [0.001, 0.001, 0.001] nmg_constant_slope.at_link["reach_length"] = [100.0, 100.0, 100.0] # m nmg_constant_slope.at_link["channel_width"] = 15 * np.ones( nmg_constant_slope.size("link") ) nmg_constant_slope.at_link["flow_depth"] = 3 * np.ones( nmg_constant_slope.size("link") ) flow_director = FlowDirectorSteepest(nmg_constant_slope) flow_director.run_one_step() time = [0.0] items = {"grid_element": "link", "element_id": np.array([[0]])} initial_volume = np.array([[1]]) abrasion_rate = np.array([0]) variables = { "starting_link": (["item_id"], np.array([0])), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], np.array([2650])), "time_arrival_in_link": (["item_id", "time"], np.array([[0.71518937]])), "active_layer": (["item_id", "time"], np.array([[1]])), "location_in_link": (["item_id", "time"], np.array([[0]])), "D": (["item_id", "time"], np.array([[0.05]])), "volume": (["item_id", "time"], initial_volume), } parcels = DataRecord( nmg_constant_slope, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) nst = NetworkSedimentTransporter( nmg_constant_slope, parcels, flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) dt = 60 # (seconds) 1 min timestep timesteps = 8 for t in range(0, (timesteps * dt), dt): # RECYCLE sediment: what left the network gets added back in at top. parcels.dataset.location_in_link.values[ parcels.dataset.element_id.values == NetworkSedimentTransporter.OUT_OF_NETWORK ] = 0 parcels.dataset.element_id.values[ parcels.dataset.element_id.values == NetworkSedimentTransporter.OUT_OF_NETWORK ] = 0 nst.run_one_step(dt) print("done with another timestep") print(parcels.dataset.element_id.values) Parcel_element_id = parcels.dataset.element_id.values Parcel_element_id_Should_Be = np.array( [[0.0, 0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 0.0, 0.0]] ) assert_array_almost_equal( Parcel_element_id_Should_Be, Parcel_element_id, decimal=-1 )
def __call__(self): if self._discharge is not None: # d50 = f(dominant discharge), Snyder if np.max(np.abs(self._mannings_n - 0.035)) > 0.3: msg = ( "BedParcelInitializer: Manning's n value is unrealistic. Value given = " + str(self._mannings_n)) warnings.warn(msg) d50 = calc_d50_discharge( self._grid.at_link["channel_width"], self._grid.at_link["channel_slope"], discharge=self._discharge, mannings_n=self._mannings_n, gravity=self._gravity, rho_water=self._rho_water, rho_sediment=self._rho_sediment, tau_c_50=self._tau_c_50, ) elif self._flow_depth is not None: # d50 = f(dominant flow depth), Pfeiffer d50 = calc_d50_depth( self._grid.at_link["channel_slope"], flow_depth=self._flow_depth, tau_c_multiplier=self._tau_c_multiplier, rho_water=self._rho_water, rho_sediment=self._rho_sediment, tau_c_50=self._tau_c_50, ) elif self._drainage_area_coefficient is not None: # d50 = f(drainage area) d50 = calc_d50_dArea_scaling(self._grid.at_link["drainage_area"], a=self._drainage_area_coefficient, n=self._drainage_area_exponent) elif self._user_d50 is not None: if np.size(self._user_d50) == 1: # one d50, all links d50 = np.full_like(self._grid.length_of_link, self._user_d50, dtype=float) print('d50 at each link..', d50) elif np.size(self._user_d50) == ( self._grid.number_of_links): # different d50 each link d50 = self._user_d50 else: msg = ( "BedParcelInitializer: user defined D50 must be either" + "a scalar or size(element_id)") raise ValueError(msg) else: msg = "BedParcelInitializer: user must pass depth, discharge, drainage area scaling, or uniform d50" raise ValueError(msg) self.D50 = d50 d84 = d50 * self._std_dev total_parcel_volume_at_link = calc_total_parcel_volume( self._grid.at_link["channel_width"], self._grid.at_link["reach_length"], d84 * self._sed_thickness, ) max_parcel_volume = _determine_approx_parcel_volume( total_parcel_volume_at_link, self._median_number_of_starting_parcels) variables, items = _parcel_characteristics( total_parcel_volume_at_link, max_parcel_volume, d50, self._std_dev, self._rho_sediment, self._abrasion_rate, self._extra_parcel_attributes) if np.min(self._sed_thickness) < 0.05: msg = ( "BedParcelInitializer: Sediment thickness is unrealistically low. Minimum link sediment thickness = " + str(self._sed_thickness) + " m") warnings.warn(msg) if np.max(d50) > 0.5: msg = ( "BedParcelInitializer: Median grain sizes are too large for physically realistic application of the NST. Maximum link D50 = " + str(d50) + " m") warnings.warn(msg) if np.min(d50) < 0.002: msg = ( "BedParcelInitializer: The equations used in this initializer are intended for gravel bedded rivers." "Calculated median grain sizes are too small. Minimum link D50 = " + str(d50) + " m") warnings.warn(msg) if np.max(np.abs(self._tau_c_50 - 0.055)) > 0.35: msg = ( "BedParcelInitializer: Shields stress value is unrealistic. Value given = " + str(self._sed_thickness)) warnings.warn(msg) if max_parcel_volume < 0.05: msg = ( "BedParcelInitializer: Careful! Default parcel volume is extremely small: " + str(max_parcel_volume) + ' m') warnings.warn(msg) return DataRecord( self._grid, items=items, time=self._time, data_vars=variables, dummy_elements={"link": [_OUT_OF_NETWORK]}, )
def dr_time(): time = [0.] data_vars = {'mean_elevation': (['time'], np.array([100]))} attrs = {'time_units': 'y'} return DataRecord(grid=grid, time=time, data_vars=data_vars, attrs=attrs)
""" import numpy as np import pytest from landlab import HexModelGrid, RadialModelGrid, RasterModelGrid, VoronoiDelaunayGrid from landlab.data_record import DataRecord grid = RasterModelGrid((3, 3)) # test bad dimension: with pytest.raises(ValueError): DataRecord( grid, time=[0.0], data_vars={ "mean_elev": (["time"], [100.0]), "test": (["bad_dim"], [12]) }, ) # should return ValueError('Data variable dimensions must be time and/or' # 'item_id') # test bad time format: with pytest.raises(TypeError): DataRecord(grid=grid, time="bad_time") # should return TypeError: Time must be a list or an array of length 1 # test bad datavars format: with pytest.raises(TypeError): DataRecord(grid, time=[0.0], data_vars=["not a dict"]) # should return TypeError(('Data variables (data_vars) passed to' # ' DataRecord must be a dictionary (see '
def test_add_pulse(): y_of_node = (0, 0, 0, 0) x_of_node = (0, 100, 200, 300) nodes_at_link = ((0, 1), (1, 2), (2, 3)) nmg_constant_slope = NetworkModelGrid((y_of_node, x_of_node), nodes_at_link) # add variables to nmg nmg_constant_slope.at_node["topographic__elevation"] = [3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_node["bedrock__elevation"] = [3.0, 2.0, 1.0, 0.0] nmg_constant_slope.at_link["channel_slope"] = [0.001, 0.001, 0.001] nmg_constant_slope.at_link["reach_length"] = [100.0, 100.0, 100.0] # m nmg_constant_slope.at_link["channel_width"] = 15 * np.ones( nmg_constant_slope.size("link") ) nmg_constant_slope.at_link["flow_depth"] = 2 * np.ones( nmg_constant_slope.size("link") ) flow_director = FlowDirectorSteepest(nmg_constant_slope) flow_director.run_one_step() time = [0.0] items = {"grid_element": "link", "element_id": np.array([[0]])} initial_volume = np.array([[1]]) abrasion_rate = np.array([0]) variables = { "starting_link": (["item_id"], np.array([0])), "abrasion_rate": (["item_id"], abrasion_rate), "density": (["item_id"], np.array([2650])), "time_arrival_in_link": (["item_id", "time"], np.array([[0.71518937]])), "active_layer": (["item_id", "time"], np.array([[1]])), "location_in_link": (["item_id", "time"], np.array([[0]])), "D": (["item_id", "time"], np.array([[0.05]])), "volume": (["item_id", "time"], initial_volume), } parcels = DataRecord( nmg_constant_slope, items=items, time=time, data_vars=variables, dummy_elements={"link": [NetworkSedimentTransporter.OUT_OF_NETWORK]}, ) nst = NetworkSedimentTransporter( nmg_constant_slope, parcels, flow_director, bed_porosity=0.03, g=9.81, fluid_density=1000, transport_method="WilcockCrowe", ) dt = 60 # (seconds) 1 min timestep nst.run_one_step(dt) # ONE TIMESTEP BEFORE PULSE # TIMESTEP 1 should have NANS. num_pulse_parcels = 2 newpar_element_id = np.zeros(num_pulse_parcels, dtype=int) newpar_element_id = np.expand_dims(newpar_element_id, axis=1) new_starting_link = np.squeeze(newpar_element_id) np.random.seed(0) new_time_arrival_in_link = nst._time * np.ones(np.shape(newpar_element_id)) new_volume = 0.5 * np.ones( np.shape(newpar_element_id) ) # (m3) the volume of each parcel new_lithology = ["pulse_material"] * np.size( newpar_element_id ) # a lithology descriptor for each parcel new_active_layer = np.ones( np.shape(newpar_element_id) ) # 1 = active/surface layer; 0 = subsurface layer new_density = 2650 * np.ones(np.size(newpar_element_id)) # (kg/m3) new_location_in_link = np.random.rand(np.size(newpar_element_id), 1) new_abrasion_rate = 0 * np.ones(np.size(newpar_element_id)) new_D = 0.03 * np.ones(np.shape(newpar_element_id)) newpar_grid_elements = np.array( np.empty((np.shape(newpar_element_id)), dtype=object) ) # BUG: should be able to pass ["link"], but datarecord fills it into an incorrect array shape-- the length of parcels (NOT new parcels) newpar_grid_elements.fill("link") new_parcels = { "grid_element": newpar_grid_elements, "element_id": newpar_element_id, } new_variables = { "starting_link": (["item_id"], new_starting_link), "abrasion_rate": (["item_id"], new_abrasion_rate), "density": (["item_id"], new_density), "lithology": (["item_id"], new_lithology), "time_arrival_in_link": (["item_id", "time"], new_time_arrival_in_link), "active_layer": (["item_id", "time"], new_active_layer), "location_in_link": (["item_id", "time"], new_location_in_link), "D": (["item_id", "time"], new_D), "volume": (["item_id", "time"], new_volume), } parcels.add_item( time=[nst._time], new_item=new_parcels, new_item_spec=new_variables ) nst.run_one_step(dt) print(parcels.dataset.element_id.values) Parcel_element_id = parcels.dataset.element_id.values Parcel_element_id_Should_Be = np.array( [[0.0, 0.0, 0.0], [np.nan, 0.0, 0.0], [np.nan, 0.0, 0.0]] ) assert_array_almost_equal( Parcel_element_id_Should_Be, Parcel_element_id, decimal=-1 )
def dr_time(): time = [0.] data_vars = {"mean_elevation": (["time"], np.array([100]))} attrs = {"time_units": "y"} return DataRecord(grid=grid, time=time, data_vars=data_vars, attrs=attrs)