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.

2 Comments

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.