Every incoming marker instantiates a new [.DocsSectionsImportantConcepts#SecEvents event]. During an event, one or more actions can be executed at one or more different timepoints. In the [.DocsSectionsBuildingExperiments#SecActions Actions table] is specified which actions are associated with each event and at which timepoints they must be executed. Different action types can be distinguished, namely [.DocsSectionsImportantConcepts#ModVars modifying user defined variables], [.DocsSectionsImportantConcepts#GetPut copying the content of global variables] in and out of the event structure or executing [.DocsSectionsBuildingExperiments#SecUserFun functions]. For every event, BrainStream executes the associated actions in a fixed order, based on their position in the Actions table and action type. This section describes the order in which actions are executed, together with some examples.
Order of actions based on position in the table
BrainStream handles tables from top to bottom and row by row. For example, according to the following table, first function fnc1, then fnc2, then fnc3 is executed.
If more than one action of the same type is specified within a row, the actions are executed in the order in which they appear within the row (i.e. from left to right). Another example table is shown below.
In this table, the functions are executed in the following order: fnc2, fncA, fnc4, fnc3, fnc1, fncB.
Order of actions based on action type
If more than one action type is specified within a row, the order in which the actions are executed also depends on their type.
1. Modifying variables
The content of [.DocsSectionsImportantConcepts#SecVariables global variables] can be modified by specifying expressions in the Actions table. Possible expressions are listed [.DocsSectionsImportantConcepts#ModVars here]. Modification expressions are always the first actions to be executed within a row.
The modification of one global variable can depend on the value of another global variable. If the variable that serves as input for another variable is modified in the same row of the table, this last modification is ignored. An example is shown in the table below:
Let's assume that Var1 had value 3 before marker mrk1 arrived. When marker mrk1 comes in, the value of Var1 is changed to 4. This most recent change of Var1 is not taken into account in the modification of variable Var2. Thus, the value of Var2 will be set to 3*2=6.
The reason for ignoring modifications specified in the same row is that the column order of user defined variables remains arbitrary.
2. Retrieving variable content (get, load)
After the content of the [.DocsSectionsImportantConcepts#SecVariables global variables] has been modified, their content can be copied into the [.DocsSectionsImportantConcepts#SecEvents event structure] by means of a 'get' statement in the table. Alternatively, the content of a variable may be loaded from disk by means of a 'load' statement. 'Get' and 'load' actions are performed after the modification of variables and before the execution of functions. For more information about the 'get' and 'load' statements, click [.DocsSectionsImportantConcepts#GetPut here].
3. Executing functions
When the content of all required [.DocsSectionsImportantConcepts#SecVariables global variables] has been copied into the event structure, functions are executed. This includes the execution of functions specified in the [.DocsSectionsBuildingExperiments#SecUserFun function] column as well as functions specified in the [.DocsSectionsBuildingExperiments#SecFeval feval] column.
If multiple functions are specified, they will be executed in the order in which they appear in the row. This also means that, within a row, functions in the function column will be executed before functions in the feval column.
4. Storing variable content (put, save)
The 'put' statement updates the modified content of user defined variables to the global variables, whereas the 'save' statement saves the content to disk. These actions are always the last ones to be executed during an event. This means that if subsequent rows of the table define actions for the same marker, the put action will be performed after these actions have been completed (see example below). For more information about the 'put' and 'save' statements, click [.DocsSectionsImportantConcepts#GetPut here].
|4||BS_END||EVENT||my_fnc3(Var2)||save||$self+2, get, save|
Row 1: When the BS_INIT marker arrives, first the value of Var1 will be set to 1. Subsequently, the content of Var2 will be loaded from disk. Finally, the bs_insert_marker function will be executed, inserting marker 'start_exp'.
Row 2: After the 'start_exp' marker, first the content of Var1 and Var2 will be modified. Var 1 will be set to 2 and Var2 will be set to 1*3=3 (as explained [.DocsSectionsTableHandling#ModVar above], the last modification of Var1 is ignored). After these variables have been modified, the new content of Var1 (i.e. 2) will be copied into the event structure as requested by the 'get' statement. The user defined function my_fnc1 will be executed, which takes the content of Var1 as input argument. Next, the [tic] function specified in the feval column starts a stopwatch. Although a put action is specified in this row, this will not be executed until all other actions belonging to this event, including the ones specified in the next row, are finished.
Row 3: Immediately after the actions specified in row 2, function my_fnc2 will be executed. Subsequently, the [toc] function will stop the stopwatch. Finally, the content of Var1 (which was modified by my_fnc1) will be updated to the global variables (put statement in previous row).
Row 4: At the BS_END marker, the content of Var2 will be modified to 3+2=5. After that, the new content will be copied into the event structure. Function my_fnc3 will be executed, which takes the value of Var2 (i.e. 5) as an input argument. Finally, the content of Var1 and Var2 will be saved to disk.