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:
- The Event interface, the AbstractEvent class,
and the ArrivalEvent, DepartureEvent,
SimulationReportEvent, and SimulationEndEvent classes from Phase 1.
- The WaitingLine class to model customers waiting in a queue, from Phase 2.
- The Server class to model services for which customers contend in the simulation model, from Phase 3.
- The Customer class is provided.
- The RandomNormal and RandomExponential classes from Phase 4.
- 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!
- You'll need the API for the Simulation class
- Download and extract a new version of the Simulation class from phase5.zip. NOTE: This is a production version
of the Simulation class. All test driver code has been removed. I recommend saving your Phase 3 version of Simulation.java before
downloading this one.
- Make sure the new Simulation.java and the all Java files listed above from previous phases are in the
same folder!
- In the Simulation class, the scheduleArrival(), scheduleDeparture(), scheduleSimulationReport() and
scheduleSimulationEnd()
methods in the Simulation class need to be fleshed out.
- The process() methods in the ArrivalEvent, DepartureEvent, SimulationReportEvent
and SimulationEndEvent classes need to be fleshed out.
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:
- Notice that the constructor is private. It will only be called through the static getInstance()
method, which itself is called in main. This technique is called singleton, and it means only one Simulation
instance (object) will ever be created. Look at the getInstance() code to convince yourself of this.
- The first five instance variables are all required by the simulation mechanism: the waiting line, the server,
the random number generator for random arrivals, the random number generator for random service, and the Future
Events Queue.
- Those five variables are initialized in the constructor by creating objects of the given type and assigning
them to the variables. IMPORTANT: the random number generator for arrivals is a RandomExponential and
the random number generator for service is a RandomNormal.
- The simulation clock is initialized to 0. Each clock "tick" represents one minute of time.
- Values for initializing the simulation ending time, reporting interval,
random arrival min/max/mean and random service min/max/mean/sd are provided
as run arguments. Recall these are values provided to main()
through its parameter args. The args array will contain values provided
to jGRASP through the Build->Run Arguments feature where all values are provided
in a space-separated list. In main(), parameter args is
assigned to the static variable runArgs. The constructor will use
runArgs to get these values and assign them.
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:
- Determine at what future clock time the event will occur
- Create the event, giving it the future clock time
- Add the event to the FEQ
The following implementation notes apply to Step 1.
- For scheduling an arrival, use interarrivalRNG, the provided RandomExponential instance variable, to determine how long until the next arrival.
- For scheduling a departure, use serviceRNG, the provided RandomNormal instance variable, to determine how long until service is completed.
- 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.
- 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.
- 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:
- the Simulation object itself; you already know how to get this using the static getInstance() method
- the WaitingLine object, which can be obtained from the Simulation object.
- the Server object, which can be obtained from the Simulation object.
- the SimulationReportEvent will need access to the WaitingLine and Server statistics, which can be obtained
from the WaitingLine and Server objects.
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
- 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.
- We will use minutes as the basic unit of time. So each clock "tick" represents one minute.
- 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.
- Here are some initial simulation run arguments to try:
- Run the simulation for 480 minutes (8 hours).
- Generate a report every 120 minutes (2 hours).
- Arrivals are exponentially distributed with mean interarrival time of 10 minutes. Let's say minimum 2, maximum 18.
- Service is normally distributed with a mean service time of 8 minutes and standard deviation of 4 minutes. Let's
say minimum 2 and maximum 14.
- 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).
- 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
Points | Description |
4 | the scheduling methods in Simulation |
6 | the process() method in ArrivalEvent |
6 | the process() method in DepartureEvent |
4 | the 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)