.. image:: images/sm_SimPy_Logo.png :align: left ========================= SimulationRT Manual ========================= :Authors: - Klaus Muller - Tony Vignaux :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()** 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()** 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