.. image:: images/sm_SimPy_Logo.png
   :align: left

=========================
 SimulationRT Manual
=========================


:Authors: - Klaus Muller <Muller@users.sourceforge.net>
          - Tony Vignaux <Vignaux@users.sourceforge.net>
:SimPy version: 1.8
:Web-site: http://simpy.sourceforge.net/
:Python-Version: 2.3, 2.4, 2.5
:Revision: $Revision: 1.1.1.10 $ 
:Date: $Date: 2007/01/11 10:58:57 $ 

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

What is new in SimPy 1.8?
==========================

A capability has been added to SimulationRT to change the model execution speed during
the run of a simulation model. This is useful for e.g. a simulation
GUI which shows the progress of the simulation run and allows the 
user to interactively slow down or accelerate the model execution.

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.

Introduction
============

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::

    ## RealTimeFireworks.py
    from __future__ import generators
    from SimPy.SimulationRT  import *
    from random import *
    import time
    class Launcher(Process):
        def launch(self):
            while True:
                print "Launch at %.1f; wallclock: %s"%(now(),time.clock()-startTime)
                yield hold,self,uniform(1,maxFlightTime)
		print "Boom!!! Aaaah!! at %.1f; wallclock: %s"%(now(),time.clock()-startTime)
    def model():
        initialize()
        for i in range(nrLaunchers):
            lau=Launcher()
            activate(lau,lau.launch())
        simulate(real_time=True,rel_speed=1,until=20) ##unit sim time = 1 sec clock
    nrLaunchers=2
    maxFlightTime=5.0 
    startTime=time.clock()
    model()
    
*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.2.2 on a Windows XP-box (1.7 GHz), this output resulted
over about 18 seconds of wallclock time::

	Launch at 0.0; wallclock: 0.000195555580376
	Launch at 0.0; wallclock: 0.00190107960634
	Boom!!! Aaaah!! at 1.8; wallclock: 1.78082661344
	Launch at 1.8; wallclock: 1.78274501368
	Boom!!! Aaaah!! at 2.8; wallclock: 2.84245930698
	Launch at 2.8; wallclock: 2.84435982785
	Boom!!! Aaaah!! at 4.1; wallclock: 4.08443978215
	Launch at 4.1; wallclock: 4.09004328762
	Boom!!! Aaaah!! at 5.2; wallclock: 5.14561822801
	Launch at 5.2; wallclock: 5.14878203794
	Boom!!! Aaaah!! at 7.0; wallclock: 6.99845622838
	Launch at 7.0; wallclock: 7.00175357483
	Boom!!! Aaaah!! at 7.4; wallclock: 7.39919794276
	Launch at 7.4; wallclock: 7.40245282571
	Boom!!! Aaaah!! at 9.7; wallclock: 9.69250728794
	Launch at 9.7; wallclock: 9.69912935862
	Boom!!! Aaaah!! at 10.6; wallclock: 10.5938587167
	Launch at 10.6; wallclock: 10.6006140445
	Boom!!! Aaaah!! at 13.8; wallclock: 13.8082362423
	Launch at 13.8; wallclock: 13.8134877477
	Boom!!! Aaaah!! at 14.1; wallclock: 14.1385670525
	Launch at 14.1; wallclock: 14.1438146468
	Boom!!! Aaaah!! at 16.4; wallclock: 16.411963811
	Launch at 16.4; wallclock: 16.4172373863
	Boom!!! Aaaah!! at 17.1; wallclock: 17.1429980626
	Launch at 17.1; wallclock: 17.1482308506
	Boom!!! Aaaah!! at 18.1; wallclock: 18.0742063586
	Launch at 18.1; wallclock: 18.0794469688
	
Clearly, the wallclock time does not deviate significantly from the simulation time.

Changing the execution speed during a simulation run (new in 1.8)
==================================================================

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

Here is an example::

    """variableTimeRatio.py
    Shows the SimulationRT capability to change the ratio simulation 
    time to wallclock time during the run of a simulation.
    """
    from SimulationRT import *

    class Changer(Process):
        def change(self,when,rat):
            global ratio
            yield hold,self,when
            rtset(rat)
            ratio=rat
    class Series(Process):
        def tick(self,nrTicks):
            oldratio=ratio
            for i in range(nrTicks):
                tLastSim=now()
                tLastWallclock=wallclock()
                yield hold,self,1
                diffSim=now()-tLastSim
                diffWall=wallclock()-tLastWallclock
                print "now(): %s, sim. time elapsed: %s, wall clock elapsed: "\
                    "%6.3f, sim/wall time ratio: %6.3f"\
                    %(now(),diffSim,diffWall,diffSim/diffWall)
                if not ratio==oldratio:
                    print "At simulation time %s: ratio simulation/wallclock "\
                        "time now changed to %s"%(now(),ratio)
                    oldratio=ratio
    initialize()
    ticks=15
    s=Series()
    activate(s,s.tick(nrTicks=ticks))
    c=Changer()
    activate(c,c.change(5,5))
    c=Changer()
    activate(c,c.change(10,0.1))
    ratio=1
    print "At simulation time %s: set ratio simulation/wallclock time to %s"\
           %(now(),ratio)
    simulate(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 XP computer under Python 2.3, this results in this output:

    At simulation time 0: set ratio simulation/wallclock time to 1
    now(): 1, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
    now(): 2, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
    now(): 3, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
    now(): 4, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
    now(): 5, sim. time elapsed: 1, wall clock elapsed:  0.999, sim/wall time ratio:  1.001
    At simulation time 5: ratio simulation/wallclock time now changed to 5
    now(): 6, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.021
    now(): 7, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.020
    now(): 8, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.020
    now(): 9, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.020
    now(): 10, sim. time elapsed: 1, wall clock elapsed:  0.199, sim/wall time ratio:  5.019
    At simulation time 10: ratio simulation/wallclock time now changed to 0.1
    now(): 11, sim. time elapsed: 1, wall clock elapsed: 10.001, sim/wall time ratio:  0.100
    now(): 12, sim. time elapsed: 1, wall clock elapsed: 10.001, sim/wall time ratio:  0.100
    now(): 13, sim. time elapsed: 1, wall clock elapsed: 10.001, sim/wall time ratio:  0.100
    now(): 14, sim. time elapsed: 1, wall clock elapsed: 10.001, sim/wall time ratio:  0.100
    now(): 15, sim. time elapsed: 1, wall clock elapsed: 10.001, sim/wall time ratio:  0.100

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::

    "clock()
    On Unix, return the current processor time as a floating point number expressed in seconds. 
    The precision, and in fact the very definition of the meaning of ``processor time'' , depends 
    on that of the C function of the same name, but in any case, this is the function to use for 
    benchmarking Python or timing algorithms.

    On Windows, this function returns wall-clock seconds elapsed since the first call to this 
    function, as a floating point number, based on the Win32 function QueryPerformanceCounter(). 
    The resolution is typically better than one microsecond. 
    "


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

    
$Revision: 1.1.1.10 $ $Date: 2007/01/11 10:58:57 $ kgm
