Hi everyone,
recently @Arun Kr posted this idea to add a utilization vs. time chart to the available chart types in FlexSim. I had previously build a relatively easy to set up Statistics Collector for use in our models. I have since cleaned up the design a bit and thought to post it here, since this seems to be a commonly desired feature.
utilization_vs_time_collector_24_0_fm.fsm
All necessary setup is done through labels of the collector. The first three are actually identical to labels found on the default Statistics Collector behind a state bar chart.
- Objects should point at a group that contains all objects the collector should track the utilization for.
- StateTable is a reference to the state table that will be used to determine which state counts as 'utilized'.
- StateProfile is the rank of the state profile that should be read on the linked objects (0 for default state profile).
- MeasureInterval is the time frame (in model units) over which the collector will take the average of the utilization.
- NumSubIntervals determines how often that measurement is actually taken. In the example image above (and the attached model) the collector measures the average utilization over the last 3600s 12 times within that interval of every 300s. Each meausurement still denotes the utilization over the complete "MeasureInterval".
The graph on the left takes a measurement every 5 minutes, the one on the right every 60 minutes. Each point on both graphs represents the average utilization over the previous hour from that time point in time.
- StoredTimeMap is used to allow the collector to correctly function past a warmup time, by storing the total utilized value of each object up to that point. This should no be manually changed. Since this last label has to be automatically reset, remember to save any changes made to the other labels by hitting "Apply".
The collector works by keeping an array of 'total utilized time' value for each object as row labels. Whenever a measurement is taken, the current value is added to the array and the oldest one is discarded. The difference between the newest and oldest value is used to calculate the average utilization over the measurement interval. The "NumSubIntervals" label essentially just controls how many entries are kept in that array.
To copy the collector into another model you can create a fresh collector in the target model. Then copy the node of this collector from the tree of the attached model and paste it over the node of the fresh collector.
I hope this can help to speed up the modeling process for some people (at least until a chart like this is hopefully implemented in FlexSim) or serve as inspiration for how one can use the Statistics Collector.
I might update the post with a user library version if I get to creating it (and if there is demand for it).
Best regards
Felix
Edit: Added user library with the collector as a dragable icon to the attached files.
Edit2: I noticed a bug while using the collector. Having the tracked objects enter states that are marked as "excluded" in the state table would lead to incorrect utilization values (possibly even below 0 or above 100%). Replaced the library with an updated version that fixes this.
Edit3: I fixed another bug that resulted in a wrong utilization value for the first measurement after the warmup time if the object spent time in an excluded state prior to the warmup.
This feature is super useful, and it'd be even better if it was just a built-in chart in the menu, instead of having to set it up ourselves. I always needed this chart for models I'm working on. I've got a couple of questions. First, how much would a stats collector like this slow down a medium to large model? Especially considering there are like 30-40 objects in the group and we're running the model for one month.
Also, does this stats collector work for floor storage objects or other types of storage objects? Basically, can it track how long items have been sitting on the floor storage over time?
Thanks!
As long as the collector is used 'reasonably' (not measuring utilization every couple seconds) the performance impact while the model is running should not be noticeable. I just ran a test by adding 40 processors to the example model. The State Gantt chart uses quite a lot more resources for example (because the state changes much more often, the impact per measurement is about the same).
You will experience a slowdown though if you watch the chart being drawn during the simulation run. But that is the case with any somewhat frequently updated line chart generally.
The collector uses the object's states to calculate the utilization (time spend in 'active' state vs total simulation time. Storage objects do have a state profile but don't usually use it. If you manually set their state to reflect certain statistics you could use the collector. To measure fill levels and/or staytimes there is already a large variety of charts available though.
@Arun Kr I did upvote idea yesterday.
@Felix Möhlmann How I can change the state of floor storage to "active" when there is a content on them? I've used Content vs Time and Stay Time but charts like the one below does not give me good insight on utilization if not processing the excel file.
I looked at the documenrtation which says: https://docs.flexsim.com/en/21.2/Reference/3DObjects/Warehousing/FloorStorage/FloorStorage.html
The Floor Storage does not implement any states. Use the content graph to get statistics.
It could be as simple as setting the state in the On Entry and On Exit triggers.
// On Entry current.setState(STATE_BUSY, 0);
// On Exit if(current.subnodes.length == 1)
{ current.setState(STATE_IDLE, 0); }
Though I still don't understand what purpose this would serve. The utilization is a binary state in this context. Something is either in use or not. With storage space the content/fill level is almost always more interesting since it shows you how much or margin there is left.
All the utilization vs time chart would show is that the storage is 'used' 100% of the time. Something that is also easily seen in the graph you attached.
Maybe ask this as a separate question and give some more details on what exactly you are trying to achieve?
Understood. The floor storages in my model serve as devices that process numerous items concurrently. My initial preference for floor storages was due to the enhanced visibility of items and the utilization of specific packing techniques on these storages.later i realized that these packing techniques could be done On Entry at the processors as well. I'll post a new question after I tried the method you mentioned above.
Thank you Felix. You just saved me a bunch of time on a project!
Hey Felix, thanks so much for this! Would you be able to share the model as an older 2023 version, please? (V23 or earlier)
Here's the model in version 23.0. I just tested the library and it seems to open without issues in that version.
Thank you so much, Felix! Much appreciated! The Box Plot is a good tool to capture the range when running a model for a long time, too.
The amount of time you gave me back is unreal. I have upvoted this; it really needs to be a part of Flexsim. Average Utilization doesn't tell you much in real life systems. Thanks again!
Hey Felix. If you wanted to take the measurements every 30min instead of every hour, would you simply change the 'MeasureInterval' label to 1800, or is it not that simple? Are there other changes needed to the collector?
Also, when the collector is created, is the 'StoredTimeMap' just a Number Label set to 0, or should that be something else?
The 'MeasureInterval' is the time over which the utilization is averaged and 'NumSubIntervals' is how often within this time the collector takes a measurement. So if you want to get the utilization over the last 30mins every 30mins, you would indeed just set 'MeasureInterval' to 1800 (if the model time unit is seconds) and 'NumSubIntervals' to 1.
'StoredTimeMap' should be an empty map and show up as "Map: {}" like in the screenshot.
Thanks, Felix!
Reason why I ask... I am utilizing this stats collector for AGV utilization. I have tried it with the MeasureInterval @ 3600 with NumSubInterval @ 12, and I have tried with the MeasureInterval @ 1800 with NumSubInterval @ 1. My line chart is giving me multiple values at each time interval, instead of giving me 1 value. See graph below. It doesn't seem to be calculating an average.... are there additional steps I need to take for AGVs or TaskExecutors?
Thanks, Felix. Is there any way to make it work for the group as a whole? Or this stats collector is not built for those situations?
You could of course edit the collector to average the utilization over the entire group. (Changing the row value to a single generic value, removing the "Object" column and changing the code in the On Row Adding trigger to iterate over all objects in the group).
But it's much easier and faster to just use a Calculated Table to average the values from Statistics Collector grouped by the time column. That way you also preserve the individual data per object, should you ever need it.
Thanks, Felix! Appreciate the help a ton!