Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/assign/duaIterate.py
169673 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
4
# Copyright (C) 2008-2025 German Aerospace Center (DLR) and others.
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file duaIterate.py
16
# @author Daniel Krajzewicz
17
# @author Michael Behrisch
18
# @author Jakob Erdmann
19
# @author Yun-Pang Floetteroed
20
# @author Behzad Bamdad Mehrabani
21
# @date 2008-02-13
22
23
"""
24
Run duarouter and sumo alternating to perform a dynamic user assignment or a dynamic system optimal assignment
25
"""
26
from __future__ import print_function
27
from __future__ import absolute_import
28
import os
29
import sys
30
import subprocess
31
import glob
32
import argparse
33
import xml.etree.ElementTree as ET
34
from datetime import datetime
35
from collections import defaultdict
36
37
from costMemory import CostMemory
38
39
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
40
import sumolib # noqa
41
from sumolib.options import get_long_option_names, ArgumentParser # noqa
42
43
DEBUGLOG = None
44
EDGEDATA_ADD = "edgedata.add.xml"
45
46
47
def addGenericOptions(argParser):
48
# add options which are used by duaIterate and cadytsIterate
49
argParser.add_argument("-w", "--disable-warnings", action="store_true", dest="noWarnings",
50
default=False, help="disables warnings")
51
argParser.add_argument("-n", "--net-file", dest="net", category="input", type=argParser.net_file,
52
help="SUMO network (mandatory)", metavar="FILE")
53
argParser.add_argument("-+", "--additional", category="input", default="",
54
type=argParser.additional_file, help="Additional files")
55
argParser.add_argument("-b", "--begin",
56
type=argParser.time, default=0, help="Set simulation/routing begin")
57
argParser.add_argument("-e", "--end",
58
type=argParser.time, help="Set simulation/routing end")
59
argParser.add_argument("-R", "--route-steps", type=int, default=200, help="Set simulation route steps")
60
argParser.add_argument("-a", "--aggregation",
61
type=argParser.time, default=900, help="Set main weights aggregation period")
62
argParser.add_argument("-m", "--mesosim", action="store_true",
63
default=False, help="Whether mesosim shall be used")
64
argParser.add_argument("-p", "--path", type=str, help="Path to binaries")
65
argParser.add_argument("-y", "--absrand", action="store_true",
66
default=False, help="use current time to generate random number")
67
argParser.add_argument("-I", "--nointernal-link", action="store_true", dest="internallink",
68
default=False, help="not to simulate internal link: true or false")
69
argParser.add_argument("-j", "--meso-junctioncontrol", action="store_true", default=False,
70
help="Enable mesoscopic traffic light and priority junction handling")
71
argParser.add_argument("-L", "--meso-junctioncontrollimited", action="store_true", default=False,
72
help="Enable mesoscopic traffic light and priority junction handling for saturated links")
73
argParser.add_argument("-q", "--meso-multiqueue", action="store_true", default=False,
74
help="Enable multiple queues at edge ends")
75
argParser.add_argument("--meso-recheck", type=int, default=0,
76
help="Delay before checking whether a jam is gone. " +
77
"(higher values can lead to a big speed increase)")
78
argParser.add_argument("--meso-tls-penalty", type=float,
79
help="Apply scaled time penalties when driving across tls controlled junctions")
80
argParser.add_argument("--meso-minor-penalty", type=int,
81
help="Apply fixed time penalty when driving across a minor link; " +
82
"do not use together with --meso-junctioncontrollimited")
83
argParser.add_argument("-Q", "--eco-measure", choices=['CO', 'CO2', 'PMx', 'HC', 'NOx', 'fuel', 'noise'],
84
help="define the applied eco measure, e.g. fuel, CO2, noise")
85
argParser.add_argument("--eager-insert", action="store_true",
86
default=False, help="eager insertion tests (may slow down the sim considerably)")
87
argParser.add_argument("--time-to-teleport", dest="timetoteleport", type=argParser.time, default=300,
88
help="Delay before blocked vehicles are teleported (negative value disables teleporting)")
89
argParser.add_argument("--time-to-teleport.highways", dest="timetoteleport_highways", type=argParser.time,
90
default=0, help="Delay before blocked vehicles are teleported on wrong highway lanes")
91
argParser.add_argument("--measure-vtypes", dest="measureVTypes", type=str,
92
help="Restrict edgeData measurements to the given vehicle types")
93
argParser.add_argument("-7", "--zip", action="store_true",
94
default=False, help="zip old iterations using 7zip")
95
argParser.add_argument("-s", "--method-of-successive-average", action="store_true", dest="MSA",
96
default=False, help="apply the method of successive average as the swapping algorithm")
97
98
99
def initOptions():
100
argParser = ArgumentParser(
101
description=""" Any options of the form sumo--long-option-name will be passed to sumo.
102
These must be given after all the other options
103
example: sumo--step-length 0.5 will add the option --step-length 0.5 to sumo.""",
104
allowed_programs=['duarouter', 'sumo'],
105
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
106
addGenericOptions(argParser)
107
108
argParser.add_argument("--continue-on-unbuild", action="store_true", dest="continueOnUnbuild",
109
default=False, help="continues on unbuild routes")
110
argParser.add_argument("-t", "--trips",
111
help="trips in step 0 (either trips, flows, or routes have to be supplied)", metavar="FILE")
112
argParser.add_argument("-r", "--routes",
113
help="routes in step 0 (either trips, flows, or routes have to be supplied)", metavar="FILE")
114
argParser.add_argument("-F", "--flows",
115
help="flows in step 0 (either trips, flows, or routes have to be supplied)", metavar="FILE")
116
argParser.add_argument("-A", "--gA",
117
type=float, default=.5, help="Sets Gawron's Alpha")
118
argParser.add_argument("-B", "--gBeta",
119
type=float, default=.9, help="Sets Gawron's Beta")
120
argParser.add_argument("-E", "--disable-summary", "--disable-emissions", category="output", action="store_true",
121
dest="noSummary", default=False, help="No summaries are written by the simulation")
122
argParser.add_argument("-T", "--disable-tripinfos", action="store_true", dest="noTripinfo",
123
default=False, help="No tripinfos are written by the simulation")
124
argParser.add_argument("--tripinfo-filter", dest="tripinfoFilter",
125
help="filter tripinfo attributes")
126
argParser.add_argument("--inc-start", dest="incStart",
127
type=float, default=0, help="Start for incrementing scale")
128
argParser.add_argument("--inc-max", dest="incMax",
129
type=float, default=1, help="Maximum for incrementing scale")
130
argParser.add_argument("--inc-base", dest="incBase", type=int, default=-1,
131
help="Give the incrementation base. Negative values disable incremental scaling")
132
argParser.add_argument("--incrementation", dest="incValue",
133
type=int, default=1, help="Give the incrementation")
134
argParser.add_argument("--time-inc", dest="timeInc",
135
type=int, default=0, help="Give the time incrementation")
136
argParser.add_argument("-f", "--first-step", dest="firstStep",
137
type=int, default=0, help="First DUA step")
138
argParser.add_argument("-l", "--last-step", dest="lastStep",
139
type=int, default=50, help="Last DUA step")
140
argParser.add_argument("--convergence-iterations", dest="convIt",
141
type=int, default=10, help="Number of iterations to use for convergence calculation")
142
argParser.add_argument("--max-convergence-deviation", dest="convDev",
143
type=float, help="Maximum relative standard deviation in travel times")
144
argParser.add_argument("-D", "--districts", help="use districts as sources and targets", metavar="FILE")
145
argParser.add_argument("-x", "--vehroute-file", dest="routefile",
146
choices=['None', 'routesonly', 'detailed'],
147
default='None', help="choose the format of the route file")
148
argParser.add_argument("-z", "--output-lastRoute", action="store_true", category="output", dest="lastroute",
149
default=False, help="output the last routes")
150
argParser.add_argument("-K", "--keep-allroutes", action="store_true", dest="allroutes",
151
default=False, help="save routes with near zero probability")
152
argParser.add_argument("--routing-algorithm", default="dijkstra", help="select the routing algorithm")
153
argParser.add_argument("--max-alternatives", default=5, help="prune the number of alternatives to INT")
154
argParser.add_argument("--skip-first-routing", action="store_true", dest="skipFirstRouting",
155
default=False, help="run simulation with demands before first routing")
156
argParser.add_argument("--logit", action="store_true", default=False, help="use the logit model for route choice")
157
argParser.add_argument("-g", "--logitbeta", type=float,
158
default=0.15, help="use the c-logit model for route choice; logit model when beta = 0")
159
argParser.add_argument("-i", "--logitgamma", type=float, default=1., help="use the c-logit model for route choice")
160
argParser.add_argument("-G", "--logittheta", type=float, help="parameter to adapt the cost unit")
161
argParser.add_argument("-J", "--addweights", help="Additional weights for duarouter")
162
argParser.add_argument("--convergence-steps", dest="convergenceSteps", type=int,
163
help="Given x, if x > 0 reduce probability to change route by 1/x per step "
164
"(Probabilistic Swapping (PSwap)). "
165
"If x < 0 set probability of rerouting to 1/step after step |x|")
166
argParser.add_argument("--addweights.once", dest="addweightsOnce", action="store_true",
167
default=False, help="use added weights only on the first iteration")
168
argParser.add_argument("--router-verbose", action="store_true",
169
default=False, help="let duarouter print some statistics")
170
argParser.add_argument("--weight-memory", action="store_true", default=False, dest="weightmemory",
171
help="smooth edge weights across iterations")
172
argParser.add_argument("--pessimism", default=1, type=float,
173
help="give traffic jams a higher weight when using option --weight-memory")
174
argParser.add_argument("--clean-alt", action="store_true", dest="clean_alt",
175
default=False, help="Whether old rou.alt.xml files shall be removed")
176
argParser.add_argument("--binary", dest="gzip", action="store_true", default=False,
177
help="alias for --gzip")
178
argParser.add_argument("--gzip", action="store_true", default=False,
179
help="writing intermediate and resulting route files in gzipped format")
180
argParser.add_argument("--dualog", default="dua.log", category="output", help="log file path (default 'dua.log')")
181
argParser.add_argument("--log", default="stdout.log", category="output",
182
help="stdout log file path (default 'stdout.log')")
183
argParser.add_argument("--marginal-cost", action="store_true", default=False,
184
help="use marginal cost to perform system optimal traffic assignment")
185
argParser.add_argument("--marginal-cost.exp", type=float, default=0, dest="mcExp",
186
help="apply the given exponent on the current traffic count when computing marginal cost")
187
argParser.add_argument("remaining_args", nargs='*')
188
return argParser
189
190
191
def call(command, log):
192
command = [str(c) for c in command]
193
print("-" * 79, file=log)
194
print(command, file=log)
195
log.flush()
196
retCode = subprocess.call(command, stdout=log, stderr=log)
197
if retCode != 0:
198
print(("Execution of %s failed. Look into %s for details.") %
199
(command, log.name), file=sys.stderr)
200
return retCode
201
202
203
def writeRouteConf(duarouterBinary, step, options, dua_args, file,
204
output, routesInfo):
205
filename = os.path.basename(file)
206
filename = filename.split('.')[0]
207
cfgname = "%03i/iteration_%03i_%s.duarcfg" % (step, step, filename)
208
args = [
209
'--net-file', options.net,
210
'--route-files', file,
211
'--output-file', output,
212
'--exit-times', str(routesInfo == "detailed"),
213
'--ignore-errors', str(options.continueOnUnbuild),
214
'--with-taz', str(options.districts is not None),
215
'--gawron.beta', str(options.gBeta),
216
'--gawron.a', str(options.gA),
217
'--keep-all-routes', str(options.allroutes),
218
'--routing-algorithm', options.routing_algorithm,
219
'--max-alternatives', str(options.max_alternatives),
220
'--weights.expand',
221
'--logit.beta', str(options.logitbeta),
222
'--logit.gamma', str(options.logitgamma),
223
'--random', str(options.absrand),
224
'--begin', str(options.begin),
225
'--verbose', str(options.router_verbose),
226
'--no-step-log',
227
'--no-warnings', str(options.noWarnings),
228
]
229
if options.districts:
230
args += ['--additional-files', options.districts]
231
if options.logit:
232
args += ['--route-choice-method', 'logit']
233
if options.MSA:
234
probKeepRoute = step/(step+1)
235
args += ['--keep-route-probability', str(probKeepRoute)]
236
if options.convergenceSteps:
237
if options.convergenceSteps > 0:
238
probKeepRoute = max(0, min(step / float(options.convergenceSteps), 1))
239
else:
240
startStep = -options.convergenceSteps
241
probKeepRoute = 0 if step > startStep else 1 - 1.0 / (step - startStep)
242
args += ['--keep-route-probability', str(probKeepRoute)]
243
244
if step > 0 or options.addweights:
245
weightpath = ""
246
if step > 0:
247
weightpath = get_weightfilename(options, step - 1, "dump")
248
if options.addweights and (step == 0 or not options.addweightsOnce):
249
if step > 0:
250
weightpath += ","
251
weightpath += options.addweights
252
args += ['--weight-files', weightpath]
253
if options.eco_measure:
254
args += ['--weight-attribute', options.eco_measure]
255
if 'CH' in options.routing_algorithm:
256
args += ['--weight-period', str(options.aggregation)]
257
if options.logittheta:
258
args += ['--logit.theta', str(options.logittheta)]
259
if options.end:
260
args += ['--end', str(options.end)]
261
262
args += ["--save-configuration", cfgname]
263
264
subprocess.call([duarouterBinary] + args + dua_args)
265
return cfgname
266
267
268
def get_scale(options, step):
269
# compute scaling factor for simulation
270
# using incValue = 1 (default) and incBase = 10 would produce
271
# iterations with increasing scale 0.1, 0.2, ... 0.9, 1, 1, 1, ...
272
if options.incBase > 0:
273
return min(options.incStart + options.incValue * float(step + 1) / options.incBase, options.incMax)
274
else:
275
return options.incMax
276
277
278
def get_dumpfilename(options, step, prefix, full_path=True):
279
# the file to which edge costs (traveltimes) are written
280
if full_path:
281
return "%03i/%s_%s.xml" % (step, prefix, options.aggregation)
282
return "%s_%s.xml" % (prefix, options.aggregation)
283
284
285
def get_weightfilename(options, step, prefix):
286
# the file from which edge costs are loaded
287
# this defaults to the dumpfile written by the simulation but may be
288
# different if one of the options --addweights, --memory-weights or
289
# --cost-modifier is used
290
if options.weightmemory:
291
prefix = "memory_" + prefix
292
return get_dumpfilename(options, step, prefix)
293
294
295
def writeSUMOConf(sumoBinary, step, options, additional_args, route_files):
296
cfgfile = "%03i/iteration_%03i.sumocfg" % (step, step)
297
add = [EDGEDATA_ADD]
298
if options.additional != '':
299
add += options.additional.split(',')
300
301
sumoCmd = [sumoBinary,
302
'--output-prefix', '%03i/' % step,
303
'--save-configuration', cfgfile,
304
'--log', "iteration_%03i.sumo.log" % step,
305
'--net-file', options.net,
306
'--route-files', route_files,
307
'--additional-files', ",".join(add),
308
'--no-step-log',
309
'--random', options.absrand,
310
'--begin', options.begin,
311
'--route-steps', options.route_steps,
312
'--no-internal-links', options.internallink,
313
'--eager-insert', options.eager_insert,
314
'--time-to-teleport', options.timetoteleport,
315
'--time-to-teleport.highways', options.timetoteleport_highways,
316
'--verbose',
317
'--no-warnings', options.noWarnings,
318
] + additional_args
319
320
if hasattr(options, "noSummary") and not options.noSummary:
321
sumoCmd += ['--summary-output', "summary_%03i.xml" % step]
322
if hasattr(options, "noTripinfo") and not options.noTripinfo:
323
sumoCmd += ['--tripinfo-output', "tripinfo_%03i.xml" % step]
324
if options.eco_measure:
325
sumoCmd += ['--device.emissions.probability', '1']
326
if hasattr(options, "routefile"):
327
if options.routefile == "routesonly":
328
sumoCmd += ['--vehroute-output', "vehroute_%03i.xml" % step,
329
'--vehroute-output.route-length']
330
elif options.routefile == "detailed":
331
sumoCmd += ['--vehroute-output', "vehroute_%03i.xml" % step,
332
'--vehroute-output.route-length',
333
'--vehroute-output.exit-times']
334
if hasattr(options, "lastroute") and options.lastroute:
335
sumoCmd += ['--vehroute-output.last-route', options.lastroute]
336
if hasattr(options, "timeInc") and options.timeInc:
337
sumoCmd += ['--end', int(options.timeInc * (step + 1))]
338
elif options.end:
339
sumoCmd += ['--end', options.end]
340
341
if hasattr(options, "incBase") and options.incBase > 0:
342
sumoCmd += ['--scale', get_scale(options, step)]
343
if options.mesosim:
344
sumoCmd += ['--mesosim',
345
'--meso-recheck', options.meso_recheck]
346
if options.meso_multiqueue:
347
sumoCmd += ['--meso-multi-queue']
348
if options.meso_junctioncontrol:
349
sumoCmd += ['--meso-junction-control']
350
if options.meso_junctioncontrollimited:
351
sumoCmd += ['--meso-junction-control.limited']
352
if options.meso_tls_penalty:
353
sumoCmd += ['--meso-tls-penalty', options.meso_tls_penalty]
354
if options.meso_minor_penalty:
355
sumoCmd += ['--meso-minor-penalty', options.meso_minor_penalty]
356
357
# make sure all arguments are strings
358
sumoCmd = list(map(str, sumoCmd))
359
# use sumoBinary to write a config file
360
subprocess.call(sumoCmd, stdout=subprocess.PIPE)
361
362
return cfgfile
363
364
365
def filterTripinfo(step, attrs):
366
if "id" not in attrs:
367
attrs = ["id"] + attrs
368
inFile = "%03i%stripinfo_%03i.xml" % (step, os.sep, step)
369
if os.path.exists(inFile):
370
with open(inFile) as inf, open(inFile + ".filtered", 'w') as out:
371
print("<tripinfos>", file=out)
372
hadOutput = False
373
for line in inf:
374
if "<tripinfo " in line:
375
if hadOutput:
376
print("/>", file=out)
377
print(" <tripinfo", end=' ', file=out)
378
for a in attrs:
379
pos = line.find(a)
380
if pos >= 0:
381
pos += len(a) + 2
382
print('%s="%s"' % (a, line[pos:line.find('"', pos)]), end=' ', file=out)
383
hadOutput = True
384
if "<emission" in line:
385
for a in attrs:
386
pos = line.find(a)
387
if pos >= 0:
388
pos += len(a) + 2
389
print('%s="%s"' % (a, line[pos:line.find('"', pos)]), end=' ', file=out)
390
if hadOutput:
391
print("/>", file=out)
392
print("</tripinfos>", file=out)
393
os.remove(inFile)
394
os.rename(out.name, inFile)
395
396
397
def assign_remaining_args(application, prefix, args):
398
# assign remaining args [ prefix--o1 a1 prefix--o2 prefix--o3 a3 ...]
399
# only handles long options!
400
assigned = []
401
# split into options and arguments
402
items = []
403
item = None
404
for arg in args:
405
if "--" in arg:
406
if item is not None:
407
items.append(item)
408
if "=" in arg:
409
item = arg.split("=")
410
else:
411
item = [arg]
412
else:
413
if item is None:
414
sys.exit(
415
'Encountered argument "%s" without a preceding option' % arg)
416
item.append(arg)
417
if item is not None:
418
items.append(item)
419
420
# assign to programs
421
valid_options = set(get_long_option_names(application))
422
for item in items:
423
prefixed = item[0]
424
if prefixed[0:len(prefix)] == prefix:
425
option = prefixed[len(prefix):]
426
if option in valid_options:
427
assigned.append(option)
428
assigned += item[1:]
429
else:
430
sys.exit('"%s" is not a valid option for "%s"' %
431
(option, application))
432
433
return assigned
434
435
436
def get_basename(demand_file):
437
basename = os.path.basename(demand_file)
438
# note this will still cause problems if multiple input file have the same
439
# prefix and only differ in suffix
440
for suffix in ['.rou.xml', '.rou.alt.xml', '.trips.xml', '.xml']:
441
if basename.endswith(suffix):
442
basename = basename[:-len(suffix)]
443
break
444
return basename
445
446
447
def calcMarginalCost(step, options):
448
if step > 1:
449
if DEBUGLOG:
450
log = open("marginal_cost2.log", "w" if step == 2 else "a")
451
tree_sumo_cur = ET.parse(get_weightfilename(options, step - 1, "dump"))
452
tree_sumo_prv = ET.parse(get_weightfilename(options, step - 2, "dump"))
453
oldValues = defaultdict(dict)
454
for interval_prv in tree_sumo_prv.getroot():
455
begin_prv = interval_prv.attrib.get("begin")
456
for edge_prv in interval_prv.iter('edge'):
457
if edge_prv.get("traveltime") is not None:
458
veh_prv = float(edge_prv.get("left")) + float(edge_prv.get("arrived"))
459
tt_prv = float(edge_prv.get("overlapTraveltime"))
460
mc_prv = float(edge_prv.get("traveltime"))
461
oldValues[begin_prv][edge_prv.get("id")] = (veh_prv, tt_prv, mc_prv)
462
463
for interval_cur in tree_sumo_cur.getroot():
464
begin_cur = interval_cur.attrib.get("begin")
465
if begin_cur in oldValues:
466
oldIntervalValues = oldValues[begin_cur]
467
for edge_cur in interval_cur.iter('edge'):
468
if edge_cur.get("traveltime") is not None:
469
id_cur = edge_cur.get("id")
470
if id_cur in oldIntervalValues:
471
veh_prv, tt_prv, mc_prv = oldIntervalValues[id_cur]
472
veh_cur = float(edge_cur.get("left")) + float(edge_cur.get("arrived"))
473
tt_cur = float(edge_cur.get("traveltime"))
474
dif_tt = abs(tt_cur - tt_prv)
475
dif_veh = abs(veh_cur - veh_prv)
476
if dif_veh != 0:
477
mc_cur = (dif_tt / dif_veh) * (veh_cur ** options.mcExp) + tt_cur
478
else:
479
# previous marginal cost
480
mc_cur = tt_cur
481
482
edge_cur.set("traveltime", str(mc_cur))
483
edge_cur.set("overlapTraveltime", str(tt_cur))
484
edgeID = edge_cur.get("id")
485
if DEBUGLOG:
486
if begin_cur == "1800.00":
487
print("step=%s beg=%s e=%s tt=%s ttprev=%s n=%s nPrev=%s mC=%s mCPrev=%s" %
488
(step, begin_cur, edgeID, tt_cur, tt_prv, veh_cur, veh_prv,
489
mc_cur, mc_prv), file=log)
490
tree_sumo_cur.write(get_weightfilename(options, step - 1, "dump"))
491
492
if DEBUGLOG:
493
log.close()
494
495
496
def generateEdgedataAddFile(EDGEDATA_ADD, options):
497
"""write detectorfile"""
498
with open(EDGEDATA_ADD, 'w') as fd:
499
vTypes = ' vTypes="%s"' % ' '.join(options.measureVTypes.split(',')) if options.measureVTypes else ""
500
print("<a>", file=fd)
501
print(' <edgeData id="dump_%s" freq="%s" file="%s" excludeEmpty="true" minSamples="1"%s/>' % (
502
options.aggregation,
503
options.aggregation,
504
get_dumpfilename(options, -1, "dump", False),
505
vTypes), file=fd)
506
if options.eco_measure:
507
print((' <edgeData id="eco_%s" type="emissions" freq="%s" file="%s" ' +
508
'excludeEmpty="true" minSamples="1"%s/>') % (
509
options.aggregation,
510
options.aggregation,
511
get_dumpfilename(options, -1, "dump", False),
512
vTypes), file=fd)
513
print("</a>", file=fd)
514
fd.close()
515
516
517
def main(args=None):
518
argParser = initOptions()
519
520
try:
521
options = argParser.parse_args(args=args)
522
except (NotImplementedError, ValueError) as e:
523
print(e, file=sys.stderr)
524
sys.exit(1)
525
526
if not options.net:
527
argParser.error("Option --net-file is mandatory")
528
if (not options.trips and not options.routes and not options.flows) or (options.trips and options.routes):
529
argParser.error(
530
"Either --trips, --flows, or --routes have to be given!")
531
duaBinary = sumolib.checkBinary("duarouter", options.path)
532
sumoBinary = sumolib.checkBinary("sumo", options.path)
533
if options.marginal_cost and not options.logit:
534
print("Warning! --marginal-cost works best with --logit.", file=sys.stderr)
535
536
# make sure BOTH binaries are callable before we start
537
try:
538
subprocess.call(duaBinary, stdout=subprocess.PIPE)
539
except OSError:
540
sys.exit(
541
("Error: Could not locate duarouter (%s).\nMake sure its on the search path or set environment " +
542
"variable DUAROUTER_BINARY\n") % duaBinary)
543
try:
544
subprocess.call(sumoBinary, stdout=subprocess.PIPE)
545
except OSError:
546
sys.exit(
547
("Error: Could not locate sumo (%s).\nMake sure its on the search path or set environment " +
548
"variable SUMO_BINARY\n") % sumoBinary)
549
550
sumo_args = assign_remaining_args(sumoBinary, 'sumo', options.remaining_args)
551
dua_args = assign_remaining_args(duaBinary, 'duarouter', options.remaining_args)
552
sys.stdout = sumolib.TeeFile(sys.stdout, open(options.log, "w+"))
553
log = open(options.dualog, "w+")
554
if options.zip:
555
if options.clean_alt:
556
sys.exit("Error: Please use either --zip or --clean-alt but not both.")
557
try:
558
subprocess.call("7z", stdout=open(os.devnull, 'wb'))
559
except Exception:
560
sys.exit("Error: Could not locate 7z, please make sure its on the search path.")
561
zipProcesses = {}
562
zipLog = open("7zip.log", "w+")
563
starttime = datetime.now()
564
if options.trips:
565
input_demands = options.trips.split(",")
566
elif options.flows:
567
input_demands = options.flows.split(",")
568
else:
569
input_demands = options.routes.split(",")
570
if options.weightmemory:
571
costmemory = CostMemory('traveltime', pessimism=options.pessimism, network_file=options.net
572
)
573
routesSuffix = ".xml"
574
if options.gzip:
575
routesSuffix = ".gz"
576
577
if options.weightmemory and options.firstStep != 0:
578
# load previous dump files when continuing a run
579
print(">> Reassembling cost-memory from previous iteration steps")
580
for step in range(0, options.firstStep):
581
dumpfile = get_dumpfilename(options, step, "dump")
582
print(">>> Loading %s" % dumpfile)
583
costmemory.load_costs(dumpfile, step, get_scale(options, step))
584
585
# generate edgedata.add.xml
586
generateEdgedataAddFile(EDGEDATA_ADD, options)
587
588
avgTT = sumolib.miscutils.Statistics()
589
ret = 0
590
for step in range(options.firstStep, options.lastStep):
591
current_directory = os.getcwd()
592
final_directory = os.path.join(current_directory, "%03i" % step)
593
if not os.path.exists(final_directory):
594
os.makedirs(final_directory)
595
btimeA = datetime.now()
596
print("> Executing step %s" % step)
597
598
router_demands = input_demands
599
simulation_demands = input_demands
600
# demand files have regular names based on the basename and the step
601
if not (options.skipFirstRouting and step == 0):
602
simulation_demands = ["%03i/%s_%03i.rou%s" % (step, get_basename(f), step, routesSuffix)
603
for f in input_demands]
604
if not ((options.skipFirstRouting and step == 1) or step == 0):
605
router_demands = ["%03i/%s_%03i.rou.alt%s" % (step-1, get_basename(f), step-1, routesSuffix)
606
for f in input_demands]
607
608
if not (options.skipFirstRouting and step == options.firstStep):
609
# call duarouter
610
for router_input, output in zip(router_demands, simulation_demands):
611
print(">> Running router on %s" % router_input)
612
btime = datetime.now()
613
print(">>> Begin time: %s" % btime)
614
cfgname = writeRouteConf(duaBinary, step, options, dua_args, router_input,
615
output, options.routefile)
616
log.flush()
617
sys.stdout.flush()
618
if options.marginal_cost:
619
calcMarginalCost(step, options)
620
621
ret = call([duaBinary, "-c", cfgname], log)
622
if ret != 0:
623
break
624
if options.clean_alt and router_input not in input_demands:
625
os.remove(router_input)
626
etime = datetime.now()
627
print(">>> End time: %s" % etime)
628
print(">>> Duration: %s" % (etime - btime))
629
print("<<")
630
if ret != 0:
631
break
632
633
# simulation
634
print(">> Running simulation")
635
btime = datetime.now()
636
print(">>> Begin time: %s" % btime)
637
sumocfg = writeSUMOConf(sumoBinary, step, options, sumo_args,
638
",".join(simulation_demands)) # todo: change 'grou.xml'
639
log.flush()
640
sys.stdout.flush()
641
ret = call([sumoBinary, "-c", sumocfg], log)
642
if ret != 0:
643
break
644
if options.tripinfoFilter:
645
filterTripinfo(step, options.tripinfoFilter.split(","))
646
etime = datetime.now()
647
print(">>> End time: %s" % etime)
648
print(">>> Duration: %s" % (etime - btime))
649
print("<<")
650
651
if options.weightmemory:
652
print(">> Smoothing edge weights")
653
costmemory.load_costs(get_dumpfilename(options, step, "dump"), step, get_scale(options, step))
654
costmemory.write_costs(get_weightfilename(options, step, "dump"))
655
print(">>> Updated %s edges" % costmemory.loaded())
656
print(">>> Decayed %s unseen edges" % costmemory.decayed())
657
print(">>> Error avg:%.12g mean:%.12g" % (costmemory.avg_error(), costmemory.mean_error()))
658
print(">>> Absolute Error avg:%.12g mean:%.12g" %
659
(costmemory.avg_abs_error(), costmemory.mean_abs_error()))
660
661
if options.zip and step - options.firstStep > 1:
662
# this is a little hackish since we zip and remove all files by glob, which may have undesired side effects
663
# also note that the 7z file does not have an "_" before the
664
# iteration number in order to be not picked up by the remove
665
for s in list(zipProcesses.keys()):
666
if zipProcesses[s].poll() is not None:
667
for f in glob.glob("*_%03i*" % s):
668
try:
669
os.remove(f)
670
except Exception:
671
print("Could not remove %s" % f, file=zipLog)
672
del zipProcesses[s]
673
zipStep = step - 2
674
zipProcesses[zipStep] = subprocess.Popen(
675
["7z", "a", "iteration%03i.7z" % zipStep, "%03i" % zipStep], stdout=zipLog,
676
stderr=zipLog)
677
678
converged = False
679
if options.convDev:
680
sum = 0.
681
count = 0
682
for t in sumolib.output.parse_fast("%03i/tripinfo_%03i.xml" % (step, step),
683
'tripinfo', ['duration']):
684
sum += float(t.duration)
685
count += 1
686
if count == 0:
687
sys.exit("Error: No vehicle has reached its destination within the simulation duration.")
688
avgTT.add(sum / count)
689
relStdDev = avgTT.relStdDev(options.convIt)
690
print("< relative travel time deviation in the last %s steps: %.05f" % (
691
min(avgTT.count(), options.convIt), relStdDev))
692
if avgTT.count() >= options.convIt and relStdDev < options.convDev:
693
converged = True
694
695
print("< Step %s ended (duration: %s)" %
696
(step, datetime.now() - btimeA))
697
print("------------------\n")
698
699
log.flush()
700
sys.stdout.flush()
701
if converged:
702
break
703
if options.zip:
704
for s in zipProcesses.keys():
705
zipProcesses[s].wait()
706
for f in glob.glob("*_%03i*" % s):
707
try:
708
os.remove(f)
709
except Exception:
710
print("Could not remove %s" % f, file=zipLog)
711
zipLog.close()
712
print("dua-iterate ended (duration: %s)" % (datetime.now() - starttime))
713
714
log.close()
715
sys.stdout.close()
716
sys.stdout = sys.__stdout__
717
return ret
718
719
720
if __name__ == "__main__":
721
sys.exit(main())
722
723