landlab documentation - read the docs

129
landlab Documentation Release 0.1 Author September 13, 2015

Upload: others

Post on 15-Apr-2022

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: landlab Documentation - Read the Docs

landlab DocumentationRelease 0.1

Author

September 13, 2015

Page 2: landlab Documentation - Read the Docs
Page 3: landlab Documentation - Read the Docs

Contents

1 What is Landlab? 11.1 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Installing Landlab 32.1 Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 Installing Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.3 Installing Landlab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.4 Updating Landlab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 A Tutorial on Quickly Building 2D Models in Landlab 73.1 Building a Scarp Diffusion Model Without Components . . . . . . . . . . . . . . . . . . . . . . . . 73.2 Building a Model With Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4 A rough guide to Python on Linux 154.1 What you already have, apt-get, and versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154.2 Installing pip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164.3 Downloading the packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

5 Getting Example Code Files 19

6 User Guide 216.1 The Nuts and Bolts of Coding in Landlab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216.2 Landlab’s Gridding Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236.3 Building a Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346.4 Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426.5 Simple guides to functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436.6 CellLab-CTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

7 Frequently Asked Questions 1137.1 How do I set the boundary codes for the edges of a grid? . . . . . . . . . . . . . . . . . . . . . . . . 1137.2 Can I import Landlab output into ParaView or VisIt? . . . . . . . . . . . . . . . . . . . . . . . . . . 1137.3 How do I get netCDF output? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1137.4 How do I assign values from nodes to links? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1147.5 Why are there no other FAQs besides these few? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

8 Developer Documentation 1158.1 Installing Landlab for Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1158.2 Landlab Component Developer Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

i

Page 4: landlab Documentation - Read the Docs

9 References 121

ii

Page 5: landlab Documentation - Read the Docs

CHAPTER 1

What is Landlab?

(originally authored by Greg Tucker, December 2013)

Landlab is a Python software package that supports numerical modeling in earth science, and especially those fieldsthat deal with earth-surface dynamics, including geomorphology, hydrology, glaciology, stratigraphy, and related ar-eas. Landlab is a modeling environment in which scientist can build a numerical landscape model without havingto code all of the individual parts. Landscape models compute flows of mass, such as water, sediment, glacial ice,volcanic material, or landslide debris, across a gridded terrain surface. Landscape models have a number of com-monalities, such as operating on a grid of points and routing material across the grid. Scientists who want to use alandscape model often build their own unique model from the ground up, re-coding the basic building blocks of theirlandscape model rather than taking advantage of codes that have already been written.

Landlab provides four main resources and capabilities:

1. A library of code resources for building two-dimensional numerical models from scratch. The Landlab libraryincludes a powerful “gridding engine” for creating, managing, and iteratively updating data on structured or

1

Page 6: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

unstructured grids. The library also includes support for input and output, including input of digital elevationmodels (DEMs) in ArcInfo ASCII format, handling of parameter inputs using formatted text files, and netCDF-format input and output.

2. A set of pre-built components, each of which implements a numerical representation of a particular process.

3. A framework for building models by assembling and linking process components.

4. A library of models that have already been created from component(s).

An example of some models that can easily be built with Landlabs current capabilities are:

• A landscape evolution model using linear diffusion and the stream-power model

• A model that explores the flexural response to the growth and recession of glaciers

• An ecohydrology model in which vegetation on two sides of a valley grows and dies in response to stochasticstorms and solar forcing throughout the year

• A model that routes hydrographs across a watershed based on rainfall inputs

1.1 Acknowledgements

The Landlab Team:

• Greg Tucker (University of Colorado)

• Nicole Gasparini (Tulane University)

• Erkan Istanbulluoglu (University of Washington)

• Daniel Hobley (CU)

• Sai Nudurupati (UW)

• Jordan Adams (TU)

• Eric Hutton (CU)

Initial funding was provided by a grant from the National Science Foundation to Greg Tucker (ACI 1147454), ErkanIstanbulluoglu (ACI 1148305), and Nicole Gasparini (ACI 1147519).

2 Chapter 1. What is Landlab?

Page 7: landlab Documentation - Read the Docs

CHAPTER 2

Installing Landlab

2.1 Dependencies

Landlab has the following dependencies:

• Python 2.7

• Numpy 1.8 or greater

• Scipy 0.12 or greater

• netCDF4 (will run without, but recommended)

• Cython (only required if building Landlab from source code)

If you don’t already have these packages installed on your computer, simply install one of the preassembled scientificPython collections described below under Installing Python.

Note: Although not supported, Landlab can be used with Python 3.X by simply running 2to3 on the source.

2.2 Installing Python

Note: If you have used a decent amount of scientific software on your machine before, it is likely that some of thissoftware will have already installed some “pieces” of Python onto your system. Nevertheless, we strongly recommendthat if you haven’t before, you download a whole Python distribution, as this will ensure that all of the Python modulesthat Landlab needs to run are definitely present. Most of the bug reports we get about problems installing Landlab relateto conflicts with old versions of Python on machines. Common symptoms are running the python setup commands atthe end of this file, but then not being able to load landlab. If you suspect this might be happening to you after you’veinstalled one of the distributions described below, click here.

On all platforms (Linux, Windows 7 or greater, and MacOS X), we recommend a preassembled scientific pythondistribution. In all ases, we recommend Continuum IO’s Anaconda, as its conda package manager makes controllingyour Python packages easier. (It is also possible to use Enthought’s Canopy, but be aware you will need to sign upfor an academic license with Enthought to take full advantage of its features.) Download and follow the appropriateinstructions for your operating system/distribution. These collections already include compatible (and in some casesaccelerated) versions of all of landlab’s dependencies. When the distribution asks if you want to set it as the defaultPython for your system, say yes. Note that both Canopy and Anaconda also provide a front-end, or GUI environment,from which you can work, making coding, running code, and debugging relatively easy.

3

Page 8: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

On Linux systems, you can also install Python and the Landlab dependencies from your package manager. If you’rerunning Linux but aren’t that familiar with handling Python packages in it, this might help.

(Landlab uses setuptools for packaging and is configured to automatically download and install the most up-to-dateversion of its dependencies from PyPI, if a satisfactory version is not already installed.)

Once you have a full Python distribution on your machine, it is vital to check that it has been successfully set as thedefault copy of Python on your system. Open a command prompt (Terminal on a Mac, or Command Prompt on a PC)and type the lines below (note the > indicates that you are on a command line):

> which python> which ipython

In each case, path should be the same (except the (i)python at the end), and it should clearly refer to Anaconda (orCanopy). Details will depend on your operating system. For instance, Dan’s Macbook Pro gives:

/anaconda/bin/python

If you don’t see reference to your newly installed distribution, click here to resolve the problem.

2.3 Installing Landlab

Note: If you already have a Landlab install on your machine, see updating landlab, below.

Note: If you already had a Python distribution on your machine, but it’s a bit old, remember to update both the dis-tribution itself and its internal packages before attempting a Landlab install, to make sure the necessary dependenciesare up to date. Do this from the command prompt for Anaconda, using: conda update –all (two dashes), then alsoconda update setuptools (or through the GUI in Canopy). Also update or install netCDF4 through conda if you needto.

Here we describe how to install the latest release package of Landlab. Note that this method of installation hides thecode behind Landlab. If you are an experienced Landlab user and want to actually edit existing Landlab code and addto the Landlab repository, please follow the developers’ installation instructions here.

We here assume that you have read the previous section and you have now installed a Python front-end on yourcomputer (which should have also installed a Python distribution) and that your default Python path is set correctly(more on Python path here).

The instructions below describe the installation of Landlab with Anaconda. If, however, you want a bit more adviceon beating your Linux system into shape with regards to running Python and getting Landlab, you can follow this link.

2.3.1 Quick Landlab Install Instructions (For Experienced Python Users)

If you are new to Python, you probably should see instructions here for Anaconda users. Otherwise, if you don’t likedetails, continue!

• Make sure your Python distribution is up to date, especially setuptools.

• Open a terminal (or the command prompt) and type the following:

> pip install --upgrade pip> pip install landlab

4 Chapter 2. Installing Landlab

Page 9: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

2.3.2 Installing Landlab Using using Anaconda - Recommended Method

This should work for Anaconda users with Windows 7+, Mac OS 10.6+, or Ubuntu Linux (only the latest version hasbeen tested).

• Open the Python editor in Anaconda called Spyder.

• On the Spyder toolbar, go to Tools → Open command prompt to open the command line. Alternatively you canopen a standard terminal window, such as an xterm (X11.app) or terminal window (Terminal.app) on a Mac, ora command prompt on a Windows machine. If you do use a standard terminal and run into problems, make sureyou have resolved your path issues).

• To ensure that your version of pip (a package installer) is up-to-date, enter the following command:

> pip install --upgrade pip

• Next, make sure the necessary dependencies are up-to-date. The following conda command will update allAnaconda packages (Note the conda command below handles Anaconda-supported package installation andupdates):

> conda update --all

• Installing also requires a fully up-to-date version of setuptools, which (irritatingly) is not updated by the –allcall above. So also run:

> conda update setuptools

• Once the Anaconda packages are updated and the correct version of pip is installed, now install netCDF4:

> conda install netCDF4

• Now to install Landlab! Enter the following command:

> pip install landlab

• Once Landlab has been successfully installed, on the Python shell line, check to make sure it is up-to-date (notethat those are double underscores around version; also note that you may need to close and reopen Anacondabefore typing the below commands):

>>> import landlab>>> landlab.__version__

The version number is changing rapidly at this point, but it should be something higher than 0.1.18. If you are havingproblems with Landlab, check with the Landlab development team to make sure you have the latest version.

2.3.3 Developer Installation - Installing from Landlab Source Code

This is recommended only for users who have gotten a feel for Landlab and want to keep up with the absolute latestLandlab developments and contribute codes back to the Landlab repository. If this is not you, please follow thestandard installation instructions above. Otherwise, if you are ready to become a Landlab developer, follow thesedirections.

2.4 Updating Landlab

As Landlab is still relatively early in its development cycle, the code will update fairly often and new release versionswill become available. To take advantage of new features and new library additions, we recommend you updateLandlab fairly frequently.

2.4. Updating Landlab 5

Page 10: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Note: Whenever you update Landlab, we strongly recommend you also update your Python package! For Anaconda,use the conda package manager from a command prompt:

> conda update –all #(two dashes)

(From Canopy, use the GUI to update all the available new packages listed.)

If you installed Landlab through the instructions on this page, this is trivial. Simply use pip again to update, like so:

> pip install landlab --upgrade

However, if you have ever used another method to install Landlab on your machine, this might not be adequate (i.e.,pip will give you error messages). The first thing to do in such a case is to try a full uninstall and reinstall:

> pip uninstall landlab> pip install landlab

Still having problems? This probably means that some time early in our development cycle you installed Landlab withone of our old procedures. The clue will be that you still have a (very out of date!) copy of the Landlab code basesomewhere on your machine. Another possibility is that you’ve previously tried a developer install. This procedurewill also work in this case.

Try this:

In a terminal, navigate to the top level directory of that old code, the one that contains the file setup.py. This is likelyto be your_home_dir/landlab, if you installed with git and left all the defaults as is. Then:

> pip uninstall landlab #just to be on the safe side, may get errors again> python setup.py develop -u

This should remove the install, if you installed as a developer.

Still getting error messages? This means we’re going to have to excise the old Landlab install “by hand”. You’relooking to remove any reference to Landlab that lives inside your_python_install/lib/python2.7/site-packages. Do thisonly after you’ve exhausted other possibilities, above, as packages like pip will get annoyed with you if you startmanually deleting their files if they installed them in the first place. To minimize the risk, onc again make sure youhave just run:

> pip uninstall landlab

Then find your Python directory with:

> which python

Find that folder, ignoring everything after and including the subfolder bin. Instead, go toyour_install/lib/python2.7/site-packages. In here, you should find one (or more) folders referrring to landlab,e.g., landlab or landlab.egg-link, or some other reference to landlab.egg. Delete these. Leave everything else as it is!

Now try another pip install:

> pip install landlab

This should now take. Still having problems? This is probably multiple versions of Python on your machine interferingwith each other. Solve that problem first, then return to trying to install Landlab. See here for some help.

6 Chapter 2. Installing Landlab

Page 11: landlab Documentation - Read the Docs

CHAPTER 3

A Tutorial on Quickly Building 2D Models in Landlab

Computer models can be tremendously useful in exploring and visualizing the consequences of scientific hypotheses,and comparing these predictions with data. New ideas and discoveries require new models. In an ideal world, thenecessary programming, testing, and debugging would be trivial, leaving us free to focus on the core science. Inpractice, however, high-quality scientific programming takes time. Landlab was written to make the process of writingmodels more efficient, by providing pre-built software that handles many of the common tasks, and by providingpre-built process components that save you from having to re-invent the wheel.

The following tutorial examples give a flavor for what this means. The tutorial examples here can betyped directly on the command line of any Python interpreter, or you can download all example codes fromhttps://github.com/landlab/drivers/archive/master.zip and find the codes and input file used here in the scripts/diffusionfolder. To try them out, you’ll need (1) an installation of Python 2.x, (2) the Numpy, Scipy, and Pylab modules, and(3) Landlab. If you don’t already have Numpy and its relatives installed, we recommend Anaconda Spyder or En-thought Canopy (which provide a command-line interpreter, development environment, and the Numpy, Scipy, andPylab modules all in one convenient package). To install Landlab, see Installing Landlab.

3.1 Building a Scarp Diffusion Model Without Components

In the first example, we will build a 2D model of the erosional degradation of a fault scarp through the process of lineardiffusion. Conveniently Landlab already has a component that will calculate erosion rates due to linear diffusion, but inthis example we do not take advantage of Landlab’s pre-built diffusion component. After building this model withouta component, we then contrast what the model would look like when using the pre-built component (see Building aModel With Components).

If you have downloaded the example codes, the code below is contained in scarp_diffusion_no_component.py.

Note that >>> implies that we are on the command line in your favorite python frontend. We start by importing Numpyand Landlab’s RasterModelGrid class:

>>> import numpy>>> from landlab import RasterModelGrid

We also need to import functions for plotting:

>>> from landlab.plot.imshow import imshow_node_grid>>> from pylab import show, figure

Next, we create a new raster grid with 40 columns, 25 rows, and a cell spacing of 10 m:

>>> mg = RasterModelGrid(25, 40, 10.0)

7

Page 12: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

This line creates a grid object, mg. For this application, we want values of elevation, z, tied to each grid node. We cancreate such an array by calling the grid’s add_zeros method:

>>> z = mg.add_zeros('node', 'elevation')

add_zeros is one of many methods that belong to the grid object. As those familiar with object-oriented program-ming will recognize, a method is a function (a.k.a., subroutine) that is attached to a particular class, in this case theRasterModelGrid class. Here, the add_zeros method creates and returns a Numpy array of floating-pointnumbers whose length is equal to the number of nodes in the grid. We can test this by finding the length of the array:

>>> len(z)1000

As the name suggests, the value of each element in the array is initially zero. Let’s create a fault scarp runningdiagonally across the domain by uplifting some of the grid nodes. To do this, we’ll first create an array to representthe y-coordinate of the fault trace:

>>> fault_y = 50.0 + 0.25*mg.node_x

Here node_x is a Numpy array containing the x-coordinate of each node.

Now, we uplift the portion of the domain where y > fault_y. We’ll have this co-seismic uplift increase somewhatto the right:

>>> upthrown_nodes = numpy.where(mg.node_y>fault_y)>>> z[upthrown_nodes] += 10.0 + 0.01*mg.node_x[upthrown_nodes]

The Numpy where function finds and returns the array indices where the condition mg.node_y > fault_y istrue; the resulting array upthrown_nodes contains the indices of the nodes whose elevation we want to raise. Wethen raise these elevations on the next line. Let’s see what this looks like:

>>> imshow_node_grid(mg, z, cmap='jet', grid_units=['m','m'])>>> show()

imshow_node_grid() is part of the plotting functions that come Landlab. We are sending imshow_node_grid themodel grid and the values we want to plot, in this case z. We are specifying the colormap to be jet (red to blue) andthat the units on the x and y axes are in meters. show() makes the plot pop-up on your screen.

The result looks like this:

8 Chapter 3. A Tutorial on Quickly Building 2D Models in Landlab

Page 13: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Now we’ll apply a diffusion model to calculate the degradation of the fault scarp. Start by defining a diffusioncoefficient, kd, and a time-step size:

>>> kd = 0.01 # 0.01 m2 per year>>> dt = 0.2*mg.dx*mg.dx/kd # CFL condition>>> dt2000.0

For boundary conditions, we’ll have fixed elevation values along the top and bottom sides, while the right andleft sides will be no-flux boundaries. By default, all the grid edges are open boundary nodes, meaning that theyare treated as fixed-elevation boundaries. To turn the right and left sides into no-flux boundaries, we use theset_closed_boundaries_at_grid_edges method:

>>> mg.set_closed_boundaries_at_grid_edges(False, True, False, True)

This method allows you to specify whether each of the four grid edges—counter-clockwise from the bottom—shouldbe closed, meaning that it is in effect a no-flux boundary.

We’ll also need the ID numbers of those nodes that lie in the core of the grid, because these are the ones whoseelevations we will want to iteratively update:

>>> interior_nodes = mg.get_core_nodes()

This returns an array containing the ID numbers of all the core nodes (of which there are (25-2) x (40-2) = 874).

3.1. Building a Scarp Diffusion Model Without Components 9

Page 14: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Next, we’ll run 50,000 years (25 time steps) of scarp degradation. Here is our loop:

>>> for i in range(25):... g = mg.calculate_gradients_at_active_links(z)... qs = -kd*g... dqsdx = mg.calculate_flux_divergence_at_nodes(qs)... dzdt = -dqsdx... z[interior_nodes] += dzdt[interior_nodes]*dt

Our algorithm starts by calculating gradients at each of the active links, which are those that either connect two corenodes, or connect a core node with an open boundary node (top and bottom edges in this example). We then calculatethe sediment fluxes associated with these links by using the transport law 𝑞𝑠 = −𝑘𝑑∇𝑧, where ∇𝑧 is the link gradientand 𝑞𝑠 is the flux per unit width along the link. Note that each link has a direction: it connects a from node to a tonode. The sediment flux is positive when it runs in the same direction as the link, and negative otherwise.

The next step is to add up the net sediment fluxes entering and leaving each cell in the grid. This is handled by acall to the grid’s calculate_flux_divergence_at_nodes method. The result is the net volumetric sedimentoutflux per unit area for each node, which is our ∇𝑞𝑠. The conservation of mass law says

𝜕𝑧

𝜕𝑡= −∇𝑞𝑠

We do this operation on the next line. Finally, on the last line of the loop we calculate elevation changes (by multiplyingdzdt by time-step size) and update the elevations of the interior nodes.

The following commands open a new figure window and show an image of the terrain after 50,000 years of hillslopediffusion:

>>> figure('elev_50ka')>>> imshow_node_grid(mg, z, cmap='jet', grid_units=['m','m'])>>> show()

Here is the resulting image:

10 Chapter 3. A Tutorial on Quickly Building 2D Models in Landlab

Page 15: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

3.2 Building a Model With Components

We now build the same exact model but we take advantage of Landlab’s pre-built linear diffusion component. If youhave downloaded the zip file of all code examples (https://github.com/landlab/drivers/archive/master.zip) you can findthis code in scripts/diffusion/scarp_diffusion_with_component.py. The input file, diffusion_input_file.txt is in the samefolder.

Below is the entire code for the model which uses the pre-built linear diffusion component.

#Import statements so that you will have access to the necessary functionsimport numpyfrom landlab import RasterModelGridfrom landlab.components.diffusion.diffusion import LinearDiffuserfrom landlab.plot.imshow import imshow_node_gridfrom pylab import show, figure

#Create a raster grid with 25 rows, 40 columns, and cell spacing of 10 mmg = RasterModelGrid(25, 40, 10.0)

#Create a field of node data (an array) on the grid called elevation.#Initially populate this array with zero values.

3.2. Building a Model With Components 11

Page 16: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

z = mg.add_zeros('node', 'topographic__elevation')

#Check the size of the arraylen(z)

#Create a diagonal fault across the gridfault_y = 50.0 + 0.25*mg.node_xupthrown_nodes = numpy.where(mg.node_y>fault_y)z[upthrown_nodes] += 10.0 + 0.01*mg.node_x[upthrown_nodes]

#Illustrate the gridimshow_node_grid(mg, 'topographic__elevation', cmap='jet', grid_units=['m','m'])show()

#Instantiate the diffusion component:linear_diffuse = LinearDiffuser(grid=mg, input_stream='./diffusion_input_file.txt')

#Set boundary conditionsmg.set_closed_boundaries_at_grid_edges(False, True, False, True)

#set a model timestep#(the component will subdivide this as needed to keep things stable)dt = 2000.

#Evolve landscapefor i in range(25):

linear_diffuse.diffuse(dt)

#Plot new landscapefigure()imshow_node_grid(mg, 'topographic__elevation', cmap='jet', grid_units=['m','m'])show()

Let’s go through the model with a component and compare it to the non-component version presented in the previoussection.

The import statements are nearly the same, except that the model using a component has to import theLinearDiffuser class. In Landlab components are built as classes, which among other things, means that theycan have both their own data and methods (methods are functions that are part of a class). The statement that importsthe LinearDiffuser is repeated below:

>>> from landlab.components.diffusion.diffusion import LinearDiffuser

In this case the LinearDiffuser class is contained in a file called diffusion.py that is in thelandlab/components/diffusion directory.

The code to create the raster grid (mg, an object of type RasterModelGrid), the elevation array z (or elevation fieldon mg), and the scarp across the landscape are all the same between the two different models. Similarly, the plottingis the same between the two models.

Because the model is using the LinearDiffuser class, the code must instantiate a member of the class, ormake an object of type LinearDiffuser. That step is repeated below, where linear_diffuse is an object of typeLinearDiffuser.

>>> linear_diffuse = LinearDiffuser(grid=mg, input_stream='./diffusion_input_file.txt')

Note that in order to initialize an object of type LinearDiffuser, a grid object must be passed, as well as an inputfile. If you downloaded the example codes, you should also have a copy of diffusion_input_file.txt. Hereis what it contains:

12 Chapter 3. A Tutorial on Quickly Building 2D Models in Landlab

Page 17: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

linear_diffusivity: in m2 per year0.01

In this case linear_diffusivity, is a target phrases (targets for short, and there can be no spaces in a target) that Landlabis looking for in the input file when intializing an object of type LinearDiffuser. The Landlab code will readthrough the input file and look for each required target. Once that target is found, it ignores the text on the rest of theline (so anything following the target on the same line is a comment), and takes the value for the parameter associatedwith the target from the next line of text.

Note that in the model without a component, we calculated a stable dt in the model. With the component, the testingof timestep stability happens automatically, and the component will internally subdivide the timestep as necessary.Finally, the diffusion model takes the name of the grid node field that it will be diffusing. In this case, we have alreadyadded the field topographic__elevation to the code and we would like to diffuse elevation values. The componentlooks for a field called topographic__elevation by default, and this is why we chose this field name (though equally,we could have chosen a different field name and overridden the default in the component). You can imagine that onemight use the diffusion code in a very different way, say to calculate heat transfer, and in that case we could havedeclared a different field name using the ‘values_to_diffuse’ target phrase. Setting the boundary conditions is the samebetween the two models.

The evolution loop in the model with the component is much shorter than the loop in the model without the component.In this case all that is needed is to call the diffuse method of the LinearDiffuser class:

>>> linear_diffuse.diffuse(dt)

The diffuse method essentially does everything that was typed out explicitly in the example without a component.Note that because the elevation data are a field on the grid, those data do not need to be passed to the method.

Plotting the final landscape is the same between the two models and the result should be exactly the same between thetwo example models.

3.2. Building a Model With Components 13

Page 18: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

14 Chapter 3. A Tutorial on Quickly Building 2D Models in Landlab

Page 19: landlab Documentation - Read the Docs

CHAPTER 4

A rough guide to Python on Linux

Handling Python installs on Linux if you are non-expert can be a confusing and frustrating experience. However, oneof us (DEJH) has recently gone through the pain, and offers these thoughts on how to get a Python install capable ofrunning Landlab onto your machine. (As long as your machine is Debian...)

NB: A version of Canopy does exist for linux, but DEJH couldn’t get this to install properly. If you can, this is probablythe easier way to go!

4.1 What you already have, apt-get, and versioning

Your unix box almost certainly already has a version on Python on it. However, DEJH found it wasn’t the rightversion in his case. The problem is that the stable Python (and Python package) versions that are maintained throughthe Debian package repository that apt-get looks at tend not to be up to date. This is problematic, as Landlab needs atleast Python 2.7, Numpy 1.8, and Scipy 0.12. So first, check your version:

$ python –version

Note the two dashes. If you got 2.7 or higher, congratulations! You win. No further changes to python installs areneeded. But if you didn’t, first check whether you can simply update through the package manager:

$ sudo apt-get install -u python

$ python –version

If you’re still seeing a sub-2.7 version number (as I was...), you’re going to need to download the python sourceand install it manually. Go to the python download site, select the link to the highest version number of Python 2.Xavailable (2.7.6 at time of writing), and download it as a gzipped source tarball. Then:

$ tar -xzf the_downloaded_file.tgz

$ cd the_new_directory

$ ./configure

$ make

$ sudo make install

You should now have Python 2.7! Close the terminal, reopen, and check:

$ python2.7

BUT, it’s highly likely if you just run “python”, you won’t get this version. Check by

$ python –version

15

Page 20: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

again. You can resolve this by messing with your ~/.bashrc profile. Open that file in your favourite text editor, and addat the end:

alias python=”python2.7”

Restart the terminal again, and check the version number now. Should be right! (You will probably also want to dosomething similar with ipython, but DEJH didn’t explore that...)

4.2 Installing pip

You now have the right version of python, but if you try, e.g., import numpy, you’ll notice you don’t have any packages.This is where pip - the powerful command line Python package manager - comes in.

Get pip by going to the pip site and downloading get_pip.py, which links from that page. Navigate to the folder youdownloaded it into, and simply run

$ sudo python get_pip.py

This should give you a trouble free install of pip.

Once you have it, make sure you’re fully up-to-date:

$ pip install –upgrade pip

NB: DO NOT TRY TO INSTALL PIP WITH APT-GET. Pip binds to your Python install, and the binding probablywon’t take properly unless you install through your version of Python, as described here. Note that there is a copy ofpip you can get with apt-get, but you don’t want it.

4.3 Downloading the packages

Now you have pip and it’s bound correctly to your Python install, adding packages should be trouble free:

$ sudo pip install numpy

$ sudo pip install scipy

$ sudo pip install matplotlib

$ sudo pip install sympy

$ sudo pip install netCDF4

Note in future, you can update these packages to new versions by:

$ sudo pip install –upgrade [package_name]

Now test the versions like this:

$ python

>>> import numpy

>>> numpy.__version__

And everything should now be great. You can now continue to install Landlab as you would in the main instructions.e.g., if you have a clone or downloaded copy of Landlab you want to install in developer mode, just navigate to thedownload’s top level directory and run

$ python setup.py develop

and test:

16 Chapter 4. A rough guide to Python on Linux

Page 21: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

$ python

>>> import landlab>>> landlab.test()

Or alternatively, just grab the release version using pip, as in the main instructions:

$ pip install landlab

& again, test as above.

4.3. Downloading the packages 17

Page 22: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

18 Chapter 4. A rough guide to Python on Linux

Page 23: landlab Documentation - Read the Docs

CHAPTER 5

Getting Example Code Files

Depending on how you installed Landlab, you may not have access to any of the actual Landlab files, even though youcan run the code. All example models that are illustrated in this Landlab documentation are available for download inone zip file at https://github.com/landlab/drivers/archive/master.zip.

You can also get our example files by forking and cloning the Github repository to your machine (if you’re comfortablewith it). The files are at landlab/drivers.

19

Page 24: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

20 Chapter 5. Getting Example Code Files

Page 25: landlab Documentation - Read the Docs

CHAPTER 6

User Guide

6.1 The Nuts and Bolts of Coding in Landlab

6.1.1 Why Python?

Landlab is coded in Python and exploits and includes as dependencies a number of widely used scientific Pythonpackages - in particular, numpy and scipy. The decision to code in Python was explicitly made to lower the bar toentry for Landlab; to increase the flexibility and reusability of the code base; and to increase development speed bothfor the core development team and for future users. The choice of Python also means that developers using Landlabcan take advantage of that language’s affinity for rapid development timescales.

Other advantages of this choice include high portability between platforms, open source language, numerous existingscientific libraries that prevent developers having to “reinvent the wheel”, and support for selective optimization oftime-critical parts of the code base in Cython (see Cython).

6.1.2 Dependencies

To run Landlab, you will need Python and several of its packages on your machine. These will also need to be at leastcertain versions to run. These dependencies are:

• Python 2.7

• Numpy 1.8 or greater

• Scipy 0.12 or greater

We recommend installing a Python distribution like the Enthought Python Distribution or Anaconda; these also havethe advantage of providing you with an interactive development environment (IDE) in which to view and edit the code.However, as long as you meet the dependency requirements above, several other options will work. Find out moreabout installing Python here: Installing Landlab.

6.1.3 Getting to know Python

We recommend you approach Landlab with a basic working knowledge of the Python coding language. A good,concise, complete beginner’s guide that will get you to enough knowledge to be able to get started can be found here.We like the Software Carpentry intro and these Python notebooks as more comprehensive introductions to Python.

If you’re already familiar with Matlab, you will probably feel fairly at home with Python fairly quickly. However,there are some critical differences. Important things to remember are: Python’s indexing is inclusive at the start andexclusive at the end (in contrast to Matlab). e.g.,

21

Page 26: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> numpy.arange(0,100)

will give an array of 100 numbers, starting at 0 and ending at 99.

Python doesn’t use parentheses or brackets to delimit code blocks (functions, loops, if statements, etc). Instead it usesa colon to declare the start of a code block, then spaced indenting (normally 4 spaces) to demark which lines of codebelong in the block. e.g.,

>>> def myfunction(input_param):... if type(input_param) == str:... print “The input to the function said: “, input_param... else:... print “The input parameter wasn’t a string.”... print “It was “, input param

Lines don’t need to end with the semicolon to suppress output; Python won’t print output unless you explicitly callprint.

Finally, but importantly, Python doesn’t use the hat (.^) as its raise-to-the-power symbol. Instead, it uses a doublestar (**). Simple, but typically very frustrating for a day or two during transition! There’s also the numpy method,np.square, which if you’re using arrays typically outperforms the ** operator.

We have a very short tutorial on Python and numpy from the point of view of Landab (and the key differences withMatlab) here.

Landlab is also written in an object-oriented coding style. Many of the elements of Landlab that you will interact with- grids, components, utilities - are Python objects, which means they contain both data that describe the object andfunctions that you can call that operate on the object. Think of the object as a container in which is stored everythingrelevant to that part of the code, so it can be accessed easily. You can read a bit more about Python objects here forgeneral information. We give more detail on what this means in terms of running our code later in this guide.

6.1.4 Numpy and Scipy, and Efficient Coding Style

Numpy and scipy are the workhorse scientific computing packages of Python. They provide fast, efficient, and surpris-ingly comprehensive data structures and numerical methods that we (and you) can exploit to make coding in Landlabfaster and easier.

In particular, Landlab makes extensive use of the numpy array data structure. Almost all data input and output fromLandlab is in this form (see Landlab Fields for more information). These arrays allow operations to happen muchfaster on the data than would be possible in a pure Python data structure like a list or dictionary. (This is possiblebecause arrays partially suppress some of Python’s inbuilt type checking and memory management, and impose amore ordered structure on the way raw data is held in your computer’s memory).

However, in order to exploit the speed gains that numpy can give you, you’ll need to adopt a coding style quite differentto what would be natural in, say, C++ (or likely, Matlab). A typical bottleneck in Python code occurs when loopingover data, and numpy arrays typically let you avoid doing this. So if you find yourself about to write something likethis:

>>> for i in range(len(myarray)):myoutputarray[i] = myoutputarray[i] + myarray[i]

Don’t! Try to develop a coding style where each line operates on the whole array at once, like:

>>> myoutputarray += myarray

In particular, it can be very tempting to use loops to apply a condition over a whole array. Try not to do this! e.g.,

22 Chapter 6. User Guide

Page 27: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> for i in myarray:if i < 0:

i=0

This will be really slow. Do this instead:

>>> myarray[myarray<0] = 0

You can read a lot more about writing efficient code using numpy on a large number of websites. For example, UW’sastronomy department has a great online intro. We also strongly recommend the book “High Performance Python” byGorelick and Ozsvald, published by O’Reilly, if you’re looking for a more comprehensive treatment.

6.1.5 Cython

If you go poking around in the Landlab source code code, you will discover that not all of Landlab is written inpure Python. Some of it is written in Cython. Cython is a very closely related programming language to Python,and indeed, all code written in pure Python is automatically also Cython code. Cython is probably best thoughtof as a cross between C++ and Python, which aims to combine the flexibility of Python with the brute power andgranular control over your code that C++ provides. e.g., if there are sections of code where looping through an arrayis unavoidable, Cython provides a way of significantly accelerating the speed of this code. Cython code largely lookslike straightforward Python, but may have type declarations or other C++-like features within it.

From the user’s perspective, the most important thing to note is that Cython is a compiled language. (This isn’t true ofPython, which is an interpreted - i.e., compiled at run time - language.) We provide the pre-compiled executables youwill need to run Landlab when you install, and this should be sufficient for the vast majority of users.

However, note that if as a developer you intend to modify any of the sections of code that we provide to you, you willprobably need to recompile that code on your machine before the changes take effect. See the development guide forlots more information on this.

6.2 Landlab’s Gridding Library

6.2.1 Introduction to Landlab’s Gridding Library

When creating a two-dimensional simulation model, often the most time-consuming and error-prone task involveswriting the code to set up the underlying grid. Irregular (or “unstructured”) grids are especially tricky to implement.Landlab’s ModelGrid package makes this process much easier, by providing a set of library routines for creatingand managing a 2D grid, attaching data to the grid, performing common input and output operations, and providinglibrary functions that handle common numerical operations such as calculating a field of gradients for a particular statevariable. By taking care of much of the overhead involved in writing grid-management code, ModelGrid is designedto help you build 2D models quickly and efficiently, freeing you to concentration on the science behind the code.

Some of the things you can do with ModelGrid include:

• Create and configure a structured or unstructured grid in a one or a few lines of code

• Create various data arrays attached to the grid

• Easily implement staggered-grid finite-difference / finite-volume schemes

• Calculate gradients in state variables in a single line

• Calculate net fluxes in/out of grid cells in a single line

• Set up and run “link-based” cellular automaton models

• Switch between structured and unstructured grids without needing to change the rest of the code

6.2. Landlab’s Gridding Library 23

Page 28: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

• Develop complete, 2D numerical finite-volume or finite-difference models much more quickly and efficientlythan would be possible using straight C, Fortran, Matlab, or Python code

Some of the Landlab capabilities that work with ModelGrid to enable easy numerical modeling include:

• Easily read in model parameters from a formatted text file

• Write grid and data output to netCDF files for import into open-source visualization packages such as ParaViewand VisIt

• Create grids from ArcGIS-formatted ascii files

• Create models by coupling together your own and/or pre-built process components

• Use models built by others from process components

This document provides a basic introduction to building applications using ModelGrid. It covers: (1) how grids arerepresented, and (2) a set of tutorial examples that illustrate how to build models using simple scripts.

6.2.2 How a Grid is Represented

Basic Grid Elements

Fig. 6.1: Figure 1: Elements of a model grid. The main grid elements are nodes, links, cells, and faces. Lesscommonly used elements include corners, patches, and junctions. In the spring 2015 version of Landlab, ModelGridcan implement raster (a) and Voronoi-Delaunay (b) grids. Ordered subtypes of Voronoi-Delaunay grids - radial andhexagonal - are also available. (Note that not all links and atches are shown, and only one representative cell is shaded.)

24 Chapter 6. User Guide

Page 29: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Figure 1 illustrates how ModelGrid represents a simulation grid. The grid contains a set of (x,y) points called nodes.In a typical finite-difference or finite-volume model, nodes are the locations at which one tracks scalar state variables,such as water depth, land elevation, sea-surface elevation, or temperature.

Each adjacent pair of nodes is connected by a line segment known as a link. A link has both a position in space, denotedby the coordinates of the two bounding nodes, and a direction: a link runs from one node (known as its from-node ortail-node) to another (its to-node or head-node).

Every node in the grid interior is associated with a polygon known as a cell (illustrated, for example, by the shadedsquare region in Figure 1a). Each cell is bounded by a set of line segments known as faces, which it shares with itsneighboring cells.

In the simple case of a regular (raster) grid, the cells are square, the nodes are the center points of the cells (Figure1a), and the links and faces have identical length (equal to the node spacing). In a Voronoi-Delaunay grid, the cells areVoronoi polygons (also known as Theissen polygons) (Figure 1b). In this case, each cell represents the surface areathat is closer to its own node than to any other node in the grid. The faces then represent locations that are equidistantbetween two neighboring nodes. Other grid configurations are possible as well. The spring 2015 version of Landlabincludes support for hexagonal and radial grids, which are specialized versions of the Voronoi-Delaunay grid shown inFigure 1b. Note that the node-link-cell-face topology is general enough to represent other types of grid; for example,one could use ModelGrid’s data structures to implement a quad-tree grid, or a Delaunay-Voronoi grid in which cellsare triangular elements with nodes at their circumcenters.

Creating a grid is easy. The first step is to import Landlab’s RasterModelGrid class (this assumes you haveinstalled landlab and are working in your favorite Python environment):

>>> from landlab import RasterModelGrid

Now, create a regular (raster) grid with 10 rows and 40 columns, with a node spacing (dx) of 5:

>>> mg = RasterModelGrid(10, 40, 5.)

mg is a grid object. This grid has 400 ( 10*40 ) nodes. It has 2,330 ( 40*(30-1) + 30*(40-1) ) links.

Adding Data to a Landlab Grid Element using Fields

Landlab has a data structure called fields that will store data associated with different types of grid elements. Fieldsare convenient because 1) fields create data arrays of the proper length for the associated data type and 2) fields attachthese data to the grid, so that any piece of code that has access to the grid also has access to the data stored in fields.Suppose you would like like to track the elevation at each node. The following code creates a data field (array) calledelevation and the number of elements in the array is the number of nodes:

>>> z = mg.add_zeros('node', 'elevation')

Here z is an array of zeros. You can that z has the same length as the number of nodes:

>>> z.size #or len(z)400

Note that z is a reference to the data stored in the model field. This means that if you change z, you also change thedata in the ModelGrid’s elevation field. You can also change values directly in the ModelGrid’s elevation field:

>>> mg.at_node['elevation'][5] = 1000.

or the alternative notation:

>>> mg['node']['elevation'][5]1000.

6.2. Landlab’s Gridding Library 25

Page 30: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Now the sixth element in the model’s elevation field array, or in z, is equal to 1000. (Remember that the first elementof a Python array has an index of 0 (zero).

You can see all of the field data at the nodes on mg with the following:

>>> mg.at_node.keys()['elevation']

You may recognize this as a dictionary-type structure, where the keys are the names (as strings) of the data arrays.

There are currently no data assigned to the links, as apparent by the following:

>>> mg.at_link.keys()[]

It is also possible, and indeed, often quite useful, to initialize a field from an existing numpy array of data. You can dothis with the add_field() method. This method also allows slightly more granular control over how the methodgets created, e.g., you can force a copy of the data to be made, or you can assign units to the field.

>>> import numpy as np>>> elevs_in = np.random.rand(mg.number_of_nodes)>>> mg.add_field('node', 'elevation', elevs_in, units='m', copy=True, noclobber=True)

Fields can store data at nodes, cells, links, faces, patches, junctions, and corners (though the latter two or three arevery rarely, if ever, used). Which of these you select is described in Landlab jargon as that field’s centering or group,and you will sometimes see this as an input to various grid methods.

Access only the core nodes, active links, or some other subset of node values using the properties available throughthe modelgrid:

>>> core_node_elevs = mg.at_node['elevation'][mg.core_nodes]

Note that when initializing a field, the singular of the grid element type is provided:

>>> veg = mg.add_ones('cell', 'percent_vegetation')>>> mg.at_cell.keys()['percent_vegetation']

Note that here veg is an array of ones, that has the same length as the number of cells. Note that there are no cellsaround the edge of a grid, so there are less cells than nodes:

>>> mg.at_cell['percent_vegetation'].size304

As you can see, fields are convenient because you don’t have to keep track of how many nodes, links, cells, etc. thereare on the grid. Further it is easy for any part of the code to query what data are already associated with the grid andoperate on these data.

You are free to call your fields whatever you want. However, many Landlab components require that you use Landlab’sstandard names. The standard names required can be accessed individually for each component with the propertiescomponent_instance._input_var_names and component_instance._output_var_names (returned as dictionaries), andshould also be listed in the docstring for each component.

We also maintain this list of all the Landlab standard names.

Our fields also offer direct compatibility with CSDMS’s standard naming system for variables. However, note that,for ease of use and readability, Landlab standard names are typically much shorter than CSDMS standard names. Weanticipate that future Landlab versions will be able to automatically map from Landlab standard names to CSDMSstandard names as part of Landlab’s built-in Basic Model Interface for CSDMS compatibility.

The following gives an overview of the commands you can use to interact with the grid fields.

26 Chapter 6. User Guide

Page 31: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Field initialization

• grid.add_empty(group, name, units=’-’)

• grid.add_ones(group, name, units=’-’)

• grid.add_zeros(group, name, units=’-’)

“group” is one of ‘node’, ‘link’, ‘cell’, ‘face’, ‘corner’, ‘junction’, ‘patch’

“name” is a string giving the field name

“units” (optional) is the units associated with the field values.

Field creation from existing data

• grid.add_field(group, name, value_array, units=’-’, copy=False, noclobber=False)

Arguments as above, plus:

“value_array” is a correctly sized numpy array of data from which you want to create the field.

“copy” (optional) if True adds a copy of value_array to the field; if False, creates a reference to value_array.

“noclobber” (optional) if True, raises an exception if a field called name already exists.

Field access

• grid.at_node or grid[‘node’]

• grid.at_cell or grid[‘cell’]

• grid.at_link or grid[‘link’]

• grid.at_face or grid[‘face’]

• grid.at_corner or grid[‘corner’]

• grid.at_junction or grid[‘junction’]

• grid.at_patch or grid[‘patch’]

Each of these is then followed by the field name as a string in square brackets, e.g.,

>>> grid.at_node[‘my_field_name’] #or>>> grid[‘node’][‘my_field_name’]

You can also use these commands to create fields from existing arrays, as long as you don’t want to take advantage ofthe added control “add_field()” gives you.

Representing Gradients in a Landlab Grid

Finite-difference and finite-volume models usually need to calculate spatial gradients in one or more scalar variables,and often these gradients are evaluated between pairs of adjacent nodes. ModelGrid makes these calculations easier forprogrammers by providing built-in functions to calculate gradients along links, and allowing applications to associatean array of gradient values with their corresponding links or edges. The tutorial examples on the following pagesillustrate how this capability can be used to create models of processes such as diffusion and overland flow.

Here we simply illustrate the method for calculating gradients on the links. Remember that we have already createdthe elevation array z, which is also accesible from the elevation field on mg.

6.2. Landlab’s Gridding Library 27

Page 32: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> gradients = mg.calculate_gradients_at_active_links(z)

Now gradients have been calculated at all links that are active, or links on which flow is possible (see boundaryconditions below).

Other Grid Elements

The cell vertices are called corners (Figure 1, solid squares). Each face is therefore a line segment connecting twocorners. The intersection of a face and a link (or directed edge) is known as a junction (Figure 1, open diamonds).Often, it is useful to calculate scalar values (say, ice thickness in a glacier) at nodes, and vector values (say, icevelocity) at junctions. This approach is sometimes referred to as a staggered-grid scheme. It lends itself naturally tofinite-volume methods, in which one computes fluxes of mass, momentum, or energy across cell faces, and maintainsconservation of mass within cells. (In the spring 2015 version of Lanlab, there are no supporting functions for the useof junctions, but support is imminent.)

Notice that the links also enclose a set of polygons that are offset from the cells. These secondary polygons are knownas patches (Figure 1, dotted). This means that any grid comprises two complementary tesselations: one made ofcells, and one made of patches. If one of these is a Voronoi tessellation, the other is a Delaunay triangulation. Forthis reason, Delaunay triangulations and Voronoi diagrams are said to be dual to one another: for any given Delaunaytriangulation, there is a unique corresponding Voronoi diagram. With ModelGrid, one can create a mesh with Voronoipolygons as cells and Delaunay triangles as patches (Figure 1b). Alternatively, with a raster grid, one simply has twosets of square elements that are offset by half the grid spacing (Figure 1a). Whatever the form of the tessellation,ModelGrid keeps track of the geometry and topology of the grid. patches can be useful for processes like calculatingthe mean gradient at a node, incorporating influence from its neighbors.

6.2.3 Managing Grid Boundaries

An important component of any numerical model is the method for handling boundary conditions. In general, it’s upto the application developer to manage boundary conditions for each variable. However, ModelGrid makes this task abit easier by tagging nodes that are treated as boundaries (boundary nodes) and those that are treated as regular nodesbelonging to the interior computational domain (core nodes). It also allows you to de-activate (“close”) portions of thegrid perimeter, so that they effectively act as walls.

Let’s look first at how ModelGrid treats its own geometrical boundaries. The outermost elements of a grid are nodesand links (as opposed to corners and faces). For example, Figure 2 shows a sketch of a regular four-row by five-columngrid created by RasterModelGrid. The edges of the grid are composed of nodes and links. Only the inner six nodeshave cells around them; the remaining 14 nodes form the perimeter of the grid.

All nodes are tagged as either boundary or core. Those on the perimeter of the grid are automatically tagged asboundary nodes. Nodes on the inside are core by default, but it is possible to tag some of them as boundary instead(this would be useful, for example, if you wanted to represent an irregular region, such as a watershed, inside a regulargrid). In the example shown in Figure 2, all the interior nodes are core, and all perimeter nodes are open boundary.

Boundary nodes are flagged as either open or closed, and links are tagged as either active or inactive (Figure 3).

A closed boundary is one at which no flux is permitted enter or leave, ever. By definition, all links coming into orout of a closed boundary node must be inactive. There is effectively no value assigned to a closed boundary; it willprobably have a BAD_INDEX_VALUE or null value of some kind. An open boundary is one at which flux can enteror leave, but whose value is controlled by some boundary condition rule, updated at the end of each timestep.

An active link is one that joins either two core nodes, or one core and one open boundary node (Figure 3). You canuse this distinction in models to implement closed boundaries by performing flow calculations only on active links, asseen in this tutorial. A call to mg.node_status returns the codes representing the boundary condition of each node inthe grid. There are 5 possible types:

• CORE (Type 0)

28 Chapter 6. User Guide

Page 33: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Fig. 6.2: Figure 2: Illustration of a simple four-row by five-column raster grid created with RasterModelGrid.By default, all perimeter nodes are tagged as open (fixed value) boundaries, and all interior cells are tagged as core.An active link is one that connects either two core nodes, or one core node and one open boundary node.

6.2. Landlab’s Gridding Library 29

Page 34: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Fig. 6.3: Figure 3: Illustration of a simple four-row by five-column raster grid with a combination of open and closedboundaries.

30 Chapter 6. User Guide

Page 35: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

• OPEN FIXED VALUE (Type 1)

• OPEN FIXED GRADIENT (Type 2)

• OPEN LOOPED (Type 3)

• CLOSED (Type 4)

A number of different methods are available to you to interact with (i.e., set and update) boundary conditions at nodes.Landlab is smart enough to automatically initialize new grids with fixed value boundary conditions at all perimetersand core nodes for all interior nodes, but if you want something else, you’ll need to modify the boundary conditions.

If you are working with a simple landlab raster where all interior nodes are core and all perimeter nodes are boundaries,you will find useful the set of commands:

• mg.set_closed_boundaries_at_grid_edges(bottom, left, top, right)

• mg.set_fixed_value_boundaries_at_grid_edges(bottom, left, top, right)

• mg.set_fixed_gradient_boundaries(bottom, left, top, right, gradient_in=nan, gradi-ent_of=’topographic__elevation’)

• mg.set_looped_boundaries(top_bottom_are_looped, left_right_are_looped)

Where bottom, left, top, right are all booleans. See the relevant docstring for each method for more detailed informa-tion.

If you are working with an imported irregularly shaped raster grid, you can close nodes which have some fixedNODATA value in the raster using:

• mg.set_nodata_nodes_to_closed(node_data, nodata_value)

Note that all of these commands will treat the status of node links as slave to the status of the nodes, as indicated inFigure 3. Links will be set to active or inactive according to what you set the node boundary conditions as, when youcall each method.

If you are working on an irregular grid, or want to do something more complicated with your raster boundary condi-tions, you will need to modify the grid.node_status array by hand, using indexes to node IDs. When you’re done, besure to call update_links_nodes_cells_to_new_BCs() to ensure internal consistency between the bound-ary conditions of the various grid elements.

Note that while setting Landlab boundary conditions on the grid is straightforward, it is up to the individual developerof each Landlab component to ensure it is compatible with these boundary condition schemes! Almost all existingcomponents work fine with core, closed, and fixed_value conditions, but some may struggle with fixed_gradient,and most will struggle with looped. If you’re working with the component library, take a moment to check yourcomponents can understand your implemented boundary conditions! See the Component Developer’s Guide for moreinformation.

6.2.4 Using a Different Grid Type

As noted earlier, Landlab provides several different types of grid. Available grids (as of this writing) are listed in thetable below. Grids are designed using Python classes, with more specialized grids inheriting properties and behaviorfrom more general types. The class heirarchy is given in the second column, Inherits from.

Grid type Inherits from Node arrangement Cell geometryRasterModelGrid ModelGrid raster squaresVoronoiDelaunayGrid ModelGrid Delaunay triangles Voronoi polygonsHexModelGrid VoronoiDelaunayGrid triagonal hexagonsRadialModelGrid VoronoiDelaunayGrid concentric Voronoi polygons

6.2. Landlab’s Gridding Library 31

Page 36: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

RasterModelGrid gives a regular (square) grid, initialized with number_of_node_rows, num-ber_of_node_columns, and a spacing. In a VoronoiDelaunayGrid, a set of node coordinates is given asan initial condition. Landlab then forms a Delaunay triangulation, so that the links between nodes are the edges of thetriangles, and the cells are Voronoi polygons. A HexModelGrid is a special type of VoronoiDelaunayGrid in whichthe Voronoi cells happen to be regular hexagons. In a RadialModelGrid, nodes are created in concentric circlesand then connected to form a Delaunay triangulation (again with Voronoi polygons as cells). .. The next exampleillustrates the use of a RadialModelGrid.

6.2.5 Importing a DEM

Landlab offers the methods read_esri_ascii() and read_netcdf() to allow ingestion of existing digitalelevation models as raster grids.

read_esri_ascii allows import of an ARCmap formatted ascii file (.asc or .txt) as a grid. It returns a tuple, containingthe grid and the elevations in Landlab ID order. Use the name keyword to add the elevation to a field in the importedgrid.

>>> from landlab.io import read_esri_ascii>>> (mg, z) = read_esri_ascii('myARCoutput.txt', name='topographic__elevation')>>> mg.at_node.keys()['topographic__elevation']

read_netcdf allows import of the open source netCDF format for DEMs. Fields will automatically be created accord-ing to the names of variables found in the file. Returns a RasterModelGrid.

>>> from landlab.io.netcdf import read_netcdf>>> mg = read_netcdf('mynetcdf.nc')

After import, you can use set_nodata_nodes_to_closed() to handle the boundary conditions in your im-ported DEM.

Equivalent methods for output are also available for both esri (write_esri_ascii()) and netCDF(write_netcdf()) formats.

6.2.6 Plotting and Visualization

Visualising a Grid

Landlab offers a set of matplotlib-based plotting routines for your data. These exist in the landlab.plot library. You’llalso need to import some basic plotting functions from pylab (or matplotlib) to let you control your plotting output: ata minimum show and figure. The most useful function is called imshow_node_grid(), and is imported and usedas follows:

>>> from landlab.plot.imshow import imshow_node_grid>>> from pylab import show, figure>>> mg = RasterModelGrid(50,50, 1.) #make a grid to plot>>> z = mg.node_x *0.1 #make an arbitrary sloping surface>>> #create the data as a field>>> mg.add_field(‘node’, ‘topographic_elevation’, z, units=’meters’,

copy=True)>>> figure(‘Elevations from the field’) #new fig, with a name>>> imshow_node_grid(mg, ‘topographic_elevation’)>>> figure(‘You can also use values directly, not fields’)>>> #...but if you, do you’ll lose the units, figure naming capabilities, etc>>> imshow_node_grid(mg, z)>>> show()

32 Chapter 6. User Guide

Page 37: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Note that imshow_node_grid() is clever enough to examine the grid object you pass it, work out whether thegrid is irregular or regular, and plot the data appropriately.

By default, Landlab uses a Python colormap called ‘pink’. This was a deliberate choice to improve Landlab’s user-friendliness to the colorblind in the science community. Nonetheless, you can easily override this colorscheme usingthe keyword cmap as an argument to imshow_node_grid. Other useful built in colorschemes are ‘bone’ (black towhite), ‘jet’, (blue to red, through green), ‘Blues’ (white to blue), and ‘terrain’ (blue-green-brown-white) (note thesenames are case sensitive). See the matplotlib reference guide for more options. Note that imshow_node_grid takesmany of the same keyword arguments as, and is designed to resemble, the standard matplotlib function imshow. Seealso the method help for more details. In particular, note you can set the maximum and minimum you want for yourcolorbar using the keywords vmin and vmax, much as in similar functions in the matplotlib library.

Visualising transects through your data

If you are working with a regular grid, it is trivial to plot horizontal and vertical sections through your data. Thegrid provides the method node_vector_to_raster(), which will turn a Landlab 1D node data array into a twodimensional rows*columns numpy array, which you can then take slices of. e.g., we can do this:

>>> from pylab import plot, show>>> mg = RasterModelGrid(10,10, 1.)>>> z = mg.node_x *0.1>>> my_section = mg.node_vector_to_raster(z, flip_vertically=True)[:,5]>>> my_ycoords = mg.node_vector_to_raster(mg.node_y, flip_vertically=True)[:,5]>>> plot(my_ycoords, my_section)>>> show()

Visualizing river profiles

Landlab provides a (still somewhat experimental) basic stream profiler. It is also found in the channel_profilelibrary. The key function is called analyze_channel_network_and_plot(), though you can also call thefunctions in channel_profile individually. It was designed to interface with the flow_routing Landlab com-ponent, and assumes you already have most of the fields that that component produces in your grid (i.e., ‘topo-graphic_elevation’, ‘drainage_area’, ‘flow_receiver’, and ‘links_to_flow_receiver’). It can also take three additionalarguments:

• number_of_channels - an integer giving how many stream channels you want to extract from the grid, default 1;

• starting_nodes - the ID, or list or array of IDs (per number_of_channels), of the node at which the outlet of thechannel you want to profile is at. Default is None, which tells the profiler to start from the number_of_channelsnodes with the highest drainage areas that are boundary nodes;

• threshold - the threshold drainage area (in drainage area units, not pixels) to stop tracing the channels upstream.Defaults to None, which tells the profiler to apply a threshold of twice the smallest cell area in the grid.

The profiler will add a plot of elevation vs distance upstream to the currently active figure each time it is called. Italso returns a 2-item tuple containing 1. a number_of_channels-long list of arrays of profile IDs in each stream,arranged in upstream order, and 2. a number_of_channels-long list of arrays of distances of those nodes upstream.In this way, you can extract drainage areas or other pertinent surface metrics to use with a call to pylab.plot to get, e.g.,slope-area, elevation-drainage area, etc plots.

See the component tutorial for an example of the profiler in use. (Tutorials available as downloadable and executablefile from https://github.com/landlab/drivers/archive/master.zip.)

Please let the development team know if you would like a better profiler, or better yet, have coded one up for Landlabyourself and would like to contribute it!

6.2. Landlab’s Gridding Library 33

Page 38: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Making Movies

Landlab does have an experimental movie making component. However, it has come to the developers’ attention thatthe matplotlib functions it relies on in turn demand that your machine already has installed one of a small set of highlytemperamental open source video codecs. It is quite likely using the component in its current form is more troublethan it’s worth; however, the brave can take a look at the library video_out. We intend to improve video out infuture Landlab releases.

For now, we advocate the approach of creating an animation by saving separately individual plots from, e.g., plot() orimshow_node_grid(), then stitching them together into, e.g., a gif using external software. Note it’s possible todo this directly from Preview on a Mac.

6.3 Building a Model

6.3.1 What goes into a Landlab Model?

In the previous section, we showed you most of the core functionality of the Landlab grid. In this section, we introduceyou to how to actually use it, to build models and work with the Landlab component library.

Using Landlab requires that you build a Python script to import, instantiate, and then run your landscape model. Wedescribe such a script as a driver. It’s also possible to do the same set of processes on the fly in an interactive Pythonenvironment like iPython.

Typically, a driver file will consist of six distinct sections:

• Import the Python and Landlab libraries you’ll need to run your model

• Instantiate the Landlab elements (grid and, if using them, components)

• Load any necessary data into the grid fields

• Set the boundary conditions

• Run the model, typically by creating a for loop or using a Landlab generator (see below)

• Finalize and handle the data (e.g., plot, export)

Beyond the driver, if you’re using Landlab components, you’ll probably also need a parameter file. This file suppliesthe components with the additional parameter and setup information they need. Landlab parameter files are text files(.txt), have fixed format, and for convenience (so you only have to specify the minimum of path information in the filename) should be placed in the same folder as the driver file. Find out more about parameter files here. However, ifyou’re not using components, there’s little need to create a parameter file; you can just directly other parameters to thegrid in the driver.

A Brief Introduction to Components

A key strength of Landlab is that not only is it designed to make implementing your own process simulations as simpleas possible, it also offers an off-the-shelf library of pre-designed process descriptions that you can use in your drivers.We call these process simulators Landlab components. The intention is that each component be:

• Plug-and-play

• Interoperable with all other components

• Implementable in your driver in only one or two lines of code

34 Chapter 6. User Guide

Page 39: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Note that by no means is using the component library necessary or even always desirable when working with Land-lab. However, we hope that their availability and ease of use will dramatically reduce the time investment neededto implement a wide variety of modelling scenarios. In particular, components should make production of modelscoupling more than one process significantly easier, as existing, off-the-shelf components can be slotted in alongsidenovel process descriptions.

At the time of writing, the existing library contains the following components:

• Detachment limited/stream power channel incision

• Transport limited channel incision

• Linear (hillslope) diffusion

• Nonlinear hillslope diffusion

• D8 /Dn (D8 generalized to Voronoi) flow routing

• Simple and not-so-simple crustal flexure

• A simple fire simulator

• A thin-ice glacial approximation

• Precipitation/evapotranspiration

• A relatively simple router for overland flow

• A radiative intensity calculator

• A generalized framework for cellular automata

• A hillslope particle cellular automaton

And under active development are:

• A vegetation cellular automaton

• An impact cratering simulator

• Divergent and mixed convergent-divergent flow routers

• A deltaic simulator

Note that not all components will run under all conditions, but that any limitations should be made clear in the inlinedocumentation associated with that component (access help either through the indices you can find on this site or bytyping “[component or method]?” in an interactive Python session). In particular, some components may demand youare running on a regular grid. It should probably also be emphasised that most of these components are still underactive development within this beta release of Landlab, and may behave in idiosyncratic ways or be subject to suddenchanges with little or no warning. In all cases, we’d recommend contacting the original coder of the component to letthem know they have external users to think about before setting out on any major research challenges using it!

Implementing a Landlab driver

As noted above, the process of creating a driver is essentially equivalent whether you want to implement Landlabcomponents, purely your own code, or some mixture of the two. Here we take a closer look at the various steps.

1. Import the libraries and functions you need

Landlab handles a lot like numpy, and like numpy you’ll need to import the various libraries and functions that you’llwant to use. At the very least, we suspect you’ll need from outside Landlab:

• numpy itself

6.3. Building a Model 35

Page 40: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

• rudimentary pylab plotting routines: plot, show, figure

Also useful can be:

• the Python module time, to time various parts of your code

• elements from SciPy, the scientific computing library. Lots of useful methods (e.g., matrix solutions, curvefitting) can be found in here, to avoid reinventing the wheel.

From inside Landlab, you’ll also need:

• A grid class. Choose from RasterModelGrid, VoronoiDelaunayGrid, or some of the more specializedclasses

• Any components you want to run

• Any Landlab utilities you need, like the plotters (imshow_node_grid()) or io functions

A specific example might be:

>>> import numpy as np>>> from pylab import show, figure, plot>>> import time>>> from landlab import RasterModelGrid>>> from landlab.components.flow_routing import route_flow_dn>>> from landlab.plot.imshow import imshow_node_grid

2. Instantiate objects

As noted in previous sections, Landlab is coded in an object-oriented style. This means that we need to “instantiate”the various Landlab objects that we will use to store data and run the model. The grid and all the components areobjects, so we need to instantiate them next.

Note that most components require the grid object be passed to them as one of their arguments during instantiation, sothe first thing you’ll want to instantiate will be the grid.

Check the docstrings for each class (grid, component) you want to instantiate for a detailed description of what youneed to supply as arguments. For a RasterModelGrid, this will be (number_of_node_rows, number_of_node_columns,node_spacing(optional)). For a VoronoiDelaunayGrid, it will be (array_of_node_x_coords, array_of_node_y_coords).For a generic component, it will typically be (ModelGrid, ‘path_to_parameter_file.txt’), though there may be somevariation, and optional inputs may also be available.

Give each object you instantiate a variable name. We like “mg” for ModelGrid objects, and some appropriate abbre-viation for a component.

An example might be:

>>> mg = RasterModelGrid(10,10,1.) #100 nodes, spacing of 1.>>> fr = route_flow_dn(mg, ‘./params.txt’) #this assumes params.txt is in the current directory

3. Load/create data in fields

(See this section if you don’t know what a Landlab field is)

Now we need some data to work with. Here we’ll assume that you’re going to be working with a DEM-style elevationmap across the nodes of the grid, but similar considerations would apply for any other type of data.

You will likely be in one of two situations regarding the initial data you want to put on the grid - either you will havesome external data source that you want to load in and use as your initial conditions (e.g., a DEM of some basin, or

36 Chapter 6. User Guide

Page 41: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

some other real topography), or you want to set up some simple analytical initial condition like a flat surface withnoise or an inclined surface.

In both cases, we advocate a two step process: creating a numpy array of the data, then loading it into the grid as afield. We can illustrate for both of the above cases:

>>> mg = RasterModelGrid(10,10,1.) #make a grid>>> z = np.zeros(100, dtype=float) #make a flat surface, elev 0>>> #or...>>> z = mg.node_y*0.01 #a flat surface dipping shallowly south>>> z += np.random.rand(100.)/10000. #add a little noise to the surface>>> mg.add_field(‘node’, ‘topographic__elevation’, z, units=’m’) #create the field

Alternatively, we can use the specialized Landlab function read_esri_ascii() to import an ascii raster that canbe output from ARC. Note this function both creates the grid for you and loads the data as a field if you provide‘name’. If not, you’ll have to load the data output (z, below) manually.

>>> from landlab.io import read_esri_ascii>>> mg, z = read_esri_ascii(‘my_ARC_output.asc’, name=’topographic__elevation’)>>> np.all(mg.at_node[‘topographic__elevation’] == z)

True

Note that if you don’t want to use any Landlab components, you can continue to work with data as “free floating”numpy arrays, and can ignore the fields (e.g., see the simple tutorial at the start of this guide).

4. Set the boundary conditions

Once you have a grid and the initial condition data you’ll need, it’s time to set the boundary conditions. If you’re work-ing with a raster, or some pre-existing imported data, this is very straightforward using the built in RasterModelGridfunctions. For a raster where only the edges are to be boundary nodes:

>>> mg.set_fixed_value_boundaries_at_grid_edges(False, True, False, True)>>> mg.set_closed_boundaries_at_grid_edges(True, False, True, False)

This will give a grid with fixed value boundaries at the left and right edges, and closed boundaries at the top andbottom.

If you’re working with, say, an ARC imported array with a null value on the closed nodes (e.g., -9999), you can dothis:

>>> mg.set_nodata_nodes_to_closed(mg.at_node[‘topographic__elevation’], -9999)

(Note though that you’re still likely to have to reopen an outlet node manually! In which case you’ll also need tofollow the instructions below.)

If you’re working with individual nodes’ boundary statuses, you’ll need to set the BCs slightly differently. First,you’ll need to alter those statuses directly, but then - and very importantly! - you’ll need to make sure all there’sfull internal consistency between the node statuses and all the subsidiary statuses like those on cells and links. Useupdate_links_nodes_cells_to_new_BCs(). Do this like so:

>>> #find the ID of the lowest elevation core node; we’ll make this a fixed gradient outlet:>>> outlet_id = mg.core_nodes[np.argmin(

mg.at_node[‘topographic__elevation’][mg.core_nodes])]>>> mg.node_status[outlet_id] = 2>>> #remember, 0:core, 1:fixedval, 2:fixedgrad, 3:looped, 4:closed>>> mg.update_links_nodes_cells_to_new_BCs()>>> #make sure to call this if you make manual BC changes!!

6.3. Building a Model 37

Page 42: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

5. Run the model

We’re now ready to actually implement a run of our model! Most things you might want to do with Landlab areprobably time-sensitive, so in almost all cases, you’ll probably be placing the guts of your simulation inside a loop ofsome sort. In simple cases, you can just use some variation on a simple for loop or while statement, either:

>>> dt = 10.>>> for tstep in xrange(100):... #...do the thing for one timestep dt

or

>>> dt = 10.>>> accumulated_time = 0.>>> while accumulated_time<1000.:... #...do the thing for one timestep dt... accumulated_time += dt

Both produce 1000 time units of run, with an explicit timestep of 10. Notice that the latter technique is particularlyamenable to situations where your explicit timestep is varying (e.g., a storm sequence).

Landlab also however has a built in storm generator component, PrecipitationDistribution,which (as its module name suggests) actually acts as a true Python generator. The main method isyield_storm_interstorm_duration_intensity(). This means producing a storm series in Landlabis also very easy:

>>> from landlab.components.uniform_precip.generate_uniform_precip import PrecipitationDistribution>>> time_to_run = 500000.>>> precip_perturb = PrecipitationDistribution(input_file=input_file_string, total_t=time_to_run)>>> for (interval_duration, rainfall_rate) in precip_perturb.yield_storm_interstorm_duration_intensity():... if rainfall_rate != 0.:... #...do the thing, making sure to pass it the current interval_duration and rainfall_rate

Notice that the advantage of the generator is that it just stops when the desired number of events/time duration hasexpired! See the end of this tutorial for an example of this generator in action.

What exactly “...do the thing” consists of is up to you. You can either design your own operations to do in the loop foryourself, or you can implement processes from Landlab’s component library. See here for more information on usingthe components.

6. Finalize and handle the data

Once the looping is complete, the model is effectively finished. However, you will still need to output the datasomehow! Some obvious options are:

Save or export the data If you’re using a raster grid, you can easily save your grid output to either ESRI ascii (i.e.ARCmap) or open source netCDF formats. netCDF in particular is a powerful format, and allows easy subsequentre-loading of a Landlab modelgrid and all its fields. Save your raster like this:

>>> rmg.save(‘my_savename.asc’, names=[‘field1’,’field2’]) #for esri ascii, only saving the fields 1 and 2

or

>>> rmg.save(‘my_savename.nc’) #save as netCDF3, saving all fields by default

The former way will give two save files, my_savename_field1.asc and my_savename_field2.asc. The latter will justgive ‘my_savename.nc’.

38 Chapter 6. User Guide

Page 43: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

To reload a netCDF file, use the Landlab io function read_netcdf():

>>> from landlab.io.netcdf import read_netcdf>>> mg = read_netcdf(‘my_savename.nc’)

Note all the original fields you had will automatically be repopulated.

If you’re using an irregular grid, the simple grid save function is not yet operational (though is under development).Instead, we recommend using Pickle, a native Python way of saving (“pickling”) any Python object. It works like this:

>>> import cPickle as pickle #cPickle is a lot faster than normal pickle>>> pickle.dump( mg, open(‘my_savename.pickle’, ‘wb’) ) #save the grid, and all its fields>>> mg = pickle.load( open(‘my_savename.pickle’, ‘rb’) ) #load the grid and fields back into a grid object

Unfortunately, the power of pickle comes somewhat at the expense of both disk space and speed. Saves this way canbe slow and, if the grid is big, memory expensive (e.g., ~1 Gb for millions of nodes).

You can also use lower level, numpy save routines to preserve just your data (rather than the whole grid object). Thenumpy methods save and savetxt and load and loadtxt can be called on any numpy array, including those saved asfields. Save and load use the numpy specific .npy file format; savetxt and loadtxt use textfiles. Use them like this:

>>> np.save(‘savename.npy’, mg.at_node[‘my_field’])>>> mg.at_node[‘my_field’] = np.load(‘savename.npy’)>>> np.savetxt(‘savename.txt’, mg.at_node[‘my_field’])>>> mg.at_node[‘my_field’] = np.loadtxt(‘savename.txt’)

Plot the data Landlab has a fairly comprehensive suite of built in plotting functions; read more about them here.

You also of course have the option of using the matplotlib plotting library of Python for things like cross-sections.

If you’re careful, you can also build plotting functions into the body of a run loop for your model, so you can seehow your output evolves through time. Note however that all Python save and plot functions are considerably timeexpensive, so it would probably be a bad idea to do this kind of thing every timestep. Instead, you can try somethinglike:

>>> import plot>>> dt = 10.>>> accumulated_time = 0.>>> last_accumulated_time_remainder = 0.>>> while accumulated_time<1000.:... #...do the thing for one timestep dt... accumulated_time += dt... if last_accumulated_time_remainder < accumulated_time%100.: #output every 100.... plot(mg.node_vector_to_raster(z)[mg.number_of_node_rows//2,:]) #a cross section... last_accumulated_time_remainder = accumulated_time%100.>>> show()

Note that if you’re running inside an interactive Python session like iPython, all the variables and objects (both gridand component) that you’ve used in your model will still be available in the environment. Thus, you can play withyour data for as long as you want!

6.3.2 Landlab Components

For a tutorial introduction to using the component library, see here.

6.3. Building a Model 39

Page 44: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

The Landlab Component Library

Landlab offers an ever-growing library of components that aim to describe individual or closely associated suites ofsurface processes. Components are designed to be “plug-and-play”, and to interact with each other with the minimumof technical difficulties. Each makes use of Landlab grid fields to enable the sharing of data between the components,and we aim to have a relatively standardized way of interacting with and using each different one.

Landlab components exist as classes, and can be imported from landlab.components.

Note: We emphasize that at the moment most Landlab components are under active development, and it is possiblethat changes may occur to e.g. input argument format with little or no warning. Please let the Landlab developmentteam know if you’re making heavy use of a component, so we can avoid unnecessarily breaking your code in futureLandlab releases! Components are presented as-is, and in this essentially beta release we don’t make any guaranteesabout the stability or otherwise of the implementations.

Available Landlab components

The current library includes the following components in essentially full working order:

• linear diffusion: LinearDiffuser

• nonlinear hillslope diffusion: PerronNLDiffuse

• a fire generator: FireGenerator

• a simple lithospheric flexure model: FlexureComponent

• a more complex flexural model, incorporating A. Wickert’s gFlex code: gFlex

• a single-direction (“D8 generalized” or “Dn”) flow router: FlowRouter

• a thin ice glacial approximation: Glacier

• a shallow overland flow approximation (following Bates et al., 2010): OverlandFlow

• a potential evapotranspiration module: PotentialEvapotranspiration

• a solar total incident shortwave radiation calculator: Radiation

• a soil moisture module: SoilMoisture

• a simple stream power (pure detachment limited) fluvial component: StreamPowerEroder, or SPEroder

• a transport-limited fluvial component: TransportLimitedEroder

• a sediment-flux dependent shear stress based fluvial incision component: SedDepEroder

• a generator for storms over a landscape: PrecipitationDistribution

• A powerful, generalized, continuous-time stochastic cellular automaton, that can be specialized for many othertasks, AKA “CellLab-CTS”: LandlabCellularAutomaton

Under active development are:

• a vegetation cellular automaton

• an impact cratering simulator

• divergent and mixed convergent-divergent flow routers

• a deltaic simulator

40 Chapter 6. User Guide

Page 45: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Input Files

Component input files are all .txt text files, and all share a format. The contents of the file form alternating lines, onegiving the name of the variable followed by a colon, the next giving the value to use for that variable. e.g.,:

K_sp: Additional text can go after the colon to allow annotation0.3m_sp:0.5n_sp:1.linear_diffusivity:0.0001

Landlab components use a special class called the ModelParameterDictionary to interact with these input files. Createan MPD object by using the input file as the argument to the ModelParameterDictionary. Once you have this object, itnot only behaves as a Python dictionary with the variable names as the keys and the values as the values, but also pro-vides a specialized set of property methods (read_float(), read_int(), read_bool(), read_string()),which allow you to test for type while reading the variables. A value of the wrong type that cannot be cast to the correcttype will result in a ParameterValueError.

>>> from landlab import ModelParameterDictionary>>> MPD = ModelParameterDictionary('myinputfile.txt')>>> MPD['m_sp']0.5>>> MPD.read_float['linear_diffusivity']0.0001>>> MPD.read_string['linear_diffusivity']'0.0001'>>> MPD.read_int['linear_diffusivity']ParameterValueError>>> MPD.read_bool['linear_diffusivity']ParameterValueError

Implementing a Component

Although the vagaries of their precise implementation vary due to their development histories, Landlab componentstend to share a basic grammar for their usage:

A component class is imported from the library as

>>> from landlab.components.[noun].[what_component_does] import ComponentClass

A component is instantiated like:

>>> compobj = ComponentClass(ModelGrid, ‘parameter_file.txt’, ...)

A component has a primary method, which “does the thing”. The documentation for the component will typicallytell you what is it called and how to work it (NB: you can get documentation for any object you have created inan interactive python environment by typing a “?” after it, e.g., “compobj?”; quit by pressing “q”). However, mostcomponents will run for a single timestep with a syntax something like:

>>> compobj.do_the_process(timestep, ...[any other arguments])

Running one of these methods will update the fields held in common by the single grid object which you linked to allyour components during component instantiation. If you look inside the grid fields having run one of these methods,you’ll see the new fields it has created and populated. The docstrings for the component should make it clear which

6.3. Building a Model 41

Page 46: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

fields the component needs to have in the grid as inputs, and which it modifies and/or creates as outputs. ALWAYScheck the documentation for a component you are about to use!

Component Standard Properties

As part of our rolling efforts to standardize and improve Landlab, we are also trying to implement a standardized set ofproperties that all components will have. These give automated information on fields, units, etc. For a fully compliantcomponent, you will find you can call:

Property Descriptioncomponent.name a stringcomponent.input_var_names a set giving input field namescomponent.output_var_names a set giving output field namescomponent.var_units a dict, with var_name keyscomponent.var_mapping a dict with var_name keys, giving ‘node’, ‘link’, etccomponent.var_defs a dict with var_name keys, giving short descriptions

See the tutorials for examples of use cases with one, two and more coupled components.

Landlab Standard Naming Conventions

Note: We are currently in the process of improving the Landlab-wide standardization of our naming conventions.Currently in use standard field names may change suddenly in the near future! Note we will however be making effortsto maintain backward compatibility with names currently in use.

The Landlab component library attempts to make use of a relatively standardized set of names across the variouscomponents, in order to maximize ease of component coupling. If you’re familiar with the concept of the CSDMSstandard naming conventions, note that we have tried to strike a balance between the rigor and uniqueness of thosenames and a more user-friendly, succinct approach. Nonetheless, you may recognise the basic style of the names:

thing_described__what_is_described

e.g., topographic__elevation, water_surface__gradient, water__volume_flux

You can see a list of the names currently in use here: Landlab Standard Names

Dealing with nonstandard names

The large number of developers on Landlab and historical accident have meant that despite our best efforts you’llinevitably find instances where different components use different names for the same thing. In these cases, you needto make equivalent two fields in the grid which have different names so that two components can talk to each other.This is actually easy; you can just do:

>>> mg.add_field(‘node’, ‘second_name’, mg.at_node[‘first_name’])

Note that we are making slow progress towards truly standardizing the component library, but these kind of idiosyn-crasies might yet persist for a while!

6.4 Tutorials

Start with the 10 minute Landlab introduction tutorial, then choose from:

• A super-basic intro to Python and Numpy: http://nbviewer.ipython.org/github/landlab/drivers/blob/master/notebooks/Python_intro.ipynb

42 Chapter 6. User Guide

Page 47: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

• An introduction to modelling with Landlab: http://nbviewer.ipython.org/github/landlab/drivers/blob/master/notebooks/LandlabFaultScarpDemo.ipynb

• Using the Landlab component library: http://nbviewer.ipython.org/github/landlab/drivers/blob/master/notebooks/component_tutorial.ipynb

• The Landlab flexure component: http://nbviewer.ipython.org/github/landlab/drivers/blob/master/notebooks/flexure/lots_of_loads.ipynb

• The Landlab ecohydrology components: http://nbviewer.ipython.org/github/landlab/drivers/blob/master/notebooks/Ecohydrology/cellular_automaton_vegetation_DEM/cellular_automaton_vegetation_DEM.ipynb

6.5 Simple guides to functionality

These (slightly outdated) resources provide guides to the actual functions you can find and use through Landlab.

6.5.1 List of Landlab Models

(pending)

6.5.2 List of Landlab Components

This is a (probably incomplete) list of the existing components for landlab. Most of these remain quite experimental,and may change in the future! Documentation may also be wanting in some cases.

Where a specific method is listed beneath the module class, this is the primary method of the module. This is themethod you call in a loop to actually “crank the handle” of the process.

Functional modules

class FireGenerator(input_file=None)

Methods

generate_fire_recurrencegenerate_fire_time_seriesget_scale_parameterupdate

class FlexureComponent(grid, **kwds)Landlab component that implements a 1 and 2D lithospheric flexure model.

Examples

>>> from landlab import RasterModelGrid>>> from landlab.components.flexure import FlexureComponent>>> grid = RasterModelGrid(5, 4, 1.e4)>>> flex = FlexureComponent(grid)>>> flex.name'Flexure'>>> sorted(flex.input_var_names)['lithosphere__elevation', 'lithosphere__overlying_pressure', 'planet_surface_sediment__deposition_increment']>>> sorted(flex.output_var_names)

6.5. Simple guides to functionality 43

Page 48: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

['lithosphere__elevation', 'lithosphere__elevation_increment']>>> for var in sorted(flex.units): flex.units[var]'m''m''Pa''m'

>>> flex.grid.number_of_node_rows5>>> flex.grid.number_of_node_columns4>>> flex.grid is gridTrue

>>> np.all(grid.at_node['lithosphere__elevation'] == 0.)True

>>> np.all(grid.at_node['lithosphere__elevation'] == 0.)True>>> np.all(grid.at_node['lithosphere__overlying_pressure'] == 0.)True>>> flex.update()>>> np.all(grid.at_node['lithosphere__elevation_increment'] == 0.)True

>>> load = grid.at_node['lithosphere__overlying_pressure']>>> load[4] = 1e9>>> dz = grid.at_node['lithosphere__elevation_increment']>>> np.all(dz == 0.)True

>>> flex.update()>>> np.all(grid.at_node['lithosphere__elevation_increment'] == 0.)False

Attributes

coordsgridinput_var_namesnameoutput_var_namesshapeunitsvar_definitionsvar_mappingvar_units

Methods

imshowsubside_loads

Continued on next page

44 Chapter 6. User Guide

Page 49: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Table 6.3 – continued from previous pageupdate

class FlowRouter(model_grid, input_params=None)This class implements single-path (steepest direction) flow routing, and calculates flow directions, drainage area,and (optionally) discharge.

It initializes with a reference to a ModelGrid of any kind. Optionally, it can also take input_params, the stringwhich is the name of a text input file. The input file can optionally contain ‘runoff_rate’, a float giving a (spatiallyconstant) runoff rate. This is equivalent to the optional input field ‘water__volume_flux_in’, and will override itif both are set. If neither are set, value will default to 1.

The primary method of this class is route_flow().

Attributes

coordsgridinput_var_nameslink_to_flow_receiving_nodenamenode_drainage_areanode_order_upstreamnode_receiving_flownode_steepest_slopenode_water_dischargeoutput_var_namesshapeunitsvar_definitionsvar_mappingvar_units

Methods

imshowroute_flow

route_flow()Routes surface-water flow by (1) assigning to each node a single drainage direction, and then (2) addingup the number of nodes that contribute flow to each node on the grid (including the node itself).

Stores as ModelGrid fields:

• Node array of receivers (nodes that receive flow): ‘flow_receiver’

• Node array of drainage areas: ‘drainage_area’

• Node array of discharges: ‘water__volume_flux’

• Node array of steepest downhill slopes: ‘topographic__steepest_slope’

• Node array containing downstream-to-upstream ordered list of node IDs: ‘upstream_ID_order’

6.5. Simple guides to functionality 45

Page 50: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

• Node array containing ID of link that leads from each node to its receiver (or ITS OWN ID ifthere is no receiver): ‘links_to_flow_receiver’

• Boolean node array of all local lows: ‘flow_sinks’

Returns:

• the modified grid object

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> from landlab.components.flow_routing.route_flow_dn import FlowRouter>>> mg = RasterModelGrid(5, 4, 1.0)>>> elev = np.array([0., 0., 0., 0.,... 0., 21., 10., 0.,... 0., 31., 20., 0.,... 0., 32., 30., 0.,... 0., 0., 0., 0.])>>> _ = mg.add_field('node','topographic__elevation', elev)>>> mg.set_closed_boundaries_at_grid_edges(False, True, True, True)>>> fr = FlowRouter(mg)>>> mg = fr.route_flow()>>> mg.at_node['flow_receiver']array([ 0, 1, 2, 3, 4, 1, 2, 7, 8, 6, 6, 11, 12, 10, 10, 15, 16,

17, 18, 19])>>> mg.at_node['drainage_area']array([ 1., 2., 6., 1., 1., 1., 5., 1., 1., 1., 3., 1., 1.,

1., 1., 1., 1., 1., 1., 1.])

Now let’s change the cell area and the runoff rates:

>>> mg = RasterModelGrid(5, 4, 10.) #so cell area==100.>>> _ = mg.add_field('node','topographic__elevation', elev) #put the data back into the new grid>>> mg.set_closed_boundaries_at_grid_edges(False, True, True, True)>>> fr = FlowRouter(mg)>>> runoff_rate = np.arange(mg.number_of_nodes)>>> _ = mg.add_field('node', 'water__volume_flux_in', runoff_rate)>>> mg = fr.route_flow()>>> mg.at_node['water__volume_flux']array([ 0., 600., 5400., 300., 400., 500., 5200., 700.,

800., 900., 3700., 1100., 1200., 1300., 1400., 1500.,1600., 1700., 1800., 1900.])

class PerronNLDiffuse(grid, input_stream)This module uses Taylor Perron’s implicit (2011) method to solve the nonlinear hillslope diffusion equationacross a rectangular, regular grid for a single timestep. Note it works with the mass flux implicitly, and thusdoes not actually calculate it. Grid must be at least 5x5. Built DEJH early June 2013.

Boundary condition handling assumes each edge uses the same BC for each of its nodes. This component cannotyet handle looped boundary conditions, but all others should be fine.

This components requires the following parameters be set in the input file, input_stream, set in the componentinitialization:

‘uplift’ or ‘uplift_rate’, both equivalent to the uplift rate ‘rock_density’ ‘sed_density’ ‘kappa’, thediffusivity to use ‘S_crit’, the maximum possible surface slope (radians)

Optional inputs are:

46 Chapter 6. User Guide

Page 51: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

‘dt’, the model timestep (assumed constant) ‘values_to_diffuse’, a string giving the name of the gridfield containing the data to diffuse.

If ‘dt’ is not supplied, you must call the method set_timestep() as part of your run loop. This allows you toset a dynamic timestep for this class. If ‘values_to_diffuse’ is not provided, defaults to ‘topographic__elevation’.

No particular units are necessary where they are not specified, as long as all units are internally consistent.

The component takes grid, the RasterModelGrid object, and input_stream, the filename of (& optionally, pathto) the parameter file, in its initialization.

The primary method of this class is diffuse().

Methods

coreIDtointeriorcoreIDtorealdiffusegear_timestepinput_timestepinteriorIDtocoreinteriorIDtorealrealIDtocorerealIDtointeriorset_variables

diffuse(grid_in, elapsed_time, num_uplift_implicit_comps=1)This is the primary method of the class. Call it to perform an iteration of the model. Takes grid_in, themodel grid, and elapsed_time, the total model time elapsed so far.

grid_in must contain the field to diffuse, which defaults to ‘topographic__elevation’. This can be overrid-den with the values_to_diffuse property in the input file.

See the class docstring for a list of the other properties necessary in the input file for this component torun.

Note that the implicit nature of this component requires it to incorporate uplift into its execution in orderto stay stable. If you only have one module that requires this, do not add uplift manually in your loop; thismethod will include uplift automatically.

If more than one of your components has this requirement, set num_uplift_implicit_comps to the totalnumber of components that do.

class SPEroder(grid, input_stream)This class uses the Braun-Willett Fastscape approach to calculate the amount of erosion at each node in a grid,following a stream power framework.

On initialization, it takes grid, a reference to a ModelGrid, and input_stream, a string giving the filename (andoptionally, path) of the required input file.

It needs to be supplied with the key variables:

K_sp

m_sp

...which it will draw from the supplied input file. n_sp can be any value ~ 0.5<n_sp<4., but note that performancewill be EXTREMELY degraded if n<1.

6.5. Simple guides to functionality 47

Page 52: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

If you want to supply a spatial variation in K, set K_sp to the string ‘array’, and pass a field name or array to theerode method’s K_if_used argument.

dt, rainfall_intensity, and value_field are optional variables.

dt is a fixed timestep, and rainfall_intensity is a parameter which modulates K_sp (by a product, r_i**m_sp) toreflect the direct influence of rainfall intensity on erosivity. value_field is a string giving the name of the fieldcontaining the elevation data in the grid. It defaults to ‘topographic__elevation’ if not supplied.

This module assumes you have already run landlab.components.flow_routing.route_flow_dn.FlowRouter.route_flow()in the same timestep. It looks for ‘upstream_ID_order’, ‘links_to_flow_receiver’, ‘drainage_area’,‘flow_receiver’, and ‘topographic__elevation’ at the nodes in the grid. ‘drainage_area’ should be in areaupstream, not volume (i.e., set runoff_rate=1.0 when calling FlowRouter.route_flow).

If dt is not supplied, you must call gear_timestep(dt_in, rain_intensity_in) each iteration to set these variables on-the-fly (rainfall_intensity will be overridden if supplied in the input file). If dt is supplied but rainfall_intensityis not, the module will assume you mean r_i = 1.

The primary method of this class is erode().

Methods

erodegear_timestep

erode(grid_in, dt=None, K_if_used=None)This method implements the stream power erosion, following the Braun- Willett (2013) implicit Fastscapealgorithm. This should allow it to be stable against larger timesteps than an explicit stream power scheme.

The method takes grid, a reference to the model grid. Set ‘K_if_used’ as a field name or nnodes-long arrayif you set K_sp as ‘array’ during initialization.

It returns the grid, in which it will have modified the value of value_field, as specified in componentinitialization.

Here be dragons!

These components are all in principle working, but either deviate from up to date recommended Landlab style guide-lines, or are otherwise “confusing”. All remain definitely experimental. Procede at your own risk!

class LinkCellularAutomaton(model_grid, node_state_dict, transition_list, initial_node_states, orien-tation_matters=False)

The LinkCellularAutomaton implements a link-type (or doublet-type) cellular automaton model. A link con-nects a pair of cells. Each cell has a state (represented by an integer code), and each link also has a state that isdetermined by the states of the cell pair.

Methods

active_link_orientationassign_link_states_from_node_typescreate_link_state_dict_and_pair_listdo_transition

Continued on next page

48 Chapter 6. User Guide

Page 53: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Table 6.8 – continued from previous pageget_next_eventpush_transitions_to_event_queuerunset_node_state_gridsetup_transition_dataupdate_component_dataupdate_link_stateupdate_node_states

Under development

These components are currently under development for Landlab:

• Impact cratering

• Glacial flow, in a variety of forms

• ...

6.5.3 An index for key functions in the Landlab grid

This document is designed to present a more ordered list of methods available in the Landlab grids. It is broken downprimarily into functional groups according to the type of task you may want to achieve:

• Grid creation

• Create data in the grid fields

• Resolve, project, and move data between grid element types

• Access information about the grid

• Access the grid geometry

• Link coordinates and distances to nodes

• Derive offsets, gradients, flux divergences, and steepest descents

• Control boundary conditions

• Manipulate arrays for plotting and display

At the moment, the raster grid is much better developed than the Voronoi grid (and its derived unstructured grids).Most calls to ModelGrid methods below will work for such unstructured grids, but some may result in errors. Pleasereport such missing functionality through the github page if you need it urgently!

Grid creation

These methods are used to create grids.

RasterModelGrid.__init__(*args, **kwds)Create a 2D grid with equal spacing.

Optionally takes numbers of rows and columns and cell size as inputs. If this are given, calls initialize() to setup the grid. At the moment, num_rows and num_cols MUST be specified. Both must be >=3 to allow correctautomated setup of boundary conditions.

Parameters shape : tuple of int

6.5. Simple guides to functionality 49

Page 54: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Shape of the grid in nodes.

spacing : float, optional

Row and column node spacing.

bc : dict, optional

Edge boundary conditions.

Returns RasterModelGrid

A newly-created grid.

Notes

The option for NOT giving rows, cols, and dx no longer works, because the field init requires num_active_cells,etc., to be defined. Either we force users to give arguments on instantiation, or set it up such that one can createa zero-node grid.

VoronoiDelaunayGrid.__init__(x=None, y=None, reorient_links=True, **kwds)Create a Voronoi Delaunay grid from a set of points.

Create an unstructured grid from points whose coordinates are given by the arrays x, y.

Parameters x : array_like

x-coordinate of points

y : array_like

y-coordinate of points

Returns VoronoiDelaunayGrid

A newly-created grid.

Examples

>>> from numpy.random import rand>>> from landlab.grid import VoronoiDelaunayGrid>>> x, y = rand(25), rand(25)>>> vmg = VoronoiDelaunayGrid(x, y) # node_x_coords, node_y_coords>>> vmg.number_of_nodes25

RadialModelGrid.__init__(num_shells=0, dr=1.0, origin_x=0.0, origin_y=0.0, **kwds)Create a circular grid.

Create a circular grid in which grid nodes are placed at regular radial and semi-regular arc-wise intervals. Thatis, if the radial spacing between shells is dr, the nodes are placed around the circular shell at regular intervalsthat get as close as possible to dr. The points are then arranged in a Delaunay triangulation with Voronoi cells.

Parameters num_shells : int

Number of rings in the grid.

dr : float, optional

Radial interval for rings.

origin_x : float, optional

50 Chapter 6. User Guide

Page 55: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

x-coordinate of origin node.

origin_y : float, optional

y-coordinate of origin node.

Returns RadialModelGrid

A newly-created grid.

Examples

A grid with just one ring will have a node at the origin surrounded by six other nodes.

>>> from landlab import RadialModelGrid>>> omg = RadialModelGrid(num_shells=1, dr=1., origin_x=0., origin_y=0.)>>> omg.number_of_nodes7>>> omg.number_of_cells1

A second rings will have 13 nodes.

>>> omg = RadialModelGrid(2)>>> omg.number_of_nodes20

HexModelGrid.__init__(base_num_rows=0, base_num_cols=0, dx=1.0, orientation=’horizontal’,shape=’hex’, reorient_links=False, **kwds)

Create a grid of hexagonal cells.

Create a regular 2D grid with hexagonal cells and triangular patches. It is a special type of VoronoiDelaunaygrid in which the initial set of points is arranged in a triangular/hexagonal lattice.

Parameters base_num_rows : int

Number of rows of nodes in the left column.

base_num_cols : int

Number of nodes on the first row.

dx : float, optional

Node spacing.

orientation : string, optional

One of the 3 cardinal directions in the grid, either ‘horizontal’ (default) or ‘vertical’

Returns HexModelGrid

A newly-created grid.

Examples

Create a hex grid with 2 rows of nodes. The first and third rows will have 2 nodes, and the second nodes.

>>> from landlab import HexModelGrid>>> hmg = HexModelGrid(3, 2, 1.0)>>> hmg.number_of_nodes7

6.5. Simple guides to functionality 51

Page 56: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Create data in the grid fields

These methods are used to associate data - e.g., elevations, discharge values, flow depths - with the grid object. Severalcan also be used to create new arrays of lengths related to numbers of grid elements (e.g., number of active nodes), butnot to link them to the grid. Data stored inside the grid object allows you to pass this information between componentsmore easily. The data can be accessed by, e.g., mygrid.at_node(‘my_data_name’), or a number of alternative methods(see below).

ModelGrid.create_active_link_array_zeros(name=None)Array, filled with zeros, for a given element.

Returns a 1D numpy array the same length as the number of nodes. If user gives optional argument ‘name’, weadd this data to the grid with the specified name and return a reference to it; otherwise, we just create and returna 1D numpy array.

Parameters name : str

Name of the quantity.

Returns ndarray

The newly created array.

See also:

zeros

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(3, 3)>>> grid.create_active_link_array_zeros()array([ 0., 0., 0., 0.])

ModelGrid.create_node_array_zeros(name=None, **kwds)Return a new array of the given type, filled with zeros.

Returns a 1D numpy array the same length as the number of nodes. If user gives optional argument name, weadd this data to the grid with the specified name and return a reference to it; otherwise, we just create and returna 1D numpy array.

Parameters name : str

Name of the quantity.

Returns ndarray

The newly created array.

See also:

zeros

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4,5)>>> mydata = np.arange(20, dtype=float)>>> rmg.create_node_array_zeros('topographic__elevation')

52 Chapter 6. User Guide

Page 57: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0.])

>>> rmg.at_node['topographic__elevation'] = mydata>>> rmg.at_node['topographic__elevation']array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,

11., 12., 13., 14., 15., 16., 17., 18., 19.])

ModelGrid.empty(**kwds)Returns a numpy array of uninitialized values that is the same length as the number of nodes in the grid. Usethe centering keyword to return an array for other elements of the grid. centering is a string that is one of node,cell, link, or face.

All other keywords are the same as for the numpy zeros function.

ModelGrid.ones(**kwds)Returns a numpy array of ones that is the same length as the number of nodes in the grid. Use the centeringkeyword to return an array for other elements of the grid. centering is a string that is one of node, cell, link, orface.

All other keywords are the same as for the numpy zeros function.

ModelGrid.set_nodata_nodes_to_inactive(node_data, nodata_value)Make no-data nodes inactive.

Set the status to CLOSED_BOUNDARY for all nodes whose value of node_data is equal to the nodata_value.

Note: Deprecated since version 0.6. Deprecated due to out of date terminology; useset_nodata_nodes_to_closed() instead.

Parameters node_data : ndarray

Data values.

nodata_value : float

Value that indicates an invalid value.

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(3, 4, 1.0)>>> mg.node_statusarray([1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1], dtype=int8)>>> h = np.array([-9999,-9999,-9999,-9999,-9999,-9999,12345.,0.,-9999,0.,0.,0.])>>> mg.set_nodata_nodes_to_inactive(h, -9999)>>> mg.node_statusarray([4, 4, 4, 4, 4, 4, 0, 1, 4, 1, 1, 1], dtype=int8)

ModelGrid.zeros(**kwds)Returns a numpy array of zeros that is the same length as the number of nodes in the grid. Use the centeringkeyword to return an array for other elements of the grid. centering is a string that is one of node, cell, link, orface.

All other keywords are the same as for the numpy zeros function.

6.5. Simple guides to functionality 53

Page 58: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

DEM and NetCDF input/output

The landlab/io folder contains the various methods that allow Landlab to ingest DEMs, and to import and exportNetCDF files. i/o with vtk files is also possible, but not detailed here.

read_esri_ascii(asc_file, reshape=False, name=None)Read RasterModelGrid from an ESRI ASCII file.

Read data from asc_file, an ESRI ASCII file, into a RasterModelGrid. asc_file is either the name of thedata file or is a file-like object.

The grid and data read from the file are returned as a tuple (grid, data) where grid is an instance ofRasterModelGrid and data is a numpy array of doubles with that has been reshaped to have the number ofrows and columns given in the header.

Parameters asc_file : str of file-like

Data file to read.

reshape : boolean, optional

Reshape the returned array, otherwise return a flattened array.

name : str, optional

Add data to the grid as a named field.

Returns (grid, data) : tuple

A newly-created RasterModel grid and the associated node data.

read_netcdf(nc_file, just_grid=False)Create a RasterModelGrid from a netcdf file.

Create a new RasterModelGrid from the netcdf file, nc_file. If the netcdf file also contains data, add thatdata to the grid’s fields. To create a new grid without any associated data from the netcdf file, set the just_gridkeyword to True.

Parameters nc_file : str

Name of a netcdf file.

just_grid : boolean, optional

Create a new grid but don’t add value data.

Returns RasterModelGrid

A newly-created RasterModelGrid.

Examples

Import read_netcdf() and the path to an example netcdf file included with landlab.

>>> from landlab.io.netcdf import read_netcdf>>> from landlab.io.netcdf import NETCDF4_EXAMPLE_FILE

Create a new grid from the netcdf file. The example grid is a uniform rectilinear grid with 4 rows and 3 columnsof nodes with unit spacing. The data file also contains data defined at the nodes for the grid for a variable called,surface__elevation.

54 Chapter 6. User Guide

Page 59: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> grid = read_netcdf(NETCDF4_EXAMPLE_FILE)>>> grid.shape == (4, 3)True>>> grid.node_spacing1.0>>> [str(k) for k in grid.at_node.keys()]['surface__elevation']>>> grid.at_node['surface__elevation']array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,

11.])

read_netcdf() will try to determine the format of the netcdf file. For example, the same call will also workfor netcdf3-formatted files.

>>> from landlab.io.netcdf import NETCDF3_64BIT_EXAMPLE_FILE>>> grid = read_netcdf(NETCDF3_64BIT_EXAMPLE_FILE)>>> grid.shape == (4, 3)True>>> grid.node_spacing1.0

write_netcdf(path, fields, attrs=None, append=False, format=’NETCDF3_64BIT’, names=None)Write landlab fields to netcdf.

Write the data and grid information for fields to path as NetCDF. If the append keyword argument in True,append the data to an existing file, if it exists. Otherwise, clobber an existing files.

Parameters path : str

Path to output file.

fields : field-like

Landlab field object that holds a grid and associated values.

append : boolean, optional

Append data to an existing file, otherwise clobber the file.

format : {‘NETCDF3_CLASSIC’, ‘NETCDF3_64BIT’, ‘NETCDF4_CLASSIC’,‘NETCDF4’}

Format of output netcdf file.

attrs : dict

Attributes to add to netcdf file.

names : iterable of str, optional

Names of the fields to include in the netcdf file. If not provided, write all fields.

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> from landlab.io.netcdf import write_netcdf

Create a uniform rectilinear grid with four rows and 3 columns, and add some data fields to it.

6.5. Simple guides to functionality 55

Page 60: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> rmg = RasterModelGrid(4, 3)>>> _ = rmg.add_field('node', 'topographic__elevation', np.arange(12.))>>> _ = rmg.add_field('node', 'uplift_rate', 2. * np.arange(12.))

Create a temporary directory to write the netcdf file into.

>>> import tempfile, os>>> temp_dir = tempfile.mkdtemp()>>> os.chdir(temp_dir)

Write the grid to a netcdf3 file but only include the uplift_rate data in the file.

>>> write_netcdf('test.nc', rmg, format='NETCDF3_64BIT',... names='uplift_rate')

Read the file back in and check its contents.

>>> from scipy.io import netcdf>>> fp = netcdf.netcdf_file('test.nc', 'r')>>> 'uplift_rate' in fp.variablesTrue>>> 'topographic__elevation' in fp.variablesFalse>>> fp.variables['uplift_rate'][:].flatten()array([ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18., 20.,

22.])

Access data in the grid fields

Once you’ve created the fields, these methods can be used to access and modify the data stored in them. Many othermethods are available, see the docstring of base.py.

grid.at_node[’my_data_name’]

grid[’node’][’my_data_name’]

grid.at_node.keys() Get the names of the data fields already stored on nodes in the grid.

(see also entry for ModelGrid.create_node_array_zeros, and the docstrings of the base.py module.)

Resolve, project, and move data between grid element types

These methods allow manipulation of data between links and nodes. e.g., if I have some data defined on the nodes, butI need to use it on the links, these methods may help.

ModelGrid.assign_upslope_vals_to_active_links(u, v=None)Assign upslope node value to link.

Assigns to each active link the value of u at whichever of its neighbors has a higher value of v. If v is omitted,uses u for both. The order of the link values is by link ID.

Parameters u : array-like

Node values to assign to links.

v : array-like, optional

Node values to test for upslope-ness.

Returns ndarray

56 Chapter 6. User Guide

Page 61: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Values at active links.

Examples

>>> from landlab import RasterModelGrid>>> import numpy as np>>> grid = RasterModelGrid(3, 3)>>> u = np.arange(9.)>>> grid.assign_upslope_vals_to_active_links(u)array([ 4., 7., 4., 5.])

ModelGrid.max_of_link_end_node_values(node_data)Maximum value at the end of links.

For each active link, finds and returns the maximum value of node_data at either of the two ends. Use this, forexample, if you want to find the maximum value of water depth at linked pairs of nodes (by passing in an arrayof water depth values at nodes).

Parameters node_data : ndarray

Values at grid nodes.

Returns ndarray :

Maximum values whose length is the number of active links.

Examples

>>> import numpy as np>>> import landlab as ll>>> mg = ll.RasterModelGrid(3, 4, 1.0)>>> h = np.array([2.,2.,8.,0.,8.,0.,3.,0.,5.,6.,8.,3.])>>> mg.max_of_link_end_node_values(h)array([ 2., 8., 6., 8., 8., 3., 3.])

ModelGrid.resolve_values_on_links(link_values, out=None)xy-components of links.

Resolves values provided defined on links into the x and y directions. Returns values_along_x, values_along_y

ModelGrid.resolve_values_on_active_links(link_values, out=None)xy-components of active links.

Resolves values provided defined on active links into the x and y directions. Returns values_along_x, val-ues_along_y

Access information about the grid

These methods allow you to access descriptive data about the grid itself. Note that many of them are properties, soare accessed like grid.my_property, not grid.my_method().

ModelGrid.active_link_lengthReturns the lengths of all active links, in ID order

ModelGrid.axis_nameA tuple of coordinate names for the grid

6.5. Simple guides to functionality 57

Page 62: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

ModelGrid.axis_unitsA tuple of the units (as a string) for each of a grid’s coordinates.

ModelGrid.calculate_numbers_of_node_neighbors()Number of neighbor nodes.

Calculates the number of neighboring nodes for each node, and returns the result as a 1D numpy array. Usedto find the maximum number of neighbors, so that inlink and outlink matrices can be dimensioned accordingly.Assumes that self.number_of_nodes, self.node_at_link_tail, and self.node_at_link_head have already been setup.

Algorithm works by simply looping through all links; for each, the endpoints are neighbors of one another, sowe increment the number of neighbors for both the endpoint nodes.

ModelGrid.cell_areasCell areas.

Returns an array of grid-cell areas.

Note: Sometimes it may make sense for a grid to not always calculate its cell areas but, instead, only calculatethem once they are required. In such cases, the grid class must implement a _setup_cell_areas_array method,which will be called the first time cell areas are requested.

ModelGrid.forced_cell_areasCell areas.

Returns an array of grid cell areas. In the cases of inactive nodes, this method forces the area of those nodes soit can return an nnodes- long array. For a raster, it assumes areas are equal to the normal case.

For a voronoi...?

ModelGrid.link_lengthLengths of grid links.

Lengths of all links, in ID order.

ModelGrid.max_active_link_length()Longest active link.

Returns the horizontal length of the longest active link in the grid.

ModelGrid.min_active_link_length()Shortest active link.

Returns the horizontal length of the shortest active link in the grid.

ModelGrid.ndimNumber of spatial dimensions of the grid

ModelGrid.number_of_active_cellsNumber of active cells in the grid (includes any possible boundary cells)

ModelGrid.number_of_core_cellsNumber of core cells in the grid (excludes all boundary cells).

ModelGrid.number_of_active_facesNumber of active faces in the grid

ModelGrid.number_of_active_linksNumber of active links in the grid

ModelGrid.number_of_active_nodesNumber of active nodes in the grid (i.e., core + open boundary)

58 Chapter 6. User Guide

Page 63: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

ModelGrid.number_of_core_nodesNumber of core nodes in the grid (i.e., not boundaries)

ModelGrid.number_of_cellsTotal number of cells in the grid

ModelGrid.number_of_elements(element_name)Number of instances of an element.

Get the number of instances of a grid element in a grid.

Parameters element_name : {‘node’, ‘cell’, ‘link’, ‘face’, ‘core_node’,

‘core_cell’, ‘active_link’, ‘active_face’} Name of the grid element.

}

Returns int :

Number of elements in the grid.

ModelGrid.number_of_facesTotal number of faces in the grid

ModelGrid.number_of_linksTotal number of links in the grid

ModelGrid.number_of_nodesTotal number of nodes in the grid

RasterModelGrid.d8_active_links()Active links, including diagonals.

Return a set of active links that include diagonal connections between grid cells, for use with link-based water-routing schemes. Diagonal links are listed sequentially after the regular orthogonal links in the return arrays.

Returns tuple of arrays

Tuple of (link_ids, link_from_nodes, link_to_nodes)

Notes

Calling this method also means the the individual arrays of diagonal links and their from- and tonodes are heldas properties of the class instance (see return line below).

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(3, 3)>>> (links, from_nodes, to_nodes) = grid.d8_active_links()>>> linksarray([ 1, 4, 8, 9, 12, 15, 17, 18])>>> from_nodesarray([1, 4, 3, 4, 0, 2, 4, 4])>>> to_nodesarray([4, 7, 4, 5, 4, 4, 6, 8])

RasterModelGrid.dxReturn node spacing in the column direction.

Returns float

6.5. Simple guides to functionality 59

Page 64: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Spacing of node columns.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.dx1.0>>> grid = RasterModelGrid(4, 5, 2.0)>>> grid.dx2.0

RasterModelGrid.get_grid_xdimension()Length of the grid in the x-dimension.

Return the x-dimension of the grid. Because boundary nodes don’t have cells, the dimension of the grid isnum_columns - 1, not num_columns.

Returns float

Length of the grid in the x-dimension.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.get_grid_xdimension()4.0

>>> grid = RasterModelGrid(4, 5, 2.)>>> grid.get_grid_xdimension()8.0

RasterModelGrid.get_grid_ydimension()Length of the grid in the y-dimension.

Return the y-dimension of the grid. Because boundary nodes don’t have cells, the dimension of the grid isnum_rows-1, not num_rows.

Returns float

Length of the grid in the y-dimension.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.get_grid_ydimension()3.0

>>> grid = RasterModelGrid(4, 5, 0.5)>>> grid.get_grid_ydimension()1.5

RasterModelGrid.link_lengthLengths of links.

60 Chapter 6. User Guide

Page 65: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Return the link lengths in the grid, as a nlinks-long array. This method does test if diagonal links are present inthe grid already; if they are, return a longer array where the orthogonal links are listed first, in ID order, then thediagonal links (i.e., diagonal links have effective ID numbers which count up from the number of orthogonallinks).

Returns (4, N) ndarray

Link lengths.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(3, 4)>>> grid.link_lengtharray([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,

1., 1., 1., 1.])

RasterModelGrid.max_active_link_length()Length of longest active link.

Returns the horizontal length of the longest active link in the grid. Overrides Model-Grid.max_active_link_length().

RasterModelGrid.min_active_link_length()Length of shortest active link.

Return the horizontal length of the shortest active link in the grid. Overridesmin_active_link_length().

RasterModelGrid.node_spacingSpacing betweem node rows and columns.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.node_spacing1.0>>> grid = RasterModelGrid(4, 5, 3.0)>>> grid.node_spacing3.0

RasterModelGrid.number_of_interior_nodesNumber of interior nodes.

Returns the number of interior nodes on the grid, i.e., non-perimeter nodes. Compareself.number_of_core_nodes.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.number_of_interior_nodes6

6.5. Simple guides to functionality 61

Page 66: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

RasterModelGrid.number_of_nodesTotal number of nodes.

Returns total number of nodes, including boundaries.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.number_of_nodes20

RasterModelGrid.number_of_node_columnsNumber of node columns.

Returns the number of columns, including boundaries.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.number_of_node_columns5

RasterModelGrid.number_of_node_rowsNumber of node rows.

Returns the number of rows, including boundaries.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.number_of_node_rows4

RasterModelGrid.shapeReturn the shape of the grid.

Returns shape : tuple of ints

The shape of the grid as number of node rows and node columns.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(3, 4)>>> grid.shape(3, 4)

62 Chapter 6. User Guide

Page 67: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Access the grid geometry

These methods give you data about the structural elements of the grid, i.e., nodes, cells, links, faces. This mightinclude their statuses (active/inactive; core/boundary; open/closed; interior/perimeter), their lengths and sizes, andtheir positions.

ModelGrid.node_inlink_matrix = array([], dtype=int32)Nodes on the other end of links pointing into a node.

ModelGrid.node_outlink_matrix = array([], dtype=int32)Nodes on the other end of links pointing out of a node.

ModelGrid.active_linksLink IDs of all active links

ModelGrid.active_link_lengthReturns the lengths of all active links, in ID order

ModelGrid.calculate_numbers_of_node_neighbors()Number of neighbor nodes.

Calculates the number of neighboring nodes for each node, and returns the result as a 1D numpy array. Usedto find the maximum number of neighbors, so that inlink and outlink matrices can be dimensioned accordingly.Assumes that self.number_of_nodes, self.node_at_link_tail, and self.node_at_link_head have already been setup.

Algorithm works by simply looping through all links; for each, the endpoints are neighbors of one another, sowe increment the number of neighbors for both the endpoint nodes.

ModelGrid.closed_boundary_nodesNode id of all closed boundary nodes.

ModelGrid.core_cell_index_at_nodesCore cell ID associated with grid nodes.

ModelGrid.core_nodesNode IDs of all core nodes.

ModelGrid.get_active_cell_node_ids()Nodes of active cells.

Return an integer vector of the node IDs of all active (i.e., core + open boundary) cells.

See also:

get_core_cell_node_ids may be preferable.

ModelGrid.get_active_link_connecting_node_pair(node1, node2)Returns the ID number of the active link that connects the given pair of nodes, or BAD_INDEX_VALUE if notfound. This method is slow, and can only take single ints as node1 and node2. It should ideally be overriddenfor optimal functionality in more specialized grid modules (e.g., raster).

Examples

>>> import landlab as ll>>> rmg = ll.RasterModelGrid(4, 5)>>> rmg.get_active_link_connecting_node_pair(8, 3)array([2])

6.5. Simple guides to functionality 63

Page 68: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

ModelGrid.get_boundary_nodes()Boundary nodes of a grid.

Gat ids of all open and closed boundary nodes in the grid.

Returns ndarray

IDs of boundary nodes.

ModelGrid.get_core_nodes()Node IDs of core nodes.

Returns ndarray

Node IDs of all of a grid’s core nodes.

ModelGrid.get_node_status(*args, **kwds)Status of grid nodes.

Returns ndarray

Node status of all a grid’s nodes.

ModelGrid.link_lengthLengths of grid links.

Lengths of all links, in ID order.

ModelGrid.is_boundary(ids, boundary_flag=None)Check if nodes are boundary nodes.

Check if nodes at given ids are boundary nodes. Use the boundary_flag to specify a particular boundary typestatus flag.

Parameters ids : ndarray

Node IDs to check.

boundary_flag : int, optional

A boundary type to check for.

Returns ndarray

Array of booleans indicating if nodes are boundary nodes.

ModelGrid.node_axis_coordinates(*args, **kwds)Coordinates of nodes along a particular axis.

Return node coordinates from a given axis (defaulting to 0). Axis numbering is the same as that for numpyarrays. That is, the zeroth axis is along the rows, and the first along the columns.

Parameters axis : int, optional

Coordinate axis.

Returns ndarray

Coordinates of nodes for a given axis.

ModelGrid.node_boundary_statusBoundary status of nodes.

Return an array of the status of a grid’s nodes. The node status can be one of the following: - CORE_NODE- FIXED_VALUE_BOUNDARY - FIXED_GRADIENT_BOUNDARY ‘ - ‘TRACKS_CELL_BOUNDARY -‘CLOSED_BOUNDARY ‘

64 Chapter 6. User Guide

Page 69: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

ModelGrid.node_xX-coordinates of all nodes.

ModelGrid.node_yY-coordinates of all nodes.

ModelGrid.open_boundary_nodesNode id of all open boundary nodes.

RasterModelGrid.are_all_core(ids)Check if nodes are all core.

Returns a single boolean truth value, True if all nodes with IDs are core nodes, False if not.

Parameters ids : array-like

Grid nodes.

Returns boolean

True if all the given nodes are core nodes.

RasterModelGrid.bottom_edge_node_ids()Nodes along the bottom edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the bottom (y=0) gridedge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.bottom_edge_node_ids()array([0, 1, 2, 3, 4])

RasterModelGrid.cell_faces([cell_id ])Faces of a cell.

Return an array of the face IDs for the faces of a cell with ID, cell_id. The faces are listed clockwise, startingwith the bottom face. cell_id can be either a scalar or an array. If an array, return the faces for each cell of thearray.

Parameters cell_id : array_like

Grid cell ids.

Returns (N, 4) ndarray

Face IDs

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5)>>> rmg.cell_faces(0)array([ 0, 9, 3, 10])

>>> rmg.cell_faces([0, 5])array([[ 0, 9, 3, 10],

[ 5, 15, 8, 16]])

6.5. Simple guides to functionality 65

Page 70: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> rmg.cell_faces()array([[ 0, 9, 3, 10],

[ 1, 10, 4, 11],[ 2, 11, 5, 12],[ 3, 13, 6, 14],[ 4, 14, 7, 15],[ 5, 15, 8, 16]])

RasterModelGrid.corner_nodesNodes in grid corners.

Return the IDs to the corner nodes of the grid, sorted by ID.

Returns (4, ) ndarray

Array of corner node IDs.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(4, 5)>>> grid.corner_nodesarray([ 0, 4, 15, 19])

RasterModelGrid.create_diagonal_list(bad_index=2147483647)Create list of diagonal node IDs.

Creates a list of IDs of the diagonal nodes to each node, as a 2D array. Only interior nodes are assigned diagonalneighbors; boundary nodes get -1 for each neighbor. The order of the diagonal nodes is [topright, topleft,bottomleft, bottomright].

Note: This is equivalent to the diagonals of all cells, and setting the neighbors of boundary-node cells to -1. Insuch a case, each node has one cell and each node-cell pair have the same ID. However, this is the old-style gridstructure as boundary nodes no longer have associated cells.

DEJH: As of 6/12/14, this method now uses BAD_INDEX_VALUE, and boundary nodes now have neighbors,where they are found at the ends of active links.

RasterModelGrid.create_neighbor_list(bad_index=2147483647)Create list of neighbor node IDs.

Creates a list of IDs of neighbor nodes for each node, as a 2D array. Only record neighbor nodes that are on theother end of an active link. Nodes attached to inactive links or neighbor nodes that would be outside of the gridare given an ID of BAD_INDEX_VALUE.

Neighbors are ordered as [right, top, left, bottom].

RasterModelGrid.face_links([face_id ])Links associated with faces.

Returns an array of the link IDs for the links which intersect the faces specificed by face_id. face_id can beeither a scalar or an array.

Parameters face_id : int

Face of a cell.

66 Chapter 6. User Guide

Page 71: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(4, 5)>>> mg.face_links(0)array([1])

>>> mg.face_links([0, 4, 13])array([ 1, 7, 23])

RasterModelGrid.get_active_link_connecting_node_pair(node1, node2)Returns the ID number of the active link that connects the given pair of nodes, or BAD_INDEX_VALUE if notfound. This method is slow, and can only take single ints as node1 and node2. It should ideally be overriddenfor optimal functionality in more specialized grid modules (e.g., raster).

Examples

>>> import landlab as ll>>> rmg = ll.RasterModelGrid(4, 5)>>> rmg.get_active_link_connecting_node_pair(8, 3)array([2])

RasterModelGrid.get_diagonal_list([ids], bad_index=BAD_INDEX_VALUE)Get list of diagonal node IDs.

Return lists of diagonals nodes for nodes with given ids. If ids is not given, return the diagonals for all of thenodes in the grid. For each node, the list gives diagonal ids as [topright, topleft, bottomleft, bottomright]. Setall diagonals for boundary nodes to -1.

Examples

>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(4, 5)>>> mg.get_diagonal_list([-1, 6])array([[2147483647, 2147483647, 13, 2147483647],

[ 12, 10, 0, 2]])>>> mg.get_diagonal_list(7)array([13, 11, 1, 3])

..todo: could use inlink_matrix, outlink_matrix

RasterModelGrid.get_face_connecting_cell_pair(cell_a, cell_b)Returns an array of face indices that cell_a and cell_b share. If the cells do not share any faces, returns an emptyarray.

RasterModelGrid.get_link_connecting_node_pair(node_a, node_b)Get the link that connects two nodes.

Returns the link ID that connects node_a and node_b. If the nodes do not share any links, raises ValueError.

Parameters node_a : int

Node ID

node_b : int

Node ID

6.5. Simple guides to functionality 67

Page 72: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Returns ndarray

Links that connect the nodes pairs.

Raises ValueError

If the given nodes are not connected by a link or the nodes are the same.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid((4, 5))

Nodes 6 and 7 are connected by link 20.

>>> rmg.get_link_connecting_node_pair(6, 7)20

Nodes 6 and 8 are not connected by a link, so raise an exception.

>>> rmg.get_link_connecting_node_pair(6, 8)Traceback (most recent call last):ValueError: disconnected nodes

If node_a and node_b are the same node, also raise a ValueError.

>>> rmg.get_link_connecting_node_pair(6, 6)Traceback (most recent call last):ValueError: nodes are the same

RasterModelGrid.get_neighbor_list([ids], bad_index=BAD_INDEX_VALUE)Get list of neighbor node IDs.

Return lists of neighbor nodes for nodes with given ids. If ids is not given, return the neighbors for all of thenodes in the grid. For each node, the list gives neighbor ids as [right, top, left, bottom]. Boundary nodes receivetheir actual neighbors (see example below); references to positions which are off the grid from boundary nodesreceive BAD_INDEX_VALUE. Only nodes which can be reached along an active link are returned, otherwiseagain we get BAD_INDEX_VALUE.

Parameter bad_index can be used to override the grid default for the BAD_INDEX_VALUE.

Examples

>>> from landlab.grid.base import BAD_INDEX_VALUE as X>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(4, 5)>>> np.all(mg.get_neighbor_list([-1, 6, 2]) == np.array([[X, X, X, X], [ 7, 11, 5, 1], [X, 7, X, X]]))True>>> mg.get_neighbor_list(7)array([ 8, 12, 6, 2])

..todo: could use inlink_matrix, outlink_matrix

RasterModelGrid.grid_coords_to_node_id(row, col, **kwds)Convert node indices to node ID.

Returns the ID of the node at the specified row and col of the raster grid. Since this is a wrapper for the numpyravel_multi_index function, the keyword arguments are the same as that function. In addition, row and col canboth be either scalars or arrays (of the same length) to get multiple ids.

68 Chapter 6. User Guide

Page 73: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

As with ravel_multi_index use the mode keyword to change the behavior of the method when passed an out-of-range row or col. The default is to raise ValueError (not IndexError, as you might expect).

Note: The syntax assumes that first row and column are 0, so max entry for a mg with 4 rows and 5 cols isrow=3, col=4

Parameters row : array-like

Row of node.

col : array-like

Column of node.

Returns ndarray

Node IDs.

Examples

>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(4, 5)>>> mg.grid_coords_to_node_id(2, 3)13

>>> mg.grid_coords_to_node_id([2, 0], [3, 4])array([13, 4])

RasterModelGrid.has_boundary_neighbor(ids)Checks to see if one of the eight neighbor nodes of node(s) with id has a boundary node. Returns True if a nodehas a boundary node, False if all neighbors are interior.

Examples

>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(5, 5)>>> mg.has_boundary_neighbor(6)True>>> mg.has_boundary_neighbor(12)False>>> mg.has_boundary_neighbor([12, -1])array([False, True], dtype=bool)

>>> mg.has_boundary_neighbor(25)Traceback (most recent call last):

...IndexError: index 25 is out of bounds for axis 0 with size 25

RasterModelGrid.is_core([ids])Check if a node is a core node.

Returns an boolean array of truth values for each node ID provided; True if the node is a core node, Falseotherwise. If no IDs are provided, method returns a boolean array for every node.

(Core status is typically indicated by a value of 0 in node_status.)

6.5. Simple guides to functionality 69

Page 74: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

RasterModelGrid.left_edge_node_ids()Nodes along the left edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the left (x=0) grid edge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.left_edge_node_ids()array([ 0, 5, 10, 15])

RasterModelGrid.link_faces([link_id ])Faces associated with links.

Return an array of the face IDs for the faces that intersect the links specified by link_id. link_id can be either ascalar or array. If link_id is not given, return the faces of all links.

If a link does not have an associated face (e.g., some inactive links), that entry in the returned array is set toBAD_INDEX_VALUE.

Parameters link_id : array-like, optional

Grid links.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5)>>> rmg.link_faces(2)1>>> rmg.link_faces([0, 1, 15, 19, 12, 26])array([2147483647, 0, 2147483647, 9, 7,

16])

RasterModelGrid.node_activelinks([node_ids])Active links of a node.

Parameters node_ids : int or list of ints

ID(s) of node(s) for which to find connected active links

Returns (4, N) ndarray

The ids of active links attached to grid nodes with node_ids. If node_ids is not given,return links for all of the nodes in the grid. Link ids are listed in clockwise order startingwith the south link. Diagonal links are never returned.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(3, 4)>>> rmg.node_links(5)array([[ 1],

[11],[ 5],[12]])

70 Chapter 6. User Guide

Page 75: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> rmg.node_activelinks((5, 6))array([[0, 1],

[4, 5],[2, 3],[5, 6]])

>>> rmg.node_activelinks()array([[-1, -1, -1, -1, -1, 0, 1, -1, -1, 2, 3, -1],

[-1, -1, -1, -1, -1, 4, 5, 6, -1, -1, -1, -1],[-1, 0, 1, -1, -1, 2, 3, -1, -1, -1, -1, -1],[-1, -1, -1, -1, 4, 5, 6, -1, -1, -1, -1, -1]])

RasterModelGrid.node_links([node_ids])Links attached to nodes.

Returns the ids of links attached to grid nodes with node_ids. If node_ids is not given, return links for all ofthe nodes in the grid. Link ids are listed in clockwise order starting with the south link (i.e., [S,W,N,E]). Thismethod will not return diagonal links, even if they exist. They need to be handled independently.

Parameters node_ids : array_like, optional

IDs of nodes on a grid.

Returns (4, N) ndarray

Neighbor node IDs for the source nodes.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(3, 4)>>> grid.node_links(5)array([[ 1],

[11],[ 5],[12]])

>>> grid.node_links((5, 6))array([[ 1, 2],

[11, 12],[ 5, 6],[12, 13]])

>>> grid.node_links()array([[-1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7],

[-1, 8, 9, 10, -1, 11, 12, 13, -1, 14, 15, 16],[ 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, -1],[ 8, 9, 10, -1, 11, 12, 13, -1, 14, 15, 16, -1]])

RasterModelGrid.right_edge_node_ids()Nodes along the right edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the right (x=xmax) gridedge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)

6.5. Simple guides to functionality 71

Page 76: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> rmg.right_edge_node_ids()array([ 4, 9, 14, 19])

RasterModelGrid.top_edge_node_ids()Nodes along the top edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the top (y=ymax) gridedge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.top_edge_node_ids()array([15, 16, 17, 18, 19])

Link coordinates and distances to nodes

These methods are focused on the specifically spatial relationships between grid elements. e.g., Where in x,y space ismy element? How far is it from one node to another?

ModelGrid.build_all_node_distances_azimuths_maps()Build distance-azimuth maps.

This function creates and stores in the grid field two nnodes*nnodes arrays that map the distances and azimuthsof all nodes in the grid to all nodes in the grid.

This is useful if your module needs to make repeated lookups of distances between the same nodes, but doespotentially use up a lot of memory so should be used with caution.

The map is symmetrical, so it does not matter whether rows are “from” or “to”.

The arrays are called:

• self.all_node_distances_map

• self.all_node_azimuths_map

Returns tuple of ndarrays

Tuple of (distances, azimuths)

ModelGrid.get_distances_of_nodes_to_point(tuple_xy, get_az=None, node_subset=nan,out_distance=None, out_azimuth=None)

Returns an array of distances for each node to a provided point. If “get_az” is set to ‘angles’, returns both thedistance array and an array of azimuths from up/north. If it is set to ‘displacements’, it returns the azimuths as a2xnnodes array of x and y displacements. If it is not set, returns just the distance array. If “node_subset” is setas an ID, or list/array/etc of IDs method returns just the distance (and optionally azimuth) for that node. Pointis provided as a tuple (x,y). If out_distance (& out_azimuth) are provided, these arrays are used to store theoutputs. This is recommended for memory management reasons if you are working with node subsets.

*Developer’s note* Once you start working with node subsets in Landlab, which can change size betweenloops, it’s quite possible for Python’s internal memory management to crap out after large numbers of loops(~>10k). This is to do with the way it block allocates memory for arrays of differing lengths, then cannotfree this memory effectively. The solution - as implemented here - is to pre-allocate all arrays as nnodes long,then only work with the first [len_subset] entries by slicing (in a pseudo-C-style). Care has to be taken not to

72 Chapter 6. User Guide

Page 77: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

“accidentally” allow Python to allocate a new array you don’t have control over. Then, to maintain efficientmemory allocation, we create some “dummy” nnode-long arrays to store intermediate parts of the solution in.

ModelGrid.node_axis_coordinates(*args, **kwds)Coordinates of nodes along a particular axis.

Return node coordinates from a given axis (defaulting to 0). Axis numbering is the same as that for numpyarrays. That is, the zeroth axis is along the rows, and the first along the columns.

Parameters axis : int, optional

Coordinate axis.

Returns ndarray

Coordinates of nodes for a given axis.

ModelGrid.node_xX-coordinates of all nodes.

ModelGrid.node_yY-coordinates of all nodes.

RasterModelGrid.find_nearest_node(coords, mode=’raise’)Node nearest a point.

Find the index to the node nearest the given x, y coordinates. Coordinates are provided as numpy arrays in thecoords tuple.

Use the mode keyword to specify what to do if the given coordinates are out-of-bounds. Seenp.ravel_multi_index() for a description of possible values for mode. Note that a coordinate is out-of-bounds if it is beyond one half the node spacing from the exterior nodes.

Returns the indices of the nodes nearest the given coordinates.

Parameters coords : tuple of array-like

Coordinates of points.

mode : {‘raise’, ‘wrap’, ‘clip’}, optional

What to do if a point is off the grid.

Returns array-like

IDs of the nearest nodes.

Notes

For coordinates that are equidistant to two or more nodes, see the rounding rules for numpy.around().

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5)>>> rmg.find_nearest_node([0.2, 0.2])0>>> rmg.find_nearest_node((np.array([1.6, 3.6]), np.array([2.3, .7])))array([12, 9])>>> rmg.find_nearest_node((-.4999, 1.))5

6.5. Simple guides to functionality 73

Page 78: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

RasterModelGrid.get_nodes_around_point(xcoord, ycoord)Nodes surrounding a point.

Return IDs of the four nodes of the area around a point with coordinates xcoord, ycoord. Node IDs are returnedcounter-clockwise order starting from the southwest node.

If either xcoord or ycoord are arrays the usual numpy broadcasting rules apply.

Parameters xcoord : float, array-like

x-coordinate of point

ycoord : float, array-like

y-coordinate of point

Returns (4, N) ndarray

IDs of nodes around the point.

Examples

>>> from landlab import RasterModelGrid>>> grid = RasterModelGrid(3, 4)>>> grid.get_nodes_around_point(.4, 1.2)array([4, 8, 9, 5])

>>> grid.get_nodes_around_point([.9, 1.1], 1.2)array([[ 4, 5],

[ 8, 9],[ 9, 10],[ 5, 6]])

RasterModelGrid.grid_coords_to_node_id(row, col, **kwds)Convert node indices to node ID.

Returns the ID of the node at the specified row and col of the raster grid. Since this is a wrapper for the numpyravel_multi_index function, the keyword arguments are the same as that function. In addition, row and col canboth be either scalars or arrays (of the same length) to get multiple ids.

As with ravel_multi_index use the mode keyword to change the behavior of the method when passed an out-of-range row or col. The default is to raise ValueError (not IndexError, as you might expect).

Note: The syntax assumes that first row and column are 0, so max entry for a mg with 4 rows and 5 cols isrow=3, col=4

Parameters row : array-like

Row of node.

col : array-like

Column of node.

Returns ndarray

Node IDs.

74 Chapter 6. User Guide

Page 79: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(4, 5)>>> mg.grid_coords_to_node_id(2, 3)13

>>> mg.grid_coords_to_node_id([2, 0], [3, 4])array([13, 4])

RasterModelGrid.is_point_on_grid(xcoord, ycoord)Check if a point is on a grid.

This method takes x, y coordinates and tests whether they lie within the grid. The limits of the grid are taken tobe links connecting the boundary nodes. We perform a special test to detect looped boundaries.

Coordinates can be ints or arrays of ints. If arrays, will return an array of the same length of boolean truthvalues.

Derive offsets, gradients, flux divergences, and steepest descents

These methods allow calculation of derivatives, divergences, and steepest paths through data defined on the grid.

ModelGrid.calculate_diff_at_links(*args, **kwds)Differences at links.

Calculates the difference in quantity node_values at every link in the grid. Note that this is tonode-fromnodealong links, and is thus equivalent to positive gradient up.

Parameters node_values : ndarary

Values at grid nodes.

Returns ndarray

Differences over links.

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(3, 3)>>> z = np.zeros(9.)>>> z[4] = 1.>>> rmg.calculate_diff_at_links(z)array([ 0., 1., 0., 0., -1., 0., 0., 0., 1., -1., 0., 0.])

ModelGrid.calculate_diff_at_active_links(*args, **kwds)Differences at active links.

Calculates the difference in quantity node_values at each active link in the grid. Note that this is tonode-fromnode along links, and is thus equivalent to positive gradient up.

ModelGrid.calculate_flux_divergence_at_core_nodes(active_link_flux,net_unit_flux=None)

Flux divergence for core nodes.

Given an array of fluxes along links, computes the net total flux within each cell, divides by cell area, and storesthe result in net_unit_flux.

6.5. Simple guides to functionality 75

Page 80: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

The function works by calling calculate_flux_divergence_at_nodes, then slicing out only the values at corenodes. Therefore, it is slower than calculate_flux_divergence_at_nodes, even though it returns a shorter list ofnumbers.

The input active_link_flux should be flux of something (e.g., mass, momentum, energy) per unit face width,positive if flowing in the same direction as its link, and negative otherwise. There should be one value per activelink. Returns an array of net total flux per unit area, one value per core node (creates this array if it is not givenas an argument).

By convention, divergence is positive for net outflow, and negative

for net outflow. That’s why we add outgoing flux and subtract incoming flux. This makes net_unit_flux havethe same sign and dimensions as a typical divergence term in a conservation equation.

In general, for a polygonal cell with $N$ sides of lengths Li and with surface area A, the net influx divided bycell area would be:

𝑄𝑛𝑒𝑡

𝐴=

1

𝐴

∑︁𝑞𝑖𝐿𝑖

For a square cell, which is what we have in RasterModelGrid, the sum is over 4 sides of length dx, and 𝐴 = 𝑑𝑥2,so:

𝑄𝑛𝑒𝑡

𝐴=

1

𝑑𝑥

∑︁𝑞𝑖

Note: The net flux is defined as positive outward, negative inward. In a diffusion problem, for example, onewould use:

𝑑𝑢

𝑑𝑡= source − fd

where fd is “flux divergence”.

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> u = [0., 1., 2., 3., 0.,... 1., 2., 3., 2., 3.,... 0., 1., 2., 1., 2.,... 0., 0., 2., 2., 0.]>>> u = np.array(u)>>> grad = rmg.calculate_gradients_at_active_links(u)>>> gradarray([ 1., 1., -1., -1., -1., -1., -1., 0., 1., 1., 1., -1., 1.,

1., 1., -1., 1.])>>> flux = -grad # downhill flux proportional to gradient>>> divflux = rmg.calculate_flux_divergence_at_core_nodes(flux)>>> divfluxarray([ 2., 4., -2., 0., 1., -4.])

76 Chapter 6. User Guide

Page 81: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

If calculate_gradients_at_core_nodes is called inside a loop, you can improve speed slightly by creating an arrayoutside the loop. For example, do this once, before the loop:

>>> divflux = rmg.zeros(centering='core_cell') # outside loop

Then do this inside the loop:

>>> divflux = rmg.calculate_flux_divergence_at_core_nodes(flux, divflux)

In this case, the function will not have to create the divflux array.

Note this method is untested with looped boundary conditions.

ModelGrid.calculate_flux_divergence_at_nodes(*args, **kwds)Flux divergence at nodes.

Same as calculate_flux_divergence_at_active_cells, but works with and returns a list of net unit fluxes thatcorresponds to all nodes, rather than just active cells.

Note that we don’t compute net unit fluxes at boundary nodes (which don’t have active cells associated withthem, and often don’t have cells of any kind, because they are on the perimeter), but simply return zeros forthese entries. The advantage is that the caller can work with node-based arrays instead of active-cell-basedarrays.

This method is untested with looped boundary conditions.

ModelGrid.calculate_gradients_at_links(*args, **kwds)Gradients at links.

Calculates the gradient in quantity node_values at every link in the grid. This method follows the conventionPOSITIVE UP.

ModelGrid.calculate_gradients_at_active_links(*args, **kwds)Gradients at active links.

Calculates the gradient in quantity node_values at each active link in the grid. This method follows the conven-tion POSITIVE UP.

RasterModelGrid.calculate_flux_divergence_at_nodes(*args, **kwds)Flux divergence at nodes.

Same as calculate_flux_divergence_at_active_cells, but works with and returns a list of net unit fluxes thatcorresponds to all nodes, rather than just active cells.

Note that we DO compute net unit fluxes at boundary nodes (even though these don’t have active cells associatedwith them, and often don’t have cells of any kind, because they are on the perimeter). It’s up to the user to decidewhat to do with these boundary values.

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> u = [0., 1., 2., 3., 0.,... 1., 2., 3., 2., 3.,... 0., 1., 2., 1., 2.,... 0., 0., 2., 2., 0.]>>> u = np.array(u)>>> grad = rmg.calculate_gradients_at_active_links(u)>>> gradarray([ 1., 1., -1., -1., -1., -1., -1., 0., 1., 1., 1., -1., 1.,

6.5. Simple guides to functionality 77

Page 82: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

1., 1., -1., 1.])>>> flux = -grad # downhill flux proportional to gradient>>> df = rmg.calculate_flux_divergence_at_nodes(flux)>>> dfarray([ 0., -1., -1., 1., 0., -1., 2., 4., -2., 1., -1., 0., 1.,

-4., 1., 0., -1., 0., 1., 0.])

If calculate_gradients_at_nodes is called inside a loop, you can improve speed by creating an array outside theloop. For example, do this once, before the loop:

>>> df = rmg.zeros(centering='node') # outside loop>>> rmg.number_of_nodes20

Then do this inside the loop:

>>> df = rmg.calculate_flux_divergence_at_nodes(flux, df)

In this case, the function will not have to create the df array.

RasterModelGrid.calculate_gradient_across_cell_faces(node_values[, cell_ids],out=None)

Gradient of a quantity cell faces.

Calculate the slopes of node_values, given at every node in the grid, relative to the nodes centered at cell_ids.Note that upward slopes are reported as positive. That is, the gradient is positive if a neighbor node’s value isgreater than that of the node as cell_ids.

If cell_ids is not provided, calculate the gradients for all cells in the grid.

Use the out keyword if you have an array that you want to put the result into. If not given, create and return anew array.

Returns the gradients of the neighboring links in the order (right, top, left, bottom).

RasterModelGrid.calculate_gradient_across_cell_corners(node_values[, cell_ids],out=None)

Gradient of a quantity across diagonals.

Calculate the slopes of node_values, given at every node in the grid, relative to the nodes centered at cell_ids.Note that upward slopes are reported as positive. That is, the gradient is positive if a neighbor node’s value isgreater than that of the node as cell_ids.

If cell_ids is not provided, calculate the gradients for all cells in the grid.

Use the out keyword if you have an array that you want to put the result into. If not given, create and return anew array.

Returns the gradients of the neighboring links in the order (topright, topleft, bottomleft, bottomright).

RasterModelGrid.calculate_steepest_descent_across_adjacent_cells(node_values[,cell_ids],method=’d4’,re-turn_node=False,out=None)

Steepest gradient to adjoining nodes.

Calculate the steepest downward slopes, i.e., the most negative gradients, of node_values, given at every nodein the grid, relative to the nodes centered at cell_ids. Return those (negative) gradients. Note that upward slopesare reported as positive. That is, the gradient is positive if a neighbor node’s value is greater than that of thenode as cell_ids. This method handles both orthogonal and diagonal neighbors.

78 Chapter 6. User Guide

Page 83: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

If cell_ids is not provided, calculate the minimum gradient for all cells in the grid. Note this is a cell ID, not anode ID.

The default is to only consider neighbor cells to the north, south, east, and west. To also consider gradients todiagonal nodes, set the method keyword to d8 (the default is d4).

Use the out keyword if you have an array that you want to put the result into. If not given, create a new array.

Use the return_node keyword to also the node id of the node in the direction of the steepest slope. In this case,the returned object is a length 2 tuple of the two arrays, (gradients, node_IDs).

Parameters node_values : array-like

Node quantities to take gradient of.

cell_ids : array-like, optional

Cell at which to calculate gradients.

return_node : boolean, optional

If True also return node ID to the steepest gradient.

out : array_like, optional

Alternative output array in which to place the result. Must be of the same shape andbuffer length as the expected output.

See also:

calculate_steepest_descent_across_cell_corners just diagonals

calculate_steepest_descent_across_cell_faces just neighbors

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 4)>>> node_values = rmg.zeros()>>> node_values[1] = -1>>> rmg.calculate_steepest_descent_across_adjacent_cells(node_values, 0)masked_array(data = [-1.],

mask = False,fill_value = 1e+20)

Get both the maximum gradient and the node to which the gradient is measured.

>>> rmg.calculate_steepest_descent_across_adjacent_cells(node_values, 0, return_node=True)(array([-1.]), array([1]))

Use method to choose which neighbors to consider.

>>> node_values[0] = -10.>>> node_values[1] = -1.>>> rmg.calculate_steepest_descent_across_adjacent_cells(node_values, 0, method='d4', return_node=True)(array([-1.]), array([1]))>>> rmg.calculate_steepest_descent_across_adjacent_cells(node_values, 0, method='d8', return_node=True)(array([-7.07106781]), array([0]))

6.5. Simple guides to functionality 79

Page 84: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

RasterModelGrid.calculate_steepest_descent_across_cell_corners(node_values[,cell_ids], re-turn_node=False,out=None)

Steepest gradient to diagonal nodes.

Return the steepest descents, i.e., minimum gradients, across diagonal cells.

Calculate the gradients of node_values, given at every node in the grid, relative to the nodes centered at cell_ids.Note that upward slopes are reported as positive. That is, the gradient is positive if a neighbor node’s value isgreater than that of the node as cell_ids.

If cell_ids is not provided, calculate the minimum gradient for all cells in the grid.

Use the out keyword if you have an array that you want to put the result into. If not given, create and return anew array.

Use the return_node keyword to also return the node id of the node in the direction of the maximum gradient.In this case, the returned object is a length 2 tuple of the two arrays, (gradients, node_IDs).

Parameters node_values : array-like

Node quantities to take gradient of.

cell_ids : array-like, optional

Cell at which to calculate gradients.

return_node : boolean, optional

If True also return node ID to the steepest gradient.

out : array_like, optional

Alternative output array in which to place the result. Must be of the same shape andbuffer length as the expected output.

See also:

calculate_steepest_descent_across_adjacent_cells neighbors, including diagonals

calculate_steepest_descent_across_cell_faces just neighbors

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(3, 3)>>> node_values = rmg.zeros()>>> node_values[0] = -1>>> rmg.calculate_steepest_descent_across_cell_corners(node_values, 0)array([-0.70710678])

Get both the maximum gradient and the node to which the gradient is measured.

>>> rmg.calculate_steepest_descent_across_cell_corners(node_values, 0, return_node=True)(array([-0.70710678]), array([0]))

RasterModelGrid.calculate_steepest_descent_across_cell_faces(node_values[,cell_ids], re-turn_node=False,out=None)

Steepest gradient to neighbor nodes.

80 Chapter 6. User Guide

Page 85: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Return the steepest downward slopes across cell faces, i.e., only to the orthogonal nodes, ignoring any diagonals.

Calculate the gradients of node_values, given at every node in the grid, relative to the nodes centered at cell_ids.Note that upward slopes are reported as positive. That is, the gradient is positive if a neighbor node’s value isgreater than that of the node as cell_ids. Thus, the gradients reported by this method are likely negative.

If cell_ids is not provided, calculate the steepest slope (most negative gradient) for all cells in the grid.

Use the out keyword if you have an array that you want to put the result into. If not given, create and return anew array.

Use the return_node keyword to also return the node id of the node in the direction of the maximum gradient.In this case, the returned object is a length 2 tuple of the two arrays, (gradients, node_IDs).

Parameters node_values : array-like

Node quantities to take gradient of.

cell_ids : array-like, optional

Cell at which to calculate gradients.

return_node : boolean, optional

If True also return node ID to the steepest gradient.

out : array_like, optional

Alternative output array in which to place the result. Must be of the same shape andbuffer length as the expected output.

See also:

calculate_steepest_descent_across_adjacent_cells neighbors, including diagonals

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(3, 3)>>> node_values = rmg.zeros()>>> node_values[1] = -1>>> rmg.calculate_steepest_descent_across_cell_faces(node_values, 0)masked_array(data = [-1.],

mask = False,fill_value = 1e+20)

Get both the maximum gradient and the node to which the gradient is measured.

>>> rmg.calculate_steepest_descent_across_cell_faces(node_values, 0, return_node=True)(array([-1.]), array([1]))

Control boundary conditions

These methods allow explicit control of the boundary nodes in the grid, and their properties. Note that boundarycondition handling may change somewhat in future development, in particular improving functionality for Voronoigrids and rasters with non-perimeter boundary nodes.

ModelGrid.closed_boundary_nodesNode id of all closed boundary nodes.

6.5. Simple guides to functionality 81

Page 86: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

ModelGrid.core_nodesNode IDs of all core nodes.

ModelGrid.get_boundary_nodes()Boundary nodes of a grid.

Gat ids of all open and closed boundary nodes in the grid.

Returns ndarray

IDs of boundary nodes.

ModelGrid.get_node_status(*args, **kwds)Status of grid nodes.

Returns ndarray

Node status of all a grid’s nodes.

ModelGrid.is_boundary(ids, boundary_flag=None)Check if nodes are boundary nodes.

Check if nodes at given ids are boundary nodes. Use the boundary_flag to specify a particular boundary typestatus flag.

Parameters ids : ndarray

Node IDs to check.

boundary_flag : int, optional

A boundary type to check for.

Returns ndarray

Array of booleans indicating if nodes are boundary nodes.

ModelGrid.node_boundary_statusBoundary status of nodes.

Return an array of the status of a grid’s nodes. The node status can be one of the following: - CORE_NODE- FIXED_VALUE_BOUNDARY - FIXED_GRADIENT_BOUNDARY ‘ - ‘TRACKS_CELL_BOUNDARY -‘CLOSED_BOUNDARY ‘

ModelGrid.open_boundary_nodesNode id of all open boundary nodes.

ModelGrid.set_closed_nodes(nodes)Make nodes closed boundaries.

Sets the given nodes’ boundary condition statuses to CLOSED (==4), and resets the list of active links to reflectany changes.

ModelGrid.set_nodata_nodes_to_closed(node_data, nodata_value)Make no-data nodes closed boundaries.

Sets self.node_status to CLOSED_BOUNDARY for all nodes whose value of node_data is equal to the no-data_value.

Parameters node_data : ndarray

Data values.

nodata_value : float

Value that indicates an invalid value.

82 Chapter 6. User Guide

Page 87: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> import numpy as np>>> import landlab as ll>>> mg = ll.RasterModelGrid(3, 4, 1.0)>>> mg.node_statusarray([1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1], dtype=int8)>>> h = np.array([-9999,-9999,-9999,-9999,-9999,-9999,12345.,0.,-9999,0.,0.,0.])>>> mg.set_nodata_nodes_to_closed(h, -9999)>>> mg.node_statusarray([4, 4, 4, 4, 4, 4, 0, 1, 4, 1, 1, 1], dtype=int8)

ModelGrid.update_links_nodes_cells_to_new_BCs()Update grid element connectivity, status.

This method updates all of the various lists and attributes governed by node status (e.g., core nodes, active links,etc) when you change node statuses. Call it if your method or driver makes changes to the boundary conditionsof nodes in the grid.

RasterModelGrid.are_all_core(ids)Check if nodes are all core.

Returns a single boolean truth value, True if all nodes with IDs are core nodes, False if not.

Parameters ids : array-like

Grid nodes.

Returns boolean

True if all the given nodes are core nodes.

RasterModelGrid.bottom_edge_node_ids()Nodes along the bottom edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the bottom (y=0) gridedge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.bottom_edge_node_ids()array([0, 1, 2, 3, 4])

RasterModelGrid.force_boundaries_from_gradients(link_IDs, link_gradients,value=’topographic__elevation’)

Set values of fixed-gradient boundaries.

Calculates and updates new values at the boundary nodes of a grid, when provided with a list of fixed gradientlink IDs, and the fixed values of the gradients on these links.

The “value” flag specifies which kind of data (e.g., elevation) the gradients refer to.

This method follows the convention POSITIVE GRADIENT IS UP.

The routine will automatically test to ensure the provided links are boundary links, and will raise an exception ifthey aren’t. It is clever enough to distinguish for itself if any of the links provided are corner links (i.e., joiningan edge node to a corner node). In such cases, the values of the corner nodes are updated last, such that the edgenodes they refer to have already been updated.

6.5. Simple guides to functionality 83

Page 88: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> import numpy as np>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(3, 4, 1.0) # rows, columns, spacing>>> rmg.create_node_array_zeros('topographic__elevation')array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])>>> rmg['node']['topographic__elevation'] += 2.>>> rmg.force_boundaries_from_gradients(np.array([ 0, 1, 2, 5, 6, 7, 10, 11, 13, 14]), np.array([ 0., 1., 1.,-1.,-1., 0., 0., 1.,-1., 0.]))>>> rmg['node']['topographic__elevation']array([ 1., 1., 1., 1., 1., 2., 2., 1., 1., 1., 1., 1.])>>> rmg.force_boundaries_from_gradients(np.array([ 11, 13]), np.array([-2.,-2.]))>>> rmg['node']['topographic__elevation']array([ 1., 1., 1., 1., 4., 2., 2., 0., 1., 1., 1., 1.])

...and now we demonstrate an exception if an interior link is included: >>>rmg.force_boundaries_from_gradients(np.array([ 12, 13]), np.array([-2.,-2.])) Traceback (most recentcall last):

...

ValueError: One or more of the supplied links was neither an edge link, nor a link to a corner!

RasterModelGrid.has_boundary_neighbor(ids)Checks to see if one of the eight neighbor nodes of node(s) with id has a boundary node. Returns True if a nodehas a boundary node, False if all neighbors are interior.

Examples

>>> from landlab import RasterModelGrid>>> mg = RasterModelGrid(5, 5)>>> mg.has_boundary_neighbor(6)True>>> mg.has_boundary_neighbor(12)False>>> mg.has_boundary_neighbor([12, -1])array([False, True], dtype=bool)

>>> mg.has_boundary_neighbor(25)Traceback (most recent call last):

...IndexError: index 25 is out of bounds for axis 0 with size 25

RasterModelGrid.is_core([ids])Check if a node is a core node.

Returns an boolean array of truth values for each node ID provided; True if the node is a core node, Falseotherwise. If no IDs are provided, method returns a boolean array for every node.

(Core status is typically indicated by a value of 0 in node_status.)

RasterModelGrid.left_edge_node_ids()Nodes along the left edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the left (x=0) grid edge.

84 Chapter 6. User Guide

Page 89: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.left_edge_node_ids()array([ 0, 5, 10, 15])

RasterModelGrid.right_edge_node_ids()Nodes along the right edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the right (x=xmax) gridedge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.right_edge_node_ids()array([ 4, 9, 14, 19])

RasterModelGrid.set_fixed_gradient_boundaries(bottom_is_fixed, left_is_fixed,top_is_fixed, right_is_fixed,gradient_in=nan, gradi-ent_of=’topographic__elevation’)

Create fixed gradient boundaries.

Handles boundary conditions by setting each of the four sides of the rectangular grid to ‘active (fixed gradient)’(==2) status. Arguments are booleans indicating whether the bottom, right, top, and left are fixed gradient (True)or fixed value (False).

This method assumes you are storing the values on the grid as fields in the grid object, e.g., asgrid.at_node(‘my_values’).

Parameters bottom_is_fixed : boolean

Make bottom edge a fix-gradient boundary.

left_is_fixed : boolean

Make left edge a fix-gradient boundary.

top_is_fixed : boolean

Make top edge a fix-gradient boundary.

right_is_fixed : boolean

Make right edge a fix-gradient boundary.

Notes

For a fixed gradient boundary:

• the nodes on the specified edges are flagged FIXED_GRADIENT_BOUNDARY (== 2). Other edgesare ignored, and presumed to be set elsewhere.

6.5. Simple guides to functionality 85

Page 90: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

• the links between them and the adjacent interior nodes are active, but the links between each other arenot. Corners are an awkward special case; they do not have any active links, but when boundary con-ditions are updated, each corner has a “pseudo-active” link that connects to one of its edge neighborsthat lets it update (see examples below).

• the gradient is assumed by default to be the surface elevation, and this is assumed to benamed “topographic__elevation” in the grid. If the gradient is in another surface, or the ele-vation surface is named differently, you need to set ‘gradient_of’ equal to the relevant string.self.fixed_gradient_node_properties[’fixed_gradient_of’] stores this string for access elsewhere.

• The critical IDs and values relevant to the boundary conditions are stored in two special dictionaries,

grid.fixed_gradient_link_properties, & grid.fixed_gradient_node_properties.

The link dictionary stores the fixed gradients and the IDs of the links these are defined on: ‘bound-ary_link_gradients’, ‘boundary_link_IDs’. The node dictionary stores the nodes on the bound-ary which are fixed gradient, the nodes at the other end of the links from each of these nodes,and the (fixed) value differences between these two pairs of nodes: ‘boundary_node_IDs’, ‘an-chor_node_IDs’, ‘values_to_add’. These can be used to update the boundaries fast, without needingto interrogate the links.

• if gradient is provided, either as a float or an as a iterable of length number_of_boundary_nodes, then‘boundary_link_gradients’ is set equal to gradient, and all the other properties updated using thesevalues. If it is not, then this method will attempt to access the link gradients and/or node elevationswhich were already in the grid when the method was called (i.e., the initial conditions), and usethese to set the properties. Remember, gradient is as a fractional slope, not radians or degrees, anddownslope gradients are negative! If gradient is a negative float, this method will assume you meandownslope flow out of all the edges of the grid. If it is a positive float, the method will use this valueand incline the edges inwards, but will print a warning message that it is doing so. If you want someedges pointing in and some out, you’ll need to call the function more than once, or provide an arrayof values.

• If initial conditions are present in the grid ::and:: gradient is set, gradient will override the initialconditions provided.

• if gradient is not provided (or is the wrong length), and initial conditions have not yet been set, themethod will raise an exception.

• Note that the four corners are treated as follows:

– bottom left = BOTTOM

– bottom right = BOTTOM

– top right = TOP

– top left = TOP,

...and the gradient on the link (if supplied) corresponds to the link which points in the same directionas the rest of its edge (i.e., the fixed gradient links of the bottom left and right corners point up). Thishandling is necessary for internal consistency with looped BCs.

Examples

The following example sets all boundaries as fixed gradient in a four-row by five-column grid, but does so threetimes. The first time, initial conditions are allowed to set the fixed value. The second time, this is overridden bysetting gradient in the function call as a constant. The third time, values are specified in an array:

86 Chapter 6. User Guide

Page 91: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> import numpy as np>>> from landlab import RasterModelGrid>>> import landlab.utils.structured_grid as sgrid>>> rmg = RasterModelGrid(4, 5, 1.0) # rows, columns, spacing>>> rmg.number_of_active_links17>>> rmg.node_statusarray([1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1], dtype=int8)>>> rmg.create_node_array_zeros('topographic__elevation')array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,

0., 0., 0., 0., 0., 0., 0.])>>> rmg['node']['topographic__elevation'] += 1.>>> rmg['node']['topographic__elevation'][sgrid.boundary_nodes(rmg.shape)] = 0.8>>> rmg.set_fixed_gradient_boundaries(True, True, True, True) #first caseFixed gradients will be set according to existing data in the grid...>>> rmg.node_statusarray([2, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2], dtype=int8)>>> rmg.fixed_gradient_node_properties['fixed_gradient_of']'topographic__elevation'>>> rmg.fixed_gradient_node_properties['boundary_node_IDs']array([ 0, 1, 2, 3, 4, 9, 14, 15, 16, 17, 18, 19, 5, 10])>>> rmg.fixed_gradient_link_properties['boundary_link_IDs']array([ 0, 1, 2, 3, 4, 22, 26, 10, 11, 12, 13, 14, 19, 23])>>> rmg.fixed_gradient_link_properties['boundary_link_gradients']array([ 0. , 0.2, 0.2, 0.2, 0. , -0.2, -0.2, 0. , -0.2, -0.2, -0.2,

0. , 0.2, 0.2])>>> rmg.set_fixed_gradient_boundaries(True, True, True, True, -0.1, gradient_of='topographic__elevation') #second case>>> rmg.fixed_gradient_link_properties['boundary_link_gradients']array([ 0. , 0.1, 0.1, 0.1, 0. , -0.1, -0.1, 0. , -0.1, -0.1, -0.1,

0. , 0.1, 0.1])>>> rmg['node']['topographic__elevation']array([ 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 1. , 1. , 1. , 0.9, 0.9,

1. , 1. , 1. , 0.9, 0.9, 0.9, 0.9, 0.9, 0.9])

-> All boundaries end up with the same dip outwards. Note that the corners have been automatically set with“true” gradients of 0., so they mimic their edge neighbor. This is almost always what you want to happen.

>>> import numpy as np>>> my_gradients = np.array([-0.5,-0.5,-0.5,-0.5,]) #remember these are in edge, then ID order, with the corners attached to the other edges>>> rmg.set_fixed_gradient_boundaries(False, True, False, True, my_gradients) #third case>>> rmg.fixed_gradient_link_properties['boundary_link_gradients']array([-0.5, -0.5, -0.5, -0.5, 0.6, 0.1, 0.1, 0.1, -0.4, -0.6, -0.1,

-0.1, -0.1, 0.4])>>> rmg.fixed_gradient_node_properties['boundary_node_IDs']array([ 9, 14, 5, 10, 0, 1, 2, 3, 4, 15, 16, 17, 18, 19])>>> rmg.fixed_gradient_node_properties['anchor_node_IDs']array([ 8, 13, 6, 11, 6, 6, 7, 8, 8, 11, 11, 12, 13, 13])>>> rmg.fixed_gradient_node_properties['values_to_add']array([-0.5, -0.5, 0.5, 0.5, -0.1, -0.1, -0.1, -0.1, -0.1, -0.1, -0.1,

-0.1, -0.1, -0.1])>>> rmg['node']['topographic__elevation']array([ 0.9, 0.9, 0.9, 0.9, 0.9, 1.5, 1. , 1. , 1. , 0.5, 1.5,

1. , 1. , 1. , 0.5, 0.9, 0.9, 0.9, 0.9, 0.9])

...i.e., 0.9 0.9 0.9 0.9 0.9 1.5 1. 1. 1. 0.5 1.5 1. 1. 1. 0.5 0.9 0.9 0.9 0.9 0.9

Now note we can easily update these boundary conditions much faster:

6.5. Simple guides to functionality 87

Page 92: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> elevs = rmg['node']['topographic__elevation']>>> updated_elevs = elevs>>> updated_elevs[rmg.fixed_gradient_node_properties['boundary_node_IDs']] = updated_elevs[rmg.fixed_gradient_node_properties['anchor_node_IDs']] + rmg.fixed_gradient_node_properties['values_to_add']>>> np.all(np.equal(elevs, updated_elevs))True

RasterModelGrid.set_fixed_value_boundaries_at_grid_edges(bottom_is_fixed_val,left_is_fixed_val,top_is_fixed_val,right_is_fixed_val,value=None,value_of=’topographic__elevation’)

Create fixed values boundaries.

Sets the status of nodes along the specified side(s) of a raster grid—bottom, right, top, and/or left—toFIXED_VALUE_BOUNDARY.

Arguments are booleans indicating whether the bottom, right, top, and left sides are to be set (True) or not(False).

value controls what values are held constant at these nodes. It can be either a float, an array of length num-ber_of_fixed_nodes or number_of_nodes (total), or left blank. If left blank, the values will be set from the thosealready in the grid fields, according to ‘value_of’.

value_of controls the name of the model field that contains the values. Remember, if you don’t set value, thefixed values will be set from the field values *at the time you call this method*. If no values are presentin the field, the module will complain but accept this, warning that it will be unable to automatically updateboundary conditions (and such methods, e.g., RasterModelGrid.update_boundary_nodes(), willraise exceptions if you try).

The status of links (active or inactive) is automatically updated to reflect the changes.

The following example sets the bottom and right boundaries as fixed-value in a four-row by five-column gridthat initially has all boundaries closed (i.e., flagged as node_status=4):

Parameters bottom_is_fixed_val : boolean

Set bottom edge as fixed boundary.

left_is_fixed_val : boolean

Set left edge as fixed boundary.

top_is_fixed_val : boolean

Set top edge as fixed boundary.

right_is_fixed_val : boolean

Set right edge as fixed boundary.

value : float, array or None (default).

Override value to be kept constant at nodes.

value_of : string.

The name of the grid field containing the values of interest.

88 Chapter 6. User Guide

Page 93: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0) # rows, columns, spacing>>> rmg.number_of_active_links17

Put some arbitrary values in the grid fields:

>>> import numpy as np>>> rmg.at_node['topographic__elevation'] = np.random.rand(20)>>> rmg.set_closed_boundaries_at_grid_edges(True, True, True, True)>>> rmg.node_statusarray([4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 0, 0, 0, 4, 4, 4, 4, 4, 4], dtype=int8)>>> rmg.set_fixed_value_boundaries_at_grid_edges(False, False, True, True)>>> rmg.number_of_active_links12>>> rmg.node_statusarray([4, 4, 4, 4, 4, 4, 0, 0, 0, 1, 4, 0, 0, 0, 1, 1, 1, 1, 1, 1], dtype=int8)

Note that the four corners are treated as follows: bottom left = BOTTOM bottom right = BOTTOM top right= TOP top left = TOP

This scheme is necessary for internal consistency with looped boundaries.

RasterModelGrid.set_closed_boundaries_at_grid_edges(bottom_is_closed, left_is_closed,top_is_closed, right_is_closed)

Set boundary not to be closed.

Sets the status of nodes along the specified side(s) of a raster grid (bottom, right, top, and/or left) toCLOSED_BOUNDARY.

Arguments are booleans indicating whether the bottom, left, top, and right are closed (True) or not (False).

For a closed boundary:

• the nodes are flagged CLOSED_BOUNDARY (status type 4)

• all links that connect to a CLOSED_BOUNDARY node are flagged as inactive (so they appear on link-based lists, but not active_link-based lists)

This means that if you call the calculate_gradients_at_active_links method, links connecting to closed bound-aries will be ignored: there can be no gradients or fluxes calculated, because the links that connect to that edgeof the grid are not included in the calculation. So, setting a grid edge to CLOSED_BOUNDARY is a convenientway to impose a no-flux boundary condition. Note, however, that this applies to the grid as a whole, rather thana particular variable that you might use in your application. In other words, if you want a no-flux boundary inone variable but a different boundary condition for another, then use another method.

This method is a replacement for the now-deprecated method set_inactive_boundaries(). Unlikethat method, this one ONLY sets nodes to CLOSED_BOUNDARY; it does not set any nodes toFIXED_VALUE_BOUNDARY.

Parameters bottom_is_closed : boolean

If True bottom-edge nodes are closed boundaries.

left_is_closed : boolean

If True left-edge nodes are closed boundaries.

top_is_closed : boolean

6.5. Simple guides to functionality 89

Page 94: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

If True top-edge nodes are closed boundaries.

right_is_closed : boolean

If True right-edge nodes are closed boundaries.

Notes

Note that the four corners are treated as follows:

• bottom left = BOTTOM

• bottom right = BOTTOM

• top right = TOP

• top left = TOP

This scheme is necessary for internal consistency with looped boundaries.

Examples

The following example sets the top and left boundaries as closed in a four-row by five-column grid that initiallyhas all boundaries open and all boundary nodes coded as FIXED_VALUE_BOUNDARY (=1):

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0) # rows, columns, spacing>>> rmg.number_of_active_links17>>> rmg.node_statusarray([1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1], dtype=int8)>>> rmg.set_closed_boundaries_at_grid_edges(False, False, True, True)>>> rmg.number_of_active_links12>>> rmg.node_statusarray([1, 1, 1, 1, 1, 1, 0, 0, 0, 4, 1, 0, 0, 0, 4, 4, 4, 4, 4, 4], dtype=int8)

RasterModelGrid.set_looped_boundaries(top_bottom_are_looped, sides_are_looped)Create wrap-around boundaries. Handles boundary conditions by setting corresponding parallel grid edges aslooped “tracks_cell” (==3) status, linked to each other. If top_bottom_are_looped is True, the top and bottomedges will link to each other. If sides_are_ looped is True, the left and right edges will link to each other.

Looped boundaries are experimental, and not as yet well integrated into the Landlab framework. Many functionsmay not recognise them, or silently create unforeseen errors. Use at your own risk!

Note that because of the symmetries this BC implies, the corner nodes are all paired with the bottom/top edges,not the sides.

Parameters top_bottom_are_looped : boolean

Top and bottom are wrap-around.

sides_are_looped : boolean

Left and right sides are wrap-around.

90 Chapter 6. User Guide

Page 95: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0) # rows, columns, spacing>>> rmg.number_of_active_links17>>> rmg.node_statusarray([1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1], dtype=int8)>>> rmg.create_node_array_zeros('topographic__elevation')array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,

0., 0., 0., 0., 0., 0., 0.])>>> rmg.set_looped_boundaries(True, True)>>> rmg.looped_node_properties['boundary_node_IDs']array([ 0, 1, 2, 3, 4, 5, 9, 10, 14, 15, 16, 17, 18, 19])>>> rmg.looped_node_properties['linked_node_IDs']array([10, 11, 12, 13, 14, 8, 6, 13, 11, 5, 6, 7, 8, 9])

RasterModelGrid.top_edge_node_ids()Nodes along the top edge.

Returns a 1D numpy integer array containing the node ID numbers of the nodes along the top (y=ymax) gridedge.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> rmg.top_edge_node_ids()array([15, 16, 17, 18, 19])

Manipulate arrays for plotting and display

These methods are intended to make plotting up visualizations of the grid easier. NB: these slope and aspect methodswere devised for display purposes, and not intended or tested for quantitative use. But if you wish to explore their usesfor such, have at it!

ModelGrid.display_grid(draw_voronoi=False)Displays the grid.

RasterModelGrid.calculate_aspect_at_nodes_bestFitPlane(id, val)Aspect at nodes.

Code author: Katy Barnhart <[email protected]>

Calculates the aspect at each node based on the elevation of the node and its neighbors using a best fit planecalculated using single value decomposition.

Parameters id : array-like

ID of nodes at which to calculate the aspect.

val : ndarray

Elevation at all nodes

Returns ndarray

Aspect at the nodes given by id

6.5. Simple guides to functionality 91

Page 96: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

RasterModelGrid.calculate_slope_aspect_at_nodes_bestFitPlane(id, val)THIS CODE HAS ISSUES: This code didn’t perform well on a NS facing elevation profile. Please checkslope_aspect_routines_comparison.py under landlabexamples before using this. Suggested alternative: calcu-late_slope_aspect_at_nodes_Burrough

~ SN 25Sep14

Slope aspect of best-fit plane at nodes.

Code author: Katy Barnhart <[email protected]>

Calculates both the slope and aspect at each node based on the elevation of the node and its neighbors using abest fit plane calculated using single value decomposition.

Parameters id : array-like

ID of nodes at which to calculate the aspect

val : ndarray

Elevation at all nodes

Returns tuple of floats

Tuple containing (slope, aspect)

RasterModelGrid.calculate_slope_at_nodes_bestFitPlane(id, val)Slope of best-fit plane at nodes.

Code author: Katy Barnhart <[email protected]>

Calculates the slope at each node based on the elevation of the node and its neighbors using a best fit planecalculated using single value decomposition.

Parameters id : array-like

ID of nodes at which to calculate the aspect

val : ndarray

Elevation at all nodes

Returns ndarray

Slope at the nodes given by id

RasterModelGrid.cell_vector_to_raster(u, flip_vertically=False)Unravel a 1D array.

Converts cell vector u to a 2D array and returns it, so that it can be plotted, output, etc.

If the optional argument flip_vertically=True, the function returns an array that has the rows in reverse order, foruse in plot commands (such as the image display functions) that put the (0,0) axis at the top left instead of thebottom left.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> u = rmg.zeros(centering='cell')>>> u = u + range(0, len(u))>>> uarray([ 0., 1., 2., 3., 4., 5.])>>> ur = rmg.cell_vector_to_raster(u)

92 Chapter 6. User Guide

Page 97: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

>>> urarray([[ 0., 1., 2.],

[ 3., 4., 5.]])>>> ur = rmg.cell_vector_to_raster(u, flip_vertically=True)>>> urarray([[ 3., 4., 5.],

[ 0., 1., 2.]])

RasterModelGrid.hillshade(alt=45.0, az=315.0, slp=None, asp=None, unit=’degrees’,elevs=’topographic__elevation’)

Calculate hillshade.

Code author: Katy Barnhart <[email protected]>

Promoted from raster to base by DEJH, 10/7/14.

Parameters alt : float

Sun altitude (from horizon) - defaults to 45 degrees

az : float

Sun azimuth (from north) - defaults to 315 degrees

slp : float

slope of cells at surface - optional

asp : float

aspect of cells at surface (from north) - optional (with slp)

unit : string

‘degrees’ (default) or ‘radians’ - only needed if slp and asp are not provided

If slp and asp are both not specified, ‘elevs’ must be provided as

a grid field name (defaults to ‘topographic__elevation’) or an

nnodes-long array of elevation values. In this case, the method will

calculate local slopes and aspects internally as part of the hillshade

production.

Returns float

Hillshade at each cell.

Notes

code taken from GeospatialPython.com example from December 14th, 2014 DEJH found what looked like mi-nor sign problems, and adjusted to follow the ArcGIS algorithm: http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/How_Hillshade_works/009z000000z2000000/ .

NB: grid.node_slopes_using_patches() returns slopes as RADIANS. Use caution.

Remember when plotting that bright areas have high values. cmap=’Greys’ will give an apparently invertedcolor scheme. cmap=’gray’ has white associated with the high values, so is recommended for plotting.

RasterModelGrid.node_vector_to_raster(u, flip_vertically=False)Unravel an array of node values.

Converts node vector u to a 2D array and returns it, so that it can be plotted, output, etc.

6.5. Simple guides to functionality 93

Page 98: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

If the flip_vertically keyword is True, this function returns an array that has the rows in reverse order. This isuseful for use in plot commands (such as the image display functions) that puts the first row at the top of theimage. In the landlab coordinate system, the first row is thought to be at the bottom. Thus, a flipped matrix willplot in the landlab style with the first row at the bottom.

The returned array is a view of u, not a copy.

Examples

>>> from landlab import RasterModelGrid>>> rmg = RasterModelGrid(4, 5, 1.0)>>> u = rmg.zeros(centering='node')>>> u = u + range(0, len(u))>>> uarray([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.,

11., 12., 13., 14., 15., 16., 17., 18., 19.])>>> ur = rmg.node_vector_to_raster(u)>>> urarray([[ 0., 1., 2., 3., 4.],

[ 5., 6., 7., 8., 9.],[ 10., 11., 12., 13., 14.],[ 15., 16., 17., 18., 19.]])

>>> ur = rmg.node_vector_to_raster(u, flip_vertically=True)>>> urarray([[ 15., 16., 17., 18., 19.],

[ 10., 11., 12., 13., 14.],[ 5., 6., 7., 8., 9.],[ 0., 1., 2., 3., 4.]])

6.5.4 Landlab Standard Names

UNDER DEVELOPMENT

Sorry!

Note: We are currently in the process of improving the Landlab-wide standardization of our naming conventions.Currently in use standard field names may change suddenly in the near future! Note we will however be making effortsto maintain backward compatibility with names currently in use.

6.6 CellLab-CTS

CellLab-CTS is a Landlab module for building pairwise, continuous-time stochastic (CTS) cellular automata.

6.6.1 CellLab-CTS 2015 Users Manual

Created: August 2015, Greg Tucker

Last updated: September 2015

94 Chapter 6. User Guide

Page 99: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Introduction

CellLab-CTS is a Landlab module for building pairwise, continuous-time stochastic (CTS) cellular automata. Likeother cellular automata, pairwise CTS models represent natural phenomena using a regular grid of cells; in the case ofCellLab-CTS, the user can choose between square and hexagonal cells. Each cell has a given state, which is an integercode representing something about the nature or contents of that cell. Cells change state at random time intervalsaccording to a user-defined transition rules. The transitions depend on the states of the neighboring cells, and inparticular, of the states of each pair of adjacent cells. For example a pair with states 0 and 1 might undergo a transitionto 1 and 1, or 3 and 0, etc.

This Users Manual provides instructions on how to write a model using CellLab-CTS, along with reference informationabout the classes and methods that CellLab-CTS provides. For further information about the theory, implementation,and design of CellLab-CTS, see Tucker et al. (2015 in prep). For background information on the theory of pairwiseCTS models and example applications, see Narteau et al. (2001, 2009) and Rozier and Narteau (2014). For backgroundon cellular automata in general, see Chopard and Droz (1998).

Note on terminology: In a CellLab-CTS model, the computational points—the objects that are normally called cellsin a cellular automaton model—actually correspond with the nodes in a Landlab grid. Although Landlab grids alsocontain cells, which are defined as polygons that contain a node, Landlab grids do not have cells along the outmostring of nodes around the grid. For example, a 4-row by 5-column Landlab raster grid has 20 nodes but only 6 cells(2 inner rows x 3 inner columns). For CellLab-CTS models, it is useful to include the perimeter nodes as “cells” forthe purpose of handling boundary conditions. Therefore, CellLab-CTS treats all the nodes in the grid as if they werecells in a cellular automaton. This includes the perimeter nodes, for which Landlab does not formally define cells. Forpractical purposes, the distinction doesn’t make much difference, but it is important to understand that CellLab-CTSworks with arrays of grid nodes rather than the (shorter) arrays of grid cells. Henceforth, to avoid confusion, we willrefer to nodes, which you should read as being synonymous with the usual meaning of “cell” in a cellular automaton.

Prerequisites: This manual assumes working knowledge of the Python programming language (any version), includingbasic familiarity with Python classes and objects. It also assumes a basic familiarity with Landlab grids. In addition,it will be helpful to have some familiarity with the Matplotlib and/or Pylab plotting libraries.

Writing a CellLab-CTS model

What is a CellLab-CTS model?

A CellLab-CTS model is a Python code that creates and initializes one of four types of CellLabCTSModel object,defines the possible cell states and transition rules, and calls the run method to execute the model. A CellLab-CTSmodel can be written in one of two basic ways. The first option is to write a simple Python script that imports thenecessary ingredients. This approach is easy and versatile, and is recommended for first-time users, and/or those whoare relatively unfamiliar with Python classes. The second option is to write your model as a subclass of one of thefour existing CellLabModel subclasses (more on these below). The subclass approach is useful when you wish to usethe dynamic property updating capability of CellLab-CTS—that is, for example, when you want to attach some formof additional data to the grid, and update the data at each transition event according to the state of the grid. In thismanual, we will focus on the example of a simple script-based model.

Basic ingredients of a CellLab-CTS model

The basic steps in most CellLab-CTS models are as follows:

1. Import the necessary CTS classes (and any other necessary packages). These include: one of the four CellLab-CTS model classes (described below), the Transition class, and (optionally) the CAPlotter class forgraphical display.

2. Create and initialize a Landlab ModelGrid object: either a RasterModelGrid or a HexModelGrid

6.6. CellLab-CTS 95

Page 100: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

3. Create a dictionary that defines the node states to be used

4. Create a list of Transition objects: one for each transition type in your model

5. Create an array with the initial state values in the grid

6. Instantiate and initialize one of the four CellLab-CTS classes

7. Set up plotting (if desired)

8. Run the model by calling the CellLab-CTS object’s run method (perhaps pausing every so often to display thegrid and/or write output to file)

9. Clean up

We will illustrate each of these steps using a simple example called isotropic_turbulent_suspension.py.This program simulates the random motion of neutrally buoyant sediment particles that are immersed in a turbulentfluid: think of tea leaves in a jar of tea that you are stirring with an invisible spoon. Each random motion is simulatedby simply swapping a fluid state and a particle state.

Fig. 6.4: Figure 1: A CellLab-CTS model of suspended sediment particles in an isotropic turbulent fluid.

Before diving into the example, however, it’s useful to look at the four different types of CellLab-CTS model.

Types of CellLab-CTS model

A CellLab-CTS grid can be either raster (regular grid of square cells) or hexagonal (triagonal grid of nodes withhexagonal cells). In addition, a CellLab-CTS model can be either oriented or non-oriented. An oriented model is onein which the spatial orientation of a node pair influences the types and/or of transition. For example, in an orientedraster model, a horizontal pair with states 0 and 1 might have a different set of potential transitions than a vertical pairwith states 0 and 1. A non-oriented pair treats the sequence 0-1 the same regardless of whether the pair is vertical,horizontal, or (in the case of a hex grid) at any other angle.

With these different possibilities in mind, the four CellLab-CTS model types are:

1. RasterCTS: A non-oriented grid of square cells.

96 Chapter 6. User Guide

Page 101: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

2. OrientedRasterCTS: An oriented grid of square cells, with two orientations (horizontal and vertical).

3. HexCTS: A non-oriented grid of hexagons.

4. OrientedHexCTS: An oriented grid of hexagons, with three orientations. These can be: (1) vertical, (2) +30degrees from horizontal (angling down/left to up/right), and (3) -30 degrees from horizontal (angling up/left todown/right). Or, alternatively, the three axes can be horizontal and +/-30 degrees from vertical (one determinesthis when instantiating the grid object, as illustrated below).

These four types are implemented as subclasses of the base class CellLabCTSModel, as illustrated in Figure 2.

Fig. 6.5: Figure 2: CellLab-CTS class hierarchy and main data structures. N = number of grid nodes, L = number ofgrid links, NL = number of possible link (node pair) states, NT = maximum number of transitions for any link state.

Step 1: Importing CellLab-CTS

A CellLab-CTS application normally starts by importing the appropriate type of CTS model class, along with anyother packages needed. Thus, our suspended-sediment model starts out as follows:

#!/usr/env/python

"""isotropic_turbulent_suspension.py

Example of a continuous-time, stochastic, pair-based cellular automaton model,which simulates the diffusion of suspended, neutrally buoyant particles in aturbulent fluid.

Written by Greg Tucker, February 2015"""

import timeimport matplotlib

6.6. CellLab-CTS 97

Page 102: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

from numpy import wherefrom landlab import RasterModelGridfrom landlab.components.cellular_automata.celllab_cts import Transition, CAPlotterfrom landlab.components.cellular_automata.raster_cts import RasterCTS

Here, we’re using a raster model, so we import Landlab’s RasterModelGrid class. It will be a non-oriented rastermodel, so we import the RasterCTS class (rather than OrientedRasterCTS). We also import the CAPlotterclass for help with graphical display (more on that below), as well as the Transition class. We need the Transitionclass to set up our pair transitions, which we explore next.

Setting up transitions

Sequence matters! A particular pair state is described by the two node states, and optionally by the pair’s orientation.A key thing to understand here is that any particular pair sequence, such as 0 and 1, is different from the sequence inreverse. The pair 0-1 is not the same as the pair 1-0! This is true for all four types of model. So then which is which?To answer this question, we first need to recall that each pair corresponds to the two ends of a link in the Landlab grid.A link is simply a directed line segment that connects two neighboring nodes. Every link has a tail and a head (like thehead of an arrow); the direction of the link is from tail to head. The rule for CellLab-CTS pairs is that the first numberrefers to the tail of the corresponding link, and the second refers to its head. Thus, the pair state 0-1 means that the tailnode has state 0 and the head node has state 1.

By default, the links in a raster grid always run from down to up (for vertical links) or left to right (for horizontal links)(Figure 3). For example, with a 0-1 pair in a raster grid, the 0 is either the left-hand node (if it’s a horizontal pair)or the bottom node (if the pair is vertical). In a default hex grid, the links point either (1) upward, (2) angling rightand up 30 degrees, or (3) angling right and down 30 degrees. (Note that you also have the option of switching thegrid orientation so that one of the principal axes is horizontal instead of vertical; in that case, the three orientations arehorizontal, 30 degrees clockwise from vertical, and 30 degrees counter-clockwise from vertical).

How transitions are represented Each transition type is described by the states of the tail and head nodes, and bythe orientation of the pair. This information is encoded in a 3-element tuple. Recall that each pair is associated with alink. The first number is the state of the link’s tail node, the second is the state of the link’s head node, and the thirdis an orientation code that represents the pair’s spatial orientation (Figure 4). In a non-oriented model, the orientationcode is always zero. In an oriented raster, the orientation code is either 0 (horizontal) or 1 (vertical). For example, thecode (0, 1, 0) in an oriented raster model would represent a vertical pair in which the left node has state 0 and the rightstate 1.

In an oriented hex, the orientation codes depend on the orientation of the grid itself. A Landlab HexModelGridcan be oriented such that one of the three principal axes is either horizontal (the default) or vertical. The choiceis controlled by the optional keyword argument orientation (either ’vertical’ or ’horizontal’) in theHexModelGrid initialization function. For a vertically aligned hex grid, the CellLab-CTS orientation codes are: 0for vertical, 1 for right and upward, and 2 for right and downward (Figure 4). For example, the code (1, 0, 2) wouldrepresent a down-and-right pair, with a state of 1 in the upper-left node and 0 in the lower-right node. For a horizontallyaligned hex grid, the CellLab-CTS orientation codes are: 0 for upward and left, 1 for upward and right, and 2 for right.For example, the code (1, 0, 2) would represent a left-to-right pair, with a state of 1 in the left node and 0 in the rightnode.

Example of a transition setup function It can be helpful to put the transition setup procedure inside a function ofits own. Here is the transition setup function for our turbulent suspension example (notice that the function itself hasonly four lines of code; all the rest is documentation):

def setup_transition_list():"""Creates and returns a list of Transition() objects to represent state

98 Chapter 6. User Guide

Page 103: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Fig. 6.6: Figure 3: Illustration of nodes, links, and cells in a raster and hex grids. Note directions of links, whichalways “point” toward the upper-right hemisphere. The hex illustration shows a hex grid cell in vertical orientation; inhorizontal orientation, links point rightward, up and right, and up and left.

transitions for an unbiased random walk.

Parameters----------(none)

Returns-------xn_list : list of Transition objects

List of objects that encode information about the link-state transitions.

Notes-----State 0 represents fluid and state 1 represents a particle (such as asediment grain, tea leaf, or solute molecule).

The states and transitions are as follows:

Pair state Transition to Process Rate (cells/s)========== ============= ======= ==============0 (0-0) (none) - -1 (0-1) 2 (1-0) left/down motion 10.02 (1-0) 1 (0-1) right/up motion 10.03 (1-1) (none) - -

"""

6.6. CellLab-CTS 99

Page 104: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Fig. 6.7: Figure 4: Pair orientation codes in a raster (top 2 panels) and vertical hex (bottom 3 panels) grid.

100 Chapter 6. User Guide

Page 105: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

# Create an empty transition listxn_list = []

# Append two transitions to the list.# Note that the arguments to the Transition() object constructor are:# - Tuple representing starting pair state# (left/bottom cell, right/top cell, orientation)# - Tuple representing new pair state# (left/bottom cell, right/top cell, orientation)# - Transition rate (cells per time step, in this case 1 sec)# - Name for transitionxn_list.append( Transition((0,1,0), (1,0,0), 10., 'left/down motion') )xn_list.append( Transition((1,0,0), (0,1,0), 10., 'right/up motion') )

return xn_list

In this example, state 0 represents the fluid and state 1 represents a particle. Motion is represented by a transition froma 0-1 pair to a 1-0, or vice versa.

Your transition setup function should create and return a list of Transition objects. A Transition object contains(and is initialized with) the 3-element tuples for the starting and ending transitions, a transition rate (in units of cell-widths per time), and (optionally) a name. Two other optional parameters are used when you want to track propertiesassociated with moving particles: a boolean flag (swap_properties) indicating whether the transition involves anexchange of properties, and the name of a user-defined callback function (prop_update_fn) to invoke whenever atransition of that type occurs.

(Note that it is also possible to specify a single-integer code for the link state, instead of 3-element tuple. This is a bitmore of a headache, however, since it requires you to work out the link-state code corresponding to each pair, and isnot recommended.)

Defining parameters

Typical parameters in a CellLab-CTS model, in addition to the transitions and rates, include the dimensions of thegrid, the duration of the run, and the time intervals for plotting, writing output to file, and/or reporting progress onscreen. In the following example, we have defined these within a main() function. They could also be read in froma file, input on a command line, or specified by some other method.

def main():

# INITIALIZE

# User-defined parametersnr = 80 # number of rows in gridnc = 50 # number of columns in gridplot_interval = 0.5 # time interval for plotting, secrun_duration = 20.0 # duration of run, secreport_interval = 10.0 # report interval, in real-time seconds

# Remember the clock time, and calculate when we next want to report# progress.current_real_time = time.time()next_report = current_real_time + report_interval

6.6. CellLab-CTS 101

Page 106: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Step 2: Creating a grid

Depending on the type of CTS model to be used, your code will need to instantiate either a RasterModelGrid or aHexModelGrid. If you wish to modify the default boundary setup, this should be done right after the grid is created.In the example below, we create a raster grid and set each of its four boundaries to act like a wall:

# Create gridmg = RasterModelGrid(nr, nc, 1.0)

# Make the boundaries be wallsmg.set_closed_boundaries_at_grid_edges(True, True, True, True)

Step 3: Create a node-state dictionary

The possible node states are defined by creating entries in a dictionary, in which each key is an integer and each valueis a string that gives the name for that state. There should be one entry for each state in your model. For example, ourisotropic turbulent suspension model defines just two states:

ns_dict = { 0 : 'fluid', 1 : 'particle' }

Step 4: Create the transition list

If you’ve already defined a transition setup function, all you need to do here is call that function, as in the followingexample:

xn_list = setup_transition_list()

Step 5: Create an array containing the initial node-state values

The node state array should be a 1D numpy array of integers, with length equal to the number of grid rows timesthe number of grid columns. The easiest way to create such a grid is to use the grid’s add_zeros() method (or,similarly, add_ones or add_empty). For example, for the suspended-sediment example we’ll create an array ofzeros, representing a container filled with fluid:

# Create the node-state array and attach it to the gridnode_state_grid = mg.add_zeros('node', 'node_state_map', dtype=int)

The first argument here is the name of the grid element to which values should be attached, the second is a name togive the array, and the third sets the data type to integer (instead of the default float type).

Depending on the nature of the model, the next step is to set the initial values of the node states. You can do this justas you would with any Landlab grid field. Remember that the coordinates of each node in a Landlab grid are availablethrough the node_x and node_y arrays. For our working example, we’ll set the lower 10% of nodes to state 1,indicating that we are starting with a pile of tea leaves at the bottom of the container:

# Initialize the node-state array: here, the initial condition is a pile of# resting grains at the bottom of a container.bottom_rows = where(mg.node_y<0.1*nr)[0]node_state_grid[bottom_rows] = 1

# For visual display purposes, set all boundary nodes to fluidnode_state_grid[mg.closed_boundary_nodes] = 0

Note the use of the numpy where function, which we imported in Step 1.

102 Chapter 6. User Guide

Page 107: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Step 6: Instantiate a CellLab-CTS object

Our core model will be an object (a.k.a. instance) of one of the four CellLabCTS model classes. We create this just aswe would any other Python object: by calling its constructor function, which is simply the name of the class followedby parentheses, with any necessary arguments within the parentheses. There are four required arguments: a grid object(which must be of the correct type, i.e., raster or hex), a dictionary of node states, a list of Transition objects, andthe initial node state array. Here’s what it looks like for our raster-based suspension model:

# Create the CA modelca = RasterCTS(mg, ns_dict, xn_list, node_state_grid)

Step 7: Set up plotting

If you want to display your model’s progress on screen, you can pause the run every once in a while and use pylab,matplotlib, or whatever your favorite graphics library may be to plot what’s going on. For convenience, CellLab-CTSprovides a CAPlotter class. CAPlotter is smart enough to find your node-state array, and to plot its contents in rasteror hex form as appropriate. When you create the CAPlotter object, you pass it your CA model object and optionallya matplotlib colormap object. The CAPlotter has an update_plot method to plot the current state of your model,and a finalize method to clean up.

Here’s an example of how to use a CAPlotter:

# Set up colors for plottinggrain = '#5F594D'fluid = '#D0E4F2'clist = [fluid,grain]my_cmap = matplotlib.colors.ListedColormap(clist)

# Create a CAPlotter object for handling screen displayca_plotter = CAPlotter(ca, cmap=my_cmap)

# Plot the initial gridca_plotter.update_plot()

Step 8: Run the model

Once a CTS model object has been instantiated, you run it forward in time with the run method. run takes onerequired argument: the future time to which to run. There are also three optional arguments:

• a node-state array (this is provided so that if you wish you can modify the array and re-run)

• a flag indicating whether to re-plot after each transition occurs

• a plotter object, which is required if the value of the flag is True

If you wish to pause occasionally to plot and/or write data to file, a natural approach is to place the call to the runmethod inside a loop, as in the following example:

# RUNcurrent_time = 0.0while current_time < run_duration:

# Once in a while, print out simulation real time to let the user# know that the sim is running okcurrent_real_time = time.time()if current_real_time >= next_report:

6.6. CellLab-CTS 103

Page 108: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

print('Current simulation time '+str(current_time)+' \('+str(int(100*current_time/run_duration))+'%)')

next_report = current_real_time + report_interval

# Run the model forward in time until the next output stepca.run(current_time+plot_interval, ca.node_state,

plot_each_transition=False)current_time += plot_interval

# Plot the current gridca_plotter.update_plot()

Step 9: Cleanup

There generally isn’t much to clean up. If you are using a CAPlotter object, it can be helpful to call its finalizemethod, which turns off matplotlib’s interactive mode and calls show() to make sure the plot is displayed on screen.

ca_plotter.finalize()

Reference information

Main data structures in the CellLabCTSModel class

Each of the four types of CTS model inherits from the base class (CellLabCTSModel) the following data structures.These are also illustrated in Figure 2.

node_state [1d array (x number of nodes in grid)] Node-based grid of node-state codes. This is the grid of cell(sic) states.

node_pair [list (x number of possible link states)] List of 3-element tuples representing all the various link states.Allows you to look up the node states and orientation corresponding to a particular link-state ID.

event_queue [heap of Event objects] Queue containing all future transition events, sorted by time of occurrence(from soonest to latest).

next_update [1d array (x number of active links)] Time (in the future) at which the link will undergo its nexttransition. You might notice that the update time for every scheduled transition is also stored in each Eventobject in the event queue. Why store it twice? Because a scheduled event might be invalidated after the eventhas been scheduled (because another transition has changed one of a link’s two nodes, for example). The wayto tell whether a scheduled event is still valid is to compare its time with the corresponding transition time in thenext_update array. If they are different, the event is discarded.

link_orientation [1d array of ints (x number of active links)] Orientation code for each link.

link_state [1d array of ints (x number of active links)] State code for each link.

n_xn [1d array of ints (x number of possible link states)] Number of transitions (“xn” stands for “transition”) from agiven link state.

xn_to [2d array of ints (# possible link states x max. # transitions)] Stores the link-state code(s) to which a particularlink state can transition. “max. # transitions” means the maximum number of transitions from a single state. Forexample, if each link state is associated with one and only one transition, then the maximum is 1, but if there isat least one link state that can have either of two different transitions, then the maximum would be two.

xn_rate [2d array of floats (# possible link states x max. # transitions)] Rate associated with each link-state transi-tion.

104 Chapter 6. User Guide

Page 109: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Methods and Internal Documentation for the base class: CellLabCTSModel

class CellLabCTSModel(model_grid, node_state_dict, transition_list, initial_node_states,prop_data=None, prop_reset_value=None)

A CellLabCTSModel implements a link-type (or doublet-type) cellular automaton model. A link connects a pairof cells. Each cell has a state (represented by an integer code), and each link also has a state that is determinedby the states of the cell pair.

Methods

assign_link_states_from_node_typescreate_link_state_dict_and_pair_listcurrent_link_statedo_transitionget_next_eventpush_transitions_to_event_queuerunset_node_state_gridsetup_array_of_orientation_codessetup_transition_dataupdate_component_dataupdate_link_stateupdate_link_states_and_transitionsupdate_node_states

assign_link_states_from_node_types()Assigns a link-state code for each link, and returns a list of these.

Takes lists/arrays of “tail” and “head” node IDs for each link, and a dictionary that associates pairs of nodestates (represented as a 3-element tuple, comprising the TAIL state, FROM state, and orientation) to linkstates.

create_link_state_dict_and_pair_list()Creates a dictionary that can be used as a lookup table to find out which link state corresponds to a partic-ular pair of node states. The dictionary keys are 3-element tuples, each of which represents the state of theTAIL node, the HEAD node, and the orientation of the link. The values are integer codes representing thelink state numbers.

(Performance note: making self.node_pair a tuple does not appear to change time to lookup values inupdate_node_states. Changing it to a 2D array of int actually slows it down.)

current_link_state(link_id)Used to determine whether the link state at link link_id has changed due to an independent change in thenode-state grid. Returns the current state of the link based on the states of its two end nodes; this can becompared to the entry in self.link_state to determine whether the state has changed.

Parameters link_id : int

ID of the active link to test

Returns int

New link state code

6.6. CellLab-CTS 105

Page 110: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Notes

Vectorizing this might yield some speed.

do_transition(event, current_time, plot_each_transition=False, plotter=None)Implements a state transition.

Parameters event : Event object

Event object containing the data for the current transition event

current_time : float

Current time in simulation

plot_each_transition : bool (optional)

True if caller wants to show a plot of the grid after this transition

plotter : CAPlotter object

Sent if caller wants a plot after this transition

get_next_event(link, current_state, current_time)Returns the next event for link with ID “link”, which is in state “current state”.

Parameters link : int

ID of the link

current_state : int

Current state code for the link

current_time : float

Current time in simulation (i.e., time of event just processed)

Returns Event object

The returned Event object contains the time, link ID, and type of the next transitionevent at this link.

Notes

If there is only one potential transition out of the current state, a time for the transition is selected at randomfrom an exponential distribution with rate parameter appropriate for this transition.

If there are more than one potential transitions, a transition time is chosen for each, and the smallest ofthese applied.

Assumes that there is at least one potential transition from the current state.

push_transitions_to_event_queue()Initializes the event queue by creating transition events for each cell pair that has one or more potential tran-sitions and pushing these onto the queue. Also records scheduled transition times in the self.next_updatearray.

run(run_duration, node_state_grid=None, plot_each_transition=False, plotter=None)Runs the model forward for a specified period of time.

Parameters run_duration : float

Length of time to run

106 Chapter 6. User Guide

Page 111: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

node_state_grid : 1D array of ints (x number of nodes) (optional)

Node states (if given, replaces model’s current node state grid)

plot_each_transition : bool (optional)

Option to display the grid after each transition

plotter : CAPlotter object (optional)

Needed if caller wants to plot after every transition

set_node_state_grid(node_states)Sets the grid of node-state codes to node_states. Also checks to make sure node_states is in the properformat, which is to say, it’s a Numpy array of the same length as the number of nodes in the grid.

Parameters node_states : 1D array of ints (x number of nodes in grid)

Notes

The node-state array is attached to the grid as a field with the name ‘node_state’.

setup_array_of_orientation_codes()Creates and configures an array that contain the orientation code for each active link (and correspondingcell pair).

Parameters (none)

Returns (none)

Notes

The setup varies depending on the type of LCA. The default is non-oriented, in which case we just havean array of zeros. Subclasses will override this method to handle lattices in which orientation matters (forexample, vertical vs. horizontal in an OrientedRasterLCA).

setup_transition_data(xn_list)Using the transition list and the number of link states, creates three arrays that collectively contain data onstate transitions:

n_xn: for each link state, contains the number of transitions out of that state.

xn_to: 2D array that records, for each link state and each transition, the new state intowhich the link transitions.

xn_rate: 2D array that records, for each link state and each transition, the rate (1/time) ofthe transition.

xn_propswap: 2D array that indicates, for each link state and each transition, whether thattransition is accompanied by a “property” swap, in which the two cells exchange proper-ties (in order to represent a particle moving)

update_component_data(new_node_state_array)Call this method to update all data held by the component, if, for example, another component or boundaryconditions modify the node statuses outside the component between run steps.

This method updates all necessary properties, including both node and link states.

new_node_state_array is the updated list of node states, which must still all be compatible with the statelist originally supplied to this component.

6.6. CellLab-CTS 107

Page 112: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

update_link_state(link, new_link_state, current_time)Implements a link transition by updating the current state of the link and (if appropriate) choosing the nexttransition event and pushing it on to the event queue.

Parameters link : int

ID of the link to update

new_link_state : int

Code for the new state

current_time : float

Current time in simulation

update_link_states_and_transitions(current_time)Following an “external” change to the node state grid, updates link states where necessary and creates anyneeded events.

update_node_states(tail_node, head_node, new_link_state)Updates the states of the two nodes in the given link.

Parameters tail_node : int

ID of the tail node of the link (cell pair) in question

head_node : int

ID of the head node of the link (cell pair) in question

new_link_state : int

Link state code for the new cell pair

Returns (bool, bool)

Flags indicating whether the tail node and head node, respectively, have changed state

Methods and Internal Documentation for the RasterCTS class

class RasterCTS(model_grid, node_state_dict, transition_list, initial_node_states, prop_data=None,prop_reset_value=None)

Class RasterLCA implements a non-oriented raster CellLab-CTS model.

Methods

assign_link_states_from_node_typescreate_link_state_dict_and_pair_listcurrent_link_statedo_transitionget_next_eventpush_transitions_to_event_queuerunset_node_state_gridsetup_array_of_orientation_codessetup_transition_dataupdate_component_data

Continued on next page

108 Chapter 6. User Guide

Page 113: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Table 6.10 – continued from previous pageupdate_link_stateupdate_link_states_and_transitionsupdate_node_states

Methods and Internal Documentation for the OrientedRasterCTS class

class OrientedRasterCTS(model_grid, node_state_dict, transition_list, initial_node_states,prop_data=None, prop_reset_value=None)

Class OrientedRasterCTS implements an oriented raster CellLab-CTS model.

Methods

assign_link_states_from_node_typescreate_link_state_dict_and_pair_listcurrent_link_statedo_transitionget_next_eventpush_transitions_to_event_queuerunset_node_state_gridsetup_array_of_orientation_codessetup_transition_dataupdate_component_dataupdate_link_stateupdate_link_states_and_transitionsupdate_node_states

setup_array_of_orientation_codes()Creates and configures an array that contain the orientation code for each active link (and correspondingcell pair).

Parameters (none)

Returns (none)

Notes

This overrides the method of the same name in landlab_ca.py.

Methods and Internal Documentation for the HexCTS class

class HexCTS(model_grid, node_state_dict, transition_list, initial_node_states, prop_data=None,prop_reset_value=None)

Class HexCTS implements a non-oriented hex-grid CellLab-CTS model.

Methods

6.6. CellLab-CTS 109

Page 114: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

assign_link_states_from_node_typescreate_link_state_dict_and_pair_listcurrent_link_statedo_transitionget_next_eventpush_transitions_to_event_queuerunset_node_state_gridsetup_array_of_orientation_codessetup_transition_dataupdate_component_dataupdate_link_stateupdate_link_states_and_transitionsupdate_node_states

Methods and Internal Documentation for the OrientedHexCTS class

class OrientedHexCTS(model_grid, node_state_dict, transition_list, initial_node_states, prop_data=None,prop_reset_value=None)

Class OrientedHexCTS implements an oriented hex-grid CellLab-CTS model.

Methods

assign_link_states_from_node_typescreate_link_state_dict_and_pair_listcurrent_link_statedo_transitionget_next_eventpush_transitions_to_event_queuerunset_node_state_gridsetup_array_of_orientation_codessetup_transition_dataupdate_component_dataupdate_link_stateupdate_link_states_and_transitionsupdate_node_states

setup_array_of_orientation_codes()Creates and configures an array that contain the orientation code for each active link (and correspondingcell pair).

Parameters (none)

Returns (none)

110 Chapter 6. User Guide

Page 115: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Notes

This overrides the method of the same name in celllab_cts.py. If the hex grid is oriented such that one ofthe 3 axes is vertical (a ‘vertical’ grid), then the three orientations are:

0 = vertical (0 degrees clockwise from vertical) 1 = right and up (60 degrees clockwise fromvertical) 2 = right and down (120 degrees clockwise from vertical)

If the grid is oriented with one principal axis horizontal (‘horizontal’ grid), then the orientations are:

0 = up and left (30 degrees counter-clockwise from vertical) 1 = up and right (30 degrees clock-wise from vertical) 2 = horizontal (90 degrees clockwise from vertical)

Methods and Internal Documentation for class Transition

class Transition(from_state, to_state, rate, name=None, swap_properties=False, prop_update_fn=None)Represents a transition from one state (“from_state”) to another (“to_state”) at a link. The transition probabilityis represented by a rate parameter “rate”, with dimensions of 1/T. The probability distribution of time until thetransition event occurs is exponentional with mean 1/rate. The optional name parameter allows the caller toassign a name to any given transition.

Note that from_state and to_state can now be either integer IDs for the standardised ordering of the link states(as before), or tuples explicitly describing the node state at each end, and the orientation. Orientation is 0:horizontal, L-R; 1: vertical, bottom-top. For such a tuple, order is (left/bottom, right/top, orientation).

Methods and Internal Documentation for class CAPlotter

class CAPlotter(ca, cmap=None)A CAPlotter is an object that handles display of a CellLab-CTS grid.

Methods

finalizeupdate_plot

finalize()Wraps up plotting by switching off interactive model and showing the plot.

update_plot()Plots the current node state grid.

References

Chopard, B., & Droz, M. (1998). Cellular automata. Cambridge University Press, Cambridge, UK.

Narteau, C., Le Mouël, J. L., Poirier, J. P., Sepúlveda, E., & Shnirman, M. (2001). On a small-scale roughness of thecore–mantle boundary. Earth and Planetary Science Letters, 191(1), 49-60.

Narteau, C., Zhang, D., Rozier, O., & Claudin, P. (2009). Setting the length and time scales of a cellular automa-ton dune model from the analysis of superimposed bed forms. Journal of Geophysical Research: Earth Surface(2003–2012), 114(F3).

6.6. CellLab-CTS 111

Page 116: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Rozier, O., & Narteau, C. (2014). A realspace cellular automaton laboratory. Earth Surface Processes and Landforms,39(1), 98-109.

Tucker, G.E., Hobley, D.E.J., Hutton, E., Gasparini, N.M., Istanbulluoglu, E., Adams, J.M., and Nudurupati, S.S.(in review) CellLab-CTS 2015: A Python library for continuous-time stochastic cellular automaton modeling usingLandlab. Submitted to Geoscientific Model Development, September 2015.

112 Chapter 6. User Guide

Page 117: landlab Documentation - Read the Docs

CHAPTER 7

Frequently Asked Questions

7.1 How do I set the boundary codes for the edges of a grid?

By default, the boundary nodes around the perimeter of a grid are all open boundaries. Fora raster grid, if you want to make one or more sides closed boundaries, use the grid methodset_closed_boundaries_at_grid_edges().

The following code snippet sets the southern boudary nodes to be closed.

>>> import landlab>>> grid = landlab.RasterModelGrid(3, 4)>>> grid.set_closed_boundaries_at_grid_edges(True, False, False, False)>>> grid.node_statusarray([4, 4, 4, 4, 1, 0, 0, 1, 1, 1, 1, 1], dtype=int8)

See also:

set_fixed_value_boundaries_at_grid_edges(), set_nodata_nodes_to_closed()

7.2 Can I import Landlab output into ParaView or VisIt?

See How do I get netCDF output? below.

7.3 How do I get netCDF output?

At present, Landlab can write output to a netCDF file if you are using a raster grid (support for unstructured grids iscoming later). A tutorial example is provided in landlab_tools_and_tricks. To create netCDF output, use the functionwrite_netcdf(). This function will write to file

1. the grid geometry, and

2. any data arrays that are linked to the grid

this will automatically include any arrays that you created with functions such as add_zeros(), as long as youprovided a name for the array as one of the arguments.

113

Page 118: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

7.4 How do I assign values from nodes to links?

Suppose you have a set of values, such as water depths, that are defined at nodes. How do you figure out what thecorresponding values would be at the links, so you can multiply these by some other quantity (such as water-surfaceslope) that is defined on links? Here are some options:

1. To assign the average

2. To assign the upstream value

3. to assign the downstream value

4. ...

7.5 Why are there no other FAQs besides these few?

Because the FAQ section hasn’t been finished yet.

114 Chapter 7. Frequently Asked Questions

Page 119: landlab Documentation - Read the Docs

CHAPTER 8

Developer Documentation

If you’re intending to make changes to the Landlab code base, or want to develop your own components, we recom-mend you follow these specialized developer install instructions.

8.1 Installing Landlab for Development

Landlab development takes place in your own fork of the main Landlab repository. A fork is a mirror of the repositoryand is hosted on your personal GitHub account. You will use this fork for developing new Landlab features. Yourchanges will migrate to the core repository (for review and merging) by requesting that the main repository “pull” inyour changes. This is known as a pull request and is facilitated through the GitHub website.

Note: For dev work, we actively recommend Anaconda over the Enthought Python Distribution, especially onWindows machines. This is because it ships with a working compiler already associated with Python, whereas theEPD does not. On a Mac, this is less important as the Xcode app (available through iTunes) gives you the necessarycompilers instead - install it now if you don’t have it! If you choose to use the EPD on a Windows machine, however,you’ll need to install separately either Visual Basic or MinGW and successfully associate them with your Pythoninstall. Help on this process can be found here. But unless you’re really invested in Canopy and the EPD, uninstallingit and replacing with Anaconda is probably the more stress-free way to go.

Either way, you’ll need a working C++ compiler running alongside Python to be able to perform a full developerinstall. You’ll see errors referring to Cython if you don’t have working compiler when calling python setup.py develop.

8.1.1 How to create a fork

You will only need to do this once for each project to which you want to contribute. Github has some great documen-tation on how to create a fork. We outline below the basic steps as applied to Landlab.

Create a GitHub account

1. You can create a GitHub account by going to the GitHub website.

2. If you haven’t already, Install Git. Note that if you are using a mac with OS lower than 10.7, we have found itdifficult to setup git, and you may want to upgrade your OS.

3. Configure your account to allow write access. If you choose to install the git GUI, then it will set-up an SSHkey for you. If you install on the command line, you might need some help with this, see Generating SSH Keyson GitHub.

115

Page 120: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

4. If you want to ensure the ssh key is set correctly, go to your home page on github and hit the account settings(wrench and screwdriver button in upper right corner). On this page hit the SSH keys tab on the left. This shouldshow that you have a key for whatever computer you are currently working on. Note that you may have morethan one key if you have installed git on more than one computer with the same user account.

Creating your own fork of Landlab

The following steps will create a fork of the Landlab repository under your github account.

1. Sign in to your GitHub account.

2. Go to the landlab home page on GitHub.

3. Click the fork button in the upper-right corner of the page.

Once completed, you will be redirected to the home page for your own copy of Landlab.

Cloning your fork to your computer

This is done from the GUI by:

1. Sign in to git on the GUI.

2. Hit on your account on the left side of the GUI.

3. This will show you your fork of Landlab. Hit the clone option next to the fork. This will download the Land-lab package to your local computer. If you are on a windows machine, this will put Landlab in the Docu-ments/GitHub folder. If you are on a mac, you are given the option of where to put the downloaded Landlabpackage.

This is done from the command line with the following commands:

> git clone [email protected]:your-user-name/landlab.git> cd landlab> git remote add upstream git://github.com/landlab/landlab.git

You can also clone your fork in the GUI directly through the website; navigate to the page for your fork on the web(UserName/landlab) and hit the “Clone in Desktop” button on the right hand side of the page. Make sure you have theGUI installed and set up on your machine before you try this for the most pain-free results.

Installing Landlab in developer mode

Before you start: Ensure you have installed with Xcode from the Apple app store (macs) or installed a working C++compiler on your machine (PCs) before proceeding with your developer install. You should also update your Pythondistribution! For Anaconda, use conda update –all (two dashes), and then separately, conda update setuptools (thesecond being essential!) from your terminal.

Note: This assumes you have never put Landlab on your machine before. If you’ve previously used pip to installLandlab, we recommmend you take that version off first. At a command prompt, use the command: pip uninstalllandlab

Now that you have a working copy of the Landlab code on you computer, you need to install it. To install Landlab indeveloper mode run the following command from the root Landlab folder (it will be landlab with a small l and willcontain setup.py):

> python setup.py develop

116 Chapter 8. Developer Documentation

Page 121: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

This installs Landlab on your computer in such a way that Python always imports Landlab from the working copy youjust cloned. This ensures that any changes you make to your copy of the code is seen by Python the next time youimport Landlab.

To uninstall your development version of Landlab (again from the root landlab folder) run the following command:

> python setup.py develop -u

With Landlab uninstalled, you will not longer be able to import Landlab from outside to root folder of your workingcopy.

To check you have correctly installed Landlab, run the Landlab tests. Do this by importing landlab in an interactivePython shell, then calling landlab.test().

Fetching updates to the trunk

From time to time you should fetch commits to the trunk that you don’t have in your working copy. You do this withthe following command:

> git fetch upstream

Making a new branch

Before making any changes to your code, you should create a new branch.

Update your mirror with any upstream changes you don’t have:

> git fetch upstream

Make the new branch:

> git branch name-of-branch upstream/master> git checkout name-of-branch

You will probably want to choose a descriptive name for your new branch so that you and others will remember whatit is you are intending to do with your branch (for example, bugfix-for-that-major-problem, or add-that-cool-feature).

If you want to keep your branches on you public GitHub page for Landlab (you probably do) you need to tell git topush changes to your github repo. This is done with the following command:

> git push --set-upstream origin name-of-branch

On your Landlab GitHub page you will now be able to toggle between your various branches to see the code you havecommitted.

The GUI also offers fairly simple, intuitive, and powerful control over branching and merging, for those uninclined touse the command line tools.

8.1.2 Testing the Landlab installation

The easiest way to run the Landlab tests is to do so from inside the Python interpreter:

>>> import landlab>>> landlab.test()

This will run a series of tests and print our the result of each test. If there are any failures, you can report that at thelandlab issue tracker.

8.1. Installing Landlab for Development 117

Page 122: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

8.1.3 Coding Style

• Please stick to the coding style described by PEP8.

• Class and function docstrings should follow the numpydoc conventions.

• Further, Landlab-specific advice for developing your own components can be found in the component develop-ment guide.

If you want to check how well you are doing, please look at our Landscape page. Landscape will grade the health ofthe landlab code with every push to GitHub.

8.1.4 Testing

Before merging any changes into the Landlab trunk, all unit tests (including doctests) should be passing. In addition,any new features added to Landlab should have an associated set of unit tests to verify that the new features are workingproperly.

Landlab uses Travis for continuous integration testing. The landlab page on Travis shows the latest testing results. Anew set of tests are executed whenever any changes are pushed to the Landlab repository and with every pull request.We currently run test suites for Python versions 2.6, 2.7, 3.3, and 3.4.

Continuous integration for Windows is done on Appveyor and also tests with Python 2.6, 2.7, 3.3, and 3.4.

Once you send a pull request from GitHub, you will be taken to the Landlab pull request page and all unit tests are run.You will see the status of the unit tests next to your latest commit description. If you see a green check, all tests passedand your changes can be merged! However, if you see an ex there was a problem running the tests. If you believe yourchanges are responsible for the failures, please fix them until the tests pass. Note that you do not need to send a newpull request after committing for fixes. They will be added to the current pull request and the tests automatically rerun.

You can also run unit tests locally with the test-installed-landlab.py script found in the scripts folder:

> python test-installed-landlab.py --doctest

If you don’t want to run the doctests, you can drop the –doctest option. Note that this script will test whatever versionof landlab you have installed, which may or may not be the one you are working on in your current working directory.

8.1.5 Building Binary Distributions

Ultimately, this will be automated but, for now, this is how we build our binary distributions. The basic workflow isthe following:

• Create a fresh virtual Python environment

• Install landlab dependencies

• Install landlab

• Create a wheel

• Deploy the distribution to PyPI.

The bash script, dist_to_pypi.sh is intended to help with this process. Note that it uses conda to create environmentsand install packages. Thus, to use this script you will need to have Anaconda installed. To build (and upload) a newset of binaries:

> bash_to_pypi.sh version [version [...]]

Where version is the Python version for your build. You can also build distributions for multiple version of Python.For example:

118 Chapter 8. Developer Documentation

Page 123: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

> bash_to_pypi.sh 2.6 2.7 3.3 3.4

If the version of landlab you are installing is the same as what is already on PyPI, you will not be able to upload thenew version. To upload a new set of wheels, you must fist increase the landlab version number in landlab/__init__.py.

Windows distributions are built in much the same way. However, they are created on Appveyor as part of the WindowsCI. Note that although Appveyor runs the landlab tests with every push to GitHub, binary distributions are only builtwhen a version is tagged. To create a tag for a new release:

> git tag <version>

You will then need to push the tag to GitHub to activate the build. For example:

> git tag v0.1.27> git push --tags

For consistency, please stick with the above version format and follow the usual Python versioning standards.

8.1.6 Troubleshooting

What do I do if my pull request cannot be automatically merged?

Get the latest upstream/master and go to the master branch. Remember, do not develop here. Always develop in afeature branch. Merge the lastest upstream master with your master:

> git fetch upstream> git checkout master> git merge upstream/master

Go to the branch on which you are developing and merge the lastest upstream master with your branch:

> git checkout <branch_name>> git merge upstream/master

Fix the conflicts. Do this by hand or with a merge editor. This is where you decide how to integrate the conflictingchanges. Since only you know what and why you made the changes you did, this can only be done by you:

> git mergetool

After everything has been fixed, commit the changes and push the changes to the repository. The pull request willautomatically be updated:

> git commit> git push

I’m still confused

The Landlab development team will be happy to hear from you. Email one of us or create an issue request and we’lltry to resolve your problem.

8.2 Landlab Component Developer Guide

This section under construction!

8.2. Landlab Component Developer Guide 119

Page 124: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

For now, see the main section on Landlab components. Feel free to contact the development team for more specificadvice.

120 Chapter 8. Developer Documentation

Page 125: landlab Documentation - Read the Docs

CHAPTER 9

References

• genindex

• modindex

• search

121

Page 126: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

122 Chapter 9. References

Page 127: landlab Documentation - Read the Docs

Index

Symbols__init__() (HexModelGrid method), 51__init__() (RadialModelGrid method), 50__init__() (RasterModelGrid method), 49__init__() (VoronoiDelaunayGrid method), 50

Aactive_link_length (ModelGrid attribute), 57, 63active_links (ModelGrid attribute), 63are_all_core() (RasterModelGrid method), 65, 83assign_link_states_from_node_types() (Cell-

LabCTSModel method), 105assign_upslope_vals_to_active_links() (ModelGrid

method), 56axis_name (ModelGrid attribute), 57axis_units (ModelGrid attribute), 57

Bbottom_edge_node_ids() (RasterModelGrid method), 65,

83build_all_node_distances_azimuths_maps() (ModelGrid

method), 72

Ccalculate_aspect_at_nodes_bestFitPlane() (RasterModel-

Grid method), 91calculate_diff_at_active_links() (ModelGrid method), 75calculate_diff_at_links() (ModelGrid method), 75calculate_flux_divergence_at_core_nodes() (ModelGrid

method), 75calculate_flux_divergence_at_nodes() (ModelGrid

method), 77calculate_flux_divergence_at_nodes() (RasterModelGrid

method), 77calculate_gradient_across_cell_corners() (RasterModel-

Grid method), 78calculate_gradient_across_cell_faces() (RasterModel-

Grid method), 78calculate_gradients_at_active_links() (ModelGrid

method), 77

calculate_gradients_at_links() (ModelGrid method), 77calculate_numbers_of_node_neighbors() (ModelGrid

method), 58, 63calculate_slope_aspect_at_nodes_bestFitPlane() (Raster-

ModelGrid method), 91calculate_slope_at_nodes_bestFitPlane() (RasterModel-

Grid method), 92calculate_steepest_descent_across_adjacent_cells()

(RasterModelGrid method), 78calculate_steepest_descent_across_cell_corners()

(RasterModelGrid method), 79calculate_steepest_descent_across_cell_faces() (Raster-

ModelGrid method), 80CAPlotter (class in land-

lab.components.cellular_automata.celllab_cts),111

cell_areas (ModelGrid attribute), 58cell_faces() (RasterModelGrid method), 65cell_vector_to_raster() (RasterModelGrid method), 92CellLabCTSModel (class in land-

lab.components.cellular_automata.celllab_cts),105

closed_boundary_nodes (ModelGrid attribute), 63, 81core_cell_index_at_nodes (ModelGrid attribute), 63core_nodes (ModelGrid attribute), 63, 81corner_nodes (RasterModelGrid attribute), 66create_active_link_array_zeros() (ModelGrid method),

52create_diagonal_list() (RasterModelGrid method), 66create_link_state_dict_and_pair_list() (Cell-

LabCTSModel method), 105create_neighbor_list() (RasterModelGrid method), 66create_node_array_zeros() (ModelGrid method), 52current_link_state() (CellLabCTSModel method), 105

Dd8_active_links() (RasterModelGrid method), 59diffuse() (PerronNLDiffuse method), 47display_grid() (ModelGrid method), 91do_transition() (CellLabCTSModel method), 106dx (RasterModelGrid attribute), 59

123

Page 128: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

Eempty() (ModelGrid method), 53erode() (SPEroder method), 48

Fface_links() (RasterModelGrid method), 66finalize() (CAPlotter method), 111find_nearest_node() (RasterModelGrid method), 73FireGenerator (class in land-

lab.components.fire_generator.generate_fire),43

FlexureComponent (class in land-lab.components.flexure.flexure), 43

FlowRouter (class in land-lab.components.flow_routing.route_flow_dn),45

force_boundaries_from_gradients() (RasterModelGridmethod), 83

forced_cell_areas (ModelGrid attribute), 58

Gget_active_cell_node_ids() (ModelGrid method), 63get_active_link_connecting_node_pair() (ModelGrid

method), 63get_active_link_connecting_node_pair() (RasterModel-

Grid method), 67get_boundary_nodes() (ModelGrid method), 63, 82get_core_nodes() (ModelGrid method), 64get_diagonal_list() (RasterModelGrid method), 67get_distances_of_nodes_to_point() (ModelGrid method),

72get_face_connecting_cell_pair() (RasterModelGrid

method), 67get_grid_xdimension() (RasterModelGrid method), 60get_grid_ydimension() (RasterModelGrid method), 60get_link_connecting_node_pair() (RasterModelGrid

method), 67get_neighbor_list() (RasterModelGrid method), 68get_next_event() (CellLabCTSModel method), 106get_node_status() (ModelGrid method), 64, 82get_nodes_around_point() (RasterModelGrid method),

73grid_coords_to_node_id() (RasterModelGrid method),

68, 74

Hhas_boundary_neighbor() (RasterModelGrid method),

69, 84HexCTS (class in land-

lab.components.cellular_automata.hex_cts),109

hillshade() (RasterModelGrid method), 93

Iis_boundary() (ModelGrid method), 64, 82is_core() (RasterModelGrid method), 69, 84is_point_on_grid() (RasterModelGrid method), 75

Lleft_edge_node_ids() (RasterModelGrid method), 69, 84link_faces() (RasterModelGrid method), 70link_length (ModelGrid attribute), 58, 64link_length (RasterModelGrid attribute), 60LinkCellularAutomaton (class in land-

lab.components.linkca.link_ca), 48

Mmax_active_link_length() (ModelGrid method), 58max_active_link_length() (RasterModelGrid method), 61max_of_link_end_node_values() (ModelGrid method),

57min_active_link_length() (ModelGrid method), 58min_active_link_length() (RasterModelGrid method), 61

Nndim (ModelGrid attribute), 58node_activelinks() (RasterModelGrid method), 70node_axis_coordinates() (ModelGrid method), 64, 73node_boundary_status (ModelGrid attribute), 64, 82node_inlink_matrix (ModelGrid attribute), 63node_links() (RasterModelGrid method), 71node_outlink_matrix (ModelGrid attribute), 63node_spacing (RasterModelGrid attribute), 61node_vector_to_raster() (RasterModelGrid method), 93node_x (ModelGrid attribute), 64, 73node_y (ModelGrid attribute), 65, 73number_of_active_cells (ModelGrid attribute), 58number_of_active_faces (ModelGrid attribute), 58number_of_active_links (ModelGrid attribute), 58number_of_active_nodes (ModelGrid attribute), 58number_of_cells (ModelGrid attribute), 59number_of_core_cells (ModelGrid attribute), 58number_of_core_nodes (ModelGrid attribute), 58number_of_elements() (ModelGrid method), 59number_of_faces (ModelGrid attribute), 59number_of_interior_nodes (RasterModelGrid attribute),

61number_of_links (ModelGrid attribute), 59number_of_node_columns (RasterModelGrid attribute),

62number_of_node_rows (RasterModelGrid attribute), 62number_of_nodes (ModelGrid attribute), 59number_of_nodes (RasterModelGrid attribute), 61

Oones() (ModelGrid method), 53

124 Index

Page 129: landlab Documentation - Read the Docs

landlab Documentation, Release 0.1

open_boundary_nodes (ModelGrid attribute), 65, 82OrientedHexCTS (class in land-

lab.components.cellular_automata.oriented_hex_cts),110

OrientedRasterCTS (class in land-lab.components.cellular_automata.oriented_raster_cts),109

PPerronNLDiffuse (class in land-

lab.components.nonlinear_diffusion.Perron_nl_diffuse),46

push_transitions_to_event_queue() (CellLabCTSModelmethod), 106

RRasterCTS (class in land-

lab.components.cellular_automata.raster_cts),108

read_esri_ascii() (in module landlab.io.esri_ascii), 54read_netcdf() (in module landlab.io.netcdf.read), 54resolve_values_on_active_links() (ModelGrid method),

57resolve_values_on_links() (ModelGrid method), 57right_edge_node_ids() (RasterModelGrid method), 71,

85route_flow() (FlowRouter method), 45run() (CellLabCTSModel method), 106

Sset_closed_boundaries_at_grid_edges() (RasterModel-

Grid method), 89set_closed_nodes() (ModelGrid method), 82set_fixed_gradient_boundaries() (RasterModelGrid

method), 85set_fixed_value_boundaries_at_grid_edges() (Raster-

ModelGrid method), 88set_looped_boundaries() (RasterModelGrid method), 90set_nodata_nodes_to_closed() (ModelGrid method), 82set_nodata_nodes_to_inactive() (ModelGrid method), 53set_node_state_grid() (CellLabCTSModel method), 107setup_array_of_orientation_codes() (CellLabCTSModel

method), 107setup_array_of_orientation_codes() (OrientedHexCTS

method), 110setup_array_of_orientation_codes() (OrientedRasterCTS

method), 109setup_transition_data() (CellLabCTSModel method), 107shape (RasterModelGrid attribute), 62SPEroder (class in land-

lab.components.stream_power.fastscape_stream_power),47

Ttop_edge_node_ids() (RasterModelGrid method), 72, 91Transition (class in land-

lab.components.cellular_automata.celllab_cts),111

Uupdate_component_data() (CellLabCTSModel method),

107update_link_state() (CellLabCTSModel method), 107update_link_states_and_transitions() (CellLabCTSModel

method), 108update_links_nodes_cells_to_new_BCs() (ModelGrid

method), 83update_node_states() (CellLabCTSModel method), 108update_plot() (CAPlotter method), 111

Wwrite_netcdf() (in module landlab.io.netcdf.write), 55

Zzeros() (ModelGrid method), 53

Index 125