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_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 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)
# 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. if elapsed_time < storm_duration: of.rainfall_intensity = 4.07222 * (10**-7) # Rainfall intensity (m/s) # Then the elapsed time exceeds the storm duration, rainfall ceases. else: of.rainfall_intensity = 0.0 # Generating overland flow based on the deAlmeida solution. of.overland_flow() # Append time and discharge to their lists to save data and for plotting. hydrograph_time_sec.append(elapsed_time) hydrograph_time_hrs.append(round(elapsed_time / 3600., 2)) discharge_at_outlet.append(of.q[link_to_sample]) # Add the time step, repeat until elapsed time >= model_run_time print(elapsed_time) elapsed_time += of.dt plt.figure(1) plt.imshow(z.reshape(rmg.shape), origin="left", cmap="pink") plt.tick_params(axis="both", labelbottom="off", labelleft="off") cb = plt.colorbar() cb.set_label("Elevation (m)", rotation=270, labelpad=15)
left_inactive_ids = links.left_edge_horizontal_ids(rmg.shape) # Let's see how long this run takes... starttime = time() while elapsed_time < run_time: # Now we are going to set the left edge horizontal links to their # neighboring discharge value rmg["link"]["surface_water__discharge"][left_inactive_ids] = rmg["link"][ "surface_water__discharge" ][left_inactive_ids + 1] # Now, we can generate overland flow. of.overland_flow() # Recalculate water depth at the boundary ... # water depth at left side (m) h_boundary = ( seven_over_three * n * n * u * u * u * elapsed_time ) ** three_over_seven # And now we input that water depth along the left-most interior column, # in all rows that are not boundary rows. rmg.at_node["surface_water__depth"][inside_left_edge] = h_boundary # Increased elapsed time elapsed_time += of.dt
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