Model Creation in Vensim
When you create a model in Vensim, you can use it with the Epicenter platform by:
- Creating and uploading your model file (.vmf), as well as any external data files, to the Model folder of your project.
- Optionally creating a model context file and uploading it to the Model folder of your project.
Then, when you create a user interface for your Vensim model on Epicenter, each user's interaction includes:
- Logging in and creating a run
- Setting initial values or constants
- Optionally, calling the
startGame
method to begin your simulation - Calling the
step
orstepTo
method to advance the Vensim model - Retrieving and updating variables, based on user decisions and the appropriate time or step.
- Index of available Vensim operations
- Index of available Vensim variables
Creating and Uploading your Model File
Primary Vensim Model File
Epicenter directly simulates Vensim models, using a special Vensim engine.
In order to use a Vensim model, it must be saved in the VMF binary format (file name ending in ".vmf"). Other formats (such as "mdl" or "vpm") do not work with Epicenter.
Because the Vensim models are directly simulated and not translated, fidelity and performance are high. All mathematical expressions and functions are simulated exactly as in the desktop Vensim software.
Model variables designated as "GAME" variables are available for viewing and updating through the Epicenter APIs when you create your project's user interface. (See more on retrieving and updating variables in your project's user interface.)
Model variables designated as "CONSTANT" or "LOOKUP" variables can only be changed at the start of the simulation run. See the section on setting initial values, below.
Use the Epicenter user interface to upload your model file (.vmf) to the Model folder within your project.
External Data Used in Your Model
If your model uses external resources such as a spreadsheet or CSV file, upload that file to the Model folder within your project as well.
- If you are using the current Epicenter v2 APIs, then the external data will automatically be available to your Vensim model. Uploading the external data to your project's Model folder is all you need to do.
- This is true for external data in
*.xls
,*.xlsx
,*.vdf
,*.txt
,*.tab
,*.cin
, and*.csv
file formats. - The Interface Builder uses the v2 APIs, so if you are working with that, you're all set.
- This is true for external data in
- If you are using the older Epicenter v1 APIs, then in addition to uploading the external data to your project's Model folder, you also need to:
- Include a
files
object (.cfg) ormapped_files
object (.ctx) in your context file, and - Include a
files
field when you create a run.
- Include a
For more information on working with external resources, see How To: Use External Data in Vensim. If you run into any problems, you can check the troubleshooting guide.
For more information on Epicenter API versions, see Version History.
Creating a Run
A "run" is a collection of end user interactions with the project and its model. Every time an end user wants to interact with a project, you as the project author need to create a new run.
If you are using the Interface Builder to create your interface, the name of your model file is detected automatically, and a run is created automatically when an end user visits this project page.
If you are using one of the Epicenter APIs, you'll need to create the run yourself.
For example, using the Run API Service (JavaScript), you might use:
var rs = new F.service.Run({
account: 'acme-simulations',
project: 'supply-chain-game',
token: 'eyJhbGciOiJSUzI1NiJ9'
});
rs.create('supply-chain-model.vmf');
Or if you're using the Run API (RESTful), you might use:
curl -X POST \
'https://api.forio.com/v2/run/acme-simulations/supply-chain-game' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"model": "supply-chain-model.vmf"}'
Setting Initial Values
Model variables that describe initial conditions are typically updated exactly once, before the simulation begins. (You can think of these updates as being required to occur in "step 0.") These model variables are typically designated as "CONSTANT" or "LOOKUP" variables within Vensim and can only be changed at the start of the simulation run.
Use one of the Epicenter APIs to set constants and/or initial values.
For example, using the Run API Service (JavaScript), you might use:
rs.load('runID').then(function()
{rs.save(
{variables:
{"initialConditionVariable": "initialValue"}
}
)}
);
Or if you're using the Run API (RESTful), you might use:
curl -X PATCH \
'https://api.forio.com/v2/run/acme-simulations/supply-chain-game/runID/variables' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"initialConditionVariable": "initialValue"}'
Notes:
For Vensim "LOOKUP" variables, the Epicenter format is an array. Each array element is itself an array with two elements: the x-y pairs from the original Vensim variable. For example:
- Original Vensim LOOKUP representation:
[(2000,0)-(2010,2)],(2000,1),(2005,.5),(2010,1)
- Epicenter representation:
[ [2000,1], [2005, .5], [2010, 1] ]
.
- Original Vensim LOOKUP representation:
Variable names are case sensitive, so make sure that the variable names in your API calls match their case with the variable names in your Vensim model.
Initializing the Model to Step 1
The Interface Builder and Epicenter APIs both allow you to manipulate a run using operations exposed by the model. For Vensim models, there are four available operations: startGame
, step
, stepTo
, and reset
.
To initialize the model to step 1 for a particular run, use the operation startGame
. This operation takes no arguments.
Using the separate startGame
operation is optional if you are using the Epicenter v2 APIs. (Because it is not required, it is not available in the Operation drop-down menus in when you are using the Interface Builder.)
For example, if you are using the Epicenter.js Run API Service (JavaScript), you might use:
rs.load('runID').then(function()
{ rs.do('startGame'); });
Or if you're using the Run API (RESTful), you might use:
curl -X POST \
'https://api.forio.com/v2/run/acme-simulations/supply-chain-game/runID/operations/startGame' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"arguments": []}'
Advancing the Model
The Interface Builder and Epicenter APIs both allow you to manipulate a run using operations exposed by the model. For Vensim models, there are four available operations: startGame
, step
, stepTo
, and reset
.
To advance the Vensim model for a particular run, use the step
or stepTo
operation.
- The
step
operation advances the run a specified number of Vensim time units. It has one optional argument, a floating point number for the steps (Vensim time units) to advance. The default value is1
. - The
stepTo
operation advances the run up to a particular Vensim time, or the end of the model. It has one argument, which can be either:- An integer: step the model to that time but not past.
- The string
"end"
: step the run to the end of the sim.
If you are using the Interface Builder to create your project's interface, you can select Step
under Add Operations for the Properties of a button. Optionally, you can select from the Parameters drop-down to choose how far to step (1 step, 10 steps, or to the end of the model). There is not an explicit stepTo
available from the Interface Builder.
If you are using one of the Epicenter APIs, for example, you could advance the model by three steps using the Epicenter.js Run API Service:
rs.load('runID').then(function()
{ rs.do('step', [3]); });
Or if you're using the Run API (RESTful), you might use:
curl -X POST \
'https://api.forio.com/v2/run/acme-simulations/supply-chain-game/runID/operations/step' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"arguments": [3]}'
Retrieving and Updating Variables
You can reference any Vensim variables from your project's user interface if they are designated as "GAME", "CONSTANT", or "LOOKUP" variables within Vensim.
You can update any of these types of Vensim variables before you start the simulation run. Once you have started the simulation, you can only update "GAME" variables. (If you're not sure about a particular variable, you can Introspect the run and check the access field for that variable: BEFORE
means you can only update the variable before the model is advanced; ALWAYS
means you can update the variable any time after the run is created.)
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, Vensim models are necessarily 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 1-based. Including the step is optional when you reference a variable. Leaving it off implies the current step. Only variables in the current step can be updated. The value from any step (including the current step) can be retrieved.
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.Variable names are case sensitive, so make sure that the variable names in your project's user interface match their case with the variable names in your Vensim model and in your model context file.
Variables that you want to save in the Epicenter backend database need to be noted in the model context file.
Scalars
To update or reference a scalar variable, use the variable name. Optionally, include the step in square brackets, [s]
. Only variables in the current step can be updated. The value from any step (including the current step) can be retrieved.
Unlike other modeling languages, Vensim models are necessarily 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, suppose you have the variable Budget
, which changes over time:
Budget | Step |
100 | 1 |
120 | 2 |
130 | 3 |
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 Budget for current step -->
<input data-f-bind="Budget"></input>
<!-- Budget for step 2: returns "120". can reference, but not update -->
<span data-f-bind="Budget[2]"></span>
You can list values of an array (that is, your scalar variable over all steps) using the data-f-foreach
attribute.
And if you are using the Run API, this looks like:
<!-- update Budget for current step -->
curl -X PATCH \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"Budget": 95}'
<!-- Budget for step 2: returns "120". can reference, but not update -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Budget[2]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
<!-- Budget for current step, using the value of the step (3): returns 130 -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Budget[3]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
<!-- Budget for current step, using the POINT_IN_TIME notation: returns 130 -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Budget.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-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Budget' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
[
100,
120,
130
]
Arrays
To update or reference an element of an array, use square brackets and strings to describe the index of the array: [indexName]
. Optionally, include the step as the second subscript: [indexName,s]
. Only variables in the current step can be updated. The value from any step (including the current step) can be retrieved.
For example, suppose in Vensim you have:
Sales, Apples | Sales, Oranges | Step |
100 | 200 | 1 |
120 | 220 | 2 |
130 | 230 | 3 |
140 | 240 | 4 |
If you are using Flow.js, this looks like:
<!-- sales of apples in current step: returns 140 -->
<span data-f-bind="Sales[apples]"></span>
<!-- set sales of apples and oranges sold in current step
(step 4), requires two different inputs -->
<input data-f-bind="Sales[apples][4]"></input>
<input data-f-bind="Sales[oranges][4]"></input>
You can list values of an array (that is, your variable over all steps) using the data-f-foreach
attribute.
And if you are using the Run API, this looks like:
<!-- sales of apples in step 3: returns 130 -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales[apples][3]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
<!-- set sales of apples and oranges sold in current step
(step 4), requires two different updates -->
curl -X PATCH \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables' \
--header 'Content-Type:application/json' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
--data '{"Sales[apples][4]": 150, "Sales[oranges][4]": 250}'
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-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
{
"apples": [
100,
120,
130,
140
],
"oranges": [
200,
220,
230,
240
]
}
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-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales.POINT_IN_TIME' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
{
"apples": 140,
"oranges": 240
}
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-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales.COLLAPSED_ARRAY' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
returns:
[
[
100, // "apples" dimension for the first step
200 // "oranges" dimension for the first step
],
[
120, // "apples" dimension for the second step
220 // "oranges" dimension for the second step
],
[
130, // etc.
230
],
[
140,
240
]
]
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.
Note that you cannot update variables which do not exist (including arrayed variables, for example Sales[pineapple]
if your only products are apples
and oranges
). In other words, you cannot create new variables this way; your variables must already be defined in your model.
Multidimensional Arrays
For multidimensional arrays, you must explicitly specify the additional dimensions, either by adding the specific dimension, or by using *
(wildcard) to indicate all dimensions.
For example, suppose in Vensim you have:
Sales, Apples, West | Sales, Apples, East | Step |
100 | 200 | 1 |
120 | 220 | 2 |
130 | 230 | 3 |
140 | 240 | 4 |
To look up all of the apple sales in the west region, you can use:
<!-- sales of apples in west region -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales[apples,west]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
And to look up all of the apple sales in all regions, you can use:
<!-- sales of apples in all regions -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales[apples,*]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
However, asking just for sales of apples will return an error:
<!-- asking for sales of apples without any region information is an error: returns 404 -->
curl -G \
'https://api.forio.com/v2/run/acme-simulations/sample-vensim-model/000001577c0c5359720faa8b0c4b32e182d9/variables/Sales[apples]' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9'
Determining the Current Time or Step
In some situations, you may know already the time or step for which you want to view or update variables. If you are not sure, there are a few ways to determine this:
For the current step, read from the
Step
variable. This variable is automatically included for you and always holds the current Vensim step. (It is a scalar value, not an array.)For example, using the Run API Service (JavaScript), you might use:
rs.load('runID', {include: 'Step'});
Or if you're using the Run API (RESTful), you might use:
curl -G \ 'https://api.forio.com/v2/run/acme-simulations/supply-chain-game/000001577c0c5359720faa8b0c4b32e182d9/variables/Step' \ --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
For additional time details if you are working with Epicenter v2 APIs, read from the
Time
,Start Time
,Final Time
, orTime Step
variables.The
Time
variable returns an array of the simulation times that you have stepped through so far, while the other variables return scalars. See the index, below for complete descriptions of each.For example, using the Run API Service (JavaScript), you might use:
rs.load('runID', {include: 'Start Time'});
Or if you're using the Run API (RESTful), you might use:
curl -G \ 'https://api.forio.com/v2/run/acme-simulations/supply-chain-game/000001577c0c5359720faa8b0c4b32e182d9/variables/Start Time' \ --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
For additional time details if you are working with Epicenter v1 APIs, request all of the time details with the
getTimeDetails
operation. (Important! This operation only works with the Epicenter v1 APIs.)This operation does not take any arguments.
For example, using the Run API Service (JavaScript), you might use:
rs.load('runID').then(function() { rs.do('getTimeDetails'); });
Or if you're using the Run API (RESTful), you might use:
curl -X POST \ 'https://api.forio.com/v1/run/acme-simulations/supply-chain-game/runID/operations/getTimeDetails' \ --header 'Content-Type:application/json' \ --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \ --data '{"arguments": []}'
This operation returns an object showing the value of the Vensim
TIME STEP
variable (timeStep
), the current Vensim time (time
), the current Vensim step (step
), and the start and end (final) times (startTime
,finalTime
) for the model:{ "name": "getTimeDetails", "arguments": [], "result": { "timeStep": 0.08333, "time": 2000, "finalTime": 2050, "startTime": 2000 "step": 1 } }
Index of Available Vensim Operations
getTimeDetails
- Arguments: none
- Result: Returns an object showing the value of the Vensim
TIME STEP
variable (timeStep
), the current Vensim time (time
), the current Vensim step (step
), and the start and end (final) times (startTime
,finalTime
) for the model. - Note! that this operation ONLY works with the Epicenter v1 APIs. (See more on the versions of the Epicenter APIs.)
- More info
reset
- Arguments: none
- Result: Returns a new run, that is, a new instantiation of your model for an end user to play with. (Remember that a run is a collection of interactions with a model.) For example, this is useful if your end user needs to "start over" to create a new scenario within your project.
- Note that this can ONLY be called from your project's user interface if you are using the Interface Builder or Flow.js. (Under the hood, this is not an operation as defined for the RESTful Run API. If you are building your project's user interface with the Epicenter RESTful APIs, you should just create a new run instead of calling
reset()
.)
startGame
- Arguments: none
- Result: Initialize the model to step 1 for a particular run.
- Note that this operation is optional if you are using the current version of the Epicenter APIs, v2. It is required if you are using the previous version of the Epicenter APIs. (See more on the version history.)
- More info
step
- Arguments: Optional, floating point number for steps (Vensim time units) to advance. If not provided,
1
is assumed. - Result: Advances the run the specified number of Vensim time units, rounded to the nearest multiple of Vensim
TIME STEP
. - More info
- Note that
step
is also the name of a Vensim model variable (current Vensim step), see above. Don't accidentally confuse looking up the current step and advancing the model!
- Arguments: Optional, floating point number for steps (Vensim time units) to advance. If not provided,
stepTo
Arguments:
Integer, the Vensim time unit to step to (but not past)
or
- String
"end"
, step the run to the end of the sim.
- Result: Advances the run up a particular Vensim time unit, or the end of the model.
- More info
Index of Available Vensim Variables
In addition to any variables in your Vensim model, the following variables are available for reference when you are running a Vensim model on Epicenter.
Final Time
, aliasFINAL TIME
: The end of your simulation.Time
: An array of the simulation times that you have stepped through so far.Time Step
, aliasTIME STEP
: The value of the VensimTIME STEP
variable.Start Time
, aliasINITIAL TIME
: The beginning of your simulation.Step
, aliasSTEP
: The current step.
For example, in a model in which we have stepped twice and then asked for all of these variables, using the Run API (RESTful):
curl -G \
'https://api.forio.com/v2/run/acme-simulations/supply-chain-game/000001577c0c5359720faa8b0c4b32e182d9/variables?include=Time,Start Time,Final Time,Time Step,Step' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiJ9' \
which returns:
{
"Start Time": 2015,
"Final Time": 2020,
"Time": [
2015,
2016,
2017
],
"Step": 3,
"Time Step": 1
}