Path: blob/main/tools/district/aggregateAndSplitMatrices.py
169674 views
#!/usr/bin/env python1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2# Copyright (C) 2008-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 aggregateAndSplitMatrices.py14# @author Yun-Pang Floetteroed15# @author Daniel Krajzewicz16# @author Michael Behrisch17# @author Mirko Barthauer18# @date 2008-08-201920"""21This script is to22(1) aggregate the demands of the traffic zones in a given VISUM daily matrix, where23traffic zones have the same connection links, and then24(2) generate hourly matrices in VISUM format with an time series pattern (unified or user-defined).2526Traffic zones, whose demands are aggregated into other traffic zones, will be set to have zero demand.27A file containing combined zones will be generated as well.2829The demand aggregation helps to avoid small demands(e.g. < 0.5) being ignored when using od2trips to30generate trip files.3132"""33from __future__ import absolute_import34from __future__ import print_function35import os36import sys37from xml.sax import make_parser, handler38SUMO_HOME = os.environ.get('SUMO_HOME',39os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))40sys.path.append(os.path.join(SUMO_HOME, 'tools'))41from sumolib.options import ArgumentParser # noqa4243OUTPUTDIR = "./input/"44ap = ArgumentParser()45ap.add_argument("-m", "--matrix-file", dest="mtxpsfile", category="input", type=ap.file, required=True,46help="read OD matrix for passenger vehicles(long dist.) from FILE (mandatory)", metavar="FILE")47ap.add_argument("-z", "--districts-file", dest="districtsfile", category="input", type=ap.file, required=True,48help="read connecting links from FILE (mandatory)", metavar="FILE")49ap.add_argument("-t", "--timeSeries-file", dest="timeseries", category="input", type=ap.file,50help="read hourly traffic demand rate from FILE", metavar="FILE")51ap.add_argument("-d", "--dir", dest="OUTPUTDIR", default=OUTPUTDIR, category="output", type=str,52help="Directory to store the output files. Default: " + OUTPUTDIR)53ap.add_argument("-v", "--verbose", action="store_true", dest="verbose",54default=False, help="tell me what you are doing")5556options = ap.parse_args()575859class District:6061def __init__(self, label):62self.label = label63self.sourcelink = None64self.sinklink = None65self.combinedDistrict = []66self.alreadyCombined = False6768def __repr__(self):6970return "%s<%s|%s|%s>" % (self.label, self.sourcelink, self.sinklink, self.combinedDistrict)717273class DistrictsReader(handler.ContentHandler):7475def __init__(self, districtList):76self._districtList = districtList77self._newDistrict = None78self._district = None7980def startElement(self, name, attrs):81if name == 'taz':82self._newDistrict = District(attrs['id'])83self._district = attrs['id']84self._districtList.append(self._newDistrict)85elif name == 'tazSource' and self._district is not None:86self._newDistrict.sourcelink = attrs['id']87elif name == 'tazSink' and self._district is not None:88self._newDistrict.sinklink = attrs['id']8990def endElement(self, name):91if name == 'taz':92self._district = None939495def combineDemand(matrix, districtList, startVertices, endVertices):96matrixMap = {}97combinedCounter = 098existCounter = 099foutzone = open('combinedZones.txt', 'w')100101for i, start in enumerate(startVertices):102matrixMap[start] = {}103for j, end in enumerate(endVertices):104matrixMap[start][end] = matrix[i][j]105106for district1 in districtList:107if not district1.alreadyCombined:108foutzone.write('district:%s\n' % district1.label)109foutzone.write('combinedDistricts: ')110for district2 in districtList:111if not district2.alreadyCombined:112if district1.label != district2.label and district1.sourcelink == district2.sourcelink:113district1.combinedDistrict.append(district2)114district2.alreadyCombined = True115foutzone.write('%s, ' % district2.label)116foutzone.write('\n')117118for start in startVertices:119for district in districtList:120if start == district.label and district.combinedDistrict != []:121existCounter += 1122combinedCounter += len(district.combinedDistrict)123for end in endVertices:124for zone in district.combinedDistrict:125matrixMap[start][end] += matrixMap[zone.label][end]126matrixMap[zone.label][end] = 0.127128elif start == district.label and district.combinedDistrict == [] and not district.alreadyCombined:129existCounter += 1130131for i, start in enumerate(startVertices):132for j, end in enumerate(endVertices):133matrix[i][j] = matrixMap[start][end]134135foutzone.close()136matrixMap.clear()137print('finish combining zones!')138print('number of zones (before):', len(startVertices))139print('number of zones (after):', existCounter)140print('number of the combined zones:', combinedCounter)141142return matrix143# read the analyzed matrix144145146def getMatrix(verbose, matrix): # , mtxplfile, mtxtfile):147matrixPshort = []148startVertices = []149endVertices = []150Pshort_EffCells = 0151periodList = []152MatrixSum = 0.153if verbose:154print('matrix:', str(matrix))155ODpairs = 0156origins = 0157dest = 0158CurrentMatrixSum = 0.0159skipCount = 0160zones = 0161for line in open(matrix):162if line[0] == '$':163visumCode = line[1:3]164if visumCode != 'VM':165skipCount += 1166elif line[0] != '*' and line[0] != '$':167skipCount += 1168if skipCount == 2:169for elem in line.split():170periodList.append(float(elem))171if verbose:172print('periodList:', periodList)173elif skipCount > 3:174if zones == 0:175for elem in line.split():176zones = int(elem)177if verbose:178print('zones:', zones)179elif len(startVertices) < zones:180for elem in line.split():181if len(elem) > 0:182startVertices.append(elem)183endVertices.append(elem)184origins = len(startVertices)185dest = len(endVertices)186elif len(startVertices) == zones:187if ODpairs % origins == 0:188matrixPshort.append([])189for item in line.split():190matrixPshort[-1].append(float(item))191ODpairs += 1192MatrixSum += float(item)193CurrentMatrixSum += float(item)194if float(item) > 0.0:195Pshort_EffCells += 1196begintime = int(periodList[0])197if verbose:198foutlog = open('log.txt', 'w')199foutlog.write('Number of zones:%s, Number of origins:%s, Number of destinations:%s, begintime:%s, \n' % (200zones, origins, dest, begintime))201foutlog.write('CurrentMatrixSum:%s, total O-D pairs:%s, effective O-D pairs:%s\n' %202(CurrentMatrixSum, ODpairs, Pshort_EffCells))203print('Number of zones:', zones)204print('Number of origins:', origins)205print('Number of destinations:', dest)206print('begintime:', begintime)207print('CurrentMatrixSum:', CurrentMatrixSum)208print('total O-D pairs:', ODpairs)209print('Effective O-D Cells:', Pshort_EffCells)210print('len(startVertices):', len(startVertices))211print('len(endVertices):', len(endVertices))212foutlog.close()213214return matrixPshort, startVertices, endVertices, Pshort_EffCells, MatrixSum, CurrentMatrixSum, begintime, zones215216217def main():218if not options.mtxpsfile:219ap.print_help()220sys.exit()221222districtList = []223parser = make_parser()224parser.setContentHandler(DistrictsReader(districtList))225parser.parse(options.districtsfile)226227MTX_STUB = "mtx%02i_%02i.fma"228matrix = options.mtxpsfile229if options.OUTPUTDIR:230OUTPUTDIR = options.OUTPUTDIR231232matrix, startVertices, endVertices, Pshort_EffCells, MatrixSum, CurrentMatrixSum, begintime, zones = getMatrix(233options.verbose, matrix)234timeSeriesList = []235hourlyMatrix = []236subtotal = 0.237238if options.verbose:239foutlog = open('log.txt', 'a')240if options.timeseries:241print('read the time-series profile')242# combine matrices243matrix = combineDemand(matrix, districtList, startVertices, endVertices)244245for i in range(0, len(startVertices)):246hourlyMatrix.append([])247for j in range(0, len(endVertices)):248hourlyMatrix[-1].append(0.)249250if options.timeseries:251for line in open(options.timeseries):252for elem in line.split():253timeSeriesList.append(float(elem))254else:255factor = 1. / 24.256for i in range(0, 24):257timeSeriesList.append(factor)258259for hour in range(0, 24):260for i in range(0, len(startVertices)):261for j in range(0, len(endVertices)):262hourlyMatrix[i][j] = matrix[i][j] * timeSeriesList[0]263264filename = MTX_STUB % (hour, hour + 1)265266foutmatrix = open(OUTPUTDIR + filename, 'w') # /input/filename267268foutmatrix.write('$VMR;D2\n')269foutmatrix.write('* Verkehrsmittelkennung\n')270foutmatrix.write(' 1\n')271foutmatrix.write('* ZeitIntervall\n')272foutmatrix.write(' %s.00 %s.00\n' % (hour, hour + 1))273foutmatrix.write('* Faktor\n')274foutmatrix.write(' 1.000000\n')275foutmatrix.write('* Anzahl Bezirke\n')276foutmatrix.write(' %s\n' % zones)277foutmatrix.write('* BezirksNummern \n')278279for count, start in enumerate(startVertices):280count += 1281if count == 1:282foutmatrix.write(' %s ' % start)283else:284foutmatrix.write('%s ' % start)285if count != 1 and count % 10 == 0:286foutmatrix.write('\n')287foutmatrix.write(' ')288# count == (len(startVertices) -1):289elif count % 10 != 0 and count == len(startVertices):290foutmatrix.write('\n')291292for i, start in enumerate(startVertices):293subtotal = 0.294foutmatrix.write('* %s\n' % startVertices[i])295foutmatrix.write(' ')296for j, end in enumerate(endVertices):297k = j + 1298foutmatrix.write(' %.4f' % hourlyMatrix[i][j])299subtotal += hourlyMatrix[i][j]300if k % 10 == 0:301foutmatrix.write('\n')302foutmatrix.write(' ')303elif k % 10 != 0 and j == (len(endVertices) - 1):304foutmatrix.write('\n')305if options.verbose:306print('origin:', startVertices[i])307print('subtotal:', subtotal)308foutlog.write('origin:%s, subtotal:%s\n' %309(startVertices[i], subtotal))310foutmatrix.close()311if options.verbose:312print('done with generating', filename)313314if options.verbose:315foutlog.close()316317318main()319320321