This chapter had some example from the SimPy web site and equivalent examples in the simulation collection.
| #!/usr/bin/env python |
| """ Simulate the operation of a BCC cellphone system using SimPy |
|
| """ |
| from __future__ import generators # not needed for Python 2.3+ |
| from SimPy.Simulation import * |
| from random import Random,expovariate |
|
| class Generator(Process): |
| """ generates a sequence of calls """ |
| def __init__(self, maxN, lam): |
| global busyEndTime |
| Process.__init__(self) |
| self.name = "generator" |
| self.maxN = maxN |
| self.lam = lam |
| self.iatime = 1.0/lam |
| self.rv = Random(gSeed) |
| busyEndTime = now() # simulation start time |
|
| def execute(self): |
| for i in range(self.maxN): |
| j = Job(i) |
| activate(j,j.execute()) |
| yield hold,self,self.rv.expovariate(lam) |
| self.trace("WARNING generator finished -- ran out of jobs") |
|
| def trace(self,message): |
| if GTRACING: print "%7.4f \t%s"%(self.time(), message) |
|
|
| class Job(Process): |
| """ instances of the Job class represent calls arriving at |
| random at the chnnels. |
| """ |
| def __init__(self,i): |
| Process.__init__(self) |
| self.i = i |
| self.name = "Job"+`i` |
|
| def execute(self): |
| global busyStartTime,totalBusyVisits,totalBusyTime |
| global Nfree,busyEndTime,Jrv |
| self.trace("arrived ") |
| if Nfree == 0: self.trace("blocked and left") |
| else: |
| self.trace("got a channel") |
| Nfree -= 1 |
| if Nfree == 0: |
| self.trace("start busy period======") |
| busyStartTime = now() |
| totalBusyVisits += 1 |
| interIdleTime = now() - busyEndTime |
| yield hold,self,Jrv.expovariate(mu) |
| self.trace("finished") |
| if Nfree == 0: |
| self.trace("end busy period++++++") |
| busyEndTime = now() |
| busy = now() - busyStartTime |
| self.trace(" busy = %9.4f"%(busy,)) |
| totalBusyTime +=busy |
| Nfree += 1 |
|
| def trace(self,message): |
| if TRACING: print "%7.4f \t%s %s "%(now(), message , self.name) |
|
|
| class Statistician(Process): |
| """ observes the system at intervals """ |
| def __init__(self,Nhours,interv,gap): |
| Process.__init__(self) |
| self.Nhours = Nhours |
| self.interv = interv |
| self.gap = gap |
| self.name="Statistician" |
|
| def execute(self): |
| global busyStartTime,totalBusyTime,totalBusyVisits |
| global hourBusyTime,hourBusyVisits |
| for i in range(self.Nhours): |
| yield hold,self,self.gap |
| totalBusyTime = 0.0 |
| totalBusyVisits = 0 |
| if Nfree == 0: busyStartTime = now() |
| yield hold,self,self.interv |
| if Nfree == 0: totalBusyTime += now()-busyStartTime |
| if STRACING: print "%7.3f %5d"%(totalBusyTime,totalBusyVisits) |
| m.tally(totalBusyTime) |
| bn.tally(totalBusyVisits) |
| print("Busy Time: mean = %10.5f var= %10.5f"%(m.mean(),m.var())) |
| print("Busy Number: mean = %10.5f var= %10.5f"%(bn.mean(),bn.var())) |
|
|
| def trace(self,message): |
| if STRACING: print "%7.4f \t%s"%(self.time(), message) |
|
| totalBusyVisits = 0 |
| totalBusyTime = 0.0 |
| NChannels = 4 # number of channels in the cell |
| Nfree = NChannels |
| maxN = 1000 |
| gSeed = 11111111 |
| JrvSeed = 3333333 |
| lam = 1.0 |
| mu = 0.6667 |
| meanLifeTime = 1.0/mu |
| TRACING = 0 |
| GTRACING = 0 |
| STRACING = 1 |
| Nhours = 10 |
| interv = 60.0 # monitor |
| gap = 15.0 # monitor |
| print "lambda mu s Nhours interv gap" |
| print "%7.4f %6.4f %4d %4d %6.2f %6.2f"%(lam,mu,NChannels,Nhours,interv,gap) |
|
| m = Monitor() |
| bn=Monitor() |
| Jrv = Random(JrvSeed) |
| s = Statistician(Nhours,interv,gap) |
| initialize() |
| g = Generator(maxN, lam) |
| activate(g,g.execute()) |
| activate(s,s.execute()) |
| simulate(until=10000.0) |
The output from the program follows.
| #lang scheme/base |
| |
| |
| (require (planet williams/simulation/simulation)) |
| (require (planet williams/science/random-distributions)) |
| |
| |
| |
| (define Nchannels 4) |
| (define maxN 1000) |
| (define lam 1.0) |
| (define mu 0.6667) |
| (define meanLifeTime (/ 1.0 mu)) |
| (define Nhours 10) |
| (define interv 60.0) |
| (define gap 15.0) |
| |
| |
| |
| (define Nfree Nchannels) |
| (define totalBusyVisits 0) |
| (define totalBusyTime 0.0) |
| (define busyStartTime 0.0) |
| (define busyEndTime 0.0) |
| |
| |
| |
| |
| (define m #f) |
| (define bn #f) |
| |
| (define-process (generator n) |
| (do ((i 0 (+ i 1))) |
| ((= i n) (void)) |
| (schedule now (job i)) |
| (wait (random-exponential (/ 1.0 lam))))) |
| |
| (define-process (job i) |
| (when (> Nfree 0) |
| (set! Nfree (- Nfree 1)) |
| (when (= Nfree 0) |
| |
| (set! busyStartTime (current-simulation-time)) |
| (set! totalBusyVisits (+ totalBusyVisits 1))) |
| (work (random-exponential (/ 1.0 mu))) |
| (when (= Nfree 0) |
| |
| (set! busyEndTime (current-simulation-time)) |
| (set! totalBusyTime (+ totalBusyTime |
| (- (current-simulation-time) |
| busyStartTime)))) |
| (set! Nfree (+ Nfree 1)))) |
| |
| (define-process (statistician) |
| (do ((i 0 (+ i 1))) |
| ((= i Nhours) (void)) |
| |
| (wait gap) |
| |
| (set! totalBusyTime 0.0) |
| (set! totalBusyVisits 0) |
| (when (= Nfree 0) |
| (set! busyStartTime (current-simulation-time))) |
| |
| (wait interv) |
| |
| (when (= Nfree 0) |
| (set! totalBusyTime (+ totalBusyTime |
| (- (current-simulation-time) |
| busyStartTime)))) |
| (printf "~a: busy time = ~a; busy visits = ~a~n" |
| (current-simulation-time) totalBusyTime totalBusyVisits) |
| |
| (set-variable-value! m totalBusyTime) |
| (set-variable-value! bn totalBusyVisits)) |
| |
| (printf "Busy time: mean = ~a, variance = ~a~n" |
| (variable-mean m) (variable-variance m)) |
| (printf "Busy number: mean = ~a, variance = ~a~n" |
| (variable-mean bn) (variable-variance bn))) |
| |
| (define (run-simulation) |
| (with-new-simulation-environment |
| |
| (printf "lambda = ~a~n" lam) |
| (printf "mu = ~a~n" mu) |
| (printf "s = ~a~n" Nchannels) |
| (printf "Nhours = ~a~n" Nhours) |
| (printf "interv = ~a~n" interv) |
| (printf "gap = ~a~n" gap) |
| |
| (set! Nfree Nchannels) |
| (set! totalBusyVisits 0) |
| (set! totalBusyTime 0.0) |
| (set! busyEndTime 0.0) |
| |
| (set! m (make-variable)) |
| (tally (variable-statistics m)) |
| (set! bn (make-variable)) |
| (tally (variable-statistics bn)) |
| |
| (schedule (at 0.0) (generator maxN)) |
| (schedule (at 0.0) (statistician)) |
| (schedule (at 10000.0) (stop-simulation)) |
| (start-simulation))) |
| |
| (run-simulation) |
The output from the program follows.
| #!/usr/bin/env python |
| """ |
| Simulation of a jackson queue network |
|
| """ |
| from __future__ import generators # not needed in Python 2.3+ |
| from SimPy.Simulation import * |
| from random import Random,expovariate,uniform |
|
| def sum(P): |
| """ Sum of the real vector P """ |
| sumP = 0.0 |
| for i in range(len(P)): sumP += P[i] |
| return (sumP) |
|
|
|
| def choose2dA(i,P,g): |
| """ return a random choice from a set j = 0..n-1 |
| with probs held in list of lists P[j] (n by n) |
| using row i |
| g = random variable |
| call: next = choose2d(i,P,g) |
| """ |
| U = g.random() |
| sumP = 0.0 |
| for j in range(len(P[i])): # j = 0..n-1 |
| sumP += P[i][j] |
| if U < sumP: break |
| return(j) |
|
| ## ----------------------------------------------- |
| class Msg(Process): |
| """a message""" |
| def __init__(self,i,node): |
| Process.__init__(self) |
| self.i = i |
| self.node = node |
|
| def execute(self): |
| """ executing a message """ |
| global noInSystem |
| startTime = now() |
| noInSystem += 1 |
| ##print "DEBUG noInSystm = ",noInSystem |
| NoInSystem.accum(noInSystem) |
| self.trace("Arrived node %d"%(self.node,)) |
| while self.node <> 3: |
| yield request,self,processor[self.node] |
| self.trace("Got processor %d"%(self.node,)) |
| st = Mrv.expovariate(1.0/mean[self.node]) |
| Stime.observe(st) |
| yield hold,self,st |
| yield release,self,processor[self.node] |
| self.trace("Finished with %d"%(self.node,)) |
| self.node = choose2dA(self.node,P,Mrv) |
| self.trace("Transfer to %d"%(self.node,)) |
| TimeInSystem.observe(now()-startTime) |
| self.trace( "leaving %d"%(self.node,),noInSystem) |
| noInSystem -= 1 |
| NoInSystem.accum(noInSystem) |
|
| def trace(self,message,nn=0): |
| if MTRACING: print "%7.4f %3d %10s %3d"%(now(),self.i, message,nn) |
|
|
| ## ----------------------------------------------- |
| class Generator(Process): |
| """ generates a sequence of msgs """ |
| def __init__(self, rate,maxT,maxN): |
| Process.__init__(self) |
| self.name = "Generator" |
| self.rate = rate |
| self.maxN = maxN |
| self.maxT = maxT |
| self.g = Random(11335577) |
| self.i = 0 |
|
| def execute(self): |
| while (now() < self.maxT) & (self.i < self.maxN): |
| self.i+=1 |
| p = Msg(self.i,startNode) |
| activate(p,p.execute()) |
| ## self.trace("starting "+p.name) |
| yield hold,self,self.g.expovariate(self.rate) |
| self.trace("generator finished with "+`self.i`+" ========") |
| self.stopSim() |
|
| def trace(self,message): |
| if GTRACING: print "%7.4f \t%s"%(now(), message) |
|
| ## ----------------------------------------------- |
| # generator: |
| GTRACING = 0 |
| # messages: |
| rate = 0.5 |
| noInSystem = 0 |
| MTRACING = 0 |
| startNode = 0 |
| maxNumber = 10000 |
| maxTime = 100000.0 |
| Mrv = Random(77777) |
| TimeInSystem=Monitor() |
| NoInSystem= Monitor() |
| Stime = Monitor() |
|
| processor = [Resource(1),Resource(1),Resource(1)] |
| mean=[1.0, 2.0, 1.0] |
| P = [[0, 0.5, 0.5, 0],[0,0,0.8,0.2], [0.2,0,0,0.8]] |
|
| initialize() |
| g = Generator(rate,maxTime,maxNumber) |
| activate(g,g.execute()) |
| simulate(until=100.0) |
|
| print "Mean numberm= %8.4f"%(NoInSystem.timeAverage(),) |
| print "Mean delay = %8.4f"%(TimeInSystem.mean(),) |
| print "Mean stime = %8.4f"%(Stime.mean(),) |
| print "Total jobs = %8d"%(TimeInSystem.count(),) |
| print "Total time = %8.4f"%(now(),) |
| print "Mean rate = %8.4f"%(TimeInSystem.count()/now(),) |
The following is the output from the program.
| #lang scheme/base |
| |
| |
| (require (planet williams/simulation/simulation-with-graphics)) |
| (require (planet williams/science/random-distributions)) |
| |
| |
| |
| (define n 3) |
| (define m #(1.0 2.0 1.0)) |
| (define p (vector |
| (make-discrete #(0.0 0.5 0.5 0.0)) |
| (make-discrete #(0.0 0.0 0.8 0.2)) |
| (make-discrete #(0.2 0.0 0.0 0.8)))) |
| (define np '(1 1 1)) |
| (define mu (/ 1.0 1.5)) |
| (define max-messages 10000) |
| |
| |
| |
| (define n-arrivals 0) |
| (define n-in-system #f) |
| (define time-in-system #f) |
| (define processor #f) |
| |
| |
| |
| (define-process (message i) |
| (let ((arrive-time (current-simulation-time)) |
| (work-duration 0.0)) |
| (set-variable-value! |
| n-in-system (+ (variable-value n-in-system) 1)) |
| (let loop ((node 0)) |
| (when (< node n) |
| (with-resource ((vector-ref processor node)) |
| (work (random-exponential (vector-ref m node)))) |
| (loop (random-discrete (vector-ref p node))))) |
| (set-variable-value! |
| n-in-system (- (variable-value n-in-system) 1)) |
| (set-variable-value! |
| time-in-system (- (current-simulation-time) |
| arrive-time)))) |
| |
| (define (generator) |
| (do ((i 0 (+ i 1))) |
| ((= i max-messages) (void)) |
| (set! n-arrivals (+ n-arrivals 1)) |
| (schedule now (message i)) |
| (wait (random-exponential (/ mu))))) |
| |
| (define (main) |
| (with-new-simulation-environment |
| |
| (set! n-arrivals 0) |
| (set! n-in-system (make-variable 0)) |
| (accumulate (variable-history n-in-system)) |
| (set! time-in-system (make-variable)) |
| (tally (variable-statistics time-in-system)) |
| (set! processor (list->vector |
| (map make-resource np))) |
| |
| (schedule (at 0.0) (generator)) |
| (schedule (at 5000.0) (stop-simulation)) |
| (start-simulation) |
| (printf "Mean number in system = ~a~n" (variable-mean n-in-system)) |
| (printf "Mean delay in system = ~a~n" (variable-mean time-in-system)) |
| (printf "Total time run = ~a~n" (current-simulation-time)) |
| (printf "Total jobs arrived = ~a~n" n-arrivals) |
| (printf "Total jobs completed = ~a~n" (variable-n time-in-system)) |
| (printf "Average arrival rate = ~a~n" (/ n-arrivals |
| (current-simulation-time))) |
| (write-special (history-plot (variable-history n-in-system))) |
| (newline))) |
| |
| (main) |
The following is the output from the program.