def test_simple_water_table_adaptive_dt(): """Test a one-node steady simulation. Notes ----- This test demonstrates the same simple water table as test_simple_water_table, but with the run_with_adaptive_time_step_solver method. """ boundaries = {"top": "closed", "left": "closed", "bottom": "closed"} rg = RasterModelGrid((3, 3), bc=boundaries) rg.add_zeros("aquifer_base__elevation", at="node") rg.add_ones("topographic__elevation", at="node") rg.add_zeros("water_table__elevation", at="node") rg.at_node["water_table__elevation"][rg.core_nodes] += 1e-10 gdp = GroundwaterDupuitPercolator( rg, recharge_rate=1.0e-8, hydraulic_conductivity=0.01, ) for _ in range(10): gdp.run_with_adaptive_time_step_solver(1e4) assert_equal(np.round(gdp._thickness[4], 5), 0.001)
def test_run_one_step(): from landlab import RasterModelGrid grid = RasterModelGrid((10, 10), spacing=25) grid.add_ones('node', 'soil_water_infiltration__depth', dtype=float) grid.add_ones('node', 'surface_water__depth') hydraulic_conductivity = (2.5 * (10**-6)) grid['node']['surface_water__depth'] *= 5.0 grid['node']['soil_water_infiltration__depth'] *= (10**-5) SI = SoilInfiltrationGreenAmpt( grid, hydraulic_conductivity=hydraulic_conductivity, soil_bulk_density=1700., rock_density=2650., initial_soil_moisture_content=0.2, soil_type='silt loam', volume_fraction_coarse_fragments=0.6, coarse_sed_flag=False, surface_water_minimum_depth=1.e-7, soil_pore_size_distribution_index=None, soil_bubbling_pressure=None, wetting_front_capillary_pressure_head=None) SI.run_one_step(dt=5) np.testing.assert_almost_equal(grid['node']['surface_water__depth'][0], 3.97677483519, decimal=6)
def test_exp_reg_prod(): """ Test RegolithExponentialProduction and ensure fields are updated based on an exact solution. """ mg = RasterModelGrid((3, 3), xy_spacing=10.0) z = mg.add_ones("node", "topographic__elevation") zb = mg.add_zeros("node", "aquifer_base__elevation") zwt = mg.add_ones("node", "water_table__elevation") rm = RegolithExponentialProduction(mg) rm.run_step(1e9) assert_almost_equal(z[4], 1.001) assert_almost_equal(zb[4], 1.001 - np.log(np.exp(1) + 1e9 * 2e-12)) assert_almost_equal(zwt[4], 1.001 - np.log(np.exp(1) + 1e9 * 2e-12) + 1.0) b0 = (z - zb)[4] rm.run_step(1e9) assert_almost_equal(z[4], 1.002) assert_almost_equal(zb[4], 1.002 - np.log(np.exp(b0) + 1e9 * 2e-12)) assert_almost_equal(zwt[4], 1.002 - np.log(np.exp(b0) + 1e9 * 2e-12) + 1.0)
def test_wt_above_surface_standard_run_step(): """test that water tables above the topogrpahic elevation are set to the topographic elevation. Notes: ---- Water tables above the land surface represent a non-physical condition. The GroundwaterDupuitPercolator will not produce this state when it is the only component operating on water table elevation or topogrpahic elevation, however, when combined with components that do, this may occur. If the water table is above the ground surface at a node, it is set to the ground surface elevation at that node. """ grid = RasterModelGrid((3, 3)) grid.set_closed_boundaries_at_grid_edges(True, True, True, False) wt = grid.add_ones("node", "water_table__elevation") _ = grid.add_ones("node", "topographic__elevation") _ = grid.add_zeros("node", "aquifer_base__elevation") # initialize the groundwater model gdp = GroundwaterDupuitPercolator(grid, recharge_rate=0.0) gdp.run_one_step(1) assert_equal(wt[4], 1)
def test_simple_water_table(): """Test a one-node steady simulation. Notes ----- The analytical solution for one interior cell with one open boundary is as follows. The incoming recharge must equal the outgoing discharge. The incoming recharge is R, and the surface area is 1 m2, so the incoming volume per unit time is R m/s x 1 m x 1 m. The outgoing discharge is equal to the conductivity, K (m/s), times the thickness at the boundary, Hb, times the hydraulic gradient, which in this case is (H - 0) / dx = H. The model uses the upwind thickness, which in this case is H. Therefore: K H^2 = R, or H = sqrt( R / K ). With R = 10^-8 m/s and K = 10^-2 m/s, we should have H = 0.001 m. """ boundaries = {"top": "closed", "left": "closed", "bottom": "closed"} rg = RasterModelGrid((3, 3), bc=boundaries) rg.add_zeros("aquifer_base__elevation", at="node") rg.add_ones("topographic__elevation", at="node") gdp = GroundwaterDupuitPercolator(rg, recharge_rate=1.0e-8, hydraulic_conductivity=0.01) for _ in range(100): gdp.run_one_step(1e3) assert_equal(np.round(gdp._thickness[4], 5), 0.001)
def test_add_ones_at_corners(): """Test add a field to corners.""" grid = RasterModelGrid((4, 5)) grid.add_ones('z', at='corner') assert_array_equal(grid.at_corner['z'], [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
def grid_1(): grid = RasterModelGrid((3, 21), xy_spacing=100.0) grid.set_closed_boundaries_at_grid_edges(False, True, False, True) grid.add_zeros("node", "topographic__elevation") grid.add_ones("node", "soil__depth") grid.add_zeros("node", "lithology_contact__elevation") return grid
def test_run_one_step(): grid = RasterModelGrid((10, 10), xy_spacing=25) grid.add_ones("soil_water_infiltration__depth", at="node", dtype=float) grid.add_ones("surface_water__depth", at="node") hydraulic_conductivity = 2.5 * (10 ** -6) grid["node"]["surface_water__depth"] *= 5.0 grid["node"]["soil_water_infiltration__depth"] *= 10 ** -5 SI = SoilInfiltrationGreenAmpt( grid, hydraulic_conductivity=hydraulic_conductivity, soil_bulk_density=1700.0, rock_density=2650.0, initial_soil_moisture_content=0.2, soil_type="silt loam", volume_fraction_coarse_fragments=0.6, coarse_sed_flag=False, surface_water_minimum_depth=1.0e-7, soil_pore_size_distribution_index=None, soil_bubbling_pressure=None, wetting_front_capillary_pressure_head=None, ) SI.run_one_step(dt=5) np.testing.assert_almost_equal( grid["node"]["surface_water__depth"][0], 3.97677483519, decimal=6 )
def test_run_one_step(): grid = RasterModelGrid((10, 10), xy_spacing=25) grid.add_ones("node", "soil_water_infiltration__depth", dtype=float) grid.add_ones("node", "surface_water__depth") hydraulic_conductivity = 2.5 * (10 ** -6) grid["node"]["surface_water__depth"] *= 5.0 grid["node"]["soil_water_infiltration__depth"] *= 10 ** -5 SI = SoilInfiltrationGreenAmpt( grid, hydraulic_conductivity=hydraulic_conductivity, soil_bulk_density=1700., rock_density=2650., initial_soil_moisture_content=0.2, soil_type="silt loam", volume_fraction_coarse_fragments=0.6, coarse_sed_flag=False, surface_water_minimum_depth=1.e-7, soil_pore_size_distribution_index=None, soil_bubbling_pressure=None, wetting_front_capillary_pressure_head=None, ) SI.run_one_step(dt=5) np.testing.assert_almost_equal( grid["node"]["surface_water__depth"][0], 3.97677483519, decimal=6 )
def test_add_ones_at_corners(): """Test add a field to corners.""" grid = RasterModelGrid((4, 5)) grid.add_ones("z", at="corner") assert_array_equal( grid.at_corner["z"], [1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.] )
def test_add_ones_zeros_empty_to_at_grid(): """Test different add methods for keyword at='grid'""" grid = RasterModelGrid((4, 5)) with pytest.raises(ValueError): grid.add_zeros("value", at="grid") with pytest.raises(ValueError): grid.add_empty("value", at="grid") with pytest.raises(ValueError): grid.add_ones("value", at="grid")
def test_drainage_area(): """Test that correct error is raised when no flow__upstream_node_order.""" mg = RasterModelGrid(30, 70) mg.add_ones("node", "topographic__elevation") mg.add_ones("node", "flow__upstream_node_order") fd = FlowDirectorSteepest(mg) fd.run_one_step() with pytest.raises(FieldError): calculate_distance_to_divide(mg)
def grid_5(): grid = RasterModelGrid((6, 9), xy_spacing=10) grid.add_zeros("node", "topographic__elevation") grid.add_ones("node", "soil__depth") lith = grid.add_zeros("node", "lithology_contact__elevation") lith[:27] = -30 lith[27:] = 10.0 lith[grid.boundary_nodes] = -9999.0 return grid
def test_add_ones_at_corners(): """Test add a field to corners.""" grid = RasterModelGrid((4, 5)) grid.add_ones("z", at="corner") assert_array_equal( grid.at_corner["z"], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], )
def test_add_ones_zeros_empty_to_at_grid(): """Test different add methods for keyword at='grid'""" grid = RasterModelGrid((4, 5)) with pytest.raises(ValueError): grid.add_zeros('value', at='grid') with pytest.raises(ValueError): grid.add_empty('value', at='grid') with pytest.raises(ValueError): grid.add_ones('value', at='grid')
def test_flow_director_steepest_flow__link_dir_field_creation(): mg = RasterModelGrid((3, 3)) mg.set_closed_boundaries_at_grid_edges(True, True, True, False) z = mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") mg.add_ones("flow__link_direction", at="link", dtype=int) fd = FlowDirectorSteepest(mg, z) assert_array_equal( fd.flow_link_direction, np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) )
def grid_3(): grid = RasterModelGrid((21, 3), xy_spacing=100.0) grid.set_closed_boundaries_at_grid_edges(False, True, False, True) grid.add_zeros("node", "topographic__elevation") grid.add_ones("node", "soil__depth") lith = grid.add_zeros("node", "lithology_contact__elevation") lith[grid.core_nodes[:9]] = -100000.0 lith[grid.core_nodes[9:]] = 100000.0 return grid
def grid_2(): grid = RasterModelGrid((8, 20), xy_spacing=100.0) grid.set_closed_boundaries_at_grid_edges(False, True, False, True) grid.add_zeros("node", "topographic__elevation") grid.add_ones("node", "soil__depth") lith = grid.add_zeros("node", "lithology_contact__elevation") lith[:80] = 10 lith[80:] = -10000.0 return grid
def test_flow_director_steepest_flow__link_dir_field_creation(): mg = RasterModelGrid((3, 3)) mg.set_closed_boundaries_at_grid_edges(True, True, True, False) z = mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") mg.add_ones("flow_link_direction", at="link", dtype=int) fd = FlowDirectorSteepest(mg, z) assert_array_equal( fd.flow_link_direction, np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) )
def test_stream_power_save_output(tmpdir): mg = RasterModelGrid((3, 3), xy_spacing=10.0) mg.set_status_at_node_on_edges( right=mg.BC_NODE_IS_CLOSED, top=mg.BC_NODE_IS_CLOSED, left=mg.BC_NODE_IS_CLOSED, bottom=mg.BC_NODE_IS_FIXED_VALUE, ) mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") mg.add_ones("node", "water_table__elevation") gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-4) hm = HydrologySteadyStreamPower(mg, groundwater_model=gdp) sp = FastscapeEroder( mg, K_sp=1e-10, m_sp=1, n_sp=1, discharge_field="surface_water_area_norm__discharge", ) ld = LinearDiffuser(mg, linear_diffusivity=1e-10) rm = RegolithConstantThickness(mg, uplift_rate=0.0) output = {} output["output_interval"] = 1000 output["output_fields"] = [ "at_node:topographic__elevation", "at_node:aquifer_base__elevation", "at_node:water_table__elevation", ] output["base_output_path"] = tmpdir.strpath + "/" output["run_id"] = 0 # make this task_id if multiple runs mdl = StreamPowerModel( mg, hydrology_model=hm, diffusion_model=ld, erosion_model=sp, regolith_model=rm, total_morphological_time=1e8, output_dict=output, ) mdl.run_model() file = tmpdir.join("0_grid_0.nc") mg1 = from_netcdf(file.strpath) keys = [ "topographic__elevation", "aquifer_base__elevation", "water_table__elevation", ] assert isinstance(mg1, RasterModelGrid) assert set(mg1.at_node.keys()) == set(keys) assert_equal(mg1.status_at_node, mg.status_at_node)
def test_stoch_sp_raster_record_state(): """ Initialize HydrologyEventStreamPower on a raster grid. Use several storm-interstorm pairs and make sure state recorded as expected. """ mg = RasterModelGrid((3, 3), xy_spacing=10.0) mg.set_status_at_node_on_edges( right=mg.BC_NODE_IS_CLOSED, top=mg.BC_NODE_IS_CLOSED, left=mg.BC_NODE_IS_CLOSED, bottom=mg.BC_NODE_IS_FIXED_VALUE, ) mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") wt = mg.add_ones("node", "water_table__elevation") gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-6) pd = PrecipitationDistribution( mg, mean_storm_duration=10, mean_interstorm_duration=100, mean_storm_depth=1e-3, total_t=200, ) pd.seed_generator(seedval=1) hm = HydrologyEventStreamPower(mg, precip_generator=pd, groundwater_model=gdp) wt0 = wt.copy() hm.run_step_record_state() times = np.array([ 0.0, hm.storm_dts[0], hm.storm_dts[0] + hm.interstorm_dts[0], hm.storm_dts[0] + hm.interstorm_dts[0] + hm.storm_dts[1], hm.storm_dts[0] + hm.interstorm_dts[0] + hm.storm_dts[1] + hm.interstorm_dts[1], ]) intensities = np.zeros(5) intensities[0] = hm.intensities[0] intensities[2] = hm.intensities[1] assert_equal(hm.time, times) assert_equal(hm.intensity, intensities) assert_equal(hm.qs_all.shape, (5, 9)) assert_equal(hm.Q_all.shape, (5, 9)) assert_equal(hm.wt_all.shape, (5, 9)) assert_equal(hm.qs_all[0, :], np.zeros(9)) assert_equal(hm.Q_all[0, :], np.zeros(9)) assert_equal(hm.wt_all[0, :], wt0)
def test_wt_above_surface_adaptive_run_step(): grid = RasterModelGrid((3, 3)) grid.set_closed_boundaries_at_grid_edges(True, True, True, False) wt = grid.add_ones("node", "water_table__elevation") _ = grid.add_ones("node", "topographic__elevation") _ = grid.add_zeros("node", "aquifer_base__elevation") # initialize the groundwater model gdp = GroundwaterDupuitPercolator(grid, recharge_rate=0.0) gdp.run_with_adaptive_time_step_solver(1) assert_equal(wt[4], 1)
def test_include_keyword_is_empty(tmpdir, format, include): grid = RasterModelGrid((4, 3), xy_spacing=(2, 5), xy_of_lower_left=(-2.0, 10.0)) grid.add_ones("elev", at="node") grid.add_zeros("elev", at="link") grid.add_empty("temp", at="node") with tmpdir.as_cwd(): to_netcdf(grid, "test.nc", format=format) actual = from_netcdf("test.nc", include=include) assert len(actual.at_node) == 0 assert len(actual.at_link) == 0
def test_sheetflow(): flux = np.array( [1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+06, 1.87867966e+06, 2.72182541e+06, 3.54415588e+06, 4.35303038e+06, 5.15223689e+06, 5.94408409e+06, 6.73016503e+06, 6.51166745e+06, 1.00000000e+00, 1.00000000e+06, 2.12132034e+06, 3.24264069e+06, 4.35965005e+06, 5.47056275e+06, 6.57568517e+06, 7.67583899e+06, 8.77188984e+06, 8.86460677e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.03553391e+06, 4.08578644e+06, 5.14392129e+06, 6.20695360e+06, 7.27341175e+06, 8.34244102e+06, 8.41347211e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.00000000e+06, 4.01040764e+06, 5.03248558e+06, 6.06512434e+06, 7.10666517e+06, 8.15550411e+06, 8.21025766e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.00000000e+06, 4.01040764e+06, 5.03248558e+06, 6.06512434e+06, 7.10666517e+06, 8.15550411e+06, 8.21025766e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.03553391e+06, 4.08578644e+06, 5.14392129e+06, 6.20695360e+06, 7.27341175e+06, 8.34244102e+06, 8.41347211e+06, 1.00000000e+00, 1.00000000e+06, 2.12132034e+06, 3.24264069e+06, 4.35965005e+06, 5.47056275e+06, 6.57568517e+06, 7.67583899e+06, 8.77188984e+06, 8.86460677e+06, 1.00000000e+00, 1.00000000e+06, 1.87867966e+06, 2.72182541e+06, 3.54415588e+06, 4.35303038e+06, 5.15223689e+06, 5.94408409e+06, 6.73016503e+06, 6.51166745e+06, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00]) mg = RasterModelGrid((NROWS, NCOLS), (DX, DX)) z = (3000. - mg.node_x) * 0.5 mg.at_node['topographic__elevation'] = z mg.set_closed_boundaries_at_grid_edges(False, True, True, True) mg.add_ones('node', 'water__unit_flux_in') pfr = PotentialityFlowRouter(mg) pfr.route_flow() assert_allclose(mg.at_node['surface_water__discharge'], flux)
def test_sheetflow(): flux = np.array( [1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+06, 1.87867966e+06, 2.72182541e+06, 3.54415588e+06, 4.35303038e+06, 5.15223689e+06, 5.94408409e+06, 6.73016503e+06, 6.51166745e+06, 1.00000000e+00, 1.00000000e+06, 2.12132034e+06, 3.24264069e+06, 4.35965005e+06, 5.47056275e+06, 6.57568517e+06, 7.67583899e+06, 8.77188984e+06, 8.86460677e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.03553391e+06, 4.08578644e+06, 5.14392129e+06, 6.20695360e+06, 7.27341175e+06, 8.34244102e+06, 8.41347211e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.00000000e+06, 4.01040764e+06, 5.03248558e+06, 6.06512434e+06, 7.10666517e+06, 8.15550411e+06, 8.21025766e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.00000000e+06, 4.01040764e+06, 5.03248558e+06, 6.06512434e+06, 7.10666517e+06, 8.15550411e+06, 8.21025766e+06, 1.00000000e+00, 1.00000000e+06, 2.00000000e+06, 3.03553391e+06, 4.08578644e+06, 5.14392129e+06, 6.20695360e+06, 7.27341175e+06, 8.34244102e+06, 8.41347211e+06, 1.00000000e+00, 1.00000000e+06, 2.12132034e+06, 3.24264069e+06, 4.35965005e+06, 5.47056275e+06, 6.57568517e+06, 7.67583899e+06, 8.77188984e+06, 8.86460677e+06, 1.00000000e+00, 1.00000000e+06, 1.87867966e+06, 2.72182541e+06, 3.54415588e+06, 4.35303038e+06, 5.15223689e+06, 5.94408409e+06, 6.73016503e+06, 6.51166745e+06, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, 1.00000000e+00]) mg = RasterModelGrid((NROWS, NCOLS), (DX, DX)) z = (3000. - mg.node_x) * 0.5 mg.at_node['topographic__elevation'] = z mg.set_closed_boundaries_at_grid_edges(False, True, True, True) mg.add_ones('node', 'water__unit_flux_in') pfr = PotentialityFlowRouter(mg) pfr.route_flow() assert_allclose(mg.at_node['water__discharge'], flux)
def test_stoch_sp_threshold_above_threshold(): """ Test the stochastic event model with stream power threshold in which the one core node is set up to exceed erosion threshold for the value of Q that it attains. This can be checked by comparing the accumulated q to the threshold value needed for erosion Q0. """ mg = RasterModelGrid((3, 3), xy_spacing=10.0) mg.set_status_at_node_on_edges( right=mg.BC_NODE_IS_CLOSED, top=mg.BC_NODE_IS_CLOSED, left=mg.BC_NODE_IS_CLOSED, bottom=mg.BC_NODE_IS_FIXED_VALUE, ) elev = mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") wt = mg.add_ones("node", "water_table__elevation") elev[4] += 0.01 wt[:] = elev gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-6) pd = PrecipitationDistribution( mg, mean_storm_duration=10, mean_interstorm_duration=100, mean_storm_depth=1e-3, total_t=100, ) pd.seed_generator(seedval=1) hm = HydrologyEventThresholdStreamPower( mg, precip_generator=pd, groundwater_model=gdp, sp_coefficient=1e-5, sp_threshold=1e-12, ) hm.run_step() storm_dt = 1.4429106411 # storm duration storm_q = 0.0244046740 # accumulated q before threshold effect subtracted interstorm_q = 0.0 # interstorm q is zero in this case assert_almost_equal( hm.q_eff[4], 0.5 * (max(interstorm_q - hm.Q0[4], 0) + max(storm_q - hm.Q0[4], 0)) * storm_dt / hm.T_h, )
def _test(): rmg = RasterModelGrid(4, 5) number_of_elements = rmg.number_of_elements(element) rtn_values = rmg.add_ones(element, 'name') assert_is(rtn_values, rmg.field_values(element, 'name')) assert_array_equal(rtn_values, np.ones(number_of_elements, dtype=np.float))
def _test(): rmg = RasterModelGrid(4, 5) number_of_elements = rmg.number_of_elements(element) rtn_values = rmg.add_ones(element, 'name') assert_is(rtn_values, rmg.field_values(element, 'name')) assert_array_equal( rtn_values, np.ones(number_of_elements, dtype=np.float))
def test_add_ones(graph_element): grid = RasterModelGrid((4, 5)) number_of_elements = grid.number_of_elements(graph_element) rtn_values = grid.add_ones("name", at=graph_element, dtype=field_dtype) assert rtn_values is grid.field_values(graph_element, "name") assert np.all( rtn_values == approx(np.ones(number_of_elements, dtype=field_dtype)))
def test_callback_func(): """ Test the use of a callback function to return the storage and substep durations while using the run_with_adaptive_time_step_solver method. Notes: ---- Two tests here: make sure that the substeps sum to the global timestep, and make sure that when recharge is 0.0, the total storage does not increase during any of the substeps. See component documentation for more detail on arguments for the callback_fun. """ # make a function that writes storage and substep duration to # externally defined lists storage_subdt = [] subdt = [] all_n = [] def test_fun(grid, recharge, dt, n=0.2): cores = grid.core_nodes h = grid.at_node["aquifer__thickness"] area = grid.cell_area_at_node storage = np.sum(n * h[cores] * area[cores]) storage_subdt.append(storage) subdt.append(dt) all_n.append(n) # initialize grid grid = RasterModelGrid((3, 3)) grid.set_closed_boundaries_at_grid_edges(True, True, False, True) elev = grid.add_ones("topographic__elevation", at="node") elev[3] = 0.1 grid.add_zeros("aquifer_base__elevation", at="node") wt = grid.add_zeros("water_table__elevation", at="node") wt[:] = elev # initialize groundwater model gdp = GroundwaterDupuitPercolator( grid, recharge_rate=0.0, hydraulic_conductivity=0.0001, callback_fun=test_fun, n=0.1, ) # run groundawter model gdp.run_with_adaptive_time_step_solver(1e5) # assert that the water table does not increase during substeps assert (np.diff(storage_subdt) <= 0.0).all() # assert that substeps sum to the global timestep assert_almost_equal(1e5, sum(subdt)) assert all(x == 0.1 for x in all_n)
def test_outlet_lowering_rate_no_scaling_bedrock(): """Test using an outlet lowering rate with no scaling and bedrock.""" mg = RasterModelGrid((5, 5)) z = mg.add_ones("node", "topographic__elevation") b = mg.add_zeros("node", "bedrock__elevation") bh = NotCoreNodeBaselevelHandler( mg, modify_core_nodes=True, lowering_rate=-0.1 ) for _ in range(240): bh.run_one_step(10) closed = mg.status_at_node != 0 not_closed = mg.status_at_node == 0 # closed should have stayed the same assert_array_equal(z[closed], np.ones(np.sum(closed))) assert_array_equal(b[closed], np.zeros(np.sum(closed))) # not closed should have been uplifted 2410*0.1 assert_array_equal(b[not_closed], 240.0 * np.ones(np.sum(not_closed))) assert_array_equal(z[not_closed], 241.0 * np.ones(np.sum(not_closed))) # % doing the oposite should also work mg = RasterModelGrid((5, 5)) z = mg.add_ones("node", "topographic__elevation") b = mg.add_zeros("node", "bedrock__elevation") bh = NotCoreNodeBaselevelHandler( mg, modify_core_nodes=False, lowering_rate=-0.1 ) for _ in range(240): bh.run_one_step(10) closed = mg.status_at_node != 0 not_closed = mg.status_at_node == 0 # not closed should have staued the same assert_array_equal(z[not_closed], np.ones(np.sum(not_closed))) assert_array_equal(b[not_closed], np.zeros(np.sum(not_closed))) # closed should have lowered by 240 assert_array_equal(b[closed], -240.0 * np.ones(np.sum(closed))) assert_array_equal(z[closed], -239.0 * np.ones(np.sum(closed)))
def test_const_thickness(): """ Test RegolithConstantThickness and ensure fields are updated based on an exact solution. """ mg = RasterModelGrid((3, 3), xy_spacing=10.0) z = mg.add_ones("node", "topographic__elevation") zb = mg.add_zeros("node", "aquifer_base__elevation") zwt = mg.add_ones("node", "water_table__elevation") rm = RegolithConstantThickness(mg) rm.run_step(1e9) assert_almost_equal(z[4], 1.001) assert_almost_equal(zb[4], 0.001) assert_almost_equal(zwt[4], 1.001)
def si(): grid = RasterModelGrid((10, 10), spacing=25) grid.add_ones('soil_water_infiltration__depth', at='node', dtype=float) grid.add_ones('surface_water__depth', at='node') hydraulic_conductivity = (2.5 * (10**-5)) grid.at_node['surface_water__depth'] *= 0.5 grid.at_node['soil_water_infiltration__depth'] *= (10**-5) return SoilInfiltrationGreenAmpt( grid, hydraulic_conductivity=hydraulic_conductivity, soil_bulk_density=1700., rock_density=2650., initial_soil_moisture_content=0.2, soil_type='silt loam', volume_fraction_coarse_fragments=0.6, coarse_sed_flag=False, surface_water_minimum_depth=1.e-7, soil_pore_size_distribution_index=None, soil_bubbling_pressure=None, wetting_front_capillary_pressure_head=None)
def test_simple_surface_leakage(): """test a one-node steady simulation for surface leakage. Notes ---- This test demonstrates that at steady state when no flow is allowed to leave the domain through the subsurface, the surface water flux is equal to the recharge flux. """ grid = RasterModelGrid((3, 3), xy_spacing=1.0) grid.set_closed_boundaries_at_grid_edges(True, True, True, True) grid.add_zeros("aquifer_base__elevation", at="node") grid.add_ones("topographic__elevation", at="node") gdp = GroundwaterDupuitPercolator(grid, recharge_rate=1.0e-6) for _ in range(1000): gdp.run_one_step(1e3) assert_almost_equal(gdp._qs[4], 1e-6)
def test_steady_sp_raster(): """ Initialize HydrologySteadyStreamPower on a raster grid. After one timestep it returns all recharge as discharge. """ mg = RasterModelGrid((3, 3), xy_spacing=10.0) mg.status_at_node[mg.status_at_node == 1] = 4 mg.status_at_node[0] = 1 mg.add_ones("node", "topographic__elevation") mg.add_zeros("node", "aquifer_base__elevation") mg.add_ones("node", "water_table__elevation") gdp = GroundwaterDupuitPercolator(mg, recharge_rate=1e-6) hm = HydrologySteadyStreamPower(mg, groundwater_model=gdp) hm.run_step() assert_almost_equal(hm.q[4], 1e-4) assert_almost_equal(hm.q_an[4], 1e-5)
def test_no_upstream_array(): """Test that correct error is raised when no flow__upstream_node_order.""" # instantiate a model grid, do not run flow accumulation on it mg = RasterModelGrid((30, 70)) # Add a field called topographic__elevation to mg mg.add_ones("node", "topographic__elevation") # Run the FlowDirectorSteepest component fd = FlowDirectorSteepest(mg) fd.run_one_step() # test that the flow distance utility will fail because of a ValueError with pytest.raises(FieldError): calculate_flow__distance(mg)
def test_no_upstream_array(): """Test that correct error is raised when no flow__upstream_node_order.""" # instantiate a model grid, do not run flow accumulation on it mg = RasterModelGrid((30, 70)) # Add a field called topographic__elevation to mg mg.add_ones("topographic__elevation", at="node") # Run the FlowDirectorSteepest component fd = FlowDirectorSteepest(mg) fd.run_one_step() # test that the flow distance utility will fail because of a ValueError with pytest.raises(FieldError): calculate_flow__distance(mg)
#Create data fields zb=mg.add_empty('node','land_surface_elevation') h=mg.add_zeros('node','water_thickness') zw=mg.add_empty('node','water_elevation') w_slope=mg.add_zeros('link','water_slope') #make all links have zero slope q=mg.add_zeros('link','flux') #Initialize elevation zb[:]=zmax-valley_s*mg.node_x zb+=side_s * np.abs(mg.node_y - mg.dx * ((num_rows - 1) / 2.0)) zw[:]=zb+h #Define constants n=0.045 #roughness of bed surface r=mg.add_ones('node','rain_rate') inf=mg.add_ones('node','infiltration_rate') #Boundary conditions (ENWS) mg.set_closed_boundaries_at_grid_edges(False, True, True, True) #water can flow out of right side #Plot setup nplots=10 #number of plots tplot=int(t_max/nplots) #Number of runs imax=len(timearray) #__________RUN___________# for t in range(imax):
def test_raster_cts(): """ Tests instantiation of a RasterCTS and implementation of one transition, with a callback function. """ # Set up a small grid with no events scheduled mg = RasterModelGrid((4, 4)) mg.set_closed_boundaries_at_grid_edges(True, True, True, True) node_state_grid = mg.add_ones("node", "node_state_map", dtype=int) node_state_grid[6] = 0 ns_dict = {0: "black", 1: "white"} xn_list = [] xn_list.append(Transition((1, 0, 0), (0, 1, 0), 0.1, "", True, callback_function)) pd = mg.add_zeros("node", "property_data", dtype=int) pd[5] = 50 ca = RasterCTS( mg, ns_dict, xn_list, node_state_grid, prop_data=pd, prop_reset_value=0 ) # Test the data structures assert ca.num_link_states == 4, "wrong number of link states" assert ca.prop_data[5] == 50, "error in property data" assert ca.num_node_states == 2, "error in num_node_states" assert ca.link_orientation[-1] == 0, "error in link orientation array" assert ca.link_state_dict[(1, 0, 0)] == 2, "error in link state dict" assert ca.n_trn[2] == 1, "error in n_trn" assert ca.node_pair[1] == (0, 1, 0), "error in cell_pair list" assert len(ca.priority_queue._queue) == 1, "event queue has wrong size" assert ca.next_trn_id.size == 24, "wrong size next_trn_id" assert ca.trn_id.shape == (4, 1), "wrong size for trn_to" assert ca.trn_id[2][0] == 0, "wrong value in trn_to" assert ca.trn_to[0] == 1, "wrong trn_to state" assert ca.trn_rate[0] == 0.1, "wrong trn rate" assert ca.trn_propswap[0] == 1, "wrong trn propswap" assert ca.trn_prop_update_fn == callback_function, "wrong prop upd" # Manipulate the data in the event queue for testing: # pop the scheduled event off the queue (event_time, index, event_link) = ca.priority_queue.pop() assert ca.priority_queue._queue == [], "event queue should now be empty but is not" # engineer an event ca.priority_queue.push(8, 1.0) ca.next_update[8] = 1.0 ca.next_trn_id[8] = 0 # run the CA ca.run(2.0) # some more tests. # Is current time advancing correctly? (should only go to 1.0, not 2.0) # Did the two nodes (5 and 6) correctly exchange states? # Did the property ID and data arrays get updated? Note that the "propswap" # should switch propids between nodes 5 and 6, and the callback function # should increase the value of prop_data in the "swap" node from 50 to 150. assert ca.current_time == 1.0, "current time incorrect" assert ca.node_state[5] == 0, "error in node state 5" assert ca.node_state[6] == 1, "error in node state 6"
def test_raster_cts(): """ Tests instantiation of a RasterCTS and implementation of one transition, with a callback function. """ # Set up a small grid with no events scheduled mg = RasterModelGrid(4, 4, 1.0) mg.set_closed_boundaries_at_grid_edges(True, True, True, True) node_state_grid = mg.add_ones('node', 'node_state_map', dtype=int) node_state_grid[6] = 0 ns_dict = { 0 : 'black', 1 : 'white' } xn_list = [] xn_list.append( Transition((1,0,0), (0,1,0), 0.1, '', True, callback_function)) pd = mg.add_zeros('node', 'property_data', dtype=int) pd[5] = 50 ca = RasterCTS(mg, ns_dict, xn_list, node_state_grid, prop_data=pd, prop_reset_value=0) # Test the data structures assert (ca.xn_to.size==4), 'wrong size for xn_to' assert (ca.xn_to.shape==(4, 1)), 'wrong size for xn_to' assert (ca.xn_to[2][0]==1), 'wrong value in xn_to' assert (len(ca.event_queue)==1), 'event queue has wrong size' assert (ca.num_link_states==4), 'wrong number of link states' assert (ca.prop_data[5]==50), 'error in property data' assert (ca.xn_rate[2][0]==0.1), 'error in transition rate array' assert (ca._active_links_at_node[1][6]==8), 'error in active link array' assert (ca.num_node_states==2), 'error in num_node_states' assert (ca.link_orientation[-1]==0), 'error in link orientation array' assert (ca.link_state_dict[(1, 0, 0)]==2), 'error in link state dict' assert (ca.n_xn[2]==1), 'error in n_xn' assert (ca.node_pair[1]==(0, 1, 0)), 'error in cell_pair list' # Manipulate the data in the event queue for testing: # pop the scheduled event off the queue ev = heappop(ca.event_queue) assert (ca.event_queue==[]), 'event queue should now be empty but is not' # engineer an event ev.time = 1.0 ev.link = 8 ev.xn_to = 1 ev.propswap = True ev.prop_update_fn = callback_function ca.next_update[8] = 1.0 # push it onto the event queue heappush(ca.event_queue, ev) # run the CA ca.run(2.0) # some more tests. # Is current time advancing correctly? (should only go to 1.0, not 2.0) # Did the two nodes (5 and 6) correctly exchange states? # Did the property ID and data arrays get updated? Note that the "propswap" # should switch propids between nodes 5 and 6, and the callback function # should increase the value of prop_data in the "swap" node from 50 to 150. assert (ca.current_time==1.0), 'current time incorrect' assert (ca.node_state[5]==0), 'error in node state 5' assert (ca.node_state[6]==1), 'error in node state 6'