Skip to main content

Python bindings for the Simlin system dynamics simulation engine

Project description

pysimlin - Python bindings for Simlin

Python bindings for the Simlin system dynamics simulation engine.

Features

  • Load models from XMILE, Vensim MDL, and binary protobuf formats
  • Run system dynamics simulations with full control
  • Get simulation results as pandas DataFrames
  • Analyze model structure and feedback loops
  • Full type hints for IDE support
  • Loops That Matter (LTM) analysis for feedback loop importance

Installation

pip install pysimlin

Note: Install with pip install pysimlin but import with import simlin.

Requirements

  • Python 3.11 or higher
  • numpy >= 1.22.0
  • pandas >= 1.5.0
  • cffi >= 1.15.0

Quick Start

import simlin
from pathlib import Path

# Load a model from file (auto-detects format)
project = simlin.Project.from_file("model.stmx")

# Get the default model
model = project.get_model()

# Create and run a simulation
sim = model.new_sim()
sim.run_to_end()

# Get results as a pandas DataFrame
results = sim.get_results()
print(results.head())

# Access individual variables
population = sim.get_series("population")

API Reference

Loading Models

# Load from different formats
project = simlin.Project.from_xmile(xmile_bytes)  # XMILE/STMX format
project = simlin.Project.from_mdl(mdl_bytes)      # Vensim MDL format
project = simlin.Project.from_protobin(pb_bytes)  # Binary protobuf format

# Auto-detect format from file extension
project = simlin.Project.from_file("model.stmx")  # .stmx, .mdl, .pb, etc.

# Context manager for automatic cleanup
with simlin.Project.from_file("model.stmx") as project:
    model = project.get_model()
    # Project is automatically cleaned up when exiting the context

Working with Projects

# Get model information
model_names = project.get_model_names()

# Access models
model = project.get_model()           # Get default/main model
model = project.get_model("submodel") # Get specific model by name

# Check for compilation errors
errors = project.get_errors()
if errors:
    for error in errors:
        print(f"{error.code.name}: {error.message}")

Model Analysis

# Get model structure
var_names = model.get_var_names()
var_count = model.get_var_count()

# Analyze variable dependencies
incoming_deps = model.get_incoming_links("population")  # Variables that affect "population"

# Get causal links
links = model.get_links()
for link in links:
    print(f"{link.from_var} --{link.polarity}--> {link.to_var}")

Running Simulations

# Create simulation
sim = model.new_sim()                # Standard simulation
sim = model.new_sim(enable_ltm=True) # Enable Loops That Matter

# Run simulation
sim.run_to_end()        # Run to final time
sim.run_to(50.0)        # Run to specific time

# Reset to run again
sim.reset()
sim.run_to_end()

# Context manager for automatic cleanup
with model.new_sim() as sim:
    sim.run_to_end()
    results = sim.get_results()

Accessing Results

# Get results as pandas DataFrame
df = sim.get_results()                    # All variables
df = sim.get_results(variables=["x", "y"]) # Specific variables

# Get individual time series as numpy arrays
values = sim.get_series("population")

# Get current value (at current simulation time)
current_val = sim.get_value("population")

# Get metadata
step_count = sim.get_step_count()

Model Interventions

# Set initial values before running
sim.set_value("initial_population", 1000)
sim.run_to_end()

# Mid-simulation interventions
sim.run_to(10)
sim.set_value("growth_rate", 0.05)
sim.run_to_end()

Feedback Loop Analysis

# Get all feedback loops
loops = project.get_loops()
for loop in loops:
    print(f"Loop {loop.id} ({loop.polarity}): {' -> '.join(loop.variables)}")
    
# Check if variable is in a loop
for loop in loops:
    if loop.contains_variable("population"):
        print(f"Population is in loop {loop.id}")

Loops That Matter (LTM)

# Run simulation with LTM enabled
sim = model.new_sim(enable_ltm=True)
sim.run_to_end()

# Get links with importance scores over time
links = sim.get_links()
for link in links:
    if link.has_score():
        print(f"{link.from_var} -> {link.to_var}")
        print(f"  Average score: {link.average_score():.4f}")
        print(f"  Max score: {link.max_score():.4f}")

# Get relative loop scores
loops = project.get_loops()
if loops:
    loop_scores = sim.get_relative_loop_score(loops[0].id)

Model Export

# Export to different formats
xmile_bytes = project.to_xmile()    # Export as XMILE
pb_bytes = project.serialize()      # Export as protobuf

# Save to file
Path("exported.stmx").write_bytes(xmile_bytes)
Path("model.pb").write_bytes(pb_bytes)

Error Handling

from simlin import (
    SimlinError,
    SimlinImportError,
    SimlinRuntimeError,
    SimlinCompilationError,
    ErrorCode
)

try:
    project = simlin.Project.from_file("model.stmx")
except SimlinImportError as e:
    print(f"Import failed: {e}")
    if e.code == ErrorCode.XML_DESERIALIZATION:
        print("Invalid XML format")

# Check for compilation errors
errors = project.get_errors()
for error in errors:
    print(f"{error.code.name} in {error.model_name}/{error.variable_name}")
    print(f"  {error.message}")

Complete Example

import simlin
import pandas as pd
import matplotlib.pyplot as plt

# Load and run a population model
with simlin.Project.from_file("population_model.stmx") as project:
    model = project.get_model()
    
    # Run baseline simulation
    with model.new_sim() as sim:
        sim.run_to_end()
        baseline = sim.get_results()
    
    # Run intervention scenario
    with model.new_sim() as sim:
        sim.set_value("birth_rate", 0.03)
        sim.run_to_end()
        intervention = sim.get_results()
    
    # Compare results
    fig, ax = plt.subplots()
    ax.plot(baseline.index, baseline["population"], label="Baseline")
    ax.plot(intervention.index, intervention["population"], label="Intervention")
    ax.set_xlabel("Time")
    ax.set_ylabel("Population")
    ax.legend()
    plt.show()

Supported Platforms

  • macOS (ARM64)
  • Linux (ARM64, x86_64)

License

Apache License 2.0

Development

For development setup and contribution guidelines, see the main Simlin repository.

Running Tests

cd src/pysimlin
pip install -e ".[dev]"
pytest

Building from Source

cd src/pysimlin
python -m build

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

pysimlin-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.1 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

pysimlin-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (10.9 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

pysimlin-0.1.2-cp313-cp313-macosx_11_0_arm64.whl (2.5 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

pysimlin-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.1 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

pysimlin-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (10.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

pysimlin-0.1.2-cp312-cp312-macosx_11_0_arm64.whl (2.5 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

pysimlin-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.1 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

pysimlin-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (10.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

pysimlin-0.1.2-cp311-cp311-macosx_11_0_arm64.whl (2.5 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

File details

Details for the file pysimlin-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3ad46434855fee5f342d48921f475ac9d75408caa05760240e4e7487b113e008
MD5 be3641294180289007bb34d73b2f13bf
BLAKE2b-256 2408713b6ccdcf9cce6239a539f939b66f6f53c70cfdf1bde8e6e9e2afb5befe

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3ab2ff73ff619462fe5529475c132cc6360ce95bf389df7d483156d59cf250ce
MD5 93fd145a8e144afe3448a23954d48e92
BLAKE2b-256 1f24243baedc4a1ea290239e2d26de0b1e01eea36c6139fbb3c65020eee54f14

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 19f88b8562bd93c011c2567620865fd9b88491d4f00de3766a3b07109243ea7d
MD5 0253ce4f99d1f6ca741f1dac7dacc616
BLAKE2b-256 30ad001657082a6aac645a4404ce74d1f8520b4a6f4ccee6125362f114a72de3

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 43e3e577f1a6b79b4772d249f84e908ad0eeaea41411d106b86f35891921d3a7
MD5 0756174022e59a6351b321f17d10e0a0
BLAKE2b-256 a3cc4dc05b5349e2f47e759b8aa135a22063894317d7f8b4d53b3fb9084f506f

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1ed3a64c34912b715bd9451f287f53a139b47281d5980ddea0f1219141e1d707
MD5 aa8a83c37eda4593ad4bbe8e809c89f2
BLAKE2b-256 32e7d11ea854b94d562f3040647dde05d5d12b2cde4a7879bcecad06ac982c9f

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4f2783aaef2e1a473025d282ac250d5c5a3066a16a3d8c42704b92b3be9abda1
MD5 07b0a05ca3f48c2a6889b1d11ff628e5
BLAKE2b-256 23bdeb903ec4f0eceec84d8856715d4a80e4aa1b04845ac1a558adff810d939d

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 810ccd85c462fd3675d9e7fc24d1850df303b9ac9cf89d7b7769e202b5a14094
MD5 703d67ff9a6d70eae799603d406c19c0
BLAKE2b-256 1f48cbf1ecda472ca8638d06dc14b422544a6b68dd1d6455e40e4f0356796ae7

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 4e47894ebfb5002d3ec109a3a918ee4d511b330fa3dfa754bc3420803127d353
MD5 8f2d8505b7c85205458ca6d02c36da0a
BLAKE2b-256 d895d84f19f1c14370462ec6b4894b94cf1a9ae9241fb6b8d63eb5a9e67761dc

See more details on using hashes here.

File details

Details for the file pysimlin-0.1.2-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pysimlin-0.1.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a59bfc7b424db283f07b82c8b8d5ea1fd236b01cfe53ffd8b58d76075c0a96b1
MD5 fee7323f340486f14b5bd8696fc70f65
BLAKE2b-256 8cc9b55541c0974f12a978fbe966d5d728781dc768e7b5247c62248e76abe135

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