├── .gitignore
├── .travis.yml
├── 3D_plot
└── Axes3D_for_LL.py
├── CONTRIBUTING.md
├── README.md
├── boundary_conds
├── set_BCs_from_xy.ipynb
├── set_BCs_on_raster_perimeter.ipynb
├── set_BCs_on_voronoi.ipynb
├── set_watershed_BCs_raster.ipynb
└── west_bijou_gully.asc
├── component_tutorial
├── component_tutorial.ipynb
├── coupled_params.txt
└── coupled_params_storms.txt
├── data_record
└── DataRecord_tutorial.ipynb
├── ecohydrology
├── cellular_automaton_vegetation_DEM
│ ├── DEM_10m.asc
│ ├── Ecohyd_functions_DEM.py
│ ├── Inputs_Vegetation_CA_DEM.txt
│ ├── ca_veg_dem_py_file.py
│ ├── cellular_automaton_vegetation_DEM.ipynb
│ └── presentation.png
└── cellular_automaton_vegetation_flat_surface
│ ├── Ecohyd_functions_flat.py
│ ├── Inputs_Vegetation_CA_flat.txt
│ ├── ca_veg_flat_surface_py_file.py
│ └── cellular_automaton_vegetation_flat_domain.ipynb
├── environment.yml
├── fault_scarp
└── landlab-fault-scarp.ipynb
├── fields
└── working_with_fields.ipynb
├── flexure
├── flexure_1d.ipynb
└── lots_of_loads.ipynb
├── flow__distance_utility
├── application_of_flow__distance_utility.ipynb
└── nocella_resampled.txt
├── flow_direction_and_accumulation
├── compare_FlowDirectors.ipynb
├── the_FlowAccumulator.ipynb
└── the_FlowDirectors.ipynb
├── gradient_and_divergence
└── gradient_and_divergence.ipynb
├── grid_object_demo
└── grid_object_demo.ipynb
├── groundwater
└── groundwater_flow.ipynb
├── landlab_header.png
├── landlab_logo_picture.jpg
├── lithology
└── lithology_and_litholayers.ipynb
├── making_components
├── component_design_tips.ipynb
└── making_components.ipynb
├── mappers
└── mappers.ipynb
├── normal_fault
└── normal_fault_component_tutorial.ipynb
├── overland_flow
├── Square_TestBasin.asc
├── hugo_site.asc
├── notebook_demo.ipynb
├── overland_flow_driver.ipynb
└── rainfall
│ └── rainfall.asc
├── plotting
├── animate-landlab-output.ipynb
├── first_phase.mp4
├── landlab-plotting.ipynb
└── second_phase.gif
├── python_intro
└── python_intro.ipynb
├── reading_dem_into_landlab
├── reading_dem_into_landlab.ipynb
├── synthetic_landscape.asc
└── west_bijou_gully.asc
├── requirements.txt
├── test_notebooks.py
├── transport-length_hillslope_diffuser
└── TLHDiff_tutorial.ipynb
└── tutorial_template.ipynb
/.gitignore:
--------------------------------------------------------------------------------
1 | .ipynb_checkpoints
2 | .DS_Store
3 |
4 | *.out
5 | *.pyc
6 |
7 | \.pytest_cache/README\.md
8 |
9 | \.pytest_cache/v/cache/lastfailed
10 |
11 | \.pytest_cache/v/cache/nodeids
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | env:
2 | matrix:
3 | - TRAVIS_PYTHON_VERSION="2.7"
4 | - TRAVIS_PYTHON_VERSION="3.6"
5 | global:
6 | - CONDA_PREFIX=$HOME/miniconda
7 | - MINICONDA_URL_BASE="https://repo.continuum.io/miniconda/Miniconda3-latest"
8 | - MPLCONFIGDIR=$HOME/.config/matplotlib
9 | os:
10 | - linux
11 | - osx
12 | sudo: false
13 | before_install:
14 | - |
15 | if [[ $TRAVIS_OS_NAME == "osx" ]]; then
16 | brew remove --force $(brew list)
17 | brew cleanup -s
18 | rm -rf $(brew --cache)
19 | fi
20 | - mkdir -p $MPLCONFIGDIR
21 | - touch $MPLCONFIGDIR/matplotlibrc
22 | install:
23 | - echo "Build on $TRAVIS_OS_NAME for Python $TRAVIS_PYTHON_VERSION"
24 | - |
25 | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
26 | OS="MacOSX-x86_64"
27 | else
28 | OS="Linux-x86_64"
29 | fi
30 | - curl $MINICONDA_URL_BASE-$OS.sh > $HOME/minconda.sh
31 | - bash $HOME/minconda.sh -b -p $CONDA_PREFIX
32 | - export PATH="$CONDA_PREFIX/bin:$PATH"
33 | - hash -r
34 | - conda config --set always_yes yes --set changeps1 no
35 | - conda create -n _testing python=$TRAVIS_PYTHON_VERSION
36 | - source activate _testing
37 | - |
38 | if [[ "$TRAVIS_BRANCH" == "release" ]]; then
39 | conda install landlab -c conda-forge
40 | else
41 | pushd ../..
42 | git clone --depth=50 https://github.com/landlab/landlab.git landlab/landlab
43 | pushd landlab/landlab
44 | git fetch origin master
45 | git checkout -qf master
46 | git submodule update --init --recursive
47 | conda env update --file environment-dev.yml
48 | conda activate landlab_dev
49 | python setup.py develop
50 | popd
51 | popd
52 | fi
53 | - conda install --file=requirements.txt
54 | - conda info -a && conda list
55 | script:
56 | - travis_wait 50 pytest -vvv # the cellular atomata test takes over 10 minutes, and the entire process takes about 30 minutes, so we'll give it 50 min
57 | virtualenv:
58 | system_site_packages: false
59 |
--------------------------------------------------------------------------------
/3D_plot/Axes3D_for_LL.py:
--------------------------------------------------------------------------------
1 | """
2 | Plot a surface + points (clasts) on it
3 |
4 | Use matplotlib Axes3D.plot_surface and Axes3D.scatter3D
5 |
6 | Axes3D.plot_surface(X, Y, Z, *args, **kwargs)
7 | X, Y and Z are 2D arrays of similar shape.
8 | In our case, the plot is clearer if we don't plot boundary nodes
9 | (but that could bean option). So the shape is that of the LL grid
10 | core nodes.
11 |
12 | X = dx * [[1, 2, 3, ..., nb_of_columns-1]
13 | [1, 2, 3, ..., nb_of_columns-1]
14 | ...
15 | [1, 2, 3, ..., nb_of_columns-1]]
16 |
17 | Y = dy * [[1, 1, 1, ..., 1]
18 | [2, 2, 2, ..., 2]
19 | ...
20 | [nb_of_rows-1, ..., nb_of_rows-1]]
21 |
22 | Z = [[z_core_node1, z_core_node2, ...]
23 | [..., ... ]
24 | ...
25 | [..., ]
26 |
27 | The rstride and cstride kwargs set the stride used to sample the input data
28 | to generate the graph. If 1k by 1k arrays are passed in, the default values
29 | for the strides will result in a 100x100 grid being plotted. Defaults to 10.
30 |
31 | The kwargs alpha sets the transparency factor (0 to 1).
32 |
33 | The LL nodes are at the crossing of the white lines that form the surface
34 | (the surface is made of LL patches, not cells).
35 |
36 |
37 | Axes3D.scatter(xs, ys, zs=0, zdir='z', s=20, c=None,
38 | depthshade=True, *args, **kwargs)
39 | xs, ys, zs are 1D arrays defining the position of the points.
40 | s = size (in points, so relation to the space scales of the plot itself is
41 | not straightforward...)
42 | c = color
43 | depthshade = Whether or not to shade the scatter markers to give the
44 | appearance of depth. Default is True.
45 | """
46 |
47 | from landlab import RasterModelGrid
48 | import numpy as np
49 |
50 | import matplotlib.pyplot as plt
51 | from mpl_toolkits.mplot3d import Axes3D
52 |
53 |
54 | ### Create Raster Model Grid
55 | rows = 20
56 | columns = 25
57 | dx = 1
58 | dy = 2
59 |
60 | mg = RasterModelGrid((rows, columns), spacing=(dy, dx))
61 |
62 | # Add elevation field
63 | z = mg.node_y*0.1
64 | _ = mg.add_field('node', 'topographic__elevation', z)
65 |
66 | # Shape of core nodes:
67 | # to be modified for more complex grids (use a mask?)
68 | number_of_core_node_rows = mg.number_of_node_rows - 2
69 | number_of_core_node_columns = mg.number_of_node_columns - 2
70 |
71 | #####################################################################
72 |
73 | ### Data for 3D plot of topographic surface
74 | xplot = mg.node_x[mg.core_nodes].reshape((
75 | number_of_core_node_rows, number_of_core_node_columns))
76 | yplot = mg.node_y[mg.core_nodes].reshape((
77 | number_of_core_node_rows, number_of_core_node_columns))
78 |
79 | # Elevation of core nodes, reshaped for 3D plot:
80 | zplot = mg.at_node['topographic__elevation'][mg.core_nodes].reshape(
81 | (number_of_core_node_rows, number_of_core_node_columns))
82 |
83 | #####################################################################
84 |
85 | ### 3D plot of elevation surface:
86 | # Figure and type of projection:
87 | fig = plt.figure(1)
88 | ax = plt.axes(projection='3d')
89 |
90 | # Plot surface:
91 | ax.plot_surface(xplot, yplot, zplot, cmap='binary', rstride=1, cstride=1,
92 | alpha=0.5)
93 |
94 | # Set initial view of the graph (elevation and azimuth):
95 | ax.view_init(elev=None, azim=-130)
96 |
97 | ax.set_xlabel('X axis')
98 | ax.set_ylabel('Y axis')
99 | ax.set_zlabel('Z axis')
100 |
101 | #####################################################################
102 |
103 | ### Data for 3D plot of topographic surface
104 | # The Clast Set class (from Clast Tracker) provides
105 | # clast node ID, x and y coordinates, clast elevation, etc.
106 | # but for this example, we define them here:
107 |
108 | clast__node = np.array([382, 386, 386, 390, 392, 392, 392, 392])
109 | clast__number = clast__node.size
110 |
111 | clast__x = mg.node_x[clast__node]
112 | clast__y= mg.node_y[clast__node]
113 |
114 | clast__elevation = np.array([3, 3, 3, 3, 3, 3, 3, 3])
115 | clast__size = np.array([0.5, 0.5, 0.5, 1, 1, 1, 1, 1])
116 |
117 | # For display purpose, clasts sizes are increased:
118 | # Marker size is in "points"...
119 | sizes = clast__size * 100
120 |
121 | # Count the number of clast on each node (WILL PUT THIS IN THE CLAST TRACKER)
122 | clast__number_at_node = np.zeros(mg.number_of_nodes)
123 | for i in range(0, mg.number_of_nodes):
124 | clast__number_at_node[i] = list(clast__node).count(mg.nodes.reshape(
125 | clast__number_at_node.shape)[i])
126 |
127 | # Assign colors to clast markers as a function of clast density on the node:
128 | clast__color = np.zeros(clast__number)
129 | for j in range(0, clast__number):
130 | clast__color[j] = clast__number_at_node[clast__node[j]]
131 |
132 | #####################################################################
133 |
134 | ### 3D plot of points (scatter):
135 |
136 | plot = ax.scatter(clast__x, clast__y, clast__elevation, marker='H',
137 | s=sizes, c=clast__color, label=clast__color, cmap='cool')
138 | cbar = plt.colorbar(plot, ticks=[1, 2, 3, 4], shrink=0.7)
139 | cbar.set_label('# of clasts')
140 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to landlab tutorials
2 |
3 | Thank you for contributing to the landlab tutorials! We appreciate
4 | your help as this is largely as volunteer effort! :heart: :heart: :heart:
5 |
6 | # How to contribute
7 |
8 | ## Reporting Bugs
9 |
10 | Before creating a bug report, please do at least a cursory check that the
11 | bug has not already been reported. If it has, add a comment to the existing
12 | issue instead of opening a new one.
13 |
14 | ### Submitting a Bug Report
15 |
16 | Bugs are tracked as
17 | [GitHub issues](https://guides.github.com/features/issues/). After you've
18 | determined you've found a new bug, please open a
19 | [new issue](https://github.com/landlab/tutorials/issues).
20 |
21 | Explain the problem and include additional details to help maintainers
22 | reproduce the problem. Here are some items that will make it easier
23 | to track down the source of the problem.
24 |
25 | * **Use a clear and descriptive title** for the issue that identifies the
26 | problem.
27 | * **Describe the exact steps that reproduce the problem**.
28 | * **If possible, provide an example that demonstrates the step** as,
29 | for example, a bash script along with input files.
30 | * **Describe the behavior you are seeing after these steps**.
31 | * **Describe the behavior you expect to see after these steps**.
32 |
33 | Additionally, the answers to the following questions about your run
34 | environment will be helpful.
35 |
36 | * **Which version of landlab are you using?** This could be a specific
37 | git sha or a release number.
38 | * **What is he name and version of you OS?**
39 | * **What compiler are you using?**
40 | * **How did you build landlab (if using the development version)?**
41 |
42 |
43 | ## Submitting Changes
44 |
45 | :tada: Whoa! This is great! We love it when folks contibute code! :tada:
46 |
47 | Changes to landlab tutorials should be submitted as
48 | [pull requests](http://help.github.com/pull-requests/)).
49 |
50 | * Create a GitHub issue that describes what you propose to do.
51 | * Create a topic branch that contains your changes.
52 | * Open a new [GitHub pull request](https://github.com/landlab/tutorials/pull/new/master).
53 | * Ensure the PR description clearly describes the problem and solution.
54 | Include the relevant issue number.
55 |
56 | ## Styleguides
57 |
58 | Use the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/).
59 | You may want to use tools like
60 | [Prospector](http://prospector.landscape.io/en/master/) to help out
61 | with this.
62 |
63 | ### Git Commit Messages
64 |
65 | * Use the present tense ("Add feature" not "Added feature")
66 | * Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
67 | * Limit the first line to 72 characters or less
68 | * Reference issues and pull requests liberally
69 | * Consider starting the commit message with an applicable emoji:
70 | * :art: `:art:` when improving the format/structure of the code
71 | * :racehorse: `:racehorse:` when improving performance
72 | * :non-potable_water: `:non-potable_water:` when plugging memory leaks
73 | * :memo: `:memo:` when writing docs
74 | * :penguin: `:penguin:` when fixing something on Linux
75 | * :apple: `:apple:` when fixing something on macOS
76 | * :checkered_flag: `:checkered_flag:` when fixing something on Windows
77 | * :bug: `:bug:` when fixing a bug
78 | * :fire: `:fire:` when removing code or files
79 | * :green_heart: `:green_heart:` when fixing the CI build
80 | * :white_check_mark: `:white_check_mark:` when adding tests
81 | * :shirt: `:shirt:` when removing linter warnings
82 |
83 | ## Adding new tutorials
84 |
85 | If you would like to create a new tutorial that we have just a few
86 | conventions that we would like you to follow.
87 |
88 | * Create a new folder that will hold your tutorial notebook
89 | and data used by your tutorial.
90 | * Start with the blank tutorial template provided in this repository.
91 | * Notice that your first cell of code should import `print_function`
92 | from `__future__`. Your tutorial will need to be compatible with
93 | both Python 2.7 and 3.4+.
94 | * If you will be plotting anything, be sure to use include ipython
95 | magic command in the first cell to indicate how plots should
96 | be rendered.
97 | * Your tutorial must be able to run without error for the **most
98 | recent landlab release**.
99 | * If your tutorial runs with the most recent **release** of landlab,
100 | a pull request should be sent to the *release* branch.
101 | * If you tutorial does not work with the most recent release but does
102 | work with a development version of landlab that's yet to be release,
103 | submit a pull request to the *next* branch.
104 |
105 |
106 | Thanks! :heart: :heart: :heart:
107 |
108 | The landlab team
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # As of mid December 2019 the Landlab tutorials are no longer being maintained here. The content that is in this repository has been 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.
2 |
3 | [](https://travis-ci.org/landlab/tutorials)
4 | [](https://mybinder.org/v2/gh/landlab/tutorials/release)
5 |
6 | [](http://landlab.github.io)
7 |
8 | Most of these Landlab tutorials can either be read as text files or run
9 | as interactive IPython notebooks (recommended!).
10 |
11 | To run the IPython notebook tutorials locally, you can copy this
12 | [landlab/tutorials](https://github.com/landlab/tutorials) repo to your
13 | local working environment (use the ``download ZIP`` button or fork/clone,
14 | whichever is most familiar to you).
15 |
16 | Alternatively, you can also access each notebook online from
17 | [https://nbviewer.jupyter.org/github/landlab/tutorials](https://nbviewer.jupyter.org/github/landlab/tutorials)
18 | and download an individual notebook (navigate to the specific IPython
19 | notebook you want, open it, and click the download button that appears
20 | in the upper right).
21 |
22 | After downloading/cloning, navigate into your new directory (or to
23 | the directory containing your new download) from the command line
24 | in your terminal.
25 |
26 | Use the command ``$ jupyter notebook`` to launch Jupyter, the IPython
27 | notebook viewer (it will open locally in your browser). Then navigate
28 | to the ``.ipynb`` tutorial you want to run and click to open it.
29 |
30 | To run the code in the notebook, place your cursor in a code cell,
31 | hold down ``shift``, and press ``enter``. The order in which you
32 | run the cells matters. You can even experiment with typing your own code
33 | into the cell and running that.
34 |
35 | Here is a short IPython notebook tutorial along with a screencast
36 | (the tutorial uses an example with statistics, but you can
37 | substitute Landlab!): http://www.randalolson.com/2012/05/12/a-short-demo-on-how-to-use-ipython-notebook-as-a-research-notebook/
38 |
--------------------------------------------------------------------------------
/boundary_conds/set_BCs_from_xy.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "
a toolkit for modeling earth surface processes
"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Setting Boundary Conditions: interior rectangle\n",
15 | "\n",
16 | "\n",
17 | " For instructions on how to run an interactive iPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
18 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials\n",
19 | "\n",
20 | "\n",
21 | "This tutorial illustrates how to modify the boundary conditions of an interior rectangle in the grid if you know the x and y coordinates of the rectangle."
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 1,
27 | "metadata": {},
28 | "outputs": [],
29 | "source": [
30 | "from landlab import RasterModelGrid, CLOSED_BOUNDARY\n",
31 | "import numpy as np\n",
32 | "from landlab.plot.imshow import imshow_grid_at_node\n",
33 | "from matplotlib.pyplot import show\n",
34 | "%matplotlib inline"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 2,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "mg = RasterModelGrid((10, 10), 1.)"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "Known coordinates of rectangle:"
51 | ]
52 | },
53 | {
54 | "cell_type": "code",
55 | "execution_count": 3,
56 | "metadata": {},
57 | "outputs": [],
58 | "source": [
59 | "min_x = 2.5\n",
60 | "max_x = 5.\n",
61 | "min_y = 3.5\n",
62 | "max_y = 7.5"
63 | ]
64 | },
65 | {
66 | "cell_type": "markdown",
67 | "metadata": {},
68 | "source": [
69 | "Define the area inside x and y coordinates:"
70 | ]
71 | },
72 | {
73 | "cell_type": "code",
74 | "execution_count": 4,
75 | "metadata": {},
76 | "outputs": [],
77 | "source": [
78 | "x_condition = np.logical_and(mg.x_of_node < max_x, mg.x_of_node > min_x)\n",
79 | "y_condition = np.logical_and(mg.y_of_node < max_y, mg.y_of_node > min_y)\n",
80 | "my_nodes = np.logical_and(x_condition, y_condition)"
81 | ]
82 | },
83 | {
84 | "cell_type": "markdown",
85 | "metadata": {},
86 | "source": [
87 | "Define boundaries as CLOSED:"
88 | ]
89 | },
90 | {
91 | "cell_type": "code",
92 | "execution_count": 5,
93 | "metadata": {},
94 | "outputs": [],
95 | "source": [
96 | "mg.status_at_node[my_nodes] = CLOSED_BOUNDARY"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | "Make a new elevation field for display:"
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": 6,
109 | "metadata": {},
110 | "outputs": [],
111 | "source": [
112 | "z = mg.add_zeros('node', 'topographic__elevation')"
113 | ]
114 | },
115 | {
116 | "cell_type": "code",
117 | "execution_count": 7,
118 | "metadata": {},
119 | "outputs": [
120 | {
121 | "data": {
122 | "image/png": "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\n",
123 | "text/plain": [
124 | ""
125 | ]
126 | },
127 | "metadata": {
128 | "needs_background": "light"
129 | },
130 | "output_type": "display_data"
131 | }
132 | ],
133 | "source": [
134 | "imshow_grid_at_node(mg, z)"
135 | ]
136 | },
137 | {
138 | "cell_type": "markdown",
139 | "metadata": {},
140 | "source": [
141 | "### Click here for more Landlab tutorials"
142 | ]
143 | }
144 | ],
145 | "metadata": {
146 | "kernelspec": {
147 | "display_name": "Python 3",
148 | "language": "python",
149 | "name": "python3"
150 | },
151 | "language_info": {
152 | "codemirror_mode": {
153 | "name": "ipython",
154 | "version": 3
155 | },
156 | "file_extension": ".py",
157 | "mimetype": "text/x-python",
158 | "name": "python",
159 | "nbconvert_exporter": "python",
160 | "pygments_lexer": "ipython3",
161 | "version": "3.6.7"
162 | }
163 | },
164 | "nbformat": 4,
165 | "nbformat_minor": 1
166 | }
167 |
--------------------------------------------------------------------------------
/component_tutorial/coupled_params.txt:
--------------------------------------------------------------------------------
1 | nrows: 100
2 | ncols: 100
3 | dx: 0.02
4 | dt: 0.5
5 | total_time: 100.
6 | uplift_rate: 0.001
7 | stream_power:
8 | K_sp: 0.3
9 | m_sp: 0.5
10 | linear_diffuser:
11 | linear_diffusivity: 0.0001
12 |
--------------------------------------------------------------------------------
/component_tutorial/coupled_params_storms.txt:
--------------------------------------------------------------------------------
1 | #these are for the storm generator:
2 | mean_storm_duration: 0.1
3 | mean_storm_depth: 0.2
4 | mean_interstorm_duration: 0.4
5 |
--------------------------------------------------------------------------------
/data_record/DataRecord_tutorial.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 | "# DataRecord Tutorial"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "\n",
22 | " For instructions on how to run an interactive IPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
23 | "For the unexpanded version to download and run, click here: https://nbviewer.jupyter.org/github/landlab/tutorials/blob/release/fault_scarp/landlab-fault-scarp-unexpanded.ipynb \n",
24 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials\n",
25 | "\n"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "This tutorial illustrates how to record variables of a Landlab model using DataRecord.\n",
33 | "\n",
34 | "## What is DataRecord?\n",
35 | "DataRecord is a data structure that can hold data variables relating to a Landlab model or to items living on the [Landlab grid](https://nbviewer.jupyter.org/github/landlab/tutorials/blob/release/grid_object_demo/grid_object_demo.ipynb).\n",
36 | "\n",
37 | "DataRecord is built on [xarray](http://xarray.pydata.org/en/stable/index.html)'s Dataset structure: a multi-dimensional, in memory, array database. Dataset implements the mapping interface with keys given by variable names and values given by DataArray objects for each variable name. DataRecord inherits all the methods and attributes from xarray.Dataset.\n",
38 | "\n",
39 | "A DataRecord can have one or both (or none) of the following dimensions:\n",
40 | "- `time`: The simulated time in the model.\n",
41 | "- `item_id`: An identifier of a generic item in the model.\n",
42 | "\n",
43 | "Coordinates are one dimensional arrays used for label-based indexing. \n",
44 | "\n",
45 | "The examples below illustrate different use cases for DataRecord. \n",
46 | "\n",
47 | "We start by importing the necessary libraries:"
48 | ]
49 | },
50 | {
51 | "cell_type": "code",
52 | "execution_count": null,
53 | "metadata": {},
54 | "outputs": [],
55 | "source": [
56 | "import numpy as np\n",
57 | "from landlab import RasterModelGrid\n",
58 | "from landlab.data_record import DataRecord\n",
59 | "\n",
60 | "from landlab import imshow_grid\n",
61 | "import matplotlib.pyplot as plt\n",
62 | "from matplotlib.pyplot import plot, subplot, xlabel, ylabel, title, legend, figure\n",
63 | "%matplotlib inline"
64 | ]
65 | },
66 | {
67 | "cell_type": "markdown",
68 | "metadata": {},
69 | "source": [
70 | "## Case 1. DataRecord with 1 dimension: time\n",
71 | "Let's start with an example where we set DataRecord to have only `time` as a dimension.\n",
72 | "An example variable that varies over time and relates to the Landlab grid could be the mean elevation of the topographic surface. We will store this example variable in DataRecord.\n",
73 | "\n",
74 | "We create a Raster grid, create a field (at nodes) called `topographic__elevation` and populate it with random values."
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": null,
80 | "metadata": {},
81 | "outputs": [],
82 | "source": [
83 | "grid_1 = RasterModelGrid((10, 10), (1., 1.))\n",
84 | "z = np.random.rand(100)\n",
85 | "_ = grid_1.add_field('node', 'topographic__elevation', z)"
86 | ]
87 | },
88 | {
89 | "cell_type": "markdown",
90 | "metadata": {},
91 | "source": [
92 | "Print the current mean elevation."
93 | ]
94 | },
95 | {
96 | "cell_type": "code",
97 | "execution_count": null,
98 | "metadata": {},
99 | "outputs": [],
100 | "source": [
101 | "current_mean = np.mean(grid_1.at_node['topographic__elevation'])\n",
102 | "print(current_mean)"
103 | ]
104 | },
105 | {
106 | "cell_type": "markdown",
107 | "metadata": {},
108 | "source": [
109 | "Now we will create a DataRecord that will hold the data variable `mean_elevation` relating to `grid_1`. The first value, at time=0 is the current mean elevation on the grid."
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": null,
115 | "metadata": {},
116 | "outputs": [],
117 | "source": [
118 | "dr_1 = DataRecord(grid_1,\n",
119 | " time=[0.],\n",
120 | " items=None,\n",
121 | " data_vars={'mean_elevation': (['time'], ([current_mean]))},\n",
122 | " attrs={'mean_elevation': 'y'})"
123 | ]
124 | },
125 | {
126 | "cell_type": "markdown",
127 | "metadata": {},
128 | "source": [
129 | "The input arguments passed in this case are: the grid, time (as a 1-element list), a data variable dictionary and an attributes dictionary. Note that `items` is not filled, we will see its use in other cases below.\n",
130 | "\n",
131 | "Note the format of the `data_vars` dictionary: \n",
132 | "```python\n",
133 | " {'variable_name_1' : (['dimensions'], variable_data_1),\n",
134 | " 'variable_name_2' : (['dimensions'], variable_data_2),\n",
135 | " ...}\n",
136 | "```\n",
137 | "\n",
138 | "The attributes dictionary `attrs` can be used to store metadata about the variables: in this example, we use it to store the variable units.\n",
139 | "\n",
140 | "So far, our DataRecord `dr_1` holds one variable `mean_elevation` with one record at time=0.\n"
141 | ]
142 | },
143 | {
144 | "cell_type": "code",
145 | "execution_count": null,
146 | "metadata": {},
147 | "outputs": [],
148 | "source": [
149 | "dr_1"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {},
155 | "source": [
156 | "We can visualise this data structure as a [pandas dataframe](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html):"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": null,
162 | "metadata": {},
163 | "outputs": [],
164 | "source": [
165 | "dr_1.dataset.to_dataframe()"
166 | ]
167 | },
168 | {
169 | "cell_type": "markdown",
170 | "metadata": {},
171 | "source": [
172 | "Now we will run a simple model where the grid surface is uplifted several times and the mean elevation is recorded at every time step. We use the method `add_record` to put the new value in the DataRecord `dr_1`:"
173 | ]
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": null,
178 | "metadata": {},
179 | "outputs": [],
180 | "source": [
181 | "total_time = 100\n",
182 | "dt = 20\n",
183 | "\n",
184 | "uplift_rate = 0.01 # m/y\n",
185 | "\n",
186 | "for t in range(20, total_time, dt):\n",
187 | " grid_1.at_node['topographic__elevation'] += uplift_rate * dt\n",
188 | " dr_1.add_record(time=[t],\n",
189 | " new_record={\n",
190 | " 'mean_elevation':\n",
191 | " (['time'],\n",
192 | " ([np.mean(grid_1.at_node['topographic__elevation'])]))\n",
193 | " })"
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "Let's see what was recorded:"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": null,
206 | "metadata": {},
207 | "outputs": [],
208 | "source": [
209 | "dr_1.dataset['mean_elevation'].values"
210 | ]
211 | },
212 | {
213 | "cell_type": "markdown",
214 | "metadata": {},
215 | "source": [
216 | "The corresponding time coordinates are:"
217 | ]
218 | },
219 | {
220 | "cell_type": "code",
221 | "execution_count": null,
222 | "metadata": {},
223 | "outputs": [],
224 | "source": [
225 | "dr_1.dataset.time.values"
226 | ]
227 | },
228 | {
229 | "cell_type": "markdown",
230 | "metadata": {},
231 | "source": [
232 | "Notice the different syntax used here: \n",
233 | "- `time` is a **dimension** and can be called by `dr_1.time` (or `dr_1['time']`)\n",
234 | "- whereas `mean_elevation` is a **variable** and must be called by `dr_1['mean_elevation']`\n",
235 | "\n",
236 | "DataRecord also has the handy property `time_coordinates` that returns these values as a list:\n",
237 | "\n",
238 | "\n"
239 | ]
240 | },
241 | {
242 | "cell_type": "code",
243 | "execution_count": null,
244 | "metadata": {},
245 | "outputs": [],
246 | "source": [
247 | "dr_1.time_coordinates"
248 | ]
249 | },
250 | {
251 | "cell_type": "markdown",
252 | "metadata": {},
253 | "source": [
254 | "You can use the methods `get_data` and `set_data` to access and change the data:"
255 | ]
256 | },
257 | {
258 | "cell_type": "code",
259 | "execution_count": null,
260 | "metadata": {},
261 | "outputs": [],
262 | "source": [
263 | "dr_1.get_data(time=[20.], data_variable='mean_elevation')"
264 | ]
265 | },
266 | {
267 | "cell_type": "code",
268 | "execution_count": null,
269 | "metadata": {},
270 | "outputs": [],
271 | "source": [
272 | "dr_1.set_data(time=[80.], data_variable='mean_elevation', new_value=1.5)\n",
273 | "\n",
274 | "dr_1.dataset['mean_elevation']"
275 | ]
276 | },
277 | {
278 | "cell_type": "markdown",
279 | "metadata": {},
280 | "source": [
281 | "## Case 2. DataRecord with 1 dimension: item_id\n",
282 | "An important feature of DataRecord is that it allows to create **items** that live on grid elements, and variables describing them. For instance, we can create *boulders* and store information about their *size* and *lithology*.\n",
283 | "\n",
284 | "To create items, we need to instantiate a DataRecord and pass it a dictionary describing where each item lives on the Landlab grid. The format of this dictionary is: \n",
285 | "```python\n",
286 | " {'grid_element' : [grid_element],\n",
287 | " 'element_id' : [element_id]}\n",
288 | "```\n",
289 | " \n",
290 | "where:\n",
291 | "- `grid_element` is a str or number-of-items-long array containing strings of the grid element(s) on which the items live (e.g.: node, link). Valid locations depend on the grid type (`my_grid.groups` gives the valid locations for your grid). If `grid_element` is provided as a string, it is assumed that all items live on the same type of grid element.\n",
292 | "- `element_id` is an array of integers identifying the grid element IDs on which each item resides. For each item, `element_id` must be less than the number of this item's `grid_element` that exist on the grid. For example, if the grid has 10 links, no item can live at link 10 or link -3 because only links 0 to 9 exist in this example.\n"
293 | ]
294 | },
295 | {
296 | "cell_type": "code",
297 | "execution_count": null,
298 | "metadata": {},
299 | "outputs": [],
300 | "source": [
301 | "grid_2 = RasterModelGrid((5, 5), (2, 2))\n",
302 | "\n",
303 | "boulders = {\n",
304 | " 'grid_element': 'node',\n",
305 | " 'element_id': np.array([6, 11, 12, 17, 12])\n",
306 | "}\n",
307 | "\n",
308 | "initial_boulder_sizes = np.array([1, 1.5, 3, 1, 2])\n",
309 | "boulder_lithologies = np.array(\n",
310 | " ['sandstone', 'granite', 'sandstone', 'sandstone', 'limestone'])\n",
311 | "\n",
312 | "dr_2 = DataRecord(grid_2,\n",
313 | " time=None,\n",
314 | " items=boulders,\n",
315 | " data_vars={\n",
316 | " 'boulder_size': (['item_id'], initial_boulder_sizes),\n",
317 | " 'boulder_litho': (['item_id'], boulder_lithologies)\n",
318 | " },\n",
319 | " attrs={'boulder_size': 'm'})\n",
320 | "dr_2.dataset.to_dataframe()"
321 | ]
322 | },
323 | {
324 | "cell_type": "markdown",
325 | "metadata": {},
326 | "source": [
327 | "Each *item* (in this case, each boulder) is designated by an `item_id`, its position on the grid is described by a `grid_element` and an `element_id`.\n",
328 | "\n",
329 | "We can use the method `add_item` to add new boulders to the record:"
330 | ]
331 | },
332 | {
333 | "cell_type": "code",
334 | "execution_count": null,
335 | "metadata": {},
336 | "outputs": [],
337 | "source": [
338 | "dr_2.add_item(\n",
339 | " new_item={\n",
340 | " 'grid_element': np.array(['link', 'node']),\n",
341 | " 'element_id': np.array([24, 8])\n",
342 | " },\n",
343 | " new_item_spec={'boulder_size': (['item_id'], np.array([1.2, 2.]))})\n",
344 | "\n",
345 | "dr_2.dataset.to_dataframe()"
346 | ]
347 | },
348 | {
349 | "cell_type": "markdown",
350 | "metadata": {},
351 | "source": [
352 | "Notice that we did not specify the lithologies of the new boulders, their recorded values are thus set as `NaN`. We can use the `set_data` method to report the boulder lithologies: "
353 | ]
354 | },
355 | {
356 | "cell_type": "code",
357 | "execution_count": null,
358 | "metadata": {},
359 | "outputs": [],
360 | "source": [
361 | "dr_2.set_data(data_variable='boulder_litho',\n",
362 | " item_id=[5, 6],\n",
363 | " new_value=['sandstone', 'granite'])\n",
364 | "dr_2.dataset.to_dataframe()"
365 | ]
366 | },
367 | {
368 | "cell_type": "markdown",
369 | "metadata": {},
370 | "source": [
371 | "We can use the method `calc_aggregate_value` to apply a function to a variable aggregated at grid elements. For example, we can calculate the mean size of boulders on each node:"
372 | ]
373 | },
374 | {
375 | "cell_type": "code",
376 | "execution_count": null,
377 | "metadata": {},
378 | "outputs": [],
379 | "source": [
380 | "mean_size = dr_2.calc_aggregate_value(func=np.mean,\n",
381 | " data_variable='boulder_size')\n",
382 | "mean_size"
383 | ]
384 | },
385 | {
386 | "cell_type": "markdown",
387 | "metadata": {},
388 | "source": [
389 | "Notice that boulder #5 is on a link so it is not taken into account in this calculation."
390 | ]
391 | },
392 | {
393 | "cell_type": "code",
394 | "execution_count": null,
395 | "metadata": {},
396 | "outputs": [],
397 | "source": [
398 | "# replace nans with 0:\n",
399 | "mean_size[np.isnan(mean_size)] = 0\n",
400 | "\n",
401 | "# show unfiltered mean sizes on the grid:\n",
402 | "imshow_grid(grid_2, mean_size)"
403 | ]
404 | },
405 | {
406 | "cell_type": "markdown",
407 | "metadata": {},
408 | "source": [
409 | "Before doing this calculation we could filter by lithology and only use the 'sandstone' boulders in the calculation:"
410 | ]
411 | },
412 | {
413 | "cell_type": "code",
414 | "execution_count": null,
415 | "metadata": {},
416 | "outputs": [],
417 | "source": [
418 | "# define a filter array:\n",
419 | "filter_litho = (dr_2.dataset['boulder_litho'] == 'sandstone')\n",
420 | "\n",
421 | "# aggregate by node and apply function numpy.mean on boulder_size\n",
422 | "filtered_mean = dr_2.calc_aggregate_value(func=np.mean,\n",
423 | " data_variable='boulder_size',\n",
424 | " at='node',\n",
425 | " filter_array=filter_litho)\n",
426 | "\n",
427 | "filtered_mean"
428 | ]
429 | },
430 | {
431 | "cell_type": "markdown",
432 | "metadata": {},
433 | "source": [
434 | "## Case 3. DataRecord with 2 dimensions: item_id and time\n",
435 | "\n",
436 | "We may want to record variables that have both dimensions `time` *and* `item_id`.\n",
437 | "\n",
438 | "In the previous example, some variables that characterize the items (boulders) may not vary with time, such as `boulder_lithology`. Although it can be interesting to keep track of the change in size through time. We will redefine the DataRecord such that the variable `boulder_size` varies among the items/boulders (identified by `item_id`) and through `time`. The variable `boulder_litho` varies only among the items/boulders and this lithogy variable does not vary through time."
439 | ]
440 | },
441 | {
442 | "cell_type": "code",
443 | "execution_count": null,
444 | "metadata": {},
445 | "outputs": [],
446 | "source": [
447 | "grid_3 = RasterModelGrid((5, 5), (2, 2))\n",
448 | "\n",
449 | "initial_boulder_sizes_3 = np.array([[10], [4], [8], [3], [5]])\n",
450 | "# boulder_lithologies = np.array(['sandstone', 'granite', 'sandstone', 'sandstone', 'limestone']) #same as above, already run\n",
451 | "\n",
452 | "boulders_3 = {\n",
453 | " 'grid_element': 'node',\n",
454 | " 'element_id': np.array([[6], [11], [12], [17], [12]])\n",
455 | "}\n",
456 | "\n",
457 | "dr_3 = DataRecord(grid_3,\n",
458 | " time=[0.],\n",
459 | " items=boulders_3,\n",
460 | " data_vars={\n",
461 | " 'boulder_size': (['item_id',\n",
462 | " 'time'], initial_boulder_sizes_3),\n",
463 | " 'boulder_litho': (['item_id'], boulder_lithologies)\n",
464 | " },\n",
465 | " attrs={'boulder_size': 'm'})\n",
466 | "dr_3"
467 | ]
468 | },
469 | {
470 | "cell_type": "markdown",
471 | "metadata": {},
472 | "source": [
473 | "Note that the syntax to define the `initial_boulder_sizes_3` (as well as `element_id`) has changed: they are number-of-items-by-1 arrays because they vary along both `time` and `item_id` (compared to `boulder_lithologies` which is just number-of-items long as it only varies along `item_id`)."
474 | ]
475 | },
476 | {
477 | "cell_type": "code",
478 | "execution_count": null,
479 | "metadata": {},
480 | "outputs": [],
481 | "source": [
482 | "boulder_lithologies.shape, initial_boulder_sizes.shape, initial_boulder_sizes_3.shape"
483 | ]
484 | },
485 | {
486 | "cell_type": "markdown",
487 | "metadata": {},
488 | "source": [
489 | "Let's define a very simple erosion law for the boulders:\n",
490 | "\n",
491 | "$$\n",
492 | "\\begin{equation}\n",
493 | "\\frac{dD}{dt} = -k_{b} . D\n",
494 | "\\end{equation}\n",
495 | "$$\n",
496 | "\n",
497 | "where $D$ is the boulder diameter $[L]$ (this value represents the `boulder_size` variable), $t$ is time, and $k_{b}$ is the block erodibility $[L.T^{-1}]$.\n",
498 | "\n",
499 | "We will now model boulder erosion and use DataRecord to store their size through time."
500 | ]
501 | },
502 | {
503 | "cell_type": "code",
504 | "execution_count": null,
505 | "metadata": {},
506 | "outputs": [],
507 | "source": [
508 | "dt = 100\n",
509 | "total_time = 100000\n",
510 | "\n",
511 | "time_index = 1\n",
512 | "\n",
513 | "for t in range(dt, total_time, dt):\n",
514 | "\n",
515 | " # create a new time coordinate:\n",
516 | " dr_3.add_record(time=np.array([t]))\n",
517 | "\n",
518 | " # this propagates grid_element and element_id values forward in time (instead of the 'nan' default filling):\n",
519 | " dr_3.ffill_grid_element_and_id()\n",
520 | "\n",
521 | " for i in range(0, dr_3.number_of_items):\n",
522 | " # value of block erodibility:\n",
523 | " if dr_3.dataset['boulder_litho'].values[i] == 'limestone':\n",
524 | " k_b = 10**-5\n",
525 | " elif dr_3.dataset['boulder_litho'].values[i] == 'sandstone':\n",
526 | " k_b = 3 * 10**-6\n",
527 | " elif dr_3.dataset['boulder_litho'].values[i] == 'granite':\n",
528 | " k_b = 3 * 10**-7\n",
529 | " else:\n",
530 | " print('Unknown boulder lithology')\n",
531 | "\n",
532 | " dr_3.dataset['boulder_size'].values[i, time_index] = dr_3.dataset[\n",
533 | " 'boulder_size'].values[i, time_index - 1] - k_b * dr_3.dataset[\n",
534 | " 'boulder_size'].values[i, time_index - 1] * dt\n",
535 | "\n",
536 | " time_index += 1\n",
537 | "\n",
538 | "print('Done')"
539 | ]
540 | },
541 | {
542 | "cell_type": "code",
543 | "execution_count": null,
544 | "metadata": {},
545 | "outputs": [],
546 | "source": [
547 | "figure(figsize=(15, 8))\n",
548 | "\n",
549 | "time = range(0, total_time, dt)\n",
550 | "boulder_size = dr_3.dataset['boulder_size'].values\n",
551 | "\n",
552 | "subplot(121)\n",
553 | "plot(time, boulder_size[1], label='granite')\n",
554 | "plot(time, boulder_size[3], label='sandstone')\n",
555 | "plot(time, boulder_size[-1], label='limestone')\n",
556 | "xlabel('Time (yr)')\n",
557 | "ylabel('Boulder size (m)')\n",
558 | "legend(loc='lower left')\n",
559 | "title('Boulder erosion by lithology')\n",
560 | "\n",
561 | "# normalized plots\n",
562 | "subplot(122)\n",
563 | "plot(time, boulder_size[1] / boulder_size[1, 0], label='granite')\n",
564 | "plot(time, boulder_size[2] / boulder_size[2, 0], label='sandstone')\n",
565 | "plot(time, boulder_size[-1] / boulder_size[-1, 0], label='limestone')\n",
566 | "xlabel('Time (yr)')\n",
567 | "ylabel('Boulder size normalized to size at t=0 (m)')\n",
568 | "legend(loc='lower left')\n",
569 | "title('Normalized boulder erosion by lithology')\n",
570 | "plt.show()"
571 | ]
572 | },
573 | {
574 | "cell_type": "markdown",
575 | "metadata": {},
576 | "source": [
577 | "## Other properties provided by DataRecord"
578 | ]
579 | },
580 | {
581 | "cell_type": "code",
582 | "execution_count": null,
583 | "metadata": {},
584 | "outputs": [],
585 | "source": [
586 | "dr_3.variable_names"
587 | ]
588 | },
589 | {
590 | "cell_type": "code",
591 | "execution_count": null,
592 | "metadata": {},
593 | "outputs": [],
594 | "source": [
595 | "dr_3.number_of_items"
596 | ]
597 | },
598 | {
599 | "cell_type": "code",
600 | "execution_count": null,
601 | "metadata": {},
602 | "outputs": [],
603 | "source": [
604 | "dr_3.item_coordinates"
605 | ]
606 | },
607 | {
608 | "cell_type": "code",
609 | "execution_count": null,
610 | "metadata": {},
611 | "outputs": [],
612 | "source": [
613 | "dr_3.number_of_timesteps"
614 | ]
615 | },
616 | {
617 | "cell_type": "code",
618 | "execution_count": null,
619 | "metadata": {},
620 | "outputs": [],
621 | "source": [
622 | "dr_1.time_coordinates"
623 | ]
624 | },
625 | {
626 | "cell_type": "code",
627 | "execution_count": null,
628 | "metadata": {},
629 | "outputs": [],
630 | "source": [
631 | "dr_1.earliest_time"
632 | ]
633 | },
634 | {
635 | "cell_type": "code",
636 | "execution_count": null,
637 | "metadata": {},
638 | "outputs": [],
639 | "source": [
640 | "dr_1.latest_time"
641 | ]
642 | },
643 | {
644 | "cell_type": "code",
645 | "execution_count": null,
646 | "metadata": {},
647 | "outputs": [],
648 | "source": [
649 | "dr_1.prior_time"
650 | ]
651 | },
652 | {
653 | "cell_type": "markdown",
654 | "metadata": {},
655 | "source": [
656 | "# More on DataRecord\n",
657 | "\n",
658 | "DataRecord is the data structure on which the following Landlab components are based:\n",
659 | "- ClastTracker (coming soon)\n",
660 | "- SpeciesEvolver (coming soon)"
661 | ]
662 | },
663 | {
664 | "cell_type": "code",
665 | "execution_count": null,
666 | "metadata": {},
667 | "outputs": [],
668 | "source": []
669 | }
670 | ],
671 | "metadata": {
672 | "kernelspec": {
673 | "display_name": "Python 3",
674 | "language": "python",
675 | "name": "python3"
676 | },
677 | "language_info": {
678 | "codemirror_mode": {
679 | "name": "ipython",
680 | "version": 3
681 | },
682 | "file_extension": ".py",
683 | "mimetype": "text/x-python",
684 | "name": "python",
685 | "nbconvert_exporter": "python",
686 | "pygments_lexer": "ipython3",
687 | "version": "3.7.3"
688 | }
689 | },
690 | "nbformat": 4,
691 | "nbformat_minor": 2
692 | }
693 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_DEM/DEM_10m.asc:
--------------------------------------------------------------------------------
1 | ncols 67
2 | nrows 53
3 | xllcorner 317284
4 | yllcorner 3808476
5 | cellsize 10
6 | NODATA_value -9999
7 | 1668 1669 1671 1674 1675 1676 1679 1681 1682 1685 1687 1691 1694 1698 1700 1702 1704 1706 1707 1707 1707 1708 1707 1708 1708 1707 1707 1707 1706 1706 1706 1706 1705 1703 1702 1700 1699 1699 1699 1699 1700 1701 1700 1698 1696 1693 1688 1685 1683 1681 1679 1681 1682 1683 1683 1681 1680 1678 1677 1678 1678 1678 1679 1679 1679 1678 1679
8 | 1670 1671 1674 1675 1678 1680 1680 1681 1683 1686 1690 1693 1696 1699 1701 1704 1705 1706 1707 1707 1707 1707 1708 1707 1708 1707 1708 1707 1707 1708 1706 1706 1705 1705 1704 1703 1701 1703 1701 1702 1703 1703 1701 1699 1696 1693 1689 1686 1685 1684 1684 1684 1684 1685 1684 1683 1681 1680 1680 1681 1681 1681 1682 1682 1680 1680 1677
9 | 1671 1673 1675 1678 1678 1681 1683 1685 1686 1688 1692 1695 1698 1700 1702 1704 1705 1706 1707 1707 1708 1707 1708 1708 1707 1708 1708 1708 1708 1708 1707 1706 1706 1706 1705 1704 1705 1704 1704 1704 1704 1705 1703 1701 1699 1695 1692 1690 1689 1689 1688 1687 1687 1687 1687 1685 1684 1684 1684 1684 1685 1685 1684 1683 1681 1679 1677
10 | 1673 1674 1677 1678 1681 1684 1686 1688 1689 1691 1694 1696 1699 1701 1703 1705 1705 1706 1707 1707 1707 1708 1708 1708 1708 1708 1708 1709 1708 1707 1708 1708 1707 1707 1707 1706 1706 1705 1704 1705 1705 1705 1703 1702 1701 1697 1695 1694 1691 1692 1691 1691 1691 1690 1689 1687 1687 1686 1686 1686 1686 1686 1685 1683 1680 1678 1675
11 | 1675 1677 1678 1681 1685 1687 1688 1691 1693 1694 1695 1698 1700 1702 1704 1705 1706 1706 1707 1707 1707 1708 1707 1708 1708 1708 1708 1708 1708 1708 1707 1708 1707 1708 1706 1706 1706 1707 1707 1707 1705 1706 1705 1704 1702 1699 1699 1697 1696 1695 1695 1695 1694 1693 1692 1692 1690 1689 1688 1688 1687 1686 1684 1681 1678 1676 1673
12 | 1676 1677 1680 1684 1686 1688 1691 1693 1694 1696 1698 1699 1701 1702 1704 1705 1706 1706 1707 1707 1707 1708 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 1707 1705 1706 1706 1705 1706 1703 1702 1700 1700 1700 1698 1698 1696 1695 1694 1693 1691 1690 1688 1687 1686 1684 1682 1679 1676 1673 1671
13 | 1676 1680 1683 1686 1688 1690 1693 1695 1696 1698 1699 1701 1702 1703 1705 1706 1705 1706 1706 1706 1707 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1704 1707 1706 1705 1706 1706 1706 1706 1706 1705 1704 1704 1705 1702 1703 1702 1700 1698 1697 1695 1693 1691 1689 1688 1686 1685 1682 1680 1677 1673 1671 1668
14 | 1678 1681 1685 1687 1689 1693 1694 1696 1699 1699 1701 1702 1703 1704 1705 1706 1706 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 1704 1704 1704 1704 1704 1703 1701 1700 1697 1694 1692 1690 1688 1686 1684 1682 1679 1677 1674 1671 1668 1665
15 | 1680 1682 1685 1689 1691 1694 1697 1699 1699 1700 1702 1704 1704 1705 1705 1705 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 1704 1705 1704 1704 1703 1702 1700 1696 1693 1690 1688 1685 1683 1681 1679 1676 1674 1671 1669 1666 1663
16 | 1681 1684 1687 1690 1693 1695 1698 1699 1701 1702 1703 1704 1704 1705 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1703 1704 1705 1705 1703 1705 1704 1704 1704 1705 1703 1702 1699 1696 1693 1689 1686 1683 1680 1678 1676 1673 1671 1668 1666 1664 1663
17 | 1682 1685 1688 1691 1694 1697 1699 1700 1702 1703 1704 1705 1704 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 1702 1700 1699 1695 1692 1688 1685 1681 1678 1675 1673 1671 1668 1666 1665 1664 1665
18 | 1683 1686 1689 1692 1695 1698 1699 1701 1704 1704 1705 1705 1704 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 1701 1698 1695 1691 1688 1684 1680 1677 1674 1672 1670 1668 1668 1667 1668 1667
19 | 1683 1687 1690 1693 1696 1699 1701 1702 1703 1704 1705 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 1699 1696 1692 1688 1686 1683 1679 1677 1675 1674 1673 1672 1672 1672 1673
20 | 1685 1688 1691 1694 1697 1699 1701 1703 1704 1705 1705 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 1699 1697 1693 1690 1687 1686 1685 1681 1679 1679 1676 1677 1676 1675 1676
21 | 1686 1689 1692 1695 1697 1700 1702 1703 1705 1705 1704 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 1697 1695 1693 1690 1688 1686 1686 1683 1682 1682 1680 1681 1680 1680
22 | 1687 1691 1694 1695 1699 1700 1703 1704 1705 1704 1705 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 1696 1694 1693 1691 1689 1688 1686 1684 1684 1682 1684 1685 1683
23 | 1688 1692 1695 1697 1699 1701 1704 1704 1704 1705 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 1694 1693 1695 1693 1690 1688 1689 1687 1686 1688 1686 1688
24 | 1690 1693 1695 1698 1701 1702 1704 1704 1705 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 1694 1692 1691 1691 1690 1690 1692 1690 1689 1691
25 | 1691 1694 1696 1700 1701 1703 1704 1705 1705 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 1692 1691 1693 1692 1691 1690 1692 1691 1690 1690
26 | 1693 1695 1697 1701 1703 1704 1705 1705 1706 1705 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 1690 1690 1689
27 | 1693 1697 1699 1701 1703 1704 1705 1705 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1674 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 1688 1687
28 | 1694 1698 1700 1702 1703 1705 1705 1706 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 1685 1684
29 | 1695 1698 1701 1703 1704 1705 1706 1706 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 1682 1680
30 | 1696 1699 1701 1703 1705 1705 1705 1706 1707 1706 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 1679 1677
31 | 1697 1699 1701 1704 1705 1705 1706 1706 1707 1707 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676 1674
32 | 1698 1700 1702 1704 1705 1706 1706 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672 1671
33 | 1699 1700 1702 1704 1705 1706 1706 1707 1707 1708 1707 1707 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669 1668
34 | 1698 1701 1702 1703 1704 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665 1664
35 | 1698 1700 1702 1704 1704 1706 1706 1706 1707 1708 1707 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662 1662
36 | 1699 1700 1703 1704 1704 1706 1705 1706 1707 1707 1707 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1662 1663 1662 1662 1662 1661 1661 1661 1661
37 | 1698 1700 1702 1703 1704 1706 1706 1706 1707 1707 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1662 1663 1663 1662 1662 1662 1661 1660 1660
38 | 1698 1700 1701 1703 1704 1704 1706 1706 1707 1706 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661 1660
39 | 1698 1700 1701 1703 1704 1704 1706 1705 1705 1706 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 1662 1660
40 | 1697 1699 1701 1703 1703 1704 1704 1705 1705 1705 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 1664 1662 1662
41 | 1697 1699 1702 1702 1703 1704 1704 1704 1705 1705 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 1667 1665 1664
42 | 1696 1699 1701 1702 1704 1704 1704 1704 1705 1704 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1674 1674 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 1668 1667 1667
43 | 1697 1699 1701 1701 1702 1703 1703 1704 1704 1705 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 1673 1672 1670 1669
44 | 1697 1699 1700 1700 1701 1702 1702 1703 1703 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 1675 1676 1673 1672
45 | 1697 1699 1699 1700 1701 1702 1702 1702 1703 1703 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 1678 1677 1676 1674
46 | 1697 1699 1698 1699 1700 1700 1701 1702 1702 1702 1702 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 1682 1680 1678 1676
47 | 1697 1698 1697 1699 1700 1702 1702 1702 1702 1701 1701 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 1685 1683 1681 1679
48 | 1696 1697 1697 1699 1698 1700 1700 1702 1701 1701 1701 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 1688 1686 1684 1681
49 | 1695 1696 1696 1697 1699 1699 1699 1701 1701 1700 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 1688 1686 1684
50 | 1694 1694 1695 1696 1697 1699 1699 1700 1700 1700 1700 1700 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 1688 1687 1684
51 | 1692 1692 1693 1694 1695 1696 1698 1699 1700 1699 1700 1699 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 1691 1688 1686 1684
52 | 1690 1690 1690 1692 1693 1695 1696 1697 1699 1700 1700 1702 1701 1699 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 1693 1692 1689 1686 1685 1682
53 | 1689 1688 1687 1689 1690 1692 1694 1695 1697 1698 1699 1700 1697 1701 1701 1697 1695 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 1698 1695 1693 1690 1688 1685 1683 1680
54 | 1688 1686 1684 1686 1688 1690 1692 1693 1695 1697 1697 1699 1697 1701 1702 1699 1697 1699 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1703 1706 1705 1706 1701 1703 1705 1705 1708 1707 1702 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 1699 1695 1692 1689 1686 1683 1680 1678
55 | 1688 1685 1682 1683 1685 1687 1688 1690 1693 1695 1696 1697 1698 1698 1699 1698 1699 1696 1699 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1701 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 1700 1699 1695 1691 1689 1684 1681 1678 1676
56 | 1689 1686 1682 1680 1682 1684 1686 1688 1690 1692 1694 1695 1696 1698 1698 1698 1697 1696 1697 1699 1695 1698 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 1702 1704 1705 1706 1706 1704 1706 1706 1706 1706 1706 1706 1707 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 1706 1703 1699 1695 1692 1688 1684 1680 1677 1675
57 | 1690 1687 1683 1678 1679 1681 1682 1685 1687 1690 1692 1693 1694 1695 1696 1697 1693 1696 1697 1697 1697 1697 1698 1700 1699 1700 1700 1700 1701 1699 1700 1701 1701 1702 1703 1706 1706 1705 1706 1706 1705 1704 1704 1704 1706 1708 1709 1710 1711 1711 1709 1709 1707 1707 1708 1707 1708 1705 1702 1699 1696 1691 1688 1685 1681 1678 1676
58 | 1690 1688 1684 1680 1677 1677 1680 1682 1684 1687 1689 1690 1692 1690 1693 1694 1695 1694 1695 1696 1697 1698 1701 1699 1699 1698 1699 1700 1700 1701 1701 1701 1701 1702 1702 1702 1703 1704 1705 1703 1702 1701 1700 1701 1703 1705 1706 1708 1709 1710 1710 1710 1709 1708 1709 1708 1708 1705 1703 1700 1697 1693 1688 1686 1683 1681 1679
59 | 1689 1687 1684 1680 1675 1674 1676 1679 1682 1684 1686 1687 1687 1688 1689 1691 1693 1694 1694 1694 1696 1695 1697 1699 1698 1698 1699 1701 1700 1702 1700 1699 1699 1700 1701 1700 1701 1703 1703 1700 1699 1697 1696 1697 1699 1702 1704 1706 1708 1709 1710 1711 1711 1710 1710 1709 1707 1705 1703 1700 1697 1694 1690 1688 1686 1684 1683
60 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_DEM/Ecohyd_functions_DEM.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | # Authors: Sai Nudurupati & Erkan Istanbulluoglu, 21May15
3 | # Edited: 15Jul16 - to conform to Landlab version 1.
4 | import numpy as np
5 | import matplotlib as mpl
6 | import matplotlib.pyplot as plt
7 | from landlab.plot import imshow_grid
8 | from landlab.components import PrecipitationDistribution
9 | from landlab.components import Radiation
10 | from landlab.components import PotentialEvapotranspiration
11 | from landlab.components import SoilMoisture
12 | from landlab.components import Vegetation
13 | from landlab.components import VegCA
14 |
15 | GRASS = 0
16 | SHRUB = 1
17 | TREE = 2
18 | BARE = 3
19 | SHRUBSEEDLING = 4
20 | TREESEEDLING = 5
21 |
22 |
23 | # Function that converts text file to a dictionary
24 | def txt_data_dict(InputFile):
25 | f = open(InputFile)
26 | data1 = {}
27 | for line in f:
28 | if line.strip() != '' and line[0] != '#':
29 | m, n = line.split(':')
30 | line = f.next()
31 | e = line[:].strip()
32 | if e[0].isdigit():
33 | if e.find('.') != -1:
34 | data1[m.strip()] = float(line[:].strip())
35 | else:
36 | data1[m.strip()] = int(line[:].strip())
37 | else:
38 | data1[m.strip()] = line[:].strip()
39 | f.close()
40 | return data1.copy()
41 |
42 |
43 | # Function to compose spatially distribute PFT
44 | def compose_veg_grid(grid, percent_bare=0.4, percent_grass=0.2,
45 | percent_shrub=0.2, percent_tree=0.2):
46 | no_cells = grid.number_of_cells
47 | V = 3 * np.ones(grid.number_of_cells, dtype=int)
48 | shrub_point = int(percent_bare * no_cells)
49 | tree_point = int((percent_bare + percent_shrub) * no_cells)
50 | grass_point = int((1 - percent_grass) * no_cells)
51 | V[shrub_point:tree_point] = 1
52 | V[tree_point:grass_point] = 2
53 | V[grass_point:] = 0
54 | np.random.shuffle(V)
55 | return V
56 |
57 |
58 | def Initialize_(data, grid, grid1, elevation):
59 | # Plant types are defined as following:
60 | # GRASS = 0; SHRUB = 1; TREE = 2; BARE = 3;
61 | # SHRUBSEEDLING = 4; TREESEEDLING = 5
62 | # Initialize random plant type field
63 | grid['cell']['vegetation__plant_functional_type'] = compose_veg_grid(
64 | grid, percent_bare=data['percent_bare_initial'],
65 | percent_grass=data['percent_grass_initial'],
66 | percent_shrub=data['percent_shrub_initial'],
67 | percent_tree=data['percent_tree_initial'])
68 | # Assign plant type for representative ecohydrologic simulations
69 | grid1['cell']['vegetation__plant_functional_type'] = np.arange(0, 6)
70 | grid1['node']['topographic__elevation'] = (1700. *
71 | np.ones(grid1.number_of_nodes))
72 | grid['node']['topographic__elevation'] = elevation
73 | PD_D = PrecipitationDistribution(
74 | mean_storm_duration=data['mean_storm_dry'],
75 | mean_interstorm_duration=data['mean_interstorm_dry'],
76 | mean_storm_depth=data['mean_storm_depth_dry'])
77 | PD_W = PrecipitationDistribution(
78 | mean_storm_duration=data['mean_storm_wet'],
79 | mean_interstorm_duration=data['mean_interstorm_wet'],
80 | mean_storm_depth=data['mean_storm_depth_wet'])
81 | Rad = Radiation(grid)
82 | Rad_PET = Radiation(grid1)
83 | PET_Tree = PotentialEvapotranspiration(grid1, method=data['PET_method'],
84 | MeanTmaxF=data['MeanTmaxF_tree'],
85 | delta_d=data['DeltaD'])
86 | PET_Shrub = PotentialEvapotranspiration(grid1, method=data['PET_method'],
87 | MeanTmaxF=data['MeanTmaxF_shrub'],
88 | delta_d=data['DeltaD'])
89 | PET_Grass = PotentialEvapotranspiration(grid1, method=data['PET_method'],
90 | MeanTmaxF=data['MeanTmaxF_grass'],
91 | delta_d=data['DeltaD'])
92 | SM = SoilMoisture(grid, **data) # Soil Moisture object
93 | VEG = Vegetation(grid, **data) # Vegetation object
94 | vegca = VegCA(grid, **data) # Cellular automaton object
95 |
96 | # # Initializing inputs for Soil Moisture object
97 | grid['cell']['vegetation__live_leaf_area_index'] = (
98 | 1.6 * np.ones(grid.number_of_cells))
99 | grid['cell']['soil_moisture__initial_saturation_fraction'] = (
100 | 0.59 * np.ones(grid.number_of_cells))
101 | # Initializing Soil Moisture
102 | return PD_D, PD_W, Rad, Rad_PET, PET_Tree, PET_Shrub, PET_Grass, SM, \
103 | VEG, vegca
104 |
105 |
106 | def Empty_arrays(n, n_years, grid, grid1):
107 | P = np.empty(n) # Record precipitation
108 | Tb = np.empty(n) # Record inter storm duration
109 | Tr = np.empty(n) # Record storm duration
110 | Time = np.empty(n) # To record time elapsed from the start of simulation
111 | # CumWaterStress = np.empty(grid.number_of_cells) # Cum Water Stress
112 | VegType = np.empty([n_years+5, grid.number_of_cells], dtype=int)
113 | PET_ = np.zeros([365, grid1.number_of_cells])
114 | Rad_Factor = np.empty([365, grid.number_of_cells])
115 | EP30 = np.empty([365, grid1.number_of_cells])
116 | # 30 day average PET to determine season
117 | PET_threshold = 0 # Initializing PET_threshold to ETThresholddown
118 | return (P, Tb, Tr, Time, VegType,
119 | PET_, Rad_Factor, EP30, PET_threshold)
120 |
121 |
122 | def Create_PET_lookup(Rad, PET_Tree, PET_Shrub, PET_Grass, PET_,
123 | Rad_Factor, EP30, Rad_PET, grid):
124 | for i in range(0, 365):
125 | Rad_PET.update(float(i)/365.25)
126 | PET_Tree.update(float(i)/365.25)
127 | PET_Shrub.update(float(i)/365.25)
128 | PET_Grass.update(float(i)/365.25)
129 | PET_[i] = [PET_Grass._PET_value, PET_Shrub._PET_value,
130 | PET_Tree._PET_value, 0., PET_Shrub._PET_value,
131 | PET_Tree._PET_value]
132 | Rad.update(float(i)/365.25)
133 | Rad_Factor[i] = grid['cell']['radiation__ratio_to_flat_surface']
134 | if i < 30:
135 | if i == 0:
136 | EP30[0] = PET_[0]
137 | else:
138 | EP30[i] = np.mean(PET_[:i], axis=0)
139 | else:
140 | EP30[i] = np.mean(PET_[i-30:i], axis=0)
141 |
142 |
143 | def Save_(sim, Tb, Tr, P, VegType, yrs, Time_Consumed, Time):
144 | np.save(sim+'Tb', Tb)
145 | np.save(sim+'Tr', Tr)
146 | np.save(sim+'P', P)
147 | np.save(sim+'VegType', VegType)
148 | # np.save(sim+'CumWaterStress', CumWaterStress)
149 | np.save(sim+'Years', yrs)
150 | np.save(sim+'Time_Consumed_minutes', Time_Consumed)
151 | np.save(sim+'CurrentTime', Time)
152 |
153 |
154 | def Plot_(grid, VegType, yrs, yr_step=10):
155 | # # Plotting
156 | pic = 0
157 | years = range(0, yrs)
158 | cmap = mpl.colors.ListedColormap(
159 | ['green', 'red', 'black', 'white', 'red', 'black'])
160 | bounds = [-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5]
161 | norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
162 | print('Plotting cellular field of Plant Functional Type')
163 | print('Green - Grass; Red - Shrubs; Black - Trees; White - Bare')
164 | # # Plot images to make gif.
165 | for year in range(0, yrs, yr_step):
166 | filename = 'Year = ' + "%05d" % year
167 | pic += 1
168 | plt.figure(pic)
169 | imshow_grid(grid, VegType[year], values_at='cell', cmap=cmap,
170 | grid_units=('m', 'm'), norm=norm, limits=[0, 5],
171 | allow_colorbar=False)
172 | plt.title(filename)
173 | plt.savefig(filename)
174 |
175 | grass_cov = np.empty(yrs)
176 | shrub_cov = np.empty(yrs)
177 | tree_cov = np.empty(yrs)
178 | grid_size = float(VegType.shape[1])
179 | for x in range(0, yrs):
180 | grass_cov[x] = (VegType[x][VegType[x] == GRASS].size/grid_size) * 100
181 | shrub_cov[x] = ((VegType[x][VegType[x] == SHRUB].size/grid_size) *
182 | 100 + (VegType[x][VegType[x] == SHRUBSEEDLING].size /
183 | grid_size) * 100)
184 | tree_cov[x] = ((VegType[x][VegType[x] == TREE].size/grid_size) *
185 | 100 + (VegType[x][VegType[x] == TREESEEDLING].size /
186 | grid_size) * 100)
187 | pic += 1
188 | plt.figure(pic)
189 | plt.plot(years, grass_cov, '-g', label='Grass')
190 | plt.plot(years, shrub_cov, '-r', label='Shrub')
191 | plt.plot(years, tree_cov, '-k', label='Tree')
192 | plt.ylabel(' % Coverage ')
193 | plt.xlabel('Time in years')
194 | plt.legend(loc=0)
195 | plt.savefig('PercentageCover_PFTs')
196 | # plt.show()
197 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_DEM/Inputs_Vegetation_CA_DEM.txt:
--------------------------------------------------------------------------------
1 |
2 | ### All inputs for Vegetation Cellular Automaton Model built on The Landlab
3 | ### can be given here.
4 | ### 14Feb2015 - Sai Nudurupati & Erkan Istanbulluoglu
5 | ### 15Jul2016 - Updated to comply with Landlab Version 1 naming conventions.
6 |
7 | ### There are some rules to use this input file:
8 | ### 1) The variable's identifier should not be changed, for e.g. 'mean_storm_dry' is
9 | ### the model input parameter. The code only understands this variable this way.
10 | ### Anything following '#' can be changed (commented part).
11 | ### 2) A separator ':' is used to define the end of the variable name.
12 | ### 3) Input value/string should be entered in the following (immediate) line of the variable name.
13 | ### 4) Nothing other than the input values should be entered in this line (where value is entered).
14 | ### 5) A float value should always have a number in front of the decimal '.', e.g '0.1' instead of '.1'
15 | ### If not, the input will be read as a string value.
16 | ### 6) Any numeric input will be identified as a float if it contains '.' . If a decimal point is not present,
17 | ### the input will be read in as an int.
18 | ### 7) String inputs are also recognized.
19 |
20 | ### Vegetation Cellular Automaton Model Input File:
21 |
22 | n_short: # Number of storms for short simulation that plots hydrologic parameters
23 | 6600
24 | n_long_DEM: # Number of storms for long simulation that operates on single grid for sloped surface
25 | 1320
26 | n_long_flat: # Number of storms for long simulation that operates on two grids - flat surface
27 | 660000
28 |
29 | ## Initial Plant Functional Types (PFT) distribution
30 | percent_bare_initial: # Initial percentage of cells occupied by bare soil
31 | 0.7
32 | percent_grass_initial: # Initial percentage of cells occupied by grass
33 | 0.1
34 | percent_shrub_initial: # Initial percentage of cells occupied by shrubs
35 | 0.1
36 | percent_tree_initial: # Initial percentage of cells occupied by trees
37 | 0.1
38 |
39 | ## Precipitation:
40 |
41 | # Dry Season
42 | mean_storm_dry: # Mean storm duration (hours)
43 | 2.016
44 | mean_interstorm_dry: # Mean interstorm duration (hours)
45 | 159.36
46 | mean_storm_depth_dry: # Mean storm depth (mm)
47 | 3.07
48 | # Wet Season
49 | mean_storm_wet: # Mean storm duration (hours)
50 | 1.896
51 | mean_interstorm_wet: # Mean interstorm duration (hours)
52 | 84.24
53 | mean_storm_depth_wet: # Mean storm depth (mm)
54 | 4.79
55 | doy__start_of_monsoon: # Day of the year when the monsoon starts
56 | 182
57 | doy__end_of_monsoon: # Day of the year when the monsoon ends
58 | 273
59 |
60 | ## PotentialEvapotranspiration:
61 | # Cosine Method
62 | PET_method:
63 | Cosine
64 | LT: # Lag between peak TmaxF estimated by cosine method and solar forcing (days)
65 | 0
66 | DeltaD: # Calibrated difference between
67 | 7.
68 | ND: # Number of days in the year (days)
69 | 365.
70 | MeanTmaxF_grass: # Mean annual rate of TmaxF (mm/d)
71 | 5.15
72 | MeanTmaxF_shrub: # Mean annual rate of TmaxF (mm/d)
73 | 3.77
74 | MeanTmaxF_tree: # Mean annual rate of TmaxF (mm/d)
75 | 4.96
76 |
77 | # TmaxF - Estimated maximum evapotranspiration as a function of DOY using Penman Monteith method for historical weather
78 |
79 | ## Soil Moisture:
80 |
81 | runon: # Runon from higher elevations (mm)
82 | 0.
83 | f_bare: # Fraction to partition PET for bare soil (None)
84 | 0.7
85 |
86 | # Grass
87 |
88 | VEGTYPE_grass: # Integer value to infer Vegetation Type
89 | 0
90 | intercept_cap_grass: # Full canopy interception capacity (mm)
91 | 1.
92 | zr_grass: # Root depth (m)
93 | 0.3
94 | I_B_grass: # Infiltration capacity of bare soil (mm/h)
95 | 20.
96 | I_V_grass: # Infiltration capacity of vegetated soil (mm/h)
97 | 24.
98 | pc_grass: # Soil porosity (None)
99 | 0.43
100 | fc_grass: # Soil saturation degree at field capacity (None)
101 | 0.56
102 | sc_grass: # Soil saturation degree at stomatal closure (None)
103 | 0.33
104 | wp_grass: # Soil saturation degree at wilting point (None)
105 | 0.13
106 | hgw_grass: # Soil saturation degree at hygroscopic point (None)
107 | 0.1
108 | beta_grass: # Deep percolation constant = 2*b+4 where b is water retention parameter
109 | 13.8
110 |
111 | # Shrub
112 |
113 | VEGTYPE_shrub: # Integer value to infer Vegetation Type
114 | 1
115 | intercept_cap_shrub: # Full canopy interception capacity (mm)
116 | 1.5
117 | zr_shrub: # Root depth (m)
118 | 0.5
119 | I_B_shrub: # Infiltration capacity of bare soil (mm/h)
120 | 20.
121 | I_V_shrub: # Infiltration capacity of vegetated soil (mm/h)
122 | 40.
123 | pc_shrub: # Soil porosity (None)
124 | 0.43
125 | fc_shrub: # Soil saturation degree at field capacity (None)
126 | 0.56
127 | sc_shrub: # Soil saturation degree at stomatal closure (None)
128 | 0.24
129 | wp_shrub: # Soil saturation degree at wilting point (None)
130 | 0.13
131 | hgw_shrub: # Soil saturation degree at hygroscopic point (None)
132 | 0.1
133 | beta_shrub: # Deep percolation constant = 2*b+4 where b is water retention parameter
134 | 13.8
135 |
136 | # Tree
137 |
138 | VEGTYPE_tree: # Integer value to infer Vegetation Type
139 | 2
140 | intercept_cap_tree: # Full canopy interception capacity (mm)
141 | 2.
142 | zr_tree: # Root depth (m)
143 | 1.3
144 | I_B_tree: # Infiltration capacity of bare soil (mm/h)
145 | 20.
146 | I_V_tree: # Infiltration capacity of vegetated soil (mm/h)
147 | 40.
148 | pc_tree: # Soil porosity (None)
149 | 0.43
150 | fc_tree: # Soil saturation degree at field capacity (None)
151 | 0.56
152 | sc_tree: # Soil saturation degree at stomatal closure (None)
153 | 0.22
154 | wp_tree: # Soil saturation degree at wilting point (None)
155 | 0.15
156 | hgw_tree: # Soil saturation degree at hygroscopic point (None)
157 | 0.1
158 | beta_tree: # Deep percolation constant = 2*b+4 where b is water retention parameter
159 | 13.8
160 |
161 | # Bare Soil
162 |
163 | VEGTYPE_bare: # Integer value to infer Vegetation Type
164 | 3
165 | intercept_cap_bare: # Full canopy interception capacity (mm)
166 | 1.
167 | zr_bare: # Root depth (m)
168 | 0.15
169 | I_B_bare: # Infiltration capacity of bare soil (mm/h)
170 | 20.
171 | I_V_bare: # Infiltration capacity of vegetated soil (mm/h)
172 | 20.
173 | pc_bare: # Soil porosity (None)
174 | 0.43
175 | fc_bare: # Soil saturation degree at field capacity (None)
176 | 0.56
177 | sc_bare: # Soil saturation degree at stomatal closure (None)
178 | 0.33
179 | wp_bare: # Soil saturation degree at wilting point (None)
180 | 0.13
181 | hgw_bare: # Soil saturation degree at hygroscopic point (None)
182 | 0.1
183 | beta_bare: # Deep percolation constant
184 | 13.8
185 |
186 |
187 | ## Vegetation Dynamics:
188 |
189 | Blive_init:
190 | 102.
191 | Bdead_init:
192 | 450.
193 | PET_growth_threshold: # PET threshold for growing season (mm/d)
194 | 3.8
195 | PET_dormancy_threshold: # PET threshold for dormant season (mm/d)
196 | 6.8
197 | Tdmax: # Constant for dead biomass loss adjustment (mm/d)
198 | 10.
199 | w: # Conversion factor of CO2 to dry biomass (Kg DM/Kg CO2)
200 | 0.55
201 |
202 | # Grass
203 |
204 | WUE_grass: # Water use efficiency KgCO2Kg-1H2O
205 | 0.01
206 | cb_grass: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
207 | 0.0047
208 | cd_grass: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
209 | 0.009
210 | ksg_grass: # Senescence coefficient of green/live biomass (d-1)
211 | 0.012
212 | kdd_grass: # Decay coefficient of aboveground dead biomass (d-1)
213 | 0.013
214 | kws_grass: # Maximum drought induced foliage loss rate (d-1)
215 | 0.02
216 | LAI_max_grass: # Maximum leaf area index (m2/m2)
217 | 2.
218 | LAIR_max_grass: # Reference leaf area index (m2/m2)
219 | 2.88
220 |
221 | # Shrub
222 |
223 | WUE_shrub: # Water use efficiency KgCO2Kg-1H2O
224 | 0.0025
225 | cb_shrub: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
226 | 0.004
227 | cd_shrub: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
228 | 0.01
229 | ksg_shrub: # Senescence coefficient of green/live biomass (d-1)
230 | 0.002
231 | kdd_shrub: # Decay coefficient of aboveground dead biomass (d-1)
232 | 0.013
233 | kws_shrub: # Maximum drought induced foliage loss rate (d-1)
234 | 0.02
235 | LAI_max_shrub: # Maximum leaf area index (m2/m2)
236 | 2.
237 | LAIR_max_shrub: # Reference leaf area index (m2/m2)
238 | 2.
239 |
240 | # Tree
241 |
242 | WUE_tree: # Water use efficiency KgCO2Kg-1H2O
243 | 0.0045
244 | cb_tree: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
245 | 0.004
246 | cd_tree: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
247 | 0.01
248 | ksg_tree: # Senescence coefficient of green/live biomass (d-1)
249 | 0.002
250 | kdd_tree: # Decay coefficient of aboveground dead biomass (d-1)
251 | 0.013
252 | kws_tree: # Maximum drought induced foliage loss rate (d-1)
253 | 0.01
254 | LAI_max_tree: # Maximum leaf area index (m2/m2)
255 | 4.
256 | LAIR_max_tree: # Reference leaf area index (m2/m2)
257 | 4.
258 |
259 | # Bare
260 |
261 | WUE_bare: # Water use efficiency KgCO2Kg-1H2O
262 | 0.01
263 | cb_bare: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
264 | 0.0047
265 | cd_bare: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
266 | 0.009
267 | ksg_bare: # Senescence coefficient of green/live biomass (d-1)
268 | 0.012
269 | kdd_bare: # Decay coefficient of aboveground dead biomass (d-1)
270 | 0.013
271 | kws_bare: # Maximum drought induced foliage loss rate (d-1)
272 | 0.02
273 | LAI_max_bare: # Maximum leaf area index (m2/m2)
274 | 0.01
275 | LAIR_max_bare: # Reference leaf area index (m2/m2)
276 | 0.01
277 |
278 |
279 | ## Cellular Automaton Vegetation:
280 |
281 | # Grass
282 |
283 | Pemaxg: # Maximal establishment probability
284 | 0.35
285 | ING: # Parameter to define allelopathic effect on grass from cresotebush
286 | 2
287 | ThetaGrass: # Drought resistant threshold
288 | 0.5
289 | PmbGrass: # Background mortality probability
290 | 0.05
291 |
292 | # Shrub
293 |
294 | Pemaxsh: # Maximal establishment probability
295 | 0.001
296 | ThetaShrub: # Drought resistant threshold
297 | 0.6
298 | PmbShrub: # Background mortality probability
299 | 0.05
300 | tpmaxShrub: # Maximum age (yr)
301 | 600
302 |
303 | # Tree
304 |
305 | Pemaxtr: # Maximal establishment probability
306 | 0.25
307 | ThetaTree: # Drought resistant threshold
308 | 0.6
309 | PmbTree: # Background mortality probability
310 | 0.01
311 | tpmaxTree: # Maximum age (yr)
312 | 350
313 |
314 | # ShrubSeedling
315 |
316 | ThetaShrubSeedling: # Drought resistant threshold
317 | 0.54
318 | PmbShrubSeedling: # Background mortality probability
319 | 0.03
320 | tpmaxShrubSeedling: # Maximum age (yr)
321 | 18
322 |
323 | # TreeSeedling
324 |
325 | ThetaTreeSeedling: # Drought resistant threshold
326 | 0.45
327 | PmbTreeSeedling: # Background mortality probability
328 | 0.03
329 | tpmaxTreeSeedling: # Maximum age (yr)
330 | 18
331 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_DEM/ca_veg_dem_py_file.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Wed Jul 20 2016
4 |
5 | This tutorial is on:
6 | landlab/tutorials/ecohydrology/cellular_automaton_vegetation_DEM.ipynb
7 |
8 | Creating a (.py) version of the same.
9 |
10 | @author: Sai Nudurupati & Erkan Istanbulluoglu
11 | """
12 |
13 | import time
14 | import numpy as np
15 | from landlab.io import read_esri_ascii
16 | from landlab import RasterModelGrid as rmg
17 | from Ecohyd_functions_DEM import (txt_data_dict, Initialize_, Empty_arrays,
18 | Create_PET_lookup, Save_, Plot_)
19 |
20 | (grid, elevation) = read_esri_ascii('DEM_10m.asc') # Read the DEM
21 | grid1 = rmg((5, 4), spacing=(5., 5.)) # Representative grid
22 |
23 | InputFile = 'Inputs_Vegetation_CA.txt'
24 | data = txt_data_dict(InputFile) # Creates dictionary that holds the inputs
25 |
26 | PD_D, PD_W, Rad, Rad_PET, PET_Tree, PET_Shrub, PET_Grass, SM, VEG, vegca = (
27 | Initialize_(data, grid, grid1, elevation))
28 |
29 | n_years = 50 # Approx number of years for model to run
30 | # Calculate approximate number of storms per year
31 | fraction_wet = (data['doy__end_of_monsoon']-data['doy__start_of_monsoon'])/365.
32 | fraction_dry = 1 - fraction_wet
33 | no_of_storms_wet = (8760 * (fraction_wet)/(data['mean_interstorm_wet'] +
34 | data['mean_storm_wet']))
35 | no_of_storms_dry = (8760 * (fraction_dry)/(data['mean_interstorm_dry'] +
36 | data['mean_storm_dry']))
37 | n = int(n_years * (no_of_storms_wet + no_of_storms_dry))
38 |
39 | P, Tb, Tr, Time, VegType, PET_, Rad_Factor, EP30, PET_threshold = (
40 | Empty_arrays(n, n_years, grid, grid1))
41 |
42 | Create_PET_lookup(Rad, PET_Tree, PET_Shrub, PET_Grass, PET_, Rad_Factor,
43 | EP30, Rad_PET, grid)
44 |
45 | # # Represent current time in years
46 | current_time = 0 # Start from first day of Jan
47 |
48 | # Keep track of run time for simulation—optional
49 | Start_time = time.clock() # Recording time taken for simulation
50 |
51 | # declaring few variables that will be used in storm loop
52 | time_check = 0. # Buffer to store current_time at previous storm
53 | yrs = 0 # Keep track of number of years passed
54 | WS = 0. # Buffer for Water Stress
55 | Tg = 365 # Growing season in days
56 |
57 | # # Run storm Loop
58 | for i in range(0, n):
59 | if i % 5 == 0:
60 | print 'Elapsed time = ', i, ' years'
61 | # # Update objects
62 | # Calculate Day of Year (DOY)
63 | Julian = np.int(np.floor((current_time - np.floor(current_time)) * 365.))
64 | # Generate seasonal storms
65 | # for Dry season
66 | if Julian < data['doy__start_of_monsoon'] or Julian > data[
67 | 'doy__end_of_monsoon']:
68 | PD_D.update()
69 | P[i] = PD_D.get_storm_depth()
70 | Tr[i] = PD_D.get_precipitation_event_duration()
71 | Tb[i] = PD_D.get_interstorm_event_duration()
72 | # Wet Season—Jul to Sep—NA Monsoon
73 | else:
74 | PD_W.update()
75 | P[i] = PD_W.get_storm_depth()
76 | Tr[i] = PD_W.get_precipitation_event_duration()
77 | Tb[i] = PD_W.get_interstorm_event_duration()
78 |
79 | # Spatially distribute PET and its 30-day-mean (analogous to degree day)
80 | grid['cell']['surface__potential_evapotranspiration_rate'] = (
81 | (np.choose(grid['cell']['vegetation__plant_functional_type'],
82 | PET_[Julian])) * Rad_Factor[Julian])
83 | grid['cell']['surface__potential_evapotranspiration_30day_mean'] = (
84 | (np.choose(grid['cell']['vegetation__plant_functional_type'],
85 | EP30[Julian])) * Rad_Factor[Julian])
86 |
87 | # Assign spatial rainfall data
88 | grid['cell']['rainfall__daily_depth'] = (P[i] *
89 | np.ones(grid.number_of_cells))
90 |
91 | # Update soil moisture component
92 | current_time = SM.update(current_time, Tr=Tr[i], Tb=Tb[i])
93 |
94 | # Decide whether its growing season or not
95 | if Julian != 364:
96 | if EP30[Julian+1, 0] > EP30[Julian, 0]:
97 | PET_threshold = 1
98 | # 1 corresponds to ETThresholdup (begin growing season)
99 | else:
100 | PET_threshold = 0
101 | # 0 corresponds to ETThresholddown (end growing season)
102 |
103 | # Update vegetation component
104 | VEG.update(PETthreshold_switch=PET_threshold, Tb=Tb[i], Tr=Tr[i])
105 |
106 | # Update yearly cumulative water stress data
107 | WS += (grid['cell']['vegetation__water_stress'])*Tb[i]/24.
108 |
109 | # Record time (optional)
110 | Time[i] = current_time
111 |
112 | # Cellular Automata
113 | if (current_time - time_check) >= 1.:
114 | if yrs % 5 == 0:
115 | print 'Elapsed time = ', yrs, ' years'
116 | VegType[yrs] = grid['cell']['vegetation__plant_functional_type']
117 | grid['cell']['vegetation__cumulative_water_stress'] = WS/Tg
118 | vegca.update()
119 | SM.initialize()
120 | VEG.initialize()
121 | time_check = current_time
122 | WS = 0
123 | yrs += 1
124 | VegType[yrs] = grid['cell']['vegetation__plant_functional_type']
125 |
126 | Final_time = time.clock()
127 | Time_Consumed = (Final_time - Start_time)/60. # in minutes
128 | print 'Time_consumed = ', Time_Consumed, ' minutes'
129 |
130 | # # Saving
131 | sim = 'VegCA_DEM_26Jul16_'
132 | # Save_(sim, Tb, Tr, P, VegType, yrs, Time_Consumed, Time)
133 |
134 | Plot_(grid, VegType, yrs, yr_step=10)
135 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_DEM/presentation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/landlab/tutorials/b98a8ab47249579b90298622853421dac5294f76/ecohydrology/cellular_automaton_vegetation_DEM/presentation.png
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_flat_surface/Ecohyd_functions_flat.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 |
3 | # Authors: Sai Nudurupati & Erkan Istanbulluoglu, 21May15
4 | # Edited: 15Jul16 - to conform to Landlab version 1.
5 | import numpy as np
6 | import matplotlib as mpl
7 | import matplotlib.pyplot as plt
8 | from landlab.plot import imshow_grid
9 | from landlab.components import PrecipitationDistribution
10 | from landlab.components import Radiation
11 | from landlab.components import PotentialEvapotranspiration
12 | from landlab.components import SoilMoisture
13 | from landlab.components import Vegetation
14 | from landlab.components import VegCA
15 |
16 | GRASS = 0
17 | SHRUB = 1
18 | TREE = 2
19 | BARE = 3
20 | SHRUBSEEDLING = 4
21 | TREESEEDLING = 5
22 |
23 |
24 | # Function that converts text file to a dictionary
25 | def txt_data_dict(InputFile):
26 | f = open(InputFile)
27 | data1 = {}
28 | for line in f:
29 | if line.strip() != '' and line[0] != '#':
30 | m, n = line.split(':')
31 | line = f.next()
32 | e = line[:].strip()
33 | if e[0].isdigit():
34 | if e.find('.') != -1:
35 | data1[m.strip()] = float(line[:].strip())
36 | else:
37 | data1[m.strip()] = int(line[:].strip())
38 | else:
39 | data1[m.strip()] = line[:].strip()
40 | f.close()
41 | return data1.copy()
42 |
43 |
44 | # Function to compose spatially distribute PFT
45 | def compose_veg_grid(grid, percent_bare=0.4, percent_grass=0.2,
46 | percent_shrub=0.2, percent_tree=0.2):
47 | no_cells = grid.number_of_cells
48 | V = 3 * np.ones(grid.number_of_cells, dtype=int)
49 | shrub_point = int(percent_bare * no_cells)
50 | tree_point = int((percent_bare + percent_shrub) * no_cells)
51 | grass_point = int((1 - percent_grass) * no_cells)
52 | V[shrub_point:tree_point] = 1
53 | V[tree_point:grass_point] = 2
54 | V[grass_point:] = 0
55 | np.random.shuffle(V)
56 | return V
57 |
58 |
59 | def Initialize_(data, grid, grid1):
60 | # Plant types are defined as following:
61 | # GRASS = 0; SHRUB = 1; TREE = 2; BARE = 3;
62 | # SHRUBSEEDLING = 4; TREESEEDLING = 5
63 | # Initialize random plant type field
64 | grid1['cell']['vegetation__plant_functional_type'] = compose_veg_grid(
65 | grid1, percent_bare=data['percent_bare_initial'],
66 | percent_grass=data['percent_grass_initial'],
67 | percent_shrub=data['percent_shrub_initial'],
68 | percent_tree=data['percent_tree_initial'])
69 | # Assign plant type for representative ecohydrologic simulations
70 | grid['cell']['vegetation__plant_functional_type'] = np.arange(0, 6)
71 | grid1['node']['topographic__elevation'] = (1700. *
72 | np.ones(grid1.number_of_nodes))
73 | grid['node']['topographic__elevation'] = (1700. *
74 | np.ones(grid.number_of_nodes))
75 | PD_D = PrecipitationDistribution(
76 | mean_storm_duration=data['mean_storm_dry'],
77 | mean_interstorm_duration=data['mean_interstorm_dry'],
78 | mean_storm_depth=data['mean_storm_depth_dry'])
79 | PD_W = PrecipitationDistribution(
80 | mean_storm_duration=data['mean_storm_wet'],
81 | mean_interstorm_duration=data['mean_interstorm_wet'],
82 | mean_storm_depth=data['mean_storm_depth_wet'])
83 | Rad = Radiation(grid)
84 | PET_Tree = PotentialEvapotranspiration(grid, method=data['PET_method'],
85 | MeanTmaxF=data['MeanTmaxF_tree'],
86 | delta_d=data['DeltaD'])
87 | PET_Shrub = PotentialEvapotranspiration(grid, method=data['PET_method'],
88 | MeanTmaxF=data['MeanTmaxF_shrub'],
89 | delta_d=data['DeltaD'])
90 | PET_Grass = PotentialEvapotranspiration(grid, method=data['PET_method'],
91 | MeanTmaxF=data['MeanTmaxF_grass'],
92 | delta_d=data['DeltaD'])
93 | SM = SoilMoisture(grid, **data) # Soil Moisture object
94 | VEG = Vegetation(grid, **data) # Vegetation object
95 | vegca = VegCA(grid1, **data) # Cellular automaton object
96 |
97 | # # Initializing inputs for Soil Moisture object
98 | grid['cell']['vegetation__live_leaf_area_index'] = (
99 | 1.6 * np.ones(grid.number_of_cells))
100 | grid['cell']['soil_moisture__initial_saturation_fraction'] = (
101 | 0.59 * np.ones(grid.number_of_cells))
102 | # Initializing Soil Moisture
103 | return PD_D, PD_W, Rad, PET_Tree, PET_Shrub, PET_Grass, SM, \
104 | VEG, vegca
105 |
106 |
107 | def Empty_arrays(n, grid, grid1):
108 | P = np.empty(n) # Record precipitation
109 | Tb = np.empty(n) # Record inter storm duration
110 | Tr = np.empty(n) # Record storm duration
111 | Time = np.empty(n) # To record time elapsed from the start of simulation
112 | # CumWaterStress = np.empty([n/55, grid1.number_of_cells])
113 | # Cum Water Stress
114 | VegType = np.empty([int(n/55), grid1.number_of_cells], dtype=int)
115 | PET_ = np.zeros([365, grid.number_of_cells])
116 | Rad_Factor = np.empty([365, grid.number_of_cells])
117 | EP30 = np.empty([365, grid.number_of_cells])
118 | # 30 day average PET to determine season
119 | PET_threshold = 0 # Initializing PET_threshold to ETThresholddown
120 | return (P, Tb, Tr, Time, VegType,
121 | PET_, Rad_Factor, EP30, PET_threshold)
122 |
123 |
124 | def Create_PET_lookup(Rad, PET_Tree, PET_Shrub, PET_Grass, PET_,
125 | Rad_Factor, EP30, grid):
126 | for i in range(0, 365):
127 | PET_Tree.update(float(i)/365.25)
128 | PET_Shrub.update(float(i)/365.25)
129 | PET_Grass.update(float(i)/365.25)
130 | PET_[i] = [PET_Grass._PET_value, PET_Shrub._PET_value,
131 | PET_Tree._PET_value, 0., PET_Shrub._PET_value,
132 | PET_Tree._PET_value]
133 | Rad.update(float(i)/365.25)
134 | Rad_Factor[i] = grid['cell']['radiation__ratio_to_flat_surface']
135 | if i < 30:
136 | if i == 0:
137 | EP30[0] = PET_[0]
138 | else:
139 | EP30[i] = np.mean(PET_[:i], axis=0)
140 | else:
141 | EP30[i] = np.mean(PET_[i-30:i], axis=0)
142 |
143 |
144 | def Save_(sim, Tb, Tr, P, VegType, yrs, Time_Consumed, Time):
145 | np.save(sim+'Tb', Tb)
146 | np.save(sim+'Tr', Tr)
147 | np.save(sim+'P', P)
148 | np.save(sim+'VegType', VegType)
149 | # np.save(sim+'CumWaterStress', CumWaterStress)
150 | np.save(sim+'Years', yrs)
151 | np.save(sim+'Time_Consumed_minutes', Time_Consumed)
152 | np.save(sim+'CurrentTime', Time)
153 |
154 |
155 | def Plot_(grid, VegType, yrs, yr_step=10):
156 | # # Plotting
157 | pic = 0
158 | years = range(0, yrs)
159 | cmap = mpl.colors.ListedColormap(
160 | ['green', 'red', 'black', 'white', 'red', 'black'])
161 | bounds = [-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5]
162 | norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
163 | print('Plotting cellular field of Plant Functional Type')
164 | print('Green - Grass; Red - Shrubs; Black - Trees; White - Bare')
165 | # # Plot images to make gif.
166 | for year in range(0, yrs, yr_step):
167 | filename = 'Year = ' + "%05d" % year
168 | pic += 1
169 | plt.figure(pic)
170 | imshow_grid(grid, VegType[year], values_at='cell', cmap=cmap,
171 | grid_units=('m', 'm'), norm=norm, limits=[0, 5],
172 | allow_colorbar=False)
173 | plt.title(filename)
174 | plt.savefig(filename)
175 | grass_cov = np.empty(yrs)
176 | shrub_cov = np.empty(yrs)
177 | tree_cov = np.empty(yrs)
178 | grid_size = float(VegType.shape[1])
179 | for x in range(0, yrs):
180 | grass_cov[x] = (VegType[x][VegType[x] == GRASS].size/grid_size) * 100
181 | shrub_cov[x] = ((VegType[x][VegType[x] == SHRUB].size/grid_size) *
182 | 100 + (VegType[x][VegType[x] == SHRUBSEEDLING].size /
183 | grid_size) * 100)
184 | tree_cov[x] = ((VegType[x][VegType[x] == TREE].size/grid_size) *
185 | 100 + (VegType[x][VegType[x] == TREESEEDLING].size /
186 | grid_size) * 100)
187 | pic += 1
188 | plt.figure(pic)
189 | plt.plot(years, grass_cov, '-g', label='Grass')
190 | plt.plot(years, shrub_cov, '-r', label='Shrub')
191 | plt.plot(years, tree_cov, '-k', label='Tree')
192 | plt.ylabel(' % Coverage ')
193 | plt.xlabel('Time in years')
194 | plt.legend(loc=0)
195 | plt.savefig('PercentageCover_PFTs')
196 | # plt.show()
197 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_flat_surface/Inputs_Vegetation_CA_flat.txt:
--------------------------------------------------------------------------------
1 |
2 | ### All inputs for Vegetation Cellular Automaton Model built on The Landlab
3 | ### can be given here.
4 | ### 14Feb2015 - Sai Nudurupati & Erkan Istanbulluoglu
5 | ### 15Jul2016 - Updated to comply with Landlab Version 1 naming conventions.
6 |
7 | ### There are some rules to use this input file:
8 | ### 1) The variable's identifier should not be changed, for e.g. 'mean_storm_dry' is
9 | ### the model input parameter. The code only understands this variable this way.
10 | ### Anything following '#' can be changed (commented part).
11 | ### 2) A separator ':' is used to define the end of the variable name.
12 | ### 3) Input value/string should be entered in the following (immediate) line of the variable name.
13 | ### 4) Nothing other than the input values should be entered in this line (where value is entered).
14 | ### 5) A float value should always have a number in front of the decimal '.', e.g '0.1' instead of '.1'
15 | ### If not, the input will be read as a string value.
16 | ### 6) Any numeric input will be identified as a float if it contains '.' . If a decimal point is not present,
17 | ### the input will be read in as an int.
18 | ### 7) String inputs are also recognized.
19 |
20 | ### Vegetation Cellular Automaton Model Input File:
21 |
22 | n_short: # Number of storms for short simulation that plots hydrologic parameters
23 | 6600
24 | n_long_DEM: # Number of storms for long simulation that operates on single grid for sloped surface
25 | 1320
26 | n_long_flat: # Number of storms for long simulation that operates on two grids - flat surface
27 | 660000
28 |
29 | ## Initial Plant Functional Types (PFT) distribution
30 | percent_bare_initial: # Initial percentage of cells occupied by bare soil
31 | 0.7
32 | percent_grass_initial: # Initial percentage of cells occupied by grass
33 | 0.1
34 | percent_shrub_initial: # Initial percentage of cells occupied by shrubs
35 | 0.1
36 | percent_tree_initial: # Initial percentage of cells occupied by trees
37 | 0.1
38 |
39 | ## Precipitation:
40 |
41 | # Dry Season
42 | mean_storm_dry: # Mean storm duration (hours)
43 | 2.016
44 | mean_interstorm_dry: # Mean interstorm duration (hours)
45 | 159.36
46 | mean_storm_depth_dry: # Mean storm depth (mm)
47 | 3.07
48 | # Wet Season
49 | mean_storm_wet: # Mean storm duration (hours)
50 | 1.896
51 | mean_interstorm_wet: # Mean interstorm duration (hours)
52 | 84.24
53 | mean_storm_depth_wet: # Mean storm depth (mm)
54 | 4.79
55 | doy__start_of_monsoon: # Day of the year when the monsoon starts
56 | 182
57 | doy__end_of_monsoon: # Day of the year when the monsoon ends
58 | 273
59 |
60 | ## PotentialEvapotranspiration:
61 | # Cosine Method
62 | PET_method:
63 | Cosine
64 | LT: # Lag between peak TmaxF estimated by cosine method and solar forcing (days)
65 | 0
66 | DeltaD: # Calibrated difference between
67 | 7.
68 | ND: # Number of days in the year (days)
69 | 365.
70 | MeanTmaxF_grass: # Mean annual rate of TmaxF (mm/d)
71 | 5.15
72 | MeanTmaxF_shrub: # Mean annual rate of TmaxF (mm/d)
73 | 3.77
74 | MeanTmaxF_tree: # Mean annual rate of TmaxF (mm/d)
75 | 4.96
76 |
77 | # TmaxF - Estimated maximum evapotranspiration as a function of DOY using Penman Monteith method for historical weather
78 |
79 | ## Soil Moisture:
80 |
81 | runon: # Runon from higher elevations (mm)
82 | 0.
83 | f_bare: # Fraction to partition PET for bare soil (None)
84 | 0.7
85 |
86 | # Grass
87 |
88 | VEGTYPE_grass: # Integer value to infer Vegetation Type
89 | 0
90 | intercept_cap_grass: # Full canopy interception capacity (mm)
91 | 1.
92 | zr_grass: # Root depth (m)
93 | 0.3
94 | I_B_grass: # Infiltration capacity of bare soil (mm/h)
95 | 20.
96 | I_V_grass: # Infiltration capacity of vegetated soil (mm/h)
97 | 24.
98 | pc_grass: # Soil porosity (None)
99 | 0.43
100 | fc_grass: # Soil saturation degree at field capacity (None)
101 | 0.56
102 | sc_grass: # Soil saturation degree at stomatal closure (None)
103 | 0.33
104 | wp_grass: # Soil saturation degree at wilting point (None)
105 | 0.13
106 | hgw_grass: # Soil saturation degree at hygroscopic point (None)
107 | 0.1
108 | beta_grass: # Deep percolation constant = 2*b+4 where b is water retention parameter
109 | 13.8
110 |
111 | # Shrub
112 |
113 | VEGTYPE_shrub: # Integer value to infer Vegetation Type
114 | 1
115 | intercept_cap_shrub: # Full canopy interception capacity (mm)
116 | 1.5
117 | zr_shrub: # Root depth (m)
118 | 0.5
119 | I_B_shrub: # Infiltration capacity of bare soil (mm/h)
120 | 20.
121 | I_V_shrub: # Infiltration capacity of vegetated soil (mm/h)
122 | 40.
123 | pc_shrub: # Soil porosity (None)
124 | 0.43
125 | fc_shrub: # Soil saturation degree at field capacity (None)
126 | 0.56
127 | sc_shrub: # Soil saturation degree at stomatal closure (None)
128 | 0.24
129 | wp_shrub: # Soil saturation degree at wilting point (None)
130 | 0.13
131 | hgw_shrub: # Soil saturation degree at hygroscopic point (None)
132 | 0.1
133 | beta_shrub: # Deep percolation constant = 2*b+4 where b is water retention parameter
134 | 13.8
135 |
136 | # Tree
137 |
138 | VEGTYPE_tree: # Integer value to infer Vegetation Type
139 | 2
140 | intercept_cap_tree: # Full canopy interception capacity (mm)
141 | 2.
142 | zr_tree: # Root depth (m)
143 | 1.3
144 | I_B_tree: # Infiltration capacity of bare soil (mm/h)
145 | 20.
146 | I_V_tree: # Infiltration capacity of vegetated soil (mm/h)
147 | 40.
148 | pc_tree: # Soil porosity (None)
149 | 0.43
150 | fc_tree: # Soil saturation degree at field capacity (None)
151 | 0.56
152 | sc_tree: # Soil saturation degree at stomatal closure (None)
153 | 0.22
154 | wp_tree: # Soil saturation degree at wilting point (None)
155 | 0.15
156 | hgw_tree: # Soil saturation degree at hygroscopic point (None)
157 | 0.1
158 | beta_tree: # Deep percolation constant = 2*b+4 where b is water retention parameter
159 | 13.8
160 |
161 | # Bare Soil
162 |
163 | VEGTYPE_bare: # Integer value to infer Vegetation Type
164 | 3
165 | intercept_cap_bare: # Full canopy interception capacity (mm)
166 | 1.
167 | zr_bare: # Root depth (m)
168 | 0.15
169 | I_B_bare: # Infiltration capacity of bare soil (mm/h)
170 | 20.
171 | I_V_bare: # Infiltration capacity of vegetated soil (mm/h)
172 | 20.
173 | pc_bare: # Soil porosity (None)
174 | 0.43
175 | fc_bare: # Soil saturation degree at field capacity (None)
176 | 0.56
177 | sc_bare: # Soil saturation degree at stomatal closure (None)
178 | 0.33
179 | wp_bare: # Soil saturation degree at wilting point (None)
180 | 0.13
181 | hgw_bare: # Soil saturation degree at hygroscopic point (None)
182 | 0.1
183 | beta_bare: # Deep percolation constant
184 | 13.8
185 |
186 |
187 | ## Vegetation Dynamics:
188 |
189 | Blive_init:
190 | 102.
191 | Bdead_init:
192 | 450.
193 | PET_growth_threshold: # PET threshold for growing season (mm/d)
194 | 3.8
195 | PET_dormancy_threshold: # PET threshold for dormant season (mm/d)
196 | 6.8
197 | Tdmax: # Constant for dead biomass loss adjustment (mm/d)
198 | 10.
199 | w: # Conversion factor of CO2 to dry biomass (Kg DM/Kg CO2)
200 | 0.55
201 |
202 | # Grass
203 |
204 | WUE_grass: # Water use efficiency KgCO2Kg-1H2O
205 | 0.01
206 | cb_grass: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
207 | 0.0047
208 | cd_grass: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
209 | 0.009
210 | ksg_grass: # Senescence coefficient of green/live biomass (d-1)
211 | 0.012
212 | kdd_grass: # Decay coefficient of aboveground dead biomass (d-1)
213 | 0.013
214 | kws_grass: # Maximum drought induced foliage loss rate (d-1)
215 | 0.02
216 | LAI_max_grass: # Maximum leaf area index (m2/m2)
217 | 2.
218 | LAIR_max_grass: # Reference leaf area index (m2/m2)
219 | 2.88
220 |
221 | # Shrub
222 |
223 | WUE_shrub: # Water use efficiency KgCO2Kg-1H2O
224 | 0.0025
225 | cb_shrub: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
226 | 0.004
227 | cd_shrub: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
228 | 0.01
229 | ksg_shrub: # Senescence coefficient of green/live biomass (d-1)
230 | 0.002
231 | kdd_shrub: # Decay coefficient of aboveground dead biomass (d-1)
232 | 0.013
233 | kws_shrub: # Maximum drought induced foliage loss rate (d-1)
234 | 0.02
235 | LAI_max_shrub: # Maximum leaf area index (m2/m2)
236 | 2.
237 | LAIR_max_shrub: # Reference leaf area index (m2/m2)
238 | 2.
239 |
240 | # Tree
241 |
242 | WUE_tree: # Water use efficiency KgCO2Kg-1H2O
243 | 0.0045
244 | cb_tree: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
245 | 0.004
246 | cd_tree: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
247 | 0.01
248 | ksg_tree: # Senescence coefficient of green/live biomass (d-1)
249 | 0.002
250 | kdd_tree: # Decay coefficient of aboveground dead biomass (d-1)
251 | 0.013
252 | kws_tree: # Maximum drought induced foliage loss rate (d-1)
253 | 0.01
254 | LAI_max_tree: # Maximum leaf area index (m2/m2)
255 | 4.
256 | LAIR_max_tree: # Reference leaf area index (m2/m2)
257 | 4.
258 |
259 | # Bare
260 |
261 | WUE_bare: # Water use efficiency KgCO2Kg-1H2O
262 | 0.01
263 | cb_bare: # Specific leaf area for green/live biomass (m2 leaf g-1 DM)
264 | 0.0047
265 | cd_bare: # Specific leaf area for dead biomass (m2 leaf g-1 DM)
266 | 0.009
267 | ksg_bare: # Senescence coefficient of green/live biomass (d-1)
268 | 0.012
269 | kdd_bare: # Decay coefficient of aboveground dead biomass (d-1)
270 | 0.013
271 | kws_bare: # Maximum drought induced foliage loss rate (d-1)
272 | 0.02
273 | LAI_max_bare: # Maximum leaf area index (m2/m2)
274 | 0.01
275 | LAIR_max_bare: # Reference leaf area index (m2/m2)
276 | 0.01
277 |
278 |
279 | ## Cellular Automaton Vegetation:
280 |
281 | # Grass
282 |
283 | Pemaxg: # Maximal establishment probability
284 | 0.35
285 | ING: # Parameter to define allelopathic effect on grass from cresotebush
286 | 2
287 | ThetaGrass: # Drought resistant threshold
288 | 0.62
289 | PmbGrass: # Background mortality probability
290 | 0.05
291 |
292 | # Shrub
293 |
294 | Pemaxsh: # Maximal establishment probability
295 | 0.2
296 | ThetaShrub: # Drought resistant threshold
297 | 0.75
298 | PmbShrub: # Background mortality probability
299 | 0.03
300 | tpmaxShrub: # Maximum age (yr)
301 | 600
302 |
303 | # Tree
304 |
305 | Pemaxtr: # Maximal establishment probability
306 | 0.3
307 | ThetaTree: # Drought resistant threshold
308 | 0.75
309 | PmbTree: # Background mortality probability
310 | 0.01
311 | tpmaxTree: # Maximum age (yr)
312 | 350
313 |
314 | # ShrubSeedling
315 |
316 | ThetaShrubSeedling: # Drought resistant threshold
317 | 0.64
318 | PmbShrubSeedling: # Background mortality probability
319 | 0.03
320 | tpmaxShrubSeedling: # Maximum age (yr)
321 | 18
322 |
323 | # TreeSeedling
324 |
325 | ThetaTreeSeedling: # Drought resistant threshold
326 | 0.64
327 | PmbTreeSeedling: # Background mortality probability
328 | 0.03
329 | tpmaxTreeSeedling: # Maximum age (yr)
330 | 18
331 |
--------------------------------------------------------------------------------
/ecohydrology/cellular_automaton_vegetation_flat_surface/ca_veg_flat_surface_py_file.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Wed Jul 20 2016
4 |
5 | This tutorial is on:
6 | landlab/tutorials/ecohydrology/cellular_automaton_vegetation_flat_surface.ipynb
7 |
8 | Creating a (.py) version of the same.
9 |
10 | @author: Sai Nudurupati & Erkan Istanbulluoglu
11 | """
12 |
13 | import time
14 | import numpy as np
15 | from landlab import RasterModelGrid as rmg
16 | from Ecohyd_functions_flat import (txt_data_dict, Initialize_, Empty_arrays,
17 | Create_PET_lookup, Save_, Plot_)
18 |
19 | grid1 = rmg((100, 100), spacing=(5., 5.))
20 | grid = rmg((5, 4), spacing=(5., 5.))
21 |
22 | InputFile = 'Inputs_Vegetation_CA.txt'
23 | data = txt_data_dict(InputFile) # Create dictionary that holds the inputs
24 |
25 | PD_D, PD_W, Rad, PET_Tree, PET_Shrub, PET_Grass, SM, VEG, vegca = Initialize_(
26 | data, grid, grid1)
27 |
28 | n_years = 1200 # Approx number of years for model to run
29 | # Calculate approximate number of storms per year
30 | fraction_wet = (data['doy__end_of_monsoon']-data['doy__start_of_monsoon'])/365.
31 | fraction_dry = 1 - fraction_wet
32 | no_of_storms_wet = (8760 * (fraction_wet)/(data['mean_interstorm_wet'] +
33 | data['mean_storm_wet']))
34 | no_of_storms_dry = (8760 * (fraction_dry)/(data['mean_interstorm_dry'] +
35 | data['mean_storm_dry']))
36 | n = int(n_years * (no_of_storms_wet + no_of_storms_dry))
37 |
38 | P, Tb, Tr, Time, VegType, PET_, Rad_Factor, EP30, PET_threshold = Empty_arrays(
39 | n, grid, grid1)
40 |
41 | Create_PET_lookup(Rad, PET_Tree, PET_Shrub, PET_Grass, PET_, Rad_Factor,
42 | EP30, grid)
43 |
44 | # # Represent current time in years
45 | current_time = 0 # Start from first day of Jan
46 |
47 | # Keep track of run time for simulation - optional
48 | Start_time = time.clock() # Recording time taken for simulation
49 |
50 | # declaring few variables that will be used in the storm loop
51 | time_check = 0. # Buffer to store current_time at previous storm
52 | yrs = 0 # Keep track of number of years passed
53 | WS = 0. # Buffer for Water Stress
54 | Tg = 270 # Growing season in days
55 |
56 | # # Run storm Loop
57 | for i in range(0, n):
58 | # Update objects
59 |
60 | # Calculate Day of Year (DOY)
61 | Julian = np.int(np.floor((current_time - np.floor(current_time)) * 365.))
62 |
63 | # Generate seasonal storms
64 | # for Dry season
65 | if Julian < data['doy__start_of_monsoon'] or Julian > data[
66 | 'doy__end_of_monsoon']:
67 | PD_D.update()
68 | P[i] = PD_D.storm_depth
69 | Tr[i] = PD_D.storm_duration
70 | Tb[i] = PD_D.interstorm_duration
71 | # Wet Season - Jul to Sep - NA Monsoon
72 | else:
73 | PD_W.update()
74 | P[i] = PD_W.storm_depth
75 | Tr[i] = PD_W.storm_duration
76 | Tb[i] = PD_W.interstorm_duration
77 |
78 | # Spatially distribute PET and its 30-day-mean (analogous to degree day)
79 | grid['cell']['surface__potential_evapotranspiration_rate'] = PET_[Julian]
80 | grid['cell']['surface__potential_evapotranspiration_30day_mean'] = EP30[
81 | Julian]
82 |
83 | # Assign spatial rainfall data
84 | grid['cell']['rainfall__daily_depth'] = P[i] * np.ones(grid.number_of_cells)
85 |
86 | # Update soil moisture component
87 | current_time = SM.update(current_time, Tr=Tr[i], Tb=Tb[i])
88 |
89 | # Decide whether its growing season or not
90 | if Julian != 364:
91 | if EP30[Julian+1, 0] > EP30[Julian, 0]:
92 | PET_threshold = 1
93 | # 1 corresponds to ETThresholdup (begin growing season)
94 | else:
95 | PET_threshold = 0
96 | # 0 corresponds to ETThresholddown (end growing season)
97 |
98 | # Update vegetation component
99 | VEG.update(PETThreshold_switch=PET_threshold, Tb=Tb[i], Tr=Tr[i])
100 |
101 | # Update yearly cumulative water stress data
102 | WS += (grid['cell']['vegetation__water_stress'])*Tb[i]/24.
103 |
104 | # Record time (optional)
105 | Time[i] = current_time
106 |
107 | # Update spatial PFTs with Cellular Automata rules
108 | if (current_time - time_check) >= 1.:
109 | if yrs % 100 == 0:
110 | print 'Elapsed time = ', yrs, ' years'
111 | VegType[yrs] = grid1['cell']['vegetation__plant_functional_type']
112 | WS_ = np.choose(VegType[yrs], WS)
113 | grid1['cell']['vegetation__cumulative_water_stress'] = WS_/Tg
114 | vegca.update()
115 | time_check = current_time
116 | WS = 0
117 | yrs += 1
118 |
119 | VegType[yrs] = grid1['cell']['vegetation__plant_functional_type']
120 |
121 | Final_time = time.clock()
122 | Time_Consumed = (Final_time - Start_time)/60. # in minutes
123 | print 'Time_consumed = ', Time_Consumed, ' minutes'
124 |
125 | # # Saving
126 | # sim = 'Sim_26Jul16_'
127 | # Save_(sim, Tb, Tr, P, VegType, yrs, Time_Consumed, Time)
128 |
129 | Plot_(grid1, VegType, yrs, yr_step=100)
130 |
--------------------------------------------------------------------------------
/environment.yml:
--------------------------------------------------------------------------------
1 | name: landlab_binder
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - python
6 | - landlab
7 | - jupyter
8 | - dask
9 | - holoviews
10 | - pytest
11 |
--------------------------------------------------------------------------------
/fields/working_with_fields.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 | "# Understanding and working with Landlab data fields"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "\n",
22 | " For instructions on how to run an interactive iPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
23 | "For the unexpanded version to download and run, click here: https://nbviewer.jupyter.org/github/landlab/tutorials/blob/release/grid_object_demo/grid_object_demo_unexpanded.ipynb \n",
24 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials\n",
25 | ""
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "Data fields, or just fields for short, are the primary way that components share model data amongst themselves. This tutorial gives a short introduction to what fields are, what they do, and how to work with them.\n",
33 | "\n",
34 | "Let's start by importing the modules we'll need for this tutorial, and instantiating a simple grid to work with for the first part of the tutorial:"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 1,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "import numpy as np\n",
44 | "from landlab import RasterModelGrid, FieldError\n",
45 | "from landlab.components import LinearDiffuser\n",
46 | "\n",
47 | "mg = RasterModelGrid((3, 4), 1.)"
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | "A discussed in the grid tutorial, all data stored on the grid exists as \"flat\" one-dimensional arrays. This means that information can be retrieved from these grids using the ID of an grid element as the index:"
55 | ]
56 | },
57 | {
58 | "cell_type": "code",
59 | "execution_count": 2,
60 | "metadata": {},
61 | "outputs": [
62 | {
63 | "data": {
64 | "text/plain": [
65 | "True"
66 | ]
67 | },
68 | "execution_count": 2,
69 | "metadata": {},
70 | "output_type": "execute_result"
71 | }
72 | ],
73 | "source": [
74 | "# demonstrate that arrays of properties are n-elements long\n",
75 | "(mg.x_of_node.shape == (mg.number_of_nodes, ) and\n",
76 | " mg.length_of_link.shape == (mg.number_of_links, ))"
77 | ]
78 | },
79 | {
80 | "cell_type": "code",
81 | "execution_count": 3,
82 | "metadata": {},
83 | "outputs": [
84 | {
85 | "data": {
86 | "text/plain": [
87 | "1.0"
88 | ]
89 | },
90 | "execution_count": 3,
91 | "metadata": {},
92 | "output_type": "execute_result"
93 | }
94 | ],
95 | "source": [
96 | "# what's the length of the link with ID 6 (the 7th link)?\n",
97 | "mg.length_of_link[6]"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {},
103 | "source": [
104 | "Any values we defined across the grid are indexed in the same way, e.g., an array of elevations would be of shape (n-nodes, ).\n",
105 | "\n",
106 | "A Landlab field, then, is simply an array like this explicitly linked to an element type, and stored within the grid object itself. Doing this serves four main purposes:\n",
107 | "\n",
108 | "1. It means that if a component has access to the grid, it also has access to all the data defined on the grid.\n",
109 | "2. It allows us to enforce the idea that an array of values of nodes is always n-nodes-long, an array on links is always n-links-long, etc.\n",
110 | "3. It provides a standardized interface where the nomenclature used by a given component for input-output is both unambiguous and clear, in the spirit of the [CSDMS standard names](https://csdms.colorado.edu/wiki/CSDMS_Standard_Names).\n",
111 | "4. The field structure also allows us to bind the measurement unit to the field, if we so wish.\n",
112 | "\n",
113 | "Note that Landlab components generally follow a \"CSDMS-like\" naming conventiomn, where the name looks like `thing_that_is_described__quantity_described`, with a double underscore in the middle. In cases where the equivalent Standard Name would be excessively long, a shorter alternatively is usually used.\n",
114 | "\n",
115 | "\n",
116 | "## Making fields on the grid\n",
117 | "\n",
118 | "There are several ways to create a field within the grid. These include functions to create fields filled just with ones or zeros, similar to the numpy functions `np.ones` and `np.zeros`, and functions to create fields from existing value arrays that you want to join to the grid.\n",
119 | "\n",
120 | "The first term supplied is always the element on which the field is defined, i.e., 'node', 'link', 'cell', etc. The second is the name to give the field.\n",
121 | "\n",
122 | "All these creation routines also return a reference to the field. This can be a useful shorthand to get at the grid without having to write out the full field name every time:"
123 | ]
124 | },
125 | {
126 | "cell_type": "code",
127 | "execution_count": 4,
128 | "metadata": {},
129 | "outputs": [
130 | {
131 | "name": "stdout",
132 | "output_type": "stream",
133 | "text": [
134 | "[1 1 1 1 0 0 1 0 0 0 1 0 0 1 1 1 1]\n"
135 | ]
136 | }
137 | ],
138 | "source": [
139 | "no_1a = mg.add_zeros('node', 'field__number_one')\n",
140 | "no_1b = mg.add_ones('link', 'field__number_two', dtype=int) # fns can also take dtype\n",
141 | "no_1b[mg.active_links] = 0\n",
142 | "print(no_1b)"
143 | ]
144 | },
145 | {
146 | "cell_type": "markdown",
147 | "metadata": {},
148 | "source": [
149 | "All the field creation routines share two optional keywords: `units` and `noclobber`. `units` (default: '-') allows a unit to be associated with a field if desired. `noclobber` (default: `True`) prevents accidental overwriting of an existing field. If you want to overwrite, set it to `False`.\n",
150 | "\n",
151 | "Let's try creating a field from an existing array here (`grid.add_field()`). In this case, there's an additional keyword `copy` (default = `False`) that controls whether the field refers to the actual first array, or whether a copy of the data is made:"
152 | ]
153 | },
154 | {
155 | "cell_type": "code",
156 | "execution_count": 5,
157 | "metadata": {},
158 | "outputs": [],
159 | "source": [
160 | "input_array = np.arange(mg.number_of_nodes, dtype=float)"
161 | ]
162 | },
163 | {
164 | "cell_type": "code",
165 | "execution_count": 6,
166 | "metadata": {},
167 | "outputs": [
168 | {
169 | "name": "stdout",
170 | "output_type": "stream",
171 | "text": [
172 | "ERROR: This field name already exists!\n"
173 | ]
174 | }
175 | ],
176 | "source": [
177 | "try:\n",
178 | " no_1c = mg.add_field('node', 'field__number_one', input_array, copy=False, units='m')\n",
179 | "except FieldError:\n",
180 | " print('ERROR: This field name already exists!')"
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "execution_count": 7,
186 | "metadata": {},
187 | "outputs": [
188 | {
189 | "name": "stdout",
190 | "output_type": "stream",
191 | "text": [
192 | "[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.]\n"
193 | ]
194 | }
195 | ],
196 | "source": [
197 | "# ...let's try that again:\n",
198 | "no_1c = mg.add_field('node', 'field__number_one', input_array, copy=False,\n",
199 | " units='m', noclobber=False)\n",
200 | "print(no_1c)"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": 8,
206 | "metadata": {},
207 | "outputs": [
208 | {
209 | "name": "stdout",
210 | "output_type": "stream",
211 | "text": [
212 | "[-1. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1. -1.]\n"
213 | ]
214 | }
215 | ],
216 | "source": [
217 | "# note that the keyword `copy=False` means that the field array *is* the input_array...\n",
218 | "input_array[:] = -1.\n",
219 | "print(no_1c)"
220 | ]
221 | },
222 | {
223 | "cell_type": "markdown",
224 | "metadata": {},
225 | "source": [
226 | "## Accessing a data field, deleting a data field\n",
227 | "\n",
228 | "We've already seen that the array creation routines return a reference to the field data. But sometimes, you want to access the field directly.\n",
229 | "\n",
230 | "In practical terms, think of the names themselves as nested inside the grid as if the grid itself were a Python dictionary. The element type is the first key, and the field name is the second key.\n",
231 | "\n",
232 | "(In detail, the type is actually a Landlab-specific object called a ScalarDataField, but it behaves essentially as an enhanced Python dictionary)."
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": 9,
238 | "metadata": {},
239 | "outputs": [
240 | {
241 | "data": {
242 | "text/plain": [
243 | "array([-1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1., -1.])"
244 | ]
245 | },
246 | "execution_count": 9,
247 | "metadata": {},
248 | "output_type": "execute_result"
249 | }
250 | ],
251 | "source": [
252 | "mg['node']['field__number_one']"
253 | ]
254 | },
255 | {
256 | "cell_type": "markdown",
257 | "metadata": {},
258 | "source": [
259 | "You'll also very commonly see some common \"syntactic sugar\" for this, where the element key is replaced by a grid property called `grid.at_[element]`. i.e.,"
260 | ]
261 | },
262 | {
263 | "cell_type": "code",
264 | "execution_count": 10,
265 | "metadata": {},
266 | "outputs": [
267 | {
268 | "data": {
269 | "text/plain": [
270 | "True"
271 | ]
272 | },
273 | "execution_count": 10,
274 | "metadata": {},
275 | "output_type": "execute_result"
276 | }
277 | ],
278 | "source": [
279 | "mg.at_node['field__number_one'] is mg['node']['field__number_one']"
280 | ]
281 | },
282 | {
283 | "cell_type": "markdown",
284 | "metadata": {},
285 | "source": [
286 | "Because these structures are dictionary-like, we can use the usual set of Python dictionary methods to interact with them too:"
287 | ]
288 | },
289 | {
290 | "cell_type": "code",
291 | "execution_count": 11,
292 | "metadata": {},
293 | "outputs": [
294 | {
295 | "data": {
296 | "text/plain": [
297 | "dict_keys(['field__number_one'])"
298 | ]
299 | },
300 | "execution_count": 11,
301 | "metadata": {},
302 | "output_type": "execute_result"
303 | }
304 | ],
305 | "source": [
306 | "mg.at_node.keys() # see the existing fields at nodes"
307 | ]
308 | },
309 | {
310 | "cell_type": "code",
311 | "execution_count": 12,
312 | "metadata": {},
313 | "outputs": [],
314 | "source": [
315 | "mg.at_node.clear() # delete all fields at nodes"
316 | ]
317 | },
318 | {
319 | "cell_type": "code",
320 | "execution_count": 13,
321 | "metadata": {},
322 | "outputs": [
323 | {
324 | "data": {
325 | "text/plain": [
326 | "dict_keys([])"
327 | ]
328 | },
329 | "execution_count": 13,
330 | "metadata": {},
331 | "output_type": "execute_result"
332 | }
333 | ],
334 | "source": [
335 | "mg.at_node.keys()"
336 | ]
337 | },
338 | {
339 | "cell_type": "code",
340 | "execution_count": 14,
341 | "metadata": {},
342 | "outputs": [
343 | {
344 | "data": {
345 | "text/plain": [
346 | "dict_keys(['field__number_two'])"
347 | ]
348 | },
349 | "execution_count": 14,
350 | "metadata": {},
351 | "output_type": "execute_result"
352 | }
353 | ],
354 | "source": [
355 | "mg.at_link.keys()"
356 | ]
357 | },
358 | {
359 | "cell_type": "code",
360 | "execution_count": 15,
361 | "metadata": {},
362 | "outputs": [
363 | {
364 | "data": {
365 | "text/plain": [
366 | "array([1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1])"
367 | ]
368 | },
369 | "execution_count": 15,
370 | "metadata": {},
371 | "output_type": "execute_result"
372 | }
373 | ],
374 | "source": [
375 | "mg.at_link.pop('field__number_two') # return the field, and remove it from the array"
376 | ]
377 | },
378 | {
379 | "cell_type": "code",
380 | "execution_count": 16,
381 | "metadata": {},
382 | "outputs": [
383 | {
384 | "data": {
385 | "text/plain": [
386 | "dict_keys([])"
387 | ]
388 | },
389 | "execution_count": 16,
390 | "metadata": {},
391 | "output_type": "execute_result"
392 | }
393 | ],
394 | "source": [
395 | "mg.at_link.keys()"
396 | ]
397 | },
398 | {
399 | "cell_type": "markdown",
400 | "metadata": {},
401 | "source": [
402 | "The units are recorded in a further dict-like structure attached to `at_[element]`:"
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": 17,
408 | "metadata": {},
409 | "outputs": [
410 | {
411 | "data": {
412 | "text/plain": [
413 | "'km'"
414 | ]
415 | },
416 | "execution_count": 17,
417 | "metadata": {},
418 | "output_type": "execute_result"
419 | }
420 | ],
421 | "source": [
422 | "z = mg.add_ones('node', 'field__number_3', units='km', noclobber=False)\n",
423 | "mg.at_node.units['field__number_3']"
424 | ]
425 | },
426 | {
427 | "cell_type": "markdown",
428 | "metadata": {},
429 | "source": [
430 | "### Click here for more Landlab tutorials"
431 | ]
432 | }
433 | ],
434 | "metadata": {
435 | "kernelspec": {
436 | "display_name": "Python 3",
437 | "language": "python",
438 | "name": "python3"
439 | },
440 | "language_info": {
441 | "codemirror_mode": {
442 | "name": "ipython",
443 | "version": 3
444 | },
445 | "file_extension": ".py",
446 | "mimetype": "text/x-python",
447 | "name": "python",
448 | "nbconvert_exporter": "python",
449 | "pygments_lexer": "ipython3",
450 | "version": "3.6.7"
451 | }
452 | },
453 | "nbformat": 4,
454 | "nbformat_minor": 1
455 | }
456 |
--------------------------------------------------------------------------------
/groundwater/groundwater_flow.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Modeling groundwater flow in a conceptual catchment\n",
15 | "\n",
16 | "\n",
17 | " For instructions on how to run an interactive iPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
18 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials\n",
19 | "\n",
20 | "\n",
21 | "This tutorial demonstrates how the GroundwaterDupuitPercolator can be used to model groundwater flow and seepage (groundwater return flow). It is recommended to read the documentation for the component before starting this tutorial to be familiar with the mechanics of the model.\n",
22 | "\n",
23 | "In this tutorial you will:\n",
24 | "* Create a raster grid on which to run the model\n",
25 | "* Simulate constant recharge and check that the component conserves mass\n",
26 | "* Simulate recharge from storm events, check conservation of mass, and look at the outflow hydrograph"
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {},
32 | "source": [
33 | "A bit of magic so that we can plot within this notebook."
34 | ]
35 | },
36 | {
37 | "cell_type": "code",
38 | "execution_count": null,
39 | "metadata": {},
40 | "outputs": [],
41 | "source": [
42 | "from __future__ import print_function\n",
43 | "%matplotlib inline"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "### Import libraries"
51 | ]
52 | },
53 | {
54 | "cell_type": "code",
55 | "execution_count": null,
56 | "metadata": {},
57 | "outputs": [],
58 | "source": [
59 | "import numpy as np\n",
60 | "import matplotlib.pyplot as plt\n",
61 | "\n",
62 | "from landlab import RasterModelGrid, FIXED_VALUE_BOUNDARY, CLOSED_BOUNDARY, imshow_grid\n",
63 | "from landlab.components import GroundwaterDupuitPercolator, FlowAccumulator\n",
64 | "from landlab.components.uniform_precip import PrecipitationDistribution"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "## Create a RasterModelGrid\n",
72 | "\n",
73 | "Here you will make the grid on which we will run the model. You will create three fields: topographic elevation, aquifer base elevation, and initial water table elevation"
74 | ]
75 | },
76 | {
77 | "cell_type": "code",
78 | "execution_count": null,
79 | "metadata": {},
80 | "outputs": [],
81 | "source": [
82 | "boundaries = {'top': 'closed','bottom': 'closed','right':'closed','left':'closed'}\n",
83 | "grid = RasterModelGrid((51, 51), spacing=10.0,bc=boundaries)\n",
84 | "grid.status_at_node[1] = FIXED_VALUE_BOUNDARY \n",
85 | "\n",
86 | "elev = grid.add_zeros('node', 'topographic__elevation')\n",
87 | "elev[:] = (0.001*grid.x_of_node**2 + 0.001*grid.y_of_node**2)+2\n",
88 | "\n",
89 | "base = grid.add_zeros('node', 'aquifer_base__elevation')\n",
90 | "base[:] = elev - 2\n",
91 | "\n",
92 | "wt = grid.add_zeros('node', 'water_table__elevation')\n",
93 | "wt[:] = elev"
94 | ]
95 | },
96 | {
97 | "cell_type": "code",
98 | "execution_count": null,
99 | "metadata": {},
100 | "outputs": [],
101 | "source": [
102 | "plt.figure()\n",
103 | "imshow_grid(grid,'topographic__elevation')"
104 | ]
105 | },
106 | {
107 | "cell_type": "markdown",
108 | "metadata": {},
109 | "source": [
110 | "The grid is square with dimensions 500x500m. The surface elevation and aquifer base have the same concave parabolic shape, with thickness 2m between them. The aquifer is initially fully saturated (water table at the surface). Water is only allowed to exit the domain through a single node in the the lower left corner. All other boundaries are closed. "
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {},
116 | "source": [
117 | "## Simulate constant groundwater recharge\n",
118 | "\n",
119 | "Now initialize the model components. In addition to the grid, the GroundwaterDupuitPercolator takes four optional arguments: hydraulic conductivity, porosity, recharge rate, and a regularization factor that smooths the transition between subsurface and surface flow as the water table approaches the ground surface. The greater the value, the smoother the transition.\n",
120 | "\n",
121 | "You will also initialize a FlowAccumulator in order to use an included method to calculate the surface water discharge out of the domain. The runoff rate used by the FlowAccumulator is the surface water specific discharge from the groundwater model."
122 | ]
123 | },
124 | {
125 | "cell_type": "code",
126 | "execution_count": null,
127 | "metadata": {},
128 | "outputs": [],
129 | "source": [
130 | "K = 0.01 # hydraulic conductivity, (m/s)\n",
131 | "R = 1e-7 # recharge rate, (m/s)\n",
132 | "n = 0.2 # porosity, (-)\n",
133 | "gdp = GroundwaterDupuitPercolator(grid, hydraulic_conductivity=K, porosity = n, recharge_rate=R,regularization_f=0.01)\n",
134 | "fa = FlowAccumulator(grid, surface='topographic__elevation',\n",
135 | " flow_director='FlowDirectorSteepest', runoff_rate='surface_water__specific_discharge')"
136 | ]
137 | },
138 | {
139 | "cell_type": "markdown",
140 | "metadata": {},
141 | "source": [
142 | "Next, run the model forward in time, and track the fluxes leaving the domain."
143 | ]
144 | },
145 | {
146 | "cell_type": "code",
147 | "execution_count": null,
148 | "metadata": {},
149 | "outputs": [],
150 | "source": [
151 | "N = 1000\n",
152 | "dt = 1E2\n",
153 | "\n",
154 | "recharge_flux = np.zeros(N)\n",
155 | "gw_flux = np.zeros(N)\n",
156 | "sw_flux = np.zeros(N)\n",
157 | "storage = np.zeros(N)\n",
158 | "\n",
159 | "for i in range(N):\n",
160 | " gdp.run_one_step(dt)\n",
161 | " \n",
162 | " fa.run_one_step()\n",
163 | " \n",
164 | " recharge_flux[i] = gdp.calc_recharge_flux_in()\n",
165 | " gw_flux[i] = gdp.calc_gw_flux_out()\n",
166 | " sw_flux[i] = gdp.calc_sw_flux_out()\n",
167 | " storage[i] = gdp.calc_total_storage()"
168 | ]
169 | },
170 | {
171 | "cell_type": "markdown",
172 | "metadata": {},
173 | "source": [
174 | "Now visualize some results."
175 | ]
176 | },
177 | {
178 | "cell_type": "code",
179 | "execution_count": null,
180 | "metadata": {},
181 | "outputs": [],
182 | "source": [
183 | "plt.figure()\n",
184 | "imshow_grid(grid,(wt-base)/(elev-base),cmap='Blues')"
185 | ]
186 | },
187 | {
188 | "cell_type": "markdown",
189 | "metadata": {},
190 | "source": [
191 | "The above shows how saturated the aquifer is. Note that it is most saturated at the lowest area of the domain, nearest the outlet.\n",
192 | "\n",
193 | "Now look at the mass balance by ploting cumulative fluxes. The cumulative recharge in should be equal to cumulative fluxes out (groundwater and surface water) plus the change in storage from the initial condition."
194 | ]
195 | },
196 | {
197 | "cell_type": "code",
198 | "execution_count": null,
199 | "metadata": {},
200 | "outputs": [],
201 | "source": [
202 | "t = np.arange(0,N*dt,dt)\n",
203 | "\n",
204 | "plt.figure(figsize=(8,6))\n",
205 | "plt.plot(t/3600,np.cumsum(gw_flux)*dt+np.cumsum(sw_flux)*dt+storage-storage[0],\n",
206 | " 'b-',linewidth=3, alpha=0.5,label='Total Fluxes + Storage' )\n",
207 | "plt.plot(t/3600,np.cumsum(recharge_flux)*dt,'k:',label='recharge flux')\n",
208 | "plt.plot(t/3600,np.cumsum(gw_flux)*dt,'b:',label='groundwater flux')\n",
209 | "plt.plot(t/3600,np.cumsum(sw_flux)*dt,'g:',label='surface water flux')\n",
210 | "plt.plot(t/3600,storage-storage[0], 'r:', label='storage')\n",
211 | "plt.ylabel('Cumulative Volume $[m^3]$')\n",
212 | "plt.xlabel('Time [h]')\n",
213 | "plt.legend(frameon=False)\n",
214 | "plt.show()"
215 | ]
216 | },
217 | {
218 | "cell_type": "markdown",
219 | "metadata": {},
220 | "source": [
221 | "The thick blue line (cumulative fluxes plus storage) matches the black cumulative recharge flux line, which indicates that the model has conserved mass. Because the initial domain was fully saturated, the primary feature that shows up in this mass balance is the loss of that initial water. It will be easier to see what is going on here in the second example. "
222 | ]
223 | },
224 | {
225 | "cell_type": "markdown",
226 | "metadata": {},
227 | "source": [
228 | "## Simulate time-varying recharge\n",
229 | "\n",
230 | "Lastly, simulate time-varying recharge, look at the mass balance, and the outflow hydrograph. This will use the same grid and groundwater model instance as above, taking the final condition of the previous model run as the new initial condition here. This time the adaptive timestep solver will be used to make sure the model remains stable.\n",
231 | "\n",
232 | "First, we need a distribution of recharge events. We will use landlab's precipitation distribution tool to create a lists paired recharge events and intensities."
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": null,
238 | "metadata": {},
239 | "outputs": [],
240 | "source": [
241 | "#generate storm timeseries\n",
242 | "T = 10*24*3600 #sec\n",
243 | "Tr = 1*3600 #sec\n",
244 | "Td = 24*3600 #sec\n",
245 | "dt = 1e3 #sec\n",
246 | "p = 1e-3 #m\n",
247 | "\n",
248 | "precip = PrecipitationDistribution(mean_storm_duration=Tr, mean_interstorm_duration=Td, \n",
249 | " mean_storm_depth=p, total_t=T, delta_t=dt)\n",
250 | "durations = []\n",
251 | "intensities = []\n",
252 | "precip.seed_generator(seedval=1)\n",
253 | "for (interval_duration, rainfall_rate_in_interval) in (\n",
254 | " precip.yield_storm_interstorm_duration_intensity(subdivide_interstorms=True)\n",
255 | "):\n",
256 | " durations.append(interval_duration)\n",
257 | " intensities.append(rainfall_rate_in_interval)\n",
258 | "N = len(durations) "
259 | ]
260 | },
261 | {
262 | "cell_type": "markdown",
263 | "metadata": {},
264 | "source": [
265 | "Next run the model forward with the run_with_adaptive_time_step_solver. This method is the same as run_one_step, except that it subdivides the provided timestep (event or inter-event duration in this case) in order to meet a Courant-type stability criterion. The argument courant_coefficient indicates how large the maximum allowed timestep is relative to the Courant limit. Values close to 0.1 are recommended for best results."
266 | ]
267 | },
268 | {
269 | "cell_type": "code",
270 | "execution_count": null,
271 | "metadata": {},
272 | "outputs": [],
273 | "source": [
274 | "recharge_flux = np.zeros(N)\n",
275 | "gw_flux = np.zeros(N)\n",
276 | "sw_flux = np.zeros(N)\n",
277 | "storage = np.zeros(N)\n",
278 | "num_substeps = np.zeros(N)\n",
279 | "\n",
280 | "for i in range(N):\n",
281 | " gdp.recharge = intensities[i]*np.ones_like(gdp.recharge)\n",
282 | " gdp.run_with_adaptive_time_step_solver(durations[i], courant_coefficient=0.2)\n",
283 | "\n",
284 | " num_substeps[i] = gdp.number_of_substeps\n",
285 | " \n",
286 | " fa.run_one_step()\n",
287 | "\n",
288 | " recharge_flux[i] = gdp.calc_recharge_flux_in()\n",
289 | " gw_flux[i] = gdp.calc_gw_flux_out()\n",
290 | " sw_flux[i] = gdp.calc_sw_flux_out()\n",
291 | " storage[i] = gdp.calc_total_storage()"
292 | ]
293 | },
294 | {
295 | "cell_type": "markdown",
296 | "metadata": {},
297 | "source": [
298 | "Again, visualize the mass balance:"
299 | ]
300 | },
301 | {
302 | "cell_type": "code",
303 | "execution_count": null,
304 | "metadata": {},
305 | "outputs": [],
306 | "source": [
307 | "t = np.cumsum(durations)\n",
308 | "\n",
309 | "plt.figure()\n",
310 | "plt.plot(t/3600,np.cumsum(gw_flux*durations)+np.cumsum(sw_flux*durations)+storage-storage[0],\n",
311 | " 'b-',linewidth=3, alpha=0.5,label='Total Fluxes + Storage' )\n",
312 | "plt.plot(t/3600,np.cumsum(recharge_flux*durations)-recharge_flux[0]*durations[0],'k:',label='recharge flux')\n",
313 | "plt.plot(t/3600,np.cumsum(gw_flux*durations),'b:',label='groundwater flux')\n",
314 | "plt.plot(t/3600,np.cumsum(sw_flux*durations),'g:',label='surface water flux')\n",
315 | "plt.plot(t/3600,storage-storage[0], 'r:', label='storage')\n",
316 | "plt.ylabel('Cumulative Volume $[m^3]$')\n",
317 | "plt.xlabel('Time [h]')\n",
318 | "plt.legend(frameon=False)\n",
319 | "plt.show()"
320 | ]
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {},
325 | "source": [
326 | "Visualize numer of substeps that the model took for stability:"
327 | ]
328 | },
329 | {
330 | "cell_type": "code",
331 | "execution_count": null,
332 | "metadata": {},
333 | "outputs": [],
334 | "source": [
335 | "plt.figure()\n",
336 | "plt.plot(num_substeps,'.')\n",
337 | "plt.xlabel('Iteration')\n",
338 | "plt.ylabel('Numer of Substeps')\n",
339 | "plt.yticks([1,5,10,15,20])\n",
340 | "plt.show()"
341 | ]
342 | },
343 | {
344 | "cell_type": "code",
345 | "execution_count": null,
346 | "metadata": {},
347 | "outputs": [],
348 | "source": [
349 | "max(num_substeps)"
350 | ]
351 | },
352 | {
353 | "cell_type": "markdown",
354 | "metadata": {},
355 | "source": [
356 | "The method has subdivided the timestep up to 18 times in order to meet the stability criterion. This is dependent on a number of factors, including the Courant coefficient, the hydraulic conductivity, and hydraulic gradient.\n",
357 | "\n",
358 | "Now look at the timeseries of recharge in and groundwater and surface water leaving the domain at the open node:"
359 | ]
360 | },
361 | {
362 | "cell_type": "code",
363 | "execution_count": null,
364 | "metadata": {},
365 | "outputs": [],
366 | "source": [
367 | "fig,ax = plt.subplots(figsize=(8,6))\n",
368 | "ax.plot(t/(3600*24),sw_flux, label='Surface water flux')\n",
369 | "ax.plot(t/(3600*24),gw_flux, label='Groundwater flux')\n",
370 | "ax.set_ylim((0,0.04))\n",
371 | "ax.set_ylabel('Flux out $[m^3/s]$')\n",
372 | "ax.set_xlabel('Time [d]')\n",
373 | "ax.legend(frameon=False,loc=7)\n",
374 | "ax1 = ax.twinx()\n",
375 | "ax1.plot(t/(3600*24),recharge_flux,'0.6')\n",
376 | "ax1.set_ylim((1.2,0))\n",
377 | "ax1.set_ylabel('Recharge flux in $[m^3/s]$')\n",
378 | "plt.show()"
379 | ]
380 | },
381 | {
382 | "cell_type": "markdown",
383 | "metadata": {},
384 | "source": [
385 | "The relationship between maximum flux that can be passed through the subsurface and the occurrence of groundwater seepage is clear from this figure."
386 | ]
387 | },
388 | {
389 | "cell_type": "markdown",
390 | "metadata": {},
391 | "source": [
392 | "### Click here for more Landlab tutorials"
393 | ]
394 | },
395 | {
396 | "cell_type": "code",
397 | "execution_count": null,
398 | "metadata": {},
399 | "outputs": [],
400 | "source": []
401 | }
402 | ],
403 | "metadata": {
404 | "kernelspec": {
405 | "display_name": "Python 3",
406 | "language": "python",
407 | "name": "python3"
408 | },
409 | "language_info": {
410 | "codemirror_mode": {
411 | "name": "ipython",
412 | "version": 3
413 | },
414 | "file_extension": ".py",
415 | "mimetype": "text/x-python",
416 | "name": "python",
417 | "nbconvert_exporter": "python",
418 | "pygments_lexer": "ipython3",
419 | "version": "3.7.3"
420 | }
421 | },
422 | "nbformat": 4,
423 | "nbformat_minor": 1
424 | }
425 |
--------------------------------------------------------------------------------
/landlab_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/landlab/tutorials/b98a8ab47249579b90298622853421dac5294f76/landlab_header.png
--------------------------------------------------------------------------------
/landlab_logo_picture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/landlab/tutorials/b98a8ab47249579b90298622853421dac5294f76/landlab_logo_picture.jpg
--------------------------------------------------------------------------------
/making_components/component_design_tips.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "
a toolkit for modeling earth surface processes
"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Tips on Writing Landlab Components"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "\n",
22 | " For instructions on how to run an interactive iPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
23 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials\n",
24 | ""
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "Thanks for your interest in developing a component in Landlab! \n",
32 | "\n",
33 | "This ipython notebook provides some tips on designing and building Landlab components. It assumes you are familiar with the basics of building a component. If you haven't already, take a look at the tutorial on [How to Write a Landlab Component](https://github.com/landlab/tutorials/blob/release/making_components/making_components.ipynb), the User Guide section on [Developing Your Own Component](https://github.com/landlab/landlab/wiki/Develop-your-own-component), and the [Example Pull Request Creating a Component](https://github.com/landlab/landlab/pull/678). We also recommend that you familiarize yourself with the [Style and Lint conventions](https://github.com/landlab/landlab/wiki/Style-conventions)."
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "metadata": {},
39 | "source": [
40 | "## Why Does This Guide Exist?\n",
41 | "\n",
42 | "The Landlab development team has been working together for nearly a decade to create the Landlab toolkit. Through this time many of the team members have iterated toward a set of best practices for creating and using components. Some of these recommendations are enforced in order to contribute code to Landlab, and some of them are just recommended. \n",
43 | "\n",
44 | "We want to make sure we communicate these recommendations to the community of potential Landlab component developers. "
45 | ]
46 | },
47 | {
48 | "cell_type": "markdown",
49 | "metadata": {
50 | "collapsed": true
51 | },
52 | "source": [
53 | "## Components versus Models\n",
54 | "\n",
55 | "Landlab components are designed to serve as the building blocks for numerical models, but a Landlab component is not a model by itself. Rather, a component-based Landlab model typically consists of a *driver program* that instantiates and runs one or more components. For this reason, a Landlab component will not normally create or contain another component (though there are occasional exceptions that prove the rule; for example, a `FlowAccumulator` can create a `FlowDirector`). Instead, if one component relies on output from another component, the recommended practice is to have the relevant output field from one component act as an input field for another. For example, a component that generates a spatial rainfall pattern would have the rainfall as an output field; a runoff-generation component might then require a rainfall field as an input.\n",
56 | "\n",
57 | "A common question we get that relates to the component vs model concept is \"how do I setup my component to ingest entire rainfall record for my model run?\" The recommended practice is to build your component so it can look at fields on the model grid and run forward in time a duration `dt`. If say, you had a external dataset that gave you gridded rainfall through time as a `(nr, nc, nt)` numpy array, we would recommend that your build your component to look at a precipitation field each time it runs one step, and that your driver use the gridded precipititation each timestep to update that field. \n",
58 | "\n",
59 | "We advocate for this design because it is agnostic to exactly how a components input fields (in this example precipitation) are set. This makes components more reusable. "
60 | ]
61 | },
62 | {
63 | "cell_type": "markdown",
64 | "metadata": {},
65 | "source": [
66 | "## Required and Recommended Elements for Components\n",
67 | "\n",
68 | "A Landlab component must:\n",
69 | "\n",
70 | "* Derive from the Component base class\n",
71 | "* Provide the standard header information (such as `input_var_names`)\n",
72 | "* Provide an `__init__` method. A Landlab grid object should be the first argument (after `self`). Any other necessary parameters should be given as keyword arguments with meaningful defaults. \n",
73 | "* Provide a `run_one_step` method. \n",
74 | "* Include external and internal documentation. If the component is included in the Landlab package (as opposed to being a separate add-on), it needs to have an entry in the API Reference Manual at landlab.readthedocs.org. (In most cases, the text on the website is autogenerated from the docstrings in the component itself, but the documentation files must still be updated by hand to refer to the new component, as described below.) The component code should include a header docstring that briefly describes what it is, and lists its input parameters.\n",
75 | "\n",
76 | "In addition to these basic ingredients, we highly recommend that Landlab components also include the following:\n",
77 | "\n",
78 | "* A docstring for each function. Docstrings should ideally include (1) a one-line description of what the component does, starting with a verb (e.g., \"Update fields with current loading conditions\"); (2) a list of parameters with their data types, units (if applicable), and a brief description; (3) data returned (if any); (4) one or more doctests; and (5) any relevant notes that will help your future self (or others) understand how the function works.\n",
79 | "* Unit tests. These can be implemented either as built-in doctests, or as external tests, or both. \n",
80 | "* Tutorial(s). A Jupyter Notebook is a great way to illustrate how a component can be used. Notebooks that contain tutorials about various Landlab components are in the [tutorials](https://github.com/landlab/tutorials) repository. Ideally, every component should have an accompanying tutorial (though as of this writing we have not yet reached that goal).\n",
81 | "\n",
82 | "As part of an ongoing effort to standardize the Landlab component library, we will soon require the following additional characteristics. Not all Landlab components currently meet these requirements, but starting with an upcoming v2.0 release all components will be required to meet these standards. \n",
83 | "\n",
84 | "* The component may use `*kwds` at the end of the `__init__` but must raise an error if unused `kwds` are passed. \n",
85 | "* The `run_one_step` method must either have no arguments other than `self`, or have a single additional argument that represents the duration of the step.\n",
86 | "* Class variables -- i.e., those defined as `self.[var_name]` in the code -- that are not meant to be seen or modified by users should ideally be flagged as private by adding a leading underscore to the variable name (this will be most of them!). Those that don't are considered public, and should be handled using the `@property` decorator as described below.\n",
87 | "\n"
88 | ]
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "metadata": {},
93 | "source": [
94 | "## Unit Testing\n",
95 | "\n",
96 | "Testing is essential to writing robust scientific software (see, e.g., [The Turing Way guide to testing research code](https://the-turing-way.netlify.com/testing/testing.html)). A typical Landlab component includes two types of test: doctests and external tests.\n",
97 | "\n",
98 | "Doctests, in addition to testing a particular piece of code, should also give users an idea of how the code works---in other words, it should function both as a test, and as an example of how to use the functionality in question. Docstrings, including doctests, are scraped automatically to create content in the [Landlab API Reference Manual](https://landlab.readthedocs.io).\n",
99 | "\n",
100 | "External testing scripts normally live in a subdirectory called `tests` inside your component's main folder, in a file called `test_`(something)`.py`, with one or more functions whose names begin with `test_`. Using this naming convention is how the testing tool we use ([`pytest`](https://pytest.org/en/latest/)) is able to find and run your tests. \n",
101 | "\n",
102 | "### Useful tools for writing tests\n",
103 | "The `numpy.testing` module provides handy functions for testing, such as asserting that the values in a particular array match the values that you expect. [`pytest`](https://pytest.org/en/latest/) provides the ability to test whether a particular error is raised with the [`pytest.raises`](https://docs.pytest.org/en/latest/reference.html?highlight=assert#pytest-raises) function. Nonetheless, in many cases the core Python libraries will suffice for testing: a test fails if any assertion fails and/or an error or exception is raised, and you can both `assert` logical conditions in tests and `raise` various [standard Python](https://docs.python.org/3/library/exceptions.html) or [Landlab-specific](https://landlab.readthedocs.io/en/latest/landlab.field.html#landlab.field.FieldError) exceptions within components \"by hand\".\n",
104 | "\n",
105 | "If you use a common block of code (e.g., setting up a grid) in multiple test, we recommend looking into using a [`pytest.fixture`](https://docs.pytest.org/en/latest/reference.html?highlight=assert#pytest-fixture) to define it. \n",
106 | "\n",
107 | "If you want to write the same test but loop through multiple parameter values (e.g., use both `D8` and `MFD` flow directing), check out the [`pytest.parametrize`](https://docs.pytest.org/en/latest/reference.html?highlight=assert#pytest-mark-parametrize) function.\n",
108 | "\n",
109 | "### How we use the tests as part of maintaining Landlab\n",
110 | "If your component is part of the Landlab codebase (and not an external plugin), its tests will be run automatically whenever a pull request is made and we will enforce that they all pass before bringing the code into the main repository. \n",
111 | "\n",
112 | "But as part of your development, you might also want to run the tests locally. As of this writing, the Landlab Development Team uses the `pytest` utility, together with the `coverage` extension that calculates which lines of code are and are not covered by at least one test. An example of the command-line syntax to run tests is:\n",
113 | "\n",
114 | "`pytest --doctest-modules --cov-report term-missing --cov=.`\n",
115 | "\n",
116 | "This example usage tells pytest to run doctests as well as external tests, to examine the coverage of any files in the current directory or its subdirectories, and to display a report listing the coverage in each file.\n",
117 | "\n",
118 | "### What parts of my should I write tests for? \n",
119 | "Best practice is to have your component 100% tested, meaning that every line gets run at least once. Not all of Landlab meets this standard (as of writing, total coverage is 87 %) and the following is what we find to be most practical. We recommend writing tests with small grids for which you can do all calculations by hand (typically 3x10, 5x5, or smaller).\n",
120 | "\n",
121 | "* Any part of your code that has an analytical solution should get a test demonstrating that this solution is met.\n",
122 | "* Barring an analytical solution, you should make a small grid and create a test that asserts that a known correct answer is met (e.g., run just one step forward, and calculate exactly what the end-of-run-one-step values are). \n",
123 | "* If there are places where you ensure something about an input (e.g., that porosity is positive), you should write a tests indicating that if the value is bad and an [`Error`](https://docs.python.org/3/library/exceptions.html) is `raised`. \n",
124 | "* Your tests don't need to be of the entire run-one-step process, but might just test critical parts of it. \n"
125 | ]
126 | },
127 | {
128 | "cell_type": "markdown",
129 | "metadata": {},
130 | "source": [
131 | "## Documentation\n",
132 | "\n",
133 | "Each Landlab component ideally has three kinds of documentation: internal documentation using docstrings within the code, \"external\" documentation in the [Landlab API Reference Manual](https://landlab.readthedocs.io), and one or more tutorials in the [tutorials](https://github.com/landlab/tutorials) repository. Internal and external documentation are essentially one and the same: the internal docstrings are read and formatted (\"scraped\") to produce the API Reference documentation for each component. To get a component's docstrings included in the API Reference, you simply need to create a short text file in Landlab's `docs` folder, and edit the `index.rst` file in the same folder to add a reference to your new file. The process is described in the User Guide section on [Developing Your Own Component](https://github.com/landlab/landlab/wiki/Develop-your-own-component)."
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | "## Coding Tips and Tricks\n",
141 | "\n",
142 | "### Avoid Hard-Coding Numbers\n",
143 | "\n",
144 | "It can be tempting to include hard numbers in your code, such as:\n",
145 | "\n",
146 | "```python\n",
147 | "grav_force = 9.81 * mass\n",
148 | "```\n",
149 | "\n",
150 | "There are two disadvantages to this approach. An obvious one is that a user who wants to change the hard number is forced to edit the code (what if you want to run your model for Mars?). Another disadvantage is that the hard numbers are buried deep in the code, and might not be documented. Yet a third potential problem is that the hard-wired numbers may have units, and therefore rely on the assumption that any other inputs and variables have compatible units. And finally, your hardwired numbers may lack sufficient precision for a user's application (e.g., is gravitational acceleration 10.0 or 9.8 or 9.81?).\n",
151 | "\n",
152 | "A better option is to have these numbers be user-determined inputs with built-in default values. For example,\n",
153 | "\n",
154 | "```python\n",
155 | "class MyCoolComponent(Component):\n",
156 | " ...\n",
157 | " def __init__(self, grid, grav_accel=9.8):\n",
158 | " ...\n",
159 | "```\n",
160 | "\n",
161 | "If for some reason this is not a practical option---for example, if the numerical value in question is truly a constant---then a good practice is to use \"syntactic sugar\": define a variable in ALLCAPS near the head of the file in question. For example,\n",
162 | "\n",
163 | "```python\n",
164 | "GRAV_CONSTANT = 6.67408e-11 # near head of file\n",
165 | "\n",
166 | "...\n",
167 | "\n",
168 | "grav_force = GRAV_CONSTANT * (mass1 * mass2 / distance**2) # somewhere deep in the code\n",
169 | "```\n",
170 | "\n",
171 | "### Avoid Multiple `if` Sequences\n",
172 | "\n",
173 | "Sometimes it is the nature of an algorithm to ask a lot of questions:\n",
174 | "\n",
175 | "```python\n",
176 | "if this:\n",
177 | " ...\n",
178 | "elif that:\n",
179 | " ...\n",
180 | "else:\n",
181 | " ...\n",
182 | "```\n",
183 | "\n",
184 | "Although this kind of construction can be hard to avoid in some cases, it also increases the testing burden: each case needs to be tested in order to ensure 100% coverage. They can also hamper performance, if the tests need to be repeated many times. If you find yourself writing long chains of conditional statements, consider whether there are any cleaner alternatives.\n",
185 | "\n",
186 | "For example consider the following example. Say that `params` is a dictionary and you need to check if `spam` is in `params`, you need a boolean variable called `spam_in_params` that indicats whether it is present. You could write:\n",
187 | "\n",
188 | "```python\n",
189 | "if \"spam\" in params:\n",
190 | " spam_in_params = True\n",
191 | "else:\n",
192 | " spam_in_params = False\n",
193 | "```\n",
194 | "\n",
195 | "You could acomplish the same thing with a cleaner alternative:\n",
196 | "\n",
197 | "```python\n",
198 | "spam_in_params = params.get(\"spam\", False)\n",
199 | "```\n",
200 | "\n",
201 | "Very complex sets of if/else logic may be best dealt with using a dictionary as a lookup table. \n",
202 | "\n",
203 | "\n",
204 | "### Field Names\n",
205 | "\n",
206 | "Landlab field names should be reasonably descriptive, while not being overly long. For example, `hydraulic_conductivity` is a better field name than simply `K`. As of this writing, Landlab has not yet adopted a standard naming convention (such as the CSDMS Standard Names, or the CF Standard Names), but best practice is to follow the *de facto* Landlab standards for names that already exist in at least one component. Landlab has tended thus far to use names that are in the spirit of (and sometimes identical to) the CSDMS Standard Names, while keeping these names to a manageable length.\n",
207 | "\n",
208 | "An (infrequently updated) list of the standard names currently used in Landlab can be found [here](https://github.com/landlab/landlab/wiki/Standard-names).\n",
209 | "\n",
210 | "### Public and Private Variables\n",
211 | "\n",
212 | "The following describes an emerging coding standard for component class variables to be adopted starting with Landlab 2.0:\n",
213 | "\n",
214 | "Use the Python convention that class variables are \"private\" if their name begins with an underscore, and \"public\" if it does not. For internal variables that are not intended to be viewed or modified by users, make the variable private by prepending an underscore. Example:\n",
215 | "\n",
216 | "```python\n",
217 | "self._diffusivity = 0.01\n",
218 | "```\n",
219 | "For internal variables that you wish users to be able to read (only), make the internal variable private but provide a \"getter\" function that is tagged with the `@property` decorator. Example (from the Flexure component):\n",
220 | "\n",
221 | "```python\n",
222 | "@property\n",
223 | "def youngs(self):\n",
224 | " \"\"\"Young's modulus of lithosphere (Pa).\"\"\"\n",
225 | " return self._youngs\n",
226 | "```\n",
227 | "\n",
228 | "Including the \"getter\" function allows you to include documentation for the public variable in the form of a docstring.\n",
229 | "\n",
230 | "If you want users to have both read and write access to a variable---for example, if you want a user to be able to dynamically change one of your parameters if needed---provide both a \"getter\" and a \"setter\". An example of a getter-setter pair is (also from Flexure):\n",
231 | "\n",
232 | "```python\n",
233 | "@property\n",
234 | "def eet(self):\n",
235 | " \"\"\"Effective elastic thickness (m).\"\"\"\n",
236 | " return self._eet\n",
237 | "\n",
238 | "@eet.setter\n",
239 | "def eet(self, new_val):\n",
240 | " if new_val <= 0:\n",
241 | " raise ValueError(\"Effective elastic thickness must be positive.\")\n",
242 | " self._eet = new_val\n",
243 | " self._r = self._create_kei_func_grid(\n",
244 | " self._grid.shape, (self.grid.dy, self.grid.dx), self.alpha\n",
245 | " )\n",
246 | "```\n",
247 | "\n",
248 | "Using a setter function allows you to make sure that the user isn't giving an inappropriate value of the parameter (as in the example of a negative elastic thickness above, which would not make any sense). In general, think long and hard about giving users the ability to set variables. An update of a variable at the \"wrong\" time can easily lead to unforeseen consequences if some parts of the component have assumed the old value previously. Careful [testing](#unit-testing) is probably in order in these cases.\n",
249 | "\n",
250 | "## Other references\n",
251 | "Many of the landlab developers have found this [resource on python anti-patterns](https://docs.quantifiedcode.com/python-anti-patterns/index.html) helpful. "
252 | ]
253 | },
254 | {
255 | "cell_type": "markdown",
256 | "metadata": {},
257 | "source": [
258 | "### Click here for more Landlab tutorials"
259 | ]
260 | }
261 | ],
262 | "metadata": {
263 | "kernelspec": {
264 | "display_name": "Python 3",
265 | "language": "python",
266 | "name": "python3"
267 | },
268 | "language_info": {
269 | "codemirror_mode": {
270 | "name": "ipython",
271 | "version": 3
272 | },
273 | "file_extension": ".py",
274 | "mimetype": "text/x-python",
275 | "name": "python",
276 | "nbconvert_exporter": "python",
277 | "pygments_lexer": "ipython3",
278 | "version": "3.6.8"
279 | }
280 | },
281 | "nbformat": 4,
282 | "nbformat_minor": 1
283 | }
284 |
--------------------------------------------------------------------------------
/mappers/mappers.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 | "# Mapping values between grid elements\n",
15 | "\n",
16 | "\n",
17 | " (Note: for instructions on how to run an interactive iPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
18 | "For the unexpanded version to download and run, click here: https://nbviewer.jupyter.org/github/landlab/tutorials/blob/release/mappers/mappers_unexpanded.ipynb \n",
19 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials)\n",
20 | "\n",
21 | "\n",
22 | "Imagine that you're using Landlab to write a model of shallow water flow over terrain. A natural approach is to place your scalar fields, such as water depth, at the nodes. You then place your vector fields, such as water surface gradient, flow velocity, and discharge, at the links. But your velocity depends on both slope and depth, which means you need to know the depth at the links too. How do you do this?\n",
23 | "\n",
24 | "This tutorial introduces *mappers*: grid functions that map quantities defined on one set of elements (such as nodes) onto another set of elements (such as links). As you'll see, there are a variety of mappers available.\n",
25 | "\n"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "## Mapping from nodes to links\n",
33 | "\n",
34 | "For the sake of example, we'll start with a simple 3-row by 4-column raster grid. The grid will contain a scalar field called `water__depth`, abbreviated `h`. We'll populate it with some example values, as follows:"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": 1,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": [
43 | "from __future__ import print_function\n",
44 | "from landlab import RasterModelGrid\n",
45 | "import numpy as np\n",
46 | "mg = RasterModelGrid((3, 4), 100.0)\n",
47 | "h = mg.add_zeros('node', 'surface_water__depth')\n",
48 | "h[:] = 7 - np.abs(6 - np.arange(12))"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "For the sake of visualizing values at nodes on our grid, we'll define a handy little function:"
56 | ]
57 | },
58 | {
59 | "cell_type": "code",
60 | "execution_count": 2,
61 | "metadata": {},
62 | "outputs": [],
63 | "source": [
64 | "def show_node_values(mg, u):\n",
65 | " for r in range(mg.number_of_node_rows - 1, -1, -1):\n",
66 | " for c in range(mg.number_of_node_columns):\n",
67 | " print(int(u[c + (mg.number_of_node_columns * r)]), end=' ')\n",
68 | " print()"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "execution_count": 3,
74 | "metadata": {},
75 | "outputs": [
76 | {
77 | "name": "stdout",
78 | "output_type": "stream",
79 | "text": [
80 | "5 4 3 2 \n",
81 | "5 6 7 6 \n",
82 | "1 2 3 4 \n"
83 | ]
84 | }
85 | ],
86 | "source": [
87 | "show_node_values(mg, h)"
88 | ]
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "metadata": {},
93 | "source": [
94 | "Let's review the numbering of nodes and links. The lines below will print a list that shows, for each link ID, the IDs of the nodes at the link's tail and head:"
95 | ]
96 | },
97 | {
98 | "cell_type": "code",
99 | "execution_count": 4,
100 | "metadata": {},
101 | "outputs": [
102 | {
103 | "name": "stdout",
104 | "output_type": "stream",
105 | "text": [
106 | "0 0 1\n",
107 | "1 1 2\n",
108 | "2 2 3\n",
109 | "3 0 4\n",
110 | "4 1 5\n",
111 | "5 2 6\n",
112 | "6 3 7\n",
113 | "7 4 5\n",
114 | "8 5 6\n",
115 | "9 6 7\n",
116 | "10 4 8\n",
117 | "11 5 9\n",
118 | "12 6 10\n",
119 | "13 7 11\n",
120 | "14 8 9\n",
121 | "15 9 10\n",
122 | "16 10 11\n"
123 | ]
124 | }
125 | ],
126 | "source": [
127 | "for i in range(mg.number_of_links):\n",
128 | " print(i, mg.node_at_link_tail[i], mg.node_at_link_head[i])"
129 | ]
130 | },
131 | {
132 | "cell_type": "markdown",
133 | "metadata": {},
134 | "source": [
135 | "### Finding the mean value between two nodes on a link\n",
136 | "\n",
137 | "Suppose we want to have a *link-based* array, called *h_edge*, that contains water depth at locations between adjacent pairs of nodes. For each link, we'll simply take the average of the depth at the link's two nodes. To accomplish this, we can use the `map_mean_of_link_nodes_to_link` grid method. At link 8, for example, we'll average the *h* values at nodes 5 and 6, which should give us a depth of (6 + 7) / 2 = 6.5:"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 5,
143 | "metadata": {},
144 | "outputs": [
145 | {
146 | "name": "stdout",
147 | "output_type": "stream",
148 | "text": [
149 | "0 1.5\n",
150 | "1 2.5\n",
151 | "2 3.5\n",
152 | "3 3.0\n",
153 | "4 4.0\n",
154 | "5 5.0\n",
155 | "6 5.0\n",
156 | "7 5.5\n",
157 | "8 6.5\n",
158 | "9 6.5\n",
159 | "10 5.0\n",
160 | "11 5.0\n",
161 | "12 5.0\n",
162 | "13 4.0\n",
163 | "14 4.5\n",
164 | "15 3.5\n",
165 | "16 2.5\n"
166 | ]
167 | }
168 | ],
169 | "source": [
170 | "h_edge = mg.map_mean_of_link_nodes_to_link('surface_water__depth')\n",
171 | "for i in range(mg.number_of_links):\n",
172 | " print(i, h_edge[i])"
173 | ]
174 | },
175 | {
176 | "cell_type": "markdown",
177 | "metadata": {},
178 | "source": [
179 | "### What's in a name?\n",
180 | "\n",
181 | "The mapping functions have long names, which are designed to make it as clear as possible to understand what each function does. All the mappers start with the verb *map*. Then the relationship is given; in this case, we are looking at the *mean*. Then the elements from which a quantity is being mapped: we are taking values from *link nodes*. Finally, the element to which the new values apply: *link*.\n",
182 | "\n",
183 | "### Mapping minimum or maximum values\n",
184 | "\n",
185 | "We can also map the minimum value of *h*:"
186 | ]
187 | },
188 | {
189 | "cell_type": "code",
190 | "execution_count": 6,
191 | "metadata": {},
192 | "outputs": [
193 | {
194 | "name": "stdout",
195 | "output_type": "stream",
196 | "text": [
197 | "0 1.0\n",
198 | "1 2.0\n",
199 | "2 3.0\n",
200 | "3 1.0\n",
201 | "4 2.0\n",
202 | "5 3.0\n",
203 | "6 4.0\n",
204 | "7 5.0\n",
205 | "8 6.0\n",
206 | "9 6.0\n",
207 | "10 5.0\n",
208 | "11 4.0\n",
209 | "12 3.0\n",
210 | "13 2.0\n",
211 | "14 4.0\n",
212 | "15 3.0\n",
213 | "16 2.0\n"
214 | ]
215 | }
216 | ],
217 | "source": [
218 | "h_edge = mg.map_min_of_link_nodes_to_link('surface_water__depth')\n",
219 | "for i in range(mg.number_of_links):\n",
220 | " print(i, h_edge[i])"
221 | ]
222 | },
223 | {
224 | "cell_type": "markdown",
225 | "metadata": {},
226 | "source": [
227 | "... or the maximum:"
228 | ]
229 | },
230 | {
231 | "cell_type": "code",
232 | "execution_count": 7,
233 | "metadata": {},
234 | "outputs": [
235 | {
236 | "name": "stdout",
237 | "output_type": "stream",
238 | "text": [
239 | "0 2.0\n",
240 | "1 3.0\n",
241 | "2 4.0\n",
242 | "3 5.0\n",
243 | "4 6.0\n",
244 | "5 7.0\n",
245 | "6 6.0\n",
246 | "7 6.0\n",
247 | "8 7.0\n",
248 | "9 7.0\n",
249 | "10 5.0\n",
250 | "11 6.0\n",
251 | "12 7.0\n",
252 | "13 6.0\n",
253 | "14 5.0\n",
254 | "15 4.0\n",
255 | "16 3.0\n"
256 | ]
257 | }
258 | ],
259 | "source": [
260 | "h_edge = mg.map_max_of_link_nodes_to_link('surface_water__depth')\n",
261 | "for i in range(mg.number_of_links):\n",
262 | " print(i, h_edge[i])"
263 | ]
264 | },
265 | {
266 | "cell_type": "markdown",
267 | "metadata": {},
268 | "source": [
269 | "### Upwind and downwind\n",
270 | "\n",
271 | "Numerical schemes often use *upwind differencing* or *downwind differencing*. For example, finite difference schemes for equations that include advection may use \"upwind\" rather than centered differences, in which a scalar quantity (our *h* for example) is taken from whichever side is upstream in the flow field.\n",
272 | "\n",
273 | "How do we know the flow direction? If the flow is driven by the gradient in some scalar field, such as pressure or elevation, one approach is to look at the values of this scalar on either end of the link: the end with the higher value is upwind, and the end with the lower value is downwind.\n",
274 | "\n",
275 | "Suppose for example that our water flow is driven by the water-surface slope (which is often a good approximation for the *energy slope*, though it omits the kinetic energy). Let's define a bed-surface elevation field *z*:"
276 | ]
277 | },
278 | {
279 | "cell_type": "code",
280 | "execution_count": 8,
281 | "metadata": {},
282 | "outputs": [
283 | {
284 | "name": "stdout",
285 | "output_type": "stream",
286 | "text": [
287 | "15 14 13 12 \n",
288 | "13 14 15 16 \n",
289 | "9 10 11 12 \n"
290 | ]
291 | }
292 | ],
293 | "source": [
294 | "z = mg.add_zeros('node', 'topographic__elevation')\n",
295 | "z[:] = 16 - np.abs(7 - np.arange(12))\n",
296 | "show_node_values(mg, z)"
297 | ]
298 | },
299 | {
300 | "cell_type": "markdown",
301 | "metadata": {},
302 | "source": [
303 | "The water-surface elevation is then the sum of *h* and *z*:"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 9,
309 | "metadata": {},
310 | "outputs": [
311 | {
312 | "name": "stdout",
313 | "output_type": "stream",
314 | "text": [
315 | "20 18 16 14 \n",
316 | "18 20 22 22 \n",
317 | "10 12 14 16 \n"
318 | ]
319 | }
320 | ],
321 | "source": [
322 | "w = z + h\n",
323 | "show_node_values(mg, w)"
324 | ]
325 | },
326 | {
327 | "cell_type": "markdown",
328 | "metadata": {},
329 | "source": [
330 | "For every link, we can assign the value of *h* from whichever end of the link has the greater *w*:"
331 | ]
332 | },
333 | {
334 | "cell_type": "code",
335 | "execution_count": 10,
336 | "metadata": {},
337 | "outputs": [
338 | {
339 | "name": "stdout",
340 | "output_type": "stream",
341 | "text": [
342 | "0 2.0\n",
343 | "1 3.0\n",
344 | "2 4.0\n",
345 | "3 5.0\n",
346 | "4 6.0\n",
347 | "5 7.0\n",
348 | "6 6.0\n",
349 | "7 6.0\n",
350 | "8 7.0\n",
351 | "9 6.0\n",
352 | "10 5.0\n",
353 | "11 6.0\n",
354 | "12 7.0\n",
355 | "13 6.0\n",
356 | "14 5.0\n",
357 | "15 4.0\n",
358 | "16 3.0\n"
359 | ]
360 | }
361 | ],
362 | "source": [
363 | "h_edge = mg.map_value_at_max_node_to_link(w, h)\n",
364 | "for i in range(mg.number_of_links):\n",
365 | " print(i, h_edge[i])"
366 | ]
367 | },
368 | {
369 | "cell_type": "markdown",
370 | "metadata": {},
371 | "source": [
372 | "Consider the middle two nodes (5 and 6). Node 6 is higher (22 versus 20). Therefore, the link between them (link 8) should be assigned the value of *h* at node 6. This value happens to be 7.0.\n",
373 | "\n",
374 | "Of course, we could also take the value from the *lower* of the two nodes, which gives link 8 a value of 6.0:"
375 | ]
376 | },
377 | {
378 | "cell_type": "code",
379 | "execution_count": 11,
380 | "metadata": {},
381 | "outputs": [
382 | {
383 | "name": "stdout",
384 | "output_type": "stream",
385 | "text": [
386 | "0 1.0\n",
387 | "1 2.0\n",
388 | "2 3.0\n",
389 | "3 1.0\n",
390 | "4 2.0\n",
391 | "5 3.0\n",
392 | "6 4.0\n",
393 | "7 5.0\n",
394 | "8 6.0\n",
395 | "9 6.0\n",
396 | "10 5.0\n",
397 | "11 4.0\n",
398 | "12 3.0\n",
399 | "13 2.0\n",
400 | "14 4.0\n",
401 | "15 3.0\n",
402 | "16 2.0\n"
403 | ]
404 | }
405 | ],
406 | "source": [
407 | "h_edge = mg.map_value_at_min_node_to_link(w, h)\n",
408 | "for i in range(mg.number_of_links):\n",
409 | " print(i, h_edge[i])"
410 | ]
411 | },
412 | {
413 | "cell_type": "markdown",
414 | "metadata": {
415 | "collapsed": true
416 | },
417 | "source": [
418 | "### Heads or tails?\n",
419 | "\n",
420 | "It is also possible to map the scalar quantity at either the head node or the tail node to the link:"
421 | ]
422 | },
423 | {
424 | "cell_type": "code",
425 | "execution_count": 12,
426 | "metadata": {},
427 | "outputs": [
428 | {
429 | "name": "stdout",
430 | "output_type": "stream",
431 | "text": [
432 | "0 2.0\n",
433 | "1 3.0\n",
434 | "2 4.0\n",
435 | "3 5.0\n",
436 | "4 6.0\n",
437 | "5 7.0\n",
438 | "6 6.0\n",
439 | "7 6.0\n",
440 | "8 7.0\n",
441 | "9 6.0\n",
442 | "10 5.0\n",
443 | "11 4.0\n",
444 | "12 3.0\n",
445 | "13 2.0\n",
446 | "14 4.0\n",
447 | "15 3.0\n",
448 | "16 2.0\n"
449 | ]
450 | }
451 | ],
452 | "source": [
453 | "h_edge = mg.map_link_head_node_to_link('surface_water__depth')\n",
454 | "for i in range(mg.number_of_links):\n",
455 | " print(i, h_edge[i])"
456 | ]
457 | },
458 | {
459 | "cell_type": "code",
460 | "execution_count": 13,
461 | "metadata": {},
462 | "outputs": [
463 | {
464 | "name": "stdout",
465 | "output_type": "stream",
466 | "text": [
467 | "0 1.0\n",
468 | "1 2.0\n",
469 | "2 3.0\n",
470 | "3 1.0\n",
471 | "4 2.0\n",
472 | "5 3.0\n",
473 | "6 4.0\n",
474 | "7 5.0\n",
475 | "8 6.0\n",
476 | "9 7.0\n",
477 | "10 5.0\n",
478 | "11 6.0\n",
479 | "12 7.0\n",
480 | "13 6.0\n",
481 | "14 5.0\n",
482 | "15 4.0\n",
483 | "16 3.0\n"
484 | ]
485 | }
486 | ],
487 | "source": [
488 | "h_edge = mg.map_link_tail_node_to_link('surface_water__depth')\n",
489 | "for i in range(mg.number_of_links):\n",
490 | " print(i, h_edge[i])"
491 | ]
492 | },
493 | {
494 | "cell_type": "markdown",
495 | "metadata": {},
496 | "source": [
497 | "### Simple example using centered water depth\n",
498 | "The following implements one time-step of a linear-viscous flow model, in which flow velocity is calculated at the links, and the depth at each link is taken as the mean of depth at the two bounding nodes. To make the flow a little tamer, we'll have our fluid be hot, low viscosity basaltic lava instead of water, with a dynamic viscosity of 100 Pa s."
499 | ]
500 | },
501 | {
502 | "cell_type": "code",
503 | "execution_count": 14,
504 | "metadata": {},
505 | "outputs": [
506 | {
507 | "name": "stdout",
508 | "output_type": "stream",
509 | "text": [
510 | "0 1.5 0.02 -3.75\n",
511 | "1 2.5 0.02 -10.4166666667\n",
512 | "2 3.5 0.02 -20.4166666667\n",
513 | "3 3.0 0.08 -60.0\n",
514 | "4 4.0 0.08 -106.666666667\n",
515 | "5 5.0 0.08 -166.666666667\n",
516 | "6 5.0 0.06 -125.0\n",
517 | "7 5.5 0.02 -50.4166666667\n",
518 | "8 6.5 0.02 -70.4166666667\n",
519 | "9 6.5 0.0 -0.0\n",
520 | "10 5.0 0.02 -41.6666666667\n",
521 | "11 5.0 -0.02 41.6666666667\n",
522 | "12 5.0 -0.06 125.0\n",
523 | "13 4.0 -0.08 106.666666667\n",
524 | "14 4.5 -0.02 33.75\n",
525 | "15 3.5 -0.02 20.4166666667\n",
526 | "16 2.5 -0.02 10.4166666667\n"
527 | ]
528 | }
529 | ],
530 | "source": [
531 | "gamma = 25000.0 # unit weight of fluid, N/m2\n",
532 | "viscosity = 100.0 # dynamic viscosity in Pa s\n",
533 | "grad = mg.calc_grad_at_link(w)\n",
534 | "h_edge = mg.map_mean_of_link_nodes_to_link(h)\n",
535 | "vel = -(gamma / (3.0 * viscosity)) * h_edge * h_edge * grad\n",
536 | "for ln in range(mg.number_of_links):\n",
537 | " print(ln, h_edge[ln], grad[ln], vel[ln])"
538 | ]
539 | },
540 | {
541 | "cell_type": "markdown",
542 | "metadata": {},
543 | "source": [
544 | "I'm not sure I love the idea of a 5-m thick lava flow moving at over 100 m/s! (I guess we can take some comfort from the thought that turbulence would probably slow it down)\n",
545 | "\n",
546 | "How different would the numerical solution be using an upwind scheme for flow depth? Let's find out:"
547 | ]
548 | },
549 | {
550 | "cell_type": "code",
551 | "execution_count": 15,
552 | "metadata": {},
553 | "outputs": [
554 | {
555 | "name": "stdout",
556 | "output_type": "stream",
557 | "text": [
558 | "0 2.0 0.02 -6.66666666667\n",
559 | "1 3.0 0.02 -15.0\n",
560 | "2 4.0 0.02 -26.6666666667\n",
561 | "3 5.0 0.08 -166.666666667\n",
562 | "4 6.0 0.08 -240.0\n",
563 | "5 7.0 0.08 -326.666666667\n",
564 | "6 6.0 0.06 -180.0\n",
565 | "7 6.0 0.02 -60.0\n",
566 | "8 7.0 0.02 -81.6666666667\n",
567 | "9 6.0 0.0 -0.0\n",
568 | "10 5.0 0.02 -41.6666666667\n",
569 | "11 6.0 -0.02 60.0\n",
570 | "12 7.0 -0.06 245.0\n",
571 | "13 6.0 -0.08 240.0\n",
572 | "14 5.0 -0.02 41.6666666667\n",
573 | "15 4.0 -0.02 26.6666666667\n",
574 | "16 3.0 -0.02 15.0\n"
575 | ]
576 | }
577 | ],
578 | "source": [
579 | "h_edge = mg.map_value_at_max_node_to_link(w, h)\n",
580 | "vel = -(gamma / (3.0 * viscosity)) * h_edge * h_edge * grad\n",
581 | "for ln in range(mg.number_of_links):\n",
582 | " print(ln, h_edge[ln], grad[ln], vel[ln])"
583 | ]
584 | },
585 | {
586 | "cell_type": "markdown",
587 | "metadata": {},
588 | "source": [
589 | "Even scarier.\n",
590 | "\n",
591 | "In any event, this example illustrates how you can use Landlab's mapping functions to build mass-conservation models in which the flow rate depends on a gradient and a scalar, both of which can be evaluated at links."
592 | ]
593 | }
594 | ],
595 | "metadata": {
596 | "kernelspec": {
597 | "display_name": "Python 3",
598 | "language": "python",
599 | "name": "python3"
600 | },
601 | "language_info": {
602 | "codemirror_mode": {
603 | "name": "ipython",
604 | "version": 3
605 | },
606 | "file_extension": ".py",
607 | "mimetype": "text/x-python",
608 | "name": "python",
609 | "nbconvert_exporter": "python",
610 | "pygments_lexer": "ipython3",
611 | "version": "3.7.3"
612 | }
613 | },
614 | "nbformat": 4,
615 | "nbformat_minor": 1
616 | }
617 |
--------------------------------------------------------------------------------
/overland_flow/hugo_site.asc:
--------------------------------------------------------------------------------
1 | ncols 76
2 | nrows 55
3 | xllcorner 0
4 | yllcorner 0
5 | cellsize 10
6 | NODATA_value -9999
7 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
8 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
9 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1708 -9999 1707 1708 -9999 1708 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
10 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1708 1709 1708 1708 1708 1707 1708 1708 1707 1707 1707 1706 1705 1706 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
11 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1708 1708 1707 1707 1707 1708 1707 1707 1706 1706 1705 1705 1707 1706 1705 1706 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
12 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1706 1707 1707 1707 1707 1707 1707 1707 1706 1706 1705 1705 1705 1705 1705 1706 1707 1706 1705 1705 1705 1705 1707 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
13 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1705 1705 1706 1706 1707 1706 1706 1707 1706 1706 1705 1704 1704 1703 1704 1704 1703 1704 1705 1704 1704 1705 1706 1705 1706 1704 1704 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
14 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1705 1704 1704 1704 1704 1705 1704 1705 1705 1705 1706 1704 1704 1704 1703 1702 1702 1701 1702 1702 1704 1704 1705 1704 1704 1704 1705 1705 1703 1705 1704 1704 1704 1705 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
15 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1704 1703 1702 1702 1703 1702 1703 1704 1703 1704 1704 1703 1702 1701 1700 1699 1699 1698 1700 1701 1702 1703 1703 1704 1704 1704 1704 1704 1705 1703 1702 1702 1702 1703 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
16 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1702 1702 1701 1700 1701 1701 1701 1702 1702 1702 1703 1702 1701 1699 1698 1696 1697 1695 1696 1699 1700 1699 1700 1700 1702 1702 1702 1702 1703 1702 1701 1701 1701 1701 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
17 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1700 1699 1698 1698 1698 1699 1698 1700 1699 1699 1699 1700 1699 1697 1696 1693 1693 1693 1694 1696 1698 1698 1698 1698 1699 1699 1700 1701 1700 1700 1699 1698 1699 1699 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
18 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1699 1698 1697 1696 1696 1695 1695 1696 1697 1697 1697 1697 1696 1696 1695 1693 1691 1689 1689 1691 1692 1695 1696 1695 1695 1695 1696 1697 1698 1698 1697 1695 1695 1696 1698 1698 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
19 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1702 1700 1698 1695 1694 1693 1692 1692 1693 1693 1693 1694 1693 1694 1693 1692 1692 1690 1688 1686 1686 1688 1691 1692 1693 1691 1692 1692 1694 1694 1695 1694 1693 1692 1692 1693 1695 1696 1697 1698 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
20 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1701 1699 1696 1694 1692 1690 1689 1689 1689 1690 1690 1690 1690 1690 1690 1690 1689 1688 1685 1684 1683 1686 1688 1689 1689 1689 1689 1689 1690 1691 1692 1692 1691 1690 1690 1691 1692 1694 1696 1696 1697 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
21 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1704 1703 1701 1698 1696 1694 1691 1688 1687 1686 1686 1687 1687 1686 1687 1687 1687 1686 1686 1685 1683 1681 1681 1683 1685 1686 1686 1686 1686 1686 1687 1688 1689 1689 1688 1687 1686 1688 1689 1691 1694 1695 1695 1696 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
22 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1704 1702 1701 1699 1696 1694 1691 1688 1685 1684 1684 1684 1684 1683 1683 1684 1683 1683 1683 1682 1681 1679 1678 1681 1683 1683 1683 1683 1682 1683 1684 1686 1687 1686 1685 1684 1684 1685 1687 1689 1691 1693 1693 1695 1694 1694 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
23 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1704 1703 1702 1700 1696 1695 1692 1689 1686 1684 1682 1682 1682 1681 1681 1681 1680 1680 1680 1680 1679 1677 1677 1679 1680 1680 1681 1680 1679 1680 1681 1683 1684 1684 1683 1681 1681 1682 1685 1687 1689 1691 1693 1694 1691 1693 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
24 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1702 1700 1698 1696 1692 1690 1688 1685 1685 1684 1681 1680 1680 1679 1678 1678 1678 1677 1677 1676 1675 1677 1677 1677 1678 1678 1677 1677 1679 1681 1682 1682 1681 1679 1678 1680 1683 1686 1688 1689 1690 1692 1691 1691 1692 1692 1692 1692 1691 1690 1692 -9999 -9999
25 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1706 1705 1705 1703 1701 1699 1696 1694 1692 1691 1690 1688 1687 1685 1683 1682 1681 1680 1678 1679 1676 1676 1676 1675 1675 1675 1675 1675 1675 1674 1676 1677 1678 1679 1679 1679 1677 1676 1678 1681 1684 1686 1688 1688 1689 1691 1691 1691 1690 1691 1689 1690 1690 1690 1689 -9999
26 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1706 1705 1704 1702 1700 1698 1696 1695 1694 1692 1691 1691 1688 1687 1686 1685 1684 1682 1682 1680 1678 1677 1675 1675 1674 1674 1673 1673 1673 1674 1675 1675 1676 1676 1677 1676 1675 1677 1680 1683 1684 1687 1686 1687 1688 1687 1688 1687 1688 1687 1687 1687 1687 1686 -9999
27 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1706 1705 1705 1703 1701 1700 1699 1697 1696 1695 1694 1693 1691 1690 1688 1688 1687 1685 1685 1683 1682 1680 1678 1678 1677 1675 1673 1672 1671 1672 1673 1673 1673 1674 1675 1673 1673 1676 1679 1680 1682 1683 1684 1683 1684 1684 1683 1684 1684 1684 1683 1684 1683 1682 -9999
28 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1704 1703 1702 1700 1700 1699 1698 1697 1696 1694 1693 1692 1691 1689 1689 1688 1687 1684 1683 1681 1681 1679 1677 1677 1674 1673 1670 1670 1670 1670 1671 1672 1671 1672 1674 1678 1678 1680 1680 1680 1679 1680 1680 1680 1680 1680 1681 1680 1680 1679 1679 -9999
29 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1706 1706 1705 1703 1703 1703 1702 1701 1699 1698 1696 1696 1695 1695 1694 1692 1691 1689 1688 1685 1685 1683 1682 1680 1679 1678 1676 1675 1673 1671 1670 1669 1669 1670 1671 1674 1675 1676 1676 1677 1676 1676 1677 1676 1677 1677 1676 1677 1676 1678 1676 1675 1676
30 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1706 1706 1705 1705 1704 1704 1703 1702 1701 1700 1699 1698 1698 1697 1696 1695 1695 1693 1691 1690 1688 1687 1685 1683 1681 1680 1679 1677 1675 1673 1672 1669 1668 1669 1670 1671 1673 1674 1674 1674 1673 1673 1673 1673 1673 1672 1672 1673 1673 1673 1672 1672 1672
31 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1705 1705 1704 1704 1704 1703 1702 1701 1701 1701 1700 1697 1697 1697 1694 1693 1692 1690 1689 1686 1685 1682 1681 1679 1678 1676 1674 1674 1670 1668 1668 1669 1670 1670 1672 1672 1671 1671 1670 1670 1670 1669 1669 1669 1669 1669 1669 1669 1668 1669
32 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1706 1706 1705 1705 1705 1704 1703 1702 1701 1701 1700 1698 1697 1696 1695 1694 1692 1690 1689 1687 1684 1683 1682 1679 1679 1677 1675 1674 1672 1670 1668 1667 1668 1668 1669 1669 1669 1668 1668 1668 1667 1666 1666 1665 1665 1665 1665 1665 1665 1665
33 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1708 1707 1707 1707 1707 1707 1706 1705 1705 1704 1703 1703 1702 1701 1700 1700 1697 1697 1695 1694 1692 1691 1689 1687 1686 1683 1681 1679 1678 1677 1675 1674 1673 1671 1669 1668 1666 1666 1667 1667 1667 1667 1666 1666 1665 1665 1664 1663 1663 1663 1663 1663 1662 1662 1662
34 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1707 1707 1708 1706 1706 1705 1704 1704 1702 1702 1701 1700 1699 1698 1696 1695 1694 1692 1690 1689 1688 1685 1684 1681 1679 1676 1675 1673 1673 1672 1670 1669 1669 1667 1667 1667 1666 1666 1666 1666 1665 1665 1665 1664 1663 1663 1663 1662 1662 1662 1661 1661 1661
35 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1707 1707 1706 1706 1706 1706 1706 1705 1705 1704 1702 1702 1700 1700 1699 1697 1696 1694 1693 1691 1690 1688 1686 1685 1683 1681 1678 1676 1673 1672 1671 1670 1670 1669 1668 1668 1668 1667 1667 1666 1666 1665 1665 1664 1664 1664 1664 1664 1663 1663 1663 1662 1662 1662 1661 1660
36 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 1706 1705 1705 1706 1705 1704 1704 1702 1701 1701 1699 1698 1697 1695 1694 1692 1691 1689 1687 1686 1684 1682 1680 1678 1676 1674 1672 1671 1670 1671 1669 1670 1670 1670 1669 1668 1670 1667 1666 1665 1666 1664 1665 1665 1665 1665 1664 1664 1664 1663 1664 1663 1662 1661
37 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1706 1705 1705 1704 1705 1704 1704 1703 1702 1701 1700 1698 1697 1696 1695 1694 1692 1690 1688 1686 1684 1682 1681 1679 1678 1676 1674 1672 1672 1673 1672 1673 1672 1672 1672 1673 1671 1671 1673 1673 1669 1667 1665 1666 1666 1668 1668 1667 1666 1667 1665 1664 1666 1665 1663 -9999
38 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1705 1704 1704 1703 1703 1702 1701 1701 1700 1698 1696 1695 1693 1692 1691 1690 1687 1685 1683 1681 1680 1678 1677 1675 1674 1673 1673 1673 1675 1676 1677 1675 1676 1675 1675 1673 1673 1674 1675 1673 1672 1672 1672 1670 1671 1670 1669 1668 1668 1666 1665 1666 1665 -9999 -9999
39 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1705 1704 1703 1702 1701 1700 1700 1699 1699 1698 1696 1694 1692 1691 1690 1688 1687 1685 1682 1681 1679 1678 1676 1675 1675 1674 1674 1676 1674 1676 1678 1679 1679 1679 1679 1677 1675 1674 1676 1679 1679 1679 1678 1674 1674 1673 1671 1670 1669 1668 1666 1666 1668 1668 -9999 -9999
40 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1699 1698 1697 1697 1697 1696 1695 1692 1691 1689 1686 1685 1684 1682 1680 1679 1676 1676 1675 1675 1676 1677 1678 1677 1676 1678 1681 1682 1681 1683 1682 1679 1677 1678 1679 1681 1682 1682 1680 1678 1677 1675 1673 1671 1669 1668 1666 1668 1671 1671 -9999 -9999
41 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1702 1701 1699 1697 1696 1694 1695 1694 1694 1693 1691 1688 1686 1683 1683 1681 1680 1679 1677 1676 1676 1678 1680 1681 1680 1678 1679 1677 1678 1681 1683 1684 1685 1684 1682 1678 1680 1682 1684 1684 1684 1683 1680 1678 1676 1673 1671 1669 1668 1668 1671 1673 -9999 -9999 -9999
42 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1704 1703 1702 1701 1698 1696 1694 1692 1691 1691 1692 1691 1690 1687 1685 1682 1680 1679 1678 1677 1677 1677 1681 1682 1682 1683 1683 1684 1682 1682 1680 1683 1686 1685 1687 1686 1683 1681 1681 1684 1686 1687 1686 1685 1681 1679 1676 1673 1671 1669 1671 1672 1675 1676 -9999 -9999 -9999
43 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1703 1701 1700 1698 1696 1693 1691 1689 1689 1690 1689 1687 1685 1684 1681 1679 1679 1680 1681 1682 1684 1684 1687 1685 1686 1687 1687 1684 1682 1681 1684 1687 1688 1689 1687 1685 1682 1685 1688 1688 1688 1687 1685 1681 1678 1676 1673 1671 1672 1673 1677 1678 1679 -9999 -9999 -9999
44 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1697 1694 1692 1688 1687 1687 1686 1685 1684 1682 1680 1680 1681 1683 1684 1685 1688 1688 1689 1688 1688 1689 1687 1685 1684 1683 1684 1688 1689 1690 1689 1686 1686 1688 1691 1690 1689 1687 1685 1681 1678 1675 1673 1673 1674 1676 1678 1680 1682 -9999 -9999 -9999
45 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1699 1699 1696 1694 1692 1689 1686 1685 1684 1683 1682 1681 1680 1682 1684 1686 1687 1687 1690 1692 1691 1690 1692 1691 1690 1689 1686 1685 1687 1689 1692 1692 1691 1689 1689 1691 1692 1693 1691 1688 1686 1682 1677 1675 1675 1676 1677 1680 1681 1683 1684 -9999 -9999 -9999
46 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1698 1696 1694 1691 1689 1687 1685 1684 1683 1682 1682 1682 1684 1686 1690 1690 1691 1694 1694 1694 1695 1694 1693 1691 1691 1689 1689 1690 1692 1693 1694 1693 1692 1693 1693 1695 1694 1692 1688 1685 1682 1678 1676 1679 1679 1680 1683 1684 1685 1686 -9999 -9999 -9999
47 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1700 1699 1698 1697 1695 1693 1690 1689 1687 1686 1685 1685 1685 1684 1685 1687 1691 1693 1694 1696 1696 1698 1698 1697 1696 1694 1693 1693 1692 1692 1694 1695 1696 1695 1696 1695 1696 1696 1693 1692 1690 1687 1683 1680 1679 1681 1684 1683 1686 1688 1688 1690 1688 -9999 -9999
48 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1695 1694 1692 1690 1689 1689 1689 1688 1687 1686 1686 1689 1692 1694 1696 1698 1699 1700 1700 1700 1699 1697 1696 1696 1695 1694 1697 1697 1699 1698 1698 1696 1698 1697 1696 1694 1691 1689 1685 1683 1681 1686 1687 1688 1687 1691 1689 1691 1691 -9999 -9999
49 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1700 1700 1697 1696 1694 1693 1692 1691 1690 1690 1690 1688 1687 1690 1692 1694 1697 1699 1701 1700 1701 1701 1702 1698 1700 1698 1698 1697 1699 1699 1700 1700 1699 1701 1700 1699 1699 1696 1693 1690 1687 1685 1687 1689 1691 1691 1691 1693 1693 1692 -9999 -9999 -9999
50 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1699 1698 1698 1698 1693 1693 1694 1693 1692 1692 1691 1689 1690 1693 1695 1697 1700 1701 1702 1702 1704 1702 1702 1703 1703 1701 1700 1699 1701 1702 1702 1705 1704 1702 1702 1700 1697 1695 1693 1691 1690 1690 1694 1694 1696 1696 1695 -9999 -9999 -9999 -9999 -9999
51 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1697 1698 1696 1695 1695 1695 1694 1694 1693 1693 1696 1698 1699 1701 1702 1705 1704 1704 1703 1704 1704 1702 1702 1702 1703 1704 1703 1706 1706 1705 1702 1703 1701 1698 1695 1694 1695 1696 1697 1697 1699 -9999 -9999 -9999 -9999 -9999 -9999 -9999
52 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1701 1697 1697 1696 1697 1697 1696 1696 1694 1695 1697 1699 1700 1703 1704 1705 1704 1706 1705 1706 1702 1703 1705 1705 1708 1707 1703 1708 1708 1706 1706 1705 1703 1701 1699 1699 1699 1698 1700 1700 1700 -9999 -9999 -9999 -9999 -9999 -9999 -9999
53 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1698 1698 1697 1698 1698 1700 1697 1698 1697 1699 1700 1702 1702 1705 1705 1706 1706 1706 1705 1706 1705 1707 1709 1706 1706 1708 1708 1709 1708 1706 1705 1705 1701 1700 1700 1701 1704 1702 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
54 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1698 1699 1701 1700 1699 1699 1700 1699 1699 1704 -9999 -9999 -9999 -9999 -9999 -9999 1706 1706 -9999 -9999 -9999 -9999 -9999 1709 1710 1710 1710 1710 1707 1708 1704 1704 1706 1704 1706 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
55 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1699 1700 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1709 1709 1707 1707 1708 1707 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
56 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1700 1701 1701 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1710 1710 1709 1708 1709 1708 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
57 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 1711 1711 1710 1710 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
58 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
59 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
60 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
61 | -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999 -9999
62 |
--------------------------------------------------------------------------------
/plotting/first_phase.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/landlab/tutorials/b98a8ab47249579b90298622853421dac5294f76/plotting/first_phase.mp4
--------------------------------------------------------------------------------
/plotting/second_phase.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/landlab/tutorials/b98a8ab47249579b90298622853421dac5294f76/plotting/second_phase.gif
--------------------------------------------------------------------------------
/reading_dem_into_landlab/synthetic_landscape.asc:
--------------------------------------------------------------------------------
1 | ncols 10
2 | nrows 10
3 | xllcorner 0
4 | yllcorner 0
5 | cellsize 5
6 | NODATA_value -9.
7 | 10 10 10 10 10 10 10 10 10 10
8 | 9 9 0.8 9 9 9 9 9 9 9
9 | 8 8 0.7 8 8 8 1.4 8 8 8
10 | 7 7 0.5 7 7 7 1.2 7 7 7
11 | 6 6 0.5 6 6 6 1 6 6 6
12 | 5 5 0.4 5 5 5 0.8 5 5 5
13 | 4 4 0.3 4 4 4 0.6 4 4 4
14 | 3 3 0.2 3 3 3 0.4 3 3 3
15 | 2 2 0.1 2 2 2 0.2 2 2 2
16 | 1 1 0 1 1 1 0 1 1 1
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | jupyter
2 | dask
3 | holoviews
4 | pytest
5 |
--------------------------------------------------------------------------------
/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 = ["animate-landlab-output.ipynb"]
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 |
--------------------------------------------------------------------------------
/tutorial_template.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "\n"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Using the Landlab flexure component\n",
15 | "\n",
16 | "\n",
17 | " For instructions on how to run an interactive iPython notebook, click here: https://github.com/landlab/tutorials/blob/release/README.md \n",
18 | "For more Landlab tutorials, click here: https://github.com/landlab/landlab/wiki/Tutorials\n",
19 | "\n",
20 | "\n",
21 | "In this tutorial we will:\n",
22 | "* do this\n",
23 | "* do that\n",
24 | "* do the other thing"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "A bit of magic so that we can plot within this notebook."
32 | ]
33 | },
34 | {
35 | "cell_type": "code",
36 | "execution_count": null,
37 | "metadata": {
38 | "collapsed": true
39 | },
40 | "outputs": [],
41 | "source": [
42 | "from __future__ import print_function\n",
43 | "%matplotlib inline"
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "## This\n",
51 | "\n",
52 | "Here we will do this."
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "## That\n",
60 | "\n",
61 | "Now we will do that."
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | "## The other thing\n",
69 | "\n",
70 | "Finally we will do the other thing."
71 | ]
72 | },
73 | {
74 | "cell_type": "markdown",
75 | "metadata": {},
76 | "source": [
77 | "### Click here for more Landlab tutorials"
78 | ]
79 | }
80 | ],
81 | "metadata": {
82 | "kernelspec": {
83 | "display_name": "Python 2",
84 | "language": "python",
85 | "name": "python2"
86 | },
87 | "language_info": {
88 | "codemirror_mode": {
89 | "name": "ipython",
90 | "version": 2
91 | },
92 | "file_extension": ".py",
93 | "mimetype": "text/x-python",
94 | "name": "python",
95 | "nbconvert_exporter": "python",
96 | "pygments_lexer": "ipython2",
97 | "version": "2.7.13"
98 | }
99 | },
100 | "nbformat": 4,
101 | "nbformat_minor": 1
102 | }
103 |
--------------------------------------------------------------------------------