from __future__ import absolute_import
from __future__ import print_function
import math
import sys
import os
from collections import defaultdict
import detector
from detector import relError
SUMO_HOME = os.environ.get('SUMO_HOME',
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))
sys.path.append(os.path.join(SUMO_HOME, 'tools'))
import sumolib
from sumolib.xml import parse
from sumolib.miscutils import parseTime
DEBUG = False
def get_options(args=None):
parser = sumolib.options.ArgumentParser()
parser.add_argument("-d", "--detector-file", dest="detfile", category="input", type=parser.additional_file,
help="read detectors from FILE (mandatory)", metavar="FILE")
parser.add_argument("-e", "--edgedata-file", dest="edgeDataFile", category="input", type=parser.edgedata_file,
help="read edgeData from FILE (mandatory)", metavar="FILE")
parser.add_argument("-f", "--detector-flow-file", dest="flowfile", category="input", type=parser.file,
help="read detector flows to compare to from FILE (mandatory)", metavar="FILE")
parser.add_argument("--flow-column", dest="flowcol", default="qPKW", type=str,
help="which column contains flows", metavar="STRING")
parser.add_argument("-z", "--respect-zero", action="store_true", dest="respectzero",
default=False, help="respect detectors without data (or with permanent zero) with zero flow")
parser.add_argument("-i", "--interval", type=parser.time,
default="1440", help="aggregation interval in minutes")
parser.add_argument("--long-names", action="store_true", dest="longnames",
default=False, help="do not use abbreviated names for detector groups")
parser.add_argument("--edge-names", action="store_true", dest="edgenames",
default=False, help="include detector group edge name in output")
parser.add_argument("-b", "--begin", type=parser.time, default=0, help="begin time in minutes")
parser.add_argument("--end", type=parser.time, default=None, help="end time in minutes")
parser.add_argument("-o", "--output-file", dest="output", category="output", type=parser.file,
help="write output to file instead of printing it to console", metavar="FILE")
parser.add_argument("--flow-output", dest="flowout", category="output", type=parser.file,
help="write output in flowfile format to FILE", metavar="FILE")
parser.add_argument("-v", "--verbose", action="store_true", dest="verbose",
default=False, help="tell me what you are doing")
options = parser.parse_args()
if not options.detfile or not options.edgeDataFile or (not options.flowfile and
not options.flowout):
parser.print_help()
sys.exit()
return options
def readEdgeData(edgeDataFile, begin, end, detReader, flowout):
edgeFlow = defaultdict(lambda: 0)
for interval in parse(edgeDataFile, "interval", attr_conversions={"begin": parseTime, "end": parseTime}):
if DEBUG:
print("reading intervals for begin=%s end=%s (current interval begin=%s end=%s)" %
(begin, end, interval.begin, interval.end))
if interval.begin < end and interval.end > begin:
validInterval = interval.end - interval.begin
if interval.begin < begin:
validInterval -= begin - interval.begin
if interval.end > end:
validInterval -= interval.end - end
scale = validInterval / (interval.end - interval.begin)
if flowout:
f = open(flowout, 'a')
if interval.edge is None:
continue
for edge in interval.edge:
flow = (int(edge.departed) + int(edge.entered)) * scale
edgeFlow[edge.id] += flow
if flowout:
for group in detReader.getEdgeDetGroups(edge.id):
f.write(";".join(map(str, [group.ids[0], interval.begin / 60,
flow, edge.speed])) + "\n")
if flowout:
f.close()
if DEBUG:
print(" validInterval=%s scale=%s" % (validInterval, scale))
return edgeFlow
def printFlows(options, edgeFlow, detReader):
edgeIDCol = "edge " if options.edgenames else ""
print('# detNames %sRouteFlow DetFlow ratio' % edgeIDCol, file=options.outfile)
output = []
for edge, detData in detReader._edge2DetData.items():
detString = []
dFlow = []
for group in detData:
if group.isValid:
groupName = os.path.commonprefix(group.ids)
if groupName == "" or options.longnames:
groupName = ';'.join(sorted(group.ids))
detString.append(groupName)
dFlow.append(group.totalFlow)
rFlow = len(detString) * [edgeFlow.get(edge, 0)]
edges = len(detString) * [edge]
output.extend(zip(detString, edges, rFlow, dFlow))
for group, edge, rflow, dflow in sorted(output):
if dflow > 0 or options.respectzero:
if options.edgenames:
print(group, edge, repr(rflow), repr(dflow), repr(relError(rflow, dflow)), file=options.outfile)
else:
print(group, repr(rflow), repr(dflow), repr(relError(rflow, dflow)), file=options.outfile)
def calcStatistics(options, begin, edgeFlow, detReader):
rSum = 0.
dSum = 0.
sumAbsDev = 0.
sumSquaredDev = 0.
sumSquaredPercent = 0.
n = 0
for edge, detData in detReader._edge2DetData.items():
rFlow = edgeFlow.get(edge, 0)
for group in detData:
if group.isValid:
dFlow = group.totalFlow
if dFlow > 0 or options.respectzero:
rSum += rFlow
dSum += dFlow
dev = float(abs(rFlow - dFlow))
sumAbsDev += dev
sumSquaredDev += dev * dev
if dFlow > 0:
sumSquaredPercent += dev * dev / dFlow / dFlow
n += 1
print('# interval', begin, file=options.outfile)
print('# avgRouteFlow avgDetFlow avgDev RMSE RMSPE', file=options.outfile)
if n == 0:
n = -1
print('#', " ".join(map(repr, [rSum / n, dSum / n, sumAbsDev / n,
math.sqrt(sumSquaredDev / n), math.sqrt(sumSquaredPercent / n)])),
file=options.outfile)
class LaneMap:
def get(self, key, default):
return key[0:-2]
def main(options):
if options.output is None:
options.outfile = sys.stdout
else:
options.outfile = open(options.output, 'w')
if options.flowout:
with open(options.flowout, 'w') as f:
f.write("Detector;Time;qPKW;vPKW\n")
options.begin = None
for interval in parse(options.edgeDataFile, "interval", attr_conversions={"begin": float, "end": float}):
if options.begin is None:
options.begin = interval.begin / 60
options.end = interval.end / 60
detReader = detector.DetectorReader(options.detfile, LaneMap())
intervalBeginM = options.begin
haveDetFlows = True
while ((options.end is None and haveDetFlows) or
(options.end is not None and intervalBeginM < options.end)):
intervalEndM = intervalBeginM + options.interval
if options.end is not None:
intervalEndM = min(intervalEndM, options.end)
if options.flowfile:
if options.verbose:
print("Reading flows")
haveDetFlows = detReader.readFlows(options.flowfile, flow=options.flowcol,
time="Time", timeVal=intervalBeginM, timeMax=intervalEndM)
if options.verbose:
print("Reading edgeData")
edgeFlow = readEdgeData(
options.edgeDataFile, intervalBeginM * 60, intervalEndM * 60,
detReader, options.flowout)
if haveDetFlows and options.flowfile:
printFlows(options, edgeFlow, detReader)
calcStatistics(options, intervalBeginM, edgeFlow, detReader)
detReader.clearFlows()
intervalBeginM += options.interval
options.outfile.close()
if __name__ == "__main__":
main(get_options())