# Simulation with Real Time Synchronization

Authors:

  - Klaus Muller <Muller@users.sourceforge.net>

  - Tony Vignaux <Vignaux@users.sourceforge.net>

SimPy release:

  2.3.1

Web-site:

  http://simpy.sourceforge.net/

Python-Version:

  2.6+

Date:

  December 2011

This manual describes SimulationRT, a SimPy module which supports synchronizing the execution of simulation models with real (wallclock) time.

## Acknowledgement

SimulationRT is based on an idea by Geoff Jarrad of CSIRO (Australia). He contributed a lot to its development and testing on Windows and Unix.

The code for the adjustment of the execution speed during the simulation run was contributed by Robert C. Ramsdell.

## Synchronizing with wall clock time

SimulationRT allows synchronizing simulation time and real (wallclock) time. This capability can be used to implement e.g. interactive game applications or to demonstrate a model’s execution in real time.

It is identical to Simulation, except for the simulate function which takes an additional parameter controlling real-time execution speed.

Here is an example:

     1""" RealTimeFireworks.py """
     2from SimPy.SimulationRT  import *
     3from random import *
     4import time
     5## Model components -----------------------------------------------------------
     6class Launcher(Process):
     7	def launch(self):
     8		while True:
     9			print "Launch at %2.2f; wallclock: %2.2f"%(now(),time.clock()-startTime)
    10			yield hold,self,uniform(1,maxFlightTime)
    11			print "Boom!!! Aaaah!! at %2.2f; wallclock: %2.2f"\
    12			       %(now(),time.clock()-startTime)
    13def model():
    14	initialize()
    15	for i in range(nrLaunchers):
    16		lau=Launcher()
    17		activate(lau,lau.launch())
    18	simulate(real_time=True,rel_speed=1,until=20) ##unit sim time = 1 sec clock
    19## Experiment data  -----------------------------------------------------------
    20nrLaunchers=2
    21maxFlightTime=5.0
    22startTime=time.clock()
    23seed(1234567)
    24## Experiment -----------------------------------------------------------------
    25model()

rel_speed is the ratio simulated time/wallclock time. rels_speed=1 sets the synchronization so that 1 simulation time unit is executed in approximately 1 second of wallclock time. Run under Python 2.6 on a Windows Vista-box (2.3 GHz), this output resulted over about 17.5 seconds of wallclock time:

     1Launch at 0.00; wallclock: 0.00
     2Launch at 0.00; wallclock: 0.00
     3Boom!!! Aaaah!! at 3.04; wallclock: 3.03
     4Launch at 3.04; wallclock: 3.03
     5Boom!!! Aaaah!! at 3.90; wallclock: 3.90
     6Launch at 3.90; wallclock: 3.90
     7Boom!!! Aaaah!! at 5.47; wallclock: 5.47
     8Launch at 5.47; wallclock: 5.47
     9Boom!!! Aaaah!! at 6.50; wallclock: 6.50
    10Launch at 6.50; wallclock: 6.50
    11Boom!!! Aaaah!! at 7.35; wallclock: 7.35
    12Launch at 7.35; wallclock: 7.35
    13Boom!!! Aaaah!! at 9.88; wallclock: 9.87
    14Launch at 9.88; wallclock: 9.87
    15Boom!!! Aaaah!! at 10.71; wallclock: 10.70
    16Launch at 10.71; wallclock: 10.70
    17Boom!!! Aaaah!! at 11.84; wallclock: 11.84
    18Launch at 11.84; wallclock: 11.84
    19Boom!!! Aaaah!! at 12.17; wallclock: 12.16
    20Launch at 12.17; wallclock: 12.16
    21Boom!!! Aaaah!! at 13.78; wallclock: 13.78
    22Launch at 13.78; wallclock: 13.78
    23Boom!!! Aaaah!! at 14.63; wallclock: 14.62
    24Launch at 14.63; wallclock: 14.62
    25Boom!!! Aaaah!! at 17.30; wallclock: 17.29
    26Launch at 17.30; wallclock: 17.29
    27Boom!!! Aaaah!! at 17.32; wallclock: 17.31
    28Launch at 17.32; wallclock: 17.31

Clearly, the wallclock time does not deviate significantly from the simulation time.

## Changing the execution speed during a simulation run

By calling method rtset with a parameter, the ratio simulated time to wallclock time can be changed during a run.

Here is an example:

     1"""variableTimeRatio.py
     2Shows the SimulationRT capability to change the ratio simulation
     3time to wallclock time during the run of a simulation.
     4"""
     5from SimPy.SimulationRT import *
     6
     7class Changer(Process):
     8    def change(self,when,rat):
     9        global ratio
    10        yield hold,self,when
    11        rtset(rat)
    12        ratio=rat
    13class Series(Process):
    14    def tick(self,nrTicks):
    15        oldratio=ratio
    16        for i in range(nrTicks):
    17            tLastSim=now()
    18            tLastWallclock=wallclock()
    19            yield hold,self,1
    20            diffSim=now()-tLastSim
    21            diffWall=wallclock()-tLastWallclock
    22            print "now(): %s, sim. time elapsed: %s, wall clock elapsed: "\
    23                "%6.3f, sim/wall time ratio: %6.3f"\
    24                %(now(),diffSim,diffWall,diffSim/diffWall)
    25            if not ratio==oldratio:
    26                print "At simulation time %s: ratio simulation/wallclock "\
    27                    "time now changed to %s"%(now(),ratio)
    28                oldratio=ratio
    29initialize()
    30ticks=15
    31s=Series()
    32activate(s,s.tick(nrTicks=ticks))
    33c=Changer()
    34activate(c,c.change(5,5))
    35c=Changer()
    36activate(c,c.change(10,10))
    37ratio=1
    38print "At simulation time %s: set ratio simulation/wallclock time to %s"\
    39       %(now(),ratio)
    40simulate(until=100,real_time=True,rel_speed=ratio)

The program changes the time ratio twice, at simulation times 5 and 10.

When run on a Windows Vista computer under Python 2.6, this results in this output:

     1At simulation time 0: set ratio simulation/wallclock time to 1
     2now(): 1, sim. time elapsed: 1, wall clock elapsed:  0.998, sim/wall time ratio:  1.002
     3now(): 2, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
     4now(): 3, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
     5now(): 4, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
     6now(): 5, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
     7At simulation time 5: ratio simulation/wallclock time now changed to 5
     8now(): 6, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.027
     9now(): 7, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.025
    10now(): 8, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.026
    11now(): 9, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.026
    12now(): 10, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.024
    13At simulation time 10: ratio simulation/wallclock time now changed to 10
    14now(): 11, sim. time elapsed: 1, wall clock elapsed:  0.099, sim/wall time ratio: 10.108
    15now(): 12, sim. time elapsed: 1, wall clock elapsed:  0.099, sim/wall time ratio: 10.105
    16now(): 13, sim. time elapsed: 1, wall clock elapsed:  0.099, sim/wall time ratio: 10.102
    17now(): 14, sim. time elapsed: 1, wall clock elapsed:  0.099, sim/wall time ratio: 10.104
    18now(): 15, sim. time elapsed: 1, wall clock elapsed:  0.099, sim/wall time ratio: 10.104

## Limitations

This module works much better under Windows than under Unix or Linux, i.e., it gives much closer synchronization. Unfortunately, the handling of time in Python is not platform-independent at all. Here is a quote from the documentation of the time module:

     1"clock()
     2On Unix, return the current processor time as a floating point number expressed in seconds.
     3The precision, and in fact the very definition of the meaning of ``processor time'' , depends
     4on that of the C function of the same name, but in any case, this is the function to use for
     5benchmarking Python or timing algorithms.
     6
     7On Windows, this function returns wall-clock seconds elapsed since the first call to this
     8function, as a floating point number, based on the Win32 function QueryPerformanceCounter().
     9The resolution is typically better than one microsecond.
    10"

## The SimulationRT API

### Structure

Basically, SimulationStep has the same API as Simulation, but with:

> - a change in the definition of simulate, and

> - an additional method to change execution speed during a simulation run.

### simulate

Executes the simulation model.

Call:

> simulate(<optional parameters>)

Mandatory parameters:

  None.

Optional parameters:

  - until=0 : the maximum simulation (end) time (positive floating point number; default: 0)

  - real_time=False : flag to switch real time synchronization on or off (boolean; default: False, meaning no synchronization)

  - rel_speed=1 : ratio simulation time over wallclock time; example: rel_speed=200 executes 200 units of simulation time in about one second (positive floating point number; default: 1, i.e. 1 sec of simulation time is executed in about 1 sec of wallclock time)

Return value:

  Simulation status at exit.

### rtset

Changes the ratio simulation time over wall clock time.

Call:

> rtset(<new ratio>)

Mandatory parameters:

  None

Optional parameters:

  - rel_speed=1 : ratio simulation time over wallclock time; example: rel_speed=200 executes 200 units of simulation time in about one second (positive floating point number; default: 1, i.e. 1 sec of simulation time is executed in about 1 sec of wallclock time)

Return value:

  None