Simulation (KiSim)
Deprecated since 0.14
This article is deprecated. The described features are no longer available in current releases.
Simulation of Models in KIELER
Overview
After a model has been created, it is reasonable to test if the model does what is expected. This can be achieved by simulating the model. The simulation must
- Receive inputs for the next tick
- Execute a tick
- Send generated outputs
Thus the simulation can be seen as a black box, which receives a state for the model, somehow computes a reaction, and communicates its new state to the outside. In KIELER the communication for receiving and sending the state of the model is done using JSON. When starting the executable file of a simulation in KIELER, the JSON communication is done on stdin and stdout of the running process.
Within KIELER a single state of a simulation is represented as a Data Pool. A data pool can have multiple models. Each model can have multiple variables. Thus a representation of a complete run of a simulation can be implemented as list of data pools.
Executables for simulation are created using the incremental project builder that is part of the project management. The typical steps to create an executable for simulation are:
- Compiling a model using the KIELER compiler
- Generating the simulation wrapper code for the model using template processing
- Compiling the resulting code using, e.g., gcc.
For more insight of the simulation generation, please take a look at the Project Management.
Using the Simulation
Besides the explicit configuration of a simulation using a kisim file, it is possible to start simulations directly on models, executables or trace files. This will start a pre-defined configuration depending on the selected files. The following table shows which files can be used to start a simulation and what simulation configuration is created for it.
Selection | Example Selection | Macro Tick Configuration of Simulation |
---|---|---|
1 executable | Sim_ModelA.exe | Performs a single tick and updates the pool with the received data from the process |
2 executables | Sim_ModelA.exe, Sim_ModelB.exe | Starts two executable data handlers with bidirectional redirection of inputs/outputs between the models. So the performed steps are: Execute tick of A, redirect A→B, execute tick of B, redirect B → A |
1 kisim file | ComplexSimulation.kisim | Uses the explicit configuration from the file |
1 executable, 1 trace file | Sim_ModelA.exe, TraceOfModelA.eso | The trace will first set inputs for the model that are read from the trace file. Then the tick is performed. Afterwards the generated outputs are compared to the outputs of the trace file and events are fired in case of a mismatch. |
1 simin file | process_output.simin | The simin file must contain a JSON object for some model. The data pool of the simulation is then updated with its contents. |
1 simout file | simulation_output.simout | A model of the simulation is written as JSON object to the simout file. |
Playing the Simulation
One can step through the simulation tick after tick. Furthermore it is possible to let the simulation step automatically. This is the play mode, in which a macro tick is performed after a given time, which can be defined in the data pool view (e.g. to perform a tick every 200ms).
Stepping Back in the Simulation
When clicking the Step Back button, the values of a former tick are set in the data pool view as user values, which will be assigned to the model before the next tick is executed. Thus it is possible to revert the simulation to a previous state if all variables that define this state are recorded in the data pool.
When stepping back and forth in the simulation history, the position in the history is shown next to the current tick count in the Data Pool View. For example, when the simulation is after tick 5 and one steps two ticks back in the simulation history, this will be indicated as the tick #5 (-2). If a tick is performed now using the old state, the values of tick 5 - 2 = 3 are applied and the new outputs are computed so that the simulation is now after tick #4.
The Data Pool View
The current data pool can be seen in the Data Pool View (Window > Show View > Other > KIELER Simulation > Data Pool View).
In the view, the variable values can be modified by the user via clicking the column User Value. If a user value is specified for a variable, the corresponding row is highlighted and marked with an asterisk ( * ) . The value is applied to the variable and send to the model before the next tick is performed.
When using traces in the simulation, a trace mismatch of a variable will be highlighted in the data pool view. A tooltip on the Current Value column shows details about the mismatch. The trace mismatch is kept between ticks. To clear a mismatch, use the menu of the view and select Clear Trace Mismatches from the view's menu.
When the data pool view is selected, stepping through the simulation can be done using the RIGHT arrow on the keyboard, which is often more useful than clicking the corresponding button in the toolbar. Furthermore the SPACE key will play/pause the simulation and with CTRL+LEFT (respectively CTRL+RIGHT) one can step back (step forward) in the simulation history.
Data Handlers
A simulation consists of a list of data handlers. These perform actions on the data pool. When the actions of all data handlers for a simulation have been executed, then this is a single full macro tick. In contrast performing only a single action on one data handler is called a sub tick and typically not necessary when using the simulation. However stepping through the data handler actions one by one can be useful to see the effect of each action on the data pool.
Which handlers are available are explained in the following.
Executable
There is a data handler for the simulation of executables. This data handler will send the inputs of the corresponding model in the simulation as JSON object to stdin of the process. Afterwards the tick is computed by the process. Finally the data pool in the current simulation is updated with the JSON object received from stdout of the running process.
Normal executables and executable jar files can be used simply by providing the path to the file. For other file types, e.g., a python script, the shell command to start the process has to be specified explicitly.
Attribute | Domain | Example | Description |
---|---|---|---|
executable | String, absolute workspace path or project relative path | /MyProject/kieler-gen/sim/bin/Sim_MyModel.exe | The path to the executable |
command | String, the shell command that is used to start the process | python -i "${executable_path}" | The shell command to start the executable |
Redirect
Multiple models may interact with each other as some can have inputs that are generated as outputs of other models. To implement this behaviour in the simulation, the redirect data handler has been created. It sets the inputs of a model to the outputs of some other model in the data pool. Thus the outputs of a some model A can be used as inputs of some model B.
Per default inputs and outputs are matched by name. However it is also possible to provide an explicit mapping of which output should be mapped to which input variable.
Attribute | Domain | Example | Description |
---|---|---|---|
from | String, name of a model in the simulation | Sim_ModelA.exe | The name of the model of which the outputs are read |
to | String, name of a model in the simulation | Sim_ModelB.exe | The name of the model of which the inputs are set |
mapping | Map, The key is an output variable and the value is an input variable | configure redirect A_to_B { | Defines which output variables should be mapped to which input variables |
Trace
A trace data handler can read a trace file. The inputs of a model can be set to corresponding inputs from the trace and outputs of a model can be compared with corresponding outputs in the trace. Therefore the trace data handler has the methods write (inputs), check (outputs), loadNextTick (to go to the next tick in the trace).
If the outputs of the trace do not match the outputs of the current simulation, an event is fired and the data pool view will display a trace mismatch.
Thus the typical simulation setup to use a trace data handler for a model A is:
- Set the input of the model to the inputs from the trace (write)
- Perform the tick of the model A
- Compare the outputs of the trace and the model A (check)
- Go to the next tick in the trace (loadNextTick)
Attribute | Domain | Example | Description |
---|---|---|---|
file | String, absolute workspace path or project relative path | MyTrace.eso | The trace file to be used |
modelName | String, name of a model in the simulation | Sim_ModelA.exe MyModelA | The model in the simulation for which the trace is for |
traceNumber | Integer | 0 | In case there are multiple traces in the eso file, determines which trace should be used. |
tickNumber | Integer | 0 | The tick of which the input is set. This can be used to skip some ticks of the trace. |
checkInterface | Boolean | true | Determines if the interface of the trace and model should be compared. |
Simulation Input Files
The simulation can communicate with executables via stdin and stdout. To use this, the executable has to be started from within KIELER.
To get information about a model that is running outside of KIELER, simulation input files can be used. A simin file contains a single JSON object with the state of a model that can be used to feed the simulation with data. Thus any program that can write a JSON object to a file can interact with the simulation.
In combination with redirects, a simin file can be used to set the inputs of a model with data that is produced from another application.
Simulation input files can also be used to feed the simulation with data to be visualized via the simulation visualization.
Attribute | Domain | Example | Description |
---|---|---|---|
file | String, absolute file system path or | /home/myuser/process_output.simin | The target file |
modelName | String, name of a model | MyModel | Name of the model in the simulation that the data in the simin file is for. |
Simulation Outputs Files
This data handler writes the output of the model in the simulation to the specified file.
Attribute | Domain | Example | Description |
---|---|---|---|
file | String, absolute file system path or | myFolder/myFile.simout | The target file |
modelName | String, name of a model | MyModel | Name of the model in the simulation that will be written as JSON object to the simout file |
Variable Setter
This data handler is only used for easier debugging and setting up simulations for different test runs. It sets the variables in the data pool to constant values, typically once for the simulation in the initialization part of a kisim file.
Attribute | Domain | Example | Description |
---|---|---|---|
variables | Map, The key is the variable name, the value is the value for this variable | configure setter S { | Sets the variables in to the given values. This way different setters can be defined for different simulation runs or manual testing. |
KiSim
Which data handlers are used and which actions are performed on them for each macro tick can be configured using a DSL, namely KiSim.
A kisim file contains two main parts:
- Configuration of data handlers
- Actions to be performed on the data handlers for each a macro tick
Besides these, an optional initialization part can be used to perform actions on data handlers once at startup.
Examples
The following shows examples of kisim files.
Configuration to simulate a single executable:
executable: kielger-gen/sim/bin/Sim_Test
}
execution {
write sim Test
}
Configuration for two executables with redirection between both:
executable: kielger-gen/sim/bin/Sim_Test
}
configure sim B {
executable: kielger-gen/sim/bin/Sim_Test2
}
configure redirect A_to_B{
from: A
to: B
}
configure redirect B_to_A{
from: B
to: A
}
execution {
write sim A
write redirect A_to_B
write sim B
write redirect B_to_A
}
Using a trace for a model:
executable: kielger-gen/sim/bin/Sim_Test
}
configure trace A {
file: MyTrace.eso
modelName: A
}
execution {
write trace A // Set inputs of model to values from trace
write sim A // Perform tick of model
read trace A // Compare outputs of model with values from trace
}
Feeding inputs of a model from a simin file:
executable: kielger-gen/sim/bin/Sim_Test
}
configure simin SimInput {
file: process_output.simin
}
configure redirect SimInput_to_A{
from: SimInput
to: A
}
execution {
write simin SimIn
write redirect SimInput_to_A
write sim A
}
Sets the variables for manual testing:
executable: kieler-gen/sim/bin/Sim_Test.exe
}
configure setter S {
variables {
x: 100
y: 100
}
}
initialization {
write setter S
}
execution {
write sim A
}
Implementation Details
The following are details about the implementation of the simulation and the JSON format that is used to communicate the variables in the models.
As said above the simulation is seen as black box which takes inputs on stdin, computes a reaction, and sends outputs stdout. Thus an executable simulation is a normal program that communicates in a specific JSON format and can also be used from command line.
The JSON Format
The JSON format is designed to communicate the state of a simulation. In KIELER such a state is saved as a single data pool. This means the JSON format for the communication with running simulations is also the JSON format for data pools.
It mainly consists of a list of models and a map of models. The models consist mainly of a map of their variables. The most important field of a variable is their value.
"VAR0":{"value": "VAR0_VALUE"}, "VAR1":{"value":"VAR1_VALUE"}, ...
}
"MODEL_NAME1" : {
"VAR0":{"value": "VAR0_VALUE"}, "VAR1":{"value":"VAR1_VALUE"}, ...
}
...
"actionIndex" : "ACTION_INDEX_AFTER_WHICH_THE_DATA_POOL_WAS_CREATED"
}
Besides these core informations, an additional field "actionIndex" can be set for the data pool. In the simulation the actions of data handlers are executed to create a macro tick. Therefore the action index takes the task of a program counter. It determines the next action to be executed. Thus in the JSON format the field "actionIndex" can be set to store when the data pool was created in the simulation.
There are also additional fields for variables than their value. However these only need to be communicated once after the initialization of the model and are explained in the table below.
Field Name | Example Values | Description | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
type | int bool pure float double string | The type of the variable in the source model. Because this information is lost in general in the compilation (for instance a bool is compiled to a char in C code), the simulation can communicate the intended variable type in the source model. | ||||||||||||||||||
interface | 0 1 2 3 4 5 6 | Bitmask, that determines how the variable is used in the source model's interface (e.g. input, output, internal, other).
Note that internal is intended for variables that are neither input nor output but still part of the source model, in contrast to variables that are created in the compilation (e.g. register flags). |
Python Example
The following shows a tiny python script, that will write a Data Pool containing an output variable x to stdout.
x = 0
while True:
json = """{"x":{"value":""" + str(x) + ""","interface":2}}"""
print(json) # Send output to simulation
raw_input("") # Wait for input from simulation
x = x + 1
This script can be executed from within KIELER to start a simulation because it uses the JSON communication on stdin and stdout. Note however that the input coming from the simulation is not handled in the script. An example kisim configuration to start such a scipt is given below.
executable: prog.py
command: "python -i ${executable_path}"
}
execution {
write sim A
}