radCAD is a cadCAD-compatible Python framework for modelling and simulating dynamical systems. A dynamical system is one whose state evolves over time according to a fixed set of rules that depend on its current state and, optionally, external inputs.
You describe a system as a set of state transitions (encoding differential equations, agent behaviour, or other logic), then run parameter sweeps, Monte Carlo runs, and A/B tests over it in parallel across multiple processing backends. radCAD is compatible with cadCAD: its functions, data structures, and simulation results follow the same conventions, so existing cadCAD models run with minimal changes.
📚 Read the documentation | 🎓 cadCAD.education courses
- Simple API: describe a model, wrap it in a simulation, run it.
- Fast: optimised for large parameter sweeps and Monte Carlo runs.
- cadCAD compatible: standard functions, data structures, and simulation results, plus a compatibility mode for existing cadCAD models.
- Extensible: hooks, iterable models, and typed dataclass parameters.
- Robust exception handling: failed runs return partial results and tracebacks, so one error won't discard a long-running simulation.
- Distributed execution: parallel processing across multiple backends, including remote Ray clusters.
- Tested: against Python 3.10–3.12 on Linux, macOS, and Windows.
- Ethereum Economic Model by CADLabs.
- Beacon Runner by Ethereum RIG.
- GEB Controller Simulations by BlockScience.
- Fei Protocol Model by CADLabs.
- QTM Interface by Outlier Ventures.
- Polygon 2.0 Economic Model by Polygon.
pip install radcadOptional extras:
pip install "radcad[compat]" # cadCAD compatibility layer
pip install "radcad[extension-backend-ray]" # Ray backendimport pandas as pd
from radcad import Model, Simulation
initial_state = {"x": 1}
params = {"growth": [1, 2, 3]}
def policy(params, substep, state_history, previous_state):
return {"dx": params["growth"]}
def update_x(params, substep, state_history, previous_state, policy_input):
return "x", previous_state["x"] + policy_input["dx"]
state_update_blocks = [
{
"policies": {"growth_policy": policy},
"variables": {"x": update_x},
}
]
model = Model(initial_state=initial_state, state_update_blocks=state_update_blocks, params=params)
simulation = Simulation(model=model, timesteps=10, runs=1)
df = pd.DataFrame(simulation.run())
print(df[["simulation", "subset", "run", "timestep", "substep", "x"]].tail())The primary API is:
Model: initial state, state update blocks, and parameters.Simulation: one model plus timesteps and Monte Carlo runs.Experiment: one or more simulations, useful for A/B tests and batches.Engine: execution settings, backend selection, deepcopy behaviour, substep retention, and exception handling.
from radcad import Experiment
experiment = Experiment([simulation_a, simulation_b])
result = experiment.run()The documentation site is built with MkDocs Material and organised with the Diátaxis framework:
- Tutorials: learn radCAD from a complete first simulation.
- How-to guides: configure sweeps, hooks, backends, experiments, and exception handling.
- Reference: API docs generated from docstrings plus the simulation data model.
- Explanation: concepts, execution model, and performance trade-offs.
Docs are published to GitHub Pages at https://cadlabs.github.io/radCAD/.
Build locally:
uv run --extra docs mkdocs serve- Iterable models: use models as step-by-step generators and live digital twins.
- Game of Life: Conway's cellular automaton.
- Predator-prey system dynamics: Lotka-Volterra equations.
- Predator-prey agent-based model: agent-based ecological model.
- Harmonic oscillator: oscillatory system example.
Set up the development environment with uv:
uv syncRun tests and benchmarks with Nox:
nox --session tests
nox --session benchmarksSee the Contributing guide for environment setup, profiling, releasing, and other development tasks.
Thanks to @danlessa, @rogervs, @abzaremba, and @smngvlkz for contributions to examples, documentation, compatibility, and CI.
radCAD is released under the license in LICENSE.
