6.3 Understanding KSL Processes and Entities
Entities can experience many processes. Thus, there needs to be a mechanism to activate the processes and to cleanup after the processes have completed. The ProcessModel
class facilitates the modeling of entities experiencing processes. A ProcessModel
has inner classes (Entity,
EntityGenerator,
etc.) that can be used to describe entities and the processes that they experience.

Figure 6.5: Overview of the ProcessModel Class
As noted in Figure 6.5 a ProcessModel
can activate KSL processes, can start entity process sequences, can dispose of entities, and will perform some after replication cleanup. One of the activities that a process model must perform is to terminate any processes that are still suspended after the replication is completed. In addition, it ensures that no entity terminates its process while still having allocations to a resource. Thus, a ProcessModel
is needed to manage the entities and processes that it manages. This is why in the pharmacy code example, the pharmacy model is a subclass of ProcessModel.
class DriveThroughPharmacy(
parent: ModelElement,
numPharmacists: Int = 1,
ad: RandomIfc = ExponentialRV(1.0, 1),
sd: RandomIfc = ExponentialRV(0.5, 2),
name: String? = null
) : ProcessModel(parent, name)
This provides the modeler with access to the inner classes e.g. Entity
that are inherited by the subclass for use in process modeling.
The key inner class is Entity,
which has a function process()
that uses a builder to describe the entity’s process in the form of a coroutine. An entity can have many processes described that it may follow based on different modeling logic. A process model facilitates the running of a sequence of processes that are stored in an entity’s processSequence
property. An entity can experience only one process at a time. After completing the process, the entity will try to use its sequence to run the next process (if available). Individual processes can be activated for specific entities. But, again, an entity instance may only be activated to experience one process at a time, even if it has many defined processes. The entity experiences processes sequentially. An error will occur if you try to activate and run a process for a given entity instance if the entity is already executing a process . Note that this does not in anyway limit the creation and activation of different entity instances and their processes.
An Entity
instance is something that can experience processes and as such may wait in queues. Entity
is a subclass of QObject.
Thus, statistics can be automatically collected on entities if they experience waiting. The general approach to defining a process for an entity is to use the process()
function to define a process that a subclass of Entity can follow. Entity instances may use resources, signals, hold queues, etc. as shared mutable state.
Entities may follow a process sequence if defined. An entity can have many properties that define different processes that it might experience. The user can store the processes in data structures. In fact, there is a processSequence
property for this purpose that defines a list of processes that the entity will follow. However, the user is responsible for adding processes to the sequence. In addition, if you provide a name for the process when defining it via the process()
function, then the processes are stored in the entity instance’s processes
map, which can be accessed via the provided name.
The following code defines a process and assigns the function to the property pharmacyProcess.
This property is of type KSLProcess.
Because the isDefaultProcess
argument was supplied to the process()
function, the process is defined as the default process to activate by entity generators. Each process can also be provided a string name via an argument of the process()
function. The name of a process may also be useful in tracing and debugging process code.
private inner class Customer : Entity() {
val pharmacyProcess: KSLProcess = process(isDefaultProcess = true) {
...
}
KSLProcess
is an interface that provides a limited view of a KSL process instance. The interface allows the user to check the state of the process, get its identification (id, and name) and access the entity that is associated with the process. Underneath, the instance of a KSLProcess
is mapped onto a specially constructed Kotlin coroutine.
interface KSLProcess {
val id: Int
val name: String
val isCreated: Boolean
val isSuspended: Boolean
val isTerminated: Boolean
val isCompleted: Boolean
val isRunning: Boolean
val isActivated: Boolean
val currentStateName: String
val entity: ProcessModel.Entity
/**
* The simulation time that the process first started (activated) after being created.
* If the process was never started, this returns Double.NaN
*/
val processStartTime: Double
/**
* The simulation time that the process completed.
* If the process was never completed, this returns Double.NaN
*/
val processCompletionTime: Double
/**
* The elapsed time from start to completion.
*/
val processElapseTime: Double
get() = processCompletionTime - processStartTime
}
The process()
function is a special builder function related to a KSLProcessBuilder.
A KSLProcessBuilder
provides the functionality for describing a process. A process is an instance of a coroutine that can be suspended and resumed. The methods of the KSLProcessBuilder
are the suspending functions that are allowed within the process modeling paradigm of the KSL. The various suspending functions have an optional string name parameter to identify the name of the suspension point. While not required for basic modeling, identifying the suspension point can be useful for more advanced modeling involving the cancellation or interrupting of a process. A unique name can be used to determine which suspension point is suspending the process when the process has many suspension points. We will examine the functionality of a KSLProcessBuilder
later in this section.
First and foremost, process modeling starts with understanding and using instances of the Entity
class.

Figure 6.6: Defined Entity States
Figure 6.5 indicates that there is an inner class called EntityState
within an Entity. As seen in Figure 6.6, EntityState
serves as the base class for defining the legal states for an entity and the legal state transitions using the state pattern as show in Figure 6.7.
CreatedState
- The entity is placed into this state when it is created. From the created state, the entity can be scheduled to be active.Scheduled
- The scheduled state indicates that the entity is associated with an event that is pending to occur in the event calendar. The entity is scheduled to be active at some future time. The underlying process associated with the entity is suspended.Active
- This is the state that indicates that the entity is executing an underlying process. It is executing non-suspending code within its process. It is the active entity. From the active state, the entity can be suspended for a number of reasons, each mapped to various states.WaitingForResource
- This state indicates that the entity’s process is suspended because the entity is waiting for units of a resource.WaitingForSignal
- This state indicates that the entity’s process is suspended because the entity is waiting on an arbitrary signal to be sent.BlockedSending
- This state indicates that the entity’s process is suspended because the entity is trying to send an item via a shared blocking queue and there is not space for the item in the queue. Blocking queues can be used to communicate between processes.BlockedReceiving
- This state indicates that the entity’s process is suspended because the entity is trying to receive items from a blocking queue and there are no items to receive. This is the other end of the communication channel formed by a blocking queue.InHoldQueue
- This state indicates that the entity’s process is suspended because the entity is an arbitrary queue that holds entities until they are removed and re-activated.WaitForProcess
- An entity may activate another process. This state indicates that the entity’s process is suspended because the entity is waiting for the process to complete before proceeding.BlockedUntilCompletion
- An entity may activate another process that has blockages. This state indicates that the entity’s process is suspended because the entity is waiting for the blockage to complete.

Figure 6.7: Legal Entity State Transitions
The entity states are mapped onto the lower level coroutine via an internal inner class (ProcessCoroutine
). This class defines the legal states of the coroutine shown in Figure 6.8.

Figure 6.8: Defined Process States
Again, these states define the legal states of the underlying process coroutine. In general, users will not care about these internal details, but a basic understanding of what are legal transitions, shown in Figure 6.9 can be helpful. The following are the process coroutine states:
- Created - The process coroutine is placed in this state when it is instantiated.
- Running - The coroutine is running after it is started. This occurs when the entity activates the associated process. Processes are started by scheduling an event that invokes the coroutine code at the appropriate simulated time. The entity moves through its process and when the entity is between suspension points the process is considered to be in the running state.
- Suspended - The underlying process coroutine is suspended using Kotlin’s coroutine suspension functionality. Suspension is mapped to the various suspension states associated with an entity.
- Completed - The process coroutine has exited normally from the process routine or reached the end of the process routine. Once completed the coroutine is finished.
- Terminated - The process coroutine has exited abnormally via an error or exception or the user has directly terminated the process. Once terminated the coroutine is finished.
When a process coroutine exits normally the process coroutine is placed in the completed state. Then, the ProcessModel
checks if the entity has a next process to start. This check occurs via the determineNextProcess()
function of the entity. If the entity has been specified to use its process sequence via its useProcessSequence
property, then the process sequence will be used to determine the next process to activate. If the entity is not using its process sequence, then the entity will not automatically start the next process. The user can also override the determineNextProcess()
function and directly determine the next process to start. The default behavior is to not follow a process sequence such that no new process will be started (automatically).
If the entity is executing a process and the process is suspended, then the process routine may be terminated. This causes the currently suspended process to exit, essentially with an error condition. No further programming statements within the process coroutine will execute. The process ends (placed in the terminated state). All resources that the entity has allocated will be deallocated. If the entity was waiting in a queue, the entity is removed from the queue and no statistics are collected on its queueing. If the entity is experiencing a delay, then the event associated with the delay is cancelled. If the entity has additional processes in its process sequence they are not automatically executed. If the user requires specific behavior to occur for the entity after termination, then the user should override the Entity’s handleTerminatedProcess()
function to supply specific logic. Termination happens immediately, with no time delay.

Figure 6.9: Legal Process States Transitions
The following section will illustrate through some simple models some of the functionality enabled by KSLProcessBuilder.