2.0.0b10
catchment modelling framework
|
This tutorial is still under development, sorry
To get a cmf program to do what you want, the order of creating the building blocks of cmf is of importance.
Python comes with some syntactic rules how a program works. But there are also not enforced rules, how a Python program should look like, the so called PEP 8 style. The cmf library does often not follow this style guide, but I wish knew it when I wrote cmf.
A simple cmf script is just a batch of commands. The only structures used are conditions (if) and loops (for / while). Such programs are very simple to understand and followed, if they are short and every reader will always be interested in every detail. This type of script is fine for the beginner, because the flow of the program is obvious: from top to bottom, like a normal text. When your program grows beyond 50 to 100 lines, take 10 minutes to restructure your program using functions or classes.
If you will ever run your model on a Linux / Unix system, it is a good idea to start the file with the so called shebang:
Followed by a docstring explaining the purpose of your program:
To use cmf, the cmf-library must be imported. However, if you like to write code that is compatible for Python 2 and 3 the first line of your program is the from __future__ import
line for Python 2 compatibility. If you need other libraries / packages in your program, import them also in the beginning. Avoid from xxx import *
commands in all scripts.
The import section of a CMF script, that uses numpy
-arrays and matplotlib
plotting and datetime
's objects might look like:
The setup part of a cmf program is, where the structure of the cmf model is defined. The structure consists of the storages, boundary conditions and connections and for more advanced models also of the cells with soil layers and vegetation.
In the Boundary conditions example the setup part is, where the project, the two storages, the two boundary conditions and the connections are defined:
CMF models are run from an initial condition using forcing (or driver) data during runtime. The place between defining the structure of your model and creating a solver is a good place to overwrite the default initial state (that are not very well documented but are usually some kind of "empty") and load and assign forcing data.
In our case, the initial condition is the stored volume of W1
and W2
and the forcing data is the flux over the Neumann boundary condition.
The solver should only be created after the structure is setup, since solvers in cmf do not own a reference to a project, or what else, but only extract references to the state variables of a project, a cell or some other owner of state variables. This means, if you create a solver and after that, you are going to extend your project with new storages, the solver knows nothing about these and the mass conversation of the model is broken. If you extend your project, eg. in an interactive environment, just make sure to create a new solver also.
The solver is used to advance the model in the runtime loop. The runtime loop is user defined, to allow the user to interact with the running model in any way. Usages of the runtime loop include:
To build the runtime loop, the generator method run
of the solver makes the iteration over the model time simple:
Of course, writing the sections from above just down in the typical "script" style of programs, gets totally confusing when your program grows and needs more then 50-100 lines. Therefore, it is good practise to seperate your code into functions with a well defined scope. For an experienced programmer, that comes naturally, if you are new to programming, please read about structured programming. A simple structure using functions could look roughly like this:
spotpy
by Tobias Houska is an ideal partner to calibrate cmf models. In fact, there is a cmf example in spotpy ( setup, tutorial, gui )
You can see there, how
__init__
), and parameter depending structure (set_parameters
)