Awesome
SDEverywhere
SDEverywhere is a collection of libraries and command line tools that help you improve the quality and expand the reach of a System Dynamics model. SDEverywhere allows for unit testing, continuous integration, the ability to compare model runs, and a toolchain to transform a model into C, JavaScript, and WebAssembly code.
Using SDEverywhere, you can deploy interactive System Dynamics models on mobile, desktop, and the web for policymakers and the public. Or you could perform model analysis using general-purpose languages, running the model as high-performance JavaScript or C code.
By following the "Quick Start" instructions below, within minutes you can turn a Vensim model like this:
<img width="500" alt="sde-vensim" src="https://github.com/climateinteractive/SDEverywhere/assets/438425/97e9b89e-54e4-438e-8cbd-51b9cd10a027"> <p> <br/> ...into an interactive (and fully customizable) simulator that runs in any web browser: </p> <img width="500" alt="sde-explorer" src="https://github.com/climateinteractive/SDEverywhere/assets/438425/95a51d0d-0201-47ae-b224-9820709de6c2">Supported Platforms
The SDEverywhere tools can be used on on any computer running macOS, Windows, or Linux. The libraries and code generated by SDEverywhere can be run in web browsers on almost any device (including phones and tablets) as well as on the server side (using C/C++, JavaScript, and/or WebAssembly).
Supported File Formats
SDEverywhere currently supports a broad range of System Dynamics models in Vensim format and handles many features of the Vensim modeling language, including subscripts, subranges, and subscript mapping. The full list of Vensim functions that are implemented in SDEverywhere can be found on the Supported Vensim Functions page in the SDEverywhere wiki.
Support for models in XMILE format (as used by e.g., Stella) is not yet available. However, our long-term vision is for SDEverywhere to have first-class support for both Vensim and XMILE formats. Please get in touch on the discussion board if you are interested in helping to add support for XMILE.
Features
Live Editing
SDEverywhere provides a live development environment and configuration files that allow you to see your edits in real time. Every time you save changes to your Vensim model or to the CSV config files, the local builder automatically rebuilds your project and the changes appear instantaneously in your browser, no manual reloads required.
The following video demonstrates using a text editor to make simple edits in the CSV config files that affect the appearance and behavior of the generated web application. In the video, we tweak the color of a graph plot, change an axis label, and set a new default for a slider. All of these settings and more can be configured by editing the CSV files in your favorite text editor or in Excel.
Quality Checks and Comparisons
SDEverywhere includes extensive QA (quality assurance) tools that you can run as you develop your model, either locally on your machine or in the cloud in a continuous integration environment (or both). There is support for two different kinds of tests:
- Checks: Check tests can be used to verify that your model behaves according to some guidelines (or conforms to your mental models). For example, you can have checks that verify that stocks are always positive, or that some output variable produces values that are close to historical reference data.
- Comparisons: Comparison tests can be used to track changes to your model between two different versions. For example, you can run your model over thousands of input scenarios and see at a glance how your model outputs differ from a previous version.
In the following video, we demonstrate how the model-check tools can be run alongside Vensim to give you immediate feedback whenever you make changes to your model. In this example, we have an existing "check" test that verifies that the different population variables always produce values in the range 0 to 10000. If we multiply a variable by -1 and save the model file, the builder detects the change and re-runs all the defined check and comparison tests.
Since the "Recovered Population" variable is now producing negative values, there is a failing check that gets flagged in the Model Check report, showing that the data now goes outside the expected (green) range. Additionally, the comparison tests show how the new model results differ from the previous ones over many different input scenarios.
Core Functionality
At its core, SDEverywhere includes a transpiler that can read a Vensim model and generate a high-performance version of that model as JavaScript or C code.
The sde
command line tool — in addition to generating JavaScript or C code — provides a plugin-based build system for extended functionality:
- plugin-config allows you to configure your model/library/app using CSV files
- plugin-wasm converts a generated C model into a fast WebAssembly module for use in a web browser or Node.js application
- plugin-worker generates a worker module that can be used to run your model in a separate thread for improved user experience
- plugin-vite provides integration with Vite for developing a library or application around your generated model
- plugin-check allows for running QA checks and comparison tests on your model every time you make a change
Additionally, the runtime and runtime-async packages make it easy to interact with your generated model in a JavaScript- or TypeScript-based application.
For more details on all of these packages, refer to the "Packages" section below.
Requirements
The SDEverywhere libraries and tools can be used on any computer running macOS, Windows, or Linux.
SDEverywhere requires Node.js version 18 or later (the current LTS version 20 is recommended). Node.js is a cross-platform runtime environment that allows for running JavaScript-based tools (like SDEverywhere) on macOS, Windows, and Linux computers.
Note: It is not necessary to have extensive knowledge of Node.js and JavaScript in order to use SDEverywhere, but a one-time download of Node.js is necessary to get started.
Once you download and install Node.js, you can run the commands listed on this page that start with npm
.
(The npm
command line tool is included when you install the Node.js runtime environment.)
If you are already familiar with Node.js and have it installed, note that SDEverywhere is also compatible with the pnpm and Yarn package managers, which can be used as an alternative to npm
.
Quick Start
The following video shows what it will look like when you follow the steps in this section.
In this video, we demonstrate commands that turn a Vensim model (the SIR model from examples/sir
) into a web application project.
As shown in the video above, the quickest way to get started with SDEverywhere is to open your terminal emulator ("Terminal" on macOS or Linux, or "Command Prompt" on Windows) and type the commands explained below.
If you already have a directory containing a Vensim mdl
file, change to that directory first.
(The script will generate some new files in that directory, so if you would prefer, feel free to create a fresh directory that includes just your mdl
file.)
# Change to the directory containing your `mdl` file:
cd my-project-folder
Or, if you don't already have a Vensim mdl
file, and/or you want to evaluate SDEverywhere for the first time, you can create an empty directory, and the script will provide a sample model to get you started:
# Create an empty directory and change to that directory:
mkdir my-project-folder
cd my-project-folder
Once you are in the correct folder, run the create
script:
# Use `npm` to run the "create" script:
npm create @sdeverywhere@latest
# Or, if you use pnpm:
pnpm create @sdeverywhere@latest
# Or, if you use Yarn:
yarn create @sdeverywhere
Answer a few questions, and within minutes you can have a functional web application that runs your model!
Documentation
Detailed API and usage documentation for each @sdeverywhere
package can be found in the "Packages" section below.
Additional user guides and documentation for contributors can be found in the SDEverywhere wiki. For example:
- For guidance on designing and building a full-featured web application around your model, refer to Creating a Web Application.
- To learn how to embed an SD model into a native C/C++ application or library, refer to Integrating a Model into a Native Application.
Caveats
SDEverywhere has been used to generate code for complex models with thousands of equations, but your model may use features of Vensim that SDEverywhere cannot translate yet. Please fork our code and contribute! Here are some prominent current limitations:
- Sketch information, the visual representation of the model, is not converted.
- Only the most common Vensim functions are implemented.
- All models run using the Euler integrator.
- Strings are not supported.
- You must rewrite tabbed arrays as separate, non-apply-to-all variables.
- You must rewrite equations that use macros or code them in C.
Tabbed arrays and macros are removed from the model during preprocessing and written to the removals.txt
file for your reference.
SDEverywhere in Production
- Climate Interactive has been using SDEverywhere in production since 2019 for their popular simulation tools:
- En-ROADS — an online global climate simulator that allows users to explore the impact of policies on hundreds of factors like energy prices, temperature, air quality, and sea level rise
- C-ROADS — an online policy simulator (also available as a macOS or Windows desktop application) that helps people understand the long-term climate impacts of national and regional greenhouse gas emission reductions at the global level
- Energy Innovation uses SDEverywhere to produce their Energy Policy Simulator.
Packages
SDEverywhere is developed in a monorepo structure.
Each package listed in the table below is developed as a separate npm package/library under the packages
directory in this repository.
All packages are published independently to the npm registry.
If you're new to SDEverywhere, refer to the "Quick Start" section above.
Running the npm create @sdeverywhere@latest
command described in that section will take care of setting up a recommended project structure and will install/configure the necessary @sdeverywhere
packages from the table below.
If you want more control over which packages are installed, or for API documentation and configuration instructions, refer to the links below.
Packages marked with an asterisk (*) are implementation details. Most users won't need to interact with these implementation packages directly, but they may be useful for advanced use cases (for example, if you want to create a new build plugin or a custom test runner).
<table> <tr> <th>Package</th> <th>Version</th> <th>Links</th> </tr> <tr> <td colspan="3"><em>Project creation</em></td> </tr> <tr> <td><a href="./packages/create">@sdeverywhere/create</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/create"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/create.svg?label=%20"></a></td> <td> <a href="./packages/create">Source</a> | <a href="./packages/create/README.md">Docs</a> | <a href="./packages/create/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td colspan="3"><em>Command line interface</em></td> </tr> <tr> <td><a href="./packages/cli">@sdeverywhere/cli</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/cli"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/cli.svg?label=%20"></a></td> <td> <a href="./packages/cli">Source</a> | <a href="./packages/cli/README.md">Docs</a> | <a href="./packages/cli/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td colspan="3"><em>Build plugins</em></td> </tr> <tr> <td><a href="./packages/plugin-config">@sdeverywhere/plugin-config</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/plugin-config"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/plugin-config.svg?label=%20"></a></td> <td> <a href="./packages/plugin-config">Source</a> | <a href="./packages/plugin-config/README.md">Docs</a> | <a href="./packages/plugin-config/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/plugin-wasm">@sdeverywhere/plugin-wasm</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/plugin-wasm"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/plugin-wasm.svg?label=%20"></a></td> <td> <a href="./packages/plugin-wasm">Source</a> | <a href="./packages/plugin-wasm/README.md">Docs</a> | <a href="./packages/plugin-wasm/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/plugin-worker">@sdeverywhere/plugin-worker</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/plugin-worker"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/plugin-worker.svg?label=%20"></a></td> <td> <a href="./packages/plugin-worker">Source</a> | <a href="./packages/plugin-worker/README.md">Docs</a> | <a href="./packages/plugin-worker/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/plugin-vite">@sdeverywhere/plugin-vite</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/plugin-vite"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/plugin-vite.svg?label=%20"></a></td> <td> <a href="./packages/plugin-vite">Source</a> | <a href="./packages/plugin-vite/README.md">Docs</a> | <a href="./packages/plugin-vite/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/plugin-check">@sdeverywhere/plugin-check</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/plugin-check"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/plugin-check.svg?label=%20"></a></td> <td> <a href="./packages/plugin-check">Source</a> | <a href="./packages/plugin-check/README.md">Docs</a> | <a href="./packages/plugin-check/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td colspan="3"><em>Runtime libraries</em></td> </tr> <tr> <td><a href="./packages/runtime">@sdeverywhere/runtime</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/runtime"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/runtime.svg?label=%20"></a></td> <td> <a href="./packages/runtime">Source</a> | <a href="./packages/runtime/README.md">Docs</a> | <a href="./packages/runtime/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/runtime-async">@sdeverywhere/runtime-async</a></td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/runtime-async"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/runtime-async.svg?label=%20"></a></td> <td> <a href="./packages/runtime-async">Source</a> | <a href="./packages/runtime-async/README.md">Docs</a> | <a href="./packages/runtime-async/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td colspan="3"><em>Build/CLI implementation</em></td> </tr> <tr> <td><a href="./packages/build">@sdeverywhere/build</a> *</td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/build"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/build.svg?label=%20"></a></td> <td> <a href="./packages/build">Source</a> | <a href="./packages/build/README.md">Docs</a> | <a href="./packages/build/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/compile">@sdeverywhere/compile</a> *</td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/compile"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/compile.svg?label=%20"></a></td> <td> <a href="./packages/compile">Source</a> | <a href="./packages/compile/README.md">Docs</a> | <a href="./packages/compile/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/parse">@sdeverywhere/parse</a> *</td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/parse"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/parse.svg?label=%20"></a></td> <td> <a href="./packages/parse">Source</a> | <a href="./packages/parse/README.md">Docs</a> | <a href="./packages/parse/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td colspan="3"><em>`model-check` implementation</em></td> </tr> <tr> <td><a href="./packages/check-core">@sdeverywhere/check-core</a> *</td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/check-core"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/check-core.svg?label=%20"></a></td> <td> <a href="./packages/check-core">Source</a> | <a href="./packages/check-core/README.md">Docs</a> | <a href="./packages/check-core/CHANGELOG.md">Changelog</a> </td> </tr> <tr> <td><a href="./packages/check-ui-shell">@sdeverywhere/check-ui-shell</a> *</td> <td><a href="https://www.npmjs.com/package/@sdeverywhere/check-ui-shell"><img style="vertical-align:middle;" src="https://img.shields.io/npm/v/@sdeverywhere/check-ui-shell.svg?label=%20"></a></td> <td> <a href="./packages/check-ui-shell">Source</a> | <a href="./packages/check-ui-shell/README.md">Docs</a> | <a href="./packages/check-ui-shell/CHANGELOG.md">Changelog</a> </td> </tr> </table>Contributing
SDEverywhere covers a subset of the Vensim modeling language used in models that have been deployed with it. There is still much to contribute, for example:
- Expand the Vensim parser to cover more of the language syntax, such as documentation strings. (See the related antlr4-vensim project for more details.)
- Enhance the C code generator to produce code for new language features now that you can parse them.
- Implement more Vensim functions. This is the easiest way to help out.
- Add support for the XMILE file format.
- Target languages other than JavaScript and C, such as R or Rust. (If you want Python, check out the excellent PySD).
For more guidance on contributing to SDEverywhere, please consult the wiki.
License
All packages developed in the SDEverywhere repository are distributed under the MIT license. See LICENSE for more details.