class HighwayAnalyzeWidget(QWidget): def __init__(self): super(HighwayAnalyzeWidget,self).__init__() self.averageSimulationTime = 325.0 mainLayout = QVBoxLayout() mainLayout.setAlignment(Qt.AlignTop|Qt.AlignHCenter) mainLayout.setSpacing(0) self.setLayout(mainLayout) topWidget = QWidget() self.topLayout = QHBoxLayout() self.topLayout.setSpacing(0) topWidget.setLayout(self.topLayout) topLeftWidget = QWidget() self.topLeftLayout = QVBoxLayout() topLeftWidget.setLayout(self.topLeftLayout) self.setupTopGroup() self.setupFilterGroup() self.topLayout.addWidget(topLeftWidget) self.layout().addWidget(topWidget) # Button and log buttonAndLogWidget = QWidget() buttonAndLogWidget.setLayout(QVBoxLayout()) # Analyze the results BUTTON self.analyzeResultsButton = QPushButton('Analyze the results') self.analyzeResultsButton.clicked.connect(self.analyzeResults) self.analyzeResultsButton.setEnabled(False) buttonAndLogWidget.layout().addWidget(self.analyzeResultsButton) # LOG self.logText = QTextBrowser() self.logText.setFont(QFont('Century Gothic', 7)) self.logText.setWordWrapMode(QTextOption.NoWrap) buttonAndLogWidget.layout().addWidget(self.logText) self.topLayout.addWidget(buttonAndLogWidget) self.results = [] self.logFile = os.path.join(self.resultsPath(), 'analyze_'+os.uname()[1]+'.log') # Image self.picLabel = QLabel() self.picLabel.setAlignment(Qt.AlignHCenter) #self.picLabel.resize(800,600) self.picLabel.setMinimumSize(800,600) self.layout().addWidget(self.picLabel) def setupTopGroup(self): topGroup = QGroupBox("Simulation Results") self.resultsPathLineEdit = SimpleOption('resultsPath','Results Path','/home/thomas/Dropbox/Keio/research/results/') topGroupLayout = QVBoxLayout() topGroupLayout.setSpacing(0) topGroupLayout.setAlignment(Qt.AlignTop) topGroupLayout.addWidget(self.resultsPathLineEdit) self.loadResultsLabel = QLabel() self.loadResultsLabel.setAlignment(Qt.AlignHCenter) topGroupLayout.addWidget(self.loadResultsLabel) self.loadResultsButton = QPushButton("Load the results") self.loadResultsButton.clicked.connect(self.loadResults) topGroupLayout.addWidget(self.loadResultsButton) topGroup.setLayout(topGroupLayout) self.topLeftLayout.addWidget(topGroup) def resultsPath(self): return self.resultsPathLineEdit.getValue() def setupFilterGroup(self): filterGroup = QGroupBox('Filter the results') filterGroupLayout = QVBoxLayout() filterGroupLayout.setSpacing(0) filterGroupLayout.setAlignment(Qt.AlignTop) # Distribution Model self.filterDistribution = SimpleComboboxOption('dis','Speed Distribution Model',3, True, 'Uniform','Exponential','Normal','Log Normal') filterGroupLayout.addWidget(self.filterDistribution) self.filterDistribution.setVisible(False) # Number of results per point self.filterNb = SimpleSpinOption('simuNbMin', 'Minimum results for a given setting', 10, integer=True, checkable=True) self.filterNb.checkBox.setChecked(True) filterGroupLayout.addWidget(self.filterNb) # Filter the date dateWidget = QWidget() dateWidget.setLayout(QHBoxLayout()) self.filterDate = QCheckBox('After') self.filterDate.setChecked(QSettings().value('filterDate','0')=='1') dateWidget.layout().addWidget(self.filterDate) self.filterDateYear = QComboBox() for m in xrange(2010,2012): self.filterDateYear.addItem(str(m)) self.filterDateYear.setCurrentIndex(int(QSettings().value('dateYear', 1))) dateWidget.layout().addWidget(self.filterDateYear) dateWidget.layout().addWidget(QLabel('Year')) self.filterDateMonth = QComboBox() for m in xrange(1,13): self.filterDateMonth.addItem(str(m)) self.filterDateMonth.setCurrentIndex(int(QSettings().value('dateMonth', 4))) dateWidget.layout().addWidget(self.filterDateMonth) dateWidget.layout().addWidget(QLabel('Month')) self.filterDateDay = QComboBox() for d in xrange(1,32): self.filterDateDay.addItem(str(d)) self.filterDateDay.setCurrentIndex(int(QSettings().value('dateDay', 0))) dateWidget.layout().addWidget(self.filterDateDay) dateWidget.layout().addWidget(QLabel('Day')) filterGroupLayout.addWidget(dateWidget) filterGroup.setLayout(filterGroupLayout) self.topLeftLayout.addWidget(filterGroup) # Filter the scenario self.filterScenar = SimpleComboboxOption('scenar','Scenario',1, True, 'vanet-highway-test-thomas','vanet-highway-scenario2') filterGroupLayout.addWidget(self.filterScenar) # Filter gap self.filterGap = SimpleSpinOption('avgdistanalyze','Average Distance (m)',100, checkable=True) filterGroupLayout.addWidget(self.filterGap) def loadResults(self): self.loadResultsButton.setText('Loading the results...') self.loadResultsButton.setEnabled(False) self.results = [] self.resultsThread = LoadResults(resultsPath=self.resultsPath()) self.resultsThread.done.connect(self.loadResultsDone) self.resultsThread.error.connect(self.loadResultsError) self.resultsThread.start() @Slot(str) def loadResultsError(self, errorMsg): QMessageBox.critical(self, 'Error!', errorMsg) self.analyzeResultsButton.setEnabled(False) @Slot(dict) def loadResultsDone(self, results): self.results = results resultsNb = len(self.results) msg= 'Found %d Simulation Results\n(%d invalid files, %d simulations failed)' % (resultsNb, self.resultsThread.fileUnloadable, self.resultsThread.simulationFailed) self.loadResultsLabel.setText(msg) #self.calculateAverageSimulationTime() self.loadResultsButton.setText('Reload the results') self.loadResultsButton.setEnabled(True) self.analyzeResultsButton.setEnabled(True) if resultsNb>0: self.analyzeResults() def calculateAverageSimulationTime(self): totalTime = 0 nb = 0 for r in self.results: if 'simulationTime' in r: #print 'simu time: %s' % r['simulationTime'] totalTime += int(r['simulationTime']) nb += 1 #print 'from %s: [%3.3f,%3.3f]' % (r['filename'], r['settings']['prate'],r['results']['timeToReachDest']) if nb<=0: errorMsg= 'No simulation found with simulationTime' QMessageBox.critical(self, 'Error!', errorMsg) self.averageSimulationTime = 290.0 else: self.averageSimulationTime= totalTime/nb self.loadResultsLabel.setText(self.loadResultsLabel.text()+'\nAverage simulation time: %3.0f'%self.averageSimulationTime) def fil(self, r): return self.checkDis(r) and self.checkDate(r) and self.checkGap(r) and self.checkScenario(r) def checkDis(self,r): return (not self.filterDistribution.checkBox.isChecked()) or r['settings']['dis']==self.filterDistribution.getValue() def checkDate(self, r): return (not self.filterDate.isChecked()) or (r['date'] >= datetime(int(self.filterDateYear.currentText()), int(self.filterDateMonth.currentText()), int(self.filterDateDay.currentText()))) def checkScenario(self, r): return (not self.filterScenar.checkBox.isChecked()) or r['scenario']==self.filterScenar.getName() def checkGap(self, r): return (not self.filterGap.checkBox.isChecked()) or float(r['settings']['avgdist'])==float(self.filterGap.getValue()) def analyzeResults(self): self.saveSettings() if len(self.results)<=0: QMessageBox.critical(self, 'Error!', 'No results loaded :s') return self.log("=== ANALYZING RESULTS ===") self.logText.clear() p=0 meanValues = {} uniqueName = dateToFilename() gnuPlotDataFile =os.path.join(self.resultsPath(),'graphs/' + uniqueName+'.dat') with open(gnuPlotDataFile,'w') as data: while p<=100: nb = 0 totalTimeToReachDest = 0 totalSimulationTime = 0 for result in filter(lambda x: x['settings']['prate']==p and self.fil(x), self.results): totalSimulationTime += float(result['simulationTime']) totalTimeToReachDest += float(result['results']['timeToReachDest']) nb += 1 if self.filterNb.checkBox.isChecked(): minNb = self.filterNb.getValue() else: minNb = 0 if nb>minNb: meanSimulationTime = float(1.0*totalSimulationTime/nb) meanTimeToReachDest = float(1.0*totalTimeToReachDest/nb) meanValues[p] = {'prate':p, 'simuLationTime':meanSimulationTime, 'simulationsNb':nb, 'timeToReachDest':meanTimeToReachDest} self.log(meanValues[p]) toPlot = '%s %s' % (p, meanValues[p]['timeToReachDest']) #print toPlot data.write(toPlot+'\n') p += 1 data.close() if len(meanValues)>0: outputPic = 'graphs/' + uniqueName s = subprocess.Popen(['./toPlot.sh', outputPic, gnuPlotDataFile], cwd=self.resultsPath()) s.wait() outputPicPath = os.path.join(self.resultsPath(),outputPic+'.svg') pic = QImage(outputPicPath) #pic = pic.scaled(QSize(640,480)) self.picLabel.setPixmap(QPixmap(pic)) #os.system(os.path.join(self.resultsPath(),'toPlot.sh')) else: QMessageBox.critical(self, 'Error!', 'No simulation satisfies the criteria...') def log(self, txt): toLog = str(txt) toLogFile = '%s | %s' % (datetime.now(), txt) with open(self.logFile, 'a') as logFile: logFile.write(toLogFile+'\n') self.logText.append(toLog) def saveSettings(self): QSettings().setValue('simuNbMin', self.filterNb.getValue()) QSettings().setValue('avgdistanalyze', self.filterGap.getValue()) QSettings().setValue('scenar', self.filterScenar.getValue()) QSettings().setValue('dis', self.filterDistribution.getValue()) QSettings().setValue('dateDay', self.filterDateDay.currentIndex()) QSettings().setValue('dateMonth', self.filterDateMonth.currentIndex()) QSettings().setValue('dateYear', self.filterDateYear.currentIndex()) if self.filterDate.isChecked(): QSettings().setValue('filterDate', '1') else: QSettings().setValue('filterDate', '0')
class HighwaySimulatorGui(QMainWindow): def __init__(self): super(HighwaySimulatorGui, self).__init__() centralTab = QTabWidget() mainWidget = QWidget() self.resultsWidget = HighwayAnalyzeWidget() centralTab.addTab(mainWidget, 'Run') centralTab.addTab(self.resultsWidget, 'Analyze') self.setCentralWidget(centralTab) centralLayout = QVBoxLayout() #centralLayout.setSpacing(0) centralLayout.setAlignment(Qt.AlignTop) gridWidget = QWidget() gridLayout = QGridLayout() gridLayout.setSpacing(0) gridWidget.setLayout(gridLayout) mainWidget.setLayout(centralLayout) self.options = dict() # GENERAL generalGroup = QGroupBox('General Settings') generalGroup.setLayout(QVBoxLayout()) generalGroup.layout().setSpacing(0) self.pathOption = SimpleOption('path','Output Path','/home/thomas/Dropbox/Keio/research/results/') generalGroup.layout().addWidget(self.pathOption) self.scenarioOption = SimpleComboboxOption('scenario','Scenario',1, False, 'vanet-highway-test-thomas','vanet-highway-scenario2') self.scenarioOption.combo.currentIndexChanged[int].connect(self.scenarioChanged) generalGroup.layout().addWidget(self.scenarioOption) self.options['time'] = SimpleSpinOption('time','Simulation Time (sec.)',1500,True) self.options['time'].setRange(0,3000) self.options['mix'] = SimpleSpinOption('mix','Percentage of cars compare to trucks (%)',80,True) self.options['mix'].setRange(0,100) self.options['gap'] = SimpleSpinOption('gap','Average Gap (m.)',5) self.options['gap'].setRange(1,2000) self.options['lane'] = SimpleSpinOption('lane','Number of Lanes',2,True) self.options['lane'].setRange(2,4) self.options['spl'] = SimpleSpinOption('spl','Speed Limit (km/h)',130,True) self.options['spl'].setRange(1,200) for widget in ('time','mix','gap','lane','spl'): generalGroup.layout().addWidget(self.options[widget]) gridLayout.addWidget(generalGroup,0,0) # TRAFFIC trafficGroup = QGroupBox('Traffic Settings') trafficGroup.setLayout(QVBoxLayout()) trafficGroup.layout().setSpacing(0) # m/s = (km/h)*1000/3600 self.options['vel1'] = SimpleSpinOption('vel1','Average Speed (km/h)',105,True) self.options['vel1'].setRange(5,150) self.options['dis'] = SimpleComboboxOption('dis','Speed Distribution Model',3, False, 'Uniform','Exponential','Normal','Log Normal') self.options['spstd'] = SimpleSpinOption('spstd','Speed Distribution Variance',1.0) self.options['spstd'].setRange(0,50) self.options['flow1'] = SimpleSpinOption('flow1','Traffic Flow Mean (veh/s)',1.0) self.options['flow1'].setRange(0.1,50.0) self.options['std1'] = SimpleSpinOption('std1','Traffic Flow Variance',0.8) self.options['std1'].setRange(0.1,50.0) self.options['maxflow'] = SimpleSpinOption('maxflow','Traffic Maximum Flow (veh/s)',5) self.options['maxflow'].setRange(0.1,50.0) # Scenar 2 self.options['avgdist'] = SimpleSpinOption('avgdist','Average Distance (m)',100) self.options['avgdist'].setRange(1,10000) self.options['avgspeed'] = SimpleSpinOption('avgspeed','Average Speed (km/h)',105) self.options['avgspeed'].setRange(1,10000) self.options['despeed'] = SimpleSpinOption('despeed','Desired Speed (km/h)',130) self.options['despeed'].setRange(1,10000) self.options['ambumaxspeed'] = SimpleSpinOption('ambumaxspeed','Ambu Max Speed (km/h)',165) self.options['ambumaxspeed'].setRange(1,10000) self.options['ambuinitspeed'] = SimpleSpinOption('ambuinitspeed','Ambu Initial Speed (km/h)',130) self.options['ambuinitspeed'].setRange(1,10000) for widget in ('vel1','dis','spstd','flow1','std1','maxflow', 'avgdist', 'avgspeed', 'despeed', 'ambumaxspeed', 'ambuinitspeed'): trafficGroup.layout().addWidget(self.options[widget]) self.scenarioChanged(self.scenarioOption.combo.currentIndex()) gridLayout.addWidget(trafficGroup,0,1) # VANET vanetGroup = QGroupBox('VANET Settings') vanetGroup.setLayout(QVBoxLayout()) vanetGroup.layout().setSpacing(0) # self.options['prate'] = SimpleSpinOption('prate','Penetration Rate of VANET (%)',100,True) # self.options['prate'].setRange(0,100) self.options['prate'] = 0 # start with 0 self.options['pw'] = SimpleSpinOption('pw','Transmission Power (dBm)',21.5) self.options['pw'].setRange(10,50) #for widget in ('prate','pw'): for widget in ('pw',): vanetGroup.layout().addWidget(self.options[widget]) gridLayout.addWidget(vanetGroup,1,0) # BATCH SETTINGS batchGroup = QGroupBox("Batch Settings") batchGroup.setLayout(QVBoxLayout()) self.gapPrateOption = SimpleSpinOption('gapPrate', 'VANET percentage rate gap', 10, integer=True) self.sameSimuTimesOption = SimpleSpinOption('sameSimuTimes', 'How many times the same simulation', 100, integer=True) batchGroup.layout().setSpacing(0) batchGroup.layout().addWidget(self.gapPrateOption) batchGroup.layout().addWidget(self.sameSimuTimesOption) gridLayout.addWidget(batchGroup,1,1) # START SIMU centralLayout.addWidget(gridWidget) self.startButton = QPushButton('START') self.startButton.clicked.connect(self.startSimu) centralLayout.addWidget(self.startButton) self.progressBar = QProgressBar() centralLayout.addWidget(self.progressBar) self.shutdownWhenDone = QCheckBox('Shutdown when done') self.actionWhenDone = QComboBox() self.actionWhenDone.addItems(['When finished... do nothing', 'When finished... shutdown the computer', 'When finished... Re-run the simulations!']) self.actionWhenDone.setCurrentIndex(int(QSettings().value('actionWhenDone', 0))) centralLayout.addWidget(self.actionWhenDone) self.infoLabel = QLabel() centralLayout.addWidget(self.infoLabel) # LOG self.logText = QTextBrowser() self.logText.setFont(QFont('Century Gothic', 7)) centralLayout.addWidget(self.logText) self.setWindowTitle('Nishimura Lab | Highway Simulation') #self.resize(520,len(self.options)*60+100) #self.resultFile = open('/home/thomas/Dropbox/Keio/research/results/summary.txt', 'a') #self.resultFile = os.path.join(self.pathOption.getValue(), 'summary.txt') self.logFile = os.path.join(self.pathOption.getValue(), 'results_'+os.uname()[1]+'.log') @Slot(int) def scenarioChanged(self, index): #print index scenar1options = ['gap', 'vel1', 'dis', 'flow1', 'std1','spstd', 'maxflow'] scenar2options = ['avgdist', 'avgspeed', 'despeed', 'ambumaxspeed', 'ambuinitspeed'] if index==0: # first scenario scenar1 = True scenar2 = False else: scenar1 = False scenar2 = True for option in scenar1options: self.options[option].setVisible(scenar1) for option in scenar2options: self.options[option].setVisible(scenar2) def log(self, txt): toLog = '%s | %s' % (datetime.now(), txt) with open(self.logFile, 'a') as logFile: logFile.write(toLog+'\n') self.logText.append(toLog) def blockUi(self): self.startButton.setEnabled(False) self.scenarioOption.setEnabled(False) for option in self.options: if option!='prate': self.options[option].setEnabled(False) def releaseUi(self): self.startButton.setEnabled(True) self.scenarioOption.setEnabled(True) self.startButton.setText('START') for option in self.options: if option!='prate': self.options[option].setEnabled(True) def startSimu(self): self.log("=== SIMULATIONS START ===") self.logText.clear() self.startTime = datetime.now() self.simulations = [] #self.nextPrate = 0 self.gapPrate = self.gapPrateOption.getValue() self.sameSimuTimes = self.sameSimuTimesOption.getValue() #self.nextSimu = 0 self.blockUi() self.simulationsDone = 0 #output = self.pathOption.getValue() + dateToFilename(d) + '_results.txt' pRate = 0 self.simulationsTotal = 0 # print 'sameSimuTimes: %d'%self.sameSimuTimes # print 'gapPrate: %d'%self.gapPrate while pRate <= 100: simu = 0 self.options['prate'] = pRate while simu<self.sameSimuTimes: waf = WafThread(self.options, self.pathOption.getValue(), self.scenarioOption.getName()) waf.setAutoDelete(True) waf.simuDone.connect(self.wafDone) self.simulations.append(waf) QThreadPool.globalInstance().start(waf) self.simulationsTotal += 1 simu += 1 pRate += self.gapPrate runningSimulations = 'Running %d Simulations...' % self.simulationsTotal self.startButton.setText(runningSimulations) self.log(runningSimulations) self.progressBar.setRange(0,self.simulationsTotal) self.progressBar.setValue(0) # 300 seconds per task average roughTime = self.simulationsTotal*self.resultsWidget.averageSimulationTime/QThreadPool.globalInstance().maxThreadCount() self.infoLabel.setText('Rough time estimation: %s' % formatTimeLeft(roughTime)) @Slot(str) def wafDone(self, outputPath): #print 'thread done!\nReceived:' self.simulationsDone += 1 simulationsLeft = self.simulationsTotal-self.simulationsDone with open(outputPath,'r') as out: r = json.loads(out.read()) out.close() if 'timeToReachDest' in r['results']: try: result = "%3.3d\t%f" % (int(r['settings']['prate']),float(r['results']['timeToReachDest'])) except TypeError, e: result = 'PYTHON ERROR: %s | File: %s' % (e, outputPath) print result print r else: