Skip to main content

Sysdyn

System Dynamics modelling, simulation and diagramming in Python.

What is System Dynamics?

System Dynamics is a way of understanding how something changes over time by describing it in terms of what accumulates and the rates at which those accumulations fill and drain.

A population is the standard example. It grows because births add to it and shrinks because deaths remove from it. The population itself is a stock, a quantity that accumulates. Births and deaths are flows, the rates at which the stock changes. What makes such a system interesting is that the flows depend on the stock: the more people there are, the more births there are, so the population feeds back into its own growth.

That feedback is why these systems are worth simulating rather than reasoning about in your head. A handful of stocks and flows connected in a loop can behave in ways nobody predicts from looking at the parts, and the behaviour often turns out to come from the structure of the connections rather than from any single number in the model.

What is Sysdyn?

Two things that work together.

A Python package for building and simulating System Dynamics models. A flow is written as an ordinary Python function, and its argument names say what it depends on:

def births(population, birth_rate):
    """People born per unit of time."""
    return population * birth_rate

Sysdyn reads those argument names to work out how the parts of a model connect, so nothing is written down twice. There is no separate equation language, and each function can be called and tested on its own like any other Python function.

A graphical application in which a model is built by drawing it, as a Stock and Flow diagram on a canvas, then checked, simulated and plotted without writing any Python.

Describing a model, checking it, and running it

from sysdyn import Flow, Model, Parameter, Stock, simulate

def births(population, birth_rate):
    """People born per year."""
    return population * birth_rate

model = Model("Population", time_units="year")
model.add(Stock("population", 1000.0, units="people"))
model.add(Parameter("birth_rate", 0.03, units="1/year"))
model.add(Flow("births", births, to_stock="population",
               units="people/year"))

print(model.problems())        # [] — nothing to object to

results = simulate(model, start_time=0.0, end_time=100.0, step_size=0.25)
print(results.values("population")[-1])

An equation may equally be written as text — Flow("births", "population * birth_rate", ...) — and only text can be read, which is what lets Sysdyn check that the units of an equation are what it says they are.

Results come back as NumPy arrays, so they go straight into Matplotlib and SciPy. The tutorial (docs/tutorial.rst in the source tree) works through a complete example and explains how to tell whether an answer can be trusted.

What is in it

  • stocks, flows, auxiliary variables and parameters, with mistakes reported before anything runs
  • three fixed-step methods and six adaptive solvers, including ones for stiff models, and any solver of your own
  • step, pulse and ramp, lookup tables, delays and smoothing, repeatable randomness, and locating the exact moment a threshold is crossed
  • conveyors, ovens and queues, for material that does not mix
  • dimensions, matched by name rather than by position
  • units, checked before a run: a flow against what it fills, and the arithmetic of an equation against what it claims to be
  • a model built out of models somebody else wrote
  • the whole visual language in the application, with undo, plots in their own windows, the numbers out as CSV and the model out as plain Python

The package does not need the graphical application

This matters enough to say on its own. The Python package is complete by itself: it needs no display and no graphical toolkit, so models can be written in plain Python files, kept under version control, and used alongside NumPy, SciPy and Matplotlib in the ordinary way.

The relationship runs one way only. The graphical application is built on top of the package's public interface, exactly as a user writing Python would use it, and holds no modelling or simulation logic of its own. So anything the application can do can also be done from Python, and choosing to draw a model never limits what can be done with it afterwards.

Requirements

  • Python 3.11 or later
  • NumPy 1.24 or later
  • SciPy 1.10 or later
  • Matplotlib 3.6 or later

The graphical application additionally needs tkinter, the standard library's interface to the Tk toolkit. This cannot be installed from a package index because it is supplied by the operating system. On Debian and its derivatives:

sudo apt install python3-tk

The Python package itself does not need it, and works on a machine with no graphical display at all.

Running the tests

From the top of the source tree:

python3 -m pytest

No installation and no virtual environment are needed. The test configuration makes the package importable from src/ directly, so a freshly cloned copy of the repository is ready to test as it stands.

Building the documentation

From the top of the source tree:

./docs/build.sh

The finished documentation is written to docs/_build/html, and the page to open is docs/_build/html/index.html.

Sphinx 5.3 or later is all that is needed. Warnings are treated as errors, so a reference to something that does not exist fails the build rather than quietly producing a page with a broken link.

Equations are written as LaTeX in the documentation source and rendered in the reader's browser, so nothing needs to be installed to typeset them. By default the renderer is fetched from a content delivery network, which means viewing the equations needs network access. To use a local copy instead — which is what a distribution package wants — pass its path through:

./docs/build.sh -D mathjax_path=/usr/share/javascript/mathjax/MathJax.js

Anything given to build.sh is passed on to sphinx-build, so any other setting can be overridden the same way.

Licence

GNU General Public License, version 3 or later. The full text is in LICENSE.

Author

The Sysdyn Developers.

The maintainer's contact address is recorded in the package metadata, which is the one place it is kept. pip show sysdyn prints it for an installed copy, and pyproject.toml holds it in the source.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sysdyn-0.1.0.tar.gz (629.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sysdyn-0.1.0-py3-none-any.whl (457.6 kB view details)

Uploaded Python 3

File details

Details for the file sysdyn-0.1.0.tar.gz.

File metadata

  • Download URL: sysdyn-0.1.0.tar.gz
  • Upload date:
  • Size: 629.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for sysdyn-0.1.0.tar.gz
Algorithm Hash digest
SHA256 98055ef9c30ea875307dcfbc5279d5f01185b89cef948acf833a42a3fb242eda
MD5 05ba7db53ac281ec5f78febe5ca4d13d
BLAKE2b-256 5a524248db4cd1ab60343abb509853ac4973eb7b0d0fe2b38d87d68b742376da

See more details on using hashes here.

File details

Details for the file sysdyn-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sysdyn-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 457.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for sysdyn-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 31d6dc8c97480fb022bf5920ed843d55758c51672b42b5d44f520e5ac03f42ec
MD5 44615b7c02116c04b0806ec204c5fe63
BLAKE2b-256 a5511bba6ec4e057217c6a72a5caf414984b2b67dda091de77d58049a9e32210

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page