Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/purgatory/Assignment.py
169673 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 Assignment.py
15
# @author Jakob Erdmann
16
# @author Yun-Pang Floetteroed
17
# @author Michael Behrisch
18
# @date 2008-03-28
19
20
"""
21
This script is for executing the traffic assignment.
22
Three assignment models are available:
23
- incremental
24
- c-logit
25
- lohse
26
27
The c-logit model are set as default.
28
"""
29
from __future__ import absolute_import
30
from __future__ import print_function
31
32
import os
33
import sys
34
import datetime
35
import math
36
import operator
37
from xml.sax import make_parser
38
from optparse import OptionParser
39
40
sys.path.append(os.path.join(os.environ["SUMO_HOME"], 'tools'))
41
import sumolib.net # noqa
42
43
from network import Net, DistrictsReader, ExtraSignalInformationReader # noqa
44
from dijkstra import dijkstraBoost, dijkstraPlain, dijkstra # noqa
45
from inputs import getMatrix, getConnectionTravelTime # noqa
46
from outputs import timeForInput, outputODZone, outputNetwork, outputStatistics, sortedVehOutput, linkChoicesOutput # noqa
47
from assign import doSUEAssign, doLohseStopCheck, doSUEVehAssign, doIncAssign # noqa
48
from tables import updateCurveTable # noqa
49
50
51
def initLinkChoiceMap(net, startVertices, endVertices, matrixPshort, linkChoiceMap, odPairsMap):
52
odpairCounts = 0
53
for start, startVertex in enumerate(startVertices):
54
odPairsMap[startVertex.label] = {}
55
for end, endVertex in enumerate(endVertices):
56
if startVertex.label != endVertex.label and matrixPshort[start][end] > 0.:
57
odpairCounts += 1
58
odPairsMap[startVertex.label][endVertex.label] = odpairCounts
59
60
for e in net._detectedEdges:
61
if e.detected not in linkChoiceMap:
62
linkChoiceMap[e.detected] = {}
63
linkChoiceMap[e.detected][odpairCounts] = 0.
64
65
return linkChoiceMap
66
67
68
def main():
69
# for measuring the required time for reading input files
70
inputreaderstart = datetime.datetime.now()
71
foutlog = open('%s_log.txt' % options.type, 'w')
72
foutlog.write(
73
'The stochastic user equilibrium traffic assignment will be executed with the %s model.\n' % options.type)
74
foutlog.write(
75
'All vehicular releasing times are determined randomly(uniform).\n')
76
77
matrices = options.mtxpsfile.split(",")
78
parser = make_parser()
79
80
if options.verbose:
81
print("Reading net")
82
print('net file:', options.netfile)
83
net = Net()
84
sumolib.net.readNet(options.netfile, net=net)
85
parser.setContentHandler(DistrictsReader(net))
86
parser.parse(options.confile)
87
if options.sigfile:
88
parser.setContentHandler(ExtraSignalInformationReader(net))
89
parser.parse(options.sigfile)
90
foutlog.write('- Reading network: done.\n')
91
foutlog.write('number of total startVertices:%s\n' % net.getstartCounts())
92
foutlog.write('number of total endVertices:%s\n' % net.getendCounts())
93
if options.verbose:
94
print(net.getfullEdgeCounts(), "edges read (internal edges included)")
95
96
if options.curvefile:
97
updateCurveTable(options.curvefile)
98
99
if options.hours == 24.:
100
assignHours = 16.
101
else:
102
assignHours = options.hours
103
104
for edge in net.getEdges():
105
if edge._lanes:
106
edge.getCapacity()
107
edge.getAdjustedCapacity(net)
108
edge.estcapacity *= assignHours
109
edge.getConflictLink()
110
111
if options.dijkstra == 'boost':
112
net.createBoostGraph()
113
if options.verbose:
114
print("after link reduction:", net.getfullEdgeCounts(), "edges read")
115
116
# calculate link travel time for all district connectors
117
getConnectionTravelTime(net._startVertices, net._endVertices)
118
119
foutlog.write('- Initial calculation of link parameters : done.\n')
120
# the required time for reading the network
121
timeForInput(inputreaderstart)
122
123
if options.debug:
124
outputNetwork(net)
125
126
# initialize the map for recording the number of the assigned vehicles
127
AssignedVeh = {}
128
# initialize the map for recording the number of the assigned trips
129
AssignedTrip = {}
130
smallDemand = []
131
linkChoiceMap = {}
132
odPairsMap = {}
133
for start, startVertex in enumerate(net._startVertices):
134
AssignedVeh[startVertex] = {}
135
AssignedTrip[startVertex] = {}
136
smallDemand.append([])
137
for end, endVertex in enumerate(net._endVertices):
138
AssignedVeh[startVertex][endVertex] = 0
139
AssignedTrip[startVertex][endVertex] = 0.
140
smallDemand[-1].append(0.)
141
142
# initialization
143
vehID = 0
144
matrixSum = 0.0
145
lohse = (options.type == "lohse")
146
incremental = (options.type == "incremental")
147
checkKPaths = False
148
149
if not incremental and options.kPaths > 1:
150
checkKPaths = True
151
if not incremental:
152
net.initialPathSet()
153
154
starttime = datetime.datetime.now()
155
# initialize the file for recording the routes
156
if options.odestimation:
157
net.getDetectedEdges(options.outputdir)
158
else:
159
foutroute = open('routes.rou.xml', 'w')
160
print('<?xml version="1.0"?>\n<!-- generated on %s by $Id: Assignment.py v1_3_1+0411-36956f96df [email protected] 2019-01-23 11:12:48 +0000 $ -->\n<routes>' % starttime, file=foutroute) # noqa
161
162
# for counter in range (0, len(matrices)):
163
for counter, matrix in enumerate(matrices):
164
# delete all vehicle information related to the last matrix for saving
165
# the disk space
166
vehicles = []
167
iterInterval = 0
168
matrixPshort, startVertices, endVertices, CurrentMatrixSum, begintime, assignPeriod, Pshort_EffCells, \
169
matrixSum, smallDemandRatio = getMatrix(net, options.verbose, matrix, matrixSum, options.demandscale)
170
options.hours = float(assignPeriod)
171
smallDemandPortion = math.ceil(
172
float(options.maxiteration) / 2. * smallDemandRatio)
173
if float(smallDemandPortion) != 0.:
174
iterInterval = math.ceil(
175
float(options.maxiteration) / float(smallDemandPortion))
176
177
departtime = begintime * 3600
178
179
if options.verbose:
180
print('the analyzed matrices:', counter)
181
print('Begintime:', begintime, "O'Clock")
182
print('departtime', departtime)
183
print('Matrix und OD Zone already read for Interval', counter)
184
print('CurrentMatrixSum:', CurrentMatrixSum)
185
186
foutlog.write('Reading matrix and O-D zones: done.\n')
187
foutlog.write(
188
'Matrix und OD Zone already read for Interval:%s\n' % counter)
189
foutlog.write('CurrentMatrixSum:%s\n' % CurrentMatrixSum)
190
foutlog.write('number of current startVertices:%s\n' %
191
len(startVertices))
192
foutlog.write('number of current endVertices:%s\n' % len(endVertices))
193
194
if options.odestimation:
195
linkChoiceMap.clear()
196
odPairsMap.clear()
197
linkChoiceMap = initLinkChoiceMap(
198
net, startVertices, endVertices, matrixPshort, linkChoiceMap, odPairsMap)
199
200
for edge in net.getEdges():
201
edge.flow = 0.
202
edge.helpflow = 0.
203
edge.actualtime = edge.freeflowtime
204
edge.helpacttime = edge.freeflowtime
205
edge.fTT = 0.
206
edge.TT = 0.
207
edge.delta = 0.
208
edge.helpacttimeEx = 0.
209
210
# the number of origins, the umber of destinations and the number of
211
# the OD pairs
212
len(startVertices)
213
len(endVertices)
214
215
# output the origin and destination zones and the number of effective
216
# OD pairs
217
if options.debug:
218
# matrixCounter)
219
outputODZone(startVertices, endVertices, Pshort_EffCells, counter)
220
221
if incremental:
222
print('begin the incremental assignment!')
223
iter = 0
224
options.lamda = 0.
225
while iter < options.maxiteration:
226
foutlog.write(
227
'- Current iteration(not executed yet):%s\n' % iter)
228
iter += 1
229
if iterInterval != 0 and operator.mod(iter, iterInterval) == 0:
230
assignSmallDemand = True
231
else:
232
assignSmallDemand = False
233
for start, startVertex in enumerate(startVertices):
234
targets = set()
235
for end, endVertex in enumerate(endVertices):
236
if assignSmallDemand and matrixPshort[start][end] > 0. and matrixPshort[start][end] < 1.:
237
smallDemand[start][end] = matrixPshort[
238
start][end] / float(smallDemandPortion)
239
240
if matrixPshort[start][end] > 1. or (assignSmallDemand and smallDemand[start][end] > 0.):
241
targets.add(endVertex)
242
243
if len(targets) > 0:
244
if options.dijkstra == 'boost':
245
D, P = dijkstraBoost(
246
net._boostGraph, startVertex.boost)
247
elif options.dijkstra == 'plain':
248
D, P = dijkstraPlain(startVertex, targets)
249
elif options.dijkstra == 'extend':
250
D, P = dijkstra(startVertex, targets)
251
vehID, smallDemand, linkChoiceMap = doIncAssign(
252
net, vehicles, options.verbose, options.maxiteration, options.odestimation,
253
endVertices, start, startVertex, matrixPshort, smallDemand,
254
D, P, AssignedVeh, AssignedTrip, vehID, assignSmallDemand, linkChoiceMap, odPairsMap)
255
256
if options.dijkstra != 'extend':
257
linkMap = net._fullEdges
258
else:
259
linkMap = net._edges
260
for edge in linkMap.values():
261
edge.getActualTravelTime(options, False)
262
if options.dijkstra == 'boost':
263
edge.boost.weight = edge.helpacttime
264
else:
265
print('begin the', options.type, " assignment!")
266
# initialization for the clogit and the lohse assignment model
267
iter_outside = 1
268
newRoutes = 1
269
stable = False
270
first = True
271
# begin the traffic Assignment
272
while newRoutes > 0:
273
foutlog.write('- SUE iteration:%s\n' % iter_outside)
274
# Generate the effective routes als intital path solutions,
275
# when considering k shortest paths (k is defined by the user.)
276
if checkKPaths:
277
checkPathStart = datetime.datetime.now()
278
newRoutes = net.calcKPaths(
279
options.verbose, options.kPaths, newRoutes, startVertices, endVertices, matrixPshort,
280
options.gamma)
281
checkPathEnd = datetime.datetime.now() - checkPathStart
282
foutlog.write(
283
'- Time for finding the k-shortest paths: %s\n' % checkPathEnd)
284
foutlog.write(
285
'- Finding the k-shortest paths for each OD pair: done.\n')
286
if options.verbose:
287
print('iter_outside:', iter_outside)
288
print('number of k shortest paths:', options.kPaths)
289
print('number of new routes:', newRoutes)
290
291
elif not checkKPaths and iter_outside == 1 and counter == 0:
292
print('search for the new path')
293
newRoutes = net.findNewPath(
294
startVertices, endVertices, newRoutes, matrixPshort, options.gamma, lohse, options.dijkstra)
295
296
checkKPaths = False
297
298
if options.verbose:
299
print('iter_outside:', iter_outside)
300
print('number of new routes:', newRoutes)
301
302
stable = False
303
iter_inside = 1
304
while not stable:
305
if options.verbose:
306
print('iter_inside:', iter_inside)
307
stable = doSUEAssign(
308
net, options, startVertices, endVertices, matrixPshort, iter_inside, lohse, first)
309
# The matrixPlong and the matrixTruck should be added when
310
# considering the long-distance trips and the truck trips.
311
if lohse:
312
stable = doLohseStopCheck(
313
net, options, stable, iter_inside, options.maxiteration, foutlog)
314
315
iter_inside += 1
316
317
if options.verbose:
318
print('stable:', stable)
319
320
newRoutes = net.findNewPath(
321
startVertices, endVertices, newRoutes, matrixPshort, options.gamma, lohse, options.dijkstra)
322
323
first = False
324
iter_outside += 1
325
326
if newRoutes < 3 and iter_outside > int((options.maxiteration) / 2):
327
newRoutes = 0
328
329
if iter_outside > options.maxiteration:
330
print('The max. number of iterations is reached!')
331
foutlog.write(
332
'The max. number of iterations is reached!\n')
333
foutlog.write(
334
'The number of new routes and the parameter stable will be set to zero and ' +
335
'True respectively.\n')
336
print('newRoutes:', newRoutes)
337
stable = True
338
newRoutes = 0
339
340
# update the path choice probability and the path flows as well as
341
# generate vehicle data
342
vehID = doSUEVehAssign(net, vehicles, options, counter, matrixPshort,
343
startVertices, endVertices, AssignedVeh, AssignedTrip, vehID, lohse)
344
345
# output the generated vehicular releasing times and routes, based on
346
# the current matrix
347
print('done with the assignment') # debug
348
if options.odestimation:
349
linkChoicesOutput(net, startVertices, endVertices, matrixPshort,
350
linkChoiceMap, odPairsMap, options.outputdir, starttime)
351
else:
352
sortedVehOutput(vehicles, departtime, options, foutroute)
353
354
if not options.odestimation:
355
foutroute.write('</routes>\n')
356
foutroute.close()
357
358
# output the global performance indices
359
assigntime = outputStatistics(net, starttime, len(matrices))
360
361
foutlog.write(
362
'- Assignment is completed and all required information is generated. ')
363
foutlog.close()
364
365
if options.verbose:
366
print('Duration for traffic assignment:', assigntime)
367
print('Total assigned vehicles:', vehID)
368
print('Total number of the assigned trips:', matrixSum)
369
370
371
optParser = OptionParser()
372
optParser.add_option("-m", "--matrix-file", dest="mtxpsfile",
373
help="read OD matrix for passenger vehicles from FILE (mandatory)", metavar="FILE")
374
optParser.add_option("-G", "--globalmatrix-file", dest="glbmtxfile",
375
help="read daily OD matrix for passenger vehicles from FILE (mandatory)", metavar="FILE")
376
optParser.add_option("-n", "--net-file", dest="netfile",
377
help="read SUMO network from FILE (mandatory)", metavar="FILE")
378
optParser.add_option("-d", "--district-file", dest="confile",
379
help="read OD Zones from FILE (mandatory)", metavar="FILE")
380
optParser.add_option("-s", "--extrasignal-file", dest="sigfile",
381
help="read extra/updated signal timing plans from FILE", metavar="FILE")
382
optParser.add_option("-u", "--crCurve-file", dest="curvefile",
383
help="read parameters used in cost functions from FILE", metavar="FILE")
384
optParser.add_option("-k", "--k-shortest-paths", dest="kPaths", type="int",
385
default=8, help="number of the paths should be found at the first iteration")
386
optParser.add_option("-i", "--max-sue-iteration", dest="maxiteration", type="int",
387
default=20, help="maximum number of the assignment iterations")
388
optParser.add_option("-t", "--sue-tolerance", dest="sueTolerance", type="float",
389
default=0.001, help="difference tolerance for the convergence in the c-logit model")
390
optParser.add_option("-a", "--alpha", dest="alpha", type="float",
391
default=0.15, help="alpha value to determine the commonality factor")
392
optParser.add_option("-g", "--gamma", dest="gamma", type="float",
393
default=1., help="gamma value to determine the commonality factor")
394
optParser.add_option("-l", "--lambda", dest="lamda", type="float",
395
default=0.3, help="lambda value to determine the penalty time due to queue")
396
optParser.add_option("-U", "--under-value", dest="under", type="float",
397
default=0.15, help="parameter 'under' to determine auxiliary link cost")
398
optParser.add_option("-p", "--upper-value", dest="upper", type="float",
399
default=0.5, help="parameter 'upper' to determine auxiliary link cost")
400
optParser.add_option("-X", "--parameter-1", dest="v1", type="float",
401
default=2.5, help="parameter 'v1' to determine auxiliary link cost in the lohse model")
402
optParser.add_option("-y", "--parameter-2", dest="v2", type="float",
403
default=4., help="parameter 'v2' to determine auxiliary link cost in the lohse model")
404
optParser.add_option("-z", "--parameter-3", dest="v3", type="float",
405
default=0.002, help="parameter 'v3' to determine auxiliary link cost in the lohse model")
406
optParser.add_option("-c", "--convergence-parameter-1", dest="cvg1", type="float",
407
default=1., help="parameter 'cvg1' to calculate the convergence value in the lohse model")
408
optParser.add_option("-o", "--convergence-parameter-2", dest="cvg2", type="float",
409
default=1., help="parameter 'cvg2' to calculate the convergence value in the lohse model")
410
optParser.add_option("-q", "--convergence-parameter-3", dest="cvg3", type="float",
411
default=10., help="parameter 'cvg3' to calculate the convergence value in the lohse model")
412
optParser.add_option("-v", "--verbose", action="store_true", dest="verbose",
413
default=False, help="tell me what you are doing")
414
optParser.add_option("-b", "--debug", action="store_true", dest="debug",
415
default=False, help="debug the program")
416
optParser.add_option("-e", "--type", dest="type", type="choice",
417
choices=('clogit', 'lohse', 'incremental'),
418
default="clogit", help="type of assignment [default: %default]")
419
optParser.add_option("-H", "--hours", dest="hours", type="float",
420
default=1., help="the analysing period(hours)")
421
optParser.add_option("-r", "--profile", action="store_true", dest="profile",
422
default=False, help="writing profiling info")
423
optParser.add_option("-+", "--dijkstra", dest="dijkstra", type="choice",
424
choices=('extend', 'plain', 'boost'),
425
default="plain", help="use penalty, plain(original) or boost in dijkstra implementation " +
426
"[default: %default]")
427
optParser.add_option("-x", "--odestimation", action="store_true", dest="odestimation",
428
default=False, help="generate trips for OD estimation")
429
optParser.add_option("-f", "--scale-factor", dest="demandscale",
430
type="float", default=1., help="scale demand by ")
431
optParser.add_option("-O", "--output-dir", dest="outputdir",
432
default=os.getcwd(), help="define the output directory name and path")
433
(options, args) = optParser.parse_args()
434
435
if not options.netfile or not options.confile or not options.mtxpsfile:
436
optParser.print_help()
437
sys.exit()
438
439
if options.profile:
440
import hotshot
441
import hotshot.stats
442
hotshotFile = "hotshot_%s_stats" % options.type
443
prof = hotshot.Profile(hotshotFile)
444
prof.runcall(main)
445
prof.close()
446
s = hotshot.stats.load(hotshotFile)
447
s.strip_dirs().sort_stats("time").print_stats(20)
448
else:
449
main()
450
451