Lists are a powerful tool that can have many applications in FlexSim. At the most basic level, a List is just that: a list of values. Each value in a list may be either a number, a string, or a reference to an object in the simulation model. Lists also harness the expressive power of SQL for searching, filtering and prioritizing the values on the List. Entries in a List can have user-defined fields. These fields essentially make the List into a dynamic database table. The List can then be filtered and prioritized using SQL queries, as if you were querying a standard database table.
Topics
Why Use Lists?
There are many applications for Lists in FlexSim. A primary reason for using them is to separate the operations of search, filter and prioritization away from the physical layout, connections, etc. of a model. Take for example the problem of Fixed Resource routing/pulling. In some scenarios,simply connecting objects together and implementing port-based send-to and/or pull strategies works quite well. The following image shows a simple one-to-many routing operation.
This scenario is pretty straight forward. You send to a downstream station based on some basic rules.
However, some situations don't lend themselves as easily to simple routing. For example, in many job shop operations, the routing becomes a many-to-many problem. This can make using port connections more difficult. The number of needed port connections grows quadratically with the number of processing stations. Proper port ranking becomes an issue. Also, since search order in a pull operation is primarily by port and secondarily by the items in the upstream queues, prioritization is difficult, especially when handling priority ties. The following image demonstrates a much more complex routing problem.
Fixed Resource routing is just one example among many where using the structure of a model as the back-bone for searching can sometimes be more difficulty than help. It could also apply to Task Executer dispatching. Often Task Executers are grouped together by a connection to their Dispatcher, or "team leader." As such, a given Task Executer usually only has one object that you dispatch Task Sequences through. However, in real life scenarios, the set of valid Task Executers to whom you want to dispatch a task might not be properly represented using a strict separation into teams. One task could potentially be performed by multiple teams, or perhaps a single member of a team might be able to perform one set of tasks while another cannot. Task Executers might each have a skill set, and/or pay grade that may not be exactly correlated with the team that the Task Executer is assigned to. The lines of team vs capability can become very blurry. In these scenarios, using the Dispatcher team groupings for dispatching logic can be difficult and error prone.
Enter Lists
Using Lists can make these complex problems much simpler. For example, in the Fixed Resource routing problem, if when an item is finished at one station, you just put that item onto a global list of "items ready to go to their next station," then when a station becomes ready to pull its next item, it can just query that list and grab the best item it finds. It can use SQL to easily filter and prioritize the item that it wants. For the Task Executer dispatching problem, if all Task Executers in a model were to put themselves onto a global list of "Available Task Executers" when they become available to take up new work, then when an object has a Task Sequence that needs to be done, it can query the list to find the best Task Executer to dispatch the Task Sequence to. Filtering and prioritizing becomes a simple expression in an SQL query.
Concepts and Terminology
When talking about Lists, we use several important terms, as follows:
- Value - A value in a List is the primary value associated with a given entry. As mentioned previously, the value can either be a number, a string, an object, or node reference.
- Entry - An entry represents the entire record that is placed on or removed from the list. An entry contains its primary value as well as all of the required field values. Note that the entry is not the same as the value in that, in some scenarios you may have in a List multiple entries with the same value. If you were to think of a list like a database table, an entry essentially represents the row (or entry) of the table.
- Field - A field designates a value to be stored with each entry. This is additional data associated with the entry's value, and can be used for filtering and prioritizing the list via SQL queries. In database table terms, this would be the column (or field) in the database table.
- Field Value A field value is the specific value associated with a given field for an entry. Field values are similar, but not exactly the same as THE value of an entry, defined above. While both field values and primary values can be used interchangeably in querying Lists, the primary value of the entry is special in that it is the value that is retrieved as part of a pull request. On the other hand, field values are only used in querying the list in a pull request. Note that in some cases we may use the terms field and field value interchangeably.
The following diagram shows example entries in a list. The first entry has a value of /Queue3/Box1 (a reference to a box in a Queue), with fieldvalues for the box's itemType, age, distance and queueSize.
- Push - The verb push is used for adding something to a list.
- Pull - The verb pull is used for removing something from a list.
You might ask why we don't just call push and pull operations add and remove. We name them differently because the pull operation represents much more than just the removal of a value. A pull may include a search of the list based on filtering criteria and/or a prioritization rule. Also, a pull operation, if it does not immediately find a value to remove, will create a back order on the list. Once a matching value is then pushed onto the list, the back order will be fulfilled and the value will be immediately removed. Additionally, the pull operation includes a return value, namely the value that was pulled from the list. So a pull operation involves much more than just the removal of a value from the list. Hence we use the specialized terms push and pull to describe these operations.
- Query - When you pull something from a list, you can optionally include a query to filter or prioritize what you want pulled from the list. This is the where the expressive power of SQL can be used. For example, using the previous list diagram, let's say you were to pull from the list using the query:
WHERE itemType < 4 ORDER BY distance ASC
This would tell the pull request to only pull boxes whose itemType is less than 4 (WHERE itemType < 4), and then to find among those filtered boxes the box with the smallest distance (ORDER BY distance in ASCending order). In this case, the value /Queue3/Box7 would be pulled from the list. - Puller - Puller designates the thing that is pulling from the list in a pull operation. Usually the field values that are used in a pull request retrieve data associated only with the primary value (value-only fields), things such as labels on the pushed value. However, when a pull request is made, you can optionally include a puller object or value in the pull request. Some field values may be dependent on who or what the puller is. For example, refer back to the distance field in the previous image. This field was created as a puller-dependent field. It represents the distance from the value (/Queue3/Box1) to some puller object that is included in a pull request.
- Back Order - When a pull request is not completely fulfilled, i.e. the things you want to pull have not yet been pushed to the list, then by default a back order will be created for the list. The back order stores needed data associated with the pull request, such as the puller and the pull query. When entries are subsequently pushed onto the list, pending back orders will be processed to see if those pushed entries fulfill the back orders. Once fulfilled, back orders will be removed from the back order queue.
- Partition - Lists also have the feature of being able to be separated into "partitions." This essentially turns the List into multiple separate lists of values, or partitions. Each partition is uniquely identified by its partition ID.
- Partition ID - Each partition of a List has a partition ID associated with it. This value is what uniquely distinguishes a partition from other partitions. When you push or pull from a List, you can define the partition ID to push/pull from, and the List push/pull logic will only reference entries and back orders that are in the partition with that partition ID. The partition ID can be a number, a string, or a reference to an object or node in the tree. Partitions are dynamic in that, if you push a value onto a partition that does not yet exist, the partition will be created automatically.
Lists are Logical Constructs
In using lists, it's important to remember that they are purely logical constructs. For example, you may have a queue object in your model push an item onto a list. This does not put the item physically onto the list. The 3D item object remains in the queue. Instead, a reference, or pointer, to that item is added to the list. The logical nature of lists is in fact one of their advantages, in that you can separate the problem of search and prioritization from the physical structure of the model. In other words, you can have items physically located in one or more areas/objects in the model, while logically searching those items through a central mechanism, namely by putting references to those items (or "pushing the items") onto the list.
List Types
When you add Global Lists to a model, you add specific types of lists. Some types include:
- Item List - A list of flowitems. Items are pushed onto the list, and Fixed Resources usually pull from it.
- Fixed Resource List - A list of Fixed Resources. Fixed Resources are pushed onto the list, and flowitems usually pull from it.
- Task Sequence List - A list of Task Sequences. Task Sequences are pushed onto the list, and Task Executers usually pull from it.
- Task Executer List - A list of Task Executers. Task Executers are pushed onto the list, and Task Sequences usually pull from it.
List Types Aren't THAT Critical
While using the different types of Lists properly can make model building easier, it's important to note that the delineation of list types is more semantic than functional. At its core, a List is just a List. The user interface for adding fields, etc., will be customized based on the list's type, however, there is nothing to stop you from pushing a Fixed Resource onto an Item List, or to have a flowitem (as opposed to a Fixed Resource) pull itself or another item from an Item List. I say this not to encourage you to put Fixed Resources onto Item Lists (I certainly do not advise that, especially if field values depend on it being a flowitem), but just to point out that, fundamentally, a List is a List is a List.
When to Use Which Type
The choice of which List type to use in which situation is essentially up to you. If you are doing Fixed Resource routing, you should either use an Item List or a Fixed Resource List, but usually not both. When you use an Item List, items are pushed onto the List and Fixed Resources choose which items they want to process next by pulling them from the List. On the other hand, when you use a Fixed Resource List, Fixed Resources push themselves onto the list, while the items choose the Fixed Resources to be sent to by pulling them from the list. The main difference is in who is doing the "querying" or pulling. Since the SQL query is used when you pull from the list, the puller is the one who gets to filter and prioritize the entries on the List easiest.
However, when a pull request is made, the puller and its data can be referenced as part of the query (like in the distance example mentioned above). If you decide to use an Item List, for example, then when a Fixed Resource pulls from the List, the query can access information both on the items in the List as well as on the Fixed Resource itself, the puller. And the same rule applies if you were to use a Fixed Resource List, with flowitems pulling from the List. Thus the query can be a way of dynamically matching puller to value, instead of only getting data about the values in the List. What all of this means is that, for the most part, an Item List can have full functional parity with a Fixed Resource List, and a Task Sequence List can have full functional parity with a Task Executer List. So, in the end, which type of List you decide to use is really a decision of intuitive feel. Use the type that makes most sense.
Global Lists vs. Local Lists
When using lists with standard 3D objects in a model, you will usually use global lists. These are lists that you add, remove, and edit through the Toolbox. However, if you use the Process Flow module in building your model, Process Flows can contain lists that are local to the Process Flow. Any lists that are only needed locally within the Process Flow can use internal lists, whereas lists that coordinate functionality between different Process Flows, or between a Process Flow and standard 3D object functionality, would use global lists.