Simulation with Event Stepping

Authors:
SimPy release:

2.2

Web-site:

http://simpy.sourceforge.net/

Python-Version:

2.3 and later (not 3.0)

Revision:

$Revision: 297 $

Date:

$Date: 2009-03-31 02:24:46 +1300 (Tue, 31 Mar 2009) $

This manual describes SimulationStep, a SimPy module which supports stepping through a simulation model event by event.

Introduction

SimulationStep can assist with debugging models, interacting with them on an event-by-event basis, getting event-by-event output from a model (e.g. for plotting purposes), etc.

SimulationStep is a derivative of the Simulation module. Over and above the capabilities provided by Simulation, SimulationStep supports stepping through a simulation model event by event. It caters for:

  • running a simulation model, with calling a user-defined procedure after every event,
  • running a simulation model one event at a time by repeated calls,
  • starting and stopping the event stepping mode under program control.

SimulationStep overview

Here is a simple program which shows basic event stepping capabilities:

## Stepping1.py
from __future__ import generators
from SimPy.SimulationStep import *                  # (1)

def callbackTimeTrace():                            # (2)
    """Prints event times
    """
    print "at time=%s"%now()

class Man(Process):
    def walk(self):
        print "got up"
        yield hold,self,1
        print "got to door"
        yield hold,self,10
        print "got to mail box"
        yield hold,self,10
        print "got home again"

#trace event times
initialize()
otto=Man()
activate(otto,otto.walk())
startStepping()                                     # (3)
simulate(callback=callbackTimeTrace,until=100)      # (4)

A trivial simulation model, but with event stepping:

  1. import the stepping version of Simulation
  2. define a procedure which gets called after every event
  3. switch into event stepping mode
  4. run the model with event callback to the procedure defined at (2); simulate in SimulationStep has an extra named parameter, callback.

Running it produces this output:

got up
at time=0
got to door
at time=1
got to mail box
at time=11
got home again
at time=21
at time=21

The callback outputs the simulation time after every event.

Here is another example, the same model, but now with the user getting control back after every event:

## Stepping2.py
from __future__ import generators
from SimPy.SimulationStep import *

def callbackUserControl():
    """Allows user to control stepping
    """
    a=raw_input("[Time=%s] Select one: End run (e), Continue stepping (s), Run to end (r)= "%now())
    if a=="e":
        stopSimulation()
    elif a=="s":
        return
    else:
        stopStepping()

class Man(Process):
    def walk(self):
        print "got up"
        yield hold,self,1
        print "got to door"
        yield hold,self,10
        print "got to mail box"
        yield hold,self,10
        print "got home again"
#allow user control
initialize()
otto=Man()
activate(otto,otto.walk())
startStepping()
simulate(callback=callbackUserControl,until=100)

Its interactive output looks like this:

got up
[Time=0] Select one: End run (e), Continue stepping (s), Run to end (r)= s
got to door
[Time=1] Select one: End run (e), Continue stepping (s), Run to end (r)= s
got to mail box
[Time=11] Select one: End run (e), Continue stepping (s), Run to end (r)= s
got home again
[Time=21] Select one: End run (e), Continue stepping (s), Run to end (r)= s
[Time=21] Select one: End run (e), Continue stepping (s), Run to end (r)= s

or this (the user stopped stepping mode at time=1):

got up
[Time=0] Select one: End run (e), Continue stepping (s), Run to end (r)= s
got to door
[Time=1] Select one: End run (e), Continue stepping (s), Run to end (r)= r
got to mail box
got home again

If one wants to run a tested/debugged model full speed, i.e. without stepping, one can write a program as follows:

## Stepping2Fast.py
from __future__ import generators
if __debug__:
        from SimPy.SimulationStep import *
else:
        from SimPy.Simulation import *

def callbackUserControl():
    """Allows user to control stepping
    """
    if __debug__:
                a=raw_input("[Time=%s] Select one: End run (e), Continue stepping (s),\
                     Run to end (r)= "%now())
                if a=="e":
                    stopSimulation()
                elif a=="s":
                    return
                else:
                    stopStepping()

class Man(Process):
    def walk(self):
        print "got up"
        yield hold,self,1
        print "got to door"
        yield hold,self,10
        print "got to mail box"
        yield hold,self,10
        print "got home again"
#allow user control if debugging
initialize()
otto=Man()
activate(otto,otto.walk())
if __debug__:
        startStepping()
        simulate(callback=callbackUserControl,until=100)
else:
        simulate(until=100)

If one runs this with the Python command line option ‘-O’, any statement starting with if __debug__: is ignored/skipped by the Python interpreter.

The SimulationStep API

Structure

Basically, SimulationStep has the same API as Simulation, but with the following additions and changes:

def startStepping()         **new**
def stopStepping()          **new**
def simulate()              **changed**
def simulateStep()          **new**

startStepping

Starts the event-stepping.

Call:

startStepping()
Mandatory parameters:
None.
Optional parameters:
None
Return value:
None.

stopStepping

Stops event-stepping.

Call:
stopStepping()
Mandatory parameters:
None
Optional parameters:
None
Return value:
None

simulate

Runs a simulation with callback to a user-defined function after each event, if stepping is turned on. By default, stepping is switched off.

Call:
simulate(callback=<proc>,until=<endtime>)
Mandatory parameters:
None
Optional parameters:
  • until = 0: the simulation time until which the simulation is to run (positive floating point or integer number)
  • callback = lambda:None: the function to be called after every event (function reference)
Return value:
The simulation status at exit (string)

simulateStep

Runs a simulation for one event, with (optional) callback to a user-defined function after the event, if stepping is turned on. By default, stepping is switched off. Thus, to execute the model to completion, simulateStep must be called repeatedly.

Note: it is not yet clear to the developers whether this part of the API offers any advantages or capabilities over and above the *simulate* function. The survival of this function in future versions depends on the feedback from the user community.

Call:
simulateStep(callback=<proc>,until=<endtime>)
Mandatory parameters:
None
Optional parameters:
  • until = 0: the simulation time until which the simulation is to run (positive floating point or integer number)
  • callback = lambda:None: the function to be called after every event (function reference)
Return value:
The tuple (simulation status at exit (string),<resumability flag>). <resumability flag> can have one of two string values: “resumable” if there are more events to be executed, and “notResumable” if all events have been exhausted or an error has occurred. simulateStep should normally only be called if “resumable” is returned.

$Revision: 297 $ $Date: 2009-03-31 02:24:46 +1300 (Tue, 31 Mar 2009) $ kgm