├── landlab_header.png ├── landlab_logo_picture.jpg ├── environment.yml ├── geomorphology_exercises ├── hillslope_notebooks │ ├── nc_image_with_transect.png │ ├── hillslope_diffusion_class_notebook.ipynb │ └── north_carolina_piedmont_hillslope_class_notebook.ipynb ├── drainage_density_notebooks │ └── drainage_density_class_notebook.ipynb └── channels_streampower_notebooks │ └── stream_power_channels_class_notebook.ipynb ├── .travis.yml ├── test_notebooks.py ├── README.md └── surface_water_hydrology_exercises └── overland_flow_notebooks └── hydrograph_class_notebook.ipynb /landlab_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/landlab/landlab_teaching_tools/master/landlab_header.png -------------------------------------------------------------------------------- /landlab_logo_picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/landlab/landlab_teaching_tools/master/landlab_logo_picture.jpg -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: landlab_tutorials 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python==3.7 6 | - jupyter 7 | - landlab 8 | - pytest 9 | -------------------------------------------------------------------------------- /geomorphology_exercises/hillslope_notebooks/nc_image_with_transect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/landlab/landlab_teaching_tools/master/geomorphology_exercises/hillslope_notebooks/nc_image_with_transect.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | os: 3 | - linux 4 | sudo: false 5 | before_install: 6 | - curl https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh > $HOME/miniconda.sh 7 | - bash $HOME/miniconda.sh -b -p $HOME/anaconda 8 | - export PATH="$HOME/anaconda/bin:$PATH" 9 | - hash -r 10 | - conda config --set always_yes yes --set changeps1 no 11 | install: 12 | - conda env create --file=environment.yml 13 | - source activate landlab_tutorials 14 | - conda info --all && conda list && conda list landlab 15 | script: 16 | - travis_wait 50 pytest -vvv 17 | -------------------------------------------------------------------------------- /test_notebooks.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import tempfile 4 | 5 | import nbformat 6 | 7 | _TEST_DIR = os.path.abspath(os.path.dirname(__file__)) 8 | _EXCLUDE = [] 9 | 10 | 11 | def all_notebooks(path="."): 12 | notebooks = [] 13 | for root, dirs, files in os.walk(path): 14 | if ".ipynb_checkpoints" in root: 15 | continue 16 | for file in files: 17 | if file.endswith(".ipynb") and (file not in _EXCLUDE): 18 | notebooks.append(os.path.join(root, file)) 19 | return notebooks 20 | 21 | 22 | def pytest_generate_tests(metafunc): 23 | if "notebook" in metafunc.fixturenames: 24 | metafunc.parametrize("notebook", all_notebooks(_TEST_DIR)) 25 | 26 | 27 | def _notebook_run(path): 28 | """Execute a notebook via nbconvert and collect output. 29 | :returns (parsed nb object, execution errors) 30 | """ 31 | _, notebook = os.path.split(path) 32 | base, ext = os.path.splitext(notebook) 33 | 34 | with tempfile.NamedTemporaryFile("w", suffix=".ipynb") as fp: 35 | args = [ 36 | "jupyter", 37 | "nbconvert", 38 | "--to", 39 | "notebook", 40 | "--execute", 41 | "--ExecutePreprocessor.kernel_name=python", 42 | "--ExecutePreprocessor.timeout=None", 43 | "--output", 44 | fp.name, 45 | "--output-dir=.", 46 | path, 47 | ] 48 | subprocess.check_call(args) 49 | 50 | nb = nbformat.read(fp.name, nbformat.current_nbformat, encoding="UTF-8") 51 | 52 | errors = [ 53 | output 54 | for cell in nb.cells 55 | if "outputs" in cell 56 | for output in cell["outputs"] 57 | if output.output_type == "error" 58 | ] 59 | 60 | return nb, errors 61 | 62 | 63 | def test_notebook(tmpdir, notebook): 64 | with tmpdir.as_cwd(): 65 | nb, errors = _notebook_run(notebook) 66 | assert not errors 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The release of Landlab 2.0 renders the teaching tutorials in this repository no longer functional. They are no longer being maintained here. The content in this repository has been updated and brought into the [main landlab repository](https://github.com/landlab/landlab) which allows the development team to better ensure that the tutorials will always run with Landlab. You are still able to clone this repository, but these tutorials will not function with Landlab 2.0. THIS REPOSITORY IS NOW ARCHIVED. 2 | 3 | 4 | [![Landlab header](./landlab_header.png)](http://landlab.github.io) 5 | 6 | [![Build Status](https://travis-ci.org/landlab/landlab_teaching_tools.svg?branch=master)](https://travis-ci.org/landlab/landlab_teaching_tools) 7 | 8 | 9 | # Landlab teaching tools :raising_hand: 10 | 11 | This repository includes Jupyter Notebooks that implement Landlab for use in teaching undergraduate and graduate courses. Jupyter Notebooks combine formatted text with code that can be run. Students can run small parts of code bit by bit as they follow along with the text. 12 | 13 | The notebooks illustrate examples of physical processes implemented numerically. These notebooks are designed to teach about processes. The notebooks are not designed to teach students to code, or to teach students to use Landlab. No coding experience is needed to successfully carry out these activities - just the ability to read and a classroom introduction of the specific processes being illustrated. 14 | 15 | The notebooks are primarily designed for use as homework assignments or laboratory assignments. However, they can be used to illustrate concepts on-the-fly in the classroom. 16 | 17 | The easiest way to see what is in the notebooks is through this website: https://nbviewer.jupyter.org/github/landlab/landlab_teaching_tools/tree/master/. 18 | 19 | For an introduction to using Jupyter Notebooks, see this webpage - http://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/execute.html. [Quick Summary: The way to launch a Jupyter notebook is to enter 'jupyter notebook' from a command line prompt. Jupyter notebooks can also be launched from within Anaconda.] 20 | 21 | The notebooks can be run locally by installing Landlab on your computer or they can be run remotely using Hydroshare. 22 | 23 | # To install Landlab and run locally: :octocat::computer: 24 | 25 | If following this method, every student will need to install Landlab on their personal computer, or it will need to be installed on classroom computers. All software needed to run Landlab locally is opensource (so free!). This link (https://landlab.github.io/#/) will take you to directions on how to install Landlab and information on preferred Python distributions. 26 | 27 | The next step would be for the class instructor to hit the _Clone or download_ button (on this webpage (https://github.com/landlab/landlab_teaching_tools), green, upper right) and download this repository locally. Choose which Jupyter Notebooks you would like the students to run, and then distribute the notebook to the students. You can edit them to your class' needs if you use this method. Note that some notebooks require supporting files to run, so make sure those are copied to the students. 28 | 29 | # To use the notebooks on Hydroshare: :umbrella::computer: 30 | 31 | These notebooks can all be run remotely using HydroShare, an online collaboration environment for sharing data, models, and code (there are no costs, fees or subscriptions). To have your students run the Notebooks without any software installation required, all of your students will need to join HydroShare. For the first time set up, follow these steps: 32 | 33 | Initiation steps: 34 | 1. Go to https://www.hydroshare.org/ 35 | 2. Hit blue button _Sign up now_ and follow steps. (remember your user name and password!) 36 | 3. Once signed up, on the top bar hit _Collaborate_ and hite on the _Groups_ button. 37 | 4. Search for the Landlab Group and _Ask to join_ 38 | 5. Once you have permission, enter the Landlab Group page. 39 | 6. Search for _classroom\_notebooks_ in the search bar. 40 | 7. Enter the collection _Landlab\_classroom\_notebooks_. 41 | 8. Scroll down to _Collection Contents_ and hit on whatever notebook you want to run. 42 | 9. Hit the blue _Open with..._ button on the top right, and choose CUAHSI JupyterHub. 43 | 10. You will come to a screen with the notebook name (ending in .ipynb). Click that and you are now running the notebook remotely! 44 | 45 | Streamlined access: 46 | After you and your students have successfully run through the steps above, in the next work sessions you can also access your personal user space on the supercomputer that makes this magic happen, simply by typing in this URL into your browser: https://jupyter.cuahsi.org You will be prompted for your HydroShare login, and you can navigate the folders to find the resources you have downloaded and created in previous work sessions. 47 | 48 | # More information: :question::open_mouth: 49 | 50 | If you have suggestions on improving these notebooks and developing new ones, or are having trouble running them, please leave us a question in our GitHub Issues page - https://github.com/landlab/landlab/issues. Please make sure you include that you are working with a Landlab Teaching Notebook and include the name of the notebook and as much information as possible. If you are getting an error, please taking a screenshot and upload it. 51 | 52 | The development of these Notebooks has been made possible by the Landlab project funded by the National Science Foundation (OAC 1450338 to N. Gasparini, OAC 1450409 to G. Tucker, OAC 1450412 to E. Istanbulluoglu). Launching these Notebooks from HydroShare is made possible by a collaboration between HydroShare researchers, the Consortium of Universities Allied for Hydrologic Science, Inc. (CUAHSI), and National SuperComputer A (NCSA) and funding by the National Science Foundation. For more details on the software architecuture behind how to run Jupyter Notebooks from HydroShare, please contact [support@hydroshare(dot)org]. 53 | -------------------------------------------------------------------------------- /geomorphology_exercises/hillslope_notebooks/hillslope_diffusion_class_notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Linear diffusion exercise with Landlab\n", 15 | "\n", 16 | "This notebook is adapted from *Landscape Evolution Modeling with CHILD* by Gregory Tucker and Stephen Lancaster. This notebook was created by Nicole Gasparini at Tulane University." 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "
\n", 24 | "For tutorials on learning Landlab, click here: https://github.com/landlab/landlab/wiki/Tutorials\n", 25 | "
\n" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "**What is this notebook?**\n", 33 | "\n", 34 | "This notebook illustrates the evolution of landforms dominated by processes that result in linear diffusion of sediment. In other words, the downhill flow of soil is proportional to the (downhill) gradient of the land surface multiplied by a transport coefficient.\n", 35 | "\n", 36 | "The notebook first illustrates a simple example of a diffusing hillslope. We then provide a number of exercises for students to do on their own. This set of exercises is recomended for students in a quantitative geomorphology class, who have been introduced to the linear diffusion equation in class. \n", 37 | "\n", 38 | "**Application of linear diffusion transport law:**\n", 39 | "\n", 40 | "For relatively gentle, soil-mantled slopes, there is reasonably strong support for a transport law of the form:\n", 41 | "\\begin{equation}\n", 42 | "q_s = -D \\nabla z\n", 43 | "\\end{equation}\n", 44 | "where ${q}_s$ is the transport rate with dimensions of L$^2$T$^{-1}$; $D$ is a transport coefficient with dimensions of L$^2$T$^{-1}$; and $z$ is elevation. $\\nabla z$ is the gradient in elevation. If distance is increasing downslope, $\\nabla z$ is negative downslope, hence the negative in front of $D$. \n", 45 | " \n", 46 | "Changes in elevation, or erosion, are calculated from conservation of mass:\n", 47 | "\\begin{equation}\n", 48 | "\\frac{dz}{dt} = U-\\nabla q_s\n", 49 | "\\end{equation}\n", 50 | "where $U$ is the rock uplift rate, with dimensions LT$^{-1}$.\n", 51 | "\n", 52 | "**How will we explore this with Landlab?**\n", 53 | "\n", 54 | "We will use the Landlab component *LinearDiffuser*, which implements the equations above, to explore how hillslopes evolve when linear diffusion describes hillslope sediment transport. We will explore both steady state, here defined as erosion rate equal to rock uplift rate, and also how a landscape gets to steady state.\n", 55 | "\n", 56 | "The first example illustrates how to set-up the model and evolve a hillslope to steady state, along with how to plot some variables of interest. We assume that you have knowledge of how to derive the steady-state form of a uniformly uplifting, steady-state, diffusive hillslope. For more information on hillslope sediment transport laws, this paper is a great overview:\n", 57 | "\n", 58 | "Roering, Joshua J. (2008) \"How well can hillslope evolution models “explain” topography? Simulating soil transport and production with high-resolution topographic data.\" Geological Society of America Bulletin.\n", 59 | "\n", 60 | "Based on the first example, you are asked to first think about what will happen as you change a parameter, and then you explore this numerically by changing the code.\n", 61 | "\n", 62 | "Start at the top by reading each block of text and sequentially running each code block (shift - enter OR got to the _Cell_ pulldown menu at the top and choose _Run Cells_). \n", 63 | "\n", 64 | "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. If you just change one code block and rerun only that code block, only the parts of the code in that code block will be updated. (E.g. if you change parameters but don't reset the code blocks that initialize run time or topography, then these values will not be reset.) " 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "**Now on to the code example**\n", 72 | "\n", 73 | "Import statements. You should not need to edit this." 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": {}, 80 | "outputs": [], 81 | "source": [ 82 | "# Code Block 1\n", 83 | "\n", 84 | "import numpy as np\n", 85 | "from landlab.plot.imshow import imshow_grid\n", 86 | "#below is to make plots show up in the notebook\n", 87 | "%matplotlib inline \n", 88 | "from matplotlib.pyplot import figure, show, plot, \\\n", 89 | " xlabel, ylabel, title, legend, ylim" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "We will create a grid with 41 rows and 5 columns, and dx is 5 m (a long, narrow, hillslope). The initial elevation is 0 at all nodes.\n", 97 | "\n", 98 | "We set-up boundary conditions so that material can leave the hillslope at the two short ends." 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "# Code Block 2\n", 108 | "\n", 109 | "# setup grid\n", 110 | "from landlab import RasterModelGrid\n", 111 | "mg = RasterModelGrid((41, 5), 5.)\n", 112 | "z_vals = mg.add_zeros('topographic__elevation', at='node')\n", 113 | "\n", 114 | "# initialize some values for plotting\n", 115 | "ycoord_rast = mg.node_vector_to_raster(mg.node_y)\n", 116 | "ys_grid = ycoord_rast[:, 2]\n", 117 | "\n", 118 | "# set boundary condition.\n", 119 | "mg.set_closed_boundaries_at_grid_edges(True, False, True, False)" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "Now we import and initialize the *LinearDiffuser* component. " 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "# Code Block 3\n", 136 | "\n", 137 | "from landlab.components import LinearDiffuser\n", 138 | "D = 0.01 # initial value of 0.01 m^2/yr\n", 139 | "lin_diffuse = LinearDiffuser(mg, linear_diffusivity=D)" 140 | ] 141 | }, 142 | { 143 | "cell_type": "markdown", 144 | "metadata": {}, 145 | "source": [ 146 | "We now initialize a few more parameters." 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": null, 152 | "metadata": {}, 153 | "outputs": [], 154 | "source": [ 155 | "# Code Block 4\n", 156 | "\n", 157 | "# Uniform rate of rock uplift\n", 158 | "uplift_rate = 0.0001 # meters/year, originally set to 0.0001\n", 159 | "\n", 160 | "# Total time in years that the model will run for.\n", 161 | "runtime = 1000000 # years, originally set to 1,000,000\n", 162 | "\n", 163 | "# Stability criteria for timestep dt. Coefficient can be changed\n", 164 | "# depending on our tolerance for stability vs tolerance for run time.\n", 165 | "dt = 0.5 * mg.dx * mg.dx / D\n", 166 | "\n", 167 | "# nt is number of time steps\n", 168 | "nt = int(runtime // dt)\n", 169 | "\n", 170 | "# Below is to keep track of time for labeling plots\n", 171 | "time_counter = 0\n", 172 | "\n", 173 | "# length of uplift over a single time step, meters\n", 174 | "uplift_per_step = uplift_rate * dt" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "Now we figure out the analytical solution for the elevation of the steady-state profile." 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "# Code Block 5\n", 191 | "\n", 192 | "ys = np.arange(mg.number_of_node_rows*mg.dx-mg.dx)\n", 193 | "\n", 194 | "# location of divide or ridge crest -> middle of grid \n", 195 | "# based on boundary conds.\n", 196 | "divide_loc = (mg.number_of_node_rows*mg.dx-mg.dx)/2\n", 197 | "\n", 198 | "# half-width of the ridge\n", 199 | "half_width = (mg.number_of_node_rows*mg.dx-mg.dx)/2\n", 200 | "\n", 201 | "# analytical solution for elevation under linear diffusion at steady state\n", 202 | "zs = (uplift_rate/(2*D)) * \\\n", 203 | " (np.power(half_width, 2) - np.power(ys - divide_loc, 2))" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "Before we evolve the landscape, let's look at the initial topography. (This is just verifying that it is flat with zero elevation.)" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": {}, 217 | "outputs": [], 218 | "source": [ 219 | "# Code Block 6\n", 220 | "\n", 221 | "figure(1)\n", 222 | "imshow_grid(mg, 'topographic__elevation')\n", 223 | "title('initial topography')\n", 224 | "figure(2)\n", 225 | "elev_rast = mg.node_vector_to_raster(\n", 226 | " mg.at_node['topographic__elevation'])\n", 227 | "plot(ys_grid, elev_rast[:, 2], 'r-', label='model')\n", 228 | "plot(ys, zs, 'k--', label='analytical solution')\n", 229 | "ylim((-5,50)) #may want to change upper limit if D changes\n", 230 | "xlabel('horizontal distance (m)')\n", 231 | "ylabel('vertical distance (m)')\n", 232 | "legend(loc='lower center')\n", 233 | "title('initial topographic cross section')" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "Now we are ready to evolve the landscape and compare it to the steady state solution.\n", 241 | "\n", 242 | "Below is the time loop that does all the calculations. " 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": null, 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "# Code Block 7\n", 252 | "\n", 253 | "for i in range(nt):\n", 254 | " mg['node']['topographic__elevation'][mg.core_nodes] += uplift_per_step\n", 255 | " lin_diffuse.run_one_step(dt)\n", 256 | " time_counter += dt\n", 257 | "\n", 258 | " # All landscape evolution is the first two lines of loop.\n", 259 | " # Below is simply for plotting the topography halfway through the run\n", 260 | " if i == int(nt // 2):\n", 261 | " figure(1)\n", 262 | " imshow_grid(mg, 'topographic__elevation')\n", 263 | " title('topography at time %s, with D = %s'%(time_counter,D))\n", 264 | " figure(2)\n", 265 | " elev_rast = mg.node_vector_to_raster(\n", 266 | " mg.at_node['topographic__elevation'])\n", 267 | " plot(ys_grid, elev_rast[:, 2], 'k-', label='model')\n", 268 | " plot(ys, zs, 'g--', label='analytical solution - SS')\n", 269 | " plot(ys, zs*0.75, 'b--', label='75% of analytical solution')\n", 270 | " plot(ys, zs*0.5, 'r--', label='50% of analytical solution')\n", 271 | " xlabel('horizontal distance (m)')\n", 272 | " ylabel('vertical distance (m)')\n", 273 | " legend(loc='lower center')\n", 274 | " title('topographic__elevation at time %s, with D = %s'\n", 275 | " %(time_counter,D))" 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "metadata": {}, 281 | "source": [ 282 | "Now we plot the final cross-section." 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": null, 288 | "metadata": {}, 289 | "outputs": [], 290 | "source": [ 291 | "# Code Block 8\n", 292 | "\n", 293 | "elev_rast = mg.node_vector_to_raster(\n", 294 | " mg.at_node['topographic__elevation'])\n", 295 | "plot(ys_grid, elev_rast[:, 2], 'k-', label='model')\n", 296 | "plot(ys, zs, 'g--', label='analytical solution - SS')\n", 297 | "plot(ys, zs*0.75, 'b--', label='75% of analytical solution')\n", 298 | "plot(ys, zs*0.5, 'r--', label='50% of analytical solution')\n", 299 | "xlabel('horizontal distance (m)')\n", 300 | "ylabel('vertical distance (m)')\n", 301 | "legend(loc='lower center')\n", 302 | "title('topographic cross section at time %s, with D = %s'%(time_counter,D))" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": {}, 308 | "source": [ 309 | "Now we plot the steepest slope in the downward direction across the landscape.\n", 310 | "\n", 311 | "(To calculate the steepest slope at a location, we need to route flow across the landscape.)" 312 | ] 313 | }, 314 | { 315 | "cell_type": "code", 316 | "execution_count": null, 317 | "metadata": {}, 318 | "outputs": [], 319 | "source": [ 320 | "# Code Block 9\n", 321 | "\n", 322 | "from landlab.components import FlowRouter\n", 323 | "fr = FlowRouter(mg) # intializing flow routing\n", 324 | "fr.run_one_step()\n", 325 | "plot(mg.node_y[mg.core_nodes],mg.at_node['topographic__steepest_slope'][mg.core_nodes],'k-')\n", 326 | "xlabel('horizontal distance (m)')\n", 327 | "ylabel('topographic slope (m/m)')\n", 328 | "title('slope of the hillslope at time %s, with D = %s'%(time_counter,D))" 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": {}, 334 | "source": [ 335 | "Has the landscape reached steady state yet? How do you know?\n", 336 | "\n", 337 | "\n", 338 | "\n", 339 | "\n", 340 | "\n", 341 | "\n", 342 | "\n", 343 | "Answer: Not quite, but it is getting close. Go back and rerun Code Blocks 7, 8 and 9 (time loop and plotting). (Remember you can rerun a cell with shift-return, or from the cell pull-down menu.) Has it reached steady state yet? " 344 | ] 345 | }, 346 | { 347 | "cell_type": "markdown", 348 | "metadata": {}, 349 | "source": [ 350 | "**What to do and hand in:**\n", 351 | "1. In the example illustrated here ($D$ = 0.01 m$^2$yr$^{-1}$ and $U$ = 0.0001 m yr$^{-1}$). Restart everything, and use the model to determine how long it takes for the landscape to go from a flat to reach 50%, 75% and 100% of its steady-state morphology. Does the landscape approach steady state linearly in time? (You can run the time loop (Code Block 7) multiple times without running other code blocks again to continually evolve the landscape. You will initially want to rerun all the code blocks and change the value of **run_time** (Code Block 4). Determining the correct value of **run_time** to use will take some iteration.)\n", 352 | "2. What do you think will happen when you increase $D$ (Code Block 3) by a factor of 10? Will the time to steady state differ? If yes, how? Will the topography be different? If yes, how and why? What does it mean physically, about processes, if $D$ increases? Answer these questions before running any code. \n", 353 | "3. Now set $D$ = 0.1 m$^2$yr$^{-1}$ and rerun landscape evolution from an initial flat. Illustrate the final steady state topography and record the time to steady state. Discuss how the landscape differs from the results in question 1. Discuss how the results are similar to or different from your intuition. It is OK if your intuition was wrong! \n", 354 | "4. What do you think will happen when you increase **uplift_rate** (Code Block 4) by a factor of 10? Will the time to steady state differ? If yes, how? Will the topography be different? If yes, how and why? Answer these questions first, and then rerun the code with **uplift_rate** = 0.001 m yr$^{-1}$. (Make sure you change $D$ - Code Block 3 - back to the original value of 0.01 m$^2$yr$^{-1}$ and restart from a flat surface.) Illustrate the final steady state topography. Discuss how these results differ from the results in question 1 and how the results match (or do not) your intuition. It is OK if your intuition was wrong.\n", 355 | "\n", 356 | "You should hand in a typed document that answers the above questions with supporting plots. Plots should be embedded in the text, or, if they all fall at the end, they need to be clearly labeled, e.g. each plot has a figure number and plots are referred to by figure number in the text.\n", 357 | "\n", 358 | "Other questions you can explore.\n", 359 | "\n", 360 | "1. What happens to time to steady state as you increase the length of your hillslope? \n", 361 | "2. Does grid resolution affect your answers? If so, how?\n" 362 | ] 363 | } 364 | ], 365 | "metadata": { 366 | "anaconda-cloud": {}, 367 | "kernelspec": { 368 | "display_name": "Python 3", 369 | "language": "python", 370 | "name": "python3" 371 | }, 372 | "language_info": { 373 | "codemirror_mode": { 374 | "name": "ipython", 375 | "version": 3 376 | }, 377 | "file_extension": ".py", 378 | "mimetype": "text/x-python", 379 | "name": "python", 380 | "nbconvert_exporter": "python", 381 | "pygments_lexer": "ipython3", 382 | "version": "3.6.6" 383 | } 384 | }, 385 | "nbformat": 4, 386 | "nbformat_minor": 1 387 | } 388 | -------------------------------------------------------------------------------- /geomorphology_exercises/drainage_density_notebooks/drainage_density_class_notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Modeling Hillslopes and Channels with Landlab\n", 15 | "The original version of this exercise was donated by Andy Wickert at the University of Minnesota. This notebook was created by Nicole Gasparini at Tulane University." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "
\n", 23 | "For tutorials on learning Landlab, click here: https://github.com/landlab/landlab/wiki/Tutorials\n", 24 | "
" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "** What is this notebook? **\n", 32 | "\n", 33 | "This notebook illustrates a landscape evolution model in which the landscape evolves according to the equation:\n", 34 | "\n", 35 | "\\begin{equation}\n", 36 | " \\frac{\\partial z}{\\partial t} = -K_\\text{sp} A^{m_{sp}} S^{n_{sp}} + K_\\text{hs} \\frac{\\partial^2 z}{\\partial x^2} + U\n", 37 | "\\end{equation}\n", 38 | "Here, $K$ are coefficients on the fluvial ($sp$) and hillslope ($hs$) parts of the equation, and $m_{sp}$ and $n_{sp}$ are positive exponents, usually thought to have a ratio, $m_{sp}/n_{sp} \\approx 0.5$. $A$ is drainage area and $S$ is the slope of steepest descent ($-\\frac{dz}{dx}$) where $x$ is horizontal distance (positive in the downslope direction) and $z$ is elevation. (If slope is negative there is no fluvial erosion.) $U$ is an externally-applied uplift field.\n", 39 | "\n", 40 | "The first term on the right hand side of the equation is the fluvial erosion term, which is also known as the stream power equation. The second term on the right hand side of the equation is elevation changes via linear diffusion, and linear diffusion is one way in which to describe hillslope sediment transport.\n", 41 | "\n", 42 | "For more information on the fluvial erosion term, please see:\n", 43 | "\n", 44 | "- Whipple, K.X. and Tucker, G.E., 1999. Dynamics of the stream‐power river incision model: Implications for height limits of mountain ranges, landscape response timescales, and research needs. Journal of Geophysical Research: Solid Earth.\n", 45 | "\n", 46 | "For more information on linear diffusion applied to hillslopes (and other fun hillslope models) see:\n", 47 | "\n", 48 | "- Roering, J.J., 2008. How well can hillslope evolution models “explain” topography? Simulating soil transport and production with high-resolution topographic data. Geological Society of America Bulletin.\n", 49 | "\n", 50 | "The ideas behind what this notebook does are presented nicely in the two papers below. Neither of them is exactly the same as this notebook, but they discuss drainage density and transitions from hillslope to fluviall processes.\n", 51 | "\n", 52 | "- Tucker, G.E. and Bras, R.L., 1998. Hillslope processes, drainage density, and landscape morphology. Water Resources Research.\n", 53 | "\n", 54 | "- Perron, J.T., Kirchner, J.W. and Dietrich, W.E., 2009. Formation of evenly spaced ridges and valleys. Nature.\n", 55 | "\n", 56 | "** What will you do? **\n", 57 | "\n", 58 | "In this exercise you will modify the code to get a better understanding of how different processes and forces control landscape evolution, landscape form and drainage density (as interpreted from slope-area data). It is expected that you have already learned the basics about fluvial bedrock incision (and the stream power equation) and sediment transport through creep on hillslopes (and the diffusion equation). (See references above.)\n", 59 | "\n", 60 | "Start by sequentially running each code block without changing anything. To run an individual code cell, put the cursor in the cell and type shift-enter, or got to the _Cell_ pulldown menu at the top and choose _Run Cells_. At the end of the notebook you will see the questions that you need to answer by changing parts of the code and rerunning it. \n", 61 | "\n", 62 | "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. If you just change one code block and rerun only that code block, only the parts of the code in that code block will be updated. (E.g. if you change parameters but don't reset the code blocks that initialize run time or topography, then these values will not be reset.) \n", 63 | "\n", 64 | "** Questions to answer before starting this assignment. **\n", 65 | "\n", 66 | "1. If hillslope diffusivity ($K_{hs}$) is fixed, but fluvial erodibility ($K_{sp}$) increases, what do you think will happen to the total relief and drainage density of a landscape?\n", 67 | "2. If fluvial erodibility ($K_{sp}$) is fixed but hillslope diffusivity ($K_{hs}$) increases, what do you think will happen to the total relief and drainage density of a landscape?\n", 68 | "3. If parameters stay fixed ($K_{hs}$ and $K_{sp}$), but the uplift rate increases, what do you think will happen to the total relief and drainage density of a landscape?" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "** Now on to the code... **\n", 76 | "\n", 77 | "First we have to import the parts of Python and Landlab that are needed to run this code. You should not have to change this first code block." 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "# Code Block 1\n", 87 | "\n", 88 | "import numpy as np\n", 89 | "from landlab import RasterModelGrid, HexModelGrid\n", 90 | "from landlab.components import StreamPowerEroder, FlowRouter, \\\n", 91 | " LinearDiffuser, DepressionFinderAndRouter\n", 92 | "from landlab import imshow_grid\n", 93 | "from matplotlib import pyplot as plt\n", 94 | "#below is to make plots show up in the notebook\n", 95 | "%matplotlib inline " 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "Now we set parameters\n", 103 | "\n", 104 | "** This part you will need to change for the different exercises. ** \n", 105 | "\n", 106 | "Note that Landlab does not impose units, but it assumes that all units are consistent. We will assume that everything is given in _meters_ (m) and _years_ (yr)." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "# Code Block 2\n", 116 | "\n", 117 | "uplift_rate = 0.001 # [m/yr], initially set at 0.001\n", 118 | "K_sp = 1.e-5 # units vary depending on m_sp and n_sp, initially set at 1e-5\n", 119 | "m_sp = 0.5 # exponent on drainage area in stream power equation, initially 0.5\n", 120 | "n_sp = 1. # exponent on slope in stream power equation, initially 1.\n", 121 | "K_hs = 0.05 # [m^2/yr], initially 0.05" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "** Make a grid. **\n", 129 | "\n", 130 | "This part you may want to change." 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": null, 136 | "metadata": {}, 137 | "outputs": [], 138 | "source": [ 139 | "# Code Block 3\n", 140 | "\n", 141 | "ncells_side = 150 # number of raster cells on each side, initially 150\n", 142 | "dxy = 50 # side length of a raster model cell, or resolution [m], initially 50\n", 143 | "\n", 144 | "# Below is a raster (square cells) grid, with equal width and height \n", 145 | "mg = RasterModelGrid((ncells_side, ncells_side), dxy)\n", 146 | "\n", 147 | "# Below is a Hexagonal grid (hexagonal cells, \n", 148 | "# with equal width and height (a square)\n", 149 | "#mg = HexModelGrid(ncells_side, ncells_side, dxy, shape='rect')\n", 150 | "\n", 151 | "# Below is a hexagonal grid (hexagonal cells), \n", 152 | "# in which the grid is also a hexagon\n", 153 | "#mg = HexModelGrid(ncells_side, ncells_side/2, dxy, shape='hex')" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "Set some variables related to time. " 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": null, 166 | "metadata": {}, 167 | "outputs": [], 168 | "source": [ 169 | "# Code Block 4\n", 170 | "\n", 171 | "dt = 1000 # time step [yr], initially 5000\n", 172 | "total_time = 0 # amount of time the landscape has evolved [yr]\n", 173 | "tmax = 1E6 # time for the model loop to run [yr], initially 1e6\n", 174 | "\n", 175 | "t = np.arange(0, tmax, dt) # each of the time steps that the code will run" 176 | ] 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "metadata": {}, 181 | "source": [ 182 | "Here we make the initial grid of elevation. " 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [ 191 | "# Code Block 5\n", 192 | "\n", 193 | "np.random.seed(0) # seed set to zero so our figures are reproducible\n", 194 | "mg_noise = np.random.rand(mg.number_of_nodes)/1000. # intial noise on elevation grid\n", 195 | "\n", 196 | "# set up the elevation on the grid\n", 197 | "zr = mg.add_zeros('node', 'topographic__elevation')\n", 198 | "zr += mg_noise" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "Intializing all of the process components that do the work." 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | "# Code Block 6\n", 215 | "\n", 216 | "frr = FlowRouter(mg) # intializing flow routing\n", 217 | "spr = StreamPowerEroder(mg, K_sp=K_sp, m_sp=m_sp, n_sp=n_sp, threshold_sp=0,\n", 218 | " use_Q=None) #initializing stream power incision\n", 219 | "dfn = LinearDiffuser(mg, linear_diffusivity=K_hs, deposit = False) # initializing linear diffusion\n", 220 | "#df = DepressionFinderAndRouter(mg) # Initializing the pit finder" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "Now for the code loop. Note that you can rerun this code block many times, and as long as you don't rerun any of the code boxes above, it will take the already evolved landscape and evolve it even more." 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": null, 233 | "metadata": {}, 234 | "outputs": [], 235 | "source": [ 236 | "# Code Block 7\n", 237 | "\n", 238 | "for ti in t:\n", 239 | " zr[mg.core_nodes] += uplift_rate*dt # uplift the landscape\n", 240 | " dfn.run_one_step(dt) # diffuse the landscape\n", 241 | " frr.run_one_step() # route flow\n", 242 | " #df.map_depressions()\n", 243 | " spr.run_one_step(dt) # fluvial incision\n", 244 | " total_time += dt # update time keeper\n", 245 | " print(total_time)" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "Plot the topography." 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "metadata": {}, 259 | "outputs": [], 260 | "source": [ 261 | "# Code Block 8\n", 262 | "\n", 263 | "plt.figure(1)\n", 264 | "imshow_grid(mg, 'topographic__elevation', grid_units=('m', 'm'),\n", 265 | " var_name='Elevation (m)')\n", 266 | "title_text = '$K_{sp}$='+str(K_sp) + '; $K_{hs}$='+str(K_hs) + '; $time$='+str(total_time) + '; $dx$='+str(dxy)\n", 267 | "plt.title(title_text)\n", 268 | "\n", 269 | "max_elev = np.max(zr)\n", 270 | "suptitle_text = 'Maximum elevation is '+str(max_elev)\n", 271 | "plt.suptitle(suptitle_text)\n", 272 | "\n", 273 | "print('Maximum elevation is ', np.max(zr))" 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "Plot the slope and area data at each point (in log-log space)." 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": null, 286 | "metadata": {}, 287 | "outputs": [], 288 | "source": [ 289 | "# Code Block 9\n", 290 | "\n", 291 | "plt.figure(2)\n", 292 | "indices = np.where(mg.status_at_node[mg.at_node['flow__receiver_node']] == 0)\n", 293 | "plt.loglog(mg.at_node['drainage_area'][indices],\n", 294 | " mg.at_node['topographic__steepest_slope'][indices], 'b.')\n", 295 | "\n", 296 | "plt.ylabel('Topographic slope')\n", 297 | "plt.xlabel('Drainage area (m^2)')\n", 298 | "plt.title(title_text)" 299 | ] 300 | }, 301 | { 302 | "cell_type": "markdown", 303 | "metadata": {}, 304 | "source": [ 305 | "Has the landscape reached steady state yet? \n", 306 | "\n", 307 | "\n", 308 | "Answer: Not quite. At perfect steady state, there will be no scatter in the fluvial part of the slope-area relationship (given this model set-up).\n", 309 | "\n", 310 | "** What to do. **\n", 311 | "\n", 312 | "Answer the following questions using the code above. All solutions should be typed, and supporting figures (produced using the code) should be embedded in your final document. (Download or screenshoot the figures.) You may want to make other plots with the data you collect using this model. You are free to make those plots using whatever software you choose.\n", 313 | "\n", 314 | "In parts of this exercise you need to work with your classmates. You are encouraged to discuss how to use the model and model results with your classmates, however the write-up that you hand in must be your own work.\n", 315 | "\n", 316 | "1. **Hillslope vs. Fluvial Processes. ** Using the parameters provided in the initial notebook, run the landscape to steady state, or the point at which the topography and the slope-area relationship stop changing (i.e. erosion equals rock uplift). (You can keep rerunning Code Block 7 until steady state is reached. Steady state is reached asymptotically, so exact steady state is less important than very close.) Use the plots of slope and area to estimate where the hillslope–fluvial transition is (or in otherwords, the threshold drainage area for channel heads. There is usually a range of values. You should be consistent in your method to determine drainage density and describe how you determined it in your write-up). Also record the maximum elevation. Now try keeping $K_{sp}$ the same but increase and decrease $K_{hs}$ (change and run Code Block 2, then rerun Code Blocks 6 and 7). How do the maximum elevation and the transition from hillslope to channel change with changes in $K_{hs}$? Now try keeping $K_{hs}$ the same but increase and decrease $K_{sp}$ (change and run Code Block 2, then rerun Code Blocks 6 and 7). How do the maximum elevation and transition from hillslope to channel change with changes in $K_{sp}$? You can work in teams with your classmates so that you can explore more parameter combinations. Produce a relationship between the different values of $K_{sp}$, $K_{hs}$ and the threshold drainage area and maximum elevation. Remember to run all of your experiments with different parameter values to steady state before estimating the threshold drainage area and maximum elevation. Describe how the different parameters affect drainage density in words, and how this is seen in the relationship that you generate. You do not have to include plots of every single run, but include plots to illustrate at least three landscapes with different drainage densities.\n", 317 | "\n", 318 | "2. **Uplift and erosion. ** Now, perform a similar set of exercises as you did in exercise 1, but also systematically vary uplift rate (Code Block 2). Work in teams, and each person should choose two combinations of $K_{sp}$ and $K_{hs}$ and three uplift rates (for a total of 6 runs). Make sure the parameter values that you choose do not overlap with your group members. Make sure you document the transition from hillslope to fluvial process (make sure all of the team members are using the same method to determine threshold area for drainage density), and also note the maximum steady-state elevation for each combination of uplift, $K_{sp}$ and $K_{hs}$. Produce relationships to show how the area threshold and maximum elevation change with the different variables. Describe how uplift rate affects drainage density in words, and how this is seen in the relationship that you generate. You do not have to include plots of every single run, but include some plots to illustrate the changes that you describe. (Note whom your group members were in your write-up.)\n", 319 | "\n", 320 | "3. ** Free-form exploration. (Optional) ** Try changing the grid type (Code Block 3), grid size (Code Block 3), stream power exponents (Code Block 2), distribution of uplift rate (e.g., what happens if you have just part of the landscape experience uplift, a bit trickier, as uplift in Code Block 2 will need to be changed to an array), etc. Based on what you observe, create a consistent geomorphic history of the system. Creativity is expected here!\n", 321 | "\n", 322 | "4. ** Final reflection. ** Was your initial insight into how parameters would affect the landscape correct? Discuss in less than 5 sentences." 323 | ] 324 | } 325 | ], 326 | "metadata": { 327 | "anaconda-cloud": {}, 328 | "kernelspec": { 329 | "display_name": "Python 3", 330 | "language": "python", 331 | "name": "python3" 332 | }, 333 | "language_info": { 334 | "codemirror_mode": { 335 | "name": "ipython", 336 | "version": 3 337 | }, 338 | "file_extension": ".py", 339 | "mimetype": "text/x-python", 340 | "name": "python", 341 | "nbconvert_exporter": "python", 342 | "pygments_lexer": "ipython3", 343 | "version": "3.6.6" 344 | } 345 | }, 346 | "nbformat": 4, 347 | "nbformat_minor": 1 348 | } 349 | -------------------------------------------------------------------------------- /surface_water_hydrology_exercises/overland_flow_notebooks/hydrograph_class_notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Exploring rainfall driven hydrographs with Landlab\n", 15 | "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." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "
\n", 23 | "For tutorials on learning Landlab, click here: https://github.com/landlab/landlab/wiki/Tutorials\n", 24 | "
" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "** What is this notebook? **\n", 32 | "\n", 33 | "This notebook illustrates the importance of watershed shape and rainfall intensity and duration on the characteristics of hydrographs. \n", 34 | "\n", 35 | "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", 36 | "\n", 37 | "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", 38 | "\n", 39 | "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", 40 | "\n", 41 | "Dingman, S.L., 2015. Physical hydrology, third edition. Waveland press.\n", 42 | "\n", 43 | "More background on the model used here and the results presented can be found in:\n", 44 | "\n", 45 | "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", 46 | "\n", 47 | "The code used in this exercise is taken from the above Adams et al., (2017) reference.\n", 48 | "\n", 49 | "** What will you do? ** \n", 50 | "\n", 51 | "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", 52 | "\n", 53 | "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", 54 | "\n", 55 | "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", 56 | "\n", 57 | "** Questions to answer before running this notebook. **\n", 58 | "\n", 59 | "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", 60 | "2. Do you think that the rainfall intensity impacts the time to peak and peak discharge at a watershed outlet? If so, how?\n", 61 | "3. Do you think that the rainfall duration impacts the time to peak and peak discharge at a watershed outlet? If so, how?" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "**Now on to the code.**\n", 69 | "* Below we import Landlab components, functions for importing data, numpy and plotting tools. You should not need to change this." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "## Code Block 1\n", 79 | "\n", 80 | "from landlab.components import OverlandFlow\n", 81 | "from landlab.components.flow_routing import FlowRouter\n", 82 | "from landlab.io import read_esri_ascii\n", 83 | "from landlab import imshow_grid\n", 84 | "import numpy as np\n", 85 | "import copy\n", 86 | "from matplotlib import pyplot as plt\n", 87 | "\n", 88 | "## only needed for plotting in a jupyter notebook.\n", 89 | "%matplotlib inline " 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "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", 97 | "\n", 98 | "* The user can change the `basin_flag` to equal `Square` or `Long` depending on the watershed to run.\n", 99 | " * The outlet link for each watershed was pretermined for plotting purposes.\n", 100 | "* The user can also choose which storm to run. \n", 101 | " * `Base` has an intensity of 5.0 mm/hr, with a duration of 2 hr.\n", 102 | " * `HigherIntensity` has an intensity of 10.0 mm/hr, with a duration of 1 hr.\n", 103 | " * `LongerDuration` has an intensity of 2.5 mm/hr, with a duration of 4 hr." 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "## Code Block 2\n", 113 | "\n", 114 | "basin_flag = 'Square' # 'Square' or Long'\n", 115 | "storm_flag = 'Base' # 'Base' or'HigherIntensity' or 'LongerDuration'\n", 116 | "\n", 117 | "## If the basin flag matches one of the two select basins, \n", 118 | "## below will set the filename which to read the DEM from and\n", 119 | "## the outlet link and upstream link to sample discharge values \n", 120 | "## from for plotting.\n", 121 | "\n", 122 | "if basin_flag == 'Square':\n", 123 | " watershed_dem = 'Square_TestBasin.asc'\n", 124 | " ## Reading in the DEM given the filename from above\n", 125 | " (rmg, z) = read_esri_ascii(watershed_dem, name='topographic__elevation')\n", 126 | " outlet_node_to_sample = 300\n", 127 | " outlet_link_to_sample = rmg.links_at_node[outlet_node_to_sample][3]\n", 128 | " upstream_node_to_sample = 28689\n", 129 | " upstream_link_to_sample = rmg.links_at_node[upstream_node_to_sample][3]\n", 130 | " midstream_node_to_sample = 9102\n", 131 | " midstream_link_to_sample = rmg.links_at_node[midstream_node_to_sample][3]\n", 132 | "else:\n", 133 | " watershed_dem = 'Long_TestBasin.asc'\n", 134 | " ## Reading in the DEM given the filename from above\n", 135 | " (rmg, z) = read_esri_ascii(watershed_dem, name='topographic__elevation')\n", 136 | " outlet_node_to_sample = 150\n", 137 | " outlet_link_to_sample = rmg.links_at_node[outlet_node_to_sample][3]\n", 138 | " upstream_node_to_sample = 33859\n", 139 | " upstream_link_to_sample = rmg.links_at_node[upstream_node_to_sample][3]\n", 140 | " midstream_node_to_sample = 14658\n", 141 | " midstream_link_to_sample = rmg.links_at_node[midstream_node_to_sample][2]\n", 142 | "\n", 143 | "## The Flow Router calculates drainage area, which is helpful for\n", 144 | "## calculating equilibrium discharge, which we illustrate later.\n", 145 | "fr = FlowRouter(rmg) # Instantiate flow router\n", 146 | "fr.run_one_step() # Drainage area calculated" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "Now we set the boundary conditions, initialize the process components, and set the appropriate storm parameters." 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": null, 159 | "metadata": {}, 160 | "outputs": [], 161 | "source": [ 162 | "## Code Block 3\n", 163 | "\n", 164 | "## Set boundary coditions on the grid\n", 165 | "rmg.set_watershed_boundary_condition(z)\n", 166 | "\n", 167 | "## instantiate OverlandFlow object\n", 168 | "of = OverlandFlow(rmg, alpha=0.45, steep_slopes=True) \n", 169 | "\n", 170 | "## Assign storm conditions based on flag in Code Block 2\n", 171 | "if storm_flag == 'Base':\n", 172 | " starting_precip_mmhr = 5.0\n", 173 | " starting_precip_ms = starting_precip_mmhr * (2.77778 * 10 ** -7)\n", 174 | " storm_duration = 7200.\n", 175 | "elif storm_flag == 'HigherIntensity':\n", 176 | " starting_precip_mmhr = 10.0\n", 177 | " starting_precip_ms = starting_precip_mmhr * (2.77778 * 10 ** -7)\n", 178 | " storm_duration = 3600.\n", 179 | "elif storm_flag == 'LongerDuration':\n", 180 | " starting_precip_mmhr = 2.5\n", 181 | " starting_precip_ms = starting_precip_mmhr * (2.77778 * 10 ** -7)\n", 182 | " storm_duration = 14400." 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "Before we go further, let's pause to look at the landscape that we will be routing flow over." 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "## Code Block 4\n", 199 | "\n", 200 | "plt.figure(1)\n", 201 | "imshow_grid(rmg, z) # plot the DEM\n", 202 | "plt.plot(rmg.node_x[outlet_node_to_sample],rmg.node_y[outlet_node_to_sample],'yo')\n", 203 | "plt.plot(rmg.node_x[upstream_node_to_sample],rmg.node_y[upstream_node_to_sample],'bo')\n", 204 | "plt.plot(rmg.node_x[midstream_node_to_sample],rmg.node_y[midstream_node_to_sample],'go')" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "Initialize a few more parameters, and getting ready to run the time loop and save data for plotting.\n", 212 | " * Note that time is in *seconds*" 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": null, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "## Code Block 5\n", 222 | "\n", 223 | "elapsed_time = 1.0 # s\n", 224 | "model_run_time = 43200.0 # s\n", 225 | "\n", 226 | "## Lists for saving data\n", 227 | "discharge_at_outlet = []\n", 228 | "discharge_upstream = []\n", 229 | "discharge_midstream = []\n", 230 | "hydrograph_time = []\n", 231 | "\n", 232 | "## Setting initial fields...\n", 233 | "rmg['node']['surface_water__discharge'] = np.zeros(rmg.number_of_nodes)" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "Now the time loop that generates overland flow.\n", 241 | "\n", 242 | "_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." 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": null, 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "## Code Block 6\n", 252 | "\n", 253 | "while elapsed_time < model_run_time:\n", 254 | " # Setting the adaptive time step\n", 255 | " of.dt = of.calc_time_step()\n", 256 | "\n", 257 | " ## The storm starts when the model starts. While the elapsed time is less\n", 258 | " ## than the storm duration, we add water to the system as rainfall.\n", 259 | " if elapsed_time < (storm_duration):\n", 260 | " of.rainfall_intensity = starting_precip_ms \n", 261 | " else: # elapsed time exceeds the storm duration, rainfall ceases.\n", 262 | " of.rainfall_intensity = 0.0\n", 263 | "\n", 264 | " of.overland_flow() # Generating overland flow based on the deAlmeida solution.\n", 265 | "\n", 266 | " ## Append time and discharge to their lists to save data and for plotting.\n", 267 | " hydrograph_time.append(elapsed_time)\n", 268 | " discharge_at_outlet.append(np.abs(of.q[outlet_link_to_sample]) * rmg.dx)\n", 269 | " discharge_upstream.append(np.abs(of.q[upstream_link_to_sample]) * rmg.dx)\n", 270 | " discharge_midstream.append(np.abs(of.q[midstream_link_to_sample]) * rmg.dx)\n", 271 | "\n", 272 | " ## output time every now and then so that you know the code\n", 273 | " ## is actually running\n", 274 | " if (elapsed_time % 100) < 2:\n", 275 | " print('elapsed time = ',elapsed_time)\n", 276 | "\n", 277 | " ## Updating elapsed_time\n", 278 | " elapsed_time += of.dt" 279 | ] 280 | }, 281 | { 282 | "cell_type": "markdown", 283 | "metadata": {}, 284 | "source": [ 285 | "Let's look at the data." 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": null, 291 | "metadata": {}, 292 | "outputs": [], 293 | "source": [ 294 | "## Code Block 7\n", 295 | "\n", 296 | "## Calculate equilibrium discharge at each point for reference\n", 297 | "outlet_eq_q = starting_precip_ms*rmg.at_node['drainage_area'][outlet_node_to_sample]\n", 298 | "midstream_eq_q = starting_precip_ms*rmg.at_node['drainage_area'][midstream_node_to_sample]\n", 299 | "upstream_eq_q = starting_precip_ms*rmg.at_node['drainage_area'][upstream_node_to_sample]\n", 300 | "\n", 301 | "\n", 302 | "## Plotting hydrographs and equilibrium discharge\n", 303 | "plt.figure(2)\n", 304 | "plt.plot(hydrograph_time, discharge_at_outlet, 'y-', label = 'outlet')\n", 305 | "plt.plot([np.min(hydrograph_time),np.max(hydrograph_time)],\n", 306 | " [outlet_eq_q,outlet_eq_q], 'y--', label = 'outlet eq Q')\n", 307 | "plt.plot(hydrograph_time, discharge_midstream, 'g-', label = 'midstream')\n", 308 | "plt.plot([np.min(hydrograph_time),np.max(hydrograph_time)],\n", 309 | " [midstream_eq_q,midstream_eq_q], 'g--', \n", 310 | " label = 'midstream eq Q')\n", 311 | "plt.plot(hydrograph_time, discharge_upstream, 'b-', label = 'upstream')\n", 312 | "plt.plot([np.min(hydrograph_time),np.max(hydrograph_time)],\n", 313 | " [upstream_eq_q,upstream_eq_q], 'b--', \n", 314 | " label = 'upstream eq Q')\n", 315 | "\n", 316 | "## Plot storm end and center of storm for reference\n", 317 | "plt.plot([storm_duration,storm_duration],[0,100],'k-', linewidth=2, label='storm end')\n", 318 | "plt.plot([storm_duration/2,storm_duration/2],[0,100],'k:', label='storm mid point')\n", 319 | "\n", 320 | "plt.ylabel('Discharge (cms)')\n", 321 | "plt.xlabel('Time (seconds)')\n", 322 | "plt.legend(loc = 'upper right')\n", 323 | "title_text = 'Hydrographs, Storm is '+ storm_flag + ', Watershed is ' \\\n", 324 | " + basin_flag\n", 325 | "plt.title(title_text)\n", 326 | "plt.axis([0, np.max(hydrograph_time), 0, 100])" 327 | ] 328 | }, 329 | { 330 | "cell_type": "markdown", 331 | "metadata": {}, 332 | "source": [ 333 | "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", 334 | "\n", 335 | "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", 336 | "\n", 337 | "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", 338 | "\n", 339 | "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", 340 | "\n", 341 | "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", 342 | "\n", 343 | "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?" 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": null, 349 | "metadata": {}, 350 | "outputs": [], 351 | "source": [] 352 | } 353 | ], 354 | "metadata": { 355 | "anaconda-cloud": {}, 356 | "kernelspec": { 357 | "display_name": "Python 3", 358 | "language": "python", 359 | "name": "python3" 360 | }, 361 | "language_info": { 362 | "codemirror_mode": { 363 | "name": "ipython", 364 | "version": 3 365 | }, 366 | "file_extension": ".py", 367 | "mimetype": "text/x-python", 368 | "name": "python", 369 | "nbconvert_exporter": "python", 370 | "pygments_lexer": "ipython3", 371 | "version": "3.6.6" 372 | } 373 | }, 374 | "nbformat": 4, 375 | "nbformat_minor": 2 376 | } 377 | -------------------------------------------------------------------------------- /geomorphology_exercises/hillslope_notebooks/north_carolina_piedmont_hillslope_class_notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Using Landlab to explore a diffusive hillslope in the piedmont of North Carolina \n", 15 | "\n", 16 | "This notebook was developed in collaboration with Karl Wegmann at North Carolina State University. This notebook was coded by Nicole Gasparini at Tulane University." 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "
\n", 24 | "For tutorials on learning Landlab, click here: https://github.com/landlab/landlab/wiki/Tutorials\n", 25 | "
\n" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": {}, 31 | "source": [ 32 | "**What is this notebook?**\n", 33 | "\n", 34 | "This notebook is designed to be an exercise for students in a quantative geomorphology class. This notebook is meant to illustrate to students how a model can be used to understand and interpret real landscapes. This notebook is not designed to teach students how to code, nor is it designed to teach students how to use Landlab.\n", 35 | "\n", 36 | "This notebook provides data from a real landscape in North Carolina (below) in order to compare the shape of this hillslope with those produced by models using linear diffusion. A group of students at NC State have collected elevation data along the yellow transect in the image of the landscape below. This notebook uses that transect data and compares it with model output.\n", 37 | " \n", 38 | "![alt text](nc_image_with_transect.png)\n", 39 | "\n", 40 | "This notebook steps students through exercises to quantify the diffusivity on this hillslope, assuming that sediment transport on this hillslope follows a linear diffusion law. Students should be introduced to the linear diffusion transport law _before_ using this notebook.\n", 41 | "\n", 42 | "**Application of linear diffusion transport law:**\n", 43 | "\n", 44 | "The tranport law applied here is of the form:\n", 45 | "\\begin{equation}\n", 46 | "q_s = -D \\nabla z\n", 47 | "\\end{equation}\n", 48 | "where ${q}_s$ is the transport rate with dimensions of L$^2$T$^{-1}$; $D$ is a transport coefficient with dimensions of L$^2$T$^{-1}$; and $z$ is elevation. $\\nabla z$ is the gradient in the landscape, or change in elevation with change in distance. Landscape slope is $-\\nabla z$ (assuming distance increases downhill), hence the negative in the above equation. \n", 49 | " \n", 50 | "Changes in elevation, or erosion, are calculated from conservation of mass:\n", 51 | "\\begin{equation}\n", 52 | "\\frac{dz}{dt} = U-\\nabla q_s\n", 53 | "\\end{equation}\n", 54 | "where $U$ is the rock uplift rate (relative to a fixed elevation at the boundary), with dimensions LT$^{-1}$, and $t$ is time.\n", 55 | "\n", 56 | "Note that at steady state the rock uplift rate sets the erosion rate. If the erosion rate in a landscape is a known, a modeling scenario in which the landscape is uplifting at the same rate as the known erosion rate will eventually lead to a landscape that is also eroding at that rate. \n", 57 | "\n", 58 | "Although we call $U$ the rate of rock uplift rate, we would get the same solution if $U$ is the rate of river erosion in the river at the base of a hillslope. For this example, it might easier to think of $U$ as a base-level lowering rate.\n", 59 | "\n", 60 | "**What will we do with Landlab?**\n", 61 | "\n", 62 | "Here we will use the Landlab component *LinearDiffuser*, to explore whether hillslopes evolved according to a linear diffusion rule look like the example North Carolina hillslope. We will just be eye-balling similarities. No rigorous comparison between the real and modeled hillslope is performed.\n", 63 | "\n", 64 | "More general background on applying hillslope process models to real landscapes can be found in this paper:\n", 65 | "\n", 66 | "Roering, Joshua J. (2008) \"How well can hillslope evolution models “explain” topography? Simulating soil transport and production with high-resolution topographic data.\" Geological Society of America Bulletin.\n", 67 | "\n", 68 | "This paper has a nice compilation of measured landscape diffusivity values that can help put the values you get from this exercise in context:\n", 69 | "\n", 70 | "Perron, J. T., (2017) \"Climate and the pace of erosional landscape evolution\" Annual Review of Earth and Planetary Sciences.\n", 71 | "\n", 72 | "**What do you need to know about this Landscape?**\n", 73 | "\n", 74 | "General information on this landscape can be found in this reference:\n", 75 | "\n", 76 | "Wegmann, K. W., Lewis, R. Q., & Hunt, M. C. (2012). \"Historic mill ponds and piedmont stream water quality: Making the connection near Raleigh, North Carolina\". The Geological Society of America, Field Guide 29.\n", 77 | "\n", 78 | "For now the following information is provided.\n", 79 | "\n", 80 | "- The site is in the Piedmont near Raleigh, North Carolina.\n", 81 | "- The site is in the W.B. Umstead State Park which is in the Sycamore Creek watershed. Sycamore Creek drains into the Neuse River.\n", 82 | "- The area gets ~ 1.25 m/yr of rainfall.\n", 83 | "- The site is currently forested.\n", 84 | "- Basin average erosion rates from the area are on the order of 10 m/million years, or 1e-5 m/yr. These rates are averaged over approximately 100,000 years. These rates are from a nearby area similar to this, but not exactly this study area.\n", 85 | "- The site has been heavily impacted from agriculture due to European settlers, beginning in the 1600s. \n", 86 | "\n", 87 | "**STUDENTS - Step 0 - What you need to do:**\n", 88 | "\n", 89 | "You will start out by making the assumption that the landscape is eroding at a rate of 1e-5 m/yr. \n", 90 | "\n", 91 | "As you will see, the study area hillslope profile has a form similar to what one would expect from a uniformly eroding diffusive profile. **Your first goal is to find the diffusivity and time required for the profile to reach steady state given the background erosion rate of 1e-5 m/yr.** You can do that by running the code below. **Take special note of Code Block 4 where you set the diffusivity. Make sure choose a resonable initial value, and record what your initial value was.** Code Block 5 will allow you to see the analytical solution for hillslope form using different $D$ Values. You can play with the analystical solution to find the best $D$. Also be prepared to change model run time (Code Block 4) for your initial experiments. Once you iterate to a modeled profile that you feel reasonably matches the DEM profile (just eye-ball the similarity), you will be ready to answer the questions that follow all of the code. \n", 92 | "\n", 93 | "**How to run a Jupyter notebook:**\n", 94 | "\n", 95 | "Read the text boxes and sequentially run each code block (shift - enter OR got to the _Cell_ pulldown menu at the top and choose _Run Cells_). While a code block is running there is a * in the brackets next to it. Once it has completed running there will be a number in the brackets next to it\n", 96 | "\n", 97 | "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. If you just change one code block and rerun only that code block, only the parts of the code in that code block will be updated. (E.g. if you change parameters but don't reset the code blocks that initialize run time or topography, then these values will not be reset.) " 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "**Now on to the code...**\n", 105 | "\n", 106 | "We start by importing libraries that we will need to run the code. You should not need to edit this code block." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "# Code Block 1\n", 116 | "\n", 117 | "import numpy as np\n", 118 | "from landlab.io import read_esri_ascii\n", 119 | "from landlab.plot.imshow import imshow_grid\n", 120 | "import matplotlib.pyplot as plt\n", 121 | "#below is to make plots show up in the notebook\n", 122 | "%matplotlib inline " 123 | ] 124 | }, 125 | { 126 | "cell_type": "markdown", 127 | "metadata": {}, 128 | "source": [ 129 | "Now we will use the survey data from the NC State students and compare it to model output. Below is the information from the survey. You should not need to edit this code block." 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "# Code Block 2\n", 139 | "\n", 140 | "# distance and elevation data along the survey line\n", 141 | "\n", 142 | "field_dist = np.array([0,1,2,3,4,4.99,5.99,6.99,7.99,8.99,9.99,10.99,11.99,\n", 143 | " 12.99,13.99,14.98,15.98,16.98,17.98,18.98,19.98,\n", 144 | " 20.98,21.98,22.98,23.98,24.97,25.97,26.97,27.97,\n", 145 | " 28.97,29.97,30.97,31.97,32.97,33.97,34.96,35.96,\n", 146 | " 36.96,37.96,38.96,39.96,40.96,41.96,42.96,43.95,\n", 147 | " 44.95,45.95,46.95,49.95,50.95,51.95,52.95,53.94,\n", 148 | " 54.94,55.94,56.94,57.94,58.94,59.94,60.94,61.94,\n", 149 | " 62.94,63.93,64.93,65.93,66.93,67.93,68.93,69.93,\n", 150 | " 70.93,71.93,72.92,73.92,74.92,75.92,76.92,77.92,\n", 151 | " 78.92,79.92,80.92,81.92,82.91,83.91,84.91,85.91,\n", 152 | " 86.91,87.91,88.91]) \n", 153 | "field_z = np.array([0,0.03,0.3,0.47,0.62,0.83,1.09,1.31,1.54,1.8,2.14,2.38,\n", 154 | " 2.55,2.84,3.15,3.49,3.78,4.05,4.41,4.57,4.77,5.05,5.29,\n", 155 | " 5.46,5.68,5.96,6.4,6.81,6.99,7.21,7.45,7.63,7.79,7.87,\n", 156 | " 8.06,8.24,8.4,8.51,8.65,8.68,8.82,8.98,9.01,9.04,9.05,\n", 157 | " 9.09,9.07,9.07,9.02,8.93,8.9,8.83,8.73,8.62,8.47,8.28,\n", 158 | " 8.22,8,7.82,7.75,7.39,7.2,7.04,6.79,6.6,6.39,6.1,5.77,\n", 159 | " 5.5,5.3,5.11,4.89,4.64,4.5,4.32,4.1,3.96,3.6,3.19,2.92,\n", 160 | " 2.73,2.41,2.12,1.76,1.21,0.95,0.56,0.06])" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "metadata": {}, 166 | "source": [ 167 | "We will create a grid for our model using Landlab's *RasterModelGrid* class, which we need to import. We make a grid with *dx* = *dy* = 1.0 m (same resolution as the survey data). We make a grid that has 5 columns and 90 rows, to match the length of the profile from the real landscape." 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "# Code Block 3\n", 177 | "\n", 178 | "from landlab import RasterModelGrid\n", 179 | "mg = RasterModelGrid((90, 5), 1.0) # make grid\n", 180 | "z_vals = mg.add_ones('topographic__elevation', at='node') # initialize z values\n", 181 | "\n", 182 | "# Set initial conditions\n", 183 | "initial_elevation = np.multiply(z_vals, -1.0) # this line and next set elevation to 87. m\n", 184 | "z_vals += initial_elevation\n", 185 | "\n", 186 | "# Set boundary conditions\n", 187 | "mg.set_closed_boundaries_at_grid_edges(True, False, True, False)\n", 188 | "\n", 189 | "# Initialize values for plotting variables down the middle of the hillslope\n", 190 | "\n", 191 | "ycoord_rast = mg.node_vector_to_raster(mg.node_y)\n", 192 | "ys_grid = ycoord_rast[:, 2]" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "Now we import and initialize the *LinearDiffuser* component. In this case the units on our diffusivity coefficient, or transport coefficient, are m$^2$yr$^{-1}$.\n", 200 | "\n", 201 | "**NOTE to Students:** You need to chose a reasonable initial value for D (diffusivity). Remember you need to justify your initial guess for D. Supplied references should help with this.\n", 202 | "\n", 203 | "We also initialize a few more parameters." 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "metadata": {}, 210 | "outputs": [], 211 | "source": [ 212 | "# Code Block 4\n", 213 | "\n", 214 | "from landlab.components import LinearDiffuser\n", 215 | "D = 0.005 # value in m^2/yr\n", 216 | "lin_diffuse = LinearDiffuser(mg, linear_diffusivity=D)\n", 217 | "\n", 218 | "# Uniform rate of rock uplift, which drives uniform erosion at steady state\n", 219 | "uplift_rate = 0.00001 # m/year, start with 1e-5 m/yr\n", 220 | "\n", 221 | "# Total time in years that the model will run for.\n", 222 | "runtime = 500000 # years\n", 223 | "\n", 224 | "# Stability criteria for timestep dt. Coefficient can be changed\n", 225 | "# depending on our tolerance for stability vs tolerance for run time.\n", 226 | "# Do not change this.\n", 227 | "dt = 0.5 * mg.dx * mg.dx / D\n", 228 | "\n", 229 | "print(\"dt\", dt)\n", 230 | "\n", 231 | "# nt is number of time steps\n", 232 | "nt = int(runtime // dt)\n", 233 | "\n", 234 | "# Below is to keep track of time for labeling plots\n", 235 | "time_counter = 0\n", 236 | "\n", 237 | "# length of uplift over a single time step, meters\n", 238 | "uplift_per_step = uplift_rate * dt" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "Now we figure out the analytical solution for the elevation of the steady-state profile.\n", 246 | "\n", 247 | "Before we evolve the landscape, we look at the model initial topography, the analytical solution, and the field profile." 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "# Code Block 5\n", 257 | "\n", 258 | "#ANALYTICAL SOLUTION\n", 259 | "ys = np.arange(mg.number_of_node_rows*mg.dx-mg.dx)\n", 260 | "\n", 261 | "# location of divide or ridge crest -> middle of grid \n", 262 | "# based on boundary conds.\n", 263 | "divide_loc = (mg.number_of_node_rows*mg.dx-mg.dx)/2\n", 264 | "\n", 265 | "# half-width of the ridge\n", 266 | "half_width = (mg.number_of_node_rows*mg.dx-mg.dx)/2\n", 267 | "\n", 268 | "# analytical solution for elevation under linear diffusion at steady state\n", 269 | "zs = (uplift_rate/(2*D)) * \\\n", 270 | " (np.power(half_width, 2) - np.power(ys - divide_loc, 2))\n", 271 | "\n", 272 | "#PLOTTING\n", 273 | "plt.figure()\n", 274 | "imshow_grid(mg, 'topographic__elevation')\n", 275 | "plt.title('initial topography, at right is the colorbar')\n", 276 | "plt.figure()\n", 277 | "elev_rast = mg.node_vector_to_raster(\n", 278 | " mg.at_node['topographic__elevation'])\n", 279 | "plt.figure()\n", 280 | "plt.plot(ys_grid, elev_rast[:, 2], 'r-', label='model')\n", 281 | "plt.plot(ys, zs, 'k--', label='analytical solution')\n", 282 | "plt.plot(field_dist, field_z, 'b:', label='field data')\n", 283 | "plt.xlabel('horizontal distance (m)')\n", 284 | "plt.ylabel('elevation (m)')\n", 285 | "plt.legend(loc='lower center')\n", 286 | "#plt.title('before running model')" 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "metadata": {}, 292 | "source": [ 293 | "Now you can update the values of $D$ in Code Block 4 and rerun Code Block 5 to fit the analytical solution to the field data. \n", 294 | "\n", 295 | "Once you have done that, run the model and evolve the landscape to make sure it also fits the analytical solution. You may need to update $runtime$ in Code Block 4 if the model does not match the analytical solution. Remember that you need to find the $D$ value and approximate time that it takes for the landscape to reach steady state.\n", 296 | "\n", 297 | "Below is the time loop that does all the calculations. " 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": null, 303 | "metadata": {}, 304 | "outputs": [], 305 | "source": [ 306 | "# Code Block 6\n", 307 | "\n", 308 | "for i in range(nt):\n", 309 | " mg['node']['topographic__elevation'][mg.core_nodes] += uplift_per_step\n", 310 | " lin_diffuse.run_one_step(dt)\n", 311 | " time_counter += dt\n", 312 | " \n", 313 | "print('time evolved for ',time_counter,' years')" 314 | ] 315 | }, 316 | { 317 | "cell_type": "markdown", 318 | "metadata": {}, 319 | "source": [ 320 | "Now we plot the evolved cross-section." 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": null, 326 | "metadata": {}, 327 | "outputs": [], 328 | "source": [ 329 | "# Code Block 7\n", 330 | "plt.figure()\n", 331 | "elev_rast = mg.node_vector_to_raster(\n", 332 | " mg.at_node['topographic__elevation'])\n", 333 | "plt.plot(ys_grid, elev_rast[:, 2], 'r-', label='model')\n", 334 | "plt.plot(ys, zs, 'k--', label='analytical solution')\n", 335 | "plt.plot(field_dist, field_z, 'b:', label='field data')\n", 336 | "plt.xlabel('horizontal distance (m)')\n", 337 | "plt.ylabel('vertical elevation (m)')\n", 338 | "plt.legend(loc='lower center')\n", 339 | "plt.title('topographic cross section at time %s, with D = %s m^2/yr'%(time_counter,D))" 340 | ] 341 | }, 342 | { 343 | "cell_type": "markdown", 344 | "metadata": {}, 345 | "source": [ 346 | "**Questions to answer and further model experiments:**\n", 347 | "\n", 348 | "_NOTE_ You should hand in a typed, electronic document that has figures embedded in the document. The document can be any type of readable file. Please include your name in the file name that you turn in.\n", 349 | "\n", 350 | "**Questions:**\n", 351 | "1. Your first task was to find the diffusivity and time to steady state required for the model to produce a landscape similar to the field area near Raleigh, NC. (Time to steady state can be approximate, as in within 500,000 years.) What was your initial guess for a diffusivity? What information did you use to choose that initial value? What was the value that produced a good match between the modeled and real hillslope form? (Again, you can eye-ball the match. Just get close visually.) Compared with other values of diffusivity that have been reported in the literature, how does your value compare? Given what you know about this landscape, does this seem like a reasonable diffusivity? Explain.\n", 352 | "2. What was the estimated time to steady state using the model? Compare the time to steady state with the time over which erosion rates were measured and the time period over which settlers have dramatically impacted this landscape. What are the implications of the differences among the time to steady state, the time over which erosion rates were measured, and time over which settlers have impacted this system?\n", 353 | "3. It is possible that settlers accelerated erosion rates (from the background, pre-settlement rate, which here we can assume is set from \"background rock uplift\" as 1e-5 m/yr) by almost 500 times. If that happened, the pre-settlement profile likely had a higher peak elevation (and higher total relief), and accelerated erosion would have removed soil and lowered elevations across the profile. This has implications for your estimated diffusivity. \n", 354 | " - Develop a scenario in which you evolve a 'pre-settlement' hillslope to steady state (should have higher relief than the current profile) with a different diffusivity. Think about whether the diffusivity should be higher or lower to create higher relief, using the same background erosion/rock uplift rate. Change Code Block 4 and create this new pre-settlement steady state landscape using Code Blocks 6 and 7. \n", 355 | " - Use this landscape as the initial condition to evolve the landscape another 400 years with a new diffusivity to simulate the impact of settlers. (Once you get your pre-settlement hillslope, go back to Code Block 4 and change $D$ and $runtime$ accordingly, then rerun Code Blocks 6 & 7). \n", 356 | " - You should end up with a simulated hillslope that matches the current topography, but you got there in a different way than you did for the first part of this exercise. Provide plots and describe in detail exactly what you did to simulate the pre- and post-settler landscape. Are there noticeable changes in the landscape? Does this have implications for future evolution of this hillslope?" 357 | ] 358 | }, 359 | { 360 | "cell_type": "code", 361 | "execution_count": null, 362 | "metadata": {}, 363 | "outputs": [], 364 | "source": [] 365 | } 366 | ], 367 | "metadata": { 368 | "anaconda-cloud": {}, 369 | "kernelspec": { 370 | "display_name": "Python 3", 371 | "language": "python", 372 | "name": "python3" 373 | }, 374 | "language_info": { 375 | "codemirror_mode": { 376 | "name": "ipython", 377 | "version": 3 378 | }, 379 | "file_extension": ".py", 380 | "mimetype": "text/x-python", 381 | "name": "python", 382 | "nbconvert_exporter": "python", 383 | "pygments_lexer": "ipython3", 384 | "version": "3.6.6" 385 | } 386 | }, 387 | "nbformat": 4, 388 | "nbformat_minor": 1 389 | } 390 | -------------------------------------------------------------------------------- /geomorphology_exercises/channels_streampower_notebooks/stream_power_channels_class_notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "# Quantifying river channel evolution with Landlab\n", 15 | "These exercises are based on a project orginally designed by Kelin Whipple at Arizona State University. This notebook was created by Nicole Gasparini at Tulane University." 16 | ] 17 | }, 18 | { 19 | "cell_type": "markdown", 20 | "metadata": {}, 21 | "source": [ 22 | "
\n", 23 | "For tutorials on learning Landlab, click here: https://github.com/landlab/landlab/wiki/Tutorials\n", 24 | "
" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "** What is this notebook? **\n", 32 | "\n", 33 | "This notebook illustrates the evolution of detachment-limited channels in an actively uplifting landscape. The landscape evolves according to the equation:\n", 34 | "\n", 35 | "\\begin{equation}\n", 36 | " \\frac{d z}{d t} = -K_\\text{sp} A^{m_{sp}} S^{n_{sp}} + U\n", 37 | "\\end{equation}\n", 38 | "Here, $K_{sp}$ is the erodibility coefficient on fluvial incision, which is thought to be positively correlated with climate wetness, or storminess (this is hard to quantify) and to be negatively correlated with rock strength (again, rock strength is hard to quantify). $m_{sp}$ and $n_{sp}$ are positive exponents, usually thought to have a ratio, $m_{sp}/n_{sp} \\approx 0.5$. $A$ is drainage area and $S$ is the slope of steepest descent ($-\\frac{dz}{dx}$) where $x$ is horizontal distance (positive in the downslope direction) and $z$ is elevation. (If slope is negative there is no fluvial erosion.) $U$ is an externally-applied rock uplift field.\n", 39 | "\n", 40 | "The fluvial erosion term is also known as the stream power equation. Before using this notebook you should be familiar with this equation from class lectures and reading. \n", 41 | "\n", 42 | "For a great overview of the stream power equation, see: \n", 43 | "\n", 44 | "- Whipple and Tucker, 1999, Dynamics of the stream-power river incision model: Implications for height limits of mountain ranges, landscape response timescales, and research needs, Journal of Geophysical Research.\n", 45 | "\n", 46 | "For some great illustrations of modeling with the sream power equation, see:\n", 47 | "\n", 48 | "- Tucker and Whipple, 2002, Topographic outcomes predicted by stream erosion models: Sensitivity analysis and intermodel comparison, Journal of Geophysical Research.\n", 49 | "\n", 50 | "Helpful background on landscape sensitivity to rock uplift rates and patterns can be found here:\n", 51 | "\n", 52 | "- Kirby and Whipple, 2012, Expression of active tectonics in erosional landscapes, Journal of Structural Geology.\n", 53 | "\n", 54 | "** What will you do? **\n", 55 | "\n", 56 | "In this exercise you will modify the code to get a better understanding of how rock uplift rates and patterns and the erodibility coefficient control fluvial channel form.\n", 57 | "\n", 58 | "Start at the top by reading each block of text and sequentially running each code block (shift - enter OR got to the _Cell_ pulldown menu at the top and choose _Run Cells_). \n", 59 | "\n", 60 | "If you just change one code block and rerun only that code block, only the parts of the code in that code block will be updated. (E.g. if you change parameters but don't reset the code blocks that initialize run time or topography, then these values will not be reset.) \n", 61 | "\n", 62 | "** STUDENTS: Questions to answer before starting this assignment. **\n", 63 | "\n", 64 | "Answer these questions before running the notebook.\n", 65 | "\n", 66 | "1. What do you think will happen to total relief (defined as the maximum minus the minimum elevation, here area is fixed) and channel slope at steady state if $K_{sp}$ is uniformly increased?\n", 67 | "2. What do you think will happen to total relief and channel slope at steady state if $U$ is uniformly increased?\n", 68 | "3. How do you think a steady-state landscape with a uniform low rock uplift rate will respond if rock uplift is uniformly increased (relative to a steady base level)? How will channel slopes change through time?" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "** Now on to the code... **\n", 76 | "\n", 77 | "First we have to import the parts of Python and Landlab that are needed to run this code. You should not have to change this first code block." 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "# Code block 1\n", 87 | "\n", 88 | "import numpy as np\n", 89 | "import copy\n", 90 | "from landlab import RasterModelGrid\n", 91 | "from landlab.components import StreamPowerEroder, FlowRouter\n", 92 | "from landlab.components import ChiFinder, SteepnessFinder\n", 93 | "from landlab.plot import channel_profile as prf\n", 94 | "from landlab import imshow_grid\n", 95 | "from matplotlib import pyplot as plt\n", 96 | "from landlab.io import write_esri_ascii\n", 97 | "#below is to make plots show up in the notebook\n", 98 | "%matplotlib inline " 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "Make a grid and set boundary conditions. " 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "# Code Block 2\n", 115 | "\n", 116 | "number_of_rows = 50 # number of raster cells in vertical direction (y)\n", 117 | "number_of_columns = 100 # number of raster cells in horizontal direction (x)\n", 118 | "dxy = 200 # side length of a raster model cell, or resolution [m]\n", 119 | "\n", 120 | "# Below is a raster (square cells) grid, with equal width and height \n", 121 | "mg1 = RasterModelGrid((number_of_rows,number_of_columns), dxy)\n", 122 | "\n", 123 | "# Set boundary conditions - only the south side of the grid is open.\n", 124 | "# Boolean parameters are sent to function in order of\n", 125 | "# east, north, west, south.\n", 126 | "mg1.set_closed_boundaries_at_grid_edges(True, True, True, False)" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "Here we make the initial grid of elevation of zeros with a very small amount of noise to make a more pleasing network." 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": null, 139 | "metadata": {}, 140 | "outputs": [], 141 | "source": [ 142 | "# Code Block 3\n", 143 | "\n", 144 | "np.random.seed(35) # seed set so our figures are reproducible\n", 145 | "mg1_noise = np.random.rand(mg1.number_of_nodes)/1000. # intial noise on elevation gri\n", 146 | "\n", 147 | "# set up the elevation on the grid\n", 148 | "z1 = mg1.add_zeros('node', 'topographic__elevation')\n", 149 | "z1 += mg1_noise" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "Set parameters related to time." 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "# Code Block 4\n", 166 | "\n", 167 | "tmax = 5E5 # time for the model to run [yr] (Original value was 5E5 yr)\n", 168 | "dt = 1000 # time step [yr] (Original value was 100 yr)\n", 169 | "total_time = 0 # amount of time the landscape has evolved [yr]\n", 170 | "# total_time will increase as you keep running the code.\n", 171 | "\n", 172 | "t = np.arange(0, tmax, dt) # each of the time steps that the code will run" 173 | ] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "Set parameters for incision and intializing all of the process components that do the work. We also initialize tools for quantifying the landscape." 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": null, 185 | "metadata": {}, 186 | "outputs": [], 187 | "source": [ 188 | "# Code Block 5\n", 189 | "\n", 190 | "# Original K_sp value is 1e-5\n", 191 | "K_sp = 1.E-5 # units vary depending on m_sp and n_sp \n", 192 | "m_sp = 0.5 # exponent on drainage area in stream power equation\n", 193 | "n_sp = 1.0 # exponent on slope in stream power equation\n", 194 | "\n", 195 | "frr = FlowRouter(mg1) # intializing flow routing\n", 196 | "spr = StreamPowerEroder(mg1, K_sp=K_sp, m_sp=m_sp, n_sp=n_sp, threshold_sp=0,\n", 197 | " use_Q=None) #initializing stream power incision\n", 198 | "\n", 199 | "theta = m_sp/n_sp \n", 200 | "# initialize the component that will calculate channel steepness\n", 201 | "sf = SteepnessFinder(mg1, reference_concavity=theta, min_drainage_area=1000.)\n", 202 | "# initialize the component that will calculate the chi index\n", 203 | "cf = ChiFinder(mg1, min_drainage_area=1000., reference_concavity=theta, use_true_dx=True)" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "Initialize rock uplift rate. This will need to be changed later." 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": {}, 217 | "outputs": [], 218 | "source": [ 219 | "# Code Block 6\n", 220 | "\n", 221 | "# uplift_rate [m/yr] (Original value is 0.0001 m/yr)\n", 222 | "uplift_rate = np.ones(mg1.number_of_nodes)*0.0001 " 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "Now for the code loop. \n", 230 | "\n", 231 | "Note that you can rerun Code Block 7 many times, and as long as you don't reset the elevation field (Code Block 3), it will take the already evolved landscape and evolve it even more. If you want to change parameters in other code blocks (e.g. Code Block 5 or 6), you can do that too, and as long as you don't reset the elevation field (Code Block 3) the new parameters will apply on the already evolved topography. " 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": null, 237 | "metadata": { 238 | "scrolled": true 239 | }, 240 | "outputs": [], 241 | "source": [ 242 | "# Code Block 7\n", 243 | "\n", 244 | "for ti in t:\n", 245 | " z1[mg1.core_nodes] += uplift_rate[mg1.core_nodes]*dt # uplift the landscape\n", 246 | " frr.run_one_step() # route flow\n", 247 | " spr.run_one_step(dt) # fluvial incision\n", 248 | " total_time += dt # update time keeper\n", 249 | " print(total_time)" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "Plot the topography." 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": null, 262 | "metadata": {}, 263 | "outputs": [], 264 | "source": [ 265 | "# Code Block 8\n", 266 | "\n", 267 | "imshow_grid(mg1, 'topographic__elevation', grid_units=('m', 'm'),\n", 268 | " var_name='Elevation (m)')\n", 269 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy) + 'm'\n", 270 | "plt.title(title_text)\n", 271 | "\n", 272 | "max_elev = np.max(z1)\n", 273 | "print('Maximum elevation is ', np.max(z1))" 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "Plot the slope and area data at each point on the landscape (in log-log space)." 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": null, 286 | "metadata": { 287 | "scrolled": true 288 | }, 289 | "outputs": [], 290 | "source": [ 291 | "# Code Block 9\n", 292 | "\n", 293 | "indices = np.where(mg1.status_at_node[mg1.at_node['flow__receiver_node']] == 0)\n", 294 | "plt.loglog(mg1.at_node['drainage_area'][indices],\n", 295 | " mg1.at_node['topographic__steepest_slope'][indices], 'b.')\n", 296 | "plt.ylabel('Topographic slope')\n", 297 | "plt.xlabel('Drainage area (m^2)')\n", 298 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy) + 'm'\n", 299 | "plt.title(title_text)" 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "metadata": {}, 305 | "source": [ 306 | "It is slightly easier to interpret slope-area data when we look at a single channel, rather than the entire landscape. Below we plot the profile and slope-area data for the three largest channels on the landscape." 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": null, 312 | "metadata": {}, 313 | "outputs": [], 314 | "source": [ 315 | "# Code Block 10\n", 316 | "\n", 317 | "# find the location of the largest channels, set initially to find 3 chans\n", 318 | "profile_IDs = prf.channel_nodes(mg1, mg1.at_node['topographic__steepest_slope'],\n", 319 | " mg1.at_node['drainage_area'],\n", 320 | " mg1.at_node['flow__receiver_node'],\n", 321 | " number_of_channels=3)\n", 322 | "\n", 323 | "# find the upstream distances in these channels\n", 324 | "dists_upstr = prf.get_distances_upstream(\n", 325 | " mg1, len(mg1.at_node['topographic__steepest_slope']),\n", 326 | " profile_IDs, mg1.at_node['flow__link_to_receiver_node'])\n", 327 | "\n", 328 | "# channel profiles\n", 329 | "plt.figure(1)\n", 330 | "plt.plot(dists_upstr[0], z1[profile_IDs[0]], 'b-', label='channel 1')\n", 331 | "plt.plot(dists_upstr[1], z1[profile_IDs[1]], 'k-', label='channel 2')\n", 332 | "plt.plot(dists_upstr[2], z1[profile_IDs[2]], 'r-', label='channel 3')\n", 333 | "plt.xlabel('distance upstream (m)')\n", 334 | "plt.ylabel('elevation (m)')\n", 335 | "plt.legend(loc='upper left')\n", 336 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy) + 'm'\n", 337 | "plt.title(title_text)\n", 338 | "\n", 339 | "# slope-area data in just the profiled channels\n", 340 | "plt.figure(2)\n", 341 | "plt.loglog(mg1.at_node['drainage_area'][profile_IDs[0]],\n", 342 | " mg1.at_node['topographic__steepest_slope'][profile_IDs[0]], 'b.',\n", 343 | " label='channel 1')\n", 344 | "plt.loglog(mg1.at_node['drainage_area'][profile_IDs[1]],\n", 345 | " mg1.at_node['topographic__steepest_slope'][profile_IDs[1]], 'k.',\n", 346 | " label='channel 2')\n", 347 | "plt.loglog(mg1.at_node['drainage_area'][profile_IDs[2]],\n", 348 | " mg1.at_node['topographic__steepest_slope'][profile_IDs[2]], 'r.',\n", 349 | " label='channel 3')\n", 350 | "plt.legend(loc='lower left')\n", 351 | "plt.xlabel('drainage area (m^2)')\n", 352 | "plt.ylabel('channel slope [m/m]')\n", 353 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy) + 'm'\n", 354 | "plt.title(title_text)" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "The chi index is a useful way to quantitatively interpret fluvial channels. Below we plot the chi index in the three largest channels and also a chi map across the entire landscape. " 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "# Code Block 11\n", 371 | "\n", 372 | "# Relocate profile IDs and calculate distance upstream, just in case\n", 373 | "# Code Blocks are run out-of-order\n", 374 | "profile_IDs = prf.channel_nodes(mg1, mg1.at_node['topographic__steepest_slope'],\n", 375 | " mg1.at_node['drainage_area'],\n", 376 | " mg1.at_node['flow__receiver_node'],\n", 377 | " number_of_channels=3)\n", 378 | "\n", 379 | "dists_upstr = prf.get_distances_upstream(\n", 380 | " mg1, len(mg1.at_node['topographic__steepest_slope']),\n", 381 | " profile_IDs, mg1.at_node['flow__link_to_receiver_node'])\n", 382 | "\n", 383 | "# calculate the chi index\n", 384 | "cf.calculate_chi()\n", 385 | "\n", 386 | "# chi-elevation plots in the profiled channels\n", 387 | "plt.figure(3)\n", 388 | "plt.plot(mg1.at_node['channel__chi_index'][profile_IDs[0]], \n", 389 | " mg1.at_node['topographic__elevation'][profile_IDs[0]],'b-',\n", 390 | " label='channel 1')\n", 391 | "plt.plot(mg1.at_node['channel__chi_index'][profile_IDs[1]], \n", 392 | " mg1.at_node['topographic__elevation'][profile_IDs[1]],'k-',\n", 393 | " label='channel 2')\n", 394 | "plt.plot(mg1.at_node['channel__chi_index'][profile_IDs[2]], \n", 395 | " mg1.at_node['topographic__elevation'][profile_IDs[2]],'r-',\n", 396 | " label='channel 3')\n", 397 | "plt.xlabel('chi index (m)')\n", 398 | "plt.ylabel('elevation (m)')\n", 399 | "plt.legend(loc = 'lower right')\n", 400 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + \\\n", 401 | " 'yr; $dx$='+str(dxy) + 'm' + '; concavity='+str(theta)\n", 402 | "plt.title(title_text)\n", 403 | "\n", 404 | "# chi map\n", 405 | "plt.figure(4)\n", 406 | "imshow_grid(mg1, 'channel__chi_index', grid_units=('m', 'm'),\n", 407 | " var_name='Chi index (m)', cmap='jet')\n", 408 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + \\\n", 409 | " 'yr; $dx$='+str(dxy) + 'm' + '; concavity='+str(theta)\n", 410 | "plt.title(title_text)" 411 | ] 412 | }, 413 | { 414 | "cell_type": "markdown", 415 | "metadata": {}, 416 | "source": [ 417 | "The channel steepness index is another useful index to quantify fluvial channels. Below we plot the steepness index in the same three largest channels, and also plot steepness index across the grid." 418 | ] 419 | }, 420 | { 421 | "cell_type": "code", 422 | "execution_count": null, 423 | "metadata": {}, 424 | "outputs": [], 425 | "source": [ 426 | "# Code Block 12\n", 427 | "\n", 428 | "# Relocate profile IDs and calculate distance upstream, just in case\n", 429 | "# Code Blocks are run out-of-order\n", 430 | "profile_IDs = prf.channel_nodes(mg1, mg1.at_node['topographic__steepest_slope'],\n", 431 | " mg1.at_node['drainage_area'],\n", 432 | " mg1.at_node['flow__receiver_node'],\n", 433 | " number_of_channels=3)\n", 434 | "\n", 435 | "dists_upstr = prf.get_distances_upstream(\n", 436 | " mg1, len(mg1.at_node['topographic__steepest_slope']),\n", 437 | " profile_IDs, mg1.at_node['flow__link_to_receiver_node'])\n", 438 | "\n", 439 | "# calculate channel steepness\n", 440 | "sf.calculate_steepnesses()\n", 441 | "\n", 442 | "# plots of steepnes vs. distance upstream in the profiled channels\n", 443 | "plt.figure(5)\n", 444 | "plt.plot(dists_upstr[0], mg1.at_node['channel__steepness_index'][profile_IDs[0]], 'bx',\n", 445 | " label='channel 1')\n", 446 | "plt.plot(dists_upstr[1], mg1.at_node['channel__steepness_index'][profile_IDs[1]], 'kx',\n", 447 | " label='channel 2')\n", 448 | "plt.plot(dists_upstr[2], mg1.at_node['channel__steepness_index'][profile_IDs[2]], 'rx',\n", 449 | " label='channel 3')\n", 450 | "plt.xlabel('distance upstream (m)')\n", 451 | "plt.ylabel('steepness index')\n", 452 | "plt.legend(loc = 'upper left')\n", 453 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + \\\n", 454 | " 'yr; $dx$='+str(dxy) + 'm' + '; concavity='+str(theta)\n", 455 | "plt.title(title_text)\n", 456 | "\n", 457 | "# channel steepness map\n", 458 | "plt.figure(6)\n", 459 | "imshow_grid(mg1, 'channel__steepness_index', grid_units=('m', 'm'),\n", 460 | " var_name='Steepness index ', cmap='jet')\n", 461 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + \\\n", 462 | " 'yr; $dx$='+str(dxy) + 'm' + '; concavity='+str(theta)\n", 463 | "plt.title(title_text)" 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "metadata": {}, 469 | "source": [ 470 | "If you have a grid that you want to export, uncomment and edit the appropriate lines below and run the code block." 471 | ] 472 | }, 473 | { 474 | "cell_type": "code", 475 | "execution_count": null, 476 | "metadata": {}, 477 | "outputs": [], 478 | "source": [ 479 | "# Code Block 13\n", 480 | "\n", 481 | "## Below has the name of the file that data will be written to.\n", 482 | "## You need to change the name of the file every time that you want\n", 483 | "## to write data, otherwise you will get an error.\n", 484 | "## This will write to the directory that you are running the code in.\n", 485 | "#write_file_name = 'data_file.txt'\n", 486 | "## Below is writing elevation data in the ESRI ascii format so that it can\n", 487 | "## easily be read into Arc GIS or back into Landlab.\n", 488 | "#write_esri_ascii(write_file_name, mg1, 'topographic__elevation')" 489 | ] 490 | }, 491 | { 492 | "cell_type": "markdown", 493 | "metadata": {}, 494 | "source": [ 495 | "After running every code block once, has the landscape reached steady state? Answer: NO! How do you know? After you think about this, you are ready to complete this project.\n", 496 | "\n", 497 | "Answer the following questions using the code above and below. All answers should be typed, and supporting figures (produced using the code) should be embedded in one document that you hand in. Code Blocks 8-12 and 18-21 produce different figures that you may find useful. You can use any or all of these different figures to help you with the questions below. (Download or screenshoot the figures.) \n", 498 | "\n", 499 | "Anything with a question mark should be answered in the document that you hand in. Make sure your write in full sentences and proofread the document that you hand in.\n", 500 | "\n", 501 | "1. **Steady state with low uplift rate. ** Using the parameters provided in the initial notebook, run the landscape to steady state. (Note that you can keep running the main evolution loop - Code Block 7 - and the different plotting blocks without running the code blocks above them. You may also want to change $tmax$ in Code Block 4.) How did you know that the landscape reached steady state? Note the approximate time that it took to reach steady state for your own reference. (This will be usefull for later questions.) Include appropriate plots. (If you want to analyze these landscapes outside of Landlab or save for later, make sure you save the elevation data to a text file (Code Block 13).)\n", 502 | "\n", 503 | "** NOTE, For the rest of the questions you should use Code Blocks 14 - 21. These will allow you to use the steady-state landscape created for question 1 - referred to here as the 'base landscape' - as the initial condition. Start by editing what you need to in Code Blocks 14 - 16. Run these each once, sequentially. You can run Code Block 17, the time loop, as many times as you need to, along with Code Blocks 18-21, which produce plots.**\n", 504 | "\n", 505 | "2. **Transient landscape responding to an increase in rock uplift. ** Use the base landscape and increase rock uplift uniformly by a factor of 4 to 0.0004 m/yr. Make sure you update the rock uplift rate (Code Block 16) and ensure that $tmax$ is 1e5 yrs and $dt$ is 500 yrs (Code Block 15). Run this until the maximum elevation in the grid is ~ 170 m and observe how the landscape gets to this elevation, i.e. plot intermediate steps. What patterns do you see in the supporting plots that illustrate this type of transient? Which patterns, if any, are diagnostic of a landscape response to uniform increase in rock uplift rate? (You may need to answer this after completing all of the questions.)\n", 506 | "\n", 507 | "3. ** Steady-state landscape with increased rock uplift. ** Now run the landscape from question 2 until it reaches steady state. (I.e. run the time loop, Code Block 17, a bunch of times. You can increase $tmax$ and $dt$ to make this run faster.) Provide a plot that illustrates that the landscape is in steady state. What aspects of the landscape have changed in comparison with the base landscape from question 1?\n", 508 | "\n", 509 | "4. ** Increase erodibility. ** Start again from the base landscape, but this time increase $K_{sp}$ to 2E-5 (Code Block 14). Make sure rock uplift rate is set to the original value of 0.0001 m/yr (Code Block 16). Set $tmax$ to 1e5 yrs (Code Block 15). Run for 1e5 yrs and save the plots that you think are diagnostic. Run for another 1e5 yrs and save plots again. Now run for 5e5 yrs and save plots again. Quantitatively describe how the landscape evolves in response to the increase in erodibility and provide supporting plots. What could cause a uniform increase in erodibility?\n", 510 | "\n", 511 | "5. ** Spatially varible uplift - discrete, massive earthquake. ** Start again from the base landscape, and make sure that $K_{sp}$ = 1E-5 (Code Block 14). Now add a seismic event to this steady state landscape - a fault that runs horizontally across the landscape at y = 4000 m, and instantaneously uplifts half the landscape by 10 meters (Code Block 16). In this case, we will keep background uplift uniform at 0.0001 m/yr. Set $tmax$ to 1e5 yrs and $dt$ to 500 yrs (Code Block 15) before evolving the landscape after the fault. Now run the time loop four times and look at the different plots after each loop. How does the landscape respond to this fault? What patterns do you see in the supporting plots that illustrate this type of transient? Which patterns, if any, are diagnostic of a channel response to an earthquake? (You may need to answer this after completing all of the questions.)\n", 512 | "\n", 513 | "6. ** Spatially Varible Rock Uplift - discrete fault with two different uplift rates. ** Start again from the base landscape, and make sure that $K_{sp}$ = 1E-5 (Code Block 14). Now we will add a fault (at y = 4000 m) to this landscape. In this case the uplift rate on the footwall is higher (0.0004 m/yr) than on the hanging wall (uplift rate = 0.0001 m/yr). (Edit Code Block 16.) Set $tmax$ to 1e5 yrs and $dt$ to 500 yrs (Code Block 15). Now run the time loop four separate times and look at the different plots after each loop. How does the landscape respond to this fault? What patterns do you see in the supporting plots that illustrate this type of transient? Which patterns, if any, are diagnostic of a channel response to a this type of gradient in rock uplift rates? (You may need to answer this after completing all of the questions.)\n", 514 | "\n", 515 | "7. ** Spatially Varible Rock Uplift - gradient in uplift across the range. ** Start again from the base landscape, and make sure that $K_{sp}$ = 1E-5 (Code Block 14). Now we will add a linear gradient in uplift rate across the entire range (edit Code Block 16). The maximum uplift rate will be 0.0004 m/yr at the core of the range, and 0.0001 m/yr at the front of the range. Set $tmax$ to 1e5 yrs (Code Block 4) and $dt$ to 500 yrs before you start running the time loop for the fault before you start running the time loop with the rock uplift gradient. Now run the time loop four separate times and look at the different plots after each loop. How does the landscape respond to this gradient in uplift rate? What patterns do you see in the supporting plots that illustrate this type of transient? Which patterns, if any, are diagnostic of a channel response to this type of gradient in rock uplift rates? (You may need to answer this after completing all of the questions.)\n", 516 | "\n", 517 | "8. ** Final Reflection. ** Was your initial insight into how parameters would affect the landscape correct? Discuss in 6 sentences or less." 518 | ] 519 | }, 520 | { 521 | "cell_type": "code", 522 | "execution_count": null, 523 | "metadata": {}, 524 | "outputs": [], 525 | "source": [ 526 | "# Code Block 14\n", 527 | "\n", 528 | "number_of_rows = 50 # number of raster cells in vertical direction (y)\n", 529 | "number_of_columns = 100 # number of raster cells in horizontal direction (x)\n", 530 | "dxy2 = 200 # side length of a raster model cell, or resolution [m]\n", 531 | "\n", 532 | "# Below is a raster (square cells) grid, with equal width and height \n", 533 | "mg2 = RasterModelGrid((number_of_rows,number_of_columns), dxy2)\n", 534 | "\n", 535 | "# Set boundary conditions - only the south side of the grid is open.\n", 536 | "# Boolean parameters are sent to function in order of\n", 537 | "# east, north, west, south.\n", 538 | "mg2.set_closed_boundaries_at_grid_edges(True, True, True, False)\n", 539 | "\n", 540 | "z2 = copy.copy(z1) # initialize the elevations with the steady state \n", 541 | "# topography produced for question 1\n", 542 | "z2 = mg2.add_field('node','topographic__elevation',z2)\n", 543 | "\n", 544 | "# K_sp value for base landscape is 1e-5\n", 545 | "K_sp2 = 1E-5 # units vary depending on m_sp and n_sp \n", 546 | "m_sp2 = 0.5 # exponent on drainage area in stream power equation\n", 547 | "n_sp2 = 1.0 # exponent on slope in stream power equation\n", 548 | "\n", 549 | "frr2 = FlowRouter(mg2) # intializing flow routing\n", 550 | "spr2 = StreamPowerEroder(mg2, K_sp=K_sp2, m_sp=m_sp2, n_sp=n_sp2, threshold_sp=0,\n", 551 | " use_Q=None) #initializing stream power incision\n", 552 | "\n", 553 | "theta2 = m_sp2/n_sp2 \n", 554 | "# initialize the component that will calculate channel steepness\n", 555 | "sf2 = SteepnessFinder(mg2, reference_concavity=theta2, min_drainage_area=1000.)\n", 556 | "# initialize the component that will calculate the chi index\n", 557 | "cf2 = ChiFinder(mg2, min_drainage_area=1000., reference_concavity=theta2, use_true_dx=True)" 558 | ] 559 | }, 560 | { 561 | "cell_type": "code", 562 | "execution_count": null, 563 | "metadata": {}, 564 | "outputs": [], 565 | "source": [ 566 | "# Code Block 15\n", 567 | "\n", 568 | "tmax = 1E5 # time for the model to run [yr] (Original value was 5E5 yr)\n", 569 | "dt = 500 # time step [yr] (Original value was 500 yr)\n", 570 | "total_time = 0 # amount of time the landscape has evolved [yr]\n", 571 | "# total_time will increase as you keep running the code.\n", 572 | "\n", 573 | "t = np.arange(0, tmax, dt) # each of the time steps that the code will run" 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": null, 579 | "metadata": {}, 580 | "outputs": [], 581 | "source": [ 582 | "# Code Block 16\n", 583 | "\n", 584 | "# uplift_rate [m/yr] (value was 0.0001 m/yr for base landscape)\n", 585 | "uplift_rate = np.ones(mg2.number_of_nodes)*0.0001 \n", 586 | "\n", 587 | "## If you want to add a one-time event that uplifts only part of the \n", 588 | "## landscape, uncomment the 3 lines below\n", 589 | "#fault_location = 4000 # [m]\n", 590 | "#uplift_amount = 10 # [m]\n", 591 | "#z2[np.where(mg2.node_y>fault_location)] += uplift_amount \n", 592 | "\n", 593 | "## IMPORTANT! To use the below fault generator, comment the one-time \n", 594 | "## uplift event above if it isn't already commented out.\n", 595 | "## Code below creates a fault horizontally across the grid.\n", 596 | "## Uplift rates are greater where y values > fault location.\n", 597 | "## To use, uncomment the 5 code lines below and edit to your values\n", 598 | "#fault_location = 4000 # [m]\n", 599 | "#low_uplift_rate = 0.0001 # [m/yr]\n", 600 | "#high_uplift_rate = 0.0004 # [m/yr]\n", 601 | "#uplift_rate[np.where(mg2.node_yfault_location)] = high_uplift_rate\n", 603 | "\n", 604 | "## IMPORTANT! To use below rock uplift gradient, comment the two\n", 605 | "## uplift options above if they aren't already commented out.\n", 606 | "## If you want a linear gradient in uplift rate \n", 607 | "## (increasing uplift into the range),\n", 608 | "## uncomment the 4 code lines below and edit to your values.\n", 609 | "#low_uplift_rate = 0.0001 # [m/yr]\n", 610 | "#high_uplift_rate = 0.0004 # [m/yr]\n", 611 | "## below is uplift gradient per node row index, NOT row value in meters\n", 612 | "#uplift_rate_gradient = (high_uplift_rate - low_uplift_rate)/(number_of_rows-3)\n", 613 | "#uplift_rate = low_uplift_rate + ((mg2.node_y / dxy)-1) * uplift_rate_gradient" 614 | ] 615 | }, 616 | { 617 | "cell_type": "code", 618 | "execution_count": null, 619 | "metadata": {}, 620 | "outputs": [], 621 | "source": [ 622 | "# Code Block 17\n", 623 | "\n", 624 | "for ti in t:\n", 625 | " z2[mg1.core_nodes] += uplift_rate[mg2.core_nodes]*dt # uplift the landscape\n", 626 | " frr2.run_one_step() # route flow\n", 627 | " spr2.run_one_step(dt) # fluvial incision\n", 628 | " total_time += dt # update time keeper\n", 629 | " print(total_time)" 630 | ] 631 | }, 632 | { 633 | "cell_type": "code", 634 | "execution_count": null, 635 | "metadata": {}, 636 | "outputs": [], 637 | "source": [ 638 | "# Code Block 18\n", 639 | "# Plot topography\n", 640 | "\n", 641 | "plt.figure(7)\n", 642 | "imshow_grid(mg2, 'topographic__elevation', grid_units=('m', 'm'),\n", 643 | " var_name='Elevation (m)')\n", 644 | "title_text = '$K_{sp}$='+str(K_sp2) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy) + 'm'\n", 645 | "plt.title(title_text)\n", 646 | "\n", 647 | "max_elev = np.max(z2)\n", 648 | "print('Maximum elevation is ', np.max(z2))" 649 | ] 650 | }, 651 | { 652 | "cell_type": "code", 653 | "execution_count": null, 654 | "metadata": {}, 655 | "outputs": [], 656 | "source": [ 657 | "# Code Block 19\n", 658 | "# Plot Channel Profiles and slope-area data along the channels\n", 659 | "\n", 660 | "# find the location of the largest channels, set initially to find 3 chans\n", 661 | "profile_IDs = prf.channel_nodes(mg2, mg2.at_node['topographic__steepest_slope'],\n", 662 | " mg2.at_node['drainage_area'],\n", 663 | " mg2.at_node['flow__receiver_node'],\n", 664 | " number_of_channels=3)\n", 665 | "\n", 666 | "# find the upstream distances in these channels\n", 667 | "dists_upstr = prf.get_distances_upstream(\n", 668 | " mg2, len(mg2.at_node['topographic__steepest_slope']),\n", 669 | " profile_IDs, mg2.at_node['flow__link_to_receiver_node'])\n", 670 | "\n", 671 | "# channel profiles\n", 672 | "plt.figure(8)\n", 673 | "plt.plot(dists_upstr[0], z2[profile_IDs[0]], 'b-', label='channel 1')\n", 674 | "plt.plot(dists_upstr[1], z2[profile_IDs[1]], 'k-', label='channel 2')\n", 675 | "plt.plot(dists_upstr[2], z2[profile_IDs[2]], 'r-', label='channel 3')\n", 676 | "plt.xlabel('distance upstream (m)')\n", 677 | "plt.ylabel('elevation (m)')\n", 678 | "plt.legend(loc='upper left')\n", 679 | "title_text = '$K_{sp}$='+str(K_sp) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy) + 'm'\n", 680 | "plt.title(title_text)\n", 681 | "\n", 682 | "# slope-area data in just the profiled channels\n", 683 | "plt.figure(9)\n", 684 | "plt.loglog(mg2.at_node['drainage_area'][profile_IDs[0]],\n", 685 | " mg2.at_node['topographic__steepest_slope'][profile_IDs[0]], 'b.',\n", 686 | " label='channel 1')\n", 687 | "plt.loglog(mg2.at_node['drainage_area'][profile_IDs[1]],\n", 688 | " mg2.at_node['topographic__steepest_slope'][profile_IDs[1]], 'k.',\n", 689 | " label='channel 2')\n", 690 | "plt.loglog(mg2.at_node['drainage_area'][profile_IDs[2]],\n", 691 | " mg2.at_node['topographic__steepest_slope'][profile_IDs[2]], 'r.',\n", 692 | " label='channel 3')\n", 693 | "plt.legend(loc='lower left')\n", 694 | "plt.xlabel('drainage area (m^2)')\n", 695 | "plt.ylabel('channel slope [m/m]')\n", 696 | "title_text = '$K_{sp}$='+str(K_sp2) + '; $time$='+str(total_time) + 'yr; $dx$='+str(dxy2) + 'm'\n", 697 | "plt.title(title_text)" 698 | ] 699 | }, 700 | { 701 | "cell_type": "code", 702 | "execution_count": null, 703 | "metadata": {}, 704 | "outputs": [], 705 | "source": [ 706 | "# Code Block 20\n", 707 | "# Chi Plots\n", 708 | "\n", 709 | "# Relocate profile IDs and calculate distance upstream, just in case\n", 710 | "# Code Blocks are run out-of-order\n", 711 | "profile_IDs = prf.channel_nodes(mg2, mg2.at_node['topographic__steepest_slope'],\n", 712 | " mg2.at_node['drainage_area'],\n", 713 | " mg2.at_node['flow__receiver_node'],\n", 714 | " number_of_channels=3)\n", 715 | "\n", 716 | "dists_upstr = prf.get_distances_upstream(\n", 717 | " mg2, len(mg2.at_node['topographic__steepest_slope']),\n", 718 | " profile_IDs, mg2.at_node['flow__link_to_receiver_node'])\n", 719 | "\n", 720 | "# calculate the chi index\n", 721 | "cf2.calculate_chi()\n", 722 | "\n", 723 | "# chi-elevation plots in the profiled channels\n", 724 | "plt.figure(10)\n", 725 | "plt.plot(mg2.at_node['channel__chi_index'][profile_IDs[0]], \n", 726 | " mg2.at_node['topographic__elevation'][profile_IDs[0]],'b-',\n", 727 | " label='channel 1')\n", 728 | "plt.plot(mg2.at_node['channel__chi_index'][profile_IDs[1]], \n", 729 | " mg2.at_node['topographic__elevation'][profile_IDs[1]],'k-',\n", 730 | " label='channel 2')\n", 731 | "plt.plot(mg2.at_node['channel__chi_index'][profile_IDs[2]], \n", 732 | " mg2.at_node['topographic__elevation'][profile_IDs[2]],'r-',\n", 733 | " label='channel 3')\n", 734 | "plt.xlabel('chi index (m)')\n", 735 | "plt.ylabel('elevation (m)')\n", 736 | "plt.legend(loc = 'lower right')\n", 737 | "title_text = '$K_{sp}$='+str(K_sp2) + '; $time$='+str(total_time) + \\\n", 738 | " 'yr; $dx$='+str(dxy2) + 'm' + '; concavity='+str(theta2)\n", 739 | "plt.title(title_text)\n", 740 | "\n", 741 | "# chi map\n", 742 | "plt.figure(11)\n", 743 | "imshow_grid(mg2, 'channel__chi_index', grid_units=('m', 'm'),\n", 744 | " var_name='Chi index (m)', cmap='jet')\n", 745 | "title_text = '$K_{sp}$='+str(K_sp2) + '; $time$='+str(total_time) + \\\n", 746 | " 'yr; $dx$='+str(dxy2) + 'm' + '; concavity='+str(theta2)\n", 747 | "plt.title(title_text)" 748 | ] 749 | }, 750 | { 751 | "cell_type": "code", 752 | "execution_count": null, 753 | "metadata": {}, 754 | "outputs": [], 755 | "source": [ 756 | "# Code Block 21\n", 757 | "# Plot channel steepness along profiles and across the landscape\n", 758 | "\n", 759 | "# Relocate profile IDs and calculate distance upstream, just in case\n", 760 | "# Code Blocks are run out-of-order\n", 761 | "profile_IDs = prf.channel_nodes(mg2, mg2.at_node['topographic__steepest_slope'],\n", 762 | " mg2.at_node['drainage_area'],\n", 763 | " mg2.at_node['flow__receiver_node'],\n", 764 | " number_of_channels=3)\n", 765 | "\n", 766 | "dists_upstr = prf.get_distances_upstream(\n", 767 | " mg2, len(mg2.at_node['topographic__steepest_slope']),\n", 768 | " profile_IDs, mg2.at_node['flow__link_to_receiver_node'])\n", 769 | "\n", 770 | "# calculate channel steepness\n", 771 | "sf2.calculate_steepnesses()\n", 772 | "\n", 773 | "# plots of steepnes vs. distance upstream in the profiled channels\n", 774 | "plt.figure(12)\n", 775 | "plt.plot(dists_upstr[0], mg2.at_node['channel__steepness_index'][profile_IDs[0]], 'bx',\n", 776 | " label='channel 1')\n", 777 | "plt.plot(dists_upstr[1], mg2.at_node['channel__steepness_index'][profile_IDs[1]], 'kx',\n", 778 | " label='channel 2')\n", 779 | "plt.plot(dists_upstr[2], mg2.at_node['channel__steepness_index'][profile_IDs[2]], 'rx',\n", 780 | " label='channel 3')\n", 781 | "plt.xlabel('distance upstream (m)')\n", 782 | "plt.ylabel('steepness index')\n", 783 | "plt.legend(loc = 'upper left')\n", 784 | "title_text = '$K_{sp}$='+str(K_sp2) + '; $time$='+str(total_time) + \\\n", 785 | " 'yr; $dx$='+str(dxy2) + 'm' + '; concavity='+str(theta2)\n", 786 | "plt.title(title_text)\n", 787 | "\n", 788 | "# channel steepness map\n", 789 | "plt.figure(13)\n", 790 | "imshow_grid(mg2, 'channel__steepness_index', grid_units=('m', 'm'),\n", 791 | " var_name='Steepness index ', cmap='jet')\n", 792 | "title_text = '$K_{sp}$='+str(K_sp2) + '; $time$='+str(total_time) + \\\n", 793 | " 'yr; $dx$='+str(dxy2) + 'm' + '; concavity='+str(theta2)\n", 794 | "plt.title(title_text)" 795 | ] 796 | } 797 | ], 798 | "metadata": { 799 | "anaconda-cloud": {}, 800 | "kernelspec": { 801 | "display_name": "Python 3", 802 | "language": "python", 803 | "name": "python3" 804 | }, 805 | "language_info": { 806 | "codemirror_mode": { 807 | "name": "ipython", 808 | "version": 3 809 | }, 810 | "file_extension": ".py", 811 | "mimetype": "text/x-python", 812 | "name": "python", 813 | "nbconvert_exporter": "python", 814 | "pygments_lexer": "ipython3", 815 | "version": "3.6.6" 816 | } 817 | }, 818 | "nbformat": 4, 819 | "nbformat_minor": 1 820 | } 821 | --------------------------------------------------------------------------------