Using the ESAS Frameworks

The ES Framework

An example - The Cashier Model

The Code

We explain how to use the framework by providing an example. The source code can be found here. Below, we show the source with comments following each sections.

  1  #
  2  # Cashier example
  3  #
  4  
  5  # location of simulator
  6  import sys, os
  7  sys.path.append(os.pardir + os.sep + 'es')
  8
  9  # frame work modules
 10  from sim import *
 11  from model import *
 12  from event import *
 13  
 14  from rng import *
 15  
Line 14 is required only if the Random Number Generator is used. All other lines should be common to all ES model description.
 16  # constants
 17  IDLE = Utilization.IDLE
 18  BUSY = Utilization.BUSY
 19  end_time = 100
 20  
 21  # priorities
 22  LOW  = 1
 23  HIGH = 2
 24  
 25  # Random Number Generator
 26  rng_10_2 = IntUniform(mean = 10, spread = 2)
 27  
 28  
 29  # a flag to make it run with or without priorities
 30  priorityOn = 0
 31  
 32  #
 33  # This is a start event.  It will be the first
 34  # event scheduled.
 35  #
 36  class MyStartEvent(StartEvent):
 37  

The model is described in terms of classes that extend Event or one of its subclasses. Each model should have at least one class that extends the class StartEvent. An instance of this class will be the first event scheduled by the simulator.

 38      # handler routine
 39      def execute(self, sched, state):
 40          # create state variables and add then to
 41          # the state set
 42          state.add(QueueVar("queue_length"))
 43          state.add(Utilization("cashier_state", IDLE))
 44  
 45          # schedule the first arrival at time 0
 46          sched.schedule(ArrivalEvent(0))
 47          # schedule the end event at time end_time
 48          sched.schedule(StatsEndEvent(end_time))
 49  
 50  

The handler routine has the method signature execute(self, sched, state). Its purpose is to change the state and/or shedule new events. It is invoked by the simulator kernel when it is time for this event to occur. The simulator will pass two arguments to it. sched is an object of type Scheduler that provides methods to schedule events. state is a State instance. It provides methods to access and modify the state variables. The execute method provided by the Event does nothing by default. In most cases, you would want to override it to do useful thing.

Each state variable has a name and a value. Different types of state variables are already defined. The user can also define its own type by extending StateVar. A variable of type StateVar is the most general type. More specialized types such as QueueVar can be used. These special types have methods that keeps track and compute useful performance metrics. All state variables should be added to the state object at the beginning, i.e. in the start event execute() method. A state variable called current_time will be added when the simulation will start. It contains the current time and it is updated by the kernel.

Events are scheduled by creating an instance of the event and passing it to the schedule() method of the Scheduler. The default constructor takes the time as an argument. The time is always an absolute time. Note that the scheduler is aware of the current time and will not allow an event to be scheduled in the past, it will raise an error. We have provided two end events with our framework. The user can extend EndEvent to create its own. EndEvents are special events known by the kernel. They will stop the simulation (all events scheduled at the same time than the end event will be executed before it is executed and the simulation terminates). The StatsEndEvent is an end event that prints all the performance metrics to standard output.

 51  
 52  # represents the arrival of a customer
 53  class ArrivalEvent(Event):
 54  
 55      def __init__(self, time):
 56          Event.__init__(self, time)
 57          if priorityOn:
 58              self.setPriority(LOW)
 59

If a constructor is provided, it should invoke the super constructor with a time argument. The priorityOn condition was used only to allow us to run the simulation with different priorities are all the same. A small note about priorities: priorities are per event type and not per event instance.

  
 60  
 61      # handler routine
 62      def execute(self, sched, state):
 63          # current time
 64          time = self.getTime()
 65

The current time can be accessed either with getTime() or via the current_time state variable: state.getValue("current_time")

  
 66          # get variables needed
 67          queue = state.getStateVar("queue_length")
 68          cashier_state = state.getStateVar("cashier_state")

It is not necessary to "extract" a state variables from the state to read or change its value. See the State API

 69          
 70          sched.schedule(ArrivalEvent(time + rng_10_2.next()))
 71          if (queue.isEmpty()):
 72              if (cashier_state.isIdle()):
 73                  cashier_state.setValue(BUSY)
 74                  sched.schedule(DepartureEvent(time + 25))
 75              else:
 76                  # note:
 77                  # This simply increases the queue length by 1.
 78                  # No object is actually enqueued.
 79                  # It is equivalent to:
 80                  #   queue.setValue(queue.getValue() + 1)
 81                  queue.enqueue()
 82          else:
 83              queue.enqueue()
 84              
 85  
 86  class DepartureEvent(Event):
 87  
 88      def __init__(self, time):
 89          Event.__init__(self, time)
 90          if priorityOn:
 91              self.setPriority(HIGH)
 92  
 93  
 94      def execute(self, sched, state):
 95          time = self.getTime()
 96          queue = state.getStateVar("queue_length")
 97          cashier_state = state.getStateVar("cashier_state")
 98  
 99          if (queue.isEmpty()):
100              # note: equivalent to: cashier_state.setValue(IDLE)
101              cashier_state.releaseFacility()
102          else:
103              queue.dequeue()
104              sched.schedule(DepartureEvent(time + 25))
105  
106  
107  #
108  # Construct a model object.
109  # An instance of our start event is required.
110  # An optional name may be given.
111  #
112  # This model is passed on to the simulator.
113  #
114  mymodel = Model(MyStartEvent(), "Super Market")
115  simulator = Simulator(mymodel)
116  

The instance of the start event created will be the first event scheduled when the simulation will run. The name argument is optional.

117  
118  if __name__ == "__main__":
119      if len(sys.argv) > 1:
120          if sys.argv[1] == 'p':
121              print "Using priorities"
122              priorityOn = 1
123      simulator.setTrace()  # turn on trace mode, default output file
124      simulator.run()       # simulates
125  

These few lines turns the trace on and starts the simulation. Since no filename has been specified, it will use the default file name temp.txt.

Results

Our Visual Tool has been used to plot graphs from the data in the trace file.


Queue length vs time


Cashier state vs time (0 - Idle, 1 - Busy)

A second example is shown at the end of the ESHLL section.

The AS Framework

An example - The Cashier Model

- source code.
- running result.
- the time vs. queue length plotting:



Back

$Id: framework.html,v 1.1.1.1 2003/03/22 05:15:49 dbelan2 Exp $