Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/purgatory/assign.py
169673 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2007-2025 German Aerospace Center (DLR) and others.
3
# This program and the accompanying materials are made available under the
4
# terms of the Eclipse Public License 2.0 which is available at
5
# https://www.eclipse.org/legal/epl-2.0/
6
# This Source Code may also be made available under the following Secondary
7
# Licenses when the conditions for such availability set forth in the Eclipse
8
# Public License 2.0 are satisfied: GNU General Public License, version 2
9
# or later which is available at
10
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
11
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
12
13
# @file assign.py
14
# @author Yun-Pang Floetteroed
15
# @author Daniel Krajzewicz
16
# @author Michael Behrisch
17
# @date 2007-11-25
18
19
"""
20
This script is for executing traffic assignment according to the required assignment model.
21
The incremental assignment model, the C-Logit assignment model and the Lohse assignment model
22
are included in this script.
23
"""
24
from __future__ import absolute_import
25
from __future__ import print_function
26
27
import math
28
import operator
29
import elements
30
from elements import Vehicle
31
32
33
def doIncAssign(net, vehicles, verbose, iteration, odestimation, endVertices, start, startVertex, matrixPshort,
34
smallDemand, D, P, AssignedVeh, AssignedTrip, vehID, assignSmallDemand, linkChoiceMap, odPairsMap):
35
36
for end, endVertex in enumerate(endVertices):
37
getlinkChoices = False
38
if ((odestimation and matrixPshort[start][end] > 0.) or
39
(matrixPshort[start][end] > 1. or (assignSmallDemand and smallDemand[start][end] > 0.))):
40
getlinkChoices = True
41
42
if startVertex._id != endVertex._id and getlinkChoices:
43
# if matrixPling and the matrixTruck exist, matrixPlong[start][end]
44
# > 0.0 or matrixTruck[start][end] > 0.0): should be added.
45
helpPath = []
46
vertex = endVertex
47
demand = 0.
48
if matrixPshort[start][end] > 1. or odestimation:
49
demand = matrixPshort[start][end] / float(iteration)
50
if assignSmallDemand and not odestimation:
51
demand += smallDemand[start][end]
52
53
while vertex != startVertex:
54
if P[vertex].kind == "real":
55
helpPath.append(P[vertex])
56
P[vertex].flow += demand
57
if getlinkChoices and P[vertex] in net._detectedEdges:
58
odIndex = odPairsMap[startVertex._id][endVertex._id]
59
linkChoiceMap[P[vertex].detected][odIndex] += demand
60
61
vertex = P[vertex].source
62
helpPath.reverse()
63
64
# the amount of the pathflow, which will be released at this
65
# iteration
66
if assignSmallDemand:
67
smallDemand[start][end] = 0.
68
69
if not odestimation:
70
AssignedTrip[startVertex][endVertex] += demand
71
vehID = assignVeh(
72
verbose, vehicles, startVertex, endVertex, helpPath, AssignedVeh, AssignedTrip, vehID)
73
return vehID, smallDemand, linkChoiceMap
74
75
# execute the SUE model with the given path set
76
77
78
def doSUEAssign(net, options, startVertices, endVertices, matrixPshort, iter, lohse, first):
79
if lohse:
80
if options.verbose:
81
foutassign = open('lohse_pathSet.txt', 'a')
82
foutassign.write('\niter:%s\n' % iter)
83
84
# matrixPlong and matrixTruck should be added if available.
85
if options.verbose:
86
print('pathNum in doSUEAssign:', elements.pathNum)
87
# calculate the overlapping factors between any two paths of a given OD
88
# pair
89
for start, startVertex in enumerate(startVertices):
90
for end, endVertex in enumerate(endVertices):
91
cumulatedflow = 0.
92
pathcount = 0
93
if matrixPshort[start][end] > 0. and startVertex._id != endVertex._id:
94
ODPaths = net._paths[startVertex][endVertex]
95
96
for path in ODPaths:
97
path.getPathTimeUpdate()
98
calCommonalityAndChoiceProb(ODPaths, options.alpha, lohse)
99
100
# calculate the path choice probabilities and the path flows
101
# for the given OD Pair
102
for path in ODPaths:
103
pathcount += 1
104
if pathcount < len(ODPaths):
105
path.helpflow = matrixPshort[
106
start][end] * path.choiceprob
107
cumulatedflow += path.helpflow
108
if lohse and options.verbose:
109
foutassign.write(' path:%s\n' % path.label)
110
foutassign.write(
111
' path.choiceprob:%s\n' % path.choiceprob)
112
foutassign.write(
113
' path.helpflow:%s\n' % path.helpflow)
114
foutassign.write(
115
' cumulatedflow:%s\n' % cumulatedflow)
116
else:
117
path.helpflow = matrixPshort[
118
start][end] - cumulatedflow
119
if lohse and options.verbose:
120
foutassign.write(
121
' last_path.helpflow:%s\n' % path.helpflow)
122
if first and iter == 1:
123
for edge in path.edges:
124
edge.flow += path.helpflow
125
else:
126
for edge in path.edges:
127
edge.helpflow += path.helpflow
128
129
# Reset the convergence index for the C-Logit model
130
notstable = 0
131
stable = False
132
# link travel times and link flows will be updated according to the latest
133
# traffic assingment
134
for edge in net._edges:
135
if (first and iter > 1) or (not first):
136
exflow = edge.flow
137
edge.flow = edge.flow + (1. / iter) * (edge.helpflow - edge.flow)
138
139
if not lohse:
140
if edge.flow > 0.:
141
if abs(edge.flow - exflow) / edge.flow > options.sueTolerance:
142
notstable += 1
143
elif edge.flow == 0.:
144
if exflow != 0. and (abs(edge.flow - exflow) / exflow > options.sueTolerance):
145
notstable += 1
146
elif edge.flow < 0.:
147
notstable += 1
148
edge.flow = 0.
149
else:
150
if edge.flow < 0.:
151
edge.flow = 0.
152
# reset the edge.helpflow for the next iteration
153
edge.helpflow = 0.0
154
edge.getActualTravelTime(options, lohse)
155
if options.dijkstra == 'boost':
156
edge.boost.weight = edge.helpacttime
157
if edge.queuetime > 1.:
158
notstable += 1
159
if lohse and options.verbose:
160
foutassign.close()
161
162
if not lohse and iter > 5:
163
if notstable == 0:
164
stable = True
165
elif notstable < math.ceil(net.geteffEdgeCounts() * 0.005) or notstable < 3:
166
stable = True
167
168
if iter > options.maxiteration:
169
stable = True
170
print('Number of max. iterations is reached!')
171
print('stable:', stable)
172
173
return stable
174
175
# calculate the commonality factors in the C-Logit model
176
177
178
def calCommonalityAndChoiceProb(ODPaths, alpha, lohse):
179
if len(ODPaths) > 1:
180
for path in ODPaths:
181
if not lohse:
182
path.utility = path.actpathtime + \
183
alpha * math.log(path.sumOverlap)
184
else:
185
path.utility = path.pathhelpacttime + \
186
alpha * math.log(path.sumOverlap)
187
188
if lohse:
189
minpath = min(ODPaths, key=operator.attrgetter('pathhelpacttime'))
190
beta = 12. / (1. + math.exp(0.7 - 0.015 * minpath.pathhelpacttime))
191
else:
192
theta = getThetaForCLogit(ODPaths)
193
194
for pathone in ODPaths:
195
sum_exputility = 0.
196
for pathtwo in ODPaths:
197
if pathone != pathtwo:
198
if not lohse:
199
sum_exputility += math.exp(theta *
200
(pathone.utility - pathtwo.utility))
201
else:
202
pathtwoPart = beta * \
203
(pathtwo.utility / minpath.utility - 1.)
204
pathonePart = beta * \
205
(pathone.utility / minpath.utility - 1.)
206
sum_exputility += math.exp(-(pathtwoPart *
207
pathtwoPart) + pathonePart * pathonePart)
208
pathone.choiceprob = 1. / (1. + sum_exputility)
209
else:
210
for path in ODPaths:
211
path.choiceprob = 1.
212
213
# calculate the path choice probabilities and the path flows and generate
214
# the vehicular data for each OD Pair
215
216
217
def doSUEVehAssign(net, vehicles, options, counter, matrixPshort, startVertices, endVertices, AssignedVeh,
218
AssignedTrip, vehID, lohse):
219
if options.verbose:
220
if counter == 0:
221
foutpath = open('paths.txt', 'w')
222
fouterror = open('errors.txt', 'w')
223
else:
224
foutpath = open('paths.txt', 'a')
225
fouterror = open('errors.txt', 'a')
226
if lohse:
227
foutpath.write(
228
'begin the doSUEVehAssign based on the lohse assignment model!')
229
else:
230
foutpath.write(
231
'begin the doSUEVehAssign based on the c-logit model!')
232
foutpath.write('the analyzed matrix=%s' % counter)
233
234
TotalPath = 0
235
236
for start, startVertex in enumerate(startVertices):
237
if options.verbose:
238
foutpath.write('\norigin=%s, ' % startVertex)
239
for end, endVertex in enumerate(endVertices):
240
pathcount = 0
241
cumulatedflow = 0.
242
if matrixPshort[start][end] > 0. and startVertex._id != endVertex._id:
243
if options.verbose:
244
foutpath.write('destination=%s' % endVertex)
245
ODPaths = net._paths[startVertex][endVertex]
246
247
for path in ODPaths:
248
TotalPath += 1
249
path.getPathTimeUpdate()
250
if lohse:
251
path.pathhelpacttime = path.actpathtime
252
253
calCommonalityAndChoiceProb(ODPaths, options.alpha, lohse)
254
255
for path in ODPaths:
256
pathcount += 1
257
if pathcount < len(ODPaths):
258
path.pathflow = matrixPshort[
259
start][end] * path.choiceprob
260
cumulatedflow += path.pathflow
261
else:
262
path.pathflow = matrixPshort[
263
start][end] - cumulatedflow
264
if options.verbose and path.pathflow < 0.:
265
fouterror.write(
266
'*********************** the path flow on the path:%s < 0.!!' % path.label)
267
if options.verbose:
268
foutpath.write('\npathID= %s, path flow=%4.4f, actpathtime=%4.4f, choiceprob=%4.4f, edges='
269
% (path.label, path.pathflow, path.actpathtime, path.choiceprob))
270
for item in path.edges:
271
foutpath.write('%s, ' % (item._id))
272
273
AssignedTrip[startVertex][endVertex] += path.pathflow
274
edges = []
275
for link in path.edges:
276
edges.append(link)
277
vehID = assignVeh(
278
options.verbose, vehicles, startVertex, endVertex, edges, AssignedVeh, AssignedTrip, vehID)
279
if options.verbose:
280
foutpath.write('\n')
281
if options.verbose:
282
print(
283
'total Number of the used paths for the current matrix:', TotalPath)
284
foutpath.write(
285
'\ntotal Number of the used paths for the current matrix:%s' % TotalPath)
286
foutpath.close()
287
fouterror.close()
288
return vehID
289
290
291
def assignVeh(verbose, vehicles, startVertex, endVertex, edges, AssignedVeh, AssignedTrip, vehID):
292
while AssignedVeh[startVertex][endVertex] < int(round(AssignedTrip[startVertex][endVertex])):
293
vehID += 1
294
newVehicle = Vehicle(str(vehID))
295
newVehicle.route = edges
296
vehicles.append(newVehicle)
297
298
AssignedVeh[startVertex][endVertex] += 1
299
if verbose:
300
print('vehID:', vehID)
301
print('AssignedTrip[start][end]', AssignedTrip[startVertex][endVertex])
302
print('AssignedVeh[start][end]', AssignedVeh[startVertex][endVertex])
303
304
return vehID
305
306
307
def getThetaForCLogit(ODPaths):
308
sum = 0.
309
diff = 0.
310
minpath = min(ODPaths, key=operator.attrgetter('actpathtime'))
311
312
for path in ODPaths:
313
sum += path.actpathtime
314
315
meanpathtime = sum / float(len(ODPaths))
316
317
for path in ODPaths:
318
diff += (path.actpathtime - meanpathtime)**2.
319
320
sdpathtime = (diff / float(len(ODPaths)))**0.5
321
322
if sdpathtime > 0.04:
323
theta = math.pi / (pow(6., 0.5) * sdpathtime * minpath.actpathtime)
324
else:
325
theta = 1.
326
327
return theta
328
329
330
def doLohseStopCheck(net, options, stable, iter, maxIter, foutlog):
331
stable = False
332
# Check if the convergence reaches.
333
if iter > 1:
334
counts = 0
335
for edge in net._edges.values():
336
stop = edge.stopCheck(options)
337
if stop:
338
counts += 1
339
if counts == net.geteffEdgeCounts():
340
stable = True
341
foutlog.write(
342
'The defined convergence is reached. The number of the required iterations:%s\n' % iter)
343
elif counts < int(net.geteffEdgeCounts() * 0.05) and float(iter) > options.maxiteration * 0.85:
344
stable = True
345
foutlog.write(
346
('The number of the links with convergence is 95% of the total links.' +
347
'The number of executed iterations:%s\n') % iter)
348
349
if iter >= maxIter:
350
print('The max. number of iterations is reached!')
351
foutlog.write('The max. number(%s) of iterations is reached!\n' % iter)
352
foutlog.write(
353
'The number of new routes will be set to 0, since the max. number of iterations is reached.')
354
stable = True
355
print('stop?:', stable)
356
print('iter_inside:', iter)
357
return stable
358
359