MaterialLayers: Add material layers to a landlab grid#

class MaterialLayers(number_of_stacks, allocated=0)[source]#

Bases: EventLayers

Track MaterialLayers where each layer has some material in it.

MaterialLayers are meant to represent a layered object in which each layer has some material in it. If erosion occurs, no new layer is created. These layers stand in contrast to the EventLayers for which each event is represented by a layer.

MaterialLayers is likely a more memory efficent data structure than EventLayers as it does not record erosion as an array of zeros.

Parameters:

number_of_stacks (int) – Number of layer stacks to track.

Examples

>>> from landlab.layers.materiallayers import MaterialLayers

Create an empty layer stack with 5 stacks.

>>> layers = MaterialLayers(5)
>>> layers.number_of_stacks
5
>>> layers.number_of_layers
0

Add a layer with a uniform thickness.

>>> layers.add(1.5)
>>> layers.number_of_layers
1
>>> layers.dz
array([[ 1.5,  1.5,  1.5,  1.5,  1.5]])

MaterialLayers will combine layers if they have the same attributes. Adding a second layer with uneven thickness. Will increment the first layers thickness. This stands in contrast with EventLayers which will track each addition as a separate entry in the layers datastructure.

>>> layers.add([1.0, 2.0, 3.0, 5.0, 0.0])
>>> layers.dz
array([[ 2.5,  3.5,  4.5,  6.5,  1.5]])

Adding a layer with negative thickness will remove material from the layers. Unlike EventLayers, it will not add a layer of zeros that represent an event with no deposition.

>>> layers.add(-1)
>>> layers.dz
array([[ 1.5,  2.5,  3.5,  5.5,  0.5]])

Get the index value of the layer within each stack at the topographic surface.

>>> layers.surface_index
array([0, 0, 0, 0, 0])

See the example in the add method to learn how MaterialLayers behaves if material properties are also tracked.

add(dz, **kwds)[source]#

Add a layer to the MaterialLayers stacks.

Parameters:

dz (float or array_like) – Thickness to add to each stack.

Examples

>>> from landlab.layers.materiallayers import MaterialLayers

Create an empty layer stack with 3 stacks.

>>> layers = MaterialLayers(3)
>>> layers.number_of_layers
0

To add a layer of uniform thickness to every stack.

>>> layers.add(1.5)
>>> layers.number_of_layers
1
>>> layers.dz
array([[ 1.5,  1.5,  1.5]])

Add a second layer with uneven thickness.

>>> layers.add([1.0, 2.0, 0.5])
>>> layers.dz
array([[ 2.5,  3.5,  2. ]])

Because the attributes of this layer and the previous layer are the same (e.g. they don’t exist), MaterialLayer will combine them. This is the primary difference between MaterialLayers and EventLayers.

Adding a layer with negative thickness will remove material from the top of the stack.

>>> layers.add(-1)
>>> layers.dz
array([[ 1.5,  2.5,  1. ]])
>>> layers.number_of_layers
1

Use keywords to track properties of each layer. For instance, here we create a new stack and add a layer with a particular type and a particular size. You can access the layer properties as if the object were a dictionary.

>>> layers = MaterialLayers(3)
>>> layers.add(1.0, type=3.0, size="sand")
>>> layers.dz
array([[ 1.,  1.,  1.]])
>>> layers["type"]
array([[ 3.,  3.,  3.]])

As you can see, there is no rule that says you can’t use a string as the value of an attribute.

Adding a layer with the same attributes as the entire surface of the MaterialLayers will result in the layers being combined.

>>> layers.add(1.0, type=3.0, size="sand")
>>> layers.add([2, -1, 0], type=3.0, size="sand")
>>> layers.dz
array([[ 4.,  1.,  2.]])

Adding material with different attributes results in the creation of a new layer.

>>> layers.add(2.0, type=6.0, size="sand")
>>> layers.dz
array([[ 4.,  1.,  2.],
       [ 2.,  2.,  2.]])
>>> layers["type"]
array([[ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])
>>> np.all(
...     layers["size"] == [["sand", "sand", "sand"], ["sand", "sand", "sand"]]
... )
True

Attributes for each layer will exist even if part the the layer is associated with erosion.

>>> layers.add([-2, -1, 1], type=8.0, size="gravel")
>>> layers.dz
array([[ 4.,  1.,  2.],
       [ 0.,  1.,  2.],
       [ 0.,  0.,  1.]])
>>> layers["type"]
array([[ 3.,  3.,  3.],
       [ 6.,  6.,  6.],
       [ 8.,  8.,  8.]])

To get the values at the surface of the layer stack:

>>> layers.get_surface_values("type")
array([ 3.,  6.,  8.])

Removing enough material such that an entire layer’s thickness is no longer present, results in that layer no longer being tracked. This is another difference between MaterialLayers and EventLayers.

>>> layers.add([0.0, 0.0, -1.0])
>>> layers.dz
array([[ 4.,  1.,  2.],
       [ 0.,  1.,  2.]])
>>> layers["type"]
array([[ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])
>>> np.all(
...     layers["size"] == [["sand", "sand", "sand"], ["sand", "sand", "sand"]]
... )
True
>>> layers.number_of_layers
2

If attributes (like age and size in this example) are tracked, a layer will be combined with the surface layer only if all attributes are the same across the entire layer. Right now, the surface values vary.

>>> layers.get_surface_values("type")
array([ 3.,  6.,  6.])
>>> np.all(layers.get_surface_values("size") == ["sand", "sand", "sand"])
True

Since the surface has different types, adding material will create a new layer.

>>> layers.add(3.0, type=6.0, size="sand")
>>> layers.dz
array([[ 4.,  1.,  2.],
       [ 0.,  1.,  2.],
       [ 3.,  3.,  3.]])
>>> layers["type"]
array([[ 3.,  3.,  3.],
       [ 6.,  6.,  6.],
       [ 6.,  6.,  6.]])
>>> layers.number_of_layers
3

But now, the entire surface has the qualities of type = 6. and size = ‘sand’, so layers will be combined. This even works if the thickness of the new layer includes both erosion and deposition.

>>> layers.add([-3.5, 0.0, 2.0], type=6.0, size="sand")
>>> layers.dz
array([[ 3.5,  1. ,  2. ],
       [ 0. ,  1. ,  2. ],
       [ 0. ,  3. ,  5. ]])
>>> layers["type"]
array([[ 3.,  3.,  3.],
       [ 6.,  6.,  6.],
       [ 6.,  6.,  6.]])
>>> layers.number_of_layers
3
property allocated#

Total number of allocated layers.

Examples

>>> from landlab.layers.eventlayers import EventLayers
>>> layers = EventLayers(3)
>>> layers.number_of_layers
0
>>> layers.allocated == 0
True
>>> layers.add(15.0)
>>> layers.number_of_layers
1
>>> layers.allocated == 7
True
>>> for _ in range(layers.allocated):
...     layers.add(0.0)
...
>>> layers.number_of_layers
8
>>> layers.allocated == 15
True

If you know how many layers you will ultimately have, you can allocated enough memory for them when you create your layer stacks.

>>> layers = EventLayers(3, allocated=15)
>>> layers.number_of_layers
0
>>> layers.allocated == 15
True
>>> layers.add(15.0)
>>> layers.number_of_layers
1
>>> layers.allocated == 15
True
>>> for _ in range(layers.allocated):
...     layers.add(0.0)
...
>>> layers.number_of_layers
16
>>> layers.allocated == 24
True
property dz#

Thickness of each layer.

The thickness of each layer at each stack as an array of shape (number_of_layers, number_of_stacks).

Examples

>>> from landlab.layers.eventlayers import EventLayers

Initially there are no layers so there are not thicknesses.

>>> layers = EventLayers(3)
>>> layers.dz.shape == (0, 3)
True

Now add two layers, the first of uniform thickness and the second non-uniform and with some erosion.

>>> layers.add(15.0)
>>> layers.add([1.0, -1.0, 2.0])
>>> layers.dz
array([[ 15.,  14.,  15.],
       [  1.,   0.,   2.]])
get_surface_values(name)#

Values of a field on the surface layer.

is_compatible(dz, **kwds)[source]#

Check if a new layer is compatible with the existing top layer.

Parameters:

dz (float or array_like) – Thickness to add to each stack.

Returns:

True if the new layer is compatible, otherwise False.

Return type:

bool

property number_of_layers#

Total number of layers.

Examples

>>> from landlab.layers.eventlayers import EventLayers
>>> layers = EventLayers(3)
>>> layers.number_of_layers
0
>>> layers.add(15.0)
>>> layers.add([1.0, -1.0, 2.0])
>>> layers.number_of_layers
2
property number_of_stacks#

Number of stacks.

reduce([start, ]stop[, step])#

Combine layers.

Reduce adjacent layers into a single layer.

Examples

>>> from landlab.layers.eventlayers import EventLayers

Create an empty layer stack with 3 stacks.

>>> layers = EventLayers(3)
>>> layers.number_of_layers
0

To add a layer of uniform thickness to every stack.

>>> layers.add(1.5)
>>> layers.number_of_layers
1
>>> layers.dz
array([[ 1.5,  1.5,  1.5]])

Add a second layer with uneven thickness.

>>> layers.add([1.0, 2.0, 0.5])
>>> layers.dz
array([[ 1.5,  1.5,  1.5],
       [ 1. ,  2. ,  0.5]])

Combine all of the layers into a single layer.

>>> layers.reduce()
>>> layers.dz
array([[ 2.5,  3.5,  2. ]])

Add two additional layers to the top. The bottom-most layer is row 0, and the two new layers are rows 1 and 2.

>>> layers.add([1.0, 2.0, 0.5])
>>> layers.add([1.0, 2.0, 0.5])
>>> layers.dz
array([[ 2.5,  3.5,  2. ],
       [ 1. ,  2. ,  0.5],
       [ 1. ,  2. ,  0.5]])

Combine the two new layers (layers 1 and 2) into a single layer.

>>> layers.reduce(1, 3)
>>> layers.dz
array([[ 2.5,  3.5,  2. ],
       [ 2. ,  4. ,  1. ]])
>>> layers.add([1.0, 2.0, 0.5])
>>> layers.add([1.0, 2.0, 0.5])
>>> layers.dz
array([[ 2.5,  3.5,  2. ],
       [ 2. ,  4. ,  1. ],
       [ 1. ,  2. ,  0.5],
       [ 1. ,  2. ,  0.5]])

Combine the middle two layers.

>>> layers.reduce(1, 3)
>>> layers.dz
array([[ 2.5,  3.5,  2. ],
       [ 3. ,  6. ,  1.5],
       [ 1. ,  2. ,  0.5]])
>>> layers.add([1.0, 1.0, 1.0])
>>> layers.dz
array([[ 2.5,  3.5,  2. ],
       [ 3. ,  6. ,  1.5],
       [ 1. ,  2. ,  0.5],
       [ 1. ,  1. ,  1. ]])

Combine every two layers (layers 0 and 1 and combined, and layers 1 and 2 are combined).

>>> layers.reduce(0, 4, 2)
>>> layers.dz
array([[ 5.5,  9.5,  3.5],
       [ 2. ,  3. ,  1.5]])

When layers are combined, thicknesses are summed but layer attributes can be combined in other ways (e.g. max, or mean)

>>> layers = EventLayers(3)
>>> layers.add([1, 1, 1], age=0.0)
>>> layers.add([1, 2, 5], age=1.0)
>>> layers.add([2, 2, 2], age=2.0)
>>> layers.reduce(age=np.max)
>>> layers["age"]
array([[ 2.,  2.,  2.]])
>>> layers.add([2, 2, 2], age=3.0)
>>> layers.add([2, 2, 2], age=4.0)
>>> layers.reduce(1, 3, age=np.mean)
>>> layers["age"]
array([[ 2. ,  2. ,  2. ],
       [ 3.5,  3.5,  3.5]])
property surface_index#

Index to the top non-empty layer.

Examples

>>> from landlab.layers.eventlayers import EventLayers

Create an empty layer stack with 5 stacks.

>>> layers = EventLayers(3)
>>> layers.surface_index
array([0, 0, 0])

Add a layer with a uniform thickness.

>>> for _ in range(5):
...     layers.add(1.0)
...
>>> layers.surface_index
array([4, 4, 4])

Add a layer with varying thickness. Negative thickness removes thickness from underlying layers, zero thickness adds a layer but doesn’t change the surface index.

>>> layers.add([-1.0, 0.0, 1.0])
>>> layers.surface_index
array([3, 4, 5])
property thickness#

Total thickness of the columns.

The sum of all layer thicknesses for each stack as an array of shape (number_of_stacks, ).

Examples

>>> from landlab.layers.eventlayers import EventLayers

Initially there are no layers so the total thickness is 0.

>>> layers = EventLayers(3)
>>> layers.thickness
array([ 0.,  0.,  0.])

After adding some layers, the stacks have varying thicknesses.

>>> layers.add(15.0)
>>> layers.add([1.0, -1.0, 2.0])
>>> layers.thickness
array([ 16.,  14.,  17.])
property tracking#

Layer properties being tracked.

Examples

>>> from landlab.layers.eventlayers import EventLayers
>>> layers = EventLayers(3)
>>> layers.tracking
[]
>>> layers.add(1.0, age=1.0)
>>> layers.tracking
['age']
property z#

Thickness to top of each layer.

Thickness from the bottom of each stack to the top of each layer as an array of shape (number_of_layers, number_of_stacks).

Examples

>>> from landlab.layers.eventlayers import EventLayers

Initially there are no layers so the elevation to the top is 0.

>>> layers = EventLayers(3)
>>> layers.z.shape == (0, 3)
True

After adding some layers, elevations are to the top of each layer.

>>> layers.add(15.0)
>>> layers.add([1.0, -1.0, 2.0])
>>> layers.dz
array([[ 15.,  14.,  15.],
       [  1.,   0.,   2.]])
>>> layers.z
array([[ 15.,  14.,  15.],
       [ 16.,  14.,  17.]])
class MaterialLayersMixIn[source]#

Bases: object

MixIn that adds a MaterialLayers attribute to a ModelGrid.

property material_layers#

MaterialLayers for each cell.