PySDTorch is an experimental Python package for translating Vensim system dynamics models into a backend-agnostic intermediate representation and running batched simulations with PyTorch.
The repository currently focuses on:
- Parsing Vensim
.mdltext models into a compact intermediate representation. - Expanding Vensim subscripts and lookup tables into runtime-ready variables.
- Running vectorized Torch simulations over many parameter draws.
- Sampling parameter ensembles from bounds.
- Parsing Vensim VOC files into parameter-bound dictionaries.
This project is in active development.
- The Torch runtime is the primary implemented backend.
- The NumPy runtime exists as a reference backend stub and currently raises
NotImplementedError. - Vensim support covers a useful subset of equations and functions, but not the full Vensim language.
- Pink-noise translation is not currently available. Models should explicitly
build the stock-and-flow structure needed to replicate process noise instead
of relying on Vensim's
RANDOM PINK NOISEfunction.
pysdtorch/
model.py High-level load/simulate wrapper
config.py Simulation configuration dataclass
sampling.py Parameter-bound normalization helpers
voc.py Vensim VOC bounds parsing and expansion
ir/ Backend-neutral model representation
runtime/ Runtime interface plus Torch/NumPy backends
translators/ Current Vensim text translator
legacy_translators/ Older parser structures and Vensim grammar files
benchmarks/ Translation and runtime benchmark entry points
Examples/
LV.mdl Example Vensim model
Synth_Data_Gen.voc Parameter bounds used by the example
example.py End-to-end load, sample, simulate, and time script
example_plot.py Generate and plot 50 simulated MN1/MN2 time series
PySDTorch uses modern Python typing syntax and should be run with Python 3.10 or newer. The Torch backend requires PyTorch.
This repository does not currently include packaging metadata such as a
pyproject.toml, so run commands from the repository root or add the repository
root to PYTHONPATH.
python -m venv .venv
source .venv/bin/activate
python -m pip install torchSome legacy translator modules import parsimonious; install it only if you are
working directly with pysdtorch/legacy_translators.
Translate a Vensim model to the internal representation:
python -m pysdtorch.benchmarks.translate path/to/model.mdl --no-python-compileRun the included example:
python Examples/example.pyGenerate a PDF plot from 50 random parameter draws:
python Examples/example_plot.pyLoad and simulate a supported Vensim model:
from pysdtorch import SimulationConfig, load_model
config = SimulationConfig(
backend="torch",
device="cpu",
dtype="float32",
rng_seed=42,
)
model = load_model("path/to/model.mdl", config=config)
samples = model.sample_parameters(
{
"parameter name": (0.0, 1.0),
},
n_draws=1024,
)
outputs = model.simulate(
samples,
tracked=["stock name"],
n_draws=1024,
)
series = outputs["stock_name"]
print(series.shape) # torch.Size([1024, number_of_saved_timesteps])Variable names are canonicalized internally by lowercasing and replacing
non-word characters with underscores. For example, Stock Name becomes
stock_name in returned output dictionaries.
SimulationConfig controls the backend and simulation settings:
from pysdtorch import SimulationConfig
config = SimulationConfig(
backend="torch",
device="cpu",
dtype="float32",
initial_time=0.0,
final_time=100.0,
time_step=1.0,
saveper=1.0,
rng_seed=None,
)When a Vensim model defines INITIAL TIME, FINAL TIME, TIME STEP, or
SAVEPER, those control values are merged into the runtime configuration during
load_model.
VOC files can be parsed into simulation bounds:
from pathlib import Path
from pysdtorch.voc import parse_voc_bounds
bounds, expansions = parse_voc_bounds(
Path("path/to/bounds.voc"),
mdl_path=Path("path/to/model.mdl"),
)When expand_subscripts=True, subscripted parameters such as Param[Region]
are expanded into concrete per-element parameter names using the .mdl
subscript definitions.
Translation benchmark:
python -m pysdtorch.benchmarks.translate path/to/model.mdlRuntime benchmark:
python -m pysdtorch.benchmarks.rbcThe runtime benchmark expects an RBC.mdl file at the path supplied to
run_benchmark or in the current working directory.
The current translator/runtime includes support for:
INTEGstocks with flow and initial expressions.- Control variables:
INITIAL TIME,FINAL TIME,TIME STEP, andSAVEPER. - Lookup tables.
- Subscript expansion and mapped subscript handling.
- Common numeric functions such as
MAX,MIN,ABS,SQRT,EXP,LN,SIN,ZIDZ, andXIDZ. - Conditional and time functions including
IF THEN ELSE,STEP,RAMP,PULSE,INITIAL, and selected delay/allocation helpers. - Random functions including normal, uniform, Poisson, gamma, and negative binomial streams.
Unsupported Vensim functions generally surface as translation or Python compile errors. Use the translation benchmark with Python compilation enabled to catch unsupported expression rewrites early.