sitemap.xml llms.txt
Skip to main content

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.

Savings account model example
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.

OperationArgumentsDescription
step()Optional: number of time unitsAdvances 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 unitsMoves the simulation backward. Defaults to 1 time unit.
reset()NoneCreates a new run, discarding the current one.
clear()NoneResets the current run to its initial step without creating a new run.
recalculate([...])Array of variable/decision namesRecalculates the listed elements from their equations and "unfreezes" variables.

Use the operation() function of the Run adapter to call operations from your application:

Advance the model one step
import { runAdapter } from 'epicenter-libs';

await runAdapter.operation(runKey, 'step', [1]);
Step to the end of the simulation
import { runAdapter } from 'epicenter-libs';

await runAdapter.operation(runKey, 'stepTo', ['end']);
Recalculate specific variables
import { runAdapter } from 'epicenter-libs';

await runAdapter.operation(runKey, 'recalculate', [['Interest Rate', 'Yearly Deposits']]);
Note

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.

VariableDescription
TimeArray of simulation times stepped through so far
StepCurrent step number (0-based)
Start TimeValue of M StartTime
Final TimeValue of M EndTime
Time StepValue 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_TIME to retrieve the current step's value as a scalar rather than an array.
  • Append .COLLAPSED_ARRAY to 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].

Model definition
D Sales = 100
Retrieve Sales at the current step
import { runAdapter } from 'epicenter-libs';

const sales = await runAdapter.getVariable(runKey, 'Sales.POINT_IN_TIME');
Retrieve Sales over all steps
import { runAdapter } from 'epicenter-libs';

const salesHistory = await runAdapter.getVariable(runKey, 'Sales');
// returns [100, 120, 130]
Retrieve Sales from step 1
import { runAdapter } from 'epicenter-libs';

const salesStep1 = await runAdapter.getVariable(runKey, 'Sales[1]');
Update Sales for the current step
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].

Model definition
D Price[3] = {100, 150, 175}
Retrieve the 2nd element at the current step
import { runAdapter } from 'epicenter-libs';

const price2 = await runAdapter.getVariable(runKey, 'Price[2]');
// returns 150
Retrieve the 2nd element from step 1
import { runAdapter } from 'epicenter-libs';

const price2step1 = await runAdapter.getVariable(runKey, 'Price[2,1]');
Retrieve all elements over all steps
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] }
Retrieve all elements at the current step (POINT_IN_TIME)
import { runAdapter } from 'epicenter-libs';

const priceNow = await runAdapter.getVariable(runKey, 'Price.POINT_IN_TIME');
// returns { "1": 300, "2": 350, "3": 375 }
Retrieve all elements organized by step (COLLAPSED_ARRAY)
import { runAdapter } from 'epicenter-libs';

const priceByStep = await runAdapter.getVariable(runKey, 'Price.COLLAPSED_ARRAY');
// returns [[100, 150, 175], [200, 250, 275], [300, 350, 375]]
Update the 2nd element at the current step
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].

Model definition
R Products = Books, CDs, Games
D Cost[Products] = {100, 150, 175}
Retrieve the Books value at the current step
import { runAdapter } from 'epicenter-libs';

const booksCost = await runAdapter.getVariable(runKey, 'Cost[Books]');
Retrieve the Books value from step 0
import { runAdapter } from 'epicenter-libs';

const booksCostStep0 = await runAdapter.getVariable(runKey, 'Cost[Books,0]');
Retrieve the full Cost array over all steps
import { runAdapter } from 'epicenter-libs';

const costHistory = await runAdapter.getVariable(runKey, 'Cost');
// returns { "Books": [100, 240], "CDs": [150, 153], "Games": [175, 189] }
Update the Books cost at the current step
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].

Model definition
D SalesByRegion[5, 2] = {
{100, 200},
{300, 400},
{500, 600},
{700, 800},
{900, 1000}
}
Retrieve 2nd region, 1st item at the current step
import { runAdapter } from 'epicenter-libs';

const val = await runAdapter.getVariable(runKey, 'SalesByRegion[2,1]');
// returns 300
Retrieve 2nd region, 1st item from step 0
import { runAdapter } from 'epicenter-libs';

const valStep0 = await runAdapter.getVariable(runKey, 'SalesByRegion[2,1,0]');
Retrieve all values for the 2nd region over all steps
import { runAdapter } from 'epicenter-libs';

const region2 = await runAdapter.getVariable(runKey, 'SalesByRegion[2]');
// returns { "1": [300, 301, 302], "2": [400, 401, 402] }
Retrieve the full SalesByRegion array over all steps
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.

Advance the model one step
import { runAdapter } from 'epicenter-libs';

await runAdapter.operation(runKey, 'step', [1]);
Step to the end of the simulation
import { runAdapter } from 'epicenter-libs';

await runAdapter.operation(runKey, 'stepTo', ['end']);
Reset to a new run
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.

Learn more

For configuration options, read the model context schema.