 Okay, before we get started, we'll do one last audio and video check here. Lynn, can you hear me and see the intro slide? Yes, I can. Okay, great. So we'll go ahead and get started. Welcome everybody to this webinar about the LandLab Toolkit. My name is Greg Tucker. I'm the director of CSDMS and a member of the LandLab Development Team. And what we're going to do today is I'm going to give an overview of what LandLab is, what it can do, why it was developed, and we'll do that in two parts. I'll show a few slides to sort of give the broad view of what LandLab is and what are some of its capabilities, and then switch to showing a couple of demos that are run in Jupyter Notebooks to give a little bit of a sense of what LandLab looks like when it's live and in action. And then we'll open it up to questions. So I expect the slides portion of this will take maybe 20 or 25 minutes and we'll have perhaps 20 minutes of notebook demo and then plenty of time for questions at the end. Before I dive into this, let me point out that this is the inaugural webinar of the new CSDMS webinar series. We have more coming up soon. Let's see here. A couple that are coming up this fall are listed here. One is on using CSDMS products in the classroom. That's going to be taught by CSDMS Deputy Director, Irina Overame. And that will be on October 9th at noon Eastern time. And then the other one will be a webinar led by Mark Piper, a research software engineer with CSDMS on the basic model interface and what that's about. That will be on November 13th also at noon Eastern time. So stay tuned for those and for more webinars coming up in the new year. If you have a topic that you'd like to do a webinar on and you think it might be of broad interest to the CSDMS community, please let us know and we'll look to get that scheduled. Okay, so LandLab. LandLab is a Python language programming library and it was developed to make it easier to create or modify or combine two-dimensional numerical models, grid-based numerical models. And of course, it's geared toward earth surface dynamics of various sorts, various kinds of earth surface processes, not necessarily because there's anything unique about those domains as far as 2D modeling, but simply because that's where the development team is coming from and because it was developed specifically as a product by and for the CSDMS community and it's been developed by a team within the CSDMS Terrestrial Working Group. In many ways, LandLab is the complement to the CSDMS Python modeling tool or PiMT. You're going to hear more about that in a future webinar, but where the Python modeling tool is about running and possibly coupling pre-existing models, entire models, LandLab acts at a more granular level and as you'll see the components in LandLab instead of representing a full model of something, they tend to represent one individual process at a time and you'll see some examples of that. First, a couple of words about the motivation behind creating LandLab in the first place. Two-dimensional numerical models are widely used across the spectrum of earth and environmental sciences and indeed planetary sciences to address all kinds of basic science questions and practical engineering problems. In this next slide, I'm showing a few examples of that. These are images from the literature of six different 2D models of different kinds of systems. So, from the upper left, we have a model of watershed hydrology developed by Valeri Ivanov and colleagues showing here the simulated depth to water table. In the upper middle is a model of soil erosion, so this is on the scale of an agricultural field and then on the upper right a much larger area. This is a simulation of the extent of glaciers in the Sierra Nevada mountain range in California as it might have looked during the last glacial maximum. And then in the lower left is a model of landform evolution and depositional stratigraphy. So you can see some rivers eroding into a mountain plateau and creating a couple of deltas. Then we have a model of impact cratering as it might have played out on early Mars when those craters are being eroded by some kind of an active hydrologic cycle. And finally on the lower right, from the volcanology community, a simulation of lava flows on an active volcano. So you can appreciate that these, just these six examples are, they represent different sub-communities within the earth and environmental sciences, communities that often have different meetings and different journals and so on. They obviously represent different space and time scales, different kind of science targets. And yet from a cyber infrastructure perspective, you know, from the perspective of actually writing the code to do this, all of these authors are solving some very similar problems. For example, they're all, they all have to create some kind of a 2D grid, whether it's an unstructured grid or a regular raster grid, and there are examples of both in this collection. They all also have to deal with routing of some kind of a geophysical flow across a terrain surface, whether that's water or soil or sediment or lava or ice or combinations. And of course, each of these authors had to spend some time, presumably grappling with, okay, how do I get my parameters into my model and how do I read input data and how do I write data out and how do I manage numerical operations. So it's interesting to observe that there are some common elements among otherwise seemingly very different applications. And so one of the goals behind LandLab was to save the research community from having to reinvent all these particular wheels of software by providing some common tools that you can use to take care of these common tasks. So some of the goals in developing LandLab were, whereas follows, one was to make the gridding problem much easier to deal with. And I'll say more about that in a minute, but the idea was it would be nice if you could set up a 2D grid in just one or a few lines of code. And it would be good to be able to attach layers of data to grid elements. Every particular application has different kinds of data layers associated with it. And in keeping with the CSTMS design philosophy, it would be nice to do all this in a plug-and-play environment so that if you or I or anybody else creates a piece of code that's useful, that there's a way to encapsulate that in a standardized form that it could then be reused in other applications in a plug-and-play mode. The same time the idea was and is to have a relatively lightweight interface. So it's not too difficult to learn use, that we have a set of tools and utilities that can deal with common things like input and output. And finally, that the framework be usable in other frameworks, such as the CSTMS model coupling framework. So I'm not going to address all of these today, but we'll look at a few of them starting out with the gridding issue. So I think anybody who has ever tried to write a grid-based model will have found that even if you're using the simplest of grid types, just a sort of a square of points, let's say, that there can be some second-order challenges in setting up the right data structures and making sure you're handling boundaries correctly and so on. So LandLab provides a grid management tool, I guess you could say. We sometimes call it the gridding engine. And the solution here is to treat grids as data objects. So these are Python objects. So to use them, you need to know a few basic aspects of object-oriented programming. Fortunately with Python, that's not too challenging. All grids in LandLab use flat arrays to represent their data. So even though it may be natural to use a 2D grid to represent a simple raster grid like the one on the lower left, all the information about grid objects is representing using simple 1D arrays. What that means is that you can use the same data structures to represent a variety of different grid types. And at the moment, LandLab supports four different grid types that are shown here. There are simple rectilinear grids, x-grids, unstructured grids in which the cells are Voronoi polygons, and a sort of a specialized class called radial grids that are perhaps useful for things if you're wanting to model the development of a seamount or a zinder cone or something radially symmetrical like that. In each of these cases, there is a mechanism that we'll look at in a moment to attach fields of data to the grid so that the grid object, once you've set it up for your application, will have not only all the information about the grid, but it will have all your layers of data as well. In addition, there are some built-in functions that handle common numerical operators. So these would be things like I would like to take the gradient in some field. So for example, maybe one of my fields of data is the elevation of the land surface or the sea floor, and I would like to know what the slope is at different points. So there's function that will take care of that. So in the spirit of a picture is worth a thousand words, I thought I'd show you a couple of semi-code examples of grid creation. So here's a line of code using the LandLab library that creates a raster model grid object. This is a simple raster grid. In this case, it has 10 rows and 16 columns. And as you created, it's returned to a variable that we'll call grid. Now the grid that this generates looks graphically like this. Here in this illustration, the black dots represent grid nodes. The red line segments are what are called links. So if you're familiar with graph theory, these are just links in a graph. And a link is a line segment that connects a pair of adjacent grid nodes. And we'll see in a few moments why that can be useful for numerical solutions. And then the blue squares are cells. So you might want to use these cells to do conservation of mass problems and track the flow in and out of different cells. Those are three of the primitive objects that compose any LandLab grid. There are others such as the corners of the cells. But these are the three that we'll focus on here. A couple of other examples. Let's suppose I want a hex grid. I can do that with a one line code. That little piece of code there creates a hex grid that looks like this. So now our grid cells are hexagons and our links are arranged in a triangular pattern. You have some control over the shape and size of your grid. So for example, with a hex grid, we might actually want the arrangement or the shape of the overall grid to be a rectangle. And we can do that too by passing some optional arguments to the hex model grid function. And so we might want a grid that looks like that, for instance. A final example is showing a radial model grid. Here I want to have, let's see, three shells and three concentric layers and initially five nodes in the first full ring. How I get a grid like that. Here you can see that the cells are now not all the same. They have their shape is a little bit variable from one to the other. So that's sort of a quick overview of LandLab grids. And again, we'll put this into action in a few minutes. The next capability I want to talk about a little bit is this plug and play capability having to do with creating components. So a component in LandLab is just an encapsulated piece of code that does one thing. And often that one thing is to provide a numerical solution to represent one particular process. And so a way to illustrate this, I'm going to get into the weeds a little bit here. Again, on the theory that sometimes it's nice to actually see how things are done rather than just hear about them in the abstract. So imagine we want to create a component that simulates heat diffusion in two dimensions. So I might call that component a heat diffuser. And any component in LandLab is implemented as a Python class. So I would define a class called heat diffuser. And that class would include in its header some basic standardized metadata. And here's what those metadata look like. So it's things like, okay, we can give the component a name. We can list the names of the input variables. And so here an input variable is simply a field of data that must already have been created at the time the component itself is instantiated or turned on. So in this case, what we want is temperature. And then there are output variable names. These are fields of data that the component creates and modifies as part of its activity. So it's going to modify temperature. So that counts as an output as well as an input. And we'll also need to define a gradient in temperature and a heat flux. The rest of the metadata does things like define the units of these quantities and describe how they are mapped onto the grid. So for instance, if you look at the entry under var mapping, it says that temperature is associated with grid nodes, but the temperature gradient and the heat flux are associated with links on the philosophy that we're interested in flow between pairs of nodes. And then there's a little bit of descriptive information. So there's two other pieces that every land lab component has. One is an initialized method. So this is a standardized Python class function called init. And in a land lab component, that must take as the first argument after self a grid object. So in order to use this particular component, you have to have already created a grid. Then after that, there's a list of component specific parameters. So in this case, we'd like to send it the value of the thermal diffusivity as a parameter. Then there's only one other, and so I've left this particular initialized function blank just for the sake of illustration here. There's one other function that every land lab component has, and that's called run one step. Run one step says do your thing component. And if you're a time advancing component like this one, it says do your thing for one time step. And I'll tell you how big that time step should be. I'll pass in this argument dt. If you're a component that doesn't really function in time, it just has an operation than it does, then you don't need a time step. It just says do your thing. So that's really all there is to a land lab component. Now obviously there are some guts that would go into it where the word pass is there just a placeholder, but that's the essence of the design. So it's a fairly simple way of encapsulating functionality. What this allows you to do is to create a complete model by having a piece of Python code that creates a grid and creates some components. So the idea is illustrated graphically here. This rectangle is meant to be a kind of a graphical illustration of what amounts to a short, usually a short Python script. And in that script, you create a grid object of desired type and size and so on. You create one or more components and you create or the components create the fields of data that you need for your application. So for the diffusion example, we need to create a temperature field and then the component would create the fields for heat flow and temperature gradient. So that's the idea to make the process of creating a model simpler. Land lab itself has a set of components that the development team and friends have created over the past couple years. Here's an illustration of what some of those are. There's a bunch of different kinds of things that are represented and this isn't necessarily a complete list. But it includes, for instance, a pair of components that handle routing of flow over a terrain surface. There are some geomorphology components, some of us are geomorphologists, so to do things like soil creep, which we'll revisit in a second. There are some tectonic oriented components, like one that does lithosphere flexure. There's a component to do shallow water hydrodynamics, which I'll show you an application of in a moment. There is a vegetation dynamics component that is being developed by the team at the University of Washington and so on. One of the more unique elements in land lab is a cellular automaton capability, and I'll mention this just in passing. These are a couple of examples of models built from land labs, so-called cell lab CTS package, one on the left showing simulated emptying of a kind of hourglass-like silo, and the one on the right showing the long-term evolution of a hogback land form, inspired by Rachel Glade's work. Both of these were built with the Cell Lab CTS package. It's a stochastic cellular automaton modeling package that allows you to specify the cell states and the rules that they follow. So there's a couple of references there listed on the slide if anyone's interested in that. The final set of capabilities I'll mention are a variety of utilities that are designed to make the model creation process easier. So there are some tools for input and output. There is a method to read formatted input from a text file, so this might be the kind of thing you would do in order to read parameters into your model, for instance. There are some tools to read and write gridded data in various formats. At the moment, land lab supports ESRI ASCII format for raster data, and so there's an example of this function readESRI ASCII that will, if you like, read in a DEM, that's one kind of gridded data, and create a grid and a pointer to the array that contains the elevation data. Land lab will also read and write net CDF data, which is what the development team has tended to use a lot for our output applications. Then there are some collection of tools for analysis of digital terrain data and preprocessing, so you can set up watershed, some tools to set up watershed-like boundary conditions, and a few others. And then finally, there are some plotting capabilities, which we'll see shortly. Our philosophy has been that if you want sophisticated graphical visualization capabilities, that there are plenty of tools out there that will do that, and we don't need to reinvent that particular wheel, but it is nice to have some basic plotting abilities, so you can do a reconnaissance inspection of your land lab build models. So we do that using the Matplot Lib Library. So that's sort of a quick overview of some of land lab's capabilities. I want to show you now a couple of quick examples, and then we'll turn to look at versions of these more closely in some notebooks. So this particular example is showing an implementation of a 2D diffusion model that's used as a metaphor for soil creep. Here we have part of the landscape being tectonically uplifted and the soil is creeping around using a diffusion model. And the point I'm trying to make here is that it's possible to construct a model like this in relatively few lines of code. And in fact, the main loop that does this is just six lines long. We'll take a closer look at that through a notebook demo in a moment. Another example, and this doesn't use any components. If we want to use components, we can build multi-process models also with relatively few lines of code. So although I will say land lab was not built exclusively for geomorphology, since I'm a geomorphologist, those are the examples I tend to turn to. So here's another geomorphic example. This is a really a basic land form evolution model written in land lab. And the guts of it are shown to the left. That's not every single line, but it's most of it, and it amounts to about a dozen lines of code. So the idea here is to be able to shorten the time to science, to the time between when you first sit down on the computer and when you have a working model that you can compare with data and begin to analyze and interrogate. So I'll turn now to some examples of these are examples of applications, sort of real world applications people have done with land lab. This is another admittedly geomorphic example. What you're looking at here is two different models written using land lab that both represent long-term erosion. Here they're being used to generate potential forecasts with quantified uncertainties of the potential long-term future erosion at a site that happens to contain some high-level toxic waste. Concern is that that waste may be exhumed into the environment by erosion processes, and so the task here is to get a sense of how long that will take before stuff is released. Using land lab allowed Katie Barnhart and me, Katie Barnhart, being the leader on this project to develop not simply one model, but two or three dozen different types of model structure to be able to capture some of the uncertainty that's related to model structure itself. In other words, capture the uncertainty in our understanding of how these processes work. This particular collection of models has been packaged into an open source package called Terrain Vento, and Katie has a paper in review that describes that, so that'll be out and available soon. Actually, the website is there, but the description paper will be out soon. Okay, enough of geomorphic examples, let's look at a hydrologic example. These pictures here show some of the work by Jordan Adams and Nicole Gasperini and friends on constructing a basic rainfall and runoff model using land lab. One of their goals was to understand runoff and ultimately runoff and erosion on a burned landscape, and so in the upper left you see a digital elevation model of a small catchment in the Colorado Rockies. The three stars represent three points where Jordan wanted to track discharge hydrographs. The hydrographs from a simulated storm event are shown on the right, the upper right. So this was a land lab built model that combined two things. First, there's a shallow water hydrodynamics component that Jordan developed that uses it, if you're familiar with the list flood algorithm, and then there was a water infiltration component that handles infiltration of the precipitation and run on into the subsurface. So lower two figures here show a snapshot of water depth and a snapshot of the shear stress generated by that storm. So a hydrological application. Another application, if these are sort of time advancing process models, here's a different sort of model. These are maps of landslide probability generated using a Monte Carlo method. So the patch of terrain you're seeing in three different versions here represents the North Cascades National Park, and the colors represent the probability of landsliding occurring at different grid locations. So this was developed by Rhonda Strouch and Erkan Istanbulolu and their colleagues at the University of Washington using a land lab built model. And rather than marching forward in time here, what they've done is to import various different data layers for vegetation, soil type, and for recharge, water recharge into the subsurface from an independently run hydrologic model, and then do a large Monte Carlo ensemble in which they allowed parameters like soil cohesion to vary. In order to come up with not a simple binary, yes, this point will fail, no it won't, but a continuum probabilistic description of how likely is this particular location to experience a landslide within a particular time window. So Rhonda has just published that in Earth Surface Dynamics earlier this year. But anyway, these are a few different sort of live examples of people using land lab to address one problem or another. Okay, so what I'll do now is turn to do a couple of notebook demos. We'll see if the law of demos applies here, see how successful this is. The first demo I'm going to show you is from the, so let me back up a second say, so these notebooks and many others can be found on the land lab website, and I'll give you all some pointers to resources on the land lab website in a few minutes. But here we're going to start off with a simple tutorial that goes back to an example I showed you in one of those movies a moment ago, and this is to look at the problem of the evolution of a fault scarf. So you've had one or more earthquakes that have created a scarf, and then it has erosion has degraded it. It's washed some of the soil down from the crest to the base, and a classic problem in tectonic geomorphology is, okay, could we use the degree of degradation to estimate how long ago was the last earthquake. So to do that, we're going to use a 2D diffusion theory. Here's a quick look at the equations. The top box equation says that the rate of erosion or sedimentation, that is the rate of change of the land surface height, which is eta, is equal to the divergence of sediment flux, which is q. So here if you get more sediment soil accumulating at a point than leaving, it rises, and if you get more soil leaving than accumulating, it erodes and goes down. Our transport law, the lower box equation, simply says that the soil flux is equal to the local slope angle times a factor, and the minus sign says it goes downhill. So we're going to approximate those equations numerically by dividing our terrain into a bunch of boxes, like the gray one shown here. And for each box, we want to keep track of all the soil that's flowing in or out along the edges. So we want to figure out the soil flow in from the west and out to the east, in from the south, out to the north. And of course, if the soil is flowing out to the south, that would just be represented being with a minus sign. So the flow can be in any direction, and we'll use plus and minus signs to indicate that. So to do that, we'd like to be able to first calculate the slope of the land at the edges of the grid boxes. We can do that by taking, for example, the center point of the cell and the center point of the cell to its west and finding the slope between those two points. And from that slope, we'll calculate the soil flux at that location. Now, in terms of a land lab grid, what that means is we would like to put the slope and the soil flux not on the grid nodes, but on the links that connect pairs of grid nodes. So the links will represent soil flux, the grid nodes will represent elevation. And once we've calculated that, we'll just use a simple forward in time stepping scheme. So that's the problem we're going to try and solve. I'm going to switch over now to a notebook that, if luck holds, will work. So is everybody seeing a Jupiter notebook? Is anybody seeing a Jupiter notebook? I just need one. Yes. Yes. Okay, great. Okay, so I'm not going to go through all the details on this, but we'll run through a few code cells in which we're going to build a little model to do this simulation, to simulate a fault scarf that degrades over time. So I'll import some useful things. I'll import NumPy. From land lab, I'll import a type of grid called a raster model grid. And then the first thing we'll do is we will create a raster model grid object. We'll have 25 rows and 40 columns with a grid spacing of 10 meters. So boom, there's our grid. Next thing we need to do is create a field of data to represent the grid elevations. So the grid object has a function attached to it called add zeros. And what this function does is it says, okay, I want you to create a new array of length equal to the number of grid cells, grid nodes rather. So that's this keyword node. In our case, there's 25 by 40. So that's 1000 nodes. So this will create an array 1000 elements long. And we'll give it a name that's called topographic elevation. See why the name matters a little later. Okay, we'll import some stuff that'll help us plot. And we'll just make a little plot. First of all, of the X and Y locations of all the grid nodes. So this is a mat plot lib command. And here we see, we just have a simple rectangular array of grid nodes. Simple enough. We better make sure that the length of our array is indeed 1000. Yes, it's 1000. Okay, so the next thing I'm going to do is I'm going to create an earthquake. And I'm going to do this by putting in some commands that will put a fault running diagonally through the landscape and raise all those nodes on one side of the fault by 50 meters or more. I won't belabor the details of how this is done. You can inspect this notebook for yourself and see what the geometry is. So I'll just flip through these and we'll look at the result. Okay, so now I'm going to use a land lab function called mshow grid to take the grid and visualize its topographic elevation field. That's where the name comes in. Okay, so this is now a plan view of my elevation field. And you can see a jagged fault running across it. The jagged is simply because I'm using a fairly coarse grid resolution. But you can see that the lower portion here is all zero. And the upper portion here is anywhere from, let's say, maybe around 10 meters, increasing to the right up to, say, 13 meters high. So that's our initial condition. Next thing we need to do is to set some parameters. There's really two control parameters we need here. We first need our transport coefficient, which we'll set to kind of a typical field estimate of .01 square meters per year. And then we need to set our time step size. To set the time step size, I'm going to use what those of you familiar with, numerical solutions of diffusion will recognize as the current condition. Simply says your time step shouldn't be any bigger than the square of the space step divided by d. So now we have d and our time step, which turns out to be 2,000 years. Fair enough. So what last thing I really want to do here before we run a loop and actually run the model is to control the boundaries. So if I look back here, I might want to say, well, look, soil is free to exit off of this edge. And it's free to exit off of this edge, but I prefer it not to exit off of the sides. I'd like to have walls there. And I can do that with a land lab function that sets closed boundaries at certain grid edges. So this particular function will say make the east or right boundary closed. We can leave the top one alone, but let's do the left or west boundary closed and we'll leave the bottom one alone. That sets our boundaries. Another thing I'll mention is that in land lab, there's a distinction between core nodes and boundary nodes. And this is really provided to give you as a model developer a tool to identify those nodes that are on the grid interior. And by default, it's those that are not on the perimeter. You can change that if you want an irregular boundary like a watershed. But by default, it's the ones that aren't on the perimeter. And in this case, there should be 874 of them. We'll just double check that. Yes, there they are. Okay. So I said that was the last thing I forgot. There's one more thing we need to do. We need a field to represent the soil flux. And I pointed out earlier, we're going to put that field, those values are going to live on links, rather than on grid nodes. We do that with our add zeros function, we give it the link argument, and we'll give it a name called sentiment flux. And we'll call the variable Qs. Okay, so now we're at our loop. Before I run this loop, I'll just walk through quickly what it what it does. We're going to iterate over 25 time steps. So 2000 years per time step, that's 50,000 years. We'll start by calculating the slope of the land surface. And to do that, we'll use a grid function called calc grad at link. What this function does is it takes an array or a field of values that are defined at grid nodes, in this case, z, which is our elevation values. And it then goes and looks at each adjacent pair and takes the slope between them. And it returns that placing the slope value at the link itself. So it'll give us an array in of length equal to the number of links. And we'll call that array g for gradient. In the next line, we're going to turn that gradient into a soil flux. So we take g, and we're going to do this for all the links that are so called active. This is a cute way of handling boundary conditions. In this case, those the only links that are not active are the ones that are not touching core nodes, and that are not touching closed boundaries. You can see more details about that about grid geometry in the land lab grid tutorial. For now, this is going to address most of the links, but it's what will allow us to keep those right and left sides closed. We take that multiply it by our transport coefficient and give a minus sign to say soil flows downhill. And we'll store that in our QS array. Next thing we need to know is the net inflow and outflow of soil at each grid point. There's also a function built in to do that called calc flux div at node. It's kind of a mouthful, but it's short for flux divergence. And here we're going to give it our link based flow soil flux, and it will return to us the net rate of accumulation or loss of soil at each grid cell. And we'll call that variable DQSDX. Finally, here's our conservation law. Turns out the rate of erosion or sedimentation is just minus that. And as a final step, we update our elevations for the new time step. Okay, so that's sort of a quick tour through six lines of code. I'll run it. And it's done. And let's look at the result. So we started with a jagged sharp cliff edge. And now we have a smooth diffused one in which soil has has crept been transported from up here to down here. Right, so that's a very, a very quick tour of how you can build a functional 2D model in just a handful of lines of code. And it introduces you to a few of the handy functions and capabilities. The second and final demo I'd like to show is going to show how we can create a completely functional landform evolution model using LandLab components. And this too is a tutorial that's available on the tutorial's website. So let's see. Here I'm going to go to a second notebook. I probably won't go through all of this notebook, but we'll do enough to give you hopefully a little bit of the flavor of it. We'll start with a bunch of imports. And in fact, what we're going to do first is just to do something very much like what we just did, only this time using a LandLab component. It turns out there is a LandLab component called linear diffuser that does diffusion in two dimensions because we're geomorphologists, we think of it as diffusion of soil, but you could use it for diffusion of heat or anything else. We'll import some other handy LandLab bits and pieces as well as some plotting functions. As before, we'll create a grid using raster model grid. This one will be 80 by 80 rows and columns, five meter grid spacing, and we'll add a field at the nodes called topographic elevation, and we'll store it in a variable Z. Now, one of the things we can do is we can interrogate the metadata associated with a particular type of component. So let's say we didn't know exactly what this linear diffuser needs in terms of input fields. Well, we can ask it. We take the class name linear diffuser followed by a dot and input var names, and it tells us I need one variable called topographic elevation. Well, maybe that's not all that helpful. It'd be nice to have a little more information about that so I can use this function var help. And it tells me, okay, topographic elevation is the land surface topographic elevation and it's in units of meters and it's located at grid nodes. Great. Now we'll do the same kind of thing we did before to handle boundary conditions. We'll have two walls and two open boundaries, and that's what this box of code does. I'll leave it to anybody who's interested to inspect how it does that. All right, so that's a little bit of setup of the grid. Now we're going to create our component. The way we create a component is to give the name of the component class linear diffuser. We pass it our grid and we give it whatever parameters it needs. In this case, it needs a variable called linear diffusivity and we'll give it a value 0.2. Once I've done this, the variable lin underscore diffuse contains an object that is the component. That is our diffusion component. So now we're ready to rock. In this little block of code, I'll specify how long I want to run 200,000 years, what my time step will be a thousand years, what my rate of uplift will be because I'm going to give it some uplift, and how many time steps I have. Here's our loop. At each step in the loop, I call the components run one step method. That's the method that we looked at earlier and pass it dt. Then I'm going to take care of the tectonic uplift part myself here by saying at every time step, take the elevation of all the core nodes and add to it the uplift rate times the time step. Then I'll print out every once in a while just so I can be reassured that something is happening. Okay, so our model may be completed now. Let's see if we can look at what the topography looks like. There it is. So we're looking down on top of what is a parabolic hill slope that's highest in the middle and lowest at the top and bottom edges here, with a total maximum elevation of something in the order of 90 meters. Here's another view we can do. This little box of code gives us an example of how we can take a cross-sectional slice. If we view it from the side, we see that we have a nice parabolic profile as the theory predicts it should be with the steepest bit at the bottom and a gentle ridge top here. Okay, this next little chunk demonstrates that we have some flexibility when it comes to many components. In this case, what we could do is we might assert that our soil is easier to transport on one side of the domain than it is on another. We can represent this by having a spatially variable transport coefficient or diffusion coefficient. I won't step through all the code that does this. I'll simply point out that we're going to define an array called kdiff that represents the diffusivity value at each grid node. Instead of just one number for the whole landscape, each grid node has its own value. Then we'll make a map to see what that looks like. Here's our map. Green is high, blue is low. We have very easily transported soil over here, very resistant soil over here. Okay, that may not be all that geomorphically realistic, but you could imagine using this for something like a thermal problem where the thermal diffusivity varies because of some property, if it's a soil, because of some soil property, if it's some other kind of material because of metal content versus ceramic content or something like that. Once again, we'll create our diffusion component and now we'll run our experiment. This is taking a little bit longer now because we have some higher diffusion values and higher value may slow us down. I think we should be about done and there's our landscape. So you notice that we have this ridge that's sort of hump shape. So there's a big hill over here, a low saddle over there. The topography is high where the coefficient is low and vice versa, just as we might expect. So you have some flexibility in a well-designed component. One more chunk of this I'd like to show and that is a case in which we're going to combine multiple components. What we're going to do here is here's where we'll make our basic landform evolution model and we're going to do that by importing a component called the flow accumulator. This is something that routes flow across a terrain surface and one called fastscape eroder that implements what's known as the fastscape algorithm to solve the so-called stream power erosion law. This says take the slope and drainage area at a particular grid cell and calculate stream erosion at a rate that is proportional to how much area is drained at that particular location. We're also going to use a handy little utility called load params which allows us to put our parameters into a separate file and read them in. Okay so here in this next block I'm going to read in from an external text file all of our inputs. This text file is, I won't try and open it right now because I'm afraid I'm going to get tangled in all kinds of windows and directories, but you can look at this file. It comes along with this demo notebook. It's very simple. It sort of has parameter value, a parameter name, colon value. Pretty simple and then we're going to pull from that things like the number of rows and columns, the grid spacing, uplift rate, how long we want to run and what the time step is. All right and then we get a little print out of what all the parameters were in that input file. Once again I'm going to do the same things we saw before. I'll make a grid, I'll add elevations. This time I'll give the elevations a little bit of random roughness and I'll set my boundary conditions so that I have two closed boundaries. Now what I'm going to do is to read my three components. So I'm going to have a flow accumulator and I'm just going to pass it all the stuff I got from the input file. So this is a Python trick that you may or may not be familiar with. If you do two stars followed by the name of a Python dictionary it will send them all as arguments. So it's a sort of a handy shortcut that saves us having to list all the parameters as function arguments. I'm going right from my input file to my components. We'll do our flow accumulator, our erosion component and our old friend the linear diffuser. All right so the components now exist and here's our loop. Pretty simple this time. We call the flow accumulator. We don't need to give it a time step because it isn't time sensitive. We call our stream eroder and for now that's all we'll do. Well we'll give a little uplift in between but I'm not going to diffuse the topography. I'm just going to let the stream erosion component do all the work. Here we go and let's look at the result. So we have this highly dissected incised landscape. There's no soil creep to smooth out the rough edges but there's our simulated terrain. So let's redo that. We'll restart, regenerate our elevations as just a little bit of roughness. Do the same thing again but this time we'll add some diffusion to represent soil creep moving soil around the landscape and now we have a smoother landscape as a result. And I should acknowledge Dan Hobley who's the author of this particular demo and he comments that that's beautiful. I'll leave it to you to decide whether you think that's beautiful. But anyway there's a little bit more to this particular tutorial that I won't go through now but hopefully you've gotten a little bit of a flavor for how it's possible to build a land lab model by combining components and that you can do it with a relatively small amount of code. Last thing I wanted to do here before I open it up to questions is just point you towards some resources for those who are interested. There is a website and it provides sort of a launch pad for several different resources. There's a pointer toward installation instructions for land lab. There is a simple online user guide. There are tutorials including the two notebooks that I've showed you here plus many others. We have a reference manual. Those of you are familiar with the phrase API. This is the API reference. It essentially has the documentation for all the individual functions and classes and so on. So it starts with information about grids and if you page down you end up in a section that provides information about components of various sorts, information about stratigraphy and layering capabilities and a whole bunch of other stuff. One way you can use this is if you think you know the name of the function and you just want to figure out what it does, if you go to search under index, let's say I want to find out about a function called write esri asky. I find it, I click on it and then it gives me a little descriptive information, the name of the function, the arguments, the definitions of the arguments and often a few examples. So this particular part of the documentation is taken directly from the inline documentation in the code so it tends to stay up to date that way. We hope. I mentioned the Jupyter notebook tutorials, the user guide, the reference manual, the GitHub site has all the code so anybody is free to go and take a look at the source code. On the GitHub site there's several different pieces. There's the landlab code base itself, there's the tutorials repository which anybody can download and install and play with. If you run across an issue or you have a request for a new feature or you're having a question, a good way to do that is to go to the landlab GitHub page, go to issues and post a new issue. If you look at this list you'll see there's literally hundreds of issues which I don't know if it's a good sign or a bad sign but for example here's a user who has had issues with a particular capability and is posing a question so that's a good way to communicate with the development team. The last thing I'll mention is that we do have some ability to support or host site visits here if you're doing an application that uses landlab and you would like to come to the systems integration facility and spend some time we have some capability to do that so keep that in mind and if you're interested give us a shout. So that's about all I have I'll be happy to take any questions and apologies for going a bit long there but very happy to take questions. Greg you have a question in the chat window? Let me try and find the chat window. If you look at the bottom of your screen there's a chat button. I think I have to stop screen sharing maybe to do that. Okay great okay the question is is it possible to specify a certain forward in time discretization method within landlab such as leapfrog. That's a great question so you would we don't have that automatically dialed you would need to write the code to do that. Let's see a second question is can we simulate the real river profiles derived from DEM using landlab based on the field input data? So I'll try and see if I understand what's behind the question. One thing that one could do using some of the geomorphic components of landlab and possibly the terrain bento toolkit would be good for this would be if you have a real landscape and you want to test theories about how your river profiles got that way you could set up a model that represents your domain and give it whatever boundary conditions you think apply in your particular case. So for example if you're working on a on a coastal terrace that you know emerged from the sea at a certain time in the past and rose at a certain rate of rock uplift you could set up a model like that simulate the evolution of that and then compare the modeled river profile with the real thing. Can you hear me? Yes. Yeah this is Jesus Gomez thank you very much for the nice presentation. I have a quick question about the routing scheme. So if for instance I would if I had a different module of functions that need to be coupled with the routing scheme that is already implemented in landlab how hard would that be? Can you just use the the routing scheme without using any of your capabilities and only focus on a river network where I introduce my they just call it parametrications for exchange processes. Oh absolutely and that's part of the point. I mean you could take the routing component the flow accumulator and use that and write a script that uses that plus other things that you've created to work with that. But could you do it without in this case it's only the river network what matters to me not the landscape but just the network. Oh I see right so actually there's work that Katie Barnhardt is leading up now on creating a new grid class called network model grid and the idea there is that you have a type of grid that just represents branches in a network and doesn't have you know grid cells or points in between. Is that the sort of thing that you're looking for here? That's exactly what I was thinking about. Yeah so so what I would suggest if you're interested in learning more about that there's sort of an informal group that's come together to work on that and I would contact Katie if you're more interested interested in learning more about that you can find her contact info on the landlab web page please. Okay perfect thank you. Greg thank you it was a great webinar do you hear me? Yes it's Eitan. Hey Eitan how are you? I'm okay thank you. So two questions regarding boundary conditions. Do you have the option to introduce a periodic boundary conditions such that fluxes that get out from one side get back into the model from the other side? Yeah that's a good question and I'm embarrassed to say I don't remember. Dan Hobley had talked about this I think it was Dan who was trying to do this and I don't actually recall how far along he got in actually implementing that. It's a fairly straightforwardish thing to do with a raster grid if you have an unstructured grid it that's a whole different thing but I think that Dan made some headway in doing that for raster grids. Thank you and the other question on that regard can you introduce an open boundary within the model say to simulate the evolution of a landscape that is characteristic such that you lose water and sediments in the center of the model? Yeah you can actually you could put an open boundary node anywhere in the grid you want so if you wanted to have a big drain right in the center so the default is when you first grade a grid the cells or the nodes on the perimeter are open and the nodes in the interior are core but you can change that by just modifying a field called status at node. Great thank you. Okay great thanks for the questions we've reached the top of the hour and I'm mindful of everyone's time so I think we'll stop there but thank you all for joining us and stay tuned for announcements about the next CSDMS webinars.