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))
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
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
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
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)
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)