Tides on a randomly vegetated field
-----------------------------------
In this notebook we will be running the
`Landlab `__ tidal-flow-calculator over a
randomly generated field of vegetation (simulated by 2 Mannings
Roughness values) and looking at how passive particle transport is
impacted by the spatial distribution of plants.
Importing and Installing
~~~~~~~~~~~~~~~~~~~~~~~~
First we will import some standard scientific Python libraries
.. code:: ipython3
import matplotlib.pyplot as plt
import numpy as np
Next we need to install some libraries (including Landlab) to properly
accomplish this task.
As of this writing (8/18/2020) the tidal-flow-calculator is not part of
the core Landlab installation. As a consequence, we need to checkout the
feature branch containing the tidal-flow-calculator component
(https://github.com/landlab/landlab/tree/gt/tidal-flow-component). After
checking out or cloning this branch locally, ``python setup.py install``
should be run to build a new landlab installation containing the
tidal-flow-calculator.
To build random fields of different characteristic length scales, we
will use the geostatistical toolbox
`GSTools `__. To install
this package, the command ``conda install gstools`` can be run from the
command line. In this example we will be using a standard covariance
model for random field generation.
Lastly, to simulate passive particle transport we will use the
Lagrangian-based transport model
`dorado `__. To install dorado we
can type ``pip install pydorado`` from the command line.
.. code:: ipython3
from landlab.components import TidalFlowCalculator
from landlab import RasterModelGrid
from landlab.grid.mappers import map_max_of_link_nodes_to_link
from dorado.routines import plot_state
import gstools as gs
Lastly there are some custom scripts containing functions we want to use
for this example. These scripts are available in the same directory as
this notebook, and so our imports will be happening locally.
.. code:: ipython3
from map_fun import gridded_vars
from plot_fun import group_plot
from plot_fun import plot_depth
from particletransport import init_particles
from particletransport import tidal_particles
Model Parameters
~~~~~~~~~~~~~~~~
We are going to create model parameters that define the tidal scenario
for the tidal-flow-calculator as well as the random field properties.
First we will define the size of the domain (which is going to be a
square) as well as the grid spacing, mean water depth, and properties
associated with the tide. Two roughness values are going to be
specified, a low and high roughness to represent low and high vegetation
density.
.. code:: ipython3
nrows = 250
ncols = nrows
grid_spacing = 1.0 # m
mean_depth = 1.5 # m
tidal_range = 0.5 # m
roughness_low = 0.01 # s/m^1/3, i.e., Manning's n
roughness_high = 0.1 # s/m^1/3, i.e., Manning's n
tide_period = 2*60*60 # tidal period in seconds
n_tide_periods = 10 # number of tidal periods to move particles around for
Np_tracer = 100 # number of passive particles to use
We also need to define properties of the random field. The two values of
importance here are the ``seed`` which defines the random seed that is
used (can be nice for reproducability) and the value ``len_scale`` which
specifies the length scale of the features. ``len_scale`` is an integer
for an isotropic field, but can be a list (e.g. ``[5, 10]``) to create
an anisotropic field.
.. code:: ipython3
seed = 1 # defines the random seed
len_scale = 10 # length scale - integer = isotropic; list [1, 5] = anisotropic
Generating a random field
~~~~~~~~~~~~~~~~~~~~~~~~~
Now we will be generating a random field based on the ``seed`` and
``len_scale`` parameters defined above.
.. code:: ipython3
x = y = range(nrows)
model = gs.Gaussian(dim=2, var=1, len_scale=len_scale)
srf = gs.SRF(model, seed=seed)
srf.structured([x, y])
gs.transform.binary(srf)
# get array info from srf object
srf_array = srf.field
.. code:: ipython3
# Let's visualize this random field
plt.figure()
plt.imshow(srf_array)
plt.colorbar()
plt.title('Random Field')
plt.show()
.. image:: output_14_0.png
Defining the Landlab Grid
~~~~~~~~~~~~~~~~~~~~~~~~~
Next we are going to be defining the Landlab grid object and its
associated parameters. This is where we will be passing in the roughness
values as dictated by the random field. In areas where the random field
values exceed 0, the roughness will be high, and in areas where the
random field values are negative the roughness will be low.
*Note:* We are defining a domain in which the top and bottom boundaries
are open and the left and right boundaries are closed. You can modify
this by changing the True/False values!
.. code:: ipython3
# create and set up the grid
grid = RasterModelGrid((nrows, ncols), xy_spacing=grid_spacing)
z = grid.add_zeros('topographic__elevation', at='node')
grid.set_closed_boundaries_at_grid_edges(True, False, True, False)
# set up roughness field (calculate on nodes, then map to links)
roughness_at_nodes = np.zeros_like(z)
roughness_at_nodes[srf_array.flatten() > 0] = roughness_high # high roughness
roughness_at_nodes[srf_array.flatten() < 0] = roughness_low # low roughness
roughness = grid.add_zeros('roughness', at='link')
map_max_of_link_nodes_to_link(grid, roughness_at_nodes, out=roughness)
.. parsed-literal::
array([ 0.01, 0.01, 0.01, ..., 0.01, 0.01, 0.01])
Instantiate the TidalFlowCalculator and run it
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython3
# instantiate the TidalFlowCalculator
tfc = TidalFlowCalculator(grid, tidal_range=tidal_range,
tidal_period=tide_period, roughness='roughness')
# run it
tfc.run_one_step()
Initialize the particles and run them
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython3
# get gridded values
gvals = gridded_vars(grid)
# initialize the particle parameters
# particles will be placed in center of domain
center_region = list(range(int(nrows/2-10), int(nrows/2+10)))
seed_xloc = center_region
seed_yloc = center_region
params = init_particles(seed_xloc, seed_yloc, Np_tracer, grid_spacing, gvals)
.. code:: ipython3
%%capture
# move the particles with the tides
walk_data = tidal_particles(params, tide_period/10, n_tide_periods,
plot_grid=np.flipud(np.reshape(roughness_at_nodes,
grid.shape)))
Make visualizations
~~~~~~~~~~~~~~~~~~~
First we will visualize the velocity components of the ebb and flood
tides. Then we will plot the particle locations at beginning and end of
the simulation.
.. code:: ipython3
# plot velocity information
group_plot(gvals)
plt.show()
.. image:: output_23_0.png
.. code:: ipython3
# plot particle locations on the roughness field
plt.figure(figsize=(10, 10))
# first plot initial locations as blue dots
plot_state(np.flipud(np.reshape(roughness_at_nodes,grid.shape)),
walk_data, iteration=0, target_time=None, c='b')
# then plot final locations as red dots
plot_state(np.flipud(np.reshape(roughness_at_nodes,grid.shape)),
walk_data, iteration=-1, target_time=None, c='r')
# make the colorbar - yellow for high roughness, purple for low
plt.colorbar()
# tighten layout
plt.tight_layout()
# show it
plt.show()
.. image:: output_24_0.png
Other Outpus, Gifs and More
~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this example we only ran the module for 10 tidal cycles. If instead
we ran it for 50 tidal cycles and captured the particle position after
each ebb/flood tide, we could create the following video:
.. figure:: ../imgs/random_field/demo_len_scale_10.gif
:alt: 50_Tidal_Cycles_gif
50_Tidal_Cycles_gif
We can also examine cases where the length scale of the features in the
random field is changed, if we reduce the feature size then the
particles are impeded less often and can travel further. Let’s take a
look at what happens when the feature length scale is reduced from
``len_scale=10`` to ``len_scale=5``:
.. figure:: ../imgs/random_field/demo_len_scale_05.gif
:alt: len_scale_05_gif
len_scale_05_gif
Now we can see that some particles make it to the edge of the domain,
where we might say they ‘leave’ the area of study. This is a quick and
dirty demonstration of how the spatial locations and spread of
vegetation impacts the transport of nutrients and materials under the
imposition of tidal flows.