Flood simulation from direct rainfall with Python and Landlab - Tutorial

Simulation of direct precipitation events over a surface is important to assess the impacted areas and manage disaster situations. Response to precipitation is evaluated over cells in a 2D model and runoff is routed to the stream networks. Landlab is a Python library for a variety of surface processes and can model shallow water flow over topography with a variety of algorithms. We have developed an applied case of direct rainfall for flood modeling over a geospatial raster where an initial water height is applied and then flows over the surface. Resulting water heights are exported as geospatial rasters.

Tutorial


Code

# import generic packages
import numpy as np
from matplotlib import pyplot as plt

# import geospatial packages
import rasterio
from rasterio.plot import show
from shapely.geometry import LineString
import geopandas as gpd

# import landlab components
from landlab import RasterModelGrid, imshow_grid
from landlab.components.overland_flow import OverlandFlow
# Open raster image 
rasterObj = rasterio.open('../rst/ASTGTMV003_N32W098_dem_utm_clip.tif')
show(rasterObj)
<Axes: >
#extract array from raster
elevArray = rasterObj.read(1)
plt.imshow(elevArray)
<matplotlib.image.AxesImage at 0x1f9ea505880>
#create grid from raster attributes
nrows = rasterObj.height  # number of raster cells on each side, initially 150
ncols = rasterObj.width
dxy = (rasterObj.transform.a,-rasterObj.transform.e)  # side length of a raster model cell, or resolution [m], initially 50

# define a landlab raster
mg = RasterModelGrid(shape=(nrows, ncols), 
                     xy_spacing=dxy,
                     #xy_of_lower_left=(rasterObj.bounds[0],rasterObj.bounds[1]))
                     xy_of_lower_left=(0,0))

# show number of rows, cols and resolution
print(nrows, ncols, dxy)
830 1479 (8.350287626774987, 10.497077108433762)
# create a dataset of zero values
zr = mg.add_zeros("topographic__elevation", at="node")

# apply cell elevation to defined arrray
zr += elevArray[::-1,:].ravel()

imshow_grid(mg, "topographic__elevation", shrink=0.5)
#set and apply and initial height
initialHeight = 0.1
depthArray = np.ones(elevArray.shape)*initialHeight
mg.at_node["surface_water__depth"] = depthArray
#define the flood objeds
of = OverlandFlow(mg, steep_slopes=True)

#list to store times
dtList = []
#Run once and store elapsed time
of.run_one_step()
dtList.append(of.dt)
print(of.dt)
5.902247591953301
# explore the output data and location

# model outputs
print(of.output_var_names)

# where this nodes are locates
print(of.var_loc("surface_water__depth"))

# show the water depth array
print(mg.at_node["surface_water__depth"])
('surface_water__depth', 'surface_water__discharge', 'water_surface__gradient')
node
[0.10001 0.10001 0.10001 ... 0.10001 0.10001 0.10001]
# plot the resulting water depth for the first run
imshow_grid(mg, "surface_water__depth", shrink=0.5)
# run the model for 100 time steps
for i in range(100):
    of.run_one_step()
    dtList.append(of.dt)
    print("Time step: %.2f seconds. Elapsed time %.2f seconds"%(of.dt,sum(dtList)))
Time step: 1.21 seconds. Elapsed time 147.52 seconds
Time step: 1.21 seconds. Elapsed time 148.73 seconds
Time step: 1.21 seconds. Elapsed time 149.93 seconds
Time step: 1.21 seconds. Elapsed time 151.14 seconds
Time step: 1.20 seconds. Elapsed time 152.34 seconds
Time step: 1.20 seconds. Elapsed time 153.54 seconds
Time step: 1.20 seconds. Elapsed time 154.74 seconds
# plot the resulting water depth for the 101th run
imshow_grid(mg, "surface_water__depth", shrink=0.5)
#convert the resulting data to a numpy array
zArray = mg.at_node["surface_water__depth"].reshape((nrows,ncols))[::-1,:]
#plot the array
plt.imshow(zArray)
<matplotlib.image.AxesImage at 0x1f9c5579250>
# Write the array to a new GeoTIFF file
with rasterio.open(
        '../Out/floodSurfaceDepth.tif',
        'w',
        driver='GTiff',
        height=rasterObj.height,
        width=rasterObj.width,
        count=1,  # number of bands
        dtype=zArray.dtype,
        crs=rasterObj.crs,
        transform=rasterObj.transform
) as dst:
    dst.write(zArray, 1)  # write the data to the first band
# Show the resulting raster
floodObj = rasterio.open('../Out/floodSurfaceDepth.tif')
show(floodObj)

Input data

You can download the input data from this link.

Comment

Saul Montoya

Saul Montoya es Ingeniero Civil graduado de la Pontificia Universidad Católica del Perú en Lima con estudios de postgrado en Manejo e Ingeniería de Recursos Hídricos (Programa WAREM) de la Universidad de Stuttgart con mención en Ingeniería de Aguas Subterráneas y Hidroinformática.

 

Suscribe to our online newsletter

Subscribe for free newsletter, receive news, interesting facts and dates of our courses in water resources.