About SimLang Models
Read this reference to learn how to use a SimLang model in an Epicenter application.
Model file
A SimLang model can contain three types of elements in any order: decisions, variables, and properties.
M StartTime = 0
M EndTime = 10
M TimeStep = 1
D Initial Savings = 5000
D Interest Rate = 10%
D Yearly Deposits = 1000
V Interest = Previous Year Savings * Interest Rate
V Total Savings = Previous Year Savings + Interest + Yearly Deposits
Operations
SimLang models expose a set of built-in operations that your application UI can call to advance or reset the simulation.
| Operation | Arguments | Description |
|---|---|---|
step() | Optional: number of time units | Advances the model. Defaults to 1 time unit. |
stepTo(n) | Time unit or "end" | Advances to a specific time, or to the end of the simulation. |
goBack() | Optional: number of time units | Moves the simulation backward. Defaults to 1 time unit. |
reset() | None | Creates a new run, discarding the current one. |
clear() | None | Resets the current run to its initial step without creating a new run. |
recalculate([...]) | Array of variable/decision names | Recalculates the listed elements from their equations and "unfreezes" variables. |
Use the operation() function of the Run adapter to call operations from your application:
import { runAdapter } from 'epicenter-libs';
await runAdapter.operation(runKey, 'step', [1]);
import { runAdapter } from 'epicenter-libs';
await runAdapter.operation(runKey, 'stepTo', ['end']);
import { runAdapter } from 'epicenter-libs';
await runAdapter.operation(runKey, 'recalculate', [['Interest Rate', 'Yearly Deposits']]);
If M TimeStep = 0.5, then step() advances by one time unit (two time steps), and step(2) advances by two time steps (one time unit).
Epicenter variables
The following variables are always available when running a SimLang model on Epicenter, in addition to any variables you define in your model.
| Variable | Description |
|---|---|
Time | Array of simulation times stepped through so far |
Step | Current step number (0-based) |
Start Time | Value of M StartTime |
Final Time | Value of M EndTime |
Time Step | Value of M TimeStep |
Upload your model
Use the Epicenter UI to upload your EQN file to your project. Optionally, also upload a model context file to the same folder.
Referencing variables from the UI
You can reference any SimLang decision (D) or variable (V) from your project's UI using the getVariable() and updateVariables() functions of the Run adapter.
SimLang models are time-based: each variable holds an array of values — one per step. Steps are 0-based.
Key rules:
- Omitting the step index returns the current step's value.
- Only decisions at the current step can be updated.
- Variable and decision names are not case-sensitive in Epicenter.
- Append
.POINT_IN_TIMEto retrieve the current step's value as a scalar rather than an array. - Append
.COLLAPSED_ARRAYto retrieve an arrayed variable with its array collapsed for each step (useful for graphing over steps).
Scalars
Reference a scalar decision or variable by name, with an optional step index [s].
D Sales = 100
import { runAdapter } from 'epicenter-libs';
const sales = await runAdapter.getVariable(runKey, 'Sales.POINT_IN_TIME');
import { runAdapter } from 'epicenter-libs';
const salesHistory = await runAdapter.getVariable(runKey, 'Sales');
// returns [100, 120, 130]
import { runAdapter } from 'epicenter-libs';
const salesStep1 = await runAdapter.getVariable(runKey, 'Sales[1]');
import { runAdapter } from 'epicenter-libs';
await runAdapter.updateVariables(runKey, { sales: 250 });
One-dimensional arrays
Reference an element using [n], with an optional step as the second subscript: [n, s].
D Price[3] = {100, 150, 175}
import { runAdapter } from 'epicenter-libs';
const price2 = await runAdapter.getVariable(runKey, 'Price[2]');
// returns 150
import { runAdapter } from 'epicenter-libs';
const price2step1 = await runAdapter.getVariable(runKey, 'Price[2,1]');
import { runAdapter } from 'epicenter-libs';
const priceHistory = await runAdapter.getVariable(runKey, 'Price');
// returns { "1": [100, 200, 300], "2": [150, 250, 350], "3": [175, 275, 375] }
import { runAdapter } from 'epicenter-libs';
const priceNow = await runAdapter.getVariable(runKey, 'Price.POINT_IN_TIME');
// returns { "1": 300, "2": 350, "3": 375 }
import { runAdapter } from 'epicenter-libs';
const priceByStep = await runAdapter.getVariable(runKey, 'Price.COLLAPSED_ARRAY');
// returns [[100, 150, 175], [200, 250, 275], [300, 350, 375]]
import { runAdapter } from 'epicenter-libs';
await runAdapter.updateVariables(runKey, { 'price[2]': 167 });
Enumerated ranges
Use the range label as the index: [label]. Optionally include the step: [label, s].
R Products = Books, CDs, Games
D Cost[Products] = {100, 150, 175}
import { runAdapter } from 'epicenter-libs';
const booksCost = await runAdapter.getVariable(runKey, 'Cost[Books]');
import { runAdapter } from 'epicenter-libs';
const booksCostStep0 = await runAdapter.getVariable(runKey, 'Cost[Books,0]');
import { runAdapter } from 'epicenter-libs';
const costHistory = await runAdapter.getVariable(runKey, 'Cost');
// returns { "Books": [100, 240], "CDs": [150, 153], "Games": [175, 189] }
import { runAdapter } from 'epicenter-libs';
await runAdapter.updateVariables(runKey, { 'cost[books]': 45 });
Multidimensional arrays
Reference a single element using [n, m], with an optional step as the final subscript: [n, m, s].
D SalesByRegion[5, 2] = {
{100, 200},
{300, 400},
{500, 600},
{700, 800},
{900, 1000}
}
import { runAdapter } from 'epicenter-libs';
const val = await runAdapter.getVariable(runKey, 'SalesByRegion[2,1]');
// returns 300
import { runAdapter } from 'epicenter-libs';
const valStep0 = await runAdapter.getVariable(runKey, 'SalesByRegion[2,1,0]');
import { runAdapter } from 'epicenter-libs';
const region2 = await runAdapter.getVariable(runKey, 'SalesByRegion[2]');
// returns { "1": [300, 301, 302], "2": [400, 401, 402] }
import { runAdapter } from 'epicenter-libs';
const allSales = await runAdapter.getVariable(runKey, 'SalesByRegion');
// returns nested object keyed by dimension, with each value as an array over steps
Calling operations from the UI
Use the operation() function of the Run adapter to call any SimLang operation from your application code. The operations available are listed in the Operations section above.
import { runAdapter } from 'epicenter-libs';
await runAdapter.operation(runKey, 'step', [1]);
import { runAdapter } from 'epicenter-libs';
await runAdapter.operation(runKey, 'stepTo', ['end']);
import { runAdapter } from 'epicenter-libs';
await runAdapter.operation(runKey, 'reset');
Saving variables to the database
To configure which variables are saved to the database, update the model context file.
For configuration options, read the model context schema.