COMP 2100 Project 3: Queuing System Simulation

Fall 2015

PHASE 5 : Integrating all the Parts

Due: in lab, Thursday 19 November 2015
20 points

PHASE 5 : Integrating all the Parts

A complex project like this needs to be developed in phases. In the fifth phase, you will finally combine all the classes of the discrete event simulation model into a coherent whole.

Review of What You Have

So far you have developed and tested:
  1. The Event interface, the AbstractEvent class, and the ArrivalEvent, DepartureEvent, SimulationReportEvent, and SimulationEndEvent classes from Phase 1.
  2. The WaitingLine class to model customers waiting in a queue, from Phase 2.
  3. The Server class to model services for which customers contend in the simulation model, from Phase 3.
  4. The Customer class is provided.
  5. The RandomNormal and RandomExponential classes from Phase 4.
  6. The Statistic and WeightedStatistic classes from earlier projects.

What Remains to be Done

Only a few additional tasks need to be completed to integrate all the pieces into a lean mean simulatin' machine!

Simulation class: instance variables (provided)

Instance variables have been provided for the Simulation class, listed at the beginning of the class definition. I have initialized them in the constructor. The following implementation notes are for your reference only:

Simulation class: the run() method (provided)

Event-oriented simulation models require software components to model not only the entities of the system but also the mechanism to manage the events of the simulation. Here is the mechanism we will use.

Any simulation model requires a clock to record the passage of time. The Simulation class includes an int variable called clock that is initialized to time 0 (zero). This is discrete event simulation so the clock is discrete, not continuous. Thus we use an int variable. The clock itself does not have units (seconds, minutes, etc); those are determined by the system being simulated. For this project, we will use minutes as the unit of time.

From the perspective of the clock, events occur instantaneously at some known point in the future. We will assume that events occur one at a time at a predetermined future time. Such events can be managed using a data structure called a Future Events Queue (FEQ). This is a queue-based list of events ordered by their scheduled time. The event at the head of the queue will be the next to occur. It is modeled using a PriorityQueue<Event>

There are four kinds of events in the FEQ: arrivals, departures, simulation reports, and the designated simulation-end event. You have defined classes to model all of these. Each class has a predetermined priority that determines object placement in the FEQ in case two events are scheduled for the same simulation time.

There must be an algorithm to carry out the actions of the mechanism at simulation time. This is called the Events Loop because of its repeated operations. You will flesh out the Events Loop and initial scheduling in the partially-completed run() method. Here is a pseudo-code description of run().


Pseudo-code run() method including initial scheduling and event loop algorithm
Schedule simulation end event 
Schedule simulation report event
Schedule first arrival event
While (the FEQ is not empty)  {
	remove the first event from the FEQ
	update the clock to that event's time
	process the event
}

Notice that if the FEQ becomes empty, the event loop terminates and the simulation is over. However if the event loop reaches a SimulationEndEvent, the simulation will end even if the FEQ is not empty.

How are events generated and placed into the FEQ? Great question!

As you can see from the pseudo-code, the simulation end and report events are scheduled before entering the loop. These events happen at known future times and can be scheduled all at once if desired. But what about arrivals and departures? The pseudo-code shows the scheduling of only one arrival and no departures!

Here's how it works: Before entering the Event Loop, the mechanism creates the first Arrival event and places it into the FEQ. This is called "priming the pump." Once in the loop, the "process the event" step includes creating another event and adding it to the FEQ. You will see details below, but in essence when an Arrival event is processed it creates the next Arrival (and a Departure if the server is not busy) and when a Departure event is processed it creates the next Departure (assuming the waiting line is not empty).

Note: When you inspect the code, you'll notice the event loop includes a tracing statement. This will be helpful in debugging. To enable tracing, just set the instance variable trace to true in the constructor As each event is removed from the FEQ, its event type and time will be displayed.

Simulation class: Event Scheduling

Once the decision is made to schedule an event, the actual scheduling is performed by the scheduleArrival(), scheduleDeparture(), scheduleSimulationReport(), scheduleSimulationReportSequence() and scheduleSimulationEnd() methods in the Simulation class. The scheduleSimulationReportSequence() method is provided. It is used to schedule all simulation reports at once by scheduling each of them in a loop.

The four event schedulers are straightforward methods for you to write. Each of them follows the same simple algorithm:

  1. Determine at what future clock time the event will occur
  2. Create the event, giving it the future clock time
  3. Add the event to the FEQ
The following implementation notes apply to Step 1.
  1. For scheduling an arrival, use interarrivalRNG, the provided RandomExponential instance variable, to determine how long until the next arrival.
  2. For scheduling a departure, use serviceRNG, the provided RandomNormal instance variable, to determine how long until service is completed.
  3. Both random number generators produce "how long until," which means the generated value is relative to the current clock time. But scheduleArrival() and scheduleDeparture() require an absolute clock time so the randomly-generated value must be added to the current time.
  4. The simulation clock can only move forward. As long as you specify non-negative values for all the run arguments this will not be an issue.
  5. Simulation report and simulation end events will occur at fixed times and thus do not require random number generators. The time is provided as a parameter.

Your Task: Fill in the scheduleArrival(), scheduleDeparture(), scheduleSimulationReport(), and scheduleSimulationEnd() methods. (4 points)

Event classes: The process() Methods

The last pieces of the puzzle involve develping the process() methods for the four concrete event classes: ArrivalEvent, DepartureEvent, SimulationReportEvent and SimulationEndEvent.

These methods will require access to certain Simulation components:

Processing an Arrival

Pseudo-code Algorithm for Processing an Arrival Event
Schedule the next arrival
Create a customer
Customer requests to use the Server
If successful then
   Schedule a departure
else
   Customer enters the waiting line

Processing a Departure

Pseudo-code Algorithm for Processing an Departure Event
Release customer from the server
If waiting line is not empty
   Remove customer from waiting line
   Customer requests to use the Server
   If successful then
      Schedule a departure
   else
      Internal error - should not happen

Processing a Simulation Report

Pseudo-code Algorithm for Processing a Simulation Report
Report current simulation time
Report waiting line's mean line length
Report waiting line's mean wait time
Report server's mean service time
Report server's mean utilization
Report server's count  (number of customers served)

Processing the Simulation End

Pseudo-code Algorithm for Processing the Simulation End
Halt the simulation

The step "Halt the simulation" can be done simply by calling the Simulation object's halt() method.

Additional Implementation Notes

  1. Integration testing is more difficult than unit testing. Simulations are by definition non-deterministic so it is not possible to test for exact results. We'll look for "reasonable" results.
  2. We will use minutes as the basic unit of time. So each clock "tick" represents one minute.
  3. As described above, you will specify simulation run parameters through Run Arguments (check this option in the jGRASP Build menu). This allows you to experiment with different simulation settings without having to edit and recompile your program. The user will supply run argument values as space-separated values in the text box that appears above the editing window. In your program, run arguments arrive as the array parameter to main in Simulation class: public static void main(String[] args). Each element of the array contains a run argument value. They are assigned to their corresponding instance variables in the constructor.
  4. Here are some initial simulation run arguments to try:
  5. The run arguments are specified in that order. For this example, the run argument text box would contain "480 120 10 2 18 8 4 2 14" (without the quotes).
  6. I can supply you with some approximate statistical results to expect. For the above run arguments, the resulting wait time will be about 10 minutes and average waiting line length between 2 and 3. The server utilization will be between 80% and 90%.

Your Task: Fill in the process() method in the ArrivalEvent class (6 points), the DepartureEvent class (6 points), the SimulationReportEvent class (4 points), and the SimulationEndEvent class (0 points).

Scoring

PointsDescription
4the scheduling methods in Simulation
6the process() method in ArrivalEvent
6the process() method in DepartureEvent
4the process() method in SimulationReportEvent

To Turn In

Zip your entire Pr3 working folder into a ZIP file with phase5 in its name. Then drop it into your DropBox.
[ COMP 2100 | Peter Sanderson | Math Sciences home page | Otterbein ]

Last updated: 
Peter Sanderson (PSanderson@otterbein.edu)