{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Exploring rainfall driven hydrographs with Landlab\n", "This notebook was developed from code written by Jordan Adams as part of her PhD disseration at Tulane University. This notebook was created by Nicole Gasparini at Tulane University." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "For tutorials on learning Landlab, click here: https://github.com/landlab/landlab/wiki/Tutorials\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**What is this notebook?**\n", "\n", "This notebook illustrates the importance of watershed shape and rainfall intensity and duration on the characteristics of hydrographs. \n", "\n", "To clearly contrast landscape shape, this notebook uses two synthetic landscapes, or landscapes produced using a landscape evolution model. One landscape is square (length = width) and one is rectangular (length = 4*width). Both landscapes have a drainage area of 36 km$^2$ and a cell size of 30 m.\n", "\n", "Overland flow is modeled as a diffusive approximation of the shallow water equation. (If you do not understand what that means, you can still learn from this notebook.) No infiltration is modeled. Rain falls on the landscape and flows downhill, driving overland flow and a hydrograph at every location on the landscape. In this notebook, we track the hydrograph at three points in the watershed.\n", "\n", "Before using this notebook you should have learned about overland flow and a hydrograph. You should know the terms rainfall intensity and duration, as well as peak discharge, hydrograph time to peak, rising limb, and falling limb. For example, these concepts are covered in Chapter 10 of:\n", "\n", "Dingman, S.L., 2015. Physical hydrology, third edition. Waveland press.\n", "\n", "More background on the model used here and the results presented can be found in:\n", "\n", "Adams, J.M., Gasparini, N.M., Hobley, D.E., Tucker, G.E., Hutton, E.W., Nudurupati, S.S. and Istanbulluoglu, E., 2017. The Landlab v1. 0 OverlandFlow component: a Python tool for computing shallow-water flow across watersheds. Geoscientific Model Development.\n", "\n", "The code used in this exercise is taken from the above Adams et al., (2017) reference.\n", "\n", "**What will you do?** \n", "\n", "You will run this model several times, changing the rainfall characteristics or watershed on which flow is routed. You will generate hydrographs and learn how different parameters affect hydrograph characteristics.\n", "\n", "Start at the top by reading each block of text and sequentially running each code block (put your curser in a code block and type shift - enter OR got to the _Cell_ pulldown menu at the top and choose _Run Cells_). \n", "\n", "Remember that you can always go to the _Kernel_ pulldown menu at the top and choose _Restart & Clear Output_ or _Restart & Run All_ if you change things and want to start afresh. \n", "\n", "**Questions to answer before running this notebook.**\n", "\n", "1. Do you think that watershed shape affects hydrograph shape? Consider two watersheds, one that is square and one that is rectangular with a width to length ratio of 1 to 4. Both watersheds have the same drainage area. If the same amount of rain falls uniformly across each landscape, will it affect the time to peak and peak discharge at the outlet?\n", "2. Do you think that the rainfall intensity impacts the time to peak and peak discharge at a watershed outlet? If so, how?\n", "3. Do you think that the rainfall duration impacts the time to peak and peak discharge at a watershed outlet? If so, how?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Now on to the code.**\n", "* Below we import Landlab components, functions for importing data, numpy and plotting tools. You should not need to change this." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## only needed for plotting in a jupyter notebook.\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 1\n", "\n", "import copy\n", "\n", "import numpy as np\n", "from matplotlib import pyplot as plt\n", "\n", "from landlab import imshow_grid\n", "from landlab.components import OverlandFlow, FlowAccumulator\n", "from landlab.io import read_esri_ascii" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we import the data for the watershed we want to route flow on. **You will want to change this code block for the different scenarios. Initially you do not need to change anything.**\n", "\n", "* The user can change the `basin_flag` to equal `Square` or `Long` depending on the watershed to run.\n", " * The outlet link for each watershed was pretermined for plotting purposes.\n", "* The user can also choose which storm to run. \n", " * `Base` has an intensity of 5.0 mm/hr, with a duration of 2 hr.\n", " * `HigherIntensity` has an intensity of 10.0 mm/hr, with a duration of 1 hr.\n", " * `LongerDuration` has an intensity of 2.5 mm/hr, with a duration of 4 hr." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 2\n", "\n", "basin_flag = \"Square\" # 'Square' or Long'\n", "storm_flag = \"Base\" # 'Base' or'HigherIntensity' or 'LongerDuration'\n", "\n", "## If the basin flag matches one of the two select basins,\n", "## below will set the filename which to read the DEM from and\n", "## the outlet link and upstream link to sample discharge values\n", "## from for plotting.\n", "\n", "if basin_flag == \"Square\":\n", " watershed_dem = \"Square_TestBasin.asc\"\n", " ## Reading in the DEM given the filename from above\n", " (rmg, z) = read_esri_ascii(watershed_dem, name=\"topographic__elevation\")\n", " outlet_node_to_sample = 300\n", " outlet_link_to_sample = rmg.links_at_node[outlet_node_to_sample][3]\n", " upstream_node_to_sample = 28689\n", " upstream_link_to_sample = rmg.links_at_node[upstream_node_to_sample][3]\n", " midstream_node_to_sample = 9102\n", " midstream_link_to_sample = rmg.links_at_node[midstream_node_to_sample][3]\n", "else:\n", " watershed_dem = \"Long_TestBasin.asc\"\n", " ## Reading in the DEM given the filename from above\n", " (rmg, z) = read_esri_ascii(watershed_dem, name=\"topographic__elevation\")\n", " outlet_node_to_sample = 150\n", " outlet_link_to_sample = rmg.links_at_node[outlet_node_to_sample][3]\n", " upstream_node_to_sample = 33859\n", " upstream_link_to_sample = rmg.links_at_node[upstream_node_to_sample][3]\n", " midstream_node_to_sample = 14658\n", " midstream_link_to_sample = rmg.links_at_node[midstream_node_to_sample][2]\n", "\n", "## The Flow Router calculates drainage area, which is helpful for\n", "## calculating equilibrium discharge, which we illustrate later.\n", "fr = FlowAccumulator(rmg) # Instantiate flow router\n", "fr.run_one_step() # Drainage area calculated" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we set the boundary conditions, initialize the process components, and set the appropriate storm parameters." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 3\n", "\n", "## Set boundary coditions on the grid\n", "rmg.set_watershed_boundary_condition(z)\n", "\n", "## instantiate OverlandFlow object\n", "rmg.add_zeros(\"surface_water__depth\", at=\"node\")\n", "of = OverlandFlow(rmg, alpha=0.45, steep_slopes=True)\n", "\n", "## Assign storm conditions based on flag in Code Block 2\n", "if storm_flag == \"Base\":\n", " starting_precip_mmhr = 5.0\n", " starting_precip_ms = starting_precip_mmhr * (2.77778 * 10 ** -7)\n", " storm_duration = 7200.0\n", "elif storm_flag == \"HigherIntensity\":\n", " starting_precip_mmhr = 10.0\n", " starting_precip_ms = starting_precip_mmhr * (2.77778 * 10 ** -7)\n", " storm_duration = 3600.0\n", "elif storm_flag == \"LongerDuration\":\n", " starting_precip_mmhr = 2.5\n", " starting_precip_ms = starting_precip_mmhr * (2.77778 * 10 ** -7)\n", " storm_duration = 14400.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before we go further, let's pause to look at the landscape that we will be routing flow over." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 4\n", "\n", "plt.figure(1)\n", "imshow_grid(rmg, z) # plot the DEM\n", "plt.plot(rmg.node_x[outlet_node_to_sample], rmg.node_y[outlet_node_to_sample], \"yo\")\n", "plt.plot(rmg.node_x[upstream_node_to_sample], rmg.node_y[upstream_node_to_sample], \"bo\")\n", "plt.plot(\n", " rmg.node_x[midstream_node_to_sample], rmg.node_y[midstream_node_to_sample], \"go\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Initialize a few more parameters, and getting ready to run the time loop and save data for plotting.\n", " * Note that time is in *seconds*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 5\n", "\n", "elapsed_time = 1.0 # s\n", "model_run_time = 43200.0 # s\n", "\n", "## Lists for saving data\n", "discharge_at_outlet = []\n", "discharge_upstream = []\n", "discharge_midstream = []\n", "hydrograph_time = []\n", "\n", "## Setting initial fields...\n", "rmg[\"node\"][\"surface_water__discharge\"] = np.zeros(rmg.number_of_nodes)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the time loop that generates overland flow.\n", "\n", "_Note_ On a 2016 MacBook Pro laptop the following code block can take ~ 5 minutes depending on the model set-up. It could take longer if multiple users are running at the same time using the Hydroshare platform." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 6\n", "\n", "while elapsed_time < model_run_time:\n", " # Setting the adaptive time step\n", " of.dt = of.calc_time_step()\n", "\n", " ## The storm starts when the model starts. While the elapsed time is less\n", " ## than the storm duration, we add water to the system as rainfall.\n", " if elapsed_time < (storm_duration):\n", " of.rainfall_intensity = starting_precip_ms\n", " else: # elapsed time exceeds the storm duration, rainfall ceases.\n", " of.rainfall_intensity = 0.0\n", "\n", " of.run_one_step() # Generating overland flow based on the deAlmeida solution.\n", "\n", " ## Append time and discharge to their lists to save data and for plotting.\n", " hydrograph_time.append(elapsed_time)\n", " q = rmg.at_link[\"surface_water__discharge\"]\n", " discharge_at_outlet.append(np.abs(q[outlet_link_to_sample]) * rmg.dx)\n", " discharge_upstream.append(np.abs(q[upstream_link_to_sample]) * rmg.dx)\n", " discharge_midstream.append(np.abs(q[midstream_link_to_sample]) * rmg.dx)\n", "\n", " ## output time every now and then so that you know the code\n", " ## is actually running\n", " if (elapsed_time % 100) < 2:\n", " print(\"elapsed time = \", elapsed_time)\n", "\n", " ## Updating elapsed_time\n", " elapsed_time += of.dt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's look at the data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "## Code Block 7\n", "\n", "## Calculate equilibrium discharge at each point for reference\n", "outlet_eq_q = starting_precip_ms * rmg.at_node[\"drainage_area\"][outlet_node_to_sample]\n", "midstream_eq_q = (\n", " starting_precip_ms * rmg.at_node[\"drainage_area\"][midstream_node_to_sample]\n", ")\n", "upstream_eq_q = (\n", " starting_precip_ms * rmg.at_node[\"drainage_area\"][upstream_node_to_sample]\n", ")\n", "\n", "\n", "## Plotting hydrographs and equilibrium discharge\n", "plt.figure(2)\n", "plt.plot(hydrograph_time, discharge_at_outlet, \"y-\", label=\"outlet\")\n", "plt.plot(\n", " [np.min(hydrograph_time), np.max(hydrograph_time)],\n", " [outlet_eq_q, outlet_eq_q],\n", " \"y--\",\n", " label=\"outlet eq Q\",\n", ")\n", "plt.plot(hydrograph_time, discharge_midstream, \"g-\", label=\"midstream\")\n", "plt.plot(\n", " [np.min(hydrograph_time), np.max(hydrograph_time)],\n", " [midstream_eq_q, midstream_eq_q],\n", " \"g--\",\n", " label=\"midstream eq Q\",\n", ")\n", "plt.plot(hydrograph_time, discharge_upstream, \"b-\", label=\"upstream\")\n", "plt.plot(\n", " [np.min(hydrograph_time), np.max(hydrograph_time)],\n", " [upstream_eq_q, upstream_eq_q],\n", " \"b--\",\n", " label=\"upstream eq Q\",\n", ")\n", "\n", "## Plot storm end and center of storm for reference\n", "plt.plot(\n", " [storm_duration, storm_duration], [0, 100], \"k-\", linewidth=2, label=\"storm end\"\n", ")\n", "plt.plot(\n", " [storm_duration / 2, storm_duration / 2], [0, 100], \"k:\", label=\"storm mid point\"\n", ")\n", "\n", "plt.ylabel(\"Discharge (cms)\")\n", "plt.xlabel(\"Time (seconds)\")\n", "plt.legend(loc=\"upper right\")\n", "title_text = \"Hydrographs, Storm is \" + storm_flag + \", Watershed is \" + basin_flag\n", "plt.title(title_text)\n", "plt.axis([0, np.max(hydrograph_time), 0, 100])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you have reached this point, you should have produced a plot of three hydrographs from different points on the square watershed, produced from overland flow driven by the base storm.\n", "\n", "There are six scenarios to explore: two different watersheds and three different storms. Run all six scenarios by systematically changing the *basin_flag* and *storm_flag* in Code Block 2 and rerunning all of the following code blocks sequentially. Save the hydrograph plots for each scenario. Include those plots in a document that also contains your typed answers to each of the questions below. Answer all of the questions with complete sentences. Try to be as specific and as quantitative as you can. (e.g. You can compare times to peak discharge and peak discharge values among the scenarios.) You are encouraged to discuss the results of the models with your classmates, but the text you turn in must be your own thoughts and words.\n", "\n", "1. Consider only the three stroms run on the square watershed. What aspects of the hydrograph change at the outlet as the storm gets longer or more intense? Are there aspects of the outlet hydrograph that are not sensitive to the storm duration or intensity? Do the midstream and upstream hydrographs exhibit the same sensitivity to storm duration and intensity? If yes, why? If no, why not?\n", "\n", "2. Now, consider only the three stroms run on the long watershed. What aspects of the hydrograph change at the outlet as the storm gets longer or more intense? Are there aspects of the outlet hydrograph that are not sensitive to the storm duration or intensity? Do the midstream and upstream hydrographs exhibit the same sensitivity to storm duration and intensity? If yes, why? If no, why not?\n", "\n", "3. Now compare the results between the two different basin shapes. Compare only between similar points (e.g. square outlet to long outlet) and between the same storm characteristics. Does watershed shape affect hydrograph shape? If so, how? If so, does it impact all locations in the same manner? Do different storm charactersitics exaggerate the differences between the different watersheds?\n", "\n", "4. Go back and look at your answers to the questions you answered before running the models. Do the model results match your intuition? If not, do you think your intuition was wrong, or the model was wrong, or both? Remember, models are helpful for learning but they are highly simplified representations of the real world. Wihtout knowing the details of the model, does it seem like something is missing from your model results?" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.0" } }, "nbformat": 4, "nbformat_minor": 2 }