Path: blob/main/tools/output/generateITetrisIntersectionMetrics.py
169674 views
#!/usr/bin/env python1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2# Copyright (C) 2009-2025 German Aerospace Center (DLR) and others.3# This program and the accompanying materials are made available under the4# terms of the Eclipse Public License 2.0 which is available at5# https://www.eclipse.org/legal/epl-2.0/6# This Source Code may also be made available under the following Secondary7# Licenses when the conditions for such availability set forth in the Eclipse8# Public License 2.0 are satisfied: GNU General Public License, version 29# or later which is available at10# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1213# @file generateITetrisIntersectionMetrics.py14# @author Daniel Krajzewicz15# @author Lena Kalleske16# @author Michael Behrisch17# @date 2007-10-251819from __future__ import absolute_import20from __future__ import print_function21from optparse import OptionParser22import os23import sys24from numpy import mean, log25from xml.sax import parse, handler26sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))27import sumolib.net # noqa282930def getBasicStats(net, lanesInfo, T):31tlsInfo = {}32for tl in net._tlss:33tlID = tl._id34mQueueLen = []35# mWaitTime = []36nbStops = []37tWaitTime = []38seenLanes = set()39for conn in tl._connections:40lane = conn[0]41if lane in seenLanes:42continue43seenLanes.add(lane)44mQueueLenInfo = sum(lanesInfo[lane.getID()]['mQueueLen'])45mQueueLen.append(mQueueLenInfo)46# mWaitTimeInfo = mean(lanesInfo[lane.getID()]['mWaitTime'])47# mWaitTime.append(mWaitTimeInfo)48nbStopsInfo = sum(lanesInfo[lane.getID()]['nbStops'])49nbStops.append(nbStopsInfo)50tWaitTimeInfo = sum(lanesInfo[lane.getID()]['tWaitTime'])51tWaitTime.append(tWaitTimeInfo)52tlsInfo[tlID] = {}53tlsInfo[tlID]['mQueueLen'] = mean(mQueueLen) / T54tlsInfo[tlID]['mWaitTime'] = mean(tWaitTime) / T55tlsInfo[tlID]['nbStops'] = sum(nbStops)56tlsInfo[tlID]['tWaitTime'] = sum(tWaitTime)57return tlsInfo585960def mergeInfos(tlsInfoAll, tlsInfoOne, metric):61for tl in tlsInfoOne.keys():62tlsInfoAll[tl][metric] = tlsInfoOne[tl]636465def getStatisticsOutput(tlsInfo, outputfile):66with open(outputfile, 'w') as opfile:67for tl in tlsInfo.keys():68opfile.write('Traffic Light %s\n' % tl)69opfile.write('=================\n')70opfile.write(71'mean queue length in front of the junction: %s\n' % tlsInfo[tl]['mQueueLen'])72opfile.write(73'mean waiting time in front of the junction: %s\n' % tlsInfo[tl]['mWaitTime'])74if 'noise' in tlsInfo[tl]:75opfile.write('mean noise emission: %s\n' % tlsInfo[tl]['noise'])76if 'CO' in tlsInfo[tl]:77opfile.write('mean CO emission: %s\n' % tlsInfo[tl]['CO'])78opfile.write('mean CO2 emission: %s\n' % tlsInfo[tl]['CO2'])79opfile.write('mean HC emission: %s\n' % tlsInfo[tl]['HC'])80opfile.write('mean PMx emission: %s\n' % tlsInfo[tl]['PMx'])81opfile.write('mean NOx emission: %s\n' % tlsInfo[tl]['NOx'])82opfile.write('mean fuel consumption: %s\n' % tlsInfo[tl]['fuel'])83opfile.write('number of stops: %s\n' % tlsInfo[tl]['nbStops'])84opfile.write('total waiting time at junction: %s\n\n' %85tlsInfo[tl]['tWaitTime'])868788def tlsIDToNodeID(net):89tlsID2NodeID = {}90for tls in net._tlss:91tlsID = tls._id92tlsID2NodeID[tlsID] = []93seenNodes = set()94for conn in tls._connections:95lane = conn[0]96edge = lane._edge97node = edge._to98nodeID = node._id99if nodeID not in seenNodes:100tlsID2NodeID[tlsID].append(nodeID)101seenNodes.add(nodeID)102return tlsID2NodeID103104105class E2OutputReader(handler.ContentHandler):106107def __init__(self):108self._lanes = {}109self._maxT = 0110111def startElement(self, name, attrs):112if name == 'interval':113detID = attrs['id']114laneID = detID[6:len(detID)]115if laneID not in self._lanes:116self._lanes[laneID] = {}117self._lanes[laneID]['mQueueLen'] = []118# self._lanes[laneID]['mWaitTime'] = []119self._lanes[laneID]['nbStops'] = []120self._lanes[laneID]['tWaitTime'] = []121if float(attrs['end']) < 100000000:122self._lanes[laneID]['mQueueLen'].append(123float(attrs['jamLengthInMetersSum']))124# self._lanes[laneID]['mWaitTime'].append(float(attrs['meanHaltingDuration']))125self._lanes[laneID]['nbStops'].append(126float(attrs['startedHalts']))127self._lanes[laneID]['tWaitTime'].append(128float(attrs['haltingDurationSum']))129self._maxT = max(float(attrs['end']), self._maxT)130131132class HarmonoiseReader(handler.ContentHandler):133134def __init__(self, net, tlsID2NodeID):135self._nodeIntervalNoise = {}136self._maxT = 0137self._net = net138self._tlsNoise = {}139self._tlsID2NodeID = tlsID2NodeID140141def startElement(self, name, attrs):142if name == 'interval':143self._maxT = max(float(attrs['end']), self._maxT)144if name == 'edge':145edgeID = attrs['id']146noiseStr = attrs['noise']147if len(noiseStr) < 10:148noise = float(noiseStr)149else:150noise = 0151if edgeID[0] == ':':152nodeID = edgeID[1:edgeID.find('_')]153if nodeID not in self._nodeIntervalNoise:154self._nodeIntervalNoise[nodeID] = []155self._nodeIntervalNoise[nodeID].append(noise)156else:157fromNodeID = net.getEdge(edgeID)._from._id158if fromNodeID not in self._nodeIntervalNoise:159self._nodeIntervalNoise[fromNodeID] = []160self._nodeIntervalNoise[fromNodeID].append(noise)161toNodeID = net.getEdge(edgeID)._to._id162if toNodeID not in self._nodeIntervalNoise:163self._nodeIntervalNoise[toNodeID] = []164self._nodeIntervalNoise[toNodeID].append(noise)165166def endElement(self, name):167if name == 'interval':168self.sumIntervalNoise()169if name == 'netstats':170self.sumNoise()171172def sumIntervalNoise(self):173for tls in net._tlss:174sum = 0175tlsID = tls._id176if tlsID not in self._tlsNoise:177self._tlsNoise[tlsID] = []178for nodeID in self._tlsID2NodeID[tlsID]:179for noise in self._nodeIntervalNoise[nodeID]:180sum = sum + pow(10, noise / 10)181self._tlsNoise[tlsID].append(10 * log(sum) / log(10))182183def sumNoise(self):184for tls in net._tlss:185tlsID = tls._id186self._tlsNoise[tlsID] = sum(self._tlsNoise[tlsID]) / self._maxT187188189class HBEFAReader(handler.ContentHandler):190191def __init__(self, net, tlsID2NodeID):192self._maxT = 0193self._net = net194self._nodeIntervalCO = {}195self._nodeIntervalCO2 = {}196self._nodeIntervalHC = {}197self._nodeIntervalPMx = {}198self._nodeIntervalNOx = {}199self._nodeIntervalfuel = {}200self._tlsCO = {}201self._tlsCO2 = {}202self._tlsHC = {}203self._tlsPMx = {}204self._tlsNOx = {}205self._tlsfuel = {}206self._tlsID2NodeID = tlsID2NodeID207208def startElement(self, name, attrs):209if name == 'interval':210self._maxT = max(float(attrs['end']), self._maxT)211if name == 'edge':212edgeID = attrs['id']213CO = float(attrs['CO_perVeh'])214CO2 = float(attrs['CO2_perVeh'])215HC = float(attrs['HC_perVeh'])216PMx = float(attrs['PMx_perVeh'])217NOx = float(attrs['NOx_perVeh'])218fuel = float(attrs['fuel_perVeh'])219if edgeID[0] == ':':220nodeIDs = edgeID[1:edgeID.find('_')]221else:222fromNodeID = net.getEdge(edgeID)._from._id223toNodeID = net.getEdge(edgeID)._to._id224nodeIDs = [fromNodeID, toNodeID]225for nodeID in nodeIDs:226if nodeID not in self._nodeIntervalCO:227self._nodeIntervalCO[nodeID] = []228self._nodeIntervalCO2[nodeID] = []229self._nodeIntervalHC[nodeID] = []230self._nodeIntervalPMx[nodeID] = []231self._nodeIntervalNOx[nodeID] = []232self._nodeIntervalfuel[nodeID] = []233self._nodeIntervalCO[nodeID].append(CO)234self._nodeIntervalCO2[nodeID].append(CO2)235self._nodeIntervalHC[nodeID].append(HC)236self._nodeIntervalPMx[nodeID].append(PMx)237self._nodeIntervalNOx[nodeID].append(NOx)238self._nodeIntervalfuel[nodeID].append(fuel)239240def endElement(self, name):241if name == 'interval':242self.sumInterval()243if name == 'netstats':244self.sum()245246def sumInterval(self):247for tls in net._tlss:248tlsID = tls._id249if tlsID not in self._tlsCO:250self._tlsCO[tlsID] = []251self._tlsCO2[tlsID] = []252self._tlsHC[tlsID] = []253self._tlsPMx[tlsID] = []254self._tlsNOx[tlsID] = []255self._tlsfuel[tlsID] = []256sum = 0257for nodeID in self._tlsID2NodeID[tlsID]:258for v in self._nodeIntervalCO[nodeID]:259sum = sum + v260self._tlsCO[tlsID].append(sum)261sum = 0262for nodeID in self._tlsID2NodeID[tlsID]:263for v in self._nodeIntervalCO2[nodeID]:264sum = sum + v265self._tlsCO2[tlsID].append(sum)266sum = 0267for nodeID in self._tlsID2NodeID[tlsID]:268for v in self._nodeIntervalHC[nodeID]:269sum = sum + v270self._tlsHC[tlsID].append(sum)271sum = 0272for nodeID in self._tlsID2NodeID[tlsID]:273for v in self._nodeIntervalPMx[nodeID]:274sum = sum + v275self._tlsPMx[tlsID].append(sum)276sum = 0277for nodeID in self._tlsID2NodeID[tlsID]:278for v in self._nodeIntervalNOx[nodeID]:279sum = sum + v280self._tlsNOx[tlsID].append(sum)281sum = 0282for nodeID in self._tlsID2NodeID[tlsID]:283for v in self._nodeIntervalfuel[nodeID]:284sum = sum + v285self._tlsfuel[tlsID].append(sum)286287def sum(self):288for tls in net._tlss:289tlsID = tls._id290self._tlsCO[tlsID] = sum(self._tlsCO[tlsID]) / self._maxT291self._tlsCO2[tlsID] = sum(self._tlsCO2[tlsID]) / self._maxT292self._tlsHC[tlsID] = sum(self._tlsHC[tlsID]) / self._maxT293self._tlsPMx[tlsID] = sum(self._tlsPMx[tlsID]) / self._maxT294self._tlsNOx[tlsID] = sum(self._tlsNOx[tlsID]) / self._maxT295self._tlsfuel[tlsID] = sum(self._tlsfuel[tlsID]) / self._maxT296297298# initialise299optParser = OptionParser()300optParser.add_option("-n", "--netfile", dest="netfile",301help="name of the netfile (f.e. 'inputs\\pasubio\\a_costa.net.xml')", metavar="<FILE>",302type="string")303optParser.add_option("-p", "--path", dest="path",304help="name of folder to work with (f.e. 'inputs\\a_costa\\')", metavar="<FOLDER>",305type="string", default="./")306optParser.add_option("-o", "--harmonoiseFile", dest="harmonoiseFile",307help="name of the harmonoise file", metavar="<FOLDER>", type="string")308optParser.add_option("-e", "--HBEFAFile", dest="hbefaFile",309help="name of the HBEFA file", metavar="<FOLDER>", type="string")310311312optParser.set_usage(313'\n-n inputs\\pasubio\\pasubio.net.xml -p inputs\\pasubio\\')314# parse options315(options, args) = optParser.parse_args()316if not options.netfile:317print("Missing arguments")318optParser.print_help()319exit()320321netfile = options.netfile322e2OutputFile = os.path.join(options.path, 'e2_output.xml')323324net = sumolib.net.readNet(netfile)325326e2Output = E2OutputReader()327parse(e2OutputFile, e2Output)328329tlsID2NodeID = tlsIDToNodeID(net)330tlsInfo = getBasicStats(net, e2Output._lanes, e2Output._maxT)331332if options.harmonoiseFile:333harmonoiseOutput = HarmonoiseReader(net, tlsID2NodeID)334parse(options.harmonoiseFile, harmonoiseOutput)335mergeInfos(tlsInfo, harmonoiseOutput._tlsNoise, 'noise')336337if options.hbefaFile:338hbefaOutput = HBEFAReader(net, tlsID2NodeID)339parse(options.hbefaFile, hbefaOutput)340mergeInfos(tlsInfo, hbefaOutput._tlsCO, 'CO')341mergeInfos(tlsInfo, hbefaOutput._tlsCO2, 'CO2')342mergeInfos(tlsInfo, hbefaOutput._tlsHC, 'HC')343mergeInfos(tlsInfo, hbefaOutput._tlsPMx, 'PMx')344mergeInfos(tlsInfo, hbefaOutput._tlsNOx, 'NOx')345mergeInfos(tlsInfo, hbefaOutput._tlsfuel, 'fuel')346347getStatisticsOutput(348tlsInfo, os.path.join(options.path, "intersection_metrics_summary.txt"))349350print('The calculation is done!')351352353