Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/district/aggregateAndSplitMatrices.py
169674 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2008-2025 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file aggregateAndSplitMatrices.py
15
# @author Yun-Pang Floetteroed
16
# @author Daniel Krajzewicz
17
# @author Michael Behrisch
18
# @author Mirko Barthauer
19
# @date 2008-08-20
20
21
"""
22
This script is to
23
(1) aggregate the demands of the traffic zones in a given VISUM daily matrix, where
24
traffic zones have the same connection links, and then
25
(2) generate hourly matrices in VISUM format with an time series pattern (unified or user-defined).
26
27
Traffic zones, whose demands are aggregated into other traffic zones, will be set to have zero demand.
28
A file containing combined zones will be generated as well.
29
30
The demand aggregation helps to avoid small demands(e.g. < 0.5) being ignored when using od2trips to
31
generate trip files.
32
33
"""
34
from __future__ import absolute_import
35
from __future__ import print_function
36
import os
37
import sys
38
from xml.sax import make_parser, handler
39
SUMO_HOME = os.environ.get('SUMO_HOME',
40
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))
41
sys.path.append(os.path.join(SUMO_HOME, 'tools'))
42
from sumolib.options import ArgumentParser # noqa
43
44
OUTPUTDIR = "./input/"
45
ap = ArgumentParser()
46
ap.add_argument("-m", "--matrix-file", dest="mtxpsfile", category="input", type=ap.file, required=True,
47
help="read OD matrix for passenger vehicles(long dist.) from FILE (mandatory)", metavar="FILE")
48
ap.add_argument("-z", "--districts-file", dest="districtsfile", category="input", type=ap.file, required=True,
49
help="read connecting links from FILE (mandatory)", metavar="FILE")
50
ap.add_argument("-t", "--timeSeries-file", dest="timeseries", category="input", type=ap.file,
51
help="read hourly traffic demand rate from FILE", metavar="FILE")
52
ap.add_argument("-d", "--dir", dest="OUTPUTDIR", default=OUTPUTDIR, category="output", type=str,
53
help="Directory to store the output files. Default: " + OUTPUTDIR)
54
ap.add_argument("-v", "--verbose", action="store_true", dest="verbose",
55
default=False, help="tell me what you are doing")
56
57
options = ap.parse_args()
58
59
60
class District:
61
62
def __init__(self, label):
63
self.label = label
64
self.sourcelink = None
65
self.sinklink = None
66
self.combinedDistrict = []
67
self.alreadyCombined = False
68
69
def __repr__(self):
70
71
return "%s<%s|%s|%s>" % (self.label, self.sourcelink, self.sinklink, self.combinedDistrict)
72
73
74
class DistrictsReader(handler.ContentHandler):
75
76
def __init__(self, districtList):
77
self._districtList = districtList
78
self._newDistrict = None
79
self._district = None
80
81
def startElement(self, name, attrs):
82
if name == 'taz':
83
self._newDistrict = District(attrs['id'])
84
self._district = attrs['id']
85
self._districtList.append(self._newDistrict)
86
elif name == 'tazSource' and self._district is not None:
87
self._newDistrict.sourcelink = attrs['id']
88
elif name == 'tazSink' and self._district is not None:
89
self._newDistrict.sinklink = attrs['id']
90
91
def endElement(self, name):
92
if name == 'taz':
93
self._district = None
94
95
96
def combineDemand(matrix, districtList, startVertices, endVertices):
97
matrixMap = {}
98
combinedCounter = 0
99
existCounter = 0
100
foutzone = open('combinedZones.txt', 'w')
101
102
for i, start in enumerate(startVertices):
103
matrixMap[start] = {}
104
for j, end in enumerate(endVertices):
105
matrixMap[start][end] = matrix[i][j]
106
107
for district1 in districtList:
108
if not district1.alreadyCombined:
109
foutzone.write('district:%s\n' % district1.label)
110
foutzone.write('combinedDistricts: ')
111
for district2 in districtList:
112
if not district2.alreadyCombined:
113
if district1.label != district2.label and district1.sourcelink == district2.sourcelink:
114
district1.combinedDistrict.append(district2)
115
district2.alreadyCombined = True
116
foutzone.write('%s, ' % district2.label)
117
foutzone.write('\n')
118
119
for start in startVertices:
120
for district in districtList:
121
if start == district.label and district.combinedDistrict != []:
122
existCounter += 1
123
combinedCounter += len(district.combinedDistrict)
124
for end in endVertices:
125
for zone in district.combinedDistrict:
126
matrixMap[start][end] += matrixMap[zone.label][end]
127
matrixMap[zone.label][end] = 0.
128
129
elif start == district.label and district.combinedDistrict == [] and not district.alreadyCombined:
130
existCounter += 1
131
132
for i, start in enumerate(startVertices):
133
for j, end in enumerate(endVertices):
134
matrix[i][j] = matrixMap[start][end]
135
136
foutzone.close()
137
matrixMap.clear()
138
print('finish combining zones!')
139
print('number of zones (before):', len(startVertices))
140
print('number of zones (after):', existCounter)
141
print('number of the combined zones:', combinedCounter)
142
143
return matrix
144
# read the analyzed matrix
145
146
147
def getMatrix(verbose, matrix): # , mtxplfile, mtxtfile):
148
matrixPshort = []
149
startVertices = []
150
endVertices = []
151
Pshort_EffCells = 0
152
periodList = []
153
MatrixSum = 0.
154
if verbose:
155
print('matrix:', str(matrix))
156
ODpairs = 0
157
origins = 0
158
dest = 0
159
CurrentMatrixSum = 0.0
160
skipCount = 0
161
zones = 0
162
for line in open(matrix):
163
if line[0] == '$':
164
visumCode = line[1:3]
165
if visumCode != 'VM':
166
skipCount += 1
167
elif line[0] != '*' and line[0] != '$':
168
skipCount += 1
169
if skipCount == 2:
170
for elem in line.split():
171
periodList.append(float(elem))
172
if verbose:
173
print('periodList:', periodList)
174
elif skipCount > 3:
175
if zones == 0:
176
for elem in line.split():
177
zones = int(elem)
178
if verbose:
179
print('zones:', zones)
180
elif len(startVertices) < zones:
181
for elem in line.split():
182
if len(elem) > 0:
183
startVertices.append(elem)
184
endVertices.append(elem)
185
origins = len(startVertices)
186
dest = len(endVertices)
187
elif len(startVertices) == zones:
188
if ODpairs % origins == 0:
189
matrixPshort.append([])
190
for item in line.split():
191
matrixPshort[-1].append(float(item))
192
ODpairs += 1
193
MatrixSum += float(item)
194
CurrentMatrixSum += float(item)
195
if float(item) > 0.0:
196
Pshort_EffCells += 1
197
begintime = int(periodList[0])
198
if verbose:
199
foutlog = open('log.txt', 'w')
200
foutlog.write('Number of zones:%s, Number of origins:%s, Number of destinations:%s, begintime:%s, \n' % (
201
zones, origins, dest, begintime))
202
foutlog.write('CurrentMatrixSum:%s, total O-D pairs:%s, effective O-D pairs:%s\n' %
203
(CurrentMatrixSum, ODpairs, Pshort_EffCells))
204
print('Number of zones:', zones)
205
print('Number of origins:', origins)
206
print('Number of destinations:', dest)
207
print('begintime:', begintime)
208
print('CurrentMatrixSum:', CurrentMatrixSum)
209
print('total O-D pairs:', ODpairs)
210
print('Effective O-D Cells:', Pshort_EffCells)
211
print('len(startVertices):', len(startVertices))
212
print('len(endVertices):', len(endVertices))
213
foutlog.close()
214
215
return matrixPshort, startVertices, endVertices, Pshort_EffCells, MatrixSum, CurrentMatrixSum, begintime, zones
216
217
218
def main():
219
if not options.mtxpsfile:
220
ap.print_help()
221
sys.exit()
222
223
districtList = []
224
parser = make_parser()
225
parser.setContentHandler(DistrictsReader(districtList))
226
parser.parse(options.districtsfile)
227
228
MTX_STUB = "mtx%02i_%02i.fma"
229
matrix = options.mtxpsfile
230
if options.OUTPUTDIR:
231
OUTPUTDIR = options.OUTPUTDIR
232
233
matrix, startVertices, endVertices, Pshort_EffCells, MatrixSum, CurrentMatrixSum, begintime, zones = getMatrix(
234
options.verbose, matrix)
235
timeSeriesList = []
236
hourlyMatrix = []
237
subtotal = 0.
238
239
if options.verbose:
240
foutlog = open('log.txt', 'a')
241
if options.timeseries:
242
print('read the time-series profile')
243
# combine matrices
244
matrix = combineDemand(matrix, districtList, startVertices, endVertices)
245
246
for i in range(0, len(startVertices)):
247
hourlyMatrix.append([])
248
for j in range(0, len(endVertices)):
249
hourlyMatrix[-1].append(0.)
250
251
if options.timeseries:
252
for line in open(options.timeseries):
253
for elem in line.split():
254
timeSeriesList.append(float(elem))
255
else:
256
factor = 1. / 24.
257
for i in range(0, 24):
258
timeSeriesList.append(factor)
259
260
for hour in range(0, 24):
261
for i in range(0, len(startVertices)):
262
for j in range(0, len(endVertices)):
263
hourlyMatrix[i][j] = matrix[i][j] * timeSeriesList[0]
264
265
filename = MTX_STUB % (hour, hour + 1)
266
267
foutmatrix = open(OUTPUTDIR + filename, 'w') # /input/filename
268
269
foutmatrix.write('$VMR;D2\n')
270
foutmatrix.write('* Verkehrsmittelkennung\n')
271
foutmatrix.write(' 1\n')
272
foutmatrix.write('* ZeitIntervall\n')
273
foutmatrix.write(' %s.00 %s.00\n' % (hour, hour + 1))
274
foutmatrix.write('* Faktor\n')
275
foutmatrix.write(' 1.000000\n')
276
foutmatrix.write('* Anzahl Bezirke\n')
277
foutmatrix.write(' %s\n' % zones)
278
foutmatrix.write('* BezirksNummern \n')
279
280
for count, start in enumerate(startVertices):
281
count += 1
282
if count == 1:
283
foutmatrix.write(' %s ' % start)
284
else:
285
foutmatrix.write('%s ' % start)
286
if count != 1 and count % 10 == 0:
287
foutmatrix.write('\n')
288
foutmatrix.write(' ')
289
# count == (len(startVertices) -1):
290
elif count % 10 != 0 and count == len(startVertices):
291
foutmatrix.write('\n')
292
293
for i, start in enumerate(startVertices):
294
subtotal = 0.
295
foutmatrix.write('* %s\n' % startVertices[i])
296
foutmatrix.write(' ')
297
for j, end in enumerate(endVertices):
298
k = j + 1
299
foutmatrix.write(' %.4f' % hourlyMatrix[i][j])
300
subtotal += hourlyMatrix[i][j]
301
if k % 10 == 0:
302
foutmatrix.write('\n')
303
foutmatrix.write(' ')
304
elif k % 10 != 0 and j == (len(endVertices) - 1):
305
foutmatrix.write('\n')
306
if options.verbose:
307
print('origin:', startVertices[i])
308
print('subtotal:', subtotal)
309
foutlog.write('origin:%s, subtotal:%s\n' %
310
(startVertices[i], subtotal))
311
foutmatrix.close()
312
if options.verbose:
313
print('done with generating', filename)
314
315
if options.verbose:
316
foutlog.close()
317
318
319
main()
320
321