The Statistics Collector
Overview and Key Concepts
The Statistics Collector is a table that records data from the model. The Statistics Collector listens to events in the model and writes data in its table cells when those events occur. You can configure which events the Statistics Collector listens to, as well as the data that it writes with those events. You can use the table data in a chart, or you can export the data from FlexSim.
The Statistics Collector can be accessed from the Toolbox. A model can have any number of Statistics Collectors.
General Behavior
The Statistics Collector is a table, similar to a Global Table; it is a table that is accessible in the toolbox, and you can write custom values in that table. However, Global Tables are generally used to store input data, or data that the model uses to determine its behavior. Statistics Collectors, on the other hand, record data about the model's behavior as it runs. You can think of Global Tables as input tables and Statistics Collectors as output tables.
The Statistics Collector is an observer of the model. When you use a Statistics Collector, you specify what events you want to observe, and what to record when those events happen. Then, as the model runs, the Statistics Collector will listen for the specified events to happen, and update the table when those events occur.
The following subsections describe the basic logic of the Statistics Collector. The last subsection (Visualizing the Statistics Collector as a Flowchart) shows two flowcharts. One shows the logic that executes if an observed event fires. The other shows the logic that executes if the table is accessed. It may be helpful to read these subsections, view the flowcharts, and then read these subsections again.
Adding Rows to the Table
In order to add rows to the table, you must specify events to listen to. For example, the following Statistics Collector listens to two events:
Whenever an event in this list occurs, the Statistics Collector
creates an entity called data
. This entity
has information about the event such as which object
fired the event, and the name of the event. You can also
assign labels to this entity. In the previous example,
the event parameters item and port
are assigned to data
as label values.
Each event also specifies a row value.
The Statistics Collector maps each row value to a row.
If there is not yet a row for the given row value, then the
Statistics Collector will add a row for that value.
In the previous example, the event uses
data.item
as the row value. This means that
whenever an item enters the Queue, the Statistics Collector
will make sure there is a row in the table for that item.
In addition, the row value given by the event is assigned
to the data
entity's rowValue
property.
In summary, when and event occurs, it produces a row value. If the Statistics Collector doesn't have a row for that row value, it will add a row to its table. The new row is then tied to the row value. In this example, the row value is a flowitem. However, the row value can be any Variant value. More information can be found in the Row Values section.
Adding Columns to the Table
In order to add columns to the table, you specify them directly in the Statistics Collector, using the Columns tab. For example, the following Statistics Collector would have two columns:
When you add a column, you need to specify a name. You also need to specify what value to write in the column when the column is updated. The Row Add Value specifies the value that the column should write when a new row is added. When an event produces a row value that doesn't have a row, the Statistics Collector will make a new row, and fill all columns with their Row Add Value.
In this example, the Row Add Value for the Type column is set to
data.rowValue.Type
. Recall that in this example,
data.rowValue
is a flowitem. So when the row
is added, the Type column will record the value of the Type
label on the flowitem for that row.
Updating Values in the Table
You can update values in the table in three ways. The first way is by defining a Row Add Value. This allows you to write a value when the Statistics Collector adds a row, as discussed in the previous section.
The second way is by connecting an event to one or more columns. When the event occurs, the Statistics Collector will assert a row for the event's row value. Then, the Statistics Collector will visit each of the connected columns on that row, and write the value specified in the Event Value field. In the following example, the "Processor1 - On Exit" event is connected to the Staytime column:
In this example, when the "Processor1 - On Exit" event occurs, the
Statistics Collector will assert a row for the row value, writing
the Row Add Value for each
column if a row is added. Then, on that same row,
the Statistics Collector will write the
Event Value for each connected column.
In this example, the event is connected to the Staytime column,
which is set to data.Staytime
.
The third way you can update a column is by changing the Update Timing of the column. There are two options for the Update timing:
- When the row is added and/or updated by events
- When the value is accessed
Sorting Rows
By default, when the Statistics Collector adds a new row, the row will be added at the end of the table. However, you can specify a custom sort order. To do this, you can add one or more Sort Values:
The previous example demonstrates that you can access the row value during the sort step. However, there are some important rules about Sort Values:
- Sort Values shouldn't change during the row's lifetime. The sort values are cached, and compared to the other cached values for the other rows.
- Sort Values cannot depend on column values. None of the columns have been written at the point the row is sorted, so they cannot use column values. In some cases, a Sort Value might have the same value as a Row Add Value.
Finishing a Row
When an event occurs, you can optionally specify that the event should finish the row for its row value, after the event has added or updated that row. If an event finishes a row, then two things happen to that row:
- All columns that update when accessed are updated
- The row value is disconnected from the row
Visualizing the Statistics Collector as a Flowchart
Because the Statistics Collector runs logic in response to events, it can be helpful to see that logic as a flowchart. The following flowchart is made with Process Flow activities, where each type of activity has as specific meaning:
- - Something happens to start update logic
- - Code or values you have specified
- - A decision checked by the Statistics Collector
- - An action taken by the Statistics Collector
- - Indicates (using a dashed arrow) that some steps happen for each thing
- - The end of the update process.
data
entity as a token moving through the flowchart.
If one of the Statistics Collector's events occurs, this flow approximates the logic:
If something accesses the Statistics Collector's table, this flow approximates the logic:
Row Values
This section describes the different kinds of row values that can be returned from an event's Row Values property, and how they might be used in a Statistics Collector.
Number, Text, and Node Values
The most common kind of row values are number values, text values, or node values. The Statistics Collector will make one row per unique text, number, or node value.
Arrays of Values
If an event's Row Values
field returns an array, the Statistics Collector
will extract every element of that array as an
individual row value.
In this way, you can have a single event add and/or
update multiple rows. For example,
[1, 2, 3]
will assert one row
for the values 1, 2, and 3.
However, and array of a single
value will only update one row;
1 == [1]
for row values.
Array Row Values
In some cases, it can take several values to describe a row value. For example, you may want to create a table that has one row per Fixed Resource per SKU (a label on items flowing through the Fixed Resource). In this case, the row value is a composite value of Fixed Resource and SKU.
You can accomplish this using an array. However, since the Statistics Collector uses an array to mean multiple row values, you must put the array inside an array. For example, if an event returns a row value like this:
[[current, data.item.SKU]]
then the Statistics Collector will take each element of the outer
array as a row value. This leaves the inner array as the row value.
The Statistics Collector will make one row per unique array,
where every element of the array must match.
You can access elements of that array in later fields with
array syntax: data.rowValue[1]
Null Values
You can return a null value as the row value from an event. This will always add a new row to the Statistics Collector, and that row will always be finished after the event.
Enumerated Values
To understand enumerated values, you need to first
recall how the Statistics Collector uses the
data
entity. Whenever one of the events
in the Statistics Collector occurs, the
data
entity is created. In addition,
the Statistics Collector sets the following properties
on the data
entity:
data.group
- If a single event listens to all objects in a group, this property will be set to that group. Otherwise, it is empty.data.eventNode
- This value is set to the node that fired the event. This value is also known ascurrent
.data.processFlowInstance
- If an event is listening to an activity in an instanced flow, this property is set to the instance caused the event. This property is also known asinstance
.
All events set these three properties. You can return the following from any event as the row value:
data.enumerate()
This method returns a special value. When the Statistics Collector sees this special value as the row value, it asserts one row per unique combination of
[data.group, current, instance]
It also sets
data.rowValue
to current
.
There is a difference between using current
as the row value and using data.enumerate()
.
While both cases set data.rowValue
to be the same value in the end, rows made with
data.enumerate()
also remember the
instance and group used to make the row.
This difference is important when using columns that
update when accessed and need the instance
value.
For example, suppose you want to see the average content of
a Delay activity in an instanced flow for each instance.
When you access the table, there is no event, and so
normal rows cannot access current
,
instance
, or data.group
.
However, since enumerated rows remember these values,
you can use them in code like the following:
getstat(data.rowValue, "Content", STAT_CURRENT, instance)
Events
For information on events, see the Event Listening page.
The Statistics Collector has the following events:
On Row Added
This event fires when a new row is added to the Statistics Collector, after the row is sorted, and after the Row Add Values have been set.
It has the following parameters:
Event Parameter | Type | Explanation |
---|---|---|
Row Number | int | The row number of the new row |
Row Value | Variant | The value associated with the new row |
On Row Updated
This event fires when one of the events that the Statistics Collector listens to updates one or more columns on a given row.
It has the following parameters:
Event Parameter | Type | Explanation |
---|---|---|
Row Number | int | The row number of the new row |
Row Value | Variant | The value associated with the new row |
Columns Updated | Array | An array containing one value per column. If the nth column was updated, then the nth value of the array will be 1. Otherwise, the value will be zero. |
Previous Values | Array | An array containing one value per column. If the nth column was updated, then the nth value of the array will contain the value that was in the table before the update. Otherwise, the value is undefined, and should not be used. |
On Row Finished
This event fires when an event finishes a row. Any columns updated by the event will be updated before this event fires.
It has the following parameters:
Event Parameter | Type | Explanation |
---|---|---|
Row Number | int | The row number of the finished row |
Row Value | Variant | The value associated with the finished row |
On Row Adding
This event fires when the Statistics Collector needs to add
a new row, but has not actually added the row yet. The trigger
associated with this event is often used to initialize
row labels on the data
entity.
This event has no parameters.
On Row Updating
This event fires when the Statistics Collector is about
to update any columns connected to an event. The trigger
associated with this event is often used to update
row labels on the data
entity.
It has the following parameters:
Event Parameter | Type | Explanation |
---|---|---|
Event Added Row | int | If the event that is currently causing an update also added the row, this value is true. |
Event Finishes Row | int | If the event that is currently causing an update will also finish the row, this value is true. |
Properties
The Statistics Collector has three tabs with various properties. The properties in these tabs will be explained in more detail in next sections.
Events Tab
The Events Tab has the following properties:
On the left of the Events Tab is the Event List. You can use the Add button or Sampler button to add events to this list. You can use the Duplicate button to dupliate the selected event. You can use the Remove button to remove the selected event. You can use the Up and Down buttons to reorder the events in the list.
Every event allows you to specify the following properties:
- Name - The name of the current event.
- Additional Labels - This list
allows you to add extra labels to the
data
entity as part of this event.
The the following subsections describe the different kinds of events that you can listen to or create with the Statistics Collector, and the properties of each kind of event.
Standard Events
The example below shows an example of this kind of event:
The Statistics Collector can listen to the events of any 3D Object or Process Flow Activity. For example, you could listen to the On Entry of a Processor, or the On Content Change of a Queue. If you listen to a Process Flow Activity in an instanced flow, the Statistics Collector will listen to that activity for all instances attached to the flow.
When you listen to one of these kinds of events,
you will have the option of assigning the event
Parameters
as labels on the data
entity.
This kind of event also has a Condition property. After the Parameters are assigned, the Statistics Collector will evaluate the Condition. If the condition value is false, then the event will not proceed any further in the process, and will not update the table.
This kind of event also allows you to specify
Additional Labels
on the data
entity. These labels
are assigned after the Condition is evaluated.
Group Events
The example below shows an example of this kind of event:
If you need to listen to many objects of the same type, you can listen to a Group of objects. The Statistics Collector will listen to all objects in the group.
As with Standard Events, this object allows you to assign event Parameters, define a Condition, and specify Additional Labels.
Tracked Variable Events
The example below shows an example of this kind of event:
If you listen to a Tracked Variable, or if you listen to an object event with the word "Change" in it, then you are listening to a Tracked Variable event.
When you listen to a Tracked Variable Event, you can specify a Change Rule. The Change Rule is like a Condition; if the change that happened doesn't match the Change Rule, then the event won't update the table.
Depending on which Change Rule you use, you may also need to specify a Change Value. This is a value related to the Change Rule. If the Change Rule has the word "Value" in its name, then the Change Value is is used.
In addition to the Change Rule, you can specify an addition Condition, as well as Additional Parameters.
Timer Events
The example below shows an example of this kind of event:
The Statistics Collector can create a Timer event and listen to that, rather than listening to events in the model. There are two main ways to use a timer event. The first way is to create a timer event that does not repeat, and fires when the model begins. This kind of timer event usually creates all the rows the table is expected to have. The second way to use a timer event is with a repeating schedule. This allows you to update or gather data at regular intervals.
To use a Timer event, you first specify the First Time value. This is a duration in model units. The timer will not begin firing until this time. You can also choose to fire this event when the model is reset, by returning a value that is less than 0.
Next, you can specify whether the timer event is Repeating. If it is repeating, you will also need to specify the Repeat Interval. This is a duration in model units. The timer will repeat every Repeat Interval after the First Time.
You can optionally define a custom Tick Pattern. Most users do not need this option. You can use the tick pattern to fire the timer event multiple times. You can do this by returning an array of values from the Tick Pattern property. For each value in the array, the Statistics Collector will execute the timer event that many model units since the First Time or since the last Repeat Interval occurred.
This event also allows you to assign
Additional Labels to the
data
entity.
Enumerate Events
The example below shows an example of this kind of event:
The Enumerate Event, like the Timer Event, is an event that the Statistics Collector creates for itself, rather than listening to some other object in the model. This kind of event fires when the model is reset.
To use this event, you can specify a list of
Objects
. These objects can
be 3D Objects, Groups, Process Flow Activities,
TrackedVariables, or any other treenode value.
This event also allows you to
assign Additional Labels
to the data
entity.
This event does not allow you to specify your own
Row Values.
Instead, the Enumerate event creates row values
for all objects in the
Objects list.
If the object is a Group, then the Statistics Collector
will make a row value for each object in the group.
If the object is an Activity in an instanced Process Flow,
the Statistics Collector will make one row value for
each instance of the activity. All row values are
created using the
data.enumerate()
method. For more information,
see the
Enumerated Values section.
By Requirement Events
The example below shows an example of this kind of event:
This kind of event is almost identical to a Standard Event, but instead of specifying a specific object or group to listen to, you can specify a Requirement. When the Statistics Collector is creating its listeners, it will search through the entire model. It will pass each object into the Requirement property, and listen to those objects that return a true value. In this particular example, the Statistics Collector is listening to the OnExit of all Processor objects.
The Event Sampler next to the Event property allows you to sample an object like the objects you expect the requirement to find.
As with Standard Events, this object allows you to assign event Parameters, define a Condition, and specify Additional Labels.
Transient Events
The example below shows an example of this kind of event:
Most events allow you to listen to something that is present when the model is reset. Transient events allow you to listen to objects that are created later, as part of the model run. For example, you might want to listen to TrackedVariable label changes on a token. Or you might want to listen to a flowitem's OnEntering event, which fires whenever the flowitem moves to new objects. Neither of these objects exist when the model is reset.
It can be helpful to contrast Transient Events with the other kinds of events. When all other kinds of event fire, they expose a Row Value. When this kind of event fires, it exposes a Transient object. In the previous example, the Transient object is a flowitem.
To use a Transient event, you also need to configure the event you want to listen to on the Transient object. You can use the Edit transient object event... button to open a popup, like the one shown here:
This popup allows you to edit the Event, Parameters and Condition of the event for the Transient object. You must use the Event Sampler to sample an event from an object like the transient object you expect to listen to.
Transient events are more complicated than other event types because they really listen to two events: the event where the Transient object is identified, and the event fired later by the Transient object. Here are some tips about how Transient events work:
- A Transient event does not directly update the table. It attaches a listener to an event on the Transient object. When that event fires, the table will be updated.
- The Condition property on the Transient event determines whether the event will attach a listener to the Transient object. The Condition property on the Transient object event determines whether the Transient object's event will update the table.
- The Transient event has event Parameters. If you assign
those parameters to labels on the
data
entity, those label values will be available when the Transient object event fires later.
Columns Tab
The Columns Tab allows you to add columns to the Statistics Collector. The Columns Tab has the following properties:
Column List
The Column list allows you to add, duplicate, remove, and reorder columns, using the , , , and buttons. You can select a column in the list to edit the properties of that column.
Name
The Name property sets the name of the column, as it will appear in the table. Each name should be unique.
Row Add Value
The Row Add Value property specifies the value to write when a row is added to the table.
Event Value
The Event Value property specifies the value to write when an event connected to this column occurs. If no events are connected to this column, you don't need to specify this value.
Value
The Value property is only available if the column is set to update when the value is accessed.
Set Values
If you add a Column Set, rather than a single column,
then you can specify the Set Values
property. This property should return an Array of name/value
pairs. For each name/value pair, the Statistics Collector
will add a column with that name. In addition, the value
will be available through data.colValue
.
For example, if you have a group of Queue objects, you could make one column per Queue with the following code:
/**Custom Code*/
StatisticsCollector collector = ownerobject(c);
Array queues = Group("Queues").toFlatArray();
Array result;
for (int i = 1; i <= queues.length; i++) {
result.push([queues[i].name, queues[i]]);
}
return result;
Note that the name of each column is set to the name of the queue,
and that the value of each column is the queue. This
means that
data.colValue
will be the Queue corresponding to the column.
Update Timing
The Update Timing option allows you to set whether the column is updated by events or by accessing the table. This option is described in the Updating Values section.
Storage Type
The Storage Type of a column determines what type of value can be recorded in that column, and how much memory that value will require. The following list describes each option:
- Double - Can store decimal numbers, with about 15 digits of precision. Requires 8 bytes per row.
- Integer - Can store integer values between about -2 billion and 2 billion. Requires 4 bytes per row.
- String - Can store text values. Requires 4 bytes per row, plus enough memory to store each unique text value in the table.
- Float - Can store decmimal numbers, with about 7 digits of precision. Requires 4 bytes per row.
- Binary - Can store number values of 1 or 0. Requires 4 bytes per 32 fields per row.
Display Format
If a column stores a number value (not a text value), then you can specify a Display Format. The display format you choose depends on the kinds of value stored in the column. There are four possible options:
- Raw - Displays the number as it is stored in the table.
- Object - Assumes the number is the ID of an object (present on reset), obtained using the StatisticsCollector.getID() method. This format will show the path to the object with the given ID.
- Date / Time - Assumes the number is a DateTime value. This format will show the date and time represented by the number, formatted according to your windows settings.
- Percent - Assumes the number
is a percentage. This format multiplies the value by 100 and
and adds a
%
symbol.
Index Type
Use this box to specify the index type of the value. If you specify an option other than None, then an index will be added to the column, or to all columns of the Column Set. An index can greatly improve query performance. For more information, see the SQL Queries topic.
Event/Column Connections
You can use this area to connect events to columns. This area shows the list of all events. You can select an event in the list to connect columns to it.
There are two ways to connect an event to a column. The first way is By direct links. If you choose this option, you can check the box next to each column you want this event to update. This is the most common way to connect events and columns.
The second way to connect events and columns is
By column requirement.
To use this way, you specify a code callback.
This callback is called for each column in the Statistics Collector.
The data
entity is available, with the following
properties set:
data.colNum
data.colName
data.colValue
The Row Options Tab
The Row Options tab has the following properties:
Row Sorting
The Row Sorting area allows you to specify a list of Sort Values. As rows are added to the Statistics Collector, they will be sorted by the first Sort Value, then by the second Sort Value, and so on. For each Sort Value, you can specify whether the value is ordered Ascending (A-Z) or Descending (Z-A).
Reuse Finished Rows
If you are not sorting rows, you can optionally choose to reuse finished rows. This means that when the Statistics Collector adds a row, it will first check if there is a finished row. If so, the row value will be assigned to that row instead of to a new row.
This option is generally only used where another Statistics Collector will listen to this Statistics Collector. By reusing the rows, this intermediate collector can minimize memory usage.
Keep values and labels for finished rows
This property applies when a row is finished. When this box is cleared, the Statistics Collector will forget the row value and destroy and labels associated with that row. If this box is checked, however, the Statistics Collector will simply disconnect the row value and the labels from the current row, rather than discarding them.
On Warmup
The On Warmup property specifies the actions the Statistics Collector will take at the model's Warmup Time. There are five possible options:
- Remove all rows - This option removes all rows from the Statistics Collector.
- Reset to initial values - This option goes through all unfinished rows and resets the columns to their Row Add value.
- Remove finished rows - This option removes all finished rows from the table.
- Remove finished rows and reset to initial values - This option removes all finished rows from the table. All remaining rows are set to their Row Add values.
- Do nothing - This option does nothing when the warmup time occurs.
The Triggers Tab
The Triggers tab allows you to specify logic for each of the Statistics Collector's Triggers. This tab is identical to the Triggers tab of other objects in FlexSim. For more information, see the Triggers Tab topic.
The Labels Tab
The Labels tab allows you to add labels to the Statistics Collector object. It is identical to the Labels tab of other FlexSim objects. For more information, see the Labels Tab topic.
The General Tab
The General tab has the following properties:
Shared Condition
This property specifies a condition for all events. This property is evaluated immediately when an event occurs. If the condition returns a 0, or any other false value, then the event won't update the table.
Process Flow Instance
This property only applies if one or more of the events for this Statistics Collector involve Process Flow Activities in object process flows. By default, this option specifies that the Statistics Collector should listen to all instances of that activity. In order to listen to fewer instances, you can use the sampler to set this value to a single object, or to a Group of objects. The Statistics Collector will only listen to the instance objects specified by this property. The remove button will reset this property to the default of All Instances.
Object Format Depth
This property applies to columns that use the Object format. The Object format displays a path to each object, and this property controls the maximum number of names that can appear in that path. If this property is 0, then the full path will be shown. If it is 1, then only the name of the object will be shown. If this property is 2, then the parent's name and the object's name will be shown as a partial path. As the value increases, the path will include nodes higher in the tree.
Store data on hard drive
If this box is checked, then this Statistics Collector will store its table data on the hard drive, in an internal file. Memory (RAM) use for the data table will be limited to 5 MB.
View Table
Click this button to open a view of the data table for this Statistics Collector.
View Row Values
Click this button to open a table-based view. The table in this view shows the row value for each row of the Statistics Collector. If the row was enumerated, then this table will also show the group and instance associated with the row. Active rows show
Export Table
You can use this button to save a CSV file of this Statistics Collector's data table.
Connected Dashboard Charts
This list shows all the dashboard charts that are drawing data from this Statistics Collector. If no charts require this collector, the list will be empty.
Properties
Click this button to open the Properties window of the selected chart in the Connected Dashboard Charts list.