Skip to content

Commit

Permalink
Merge 1aeefd8 into d61e0c9
Browse files Browse the repository at this point in the history
  • Loading branch information
AboudyKreidieh committed Jan 5, 2020
2 parents d61e0c9 + 1aeefd8 commit 3f8ccf2
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 247 deletions.
7 changes: 4 additions & 3 deletions flow/core/kernel/network/aimsun.py
Expand Up @@ -212,7 +212,7 @@ def generate_network(self, network):
self.edgestarts = self.network.edge_starts

# if no edge_starts are specified, generate default values to be used
# by the "get_x" method
# by the "get_edge" method
if self.edgestarts is None:
length = 0
self.edgestarts = []
Expand All @@ -222,6 +222,7 @@ def generate_network(self, network):
# increment the total length of the network with the length of
# the current edge
length += self._edges[edge_id]['length']
self.edgestarts.sort(key=lambda tup: tup[1])

# these optional parameters need only be used if "no-internal-links"
# is set to "false" while calling sumo's netconvert function
Expand Down Expand Up @@ -315,9 +316,9 @@ def get_junction_list(self):
"""See parent class."""
return self._junction_list

def get_edge(self, x): # TODO: maybe remove
def _get_edge(self, x): # TODO: maybe remove
"""See parent class."""
for (edge, start_pos) in reversed(self.total_edgestarts):
for (edge, start_pos) in reversed(self.edgestarts):
if x >= start_pos:
return edge, x - start_pos

Expand Down
35 changes: 12 additions & 23 deletions flow/core/kernel/network/base.py
Expand Up @@ -154,9 +154,11 @@ def get_junction_list(self):
"""Return the names of all junctions in the network."""
raise NotImplementedError

def get_edge(self, x): # TODO: maybe remove
def _get_edge(self, x): # TODO: maybe remove
"""Compute an edge and relative position from an absolute position.
The edges do not include internal edges.
Parameters
----------
x : float
Expand Down Expand Up @@ -203,6 +205,10 @@ def prev_edge(self, edge, lane):
"""
raise NotImplementedError

def non_internal_length(self):
"""Return the length of the network, no including internal edges."""
raise NotImplementedError

###########################################################################
# Methods for generating initial vehicle positions. #
###########################################################################
Expand Down Expand Up @@ -322,30 +328,12 @@ def gen_even_start_pos(self, initial_config, num_vehicles):
# generate uniform starting positions
while car_count < num_vehicles:
# collect the position and lane number of each new vehicle
pos = self.get_edge(x)

# ensures that vehicles are not placed in an internal junction
while pos[0] in dict(self.internal_edgestarts).keys():
# find the location of the internal edge in total_edgestarts,
# which has the edges ordered by position
edges = [tup[0] for tup in self.total_edgestarts]
indx_edge = next(
i for i, edge in enumerate(edges) if edge == pos[0])

# take the next edge in the list, and place the car at the
# beginning of this edge
if indx_edge == len(edges) - 1:
next_edge_pos = self.total_edgestarts[0]
else:
next_edge_pos = self.total_edgestarts[indx_edge + 1]

x = next_edge_pos[1]
pos = (next_edge_pos[0], 0)
pos = self._get_edge(x)

# ensures that you are in an acceptable edge
while pos[0] not in available_edges:
x = (x + self.edge_length(pos[0])) % self.non_internal_length()
pos = self.get_edge(x)
pos = self._get_edge(x)

# ensure that in variable lane settings vehicles always start a
# vehicle's length away from the start of the edge. This, however,
Expand All @@ -358,15 +346,16 @@ def gen_even_start_pos(self, initial_config, num_vehicles):
(num_vehicles - car_count)

# place vehicles side-by-side in all available lanes on this edge
for lane in range(min([self.num_lanes(pos[0]), lanes_distr])):
for lane in range(min(self.num_lanes(pos[0]), lanes_distr)):
car_count += 1
startpositions.append(pos)
startlanes.append(lane)

if car_count == num_vehicles:
break

x = (x + increment + VEHICLE_LENGTH + min_gap) % self.non_internal_length()
x = (x + increment + VEHICLE_LENGTH + min_gap) \
% self.non_internal_length()

# add a perturbation to each vehicle, while not letting the vehicle
# leave its current edge
Expand Down
85 changes: 70 additions & 15 deletions flow/core/kernel/network/traci.py
Expand Up @@ -168,7 +168,7 @@ def generate_network(self, network):
self.edgestarts = self.network.edge_starts

# if no edge_starts are specified, generate default values to be used
# by the "get_x" method
# by the "get_edge" method
if self.edgestarts is None:
length = 0
self.edgestarts = []
Expand All @@ -178,17 +178,12 @@ def generate_network(self, network):
# increment the total length of the network with the length of
# the current edge
length += self._edges[edge_id]['length']
# sort the edgestarts by position
self.edgestarts.sort(key=lambda tup: tup[1])

# these optional parameters need only be used if "no-internal-links"
# is set to "false" while calling sumo's netconvert function
self.internal_edgestarts = self.network.internal_edge_starts
self.internal_edgestarts_dict = dict(self.internal_edgestarts)

# total_edgestarts and total_edgestarts_dict contain all of the above
# edges, with the former being ordered by position
self.total_edgestarts = self.edgestarts + self.internal_edgestarts
self.total_edgestarts.sort(key=lambda tup: tup[1])

# total_edgestarts and total_edgestarts_dict contain all main and
# internal edges, with the former being ordered by position
self.total_edgestarts = self._gen_internal_edgestarts()
self.total_edgestarts_dict = dict(self.total_edgestarts)

self.__length = sum(
Expand Down Expand Up @@ -247,9 +242,9 @@ def close(self):
except OSError:
pass

def get_edge(self, x):
def _get_edge(self, x):
"""See parent class."""
for (edge, start_pos) in reversed(self.total_edgestarts):
for (edge, start_pos) in reversed(self.edgestarts):
if x >= start_pos:
return edge, x - start_pos

Expand All @@ -262,7 +257,7 @@ def get_x(self, edge, position):

if edge[0] == ':':
try:
return self.internal_edgestarts_dict[edge] + position
return self.total_edgestarts_dict[edge] + position
except KeyError:
# in case several internal links are being generalized for
# by a single element (for backwards compatibility)
Expand Down Expand Up @@ -891,8 +886,11 @@ def _import_edges_from_net(self, net_params):
net_data[edge_id]['lanes'] = 0
for i, lane in enumerate(edge):
net_data[edge_id]['lanes'] += 1
# choose the largest length across lanes as the edge length
net_data[edge_id]['length'] = max(
net_data[edge_id].get('length', 0),
float(lane.attrib['length']))
if i == 0:
net_data[edge_id]['length'] = float(lane.attrib['length'])
if net_data[edge_id]['speed'] is None \
and 'speed' in lane.attrib:
net_data[edge_id]['speed'] = float(
Expand Down Expand Up @@ -935,3 +933,60 @@ def _import_edges_from_net(self, net_params):
connection_data = {'next': next_conn_data, 'prev': prev_conn_data}

return net_data, connection_data

def _gen_internal_edgestarts(self):
"""Create a list of internal edgestarts.
This method also increments the regular edgestarts so that they do not
overlap with the internal edgestarts.
Returns
-------
list of (str, float)
list of all edge names and starting positions,
ex: [(internal0, pos0), (internal1, pos1), ...]
"""
edgestarts = deepcopy(self.edgestarts)

# the length that needs to be added to all next edges in the list of
# sorted edges
prev_junction_lengths = 0

internal_edgestarts = []
for i in range(len(edgestarts)):
edge, pos = edgestarts[i]

# increment the position with the junction length increment, and
# add it back to the edgestarts
pos += prev_junction_lengths
edgestarts[i] = (edge, pos)

# collect the names of all next junctions from the current edge
all_next_edges = []
for lane in range(self.num_lanes(edge)):
next_edge = self.next_edge(edge, lane)
for edge_i, _ in next_edge:
if edge_i not in all_next_edges:
all_next_edges.append(edge_i)

# In the case there are no next edges from the current edge (e.g.
# end of a highway), stop.
if len(all_next_edges) == 0:
continue

# get the maximum length of the edges, and add it to the junction
# increment length
max_length = max(self.edge_length(e) for e in all_next_edges)
prev_junction_lengths += max_length

# add the junctions with the position being immediately after the
# current edge
next_pos = pos + self.edge_length(edge)
for next_edge in all_next_edges:
internal_edgestarts.append((next_edge, next_pos))

# combine and sort the edgestarts and internal edgestarts
total_edgestarts = edgestarts + internal_edgestarts
total_edgestarts.sort(key=lambda tup: tup[1])

return total_edgestarts
45 changes: 2 additions & 43 deletions flow/networks/base.py
Expand Up @@ -136,7 +136,7 @@ class file
If the type variable is None, then no types are available within the
network. Furthermore, a proper example of this variable being used can
be found under `specify_types` in flow/networks/loop.py.
be found under `specify_types` in flow/networks/ring.py.
Note that, if the network is meant to generate the network from an
OpenStreetMap or template file, this variable is set to None
Expand All @@ -161,13 +161,6 @@ class file
the edge/intersection/internal_link, and the second value is the
distance of the link from some global reference, i.e. [(link_0, pos_0),
(link_1, pos_1), ...]
internal_edge_starts : list of (str, float)
A variable similar to `edge_starts` but for junctions within the
network. If no junctions are available, this variable will return the
default variable: `[(':', -1)]` needed by sumo simulations.
intersection_edge_starts : list of (str, float)
A variable similar to `edge_starts` but for intersections within
the network. This variable will be deprecated in future releases.
Example
-------
Expand Down Expand Up @@ -293,17 +286,6 @@ class file
>>> print(network.edge_starts)
>>> [('bottom', 0), ('right', 57.5), ('top', 115.0), ('left', 172.5)]
Finally, the ring network does not contain any junctions or intersections,
and as a result the `internal_edge_starts` and `intersection_edge_starts`
attributes are both set to None. For an example of a network with junctions
and intersections, please refer to: flow/networks/figure_eight.py.
>>> print(network.internal_edge_starts)
>>> [(':', -1)]
>>> print(network.intersection_edge_starts)
>>> []
"""

def __init__(self,
Expand Down Expand Up @@ -385,7 +367,7 @@ def __init__(self,

# optional parameters, used to get positions from some global reference
self.edge_starts = self.specify_edge_starts()
self.internal_edge_starts = self.specify_internal_edge_starts()
self.internal_edge_starts = [] # this will be deprecated
self.intersection_edge_starts = [] # this will be deprecated

# TODO: convert to property
Expand All @@ -408,29 +390,6 @@ def specify_edge_starts(self):
"""
return None

# TODO: convert to property
def specify_internal_edge_starts(self):
"""Define the edge starts for internal edge nodes.
This is meant to provide some global reference frame for the internal
edges in the network.
These edges are the result of finite-length connections between road
sections. This methods does not need to be specified if "no-internal-
links" is set to True in net_params.
By default, all internal edge starts are given a position of -1. This
may be overridden; however, in general we do not worry about internal
edges and junctions in large networks.
Returns
-------
list of (str, float)
list of internal junction names and starting positions,
ex: [(internal0, pos0), (internal1, pos1), ...]
"""
return [(':', -1)]

# TODO: convert to property
def specify_nodes(self, net_params):
"""Specify the attributes of nodes in the network.
Expand Down
47 changes: 6 additions & 41 deletions flow/networks/figure_eight.py
Expand Up @@ -70,13 +70,6 @@ def __init__(self,
ring_radius = net_params.additional_params["radius_ring"]
self.ring_edgelen = ring_radius * np.pi / 2.
self.intersection_len = 2 * ring_radius
self.junction_len = 2.9 + 3.3 * net_params.additional_params["lanes"]
self.inner_space_len = 0.28

# # instantiate "length" in net params
# net_params.additional_params["length"] = \
# 6 * self.ring_edgelen + 2 * self.intersection_len + \
# 2 * self.junction_len + 10 * self.inner_space_len

super().__init__(name, vehicles, net_params, initial_config,
traffic_lights)
Expand Down Expand Up @@ -225,39 +218,11 @@ def specify_connections(self, net_params):
def specify_edge_starts(self):
"""See base class."""
edgestarts = [
("bottom", self.inner_space_len),
("top", self.intersection_len / 2 + self.junction_len +
self.inner_space_len),
("upper_ring", self.intersection_len + self.junction_len +
2 * self.inner_space_len),
("right", self.intersection_len + 3 * self.ring_edgelen
+ self.junction_len + 3 * self.inner_space_len),
("left", 3 / 2 * self.intersection_len + 3 * self.ring_edgelen
+ 2 * self.junction_len + 3 * self.inner_space_len),
("lower_ring", 2 * self.intersection_len + 3 * self.ring_edgelen
+ 2 * self.junction_len + 4 * self.inner_space_len)]
("bottom", 0),
("top", self.intersection_len / 2),
("upper_ring", self.intersection_len),
("right", self.intersection_len + 3 * self.ring_edgelen),
("left", 3 / 2 * self.intersection_len + 3 * self.ring_edgelen),
("lower_ring", 2 * self.intersection_len + 3 * self.ring_edgelen)]

return edgestarts

def specify_internal_edge_starts(self):
"""See base class."""
internal_edgestarts = [
(":bottom", 0),
(":center_{}".format(self.net_params.additional_params['lanes']),
self.intersection_len / 2 + self.inner_space_len),
(":top", self.intersection_len + self.junction_len +
self.inner_space_len),
(":right", self.intersection_len + 3 * self.ring_edgelen
+ self.junction_len + 2 * self.inner_space_len),
(":center_0", 3 / 2 * self.intersection_len + 3 * self.ring_edgelen
+ self.junction_len + 3 * self.inner_space_len),
(":left", 2 * self.intersection_len + 3 * self.ring_edgelen
+ 2 * self.junction_len + 3 * self.inner_space_len),
# for aimsun
('bottom_to_top',
self.intersection_len / 2 + self.inner_space_len),
('right_to_left',
+ self.junction_len + 3 * self.inner_space_len),
]

return internal_edgestarts

0 comments on commit 3f8ccf2

Please sign in to comment.