Save this model to your account. You can open it from any device.
The Plot tab displays simulation results as a retro printer-paper style time-series chart. Run a model first, then use the controls to explore the data visually.
| Control | Description |
|---|---|
| Run dropdown | Select which simulation run to display. Only runs that have a PLOT statement appear in this dropdown. |
| Lines checkbox | Show continuous line traces for each selected variable. |
| Letters checkbox | Show letter symbols on the chart at regular intervals. Each variable is assigned a letter from the PLOT statement (e.g., PLOT POP=P) or auto-assigned. |
Below the controls, colored chips appear for each plottable variable. Click a chip to toggle that variable on/off in the chart. Selected chips are highlighted with a blue border.
If units are defined (via U statements), they appear in the chip label and in chart tooltips.
In addition to the Plot tab, you can add Plot nodes directly on the diagram via the Plot button in the diagram toolbar (or Insert → Plot). These are mini time-series charts that live on the diagram canvas, each associated with a specific run. After running the model, they fill with simulation data. Click a plot node to edit which variables it displays; drag the corner handle to resize.
Use the PLOT statement in your model to assign letter symbols and optional scales:
PLOT POP=P(0,5000)/BIRTH=B(0,100)
Variables separated by / share the same scale group. The letter after = is the symbol shown on the chart.
The (lo,hi) values set the Y-axis range for a variable or group of variables. This is essential when plotting variables with very different magnitudes together — for example, a population level in the thousands and a birth rate below 100.
Without explicit scales, a small variable will appear as a flat line at the bottom of the chart because the Y-axis is dominated by the large variable. Setting separate (lo,hi) scales causes each group to be normalized independently so all traces are visible and use the full chart height. The actual scale range is shown in the legend.
You can also set these values from the lo and hi fields in the Plot configuration panel on the diagram.
Each run can have its own PLOT statement. If a run does not have a PLOT statement, it will not appear in the Plot tab’s run dropdown.
You can also configure plot variables visually by clicking a Plot node on the diagram and using the context panel.
The Data tab shows the raw numerical output from your simulation in a tabular format. Run a model to populate the table. Only runs that have a PRINT statement appear in the data table.
PRINT-listed variable at that time.PRTPER (print period) from the SPEC statement. If PRTPER=0, every time step is shown.There are two ways to configure which variables appear in the Data tab:
PRINT POP,BIRTH,DEATH directly in the editor.PRINT line for the currently active run.Each run can have its own PRINT statement. If a run has no PRINT statement, it will not appear in the data table at all.
Click the 💾 CSV button to download the data table as a comma-separated values file, ready for import into spreadsheets or other analysis tools. Only runs with PRINT statements are included in the export.
Control which variables appear in the data table:
PRINT POP,BIRTH,DEATH
Only variables listed in PRINT will appear as columns.
PRTPER to control how many rows are output. A larger value means fewer rows and a more compact table.PRINT line manually.The diagram is a stock-and-flow visual representation of your model. It syncs both ways with the editor — build your model visually, textually, or both.
Example: Simple population model with births and deaths
POP.K=POP.J+DT*(BIRTHS.JK-DEATHS.JK), set an initial value, and click Apply.BIRTHS.KL=POP.K*BR), and Apply.| Button | What It Does |
|---|---|
| Fit View | Zooms and pans so the entire diagram fits in the viewport. |
| Undo / Redo | Undo or redo the last editor change. Works for both typed edits and programmatic changes from the diagram (editing a node, adding equations, etc.). Also available via Ctrl+Z / Ctrl+Y (or Ctrl+Shift+Z). |
| Edit/Move | Default mode — click to select and drag to reposition nodes. |
| Wire Connector | Enter wire-drawing mode. Click source, then target, to create an information link. |
| Pipe Connector | Enter pipe-drawing mode. Connect a Level ↔ Rate to show material flow. |
| Level / Rate / Auxiliary / Table / Constant | Add a new node of the chosen type. Opens the properties panel to set name, formula, etc. |
| Array | Add an Array Level node — a subscripted family of similar stocks (e.g., age cohorts). See Working with Arrays below. |
| Add Ghost | Create a ghost (visual duplicate) of an existing variable to shorten long wires. |
| Plot | Add a Plot node to the diagram showing simulation time-series for the active run. |
Configure which variables appear in the Data tab. Opens a popup to select variables for the active run’s PRINT line. | |
| Note | Add a text annotation to the diagram. Notes are stored as NOTE lines in the editor, scoped to the active run. |
| Macro ▾ | Open the macro dropdown. Click + New Macro to create a reusable equation template, or click an existing macro to edit or delete it. Macros are written as MACRO..MEND blocks at the top of the editor. |
| Hidden (N) | Shows the count of hidden nodes. Click to reveal the list and unhide them. |
| Run dropdown / + Run | Select the active run section. All diagram edits target this run. Click + Run to add a new scenario. |
| Type | Shape | Color | When to Use |
|---|---|---|---|
| Level | Rectangle | ■ Blue | Anything that accumulates over time: population, inventory, capital, knowledge. Requires an initial value (N line) and at least one rate flowing in or out. |
| Rate | Bowtie | ◆ Gold | Controls how fast a level changes: birth rate, production rate, spending rate. Always connect to a level via a pipe. |
| Array Level | Stacked rectangles | ■ Blue | An array of levels — multiple stocks sharing the same equation structure, indexed by a FOR variable. Displays as stacked rectangles with a size badge. Example: age cohorts in a population model. |
| Array Rate | Stacked bowties | ◆ Gold | An array of rates — multiple flows sharing the same equation structure. Created automatically when connecting a pipe from an Array Level to a plain Rate, or by clicking the Array button and switching to a rate. |
| Auxiliary | Circle | ● Green | Intermediate calculations that combine other variables: ratios, gaps, desired values. Keeps formulas clean by breaking complex logic into steps. |
| Table | Circle with lines | ● Purple | Nonlinear lookup relationships where you define the curve by data points, e.g., how crowding affects death rate. The built-in chart editor lets you shape the curve visually. |
| Constant | Horizontal line | ■ Grey | Fixed parameters that don’t change during a run: birth fraction, normal lifetime, policy thresholds. Easy to identify and adjust for scenario testing. |
| Array Constant | Horizontal line | ■ Grey | A constant with multiple values — one per array element (e.g., age-specific death rates). Uses a T line in the editor. Created by converting a Table Lookup via the ⇌ Array Const button, or parsed automatically from T lines that aren’t used by a TABLE() function. |
Wires show that one variable reads another’s value. For example, if BIRTHS depends on POP, draw a wire from POP to BIRTHS.
Shortcut: Hold Shift and drag from one node to another for a one-off quick-wire without entering wire mode.
Pipes represent physical material flowing between a stock and a valve. For example, water flowing from a TANK through a DRAIN rate.
| Wire Connector | Pipe Connector | |
|---|---|---|
| Meaning | “A reads the value of B” | “Material flows from stock through valve” |
| Appearance | Dashed arrow | Solid colored pipe |
| Valid between | Any node → any node | Level ↔ Rate only |
| Example | POP → BIRTHS (births depends on population size) | POP → DEATHS (people physically leaving the population) |
Drag a wire sideways to bend it into an arc
Wire arrows start straight. To bend one into an arc:
The system also auto-curves wires that would pass through other nodes.
| Action | How |
|---|---|
| Move a node | Click and drag it. All connected edges follow in real-time. |
| Pan the view | Click and drag on empty canvas space. |
| Zoom | Scroll the mouse wheel. Zooms toward cursor position. Range: 5% – 800%. |
| Fit everything | Click Fit View in the toolbar. |
| Select a node | Click it. Opens the properties panel. |
| Deselect | Click empty space or press Escape. |
Click any node to open the properties panel on the right. Here’s how to use each field:
Properties panel layout for a Level node
| Field | How to Use |
|---|---|
| Type | Change between Level, Rate, Auxiliary, Table, Constant. Changing type updates the equation prefix in the editor automatically. |
| Name | The variable name (auto-uppercased). Renaming a variable here updates every reference throughout your entire model. |
| Formula | The right-hand side of the equation. Type directly, or use the insert buttons below the field to add functions and variable references with correct time subscripts. |
| Initial Value | (Levels only) The starting value at time zero. Generates the N line in the editor. |
| Table Name / Data | (Table nodes only) The lookup table name and slash-separated output values. See Table Chart below. |
| Units | Optional unit annotation (e.g., persons, $/year). Used for dimensional analysis and shown in data headers. |
| Hide in diagram | Visually hides the node without deleting it. Useful for reducing clutter with constants. |
Below the formula field, clickable buttons let you insert operators and functions at the cursor position. Click any button to insert the function template with placeholder arguments.
| Button | Description |
|---|---|
+ - * / | Arithmetic operators — addition, subtraction, multiplication, division. |
( ) | Grouping parentheses for controlling order of operations. |
DT | The simulation time step. Used in Level equations: POP.J+(DT)*(BIRTHS.JK). |
TIME.K | The current simulation time. Use to create time-dependent behavior. |
| Function | Description |
|---|---|
SQRT(x) | Square root of x. |
ABS(x) | Absolute value of x. |
SIN(x) | Sine of x (x in radians). |
COS(x) | Cosine of x (x in radians). |
EXP(x) | e raised to the power x (natural exponential). |
LOG(x) | Natural logarithm (base e) of x. |
MAX(a,b) | Returns the larger of a and b. |
MIN(a,b) | Returns the smaller of a and b. |
| Function | Description |
|---|---|
TABLE(T,x,lo,hi,step) | Standard table lookup. Looks up the value of x in table data T, with X axis ranging from lo to hi in increments of step. Linearly interpolates between data points. Returns the boundary value if x is outside the range. |
TABHL(T,x,lo,hi,step) | Table with Hard Limits. Same as TABLE but clamps the output strictly — returns exactly the first or last table value if x is outside the range (no extrapolation). |
TABXT(T,x,lo,hi,step) | Table with eXTrapolation. Like TABLE but linearly extrapolates beyond the defined range using the slope at the boundary. |
TABPL(T,x,lo,hi,step) | Table with Point-by-point Lookup. Looks up using the provided points directly as X/Y pairs rather than uniform spacing. |
| Function | Description |
|---|---|
CLIP(val1,val2,thresh,x) | Returns val1 if x ≥ thresh, otherwise returns val2. Use for policy switches that activate at a threshold. |
SWITCH(val1,val2,test) | Returns val1 if test = 0, otherwise returns val2. A simple on/off toggle. |
FIFZE(val1,val2,test) | First If Zero — returns val1 if test = 0, otherwise returns val2. |
FIFGE(val1,val2,test) | First If Greater or Equal — returns val1 if test ≥ 0, otherwise returns val2. |
| Function | Description |
|---|---|
STEP(height,stime) | Outputs 0 before time stime, then jumps to height and stays there. Use for sudden policy changes or shocks. |
RAMP(slope,stime,etime) | Outputs 0 before stime, then increases linearly at slope per time unit until etime (then holds constant). Use for gradual changes. |
PULSE(height,first,interval) | Outputs height for one DT at time first, then repeats every interval time units. Use for periodic injections or impulse testing. |
NOISE() | Returns a random number from a normal distribution (mean 0, std dev 1) at each time step. Use for stochastic disturbances. |
SAMPLE(x,s,i) | Samples the value of x at time s, then re-samples every i time units. Holds the sampled value constant between samples. Use for discrete periodic measurements. |
| Function | Description |
|---|---|
DELAY1(input,delay) | First-order exponential delay (one stock). Output lags behind input with an average delay of delay time units. Equivalent to a single level being filled by the input. |
DELAY3(input,delay) | Third-order exponential delay (three cascaded stocks). Produces an S-shaped delay response — output stays near zero initially, then rises to match input. More realistic than DELAY1 for material pipelines. |
SMOOTH(input,delay) | Exponential smoothing (identical to DELAY1). Output tracks input but smoothed over delay time units. Use for perceived or averaged quantities. |
DLINF3(input,delay) | Third-order information delay. Like DELAY3 but specifically for information (perception) rather than material. Separates reporting delays from physical delays. |
Tip: For Table nodes, only the Ops and Table groups are shown to reduce clutter.
At the bottom of the panel, the Connections section shows all incoming and outgoing edges. Click any connection name to jump to that node in the diagram and highlight it. This is a fast way to navigate between related variables.
Table nodes define nonlinear lookup curves. When you select a table node, an interactive chart appears:
Drag any point (pink = active) in any direction to reshape the curve
Below the chart is an editable table showing Input (X) and Output (Y) values for each point:
A table formula looks like: TABLE(TABNAME,INPUT.K,lo,hi,step)
Arrays (subscripted variables) let you define families of levels and rates that share equation structure. In the diagram, array elements are collapsed into a single node shown as stacked shapes with a size badge (e.g., [3]).
POP) and configure the Array Configuration panel:
AGE).YOUNG,ADULT,OLD).POP.J(AGE)+DT*(BIN.JK(AGE)-BOUT.JK(AGE)).I, FOR, L, and N lines are generated in the editor.Below the Array Configuration, clickable element tabs let you view and edit individual elements:
YOUNG, ADULT, OLD or numbers 1, 2, 3) — Click to see that specific element’s formula. You can give each element a different formula.When you click Apply, if all element formulas are identical, a single FOR-parameterized equation is written. If any differ, separate per-element equations with numeric subscripts are written instead.
The Initial Values field also switches per element: on the Shared tab it shows all values separated by /, on an element tab it shows just that element’s value.
Array rates are created in two ways:
R BIN.KL(AGE)=...), the diagram detects them and displays them as stacked bowties.Constants that vary across array elements use T (table) lines, not C lines. A C line holds a single scalar value, but a T line holds multiple slash-separated values — one per element:
T DTHRT=.002/.005/.02
These appear on the diagram as a single constant node (grey horizontal line) wired to any array that references them.
A Table Lookup node uses a TABLE() function with a curve. An Array Constant just stores slash-separated values for each element. You can convert between them:
Click ⇌ Array Const in the properties panel to convert a Table Lookup into a simple array constant (and back)
How to use:
.002/.005/.02). The lookup chart is removed.A to T: T DTHRT=.002/.005/.02To convert back, click ⇌ Table Lookup. The values become table data and a TABLE() formula is generated.
When to use which:
| Array Constant | Table Lookup | |
|---|---|---|
| Data | One fixed value per array element | Curve with many points for interpolation |
| Example | T DTHRT=.002/.005/.02 (3 values for 3 age groups) | A EFFECT.K=TABLE(EFFT,RATIO.K,0,2,0.5) |
| Diagram shape | Grey line (constant) | Purple circle with lines (table) |
| Editor line | T prefix | A prefix + separate T data line |
Multiple arrays can share the same FOR variable (e.g., both POP and BIN use AGE). The diagram handles this correctly:
I and FOR lines are preserved if any other array still uses that index variable.I/FOR lines are not inserted.Ghost nodes are visual duplicates of existing variables. They don’t create new equations — they just provide a second reference point on the diagram to reduce long crossing wires.
Use ghosts to replace long wires with short local connections
If a widely-used variable (like POPULATION) has wires stretching across the entire diagram, create a ghost near the variables that need it. The long wires become short local connections.
DYNAMO supports multiple runs — different scenarios that share the same base model but override specific parameters. The run dropdown in the diagram toolbar lets you manage these.
Runs share the base model; override runs contain only changed parameters
The run dropdown at the top of the diagram toolbar shows all runs defined in the model. It controls which run section your diagram edits target.
| Action | How |
|---|---|
| Switch active run | Select a different run from the dropdown. All subsequent diagram edits (adding nodes, changing formulas, editing SPEC, PLOT lines, etc.) are scoped to that run’s section in the editor. |
| Add a new run | Click the + Run button. You’ll be prompted for a name. A new RUN line is appended to the editor, creating a new scenario section. |
A multi-run DYNAMO file has this structure:
* MY MODEL L POP.K=POP.J+(DT)*(BR.JK) R BR.KL=POP.K*BRN N POP=1000 C BRN=0.03 SPEC DT=1,LENGTH=100,PRTPER=1,PLTPER=1 PLOT POP=P RUN BASE C BRN=0.05 SPEC DT=1,LENGTH=100,PRTPER=1,PLTPER=1 RUN HIGH BIRTH
RUN line.RUN line.When you select a non-base run in the dropdown, all diagram operations are scoped to that run’s section:
Plot nodes are mini time-series charts that live on the diagram, showing real simulation results. Each plot node is associated with a specific run — its title shows which run it belongs to (e.g., “PLOT — HIGH BIRTH”).
Plot node showing POP growth over time with resize handle in the corner
In the plot configuration panel, each variable has lo and hi fields that set its Y-axis range. Use these when plotting variables with very different magnitudes together (e.g., a large level and a small rate). Without explicit scales, the smaller variable will appear flat because the Y-axis is stretched to fit the larger one.
When variables have different scale ranges, the chart automatically normalizes each trace to its own range so all are visible. The Y-axis shows 0–100% and the legend displays each variable’s actual scale. These values correspond to the (lo,hi) in the PLOT statement: PLOT POP=P(0,5000)/BIRTH=B(0,100).
The Print toolbar button configures which variables appear in the Data tab (the tabular output after running the model). It manages the PRINT line in the editor for the currently active run.
PRINT line for the active run is updated in the editor.If a run has no PRINT line, it won’t appear in the Data tab’s run dropdown. You can also configure print variables by typing PRINT VAR1,VAR2,... directly in the editor.
Note nodes are text annotations that live on the diagram. They are ideal for documenting assumptions, labeling diagram sections, or leaving explanatory comments visible alongside the model structure.
Note nodes use dashed borders and can be placed beside related variables
NOTE line is written to the editor in the active run’s section.Notes map to NOTE lines prefixed with a marker (e.g., NOTE :n1: Your text here). They are run-scoped — each run can have its own annotations. Editing a note in the editor automatically updates the diagram, and vice versa.
Notes render with a transparent background and dashed border, using theme-aware colors that adapt to light and dark mode.
Macros are reusable equation templates that let you define a pattern once and invoke it multiple times with different arguments. They are managed from the diagram toolbar but do not appear as nodes on the diagram — only the variables that call the macro appear as normal equation nodes.
The Macro button opens a dropdown to create or edit macros, which sync to MACRO..MEND blocks in the editor
MYSMOOTH)OUT, IN, AVG)RT)R RT.KL=(IN.K-OUT.K)/AVG)MACRO..MEND block is written to the top of the editor.The macro context panel with fields for name, arguments, internals, and body equations
MACRO..MEND block from the editor).Macros themselves are not diagram nodes. When an equation calls a macro (e.g., A SAVG.K=MYSMOOTH(SAVG,ORDERS.K,8)), the interpreter expands it into real equations with unique internal variable names. Those expanded variables appear as regular nodes on the diagram.
Units work normally with macros — define U lines for the variables you pass as arguments, and the unit-inference engine propagates through the expanded equations.
MACRO..MEND block at the top of the editor (following DYNAMO convention).Hide constants and parameters to declutter your diagram
Complex models can have dozens of constants cluttering the view. To hide them:
Changes in either pane are reflected automatically in the other
The diagram and editor stay in sync automatically in both directions:
Go to File → Export Diagram and choose a format:
When you save a model (File → Save), the diagram layout is stored as a NOTE :LAYOUT: line in the file. This includes node positions, edge curves, hidden nodes, and ghost nodes. The layout is automatically restored when you reopen the model.
The Model Settings window (⚙) lets you configure the core simulation parameters before you run. Open it via Simulation → Settings, or it appears automatically when you create a new model.
| Field | DYNAMO Code | Description |
|---|---|---|
| Model Title | * title | A descriptive name for the model. Written as a comment (*) at the top of the file. |
| DT | SPEC DT=0.5 | The simulation time step. Smaller values increase accuracy but slow down the run. |
| LENGTH | SPEC LENGTH=200 | Total simulation duration in time units. |
| PRTPER | SPEC PRTPER=5 | Print period — how often data rows appear in the Data tab. Set to 0 to print every DT. |
| PLTPER | SPEC PLTPER=1 | Plot period — how often plot points are recorded. Set to 0 for every DT. |
| RUN Name | RUN BASE | A label for this simulation run. Use multiple RUN statements for scenario analysis. |
| Time Unit | U DT=years | The unit of the time step (e.g. days, years, hours). Used for rate-unit inference. |
| Integration Method | — | Choose between Euler (1st order) and Runge-Kutta (3rd order). Euler is fast and simple. Runge-Kutta uses adaptive step sizes for higher accuracy. |
| REL_ERR | C REL_ERR=0.01 | Relative error tolerance for the RK3 solver. The solver adjusts its internal step size to keep the local error below this fraction of the variable value. Typical: 0.001–0.05. |
| ABS_ERR | C ABS_ERR=0.001 | Absolute error tolerance for the RK3 solver. Prevents overly tiny steps when variable values are near zero. Typical: 0.0001–0.01. |
The Euler method (1st order) computes the next value using only the current rate: LEVEL.K = LEVEL.J + DT * RATE.JK. It is simple and fast but can accumulate error, especially with large DT values or rapidly changing rates.
The Runge-Kutta method (3rd order, Bogacki–Shampine variant) evaluates the rates at multiple sub-points within each DT step and compares a 2nd-order and 3rd-order estimate to gauge accuracy. If the estimated error exceeds your tolerances, the solver automatically shrinks the internal step size; if accuracy is easily met, it increases the step. This adaptive approach gives you higher accuracy without manually tuning DT.
When to use RK3: Models with stiff dynamics, exponential growth, or highly non-linear feedback loops benefit from RK3. If your Euler results change significantly when you halve DT, that’s a sign the model would benefit from adaptive integration.
When Euler is fine: Simple models with smooth, slowly changing rates. Euler is faster per time step and easier to reason about.
All settings sync both ways with the editor:
SPEC, RUN, C REL_ERR=, or U DT= lines directly in the editor → the settings window reflects them when reopened.| Shortcut | Action |
|---|---|
Ctrl+Z | Undo the last editor change. |
Ctrl+Y or Ctrl+Shift+Z | Redo the last undone change. |
Ctrl+Enter | Run the model. |
Ctrl+N | New model. |
Ctrl+O | Open model file. |
Ctrl+S | Save model (quick save if already saved, otherwise Save As). |
Ctrl+Shift+S | Save As — save with a new name. |
Escape | Deselect, close properties panel, or exit draw mode. |
Shift + Drag | Quick wire-draw from one node to another. |
Mouse Wheel | Zoom in/out centered on cursor. |
S.I.M.P.L.E. (Simulation of Industrial Management Problems with Lots of Equations) is a system dynamics modeling language based on DYNAMO 6. A model consists of equations that describe how variables change over time, organized by line prefixes (modes). This implementation supports macros, arrays, adaptive Runge-Kutta integration, and the ** exponentiation operator.
| Prefix | Name | Description | Example |
|---|---|---|---|
* | Title | Model title (first line) | * MY EPIDEMIC MODEL |
NOTE | Comment / Annotation | Comment ignored by interpreter. Also used for diagram annotations (NOTE :n1: text) and layout persistence (NOTE :LAYOUT: ...). | NOTE This is a comment |
L | Level | Stock / accumulator — integrates flows over time | L POP.K=POP.J+DT*(BIRTH.JK-DEATH.JK) |
R | Rate | Flow equation — determines rate of change | R BIRTH.KL=POP.K*BR |
A | Auxiliary | Helper variable computed each time step | A RATIO.K=SICK.K/TOTAL |
S | Supplementary | Output-only variable (not used in other equations) | S OUTPUT.K=POP.K*1000 |
C | Constant | Fixed value for the entire simulation | C BR=0.03 |
N | Initial | Starting value for a level | N POP=1000 |
T | Table | Lookup table data (values separated by /). Also used for array constants — values that apply across array elements (e.g., T AGDLY=15/25/1E30 gives one value per element). Use T instead of C whenever a constant has multiple values for an array. | T MYTAB=0/2.8/5.5/8/9.5/10 |
X | Continuation | Continues the previous line (for long equations) | X +RECOV.JK) |
U | Units | Units annotation for dimensional analysis | U POP=persons,BR=persons/year |
FOR | Array Index | Defines an array index variable with range and optional element names | FOR AGE=1,4=YOUTH,YADLT,MDLAG,OLDST |
I | Integer Constant | Defines integer constants for array subscripts | I NAGES=4/YOUTH=1/YADLT=2 |
MACRO | Macro Start | Begin a reusable equation template | MACRO DELAY1(IN,DEL) |
MEND | Macro End | Closes a MACRO definition | MEND |
INTRN | Macro Internals | Declares internal (local) variables inside a macro | INTRN LV,RT |
SPEC | Specification | Simulation parameters | SPEC DT=0.25,LENGTH=50,PRTPER=5,PLTPER=0.5 |
PRINT | Variables to include in print output | PRINT POP,BIRTH,DEATH | |
PLOT | Plot | Variables to plot with symbol and Y-axis scale. The (lo,hi) sets the Y-axis range for that group — use separate / groups with different scales when plotting variables of very different magnitudes (e.g., a level in the thousands and a rate below 100) so each is normalized and visible. | PLOT POP=P(0,5000)/BIRTH=B(0,100) |
RUN | Run | Execute the model with a given name | RUN BASELINE |
EDIT | Edit | Modify a previously run model and re-run | EDIT BASELINE |
S.I.M.P.L.E. uses index suffixes to indicate when a variable is evaluated:
| Index | Meaning | Used In |
|---|---|---|
.K | Current time step ("now") | Levels, Auxiliaries (left & right side) |
.J | Previous time step ("last") | Levels (right side only) |
.KL | Rate from current to next | Rates (left side) |
.JK | Rate from previous to current | Rates (right side of level equations) |
Constants and initials have no index suffix.
L STOCK.K = STOCK.J + DT * (INFLOW.JK - OUTFLOW.JK)
This reads: "the stock now = the stock before + time_step × (inflow − outflow)"
| Operator | Description | Example |
|---|---|---|
+ | Addition | A+B |
- | Subtraction (also unary minus) | A-B |
* | Multiplication | A*B |
/ | Division | A/B |
** | Exponentiation (power) | X**2 — X squared |
Note: Division precedence follows DYNAMO convention — A/B+C is interpreted as (A/B)+C, not A/(B+C). Use parentheses to be explicit.
| Parameter | Description | Default |
|---|---|---|
DT | Time step size (upper bound for adaptive integration) | 0.1 |
LENGTH | Total simulation time | 10 |
PRTPER | Print output period (0 = every step) | 0 |
PLTPER | Plot output period (0 = every step) | 0 |
REL_ERR | Relative error tolerance for adaptive RK3 integration (e.g. 0.01 = 1%) | 0.01 |
ABS_ERR | Absolute error tolerance for adaptive RK3 integration | 0.001 |
Set these via SPEC or as individual C constants. You can also configure them from the Simulation → Settings dialog, which includes an Integration Method dropdown to switch between Euler and Runge-Kutta.
When REL_ERR is set (or Runge-Kutta is selected in the settings), the simulation uses 3rd-order Runge-Kutta adaptive integration (Bogacki–Shampine variant). This automatically adjusts the step size within each DT for higher accuracy. Otherwise, standard Euler integration is used. See Diagram Help → Simulation Settings for a detailed guide.
The U statement assigns measurement units to variables. The editor performs real-time dimensional analysis — unit mismatches are flagged with red wavy underlines as you type.
U POP=persons,BR=persons/year,DT=years
Multiple variables can share one U line (comma-separated), or you can use separate U lines. Units can also be edited per-node in the diagram properties panel.
What is checked:
DT.| Function | Description | Example |
|---|---|---|
SQRT(X) | Square root | A Y.K=SQRT(X.K) |
SIN(X) | Sine (radians) | A Y.K=SIN(TIME.K) |
COS(X) | Cosine (radians) | A Y.K=COS(TIME.K) |
EXP(X) | Exponential (e^x) | A Y.K=EXP(-0.1*TIME.K) |
LOG(X) | Natural logarithm (base e) | A Y.K=LOG(X.K) |
LOGN(X) | Natural logarithm (alias for LOG) | A Y.K=LOGN(X.K) |
ABS(X) | Absolute value | A Y.K=ABS(X.K) |
MAX(X,Y) | Maximum of two values | A Z.K=MAX(A.K,B.K) |
MIN(X,Y) | Minimum of two values | A Z.K=MIN(A.K,B.K) |
| Function | Description | Returns |
|---|---|---|
CLIP(A,B,X,Y) | If X ≥ Y return A, else B | A or B |
SWITCH(A,B,X) | If X = 0 return A, else B | A or B |
FIFZE(A,B,X) | If X = 0 return A, else B | A or B |
FIFGE(A,B,X) | If X ≥ 0 return A, else B | A or B |
| Function | Description | Example |
|---|---|---|
STEP(H,T) | Returns H when TIME ≥ T, else 0 | R IN.KL=STEP(100,10) |
RAMP(S,T) | Returns S×(TIME-T) when TIME ≥ T, else 0 | R IN.KL=RAMP(5,10) |
PULSE(H,W,T,P) | Pulse of height H, width W, first at T, repeating every P (DYNAMO IV format) | R IN.KL=PULSE(50,1,10,20) |
NOISE() | Random value in [-0.5, 0.5] | A N.K=NOISE() |
NORMRN(M,S) | Normal random number with mean M and standard deviation S | A N.K=NORMRN(0,1) |
SAMPLE(X) | Sample and hold a value | A S.K=SAMPLE(X.K) |
| Function | Description |
|---|---|
TABLE(name,X,lo,hi,step) | Linear interpolation; clamps outside range |
TABHL(name,X,lo,hi,step) | Same as TABLE (alias) |
TABXT(name,X,lo,hi,step) | Linear extrapolation outside range |
TABPL(name,X,lo,hi,step) | Polynomial interpolation inside range |
Usage: Define a table with T, then reference it:
T MYTAB=0/10/30/50/40/20 A Y.K=TABLE(MYTAB,X.K,0,50,10)
This looks up X.K in MYTAB over the range 0–50 with step 10.
| Function | Description | Example |
|---|---|---|
DELAY1(rate.JK,D) | First-order exponential delay of D time units | R OUT.KL=DELAY1(IN.JK,5) |
DELAY3(rate.JK,D) | Third-order exponential delay (smoother) | R OUT.KL=DELAY3(IN.JK,5) |
DELAYP(rate.JK,D) | Pipeline (fixed) delay — 6-stage boxcar train preserving input shape delayed by D | R OUT.KL=DELAYP(IN.JK,5) |
SMOOTH(var.K,D) | Exponential smoothing with delay D | A AVG.K=SMOOTH(X.K,10) |
DLINF3(level.K,D) | Third-order information delay | A INFO.K=DLINF3(DATA.K,5) |
| Function | Description | Example |
|---|---|---|
SUM(A(*)) | Sum all elements of array A | A TOT.K=SUM(POP.K(*)) |
SUMV(A(*),lo,hi) | Sum elements of A from index lo to hi | A SUB.K=SUMV(POP.K(*),2,5) |
PRDV(A(*),lo,hi) | Product of elements of A from lo to hi | A PRD.K=PRDV(FACT.K(*),1,N) |
SCLPRD(A(*),B(*),lo,hi) | Scalar (dot) product of two arrays from lo to hi | A DOT.K=SCLPRD(X.K(*),Y.K(*),1,N) |
SHIFTL(A(*),n,lo,hi) | Shift array left by n positions | A SH.K=SHIFTL(X.K(*),1,1,N) |
SHIFTC(A(*),n,lo,hi) | Circular shift of array by n positions | A SH.K=SHIFTC(X.K(*),1,1,N) |
A macro is a copy-paste template that the computer fills in for you. You define a pattern of equations once, then stamp it out as many times as you need with different inputs.
Suppose you need to smooth three different variables. Without macros you’d write the same three equations (Level + Init + Rate) three times — 9 lines of near-identical code. With a macro, you write the pattern once and call it in one line each time.
MACRO MYSMOOTH(INPUT,DELAY) INTRN RT L MYSMOOTH.K=MYSMOOTH.J+DT*RT.JK N MYSMOOTH=INPUT R RT.KL=(INPUT.K-MYSMOOTH.K)/DELAY MEND
| Line | What It Does |
|---|---|
MACRO MYSMOOTH(INPUT,DELAY) | Declares a macro named MYSMOOTH with two dummy arguments: INPUT and DELAY. These are placeholders — they can be any name you choose. |
INTRN RT | Lists internal variables — helpers that are private to each expansion. Each call gets its own unique version (e.g., _M1_RT, _M2_RT) so they don’t collide. |
L … / N … / R … | The body equations — standard DYNAMO equations that use the dummy arguments. The macro name (MYSMOOTH) is automatically the output variable. |
MEND | End of the macro definition. |
Use the macro name like a function, passing real variables and constants in place of the dummy arguments:
A SAVG.K=MYSMOOTH(SALES.K,4) A PAVG.K=MYSMOOTH(PRICE.K,8) A CAVG.K=MYSMOOTH(COST.K,6)
Each call triggers a find-and-replace behind the scenes:
| Dummy | Call 1 | Call 2 | Call 3 |
|---|---|---|---|
INPUT | SALES | PRICE | COST |
DELAY | 4 | 8 | 6 |
MYSMOOTH (output) | SAVG_MO1 | PAVG_MO2 | CAVG_MO3 |
RT (internal) | _M1_RT | _M2_RT | _M3_RT |
You never see these expanded equations — the interpreter generates them automatically.
INPUT, DELAY) are just placeholder names. They are not real variables — they get replaced before any equations run. Don’t give them time suffixes like .K in the MACRO header.INTRN get unique names per call. Any helper variable in the body that isn’t a dummy argument or the macro name should be declared INTRN.MYSMOOTH) is the output. It automatically becomes a uniquely-named variable in each expansion. Don’t list it on INTRN..K, .J, .JK, .KL).MYSMOOTH(SALES.K,4) and MYSMOOTH(SALES,4) both work the same way.Arrays let you define families of similar equations indexed by one or more subscripts. Use FOR to define index ranges and I for integer constants.
I NAGES=4 FOR AGE=1,NAGES=YOUTH,YADLT,MDLAG,OLDST
This defines a FOR variable AGE ranging from 1 to 4, with named aliases.
L POP.K(AGE)=POP.J(AGE)+DT*(BIRTH.JK(AGE)-DEATH.JK(AGE)) N POP(AGE)=INITPOP(AGE) T INITPOP(*)=100/200/150/80
The interpreter expands AGE over its full range, generating one equation per element (e.g. POP_1, POP_2, POP_3, POP_4). Subscripts are flattened to underscore notation internally.
POP(AGE-1).* for the wildcard subscript on table data: T TAB(*)=...When REL_ERR is set (e.g. C REL_ERR=0.01), the simulator uses 3rd-order Runge-Kutta adaptive step-size integration instead of Euler. This automatically reduces DT where needed for accuracy and restores it when possible.
| Parameter | Description |
|---|---|
REL_ERR | Relative error tolerance per level (default 0.01 = 1%) |
ABS_ERR | Absolute error tolerance for all levels (default 0.001). Used when levels approach zero. |
Total tolerable error per step = REL_ERR × |level| + ABS_ERR
Stiffness: If the solver must reduce DT excessively, it reports CAUSING STIFFNESS AT TIME = and STIFFNESS ENDED AT TIME =. If the error tolerance forces DT too small, a fatal error is reported.
Use EDIT to take a previously run model, change or add equations, then run again:
RUN BASELINE NOTE Now modify and re-run: EDIT BASELINE C BR=0.05 RUN SCENARIO2
The interpreter produces DYNAMO-standard error and warning messages:
| Category | Example Messages |
|---|---|
| Math | SQRT OF A NEGATIVE NUMBER, LOG OF A NEGATIVE NUMBER, EXP ARGUMENT TOO LARGE, TRIED TO DIVIDE BY ZERO, EXPONENT OVERFLOW |
| Syntax | NO =. LINE IGNORED, TOO MANY =, LEFT OF = IMPROPER, TOO FEW ), TOO MANY ), MISPLACED TIMESCRIPT |
| Names | X NOT DEFINED, X DEFINED PREVIOUSLY, X NOT USED, X REQUIRES INITIAL VALUE |
| Tables | ABOVE/BELOW RANGE OF TABLE (AT TIME), TOO FEW/MANY VALUES IN TABLE |
| Macros | NO MEND CARD, WRONG NUMBER OF ARGUMENTS IN CALL TO MACRO |
| Arrays | ERRONEOUS FOR STATEMENT, SUBSCRIPT MUST BE > 0, RANGE IMPROPER IN SUMV/PRDV |
| Model | SIMULTANEOUS EQNS IN N/A EQNS, INCONSISTENT FIRST VALUES, NO OR INCOMPLETE SPEC CARD |
| Integration | CAUSING STIFFNESS AT TIME =, ERROR TOLERANCE FORCES DT TOO SMALL, EXTENT OF DENOMINATOR AMBIGUOUS |
* SIMPLE EPIDEMIC MODEL L SUSC.K=SUSC.J+DT*(-INF.JK) N SUSC=988 R INF.KL=SICK.K*CNTCTS.K*FRSICK C FRSICK=0.05 L SICK.K=SICK.J+DT*(INF.JK-CURE.JK) N SICK=2 A CNTCTS.K=TABLE(TABCON,SUSC.K/TOTAL,0,1,0.2) T TABCON=0/2.8/5.5/8/9.5/10 N TOTAL=SUSC+SICK+RECOV R CURE.KL=SICK.K/DUR C DUR=10 L RECOV.K=RECOV.J+DT*CURE.JK N RECOV=10 U SUSC=persons,SICK=persons,RECOV=persons,DT=days U DUR=days,FRSICK=1/days SPEC DT=0.25,LENGTH=50,PRTPER=5,PLTPER=0.5 PRINT SUSC,SICK,RECOV,INF,CURE RUN SIMPLE
* AGE-COHORT POPULATION MODEL I NAGES=3 FOR AGE=1,NAGES=YOUNG,ADULT,OLD L POP.K(AGE)=POP.J(AGE)+DT*(BIN.JK(AGE)-BOUT.JK(AGE)) N POP(1)=500 N POP(2)=300 N POP(3)=200 R BIN.KL(1)=BRTHRT*POP.K() R BIN.KL(2)=POP.K(1)/AGDLY(1) R BIN.KL(3)=POP.K(2)/AGDLY(2) R BOUT.KL(AGE)=(POP.K(AGE)/AGDLY(AGE))+(DTHRT(AGE)*POP.K(AGE)) C BRTHRT=0.03 T AGDLY=15/25/1E30 T DTHRT=.002/.005/.02 A TOTAL.K=SUM(POP.K) SPEC DT=1/LENGTH=100/PRTPER=1/PLTPER=1 PLOT POP.K(1)=Y,POP.K(2)=A,POP.K(3)=O/TOTAL.K=T PRINT TOTAL RUN COHORT
This model tracks three age cohorts (YOUNG, ADULT, OLD) as array elements. BIN (births in) has per-element equations — newborns enter the youngest cohort, while older cohorts receive population from the previous age group. BOUT (births out) uses a shared FOR-parameterized equation with age-specific death rates from a table lookup. SUM(POP.K) totals all cohorts.
Note: AGDLY and DTHRT are constants that vary across array elements, so they use T (table) lines instead of C. In DYNAMO, C defines a single scalar value, while T can hold multiple slash-separated values — one per array element. Use T whenever a constant needs a different value for each element of an array.
This complete model defines a custom smoothing macro and uses it to smooth incoming orders for a simple inventory system. Paste it into the editor and press Ctrl+Enter to run.
* INVENTORY MODEL WITH CUSTOM SMOOTH MACRO * * ---- Define the macro (template) ---- * MYSMOOTH smooths a signal over a time delay. * INPUT = the signal to smooth (dummy argument) * DELAY = averaging time in time units (dummy argument) * RT = internal rate variable (private to each call) MACRO MYSMOOTH(INPUT,DELAY) INTRN RT L MYSMOOTH.K=MYSMOOTH.J+DT*RT.JK N MYSMOOTH=INPUT R RT.KL=(INPUT.K-MYSMOOTH.K)/DELAY MEND * * ---- Main model ---- * Inventory rises with production and falls with shipments. * Production follows smoothed demand (not raw orders). L INV.K=INV.J+DT*(PROD.JK-SHIP.JK) N INV=400 R PROD.KL=DPROD.K R SHIP.KL=ORDERS.K * Call the macro: smooth ORDERS over ADJT time units A DPROD.K=MYSMOOTH(ORDERS.K,ADJT) * Orders jump from 200 to 300 at time 10 A ORDERS.K=200+STEP(100,10) C ADJT=5 SPEC DT=0.5,LENGTH=50,PRTPER=1,PLTPER=1 PLOT INV=I,ORDERS=O,DPROD=D PRINT INV,ORDERS,DPROD,SHIP RUN MACRO TEST
What happens: At time 10, orders jump instantly from 200 to 300. But production (DPROD) ramps up gradually over ~5 time units because the macro smooths the step change. Shipments respond immediately, so inventory dips temporarily before recovering. You’ll see the lag clearly on the plot.
| Feature | Description |
|---|---|
| Syntax highlighting | Keywords, variable names, comments, and units are color-coded. Recognizes all DYNAMO 6 statement types including FOR, I, MACRO, MEND, INTRN. |
| Autocomplete | As you type, a popup suggests variable names, functions (including array functions), and keywords. Use arrow keys to navigate, Enter to accept, Escape to dismiss. |
| Auto-uppercase | All text is automatically uppercased (S.I.M.P.L.E. convention). |
| Real-time error checking | Syntax errors, subscript mismatches, undefined variables, and unit inconsistencies are flagged with red wavy underlines as you type. Hover over an error line to see the message. |
| Error badge | The ⚠ N errors badge in the toolbar shows the total error count. Click it to see all errors listed in the output log. |
| Line/Col indicator | Bottom-right of the toolbar shows current cursor position (Ln X, Col Y). |
| Feature | Description |
|---|---|
| File → New / Open / Save | Create, load, and save .dynamo / .simple model files. |
| File → Export Diagram | Export the diagram as SVG, PNG, or PDF. |
| File → Example Model | Load a built-in example to get started quickly. |
| Edit → Undo / Redo | Undo and redo editor changes. Uses a custom undo stack that tracks both typed edits and programmatic changes from the diagram (adding nodes, editing formulas, etc.). Also accessible via Ctrl+Z / Ctrl+Y and the Undo/Redo buttons on the diagram toolbar. |
| Insert menu | Add new Level, Rate, Auxiliary, Table, Constant, Plot, Print (Data), or Note elements. |
| Simulation → Settings | Open the settings dialog to configure DT, LENGTH, PRTPER, PLTPER, RUN name, and time unit. |
| Simulation → Run Model | Execute the model (same as the ▶ Run button or Ctrl+Enter). |
| Theme toggle | Switch between light and dark modes. |
| Output Log | Click the status bar to see compilation messages, warnings, and runtime output. |
| Split panels | Drag the divider between Editor and Diagram to resize. Collapse either panel with its toggle button. |
| Shortcut | Action |
|---|---|
Ctrl + Enter | Run model |
Ctrl + N | New model |
Ctrl + O | Open model file |
Ctrl + S | Save model file |
Ctrl + Z | Undo |
Ctrl + Y or Ctrl + Shift + Z | Redo |
Tab | Insert 6 spaces (S.I.M.P.L.E. column alignment) |
Escape | Close popups, exit draw mode, deselect |
L, R, etc.) must be followed by spaces, then the equation.X (continuation) lines to split long equations across multiple lines.C A=1,B=2,C=3** for exponentiation: X**2 means X squared.DT should be less than double the smallest first-order delay for stability.C REL_ERR=0.01 to enable 3rd-order Runge-Kutta.L.K = L.J + DT * (something).N (initial value) equation.U (unit) lines to catch dimensional errors — the editor flags mismatches in real time.PLOT statement.PRINT statement appear in the data table.NOTE lines and are run-scoped.Choose how to get started:
Running model...
This may take a moment for large models