Creating User-defined Functions in SD Models

Creating user-defined functions in the SD DSL that is part of the BPTK-Py business simulation framework.
Keywords

system dynamics, systemdynamics, sd dsl, bptk, bptk-py, python, business simulation

Creating User-defined Functions in SD Models

One of the benefits of creating System Dynamics models in Python is that we can use the full power of Python to create our own functions, which we can then use in our models.

This how to illustrates how to do this.

First of all, lets set up our model:

Now let’s define a function we would like to use in our model. A user defined function can have as many arguments as you like, but it must accept at least a model and time parameter (you don’t need to use the parameters if you don’t want to).

How you define your function is up to you - you can use any of the methods available in Python, such as class methods, using def, or lambda functions.

The example below uses a lambda function which simply multiplies the current time t with 5.

As you can see, much like with stocks and converters, we associate our function with the model by calling the model’s function method.

Next we set up a converter whose equation calls the function, and test it at t = 5:

25.0

Let’s plot the function over time:

We can also create a stock that has the converter as an inflow:

You can do all the usual arithmetic in an equation. Here the same converter is divided by time before it flows in - a second stock rather than a second equation on the first one, because an element whose equation is set in two cells has no defined value outside the cell that just set it:

The function we created above was just dependent on time and not on other model variables. Let’s create a function that takes more arguments, e.g. one that multiplies a model variable with time.

You can add as many arguments as you like, but they must come after the model and t arguments.

The function needs two inputs, so we define a converter for each of them and then a third converter that applies another_model_function to both:

Of course functions defined in this way can also be used within scenarios. The quickest way to set up a scenario manager for a given model is register_model, which creates a scenario manager named after the model with the prefix “sm” - the name is normalized to start with a capital letter, so TestModel becomes smTestmodel - together with a “base” scenario that runs the model as-is.

Three more scenarios are added below, each with a different multiplier, and list_scenarios shows what the manager now holds:

*** smTestmodel ***
     base
     multiplier5
     multiplier10
     multiplier15

And plotting the four scenarios against each other shows what the multiplier does: