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