1
2
3 """SimGUI 1.8 Provides a Tk/Tkinter-based framework for SimPy simulation
4 models.
5
6 LICENSE:
7 Copyright (C) 2002,2003,2004,2005,2006,2007 Klaus G. Muller, Tony Vignaux
8 mailto: kgmuller@xs4all.nl and Tony.Vignaux@vuw.ac.nz
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 END OF LICENSE
24
25 SimGUI uses a Tkinter-based console for conversing with the Python interpreter,
26 developed by Ka-Ping Yee, <ping@lfw.org>.
27
28
29 **Change history:**
30 October through December 2003:
31 Development of SimGUI, with outstanding support by
32 Prof. Simon Frost of University of California, San Diego
33 as co-designer/co-implementor.
34 Simon also contributed the idea of using Ka-Ping Yee's
35 Python interpreter console.
36
37 December 16, 2003: Completion of 1.4alpha version (fully compatible with
38 SimPy 1.4alpha).
39
40 February 2004: Release as part of SimPy 1.4
41
42 """
43
44 from __future__ import generators
45 from Tkinter import *
46 from tkMessageBox import *
47 from Canvas import Line, CanvasText, Rectangle
48 import tkconsole as tkcons
49
50 __version__ = '1.8 $Revision: 1.1.1.9 $ $Date: 2007/01/08 14:46:36 $'
51
53 - def __init__(self,win,title="SimGUI",doc="No doc string found",consoleHeight=50):
54 self.root=win
55 self.doc=doc
56 self.title=title
57 win.title(title)
58 self.win=self.root
59 self.noRunYet=True
60 self.makeMenu()
61 self.makeConsole(consoleHeight)
62
65
75 self.file = Menu(self.top)
76 self.file.add_command(label='Save console content',
77 command=self.saveConsole, underline=0)
78 self.file.add_command(label='Quit',
79 command=self.win.quit,underline=0)
80 self.top.add_cascade(label='File',menu=self.file,underline=0)
82 self.edit = Menu(self.top)
83 self.edit.add_command(label='Change parameters',
84 command=self.changeParameters, underline=0)
85 self.edit.add_command(label='Clear console',
86 command=self.clearConsole, underline=1)
87 self.top.add_cascade(label='Edit',
88 menu=self.edit, underline=0)
90 self.run = Menu(self.top)
91 self.top.add_cascade(label='Run',
92 menu=self.run, underline=0)
94 self.view = Menu(self.top)
95 self.view.add_command(label="Collected data",
96 command=self.showMonitors, underline=0)
97 self.top.add_cascade(label='View',
98 menu=self.view, underline=0)
100 self.help = Menu(self.top)
101 self.help.add_command(label='About SimGUI',
102 command=self._aboutSimGUI,underline=6)
103 self.help.add_command(label='Model description',
104 command=self.about,underline=6)
105 self.help.add_command(label='Model code',
106 command=self.showcode,underline=6)
107 self.help.add_command(label='Python interpreter',
108 command=self.makeInterpreter,underline=0)
109 self.top.add_cascade(label='Help',menu=self.help,underline=0)
110
112 scrollbar=Scrollbar(self.root)
113 scrollbar.pack(side=RIGHT,fill=Y)
114 textOutput=Frame(self.root)
115
116 self.topconsole=Label(textOutput,text="")
117 self.topconsole.pack()
118
119 self.console=Text(textOutput,height=height,wrap=WORD,yscrollcommand=scrollbar.set)
120 self.console.pack()
121 scrollbar.config(command=self.console.yview)
122 textOutput.pack()
123
125 self.console.insert(END,"%s\n"%text)
126 self.root.update()
127
131
133 from tkFileDialog import asksaveasfilename
134
135 content=self.console.get('1.0',END+'-1c')
136
137 filename=asksaveasfilename()
138 if not filename[-4:] == '.txt':
139 filename+=".txt"
140 fi=open(filename,'wb')
141 fi.write(content)
142 fi.close()
143
145 self.console.delete('1.0',END)
146
148 "Show SimPy/Python code of this program"
149 import sys
150 tl=Toplevel()
151 tl.title(self.title+" - Code")
152 t=Text(tl,width=80)
153 scroll=Scrollbar(tl,command=t.yview)
154 t.configure(yscrollcommand=scroll.set)
155 sourcefile= sys.argv[0]
156 source=""
157 for i in open(sourcefile).readlines():
158 source=source+i
159 t.insert(END,source)
160 t.pack(side=LEFT)
161 scroll.pack(side=RIGHT,fill=Y)
162
164 self.showTextBox(width=80,height=30,text=self.doc,
165 title=self.title+" - Model information")
166
168 t=Toplevel()
169 t.title("About SimGUI")
170 tx=Text(t,width=60,height=7)
171 txt="SimGUI version %s\n\nSimGUI is a framework for SimPy-based simulations. "%__version__+\
172 "It has been developed by Klaus Muller, Simon Frost and Tony Vignaux. \n"+\
173 "\n\nHomepage and download: simpy.sourceforge.net\n"
174 tx.insert(END,txt)
175 tx.pack()
176
178 showerror('Not implemented','Not yet available')
179
180 - def showTextBox(self,width=60,height=10,text=" ",title=" "):
181 tl=Toplevel()
182 tl.title(title)
183 txt=text
184 t=Text(tl,width=width,height=height,wrap=WORD)
185 t.insert(END,txt)
186 t.pack()
187
189 self._monitors=[]
190 for k in self.__dict__.keys():
191 a =self.__dict__[k]
192 if isinstance(a,list) and hasattr(a,'tseries') and hasattr(a,'yseries'):
193 self._monitors.append(a)
194
196 if self.noRunYet:
197 showwarning('SimGUI warning','Run simulation first!')
198 return
199 self.findMonitors()
200 if not self._monitors:
201 showwarning("SimGUI warning","No Monitor instances found")
202 for m in self._monitors:
203 self.writeConsole("\nMonitor '%s':\n"%m.name)
204 dat=m
205 try:
206 xlab=m.tlab
207 except:
208 xlab='x'
209 try:
210 ylab=m.ylab
211 except:
212 ylab='y'
213 sep=",\t"
214 self.writeConsole("%s%s%s"%(xlab,sep,ylab))
215 for this in dat:
216 self.writeConsole("%s%s%s"%(this[0],sep,this[1]))
217 self.writeConsole()
218
220 """Finds the instance of Parameters (there may only be one)
221 and associates it with self._parameters"""
222 self._parameters=None
223 for k in self.__dict__.keys():
224 a=self.__dict__[k]
225 if isinstance(a,Parameters):
226 self._parameters=a
227
229 """Offers entry fields for parameter change"""
230
231 self.findParameters()
232 if not self._parameters:
233 showwarning("SimGUI warning","No Parameters instance found.")
234 return
235 t1=Toplevel(self.root)
236 top=Frame(t1)
237 self.lbl={}
238 self.ent={}
239 i=1
240 for p in self._parameters.__dict__.keys():
241 self.lbl[p]=Label(top,text=p)
242 self.lbl[p].grid(row=i,column=0)
243 self.ent[p]=Entry(top)
244 self.ent[p].grid(row=i,column=1)
245 self.ent[p].insert(0,self._parameters.__dict__[p])
246 i+=1
247 top.pack(side=TOP,fill=BOTH,expand=YES)
248 commitBut=Button(top,text='Change parameters',command=self.commit)
249 commitBut.grid(row=i,column=1)
250
252 """Commits parameter changes, i.e. updates self._parameters"""
253 for p in self._parameters.__dict__.keys():
254 this=self._parameters.__dict__
255 tipo=type(this[p])
256 if tipo==type(1):
257 try:
258 this[p]=int(self.ent[p].get())
259 except:
260 showerror(title="Input error",
261 message="Type Error; correct parameter '%s' to %s"%(p,tipo))
262 elif tipo==type(1.1):
263 try:
264 this[p]=float(self.ent[p].get())
265 except:
266 showerror(title="Input error",
267 message="Type Error; correct parameter '%s' to %s"%(p,tipo))
268 elif this==type("abc"):
269 try:
270 this[p]=self.ent[p].get()
271 except:
272 showerror(title="Input error",
273 message="Type Error; correct parameter '%s' to %s"%(p,tipo))
274 elif tipo==type([]):
275 try:
276 a=eval(self.ent[p].get())
277 if type(a)==type([]):
278 this[p]=a
279 except:
280 showerror(title="Input error",
281 message="Type Error; correct parameter '%s' to %s"%(p,tipo))
282 else:
283 showerror(title="Application program error",
284 message="Parameter %s has unsupported type"%p)
285 self.noRunYet=True
286
288 i=Toplevel(self.root)
289 interpreter=tkcons.Console(parent=i)
290 interpreter.dict['SimPy']=self
291 interpreter.pack(fill=BOTH,expand=1)
292
295 self.__dict__.update(kwds)
297 return str(self.__dict__)
299 return str(self.__dict__)
301 res=[]
302 for i in self.__dict__.keys():
303 res.append("%s : %s\n"%(i,self.__dict__[i]))
304 return "".join(res)
305
306 if __name__ == '__main__':
307 print "SimGUI.py %s"%__version__
308 from SimPy.Simulation import *
309 from SimPy.Monitor import *
310 from random import Random
311
313 """ Source generates customers randomly"""
317
319 rv = Random(self.SEED)
320 for i in range(number):
321 c = Customer(name = "Customer%02d"%(i,))
322 activate(c,c.visit(timeInBank=12.0))
323 t = rv.expovariate(1.0/interval)
324 yield hold,self,t
325
327 """ The number of customers in the resource R
328 in waitQ and active Q"""
329 return (len(R.waitQ)+len(R.activeQ))
330
332 """ Customer arrives, is served and leaves """
336
337 - def visit(self,timeInBank=0):
338 arrive=now()
339 Qlength = [NoInSystem(counter[i]) for i in range(Nc)]
340
341 for i in range(Nc):
342 if Qlength[i] ==0 or Qlength[i]==min(Qlength): join =i ; break
343 yield request,self,counter[join]
344 wait=now()-arrive
345 waitMonitor.observe(wait,t=now())
346
347 tib = counterRV.expovariate(1.0/timeInBank)
348 yield hold,self,tib
349 yield release,self,counter[join]
350 serviceMonitor.observe(now()-arrive,t=now())
351 if trace:
352 gui.writeConsole("Customer leaves at %.1d"%now())
353
355 global Nc,counter,counterRV,waitMonitor,serviceMonitor,trace,lastLeave,noRunYet,initialized
356 counterRV = Random(gui.params.counterseed)
357 sourceseed = gui.params.sourceseed
358 nrRuns=gui.params.nrRuns
359 lastLeave=0
360 gui.noRunYet=True
361 for runNr in range(nrRuns):
362 gui.noRunYet=False
363 trace=gui.params.trace
364 if trace:
365 gui.writeConsole(text='\n** Run %s'%(runNr+1))
366 Nc = 2
367 counter = [Resource(name="Clerk0"),Resource(name="Clerk1")]
368 gui.waitMon=waitMonitor = Monitor(name='Waiting Times')
369 waitMonitor.tlab='Time'
370 waitMonitor.ylab='Customer waiting time'
371 gui.serviceMon=serviceMonitor = Monitor(name='Service Times')
372 serviceMonitor.xlab='Time'
373 serviceMonitor.ylab='Total service time = wait+service'
374 initialize()
375 source = Source(seed = sourceseed)
376 activate(source,source.generate(gui.params.numberCustomers,gui.params.interval),0.0)
377 result=simulate(until=gui.params.endtime)
378 lastLeave+=now()
379 gui.writeConsole("%s simulation run(s) completed\n"%nrRuns)
380 gui.writeConsole("Parameters:\n%s"%gui.params.show())
381 gui.writeStatusLine("Time: %.2f "%now())
382
384 if gui.noRunYet:
385 showwarning(title='Model warning',
386 message="Run simulation first -- no data available.")
387 return
388 aver=lastLeave/gui.params.nrRuns
389 gui.writeConsole(text="Average time for %s customers to get through bank: %.1f\n(%s runs)\n"\
390 %(gui.params.numberCustomers,aver,gui.params.nrRuns))
391
392 __doc__="""
393 Modified bank11.py (from Bank Tutorial) with GUI.
394
395 Model: Simulate customers arriving at random, using a Source, requesting service
396 from two counters each with their own queue with random servicetime.
397
398 Uses Monitor objects to record waiting times and total service times."""
399
401 gui.showTextBox(text="Tony Vignaux\nKlaus Muller",title="Author information")
404 SimGUI.__init__(self,win,**p)
405 self.help.add_command(label="Author(s)",
406 command=showAuthors,underline=0)
407 self.view.add_command(label="Statistics",
408 command=statistics,underline=0)
409 self.run.add_command(label="Run",
410 command=model,underline=0)
411
412
413
414 root=Tk()
415 gui=MyGUI(root,title="SimPy GUI example",doc=__doc__,consoleHeight=40)
416 gui.params=Parameters(endtime=2000,
417 sourceseed=1133,
418 counterseed=3939393,
419 numberCustomers=50,
420 interval=10.0,
421 trace=0,
422 nrRuns=1)
423 gui.mainloop()
424