 Welcome back at the open course programming for geospatial hydrological applications. In module 4 we are going to do spatial dynamic modeling. In the previous module we have used PCRuster for map algebra and spatial analysis. PCRuster, however, also comes with a dynamic modeling framework for Python, with which we can make our own dynamic models, such as rainfall runoff models. It is basically a template that is defined as a Python class. The Python class has an initial method, where we initialize the model. These lines are only executed once. And a dynamic method, where we write the code that needs to iterate in time. In the properties of the class we define a clone map, which gives the spatial properties and the time steps. For dynamic modeling we also need time series of maps, dynamic maps. And PCRuster uses a convention for that. It uses the 8.3 convention, which means that files have 8 characters before the dot and 3 characters after the dot. Then there needs to be a minimum of 1 alphabetic character, for example, starting with an A. You can also have more alphabetic characters at the start of the filename, but you cannot start with a number. Then you fill up with zeros until the time step. So if our first character is an A, that's the alphabetic character, we fill it up with zeros until we have 8 characters before the dot. And then after the dot we fill it up with zeros until the time step. So for time step 1 we have 001 as the file extension. If we would have the second time step it would be the same, but then 002. In this way, when we have one alphabetic character at the start of the filename, we can have this number of time steps. Another example, which applies to the convention. We can define the file precip, for example precipitation. And then we fill it up until 8, so 2 zeros are added, so we have 8 characters before the dot. And time step 5 is dot 005. If we use this name, precip, we can only have 99999 time steps. So the amount of alphabetic characters determines how many time steps you can store. PCRuster also has a format for time series. These are files that we can read or write, which contains time series data. Here we see the contents of such a file. The convention is that the first line is the title of the data. The second line contains the number of columns, in this case 4, and then followed by the headers of the column. So the first column is always time, so time step 1, 2, 3, 4, 5, and then data for three different stations. First column, station 1, second column, station 2, third column, station 3. And in this way PCRuster operators can read these files and connect them to a map with the three stations, for example. You will learn this in the tutorial. This is the dynamic modeling framework of PCRuster in Python. You first import PCRuster and the framework, and then there is the class, which is a template. It has the initialization of the class, and it has the initial method and the dynamic method, and below we define the properties of the class instance. In this template we don't change anything except the time steps. We need to define the last time step and the first time step. We also need to define the clone map, in this case the m.map will specify the spatial properties of all the layers used in the model. All the layers, all the rusters will be checked against this dm.map. It will be checked if they have the same number of rows and columns, cell size, and coordinate system. In the initial method we write the code that needs to be executed only once to initialize the model. And in the dynamic method we write the code that is iterated the amount of time steps that we have defined in the properties of the class instance. When we build a model like this one, we need to define variables, and we need to distinguish between local and global variables. In this case, conversion value is a local variable and can only be used in the method where it's defined, so we can only use conversion value in the initial method. If we look at self.reservoir, which is an initial value divided by the conversion value, we see that we have self. which makes it a global variable that is needed because we use it also in the dynamic section. So we can make variables global by adding self. to the variable name. If we don't do that, we will get an error that says that the variable has not been defined. Here we see some more examples of using PCruster functions and operators in a script. Basically the same stuff as we used in the map algebra tutorial, but now in a dynamic script. There is a difference with map algebra, however, if we want to read and write files to disk. If we want to write a file in the initial method, we use self.report, the name of the variable, and we define the part of the file name before the .map. Because in the initial, the framework knows that you use static maps and it will write uni.map to disk. In the dynamic section, it will write, in this case, na for each time step. It knows that if you use self.report in the dynamic with the variable name, that each time step, it has to write a file, na. And then by the convention of the time series in PCruster, we use 6 zeros and then 001 for the first time step and 002 for the second, etc. So file names with time series always have eight characters before the dot and three after the dot. And then we need at least one alphabetic character followed then by the zeros to add up to eight before the dot and then three after the dot where we count the time steps. This is exactly the same format as the map format, but it just has a different file name. So with gdoll, if you need to convert it or you want to open it in QGIS, it's exactly the same. The file name doesn't determine what is inside the file. That is still the PCruster map format. So to summarize, if we want to store maps, it's a bit different than in map algebra. In the dynamic modeling framework, if we use self.report in the initial method, it knows that it has to add dot map. So we can only write the part before the dot. In the dynamic method, it is the same. It knows what to write after the first characters. So we only write the alphabetic characters and it will add the zeros and the 001 for the first time step. And when it enters the next one, it will write 002, et cetera. Similar for reading from the disk, we use self.readmap. So self.dem is a global variable and we read dem because it's in the initial method. The framework knows to read dem.map from the disk. And in the dynamic method here, it knows that for each time step, it has to read the file precip with the corresponding characters for the time steps. So 00.001, you see again eight characters before the dot and three after the dot where the numeric characters indicate the time step. So in this module, there is a Jupyter notebook tutorial where you can practice with spatial dynamic modeling using the PCruster Python framework. In the tutorial, we work with an example rainfall runoff model, which is the stream model.