Package SimPy :: Module SimulationStep
[hide private]
[frames] | no frames]

Source Code for Module SimPy.SimulationStep

  1  #!/usr / bin / env python 
  2  # coding=utf-8 
  3  # $Revision: 485 $ $Date: 2010-05-10 09:23:24 +0200 (Mon, 10 May 2010) $ kgm 
  4  """SimulationStep 2.1 Supports stepping through SimPy simulation event - by - event. 
  5  Based on generators (Python 2.3 and later; not 3.0) 
  6   
  7  LICENSE: 
  8  Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2010  Klaus G. Muller, Tony Vignaux 
  9  mailto: kgmuller at xs4all.nl and Tony.Vignaux at vuw.ac.nz 
 10   
 11      This library is free software; you can redistribute it and / or 
 12      modify it under the terms of the GNU Lesser General Public 
 13      License as published by the Free Software Foundation; either 
 14      version 2.1 of the License, or (at your option) any later version. 
 15   
 16      This library is distributed in the hope that it will be useful, 
 17      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 18      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 19      Lesser General Public License for more details. 
 20   
 21      You should have received a copy of the GNU Lesser General Public 
 22      License along with this library; if not, write to the Free Software 
 23      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111 - 1307  USA 
 24  END OF LICENSE 
 25  """ 
 26  from SimPy.Simulation import * 
 27   
 28  __TESTING = False 
 29  version = __version__ = '2.1 $Revision: 485 $ $Date: 2010-05-10 09:23:24 +0200 (Mon, 10 May 2010) $' 
 30  if __TESTING:  
 31      print 'SimPy.SimulationStep %s' %__version__, 
 32      if __debug__: 
 33          print '__debug__ on' 
 34      else: 
 35          print 
 36   
 37  _step = False 
 38   
39 -class SimulationStep(Simulation):
40 - def __init__(self):
41 Simulation.__init__(self) 42 self._step = False
43
44 - def initialize(self):
45 Simulation.initialize(self) 46 self._step = False
47
48 - def startStepping(self):
49 """Application function to start stepping through simulation.""" 50 self._step = True
51
52 - def stopStepping(self):
53 """Application function to stop stepping through simulation.""" 54 self._step = False
55
56 - def step(self):
57 Simulation.step(self) 58 if self._step: self.callback()
59
60 - def simulate(self, callback=lambda: None, until=0):
61 """ 62 Simulates until simulation time reaches ``until``. After processing each 63 event, ``callback`` will be invoked if stepping has been enabled with 64 :meth:`~SimPy.SimulationStep.startStepping`. 65 """ 66 self.callback = callback 67 return Simulation.simulate(self, until)
68 69 # For backward compatibility 70 Globals.sim = SimulationStep() 71
72 -def startStepping():
73 Globals.sim.startStepping()
74
75 -def stopStepping():
76 Globals.sim.stopStepping()
77 78 peek = Globals.sim.peek 79 80 step = Globals.sim.step 81
82 -def simulate(callback = lambda :None, until = 0):
83 return Globals.sim.simulate(callback = callback, until = until)
84 85 # End backward compatibility 86 87 88 ################### end of Simulation module 89 90 if __name__ == '__main__': 91 print 'SimPy.SimulationStep %s' %__version__ 92 ################### start of test / demo programs 93
94 - def askCancel():
95 a = raw_input('[Time=%s] End run (e), Continue stepping (s), Run to end (r)'%now()) 96 if a == 'e': 97 stopSimulation() 98 elif a == 's': 99 return 100 else: 101 stopStepping()
102
103 - def test_demo():
104 class Aa(Process): 105 sequIn = [] 106 sequOut = [] 107 def __init__(self, holdtime, name): 108 Process.__init__(self, name) 109 self.holdtime = holdtime
110 111 def life(self, priority): 112 for i in range(1): 113 Aa.sequIn.append(self.name) 114 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 115 len(rrr.activeQ) 116 print 'waitQ: ',[(k.name, k._priority[rrr]) for k in rrr.waitQ] 117 print 'activeQ: ',[(k.name, k._priority[rrr]) \ 118 for k in rrr.activeQ] 119 assert rrr.n + len(rrr.activeQ) == rrr.capacity, \ 120 'Inconsistent resource unit numbers' 121 print now(),self.name, 'requests 1 ', rrr.unitName 122 yield request, self, rrr, priority 123 print now(),self.name, 'has 1 ', rrr.unitName 124 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 125 len(rrr.activeQ) 126 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 127 len(rrr.activeQ) 128 assert rrr.n + len(rrr.activeQ) == rrr.capacity, \ 129 'Inconsistent resource unit numbers' 130 yield hold, self, self.holdtime 131 print now(),self.name, 'gives up 1', rrr.unitName 132 yield release, self, rrr 133 Aa.sequOut.append(self.name) 134 print now(),self.name, 'has released 1 ', rrr.unitName 135 print 'waitQ: ',[(k.name, k._priority[rrr]) for k in rrr.waitQ] 136 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 137 len(rrr.activeQ) 138 assert rrr.n + len(rrr.activeQ) == rrr.capacity, \ 139 'Inconsistent resource unit numbers' 140 141 class Destroyer(Process): 142 def __init__(self): 143 Process.__init__(self) 144 145 def destroy(self, whichProcesses): 146 for i in whichProcesses: 147 Process().cancel(i) 148 yield hold, self, 0 149 150 class Observer(Process): 151 def __init__(self): 152 Process.__init__(self) 153 154 def observe(self, step, processes, res): 155 while now() < 11: 156 for i in processes: 157 print ' %s %s: act:%s, pass:%s, term: %s, interr:%s, qu:%s'\ 158 %(now(),i.name, i.active(),i.passive(),i.terminated()\ 159 ,i.interrupted(),i.queuing(res)) 160 print 161 yield hold, self, step 162 163 class UserControl(Process): 164 def letUserInteract(self, when): 165 yield hold, self, when 166 startStepping() 167 168 print '****First case == priority queue, resource service not preemptable' 169 initialize() 170 rrr = Resource(5, name = 'Parking', unitName = 'space(s)', qType = PriorityQ, 171 preemptable = 0) 172 procs = [] 173 for i in range(10): 174 z = Aa(holdtime = i, name = 'Car ' + str(i)) 175 procs.append(z) 176 activate(z, z.life(priority = i)) 177 o = Observer() 178 activate(o, o.observe(1, procs, rrr)) 179 startStepping() 180 a = simulate(until = 10000, callback = askCancel) 181 print 'Input sequence: ', Aa.sequIn 182 print 'Output sequence: ', Aa.sequOut 183 184 print '\n****Second case == priority queue, resource service preemptable' 185 initialize() 186 rrr = Resource(5, name = 'Parking', unitName = 'space(s)', qType = PriorityQ, 187 preemptable = 1) 188 procs = [] 189 for i in range(10): 190 z = Aa(holdtime = i, name = 'Car ' + str(i)) 191 procs.append(z) 192 activate(z, z.life(priority = i)) 193 o = Observer() 194 activate(o, o.observe(1, procs, rrr)) 195 u = UserControl() 196 activate(u, u.letUserInteract(4)) 197 Aa.sequIn = [] 198 Aa.sequOut = [] 199 a = simulate(askCancel, until = 10000) 200 print a 201 print 'Input sequence: ', Aa.sequIn 202 print 'Output sequence: ', Aa.sequOut 203
204 - def test_interrupt():
205 class Bus(Process): 206 def __init__(self, name): 207 Process.__init__(self, name)
208 209 def operate(self, repairduration = 0): 210 print now(),'>> %s starts' % (self.name) 211 tripleft = 1000 212 while tripleft > 0: 213 yield hold, self, tripleft 214 if self.interrupted(): 215 print 'interrupted by %s' %self.interruptCause.name 216 print '%s: %s breaks down ' %(now(),self.name) 217 tripleft = self.interruptLeft 218 self.interruptReset() 219 print 'tripleft ', tripleft 220 reactivate(br, delay = repairduration) # breakdowns only during operation 221 yield hold, self, repairduration 222 print now(),' repaired' 223 else: 224 break # no breakdown, ergo bus arrived 225 print now(),'<< %s done' % (self.name) 226 227 class Breakdown(Process): 228 def __init__(self, myBus): 229 Process.__init__(self, name = 'Breakdown ' + myBus.name) 230 self.bus = myBus 231 232 def breakBus(self, interval): 233 234 while True: 235 yield hold, self, interval 236 if self.bus.terminated(): break 237 self.interrupt(self.bus) 238 239 print'\n\n+++test_interrupt' 240 initialize() 241 b = Bus('Bus 1') 242 activate(b, b.operate(repairduration = 20)) 243 br = Breakdown(b) 244 activate(br, br.breakBus(200)) 245 startStepping() 246 simulate(until = 4000) 247 248
249 - def testSimEvents():
250 class Waiter(Process): 251 def waiting(self, theSignal): 252 while True: 253 yield waitevent, self, theSignal 254 print '%s: process \'%s\' continued after waiting for %s' % (now(),self.name, theSignal.name) 255 yield queueevent, self, theSignal 256 print '%s: process \'%s\' continued after queueing for %s' % (now(),self.name, theSignal.name)
257 258 class ORWaiter(Process): 259 def waiting(self, signals): 260 while True: 261 yield waitevent, self, signals 262 print now(),'one of %s signals occurred' % [x.name for x in signals] 263 print '\t%s (fired / param)'%[(x.name, x.signalparam) for x in self.eventsFired] 264 yield hold, self, 1 265 266 class Caller(Process): 267 def calling(self): 268 while True: 269 signal1.signal('wake up!') 270 print '%s: signal 1 has occurred'%now() 271 yield hold, self, 10 272 signal2.signal('and again') 273 signal2.signal('sig 2 again') 274 print '%s: signal1, signal2 have occurred'%now() 275 yield hold, self, 10 276 print'\n+++testSimEvents output' 277 initialize() 278 signal1 = SimEvent('signal 1') 279 signal2 = SimEvent('signal 2') 280 signal1.signal('startup1') 281 signal2.signal('startup2') 282 w1 = Waiter('waiting for signal 1') 283 activate(w1, w1.waiting(signal1)) 284 w2 = Waiter('waiting for signal 2') 285 activate(w2, w2.waiting(signal2)) 286 w3 = Waiter('also waiting for signal 2') 287 activate(w3, w3.waiting(signal2)) 288 w4 = ORWaiter('waiting for either signal 1 or signal 2') 289 activate(w4, w4.waiting([signal1, signal2]),prior = True) 290 c = Caller('Caller') 291 activate(c, c.calling()) 292 print simulate(until = 100) 293
294 - def testwaituntil():
295 """ 296 Demo of waitUntil capability. 297 298 Scenario: 299 Three workers require sets of tools to do their jobs. Tools are shared, scarce 300 resources for which they compete. 301 """ 302 303 304 class Worker(Process): 305 def __init__(self, name, heNeeds = []): 306 Process.__init__(self, name) 307 self.heNeeds = heNeeds
308 def work(self): 309 310 def workerNeeds(): 311 for item in self.heNeeds: 312 if item.n == 0: 313 return False 314 return True 315 316 while now() < 8 * 60: 317 yield waituntil, self, workerNeeds 318 for item in self.heNeeds: 319 yield request, self, item 320 print '%s %s has %s and starts job' % (now(),self.name, 321 [x.name for x in self.heNeeds]) 322 yield hold, self, random.uniform(10, 30) 323 for item in self.heNeeds: 324 yield release, self, item 325 yield hold, self, 2 #rest 326 327 print '\n+++ nwaituntil demo output' 328 initialize() 329 brush = Resource(capacity = 1, name = 'brush') 330 ladder = Resource(capacity = 2, name = 'ladder') 331 hammer = Resource(capacity = 1, name = 'hammer') 332 saw = Resource(capacity = 1, name = 'saw') 333 painter = Worker('painter',[brush, ladder]) 334 activate(painter, painter.work()) 335 roofer = Worker('roofer',[hammer, ladder, ladder]) 336 activate(roofer, roofer.work()) 337 treeguy = Worker('treeguy',[saw, ladder]) 338 activate(treeguy, treeguy.work()) 339 for who in (painter, roofer, treeguy): 340 print '%s needs %s for his job' % (who.name,[x.name for x in who.heNeeds]) 341 print 342 print simulate(until = 9 * 60) 343 344 345 346 347 test_demo() 348 test_interrupt() 349 testSimEvents() 350 testwaituntil() 351