forked from wlxiong/PyABM
/
network.py
213 lines (169 loc) · 7.77 KB
/
network.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# The basic structure for transport network
from __future__ import division
try:
import numpypy # required by PyPy
except ImportError:
pass
import numpy as np
import math
from config import Config
from utils import Time
class Network(object):
"Network is a pool of nodes and edges. "
def __init__(self):
self.edges = []
self.trans = []
self.nodes = {}
self.stops = {}
self.locations = {}
def get_node(self, id_):
if id_ not in self.nodes:
self.nodes[id_] = Node(id_)
return self.nodes[id_]
def get_stop(self, id_):
if id_ not in self.nodes:
self.stops[id_] = self.nodes[id_] = Stop(id_)
return self.stops[id_]
def get_location(self, id_):
if id_ not in self.nodes:
self.locations[id_] = self.nodes[id_] = Location(id_)
return self.locations[id_]
def add_oneway_street(self, head_id, tail_id, drive_time, capacity, length):
head = self.get_node(head_id)
tail = self.get_node(tail_id)
id_ = len(self.edges)
self.edges.append(Street(id_, head, tail, drive_time, capacity, length, Config.ALPHA_drive))
def add_street(self, head_id, tail_id, drive_time, capacity, length):
self.add_oneway_street(head_id, tail_id, drive_time, capacity, length)
self.add_oneway_street(tail_id, head_id, drive_time, capacity, length)
def add_oneway_sidewalk(self, head_id, tail_id, walk_time, capacity):
head = self.get_node(head_id)
tail = self.get_node(tail_id)
id_ = len(self.edges)
self.edges.append(Sidewalk(id_, head, tail, walk_time, capacity, Config.ALPHA_walk))
def add_sidewalk(self, head_id, tail_id, walk_time=5.0, capacity=Config.CAPACITY_ped):
self.add_oneway_sidewalk(head_id, tail_id, walk_time, capacity)
self.add_oneway_sidewalk(tail_id, head_id, walk_time, capacity)
def _get_timetable(self, offset, headway, dwell_time, total_run, in_vehicle_time):
" Generate the timetable with given parameters. "
timetable = [None] * total_run
sum_in_vehicle_time = [sum(in_vehicle_time[0:i+1]) for i in xrange(len(in_vehicle_time))]
for run in xrange(total_run):
move_time = lambda tt: tt + headway*run + offset + dwell_time
timetable[run] = map(move_time, [0] + sum_in_vehicle_time)
return timetable
def add_transit(self, offset, headway, n_run, stop_id_list, time_list, fare_matrix, capacity):
# get stop list
stop_list = []
for stop_id in stop_id_list:
stop = self.get_stop(stop_id)
stop_list.append(stop)
# get timetable
timetable = self._get_timetable(offset, headway, 0, n_run, time_list)
id_ = len(self.trans)
self.trans[id_] = Transit(id_, timetable, stop_list, fare_matrix, capacity)
def init_flows(self):
self.flows = np.zeros([len(self.edges), Time.MAXTICK])
class Node(object):
" node is a base class here. bust stop, street intersection and activity location are derived from it. "
def __init__(self, id_):
self.id = id_
self.adj_edges = []
def __eq__(self, other):
return self.id == other.id
def __repr__(self):
return "ND%d" % self.id
def add_adj_edge(self, edge):
self.adj_edges.append(edge)
class Edge(object):
"Edge is the base class for road and sidewalk. "
def __init__(self, id_, head, tail):
self.id, self.head, self.tail = id_, head, tail
self.head.add_adj_edge(self)
def __eq__(self, other):
return self.id == other.id
def __repr__(self):
return "ED%d" % self.id
def __str__(self):
return "(%s, %s)" % (self.head, self.tail)
def calc_travel_time(self, move_flow):
raise NotImplementedError
def calc_travel_cost(self, travel_time):
raise NotImplementedError
class Street(Edge):
""" Street is the connection between zones (residential location, economic activity area)
and hubs (i.e. transit stop, parking lot) in transport network.
"""
def __init__(self, id_, head, tail, drive_time, capacity, length, cost_unit):
super(Street, self).__init__(id_, head, tail)
self.drive_time, self.capacity, self.length, self.cost_unit = drive_time, capacity, length, cost_unit
def calc_travel_time(self, flow):
if flow / self.capacity > 4.0:
print " !! %s: %s / %s > 4.0" % (self, flow, self.capacity)
# raise PendingDeprecationWarning('Street capacity excess (20x)! ')
travel_time = Time.min2tick(self.drive_time*(1.0 + .15*math.pow(flow/self.capacity, 4.0)))
return travel_time
def calc_travel_cost(self, drive_time):
return drive_time * self.cost_unit
class Sidewalk(Edge):
""" Sidewalk is the connection between zones (residential location, economic activity area)
and hubs (i.e. transit stop, parking lot) in transport network.
"""
def __init__(self, id_, head, tail, walk_time, capacity, cost_unit):
super(Sidewalk, self).__init__(id_, head, tail)
self.walk_time, self.capacity, self.cost_unit = walk_time, capacity, cost_unit
def calc_travel_time(self, flow):
if flow > self.capacity * 8:
print "%s: %s / %s" % (self, flow, self.capacity)
# raise PendingDeprecationWarning('Sidewalk capacity excess (8x)! ')
travel_time = Time.min2tick(self.walk_time*(1.0 + .15*math.pow(flow/self.capacity, 4.0)))
return travel_time
def calc_travel_cost(self, walk_time):
return walk_time * self.cost_unit
class Location(Node):
"A location is a place where people participate various activities. "
def __init__(self, id_):
super(Location, self).__init__(id_)
def __repr__(self):
return "LC%d" % self.id
class Stop(Node):
"A stop has a id and a list of lines passing by it. "
def __init__(self, id_):
super(Stop, self).__init__(id_)
def __repr__(self):
return "ST%d" % self.id
class Transit(object):
"A transit line is an ordered list of stops, associated with a timetable. "
def __init__(self, id_, timetable, stop_list, fare_matrix, capacity):
self.id = id_
self.timetable = timetable
self.stops_on_line, self.fare_matrix, self.capacity = stop_list, fare_matrix, capacity
self.stop_order = {}
for order, each_stop in enumerate(self.stops_on_line):
each_stop.add_adj_edge(self)
self.stop_order[each_stop] = order
def __str__(self):
return " line %s: %s " % (self.id, self.stops_on_line)
def __repr__(self):
return "TR%d" % self.id
def calc_arrival_time(self, time, origin, dest):
" Return the arrival time and waiting since time (min). "
try:
i_origin = self.stop_order[origin]
except KeyError:
raise KeyError('Cannot find the stop on the line. ')
if dest in self.stop_order:
i_dest = self.stop_order[dest]
if i_dest > i_origin:
for run in xrange(len(self.timetable)):
if time <= self.timetable[run][i_origin]:
wait_time = self.timetable[run][i_origin] - time
arrival_time = self.timetable[run][i_dest]
return (arrival_time, wait_time)
return (float('inf'), float('inf'))
def calc_travel_cost(self, in_vehicle_time, move_flow):
if move_flow > self.capacity * 8:
print "%s: %s / %s" % (self, move_flow, self.capacity)
# raise PendingDeprecationWarning('Transit line capacity excess (8x)! ')
travel_cost = in_vehicle_time*(1.0 + .15*math.pow(move_flow/self.capacity, 4.0))
return travel_cost