sumolib.net.generator.demand

  1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
  2# Copyright (C) 2013-2026 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    demand.py
 14# @author  Daniel Krajzewicz
 15# @date    2013-10-10
 16
 17from __future__ import absolute_import
 18from __future__ import print_function
 19import random
 20import sumolib
 21import os
 22import subprocess
 23import math
 24import tempfile
 25
 26
 27PIVOT__PEAK = 10000
 28
 29
 30class LinearChange:
 31
 32    def __init__(self, beginFlow, endFlow, beginTime, endTime):
 33        self.beginFlow = beginFlow / 3600.
 34        self.endFlow = endFlow / 3600.
 35        self.beginTime = beginTime
 36        self.endTime = endTime
 37
 38    def depart(self, t):
 39        return random.random() < (
 40            self.beginFlow + (self.endFlow - self.beginFlow) / (self.endTime - self.beginTime) * (t - self.beginTime))
 41
 42
 43class WaveComposition:
 44
 45    def __init__(self, offset, curves):
 46        self.offset = offset
 47        self.curves = curves
 48
 49    def depart(self, t):
 50        v = self.offset
 51        for c in self.curves:
 52            dt = t - c[3]
 53            v = v + \
 54                c[0] * math.sin(2 * math.pi * dt * c[2]) + \
 55                c[1] * math.cos(2 * math.pi * dt * c[2])
 56        v = v / 3600.
 57        return random.random() < v
 58
 59
 60class Vehicle:
 61
 62    def __init__(self, id, depart, fromEdge, toEdge, vType, via=None):
 63        self.id = id
 64        self.depart = depart
 65        self.fromEdge = fromEdge
 66        self.toEdge = toEdge
 67        self.vType = vType
 68        self._via = via
 69
 70
 71class Stream:
 72
 73    def __init__(self, sid, validFrom, validUntil, numberModel,
 74                 departEdgeModel, arrivalEdgeModel, vTypeModel, via=None):
 75        self.sid = sid
 76        self._numberModel = numberModel
 77        self._departEdgeModel = departEdgeModel
 78        self._arrivalEdgeModel = arrivalEdgeModel
 79        self._vTypeModel = vTypeModel
 80        self._validFrom = validFrom
 81        self._validUntil = validUntil
 82        self._via = via
 83
 84    def getVehicleDepartures(self, b, e, sampleFactor=None, seenRatio=None):
 85        if self._validFrom is not None and self._validUntil is not None and (
 86                e < self._validFrom or b > self._validUntil):
 87            return []
 88        ret = []
 89        for i in range(b, e):
 90            if self._validFrom is not None and self._validUntil is not None and (
 91                    i < self._validFrom or i > self._validUntil):
 92                continue
 93            depart = i
 94            if sampleFactor is not None:
 95                off = i % (sampleFactor * 24)
 96                if not off < sampleFactor:
 97                    continue
 98                depart = sampleFactor * int(i / (24 * sampleFactor)) + off
 99            if isinstance(self._numberModel, int) or isinstance(self._numberModel, float):
100                if random.random() < float(self._numberModel) / 3600.:
101                    ret.append(depart)
102            elif self._numberModel.depart(i):
103                ret.append(depart)
104        return ret
105
106    def getFrom(self, what, i, number):
107        if isinstance(what, str):
108            return what
109        if isinstance(what, int):
110            return what
111        if isinstance(what, float):
112            return what
113        if isinstance(what, list):
114            return what[i % len(what)]
115        if isinstance(what, dict):
116            r = random.random()
117            s = 0
118            for k in what:
119                s = s + what[k]
120                if s > r:
121                    return k
122            return None
123        return what.get()
124
125    def toVehicles(self, b, e, offset=0, sampleFactor=None, seenRatio=None):
126        vehicles = []
127        departures = self.getVehicleDepartures(b, e, sampleFactor, seenRatio)
128        number = len(departures)
129        for i, d in enumerate(departures):
130            fromEdge = self.getFrom(self._departEdgeModel, i, number)
131            toEdge = self.getFrom(self._arrivalEdgeModel, i, number)
132            vType = self.getFrom(self._vTypeModel, i, number)
133            sid = self.sid
134            if sid is None:
135                sid = fromEdge + "_to_" + toEdge + "_" + str(i)
136            vehicles.append(
137                Vehicle(sid + "#" + str(i + offset), int(d), fromEdge, toEdge, vType, self._via))
138        return vehicles
139
140
141class Demand:
142
143    def __init__(self):
144        self.streams = []
145
146    def addStream(self, s):
147        self.streams.append(s)
148
149    def build(self, b, e, netName="net.net.xml", routesName="input_routes.rou.xml", sampleFactor=None):
150        vehicles = []
151        for s in self.streams:
152            vehicles.extend(s.toVehicles(b, e, len(vehicles), sampleFactor))
153        fdo = tempfile.NamedTemporaryFile(mode="w", delete=False)
154        fdo.write("<routes>\n")
155        for v in sorted(vehicles, key=lambda veh: veh.depart):
156            via = ""
157            if v._via is not None:
158                via = ' via="%s"' % v._via
159            if v.vType == "pedestrian":
160                fdo.write('    <person id="%s" depart="%s" type="pedestrian"><walk from="%s" to="%s"/></person>\n' %
161                          (v.id, v.depart, v.fromEdge, v.toEdge))
162            else:
163                fdo.write('    <trip id="%s" depart="%s" from="%s" to="%s" type="%s" %s/>\n' %
164                          (v.id, v.depart, v.fromEdge, v.toEdge, v.vType, via))
165        fdo.write("</routes>")
166        fdo.close()
167        duarouter = sumolib.checkBinary("duarouter")
168        print("netName > %s" % netName)
169        print("routesName > %s" % routesName)
170        # aeh, implicitly setting --no-warnings is not nice, is it?; and the
171        # need to dump generated vtypes to a temporary file as well
172        subprocess.call([duarouter, "-v", "-n", netName, "-t", fdo.name, "-o", routesName,
173                         "--no-warnings", "--additional-files", "vtypes.add.xml", "--vtype-output", "tmp.add.xml"])
174        os.remove(fdo.name)
PIVOT__PEAK = 10000
class LinearChange:
31class LinearChange:
32
33    def __init__(self, beginFlow, endFlow, beginTime, endTime):
34        self.beginFlow = beginFlow / 3600.
35        self.endFlow = endFlow / 3600.
36        self.beginTime = beginTime
37        self.endTime = endTime
38
39    def depart(self, t):
40        return random.random() < (
41            self.beginFlow + (self.endFlow - self.beginFlow) / (self.endTime - self.beginTime) * (t - self.beginTime))
LinearChange(beginFlow, endFlow, beginTime, endTime)
33    def __init__(self, beginFlow, endFlow, beginTime, endTime):
34        self.beginFlow = beginFlow / 3600.
35        self.endFlow = endFlow / 3600.
36        self.beginTime = beginTime
37        self.endTime = endTime
beginFlow
endFlow
beginTime
endTime
def depart(self, t):
39    def depart(self, t):
40        return random.random() < (
41            self.beginFlow + (self.endFlow - self.beginFlow) / (self.endTime - self.beginTime) * (t - self.beginTime))
class WaveComposition:
44class WaveComposition:
45
46    def __init__(self, offset, curves):
47        self.offset = offset
48        self.curves = curves
49
50    def depart(self, t):
51        v = self.offset
52        for c in self.curves:
53            dt = t - c[3]
54            v = v + \
55                c[0] * math.sin(2 * math.pi * dt * c[2]) + \
56                c[1] * math.cos(2 * math.pi * dt * c[2])
57        v = v / 3600.
58        return random.random() < v
WaveComposition(offset, curves)
46    def __init__(self, offset, curves):
47        self.offset = offset
48        self.curves = curves
offset
curves
def depart(self, t):
50    def depart(self, t):
51        v = self.offset
52        for c in self.curves:
53            dt = t - c[3]
54            v = v + \
55                c[0] * math.sin(2 * math.pi * dt * c[2]) + \
56                c[1] * math.cos(2 * math.pi * dt * c[2])
57        v = v / 3600.
58        return random.random() < v
class Vehicle:
61class Vehicle:
62
63    def __init__(self, id, depart, fromEdge, toEdge, vType, via=None):
64        self.id = id
65        self.depart = depart
66        self.fromEdge = fromEdge
67        self.toEdge = toEdge
68        self.vType = vType
69        self._via = via
Vehicle(id, depart, fromEdge, toEdge, vType, via=None)
63    def __init__(self, id, depart, fromEdge, toEdge, vType, via=None):
64        self.id = id
65        self.depart = depart
66        self.fromEdge = fromEdge
67        self.toEdge = toEdge
68        self.vType = vType
69        self._via = via
id
depart
fromEdge
toEdge
vType
class Stream:
 72class Stream:
 73
 74    def __init__(self, sid, validFrom, validUntil, numberModel,
 75                 departEdgeModel, arrivalEdgeModel, vTypeModel, via=None):
 76        self.sid = sid
 77        self._numberModel = numberModel
 78        self._departEdgeModel = departEdgeModel
 79        self._arrivalEdgeModel = arrivalEdgeModel
 80        self._vTypeModel = vTypeModel
 81        self._validFrom = validFrom
 82        self._validUntil = validUntil
 83        self._via = via
 84
 85    def getVehicleDepartures(self, b, e, sampleFactor=None, seenRatio=None):
 86        if self._validFrom is not None and self._validUntil is not None and (
 87                e < self._validFrom or b > self._validUntil):
 88            return []
 89        ret = []
 90        for i in range(b, e):
 91            if self._validFrom is not None and self._validUntil is not None and (
 92                    i < self._validFrom or i > self._validUntil):
 93                continue
 94            depart = i
 95            if sampleFactor is not None:
 96                off = i % (sampleFactor * 24)
 97                if not off < sampleFactor:
 98                    continue
 99                depart = sampleFactor * int(i / (24 * sampleFactor)) + off
100            if isinstance(self._numberModel, int) or isinstance(self._numberModel, float):
101                if random.random() < float(self._numberModel) / 3600.:
102                    ret.append(depart)
103            elif self._numberModel.depart(i):
104                ret.append(depart)
105        return ret
106
107    def getFrom(self, what, i, number):
108        if isinstance(what, str):
109            return what
110        if isinstance(what, int):
111            return what
112        if isinstance(what, float):
113            return what
114        if isinstance(what, list):
115            return what[i % len(what)]
116        if isinstance(what, dict):
117            r = random.random()
118            s = 0
119            for k in what:
120                s = s + what[k]
121                if s > r:
122                    return k
123            return None
124        return what.get()
125
126    def toVehicles(self, b, e, offset=0, sampleFactor=None, seenRatio=None):
127        vehicles = []
128        departures = self.getVehicleDepartures(b, e, sampleFactor, seenRatio)
129        number = len(departures)
130        for i, d in enumerate(departures):
131            fromEdge = self.getFrom(self._departEdgeModel, i, number)
132            toEdge = self.getFrom(self._arrivalEdgeModel, i, number)
133            vType = self.getFrom(self._vTypeModel, i, number)
134            sid = self.sid
135            if sid is None:
136                sid = fromEdge + "_to_" + toEdge + "_" + str(i)
137            vehicles.append(
138                Vehicle(sid + "#" + str(i + offset), int(d), fromEdge, toEdge, vType, self._via))
139        return vehicles
Stream( sid, validFrom, validUntil, numberModel, departEdgeModel, arrivalEdgeModel, vTypeModel, via=None)
74    def __init__(self, sid, validFrom, validUntil, numberModel,
75                 departEdgeModel, arrivalEdgeModel, vTypeModel, via=None):
76        self.sid = sid
77        self._numberModel = numberModel
78        self._departEdgeModel = departEdgeModel
79        self._arrivalEdgeModel = arrivalEdgeModel
80        self._vTypeModel = vTypeModel
81        self._validFrom = validFrom
82        self._validUntil = validUntil
83        self._via = via
sid
def getVehicleDepartures(self, b, e, sampleFactor=None, seenRatio=None):
 85    def getVehicleDepartures(self, b, e, sampleFactor=None, seenRatio=None):
 86        if self._validFrom is not None and self._validUntil is not None and (
 87                e < self._validFrom or b > self._validUntil):
 88            return []
 89        ret = []
 90        for i in range(b, e):
 91            if self._validFrom is not None and self._validUntil is not None and (
 92                    i < self._validFrom or i > self._validUntil):
 93                continue
 94            depart = i
 95            if sampleFactor is not None:
 96                off = i % (sampleFactor * 24)
 97                if not off < sampleFactor:
 98                    continue
 99                depart = sampleFactor * int(i / (24 * sampleFactor)) + off
100            if isinstance(self._numberModel, int) or isinstance(self._numberModel, float):
101                if random.random() < float(self._numberModel) / 3600.:
102                    ret.append(depart)
103            elif self._numberModel.depart(i):
104                ret.append(depart)
105        return ret
def getFrom(self, what, i, number):
107    def getFrom(self, what, i, number):
108        if isinstance(what, str):
109            return what
110        if isinstance(what, int):
111            return what
112        if isinstance(what, float):
113            return what
114        if isinstance(what, list):
115            return what[i % len(what)]
116        if isinstance(what, dict):
117            r = random.random()
118            s = 0
119            for k in what:
120                s = s + what[k]
121                if s > r:
122                    return k
123            return None
124        return what.get()
def toVehicles(self, b, e, offset=0, sampleFactor=None, seenRatio=None):
126    def toVehicles(self, b, e, offset=0, sampleFactor=None, seenRatio=None):
127        vehicles = []
128        departures = self.getVehicleDepartures(b, e, sampleFactor, seenRatio)
129        number = len(departures)
130        for i, d in enumerate(departures):
131            fromEdge = self.getFrom(self._departEdgeModel, i, number)
132            toEdge = self.getFrom(self._arrivalEdgeModel, i, number)
133            vType = self.getFrom(self._vTypeModel, i, number)
134            sid = self.sid
135            if sid is None:
136                sid = fromEdge + "_to_" + toEdge + "_" + str(i)
137            vehicles.append(
138                Vehicle(sid + "#" + str(i + offset), int(d), fromEdge, toEdge, vType, self._via))
139        return vehicles
class Demand:
142class Demand:
143
144    def __init__(self):
145        self.streams = []
146
147    def addStream(self, s):
148        self.streams.append(s)
149
150    def build(self, b, e, netName="net.net.xml", routesName="input_routes.rou.xml", sampleFactor=None):
151        vehicles = []
152        for s in self.streams:
153            vehicles.extend(s.toVehicles(b, e, len(vehicles), sampleFactor))
154        fdo = tempfile.NamedTemporaryFile(mode="w", delete=False)
155        fdo.write("<routes>\n")
156        for v in sorted(vehicles, key=lambda veh: veh.depart):
157            via = ""
158            if v._via is not None:
159                via = ' via="%s"' % v._via
160            if v.vType == "pedestrian":
161                fdo.write('    <person id="%s" depart="%s" type="pedestrian"><walk from="%s" to="%s"/></person>\n' %
162                          (v.id, v.depart, v.fromEdge, v.toEdge))
163            else:
164                fdo.write('    <trip id="%s" depart="%s" from="%s" to="%s" type="%s" %s/>\n' %
165                          (v.id, v.depart, v.fromEdge, v.toEdge, v.vType, via))
166        fdo.write("</routes>")
167        fdo.close()
168        duarouter = sumolib.checkBinary("duarouter")
169        print("netName > %s" % netName)
170        print("routesName > %s" % routesName)
171        # aeh, implicitly setting --no-warnings is not nice, is it?; and the
172        # need to dump generated vtypes to a temporary file as well
173        subprocess.call([duarouter, "-v", "-n", netName, "-t", fdo.name, "-o", routesName,
174                         "--no-warnings", "--additional-files", "vtypes.add.xml", "--vtype-output", "tmp.add.xml"])
175        os.remove(fdo.name)
streams
def addStream(self, s):
147    def addStream(self, s):
148        self.streams.append(s)
def build( self, b, e, netName='net.net.xml', routesName='input_routes.rou.xml', sampleFactor=None):
150    def build(self, b, e, netName="net.net.xml", routesName="input_routes.rou.xml", sampleFactor=None):
151        vehicles = []
152        for s in self.streams:
153            vehicles.extend(s.toVehicles(b, e, len(vehicles), sampleFactor))
154        fdo = tempfile.NamedTemporaryFile(mode="w", delete=False)
155        fdo.write("<routes>\n")
156        for v in sorted(vehicles, key=lambda veh: veh.depart):
157            via = ""
158            if v._via is not None:
159                via = ' via="%s"' % v._via
160            if v.vType == "pedestrian":
161                fdo.write('    <person id="%s" depart="%s" type="pedestrian"><walk from="%s" to="%s"/></person>\n' %
162                          (v.id, v.depart, v.fromEdge, v.toEdge))
163            else:
164                fdo.write('    <trip id="%s" depart="%s" from="%s" to="%s" type="%s" %s/>\n' %
165                          (v.id, v.depart, v.fromEdge, v.toEdge, v.vType, via))
166        fdo.write("</routes>")
167        fdo.close()
168        duarouter = sumolib.checkBinary("duarouter")
169        print("netName > %s" % netName)
170        print("routesName > %s" % routesName)
171        # aeh, implicitly setting --no-warnings is not nice, is it?; and the
172        # need to dump generated vtypes to a temporary file as well
173        subprocess.call([duarouter, "-v", "-n", netName, "-t", fdo.name, "-o", routesName,
174                         "--no-warnings", "--additional-files", "vtypes.add.xml", "--vtype-output", "tmp.add.xml"])
175        os.remove(fdo.name)