Model Creation in SimLang
To create your model in SimLang, see:
If you already have a model in SimLang because of your work with Simulate, see:
Once you have a model in SimLang, you can use it with the Epicenter platform by:
- Creating and uploading your model code to the Model folder of your project
- Optionally, creating and uploading your model context file to the Model folder of your project
- Referencing variables from the UI
- Calling operations from the UI
After your model is uploaded, you'll want to:
- Create an interface for your project
Creating and Uploading your Model Code
Use the Epicenter user interface to upload your model code (.eqn file) to the Model folder within your project.
SimLang was originally developed for use with the previous version of the Forio platform, Simulate. You can bring your Simulate model code into Epicenter, but you'll need to recreate the user interface for your simulation. See more about migrating your model from Simulate to Epicenter and creating an interface for your project.
Referencing Variables from the UI
You can reference any SimLang decision or variable from your project's user interface. In the Interface Builder, enter the variable name under the Variable property of decisions, tables, or other components. In Flow.js, add the variable to an element on the page, for example using data-f-bind
.
Unlike some other modeling languages supported by Epicenter, SimLang models are time-based: they deal in discrete steps, and the model advances over time. For this reason, each variable is actually an array of values over steps.
Important Notes on Variables
Steps are 0-based. Including the step is optional when you reference a variable. Leaving it off implies the current step. Only decisions in the current step can be updated. Both decisions (
D
) and variables (V
) can be read. The value of the variable during any step (including the current step) can be retrieved. (See more on decisions and variables in SimLang.)To retrieve the value of a variable in the current time step, you can either include the current time step as an array index, or append
.POINT_IN_TIME
to the name of the variable when you look it up.To retrieve the value of an arrayed variable with the array collapsed for each step, append
.COLLAPSED_ARRAY
to the name of the variable when you look it up.SimLang decisions and variable names are not case-sensitive in Epicenter.
Scalars
To update or reference a scalar decision or variable, simply use the name. Optionally, include the step in square brackets, [s]
. Only decisions in the current step can be updated. The value of the variable during any step (including the current step) can be retrieved.
SimLang models are typically time-based: they deal in discrete steps, and the model advances over time. For this reason, each variable is actually an array of values over steps.
For example, if you have the decision Sales
it may initially be defined as:
D Sales = 100
Now suppose the end user changes it over time:
Sales | Step |
100 | 0 |
120 | 1 |
130 | 2 |
If you are using Flow.js, by default the value at the current step is selected. You can also specify a particular step. This looks like:
<!-- update Sales for current step -->
<input data-f-bind="Sales"></input>
<!-- Sales for step 1: returns "120". can reference, but not update -->
<span data-f-bind="Sales[1]"></span>
You can also list values of an array — in this case, your scalar variable arrayed over all steps — using the data-f-foreach
attribute. For example, if your model is currently in step 2, using:
<ul data-f-foreach="Sales">
<li></li>
</ul>
creates
<ul data-f-foreach="Sales">
<li>100</li>
<li>120</li>
<li>130</li>
</ul>
which displays
* 100
* 120
* 130
If you are using the Run API, you can also update Sales
for the current step, or get Sales
for a particular step. This looks like:
// update sales for the current step
curl -X PATCH \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"sales": 250}'
// retrieve sales for step 1: returns "120"
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/sales[1]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
// retrieve sales for the current step, using the POINT_IN_TIME notation: returns "130"
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/sales.POINT_IN_TIME' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
Using the Run API, you can also ask for the variable over all steps. For example:
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables?include=sales' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
{
"Sales": [
100,
120,
130
]
}
One-Dimensional Arrays
To update (patch) or reference an element of an array, use numeric indices with [n]
. Optionally, include the step as the second subscript: [n, s]
. Only decisions in the current step can be updated. The value of the variable from any step (including the current step) can be retrieved.
For example, suppose you have the arrayed decision Price
. It is defined initially as
D Price[3] = {100, 150, 175}
and to reference the second element (in the current step), you use
Price[2]
If you are using Flow.js, this looks like:
<!-- retrieve the 2nd element of the array, in the current step.
returns "150" -->
<span data-f-bind="Price[2]"></span>
<!-- update the 2nd element of the array, in the current step. -->
<input data-f-bind="Price[2]"></input>
Note that by default the Flow.js data-f-bind
attribute returns the final element of an array. You can use the data-f-foreach
attribute to loop over all elements if needed. See details.
<!-- displays final element of the array, in the current step: 175 -->
<span data-f-bind="Price"></span>
<!-- displays list with three items: 100, 150, and 175 -->
<ul data-f-foreach="Price">
<li></li>
</ul>
If you are using the Run API, this looks like:
// returns the 2nd element of the price array, in the current step: 150
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/price[2]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
// updates the 2nd element of the price array, in the current step
curl -X PATCH \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"price[2]": 167}'
Now suppose that as your model advances, the end user changes your Price
decision over time:
Price | Step |
{100, 150, 175} | 0 |
{200, 250, 275} | 1 |
{300, 350, 375} | 2 |
You can still use Flow.js or the Run API to reference a particular element of the array; by default, you'll retreive the array from the current step.
If you want a particular value from the a previous step, include the step as the second subscript:
<!-- returns 2nd array element from step 1: "250" -->
<span data-f-value="Price[2,1]"/>
And if you want the entire array over all time, request it without any subscripts:
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables?include=price' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns each element of Price
as an array over time.
{
"price": {
"1": [
100, // Price[1] at step 0
200, // Price[1] at step 1
300 // Price[1] at step 2
],
"2": [
150, // Price[2] at step 0
250, // etc.
350
],
"3": [
175,
275,
375
]
}
}
This format is easier to parse if you are looking for the values from a specific dimension of your array.
To retrieve the values in the current time step only, append .POINT_IN_TIME
to the name of the variable when you look it up:
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/price.POINT_IN_TIME' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
{
"1": 300,
"2": 350,
"3": 375
}
To retrieve the values of your arrayed variable with the array collapsed for each step, append .COLLAPSED_ARRAY
to the name of the variable when you look it up:
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/price.COLLAPSED_ARRAY' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
[
[
100, // "1" dimension for the first step
150, // "2" dimension for the first step
175 // "3" dimension for the first step
],
[
200, // "1" dimension for the second step
250, // "2" dimension for the second step
275 // "3" dimension for the second step
],
[
300, // etc.
350,
375
]
]
This format is easier to parse if you are looking for all values from a specific step of your model, and can be helpful for example if you are graphing the values over steps.
Enumerated Ranges in Arrays
You can use the same format when working with arrays that you have declared using enumerated ranges, using [n]
to describe the index of the array. Optionally, include the step as the second subscript: [n, s]
. Only decisions in the current step can be updated. The value of the variable from any step (including the current step) can be retrieved.
For example, if you have
R Products = Books,CDs,Games
D Cost[Products] = {100, 150, 175}
you use
Cost[Books]
to get the value from this decision array at the current step.
If you are using Flow.js, this looks like:
<!-- display or update value from current step -->
<span data-f-bind="Cost[Books]"></span>
<input data-f-bind="Cost[Books]"></input>
By default, Flow.js returns the value from the current step. Include the step as a second index if you want to show the value from a previous step:
<!-- displays value from step 0 -->
<span data-f-value="Cost[Books, 0]"></span>
If you are using the Run API, you'll need to include the step for retrieving (GET
). The update (PATCH
) assumes the current time step:
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/cost[books,0]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
curl -X PATCH \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"cost[books]": 45}'
If you do not include the step during a GET
request, you see all values over time. For example, if the end user has updated the cost of books over several steps,
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/cost[books]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
might return:
[100, 240, 357, 239]
Finally, if you do not include a subscript at all, you see the entire enumerated array, returned as a JSON object. For example, after two steps only,
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables?include=Cost' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
might return:
{
"Cost": {
"Books": [
100,
240
],
"Games": [
175,
189
],
"CDs": [
150,
153
]
}
}
Multidimensional Arrays
To update (patch) or reference a single element of a multidimensional array, use numeric indices, e.g. [n,m]
. As always, optionally include the step as the final subscript: [n,m,s]
. Only decisions in the current step can be updated. The value of the variable from any step (including the current step) can be retrieved.
For example, to reference the first item of the second element in
D SalesByRegion[5,2] = {
{100, 200},
{300, 400},
{500, 600},
{700, 800},
{900, 1000}
}
If you are using Flow.js and working with the current step, this looks like:
<!-- working with 2nd array element, 1st item: 300 -->
<span data-f-bind="SalesByRegion[2,1]"></span>
<input data-f-bind="SalesByRegion[2,1]"></input>
Note that by default the Flow.js data-f-bind
attribute returns the final element of an array. You can use the data-f-foreach
attribute to loop over all elements if needed. See details.
<!-- displays 2nd array element, final item: 400 -->
<span data-f-bind="SalesByRegion[2]"></span>
<!-- displays list with all items in 2nd array element: 300, 400 -->
<ul data-f-foreach="SalesByRegion[2]">
<li></li>
</ul>
If you are using the Run API to retrieve the SalesByRegion
for a particular step, this looks like:
// retrieve the 2nd array element, 1st item, from step 0: 300
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d8a13/variables/SalesByRegion[2,1,0]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
You can also read all dimensions or particular dimensions of multidimensional arrays. Once your model has advanced (stepped), each innermost element is itself an array over time:
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d8a13/variables/SalesByRegion[2]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns
{
"1": [
300
],
"2": [
400
]
}
if your model is still in step 0, but
{
"1": [
300,
300,
300
],
"2": [
400,
400,
400
]
}
for example, if your model has advanced through steps 0, 1 and 2.
Similarly, after three steps
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-simlang-model/0000015b8d8ee74f391285f851ac6a2d899a/variables/SalesByRegion' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
might return
{
"1": {
"1": [ 100, 101, 102 ], //1st region, 1st item sales over steps 0, 1, 2
"2": [ 200, 201, 202 ] //1st region, 2nd item sales over steps 0, 1, 2
},
"2": {
"1": [ 300, 301, 302 ], //2nd region, 1st item sales over steps 0, 1, 2
"2": [ 400, 401, 402 ] //2nd region, 2nd item sales etc.
},
"3": {
"1": [ 500, 501, 502 ],
"2": [ 600, 601, 602 ]
},
"4": {
"1": [ 700, 701, 702 ],
"2": [ 800, 801, 802 ]
},
"5": {
"1": [ 900, 901, 902 ],
"2": [ 1000, 1001, 1002 ]
}
}
Calling Operations from the UI
You can call any operation (function) from your project's user interface as well. For example, in Flow.js, add the operation to an element on the page, or call it when the run is created. (Read more about the options for creating your interface.)
The operations available from your project's user interface are primarily different ways to advance the model. They are listed in the SimLang Language Overview. (Specific SimLang functions that you use in the definition of your decisions and variables cannot be called from your project's user interface; you can only reference the decisions or variables.)