def test_deAlm_analytical_imposed_dt_short(): grid = RasterModelGrid((32, 240), xy_spacing=25) grid.add_zeros("surface_water__depth", at="node") grid.add_zeros("topographic__elevation", at="node") grid.set_closed_boundaries_at_grid_edges(True, True, True, True) left_inactive_ids = _left_edge_horizontal_ids(grid.shape) deAlm = OverlandFlow(grid, mannings_n=0.01, h_init=0.001) time = 0.0 while time < 500.0: grid.at_link["surface_water__discharge"][ left_inactive_ids] = grid.at_link["surface_water__discharge"][ left_inactive_ids + 1] dt = 10.0 deAlm.overland_flow(dt) h_boundary = ((7.0 / 3.0) * (0.01**2) * (0.4**3) * time)**(3.0 / 7.0) grid.at_node["surface_water__depth"][grid.nodes[1:-1, 1]] = h_boundary time += dt x = np.arange(0, ((grid.shape[1]) * grid.dx), grid.dx) h_analytical = -(7.0 / 3.0) * (0.01**2) * (0.4**2) * (x - (0.4 * 500)) h_analytical[np.where(h_analytical > 0)] = h_analytical[np.where( h_analytical > 0)]**(3.0 / 7.0) h_analytical[np.where(h_analytical < 0)] = 0.0 hdeAlm = deAlm.h.reshape(grid.shape) hdeAlm = hdeAlm[1][1:] hdeAlm = np.append(hdeAlm, [0]) np.testing.assert_almost_equal(h_analytical, hdeAlm, decimal=1)
def run_day(mg, precipitation: float, duration=1800): """ Calculates the mm of water that has infiltrated into soil after a rainfall event. Rainfall events are assumed to be instantaneous and constant over the model grid. :param dem: model grid :param precipitation: rainfall in mm/hr :param duration: seconds of rainfall :return: mm of water infiltrated into the soil at every coordinate in the grid """ elapsed_time = 0.0 swd = mg.add_zeros('surface_water__depth', at='node', clobber=True) swd += precipitation swid = mg.add_zeros('soil_water_infiltration__depth', at='node', clobber=True) swid += 1e-6 siga = SoilInfiltrationGreenAmpt(mg) of = OverlandFlow(mg, steep_slopes=True) while elapsed_time < duration: dt = of.calc_time_step() dt = dt if dt + elapsed_time < duration else duration - elapsed_time of.run_one_step(dt=dt) siga.run_one_step(dt=dt) elapsed_time += dt return xr.DataArray(mg.at_node['soil_water_infiltration__depth'].reshape( mg.shape), dims=('x', 'y'))
def test_deAlm_analytical(): from landlab import RasterModelGrid grid = RasterModelGrid((32, 240), spacing = 25) grid.add_zeros('node', 'surface_water__depth') grid.add_zeros('node', 'topographic__elevation') grid.set_closed_boundaries_at_grid_edges(True, True, True, True) left_inactive_ids = left_edge_horizontal_ids(grid.shape) deAlm = OverlandFlow(grid, mannings_n=0.01, h_init=0.001) time = 0.0 while time < 500.: grid['link']['surface_water__discharge'][left_inactive_ids] = ( grid['link']['surface_water__discharge'][left_inactive_ids + 1]) dt = deAlm.calc_time_step() deAlm.overland_flow(dt) h_boundary = (((7./3.) * (0.01**2) * (0.4**3) * time) ** (3./7.)) grid.at_node['surface_water__depth'][grid.nodes[1: -1, 1]] = h_boundary time += dt x = np.arange(0, ((grid.shape[1]) * grid.dx), grid.dx) h_analytical = (-(7./3.) * (0.01**2) * (0.4**2) * (x - (0.4 * 500))) h_analytical[np.where(h_analytical > 0)] = (h_analytical[np.where( h_analytical > 0)] ** (3./7.)) h_analytical[np.where(h_analytical < 0)] = 0.0 hdeAlm = deAlm.h.reshape(grid.shape) hdeAlm = hdeAlm[1][1:] hdeAlm = np.append(hdeAlm, [0]) np.testing.assert_almost_equal(h_analytical, hdeAlm, decimal=1)
def test_deAlm_analytical(): from landlab import RasterModelGrid grid = RasterModelGrid((32, 240), spacing=25) grid.add_zeros('node', 'water__depth') grid.add_zeros('node', 'topographic__elevation') grid.set_closed_boundaries_at_grid_edges(True, True, True, True) left_inactive_ids = left_edge_horizontal_ids(grid.shape) deAlm = OverlandFlow(grid, mannings_n=0.01, h_init=0.001) time = 0.0 while time < 500: grid['link']['water__discharge'][left_inactive_ids] = ( grid['link']['water__discharge'][left_inactive_ids + 1]) dt = deAlm.calc_time_step() deAlm.overland_flow(dt) h_boundary = (((7. / 3.) * (0.01**2) * (0.4**3) * time)**(3. / 7.)) grid.at_node['water__depth'][grid.nodes[1:-1, 1]] = h_boundary time += dt x = np.arange(0, ((grid.shape[1]) * grid.dx), grid.dx) h_analytical = (-(7. / 3.) * (0.01**2) * (0.4**2) * (x - (0.4 * 500))) h_analytical[np.where(h_analytical > 0)] = (h_analytical[np.where( h_analytical > 0)]**(3. / 7.)) h_analytical[np.where(h_analytical < 0)] = 0.0 hdeAlm = deAlm.h.reshape(grid.shape) hdeAlm = hdeAlm[1][1:] hdeAlm = np.append(hdeAlm, [0]) np.testing.assert_almost_equal(h_analytical, hdeAlm, decimal=1)
def test_deAlm_analytical_imposed_dt_short(): grid = RasterModelGrid((32, 240), xy_spacing=25) grid.add_zeros("node", "surface_water__depth") grid.add_zeros("node", "topographic__elevation") grid.set_closed_boundaries_at_grid_edges(True, True, True, True) left_inactive_ids = left_edge_horizontal_ids(grid.shape) deAlm = OverlandFlow(grid, mannings_n=0.01, h_init=0.001) time = 0.0 while time < 500.0: grid.at_link["surface_water__discharge"][left_inactive_ids] = grid.at_link[ "surface_water__discharge" ][left_inactive_ids + 1] dt = 10.0 deAlm.overland_flow(dt) h_boundary = ((7.0 / 3.0) * (0.01 ** 2) * (0.4 ** 3) * time) ** (3.0 / 7.0) grid.at_node["surface_water__depth"][grid.nodes[1:-1, 1]] = h_boundary time += dt x = np.arange(0, ((grid.shape[1]) * grid.dx), grid.dx) h_analytical = -(7.0 / 3.0) * (0.01 ** 2) * (0.4 ** 2) * (x - (0.4 * 500)) h_analytical[np.where(h_analytical > 0)] = h_analytical[ np.where(h_analytical > 0) ] ** (3.0 / 7.0) h_analytical[np.where(h_analytical < 0)] = 0.0 hdeAlm = deAlm.h.reshape(grid.shape) hdeAlm = hdeAlm[1][1:] hdeAlm = np.append(hdeAlm, [0]) np.testing.assert_almost_equal(h_analytical, hdeAlm, decimal=1)
def setup_grid(): from landlab import RasterModelGrid grid = RasterModelGrid((32, 240), spacing=25) grid.add_zeros('node', 'water__depth') grid.add_zeros('node', 'topographic__elevation') grid.add_zeros('water__discharge', at='active_link') deAlm = OverlandFlow(grid, mannings_n=0.01, h_init=0.001) globals().update({'deAlm': OverlandFlow(grid)})
def deAlm(): grid = RasterModelGrid((32, 240), xy_spacing=25) grid.add_zeros("surface_water__depth", at="node") grid.add_zeros("topographic__elevation", at="node") grid.add_zeros("surface_water__discharge", at="link") return OverlandFlow(grid, mannings_n=0.01, h_init=0.001)
hydrograph_time_hrs = [] # Setting initial fields... rmg["node"]["topographic__elevation"] = z rmg["link"]["surface_water__discharge"] = np.zeros(rmg.number_of_links) rmg["node"]["surface_water__depth"] = np.zeros(rmg.number_of_nodes) # and fixed link boundary conditions... rmg.set_fixed_link_boundaries_at_grid_edges( True, True, True, True, fixed_link_value_of="surface_water__discharge") # Setting the outlet node to OPEN_BOUNDARY rmg.status_at_node[100] = 1 # Initialize the OverlandFlow() class. of = OverlandFlow(rmg, use_fixed_links=True, steep_slopes=True) # Record the start time so we know how long it runs. start_time = time.time() # Link to sample at the outlet link_to_sample = 299 # Storm duration in seconds storm_duration = 7200.0 # Running the overland flow component. while elapsed_time < model_run_time: # The storm starts when the model starts. While the elapsed time is less # than the storm duration, we add water to the system as rainfall.
infBandWidthNorm = 0.5 infBandWidth = length * dx / 2 * infBandWidthNorm channel_left = (length * dx + channel_width) / 2 channel_right = (length * dx - channel_width) / 2 isChannel = np.logical_and(rmg.x_of_node < channel_left, rmg.x_of_node > channel_right) highInfBand = np.logical_and(rmg.x_of_node < channel_left + infBandWidth, rmg.x_of_node > channel_right - infBandWidth) inf_mask = np.logical_xor(highInfBand, isChannel) hc[inf_mask] *= 10 of = OverlandFlow(rmg, steep_slopes=True) SI = SoilInfiltrationGreenAmpt(rmg, hydraulic_conductivity=hc) elapsed_time = 0 run_time = 1e4 iters = 0 while elapsed_time < run_time: # First, we calculate our time step. dt = of.calc_time_step() # Now, we can generate overland flow. of.overland_flow() SI.run_one_step(dt) # Increased elapsed time if iters % 1000 == 0:
rmg.set_closed_boundaries_at_grid_edges(True, True, True, True) # Create fields in the grid for topographic elevation, water depth, discharge. rmg.add_zeros('topographic__elevation', at='node') # topographic elevation (m) rmg.add_zeros('water__depth', at='node') # water depth (m) rmg.add_zeros('water__discharge', at='link') # unit discharge (m2/s) # Add our initial thin layer of water to the field of water depth. #rmg['node']['water_depth'] += h_init # Now we'll identify our leftmost, but interior, column and the IDs of those # nodes. One column in to prevent issues with BC. inside_left_edge = rmg.nodes[1:-1, 1] # Initializing our class... of = OverlandFlow(rmg, mannings_n=n, theta=0.8, h_init=0.001) # Now, we need to set a fixed value on the left edge, so we find the # link neighbor arrays... of.set_up_neighbor_arrays() # ... and get a list of all horizonal ids, not just active ids (which is what # the deAlmeida solution uses) all_horizontal_ids = links.horizontal_link_ids(rmg.shape) # from there, we are going to reset our west neighbor array... of.west_neighbors = (links.horizontal_west_link_neighbor( rmg.shape, all_horizontal_ids)) # and find the ids of the arrays along the west edge of the grid. We actually # will set the discharge values here at every time step in the loop.
def deAlm(): grid = RasterModelGrid((32, 240), spacing=25) grid.add_zeros('surface_water__depth', at='node') grid.add_zeros('topographic__elevation', at='node') grid.add_zeros('surface_water__discharge', at='link') return OverlandFlow(grid, mannings_n=0.01, h_init=0.001)
rmg.set_closed_boundaries_at_grid_edges(True, True, True, True) # Create fields in the grid for topographic elevation, water depth, discharge. rmg.add_zeros("topographic__elevation", at="node") # topographic elevation (m) rmg.add_zeros("surface_water__depth", at="node") # water depth (m) rmg.add_zeros("surface_water__discharge", at="link") # unit discharge (m2/s) # Add our initial thin layer of water to the field of water depth. # rmg['node']['surface_water__depth'] += h_init # Now we'll identify our leftmost, but interior, column and the IDs of those # nodes. One column in to prevent issues with BC. inside_left_edge = rmg.nodes[1:-1, 1] # Initializing our class... of = OverlandFlow(rmg, mannings_n=n, theta=0.8, h_init=0.001) # Now, we need to set a fixed value on the left edge, so we find the # link neighbor arrays... of.set_up_neighbor_arrays() # ... and get a list of all horizonal ids, not just active ids (which is what # the deAlmeida solution uses) all_horizontal_ids = links.horizontal_link_ids(rmg.shape) # from there, we are going to reset our west neighbor array... of.west_neighbors = links.horizontal_west_link_neighbor(rmg.shape, all_horizontal_ids) # and find the ids of the arrays along the west edge of the grid. We actually # will set the discharge values here at every time step in the loop. left_inactive_ids = links.left_edge_horizontal_ids(rmg.shape)
# DEM, depth, and discharge assignment rmg['node']['topographic__elevation'] = z rmg.add_zeros('node', 'surface_water__depth') rmg.add_zeros('node', 'surface_water__discharge') # Assign the outlet and boundary conditions print("\tSetting Boundary Conditions...") # If more than one outlet, errors out and show which outlets # outlet_id = rmg.set_watershed_boundary_condition(z.flatten(), nodata_value=-9999, return_outlet_id=True) outlet_id = 2615 rmg.set_watershed_boundary_condition_outlet_id(outlet_id, z.flatten()) # Object for managing the simulation of = OverlandFlow(rmg, mannings_n=0.03, steep_slopes=True) # Flow Routing print("\tProcessing DEM for routing...") sf = SinkFiller(rmg, routing='D4', apply_slope=False, fill_slope=1.e-5) print("\tFilling pits...") #sf.fill_pits() print("\tOutputting topo from Landlab...") write_netcdf('ll_topo.nc', rmg, names=['topographic__elevation']) ################################# FLOW SIM ##################################### # Show the user whats going on with the progress print()
## Setting initial fields... rmg['node']['topographic__elevation'] = z rmg['link']['surface_water__discharge'] = np.zeros(rmg.number_of_links) rmg['node']['surface_water__depth'] = np.zeros(rmg.number_of_nodes) ## and fixed link boundary conditions... rmg.set_fixed_link_boundaries_at_grid_edges(True, True, True, True, fixed_link_value_of='surface_water__discharge') ## Setting the outlet node to OPEN_BOUNDARY rmg.status_at_node[100] = 1 ## Initialize the OverlandFlow() class. of = OverlandFlow(rmg, use_fixed_links = True, steep_slopes=True) ## Record the start time so we know how long it runs. start_time = time.time() ## Link to sample at the outlet link_to_sample = 299 ## Storm duration in seconds storm_duration = 7200.0 ## Running the overland flow component. while elapsed_time < model_run_time:
def reset(self): """ Reset function. Resets the world to its initial state. """ super(FloodWorld, self).reset() # Terrain generation shape = (self.grid_size,) * 2 size = self.grid_size * self.grid_size # Set initial simple topography z = self.vertical_scale * self.simple_topography(shape) # Create raster model if it does not exist if self.mg is None: self.mg = RasterModelGrid(shape, int(round(self.world_size/self.grid_size))) self.mg.set_closed_boundaries_at_grid_edges(True, True, True, True) self.z = self.mg.add_field('node', 'topographic__elevation', z) self.swd = self.mg.add_zeros('node', 'surface_water__depth') else: self.mg.at_node['topographic__elevation'] = z self.swd[:] = np.zeros(size) import matplotlib.pyplot as plt plt.figure() from landlab.plot import imshow_grid imshow_grid(self.mg, 'topographic__elevation', colorbar_label='m') plt.draw() # Set evolution parameters uplift_rate = self.inputs['uplift_rate'] total_t = self.inputs['total_time'] dt = self.inputs['dt'] nt = int(total_t // dt) # Loops uplift_per_step = uplift_rate * dt self.fr = FlowAccumulator(self.mg, **self.inputs) self.sp = FastscapeEroder(self.mg, **self.inputs) # Erode terrain for i in range(nt): self.fr.run_one_step() # Not time sensitive self.sp.run_one_step(dt) self.mg.at_node['topographic__elevation'][self.mg.core_nodes] += uplift_per_step # add the uplift if i % 10 == 0: print('Erode: Completed loop %d' % i) plt.figure() imshow_grid(self.mg, 'topographic__elevation', colorbar_label='m') plt.draw() plt.show() # Setup surface water flow self.of = OverlandFlow(self.mg, steep_slopes=True, mannings_n=0.01) # Setup initial flood self.swd[[5050, 5051, 5150, 5151]] += self.h_init self.active = np.greater(np.flip(np.reshape(self.swd, shape), axis=0), self.flood_threshold)
class FloodWorld(ActiveCellWorld): """ FloodWorld class. This ActiveCellWorld implementation uses Landlab to simulate floods. :param world_size: :param grid_size: :param torus: :param agent_dynamic: """ def __init__(self, world_size, grid_size, torus, agent_dynamic): super(FloodWorld, self).__init__(world_size, grid_size, torus, agent_dynamic) # World generation parameters self.vertical_scale = 200 # (m) self.inputs = {'nrows': 100, 'ncols': 100, 'dx': 0.02, 'dt': 0.5, 'total_time': 50.0, 'uplift_rate': 0.001, 'K_sp': 0.3, 'm_sp': 0.5, 'n_sp': 1.0, 'rock_density': 2.7, 'sed_density': 2.7, 'linear_diffusivity': 0.0001} # Flood parameters self.h_init = 5 # initial thin layer of water (m) self.n = 0.01 # roughness coefficient, (s/m^(1/3)) self.alpha = 0.7 # time-step factor (nondimensional; from Bates et al., 2010) self.u = 0.4 # constant velocity (m/s, de Almeida et al., 2012) self.cell_update_period = 10 # (s) self.mg = None self.fr = None self.sp = None self.of = None self.swd = None self.z = None self.flood_threshold = 0.05 # minimum water depth detected as flood (m) def reset(self): """ Reset function. Resets the world to its initial state. """ super(FloodWorld, self).reset() # Terrain generation shape = (self.grid_size,) * 2 size = self.grid_size * self.grid_size # Set initial simple topography z = self.vertical_scale * self.simple_topography(shape) # Create raster model if it does not exist if self.mg is None: self.mg = RasterModelGrid(shape, int(round(self.world_size/self.grid_size))) self.mg.set_closed_boundaries_at_grid_edges(True, True, True, True) self.z = self.mg.add_field('node', 'topographic__elevation', z) self.swd = self.mg.add_zeros('node', 'surface_water__depth') else: self.mg.at_node['topographic__elevation'] = z self.swd[:] = np.zeros(size) import matplotlib.pyplot as plt plt.figure() from landlab.plot import imshow_grid imshow_grid(self.mg, 'topographic__elevation', colorbar_label='m') plt.draw() # Set evolution parameters uplift_rate = self.inputs['uplift_rate'] total_t = self.inputs['total_time'] dt = self.inputs['dt'] nt = int(total_t // dt) # Loops uplift_per_step = uplift_rate * dt self.fr = FlowAccumulator(self.mg, **self.inputs) self.sp = FastscapeEroder(self.mg, **self.inputs) # Erode terrain for i in range(nt): self.fr.run_one_step() # Not time sensitive self.sp.run_one_step(dt) self.mg.at_node['topographic__elevation'][self.mg.core_nodes] += uplift_per_step # add the uplift if i % 10 == 0: print('Erode: Completed loop %d' % i) plt.figure() imshow_grid(self.mg, 'topographic__elevation', colorbar_label='m') plt.draw() plt.show() # Setup surface water flow self.of = OverlandFlow(self.mg, steep_slopes=True, mannings_n=0.01) # Setup initial flood self.swd[[5050, 5051, 5150, 5151]] += self.h_init self.active = np.greater(np.flip(np.reshape(self.swd, shape), axis=0), self.flood_threshold) def update_cells(self): """ Update cells function. Updates water level and cell status. """ self.of.overland_flow(dt=self.cell_update_period) shape = (self.grid_size,) * 2 self.active = np.greater(np.flip(np.reshape(self.swd, shape), axis=0), self.flood_threshold) @staticmethod def noise_octave(shape, f): """ Noise octave function. Generates a noise map. :param shape: (array) shape of the map. :param f: (float) frequency bounds parameter. """ return te3w_util.fbm(shape, -1, lower=f, upper=(2 * f)) def simple_topography(self, shape): """ Simple topography function. Generates an elevation map. :param shape: (array) shape of the map. """ values = np.zeros(shape) for p in range(1, 10): a = 2 ** p values += np.abs(self.noise_octave(shape, a) - 0.5) / a result = (1.0 - te3w_util.normalize(values)) ** 2 return result