Example #1
0
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)
Example #2
0
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)})
Example #7
0
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.
Example #9
0
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:
Example #10
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.
Example #11
0
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)
Example #13
0
# 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()
Example #14
0
## 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:

Example #15
0
    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)
Example #16
0
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