Source code for flow.networks.base

"""Contains the base network class."""

from flow.core.params import InitialConfig
from flow.core.params import TrafficLightParams
from flow.core.params import SumoCarFollowingParams
from flow.core.params import SumoLaneChangeParams
import time
import xml.etree.ElementTree as ElementTree
from lxml import etree
from collections import defaultdict

# default sumo probability value  TODO (ak): remove
DEFAULT_PROBABILITY = 0
# default sumo vehicle length value (in meters) TODO (ak): remove
DEFAULT_LENGTH = 5
# default sumo vehicle class class TODO (ak): remove
DEFAULT_VCLASS = 0


[docs]class Network(object): """Base network class. Initializes a new network. Networks are used to specify features of a network, including the positions of nodes, properties of the edges and junctions connecting these nodes, properties of vehicles and traffic lights, and other features as well. These features can later be acquired from this class via a plethora of get methods (see documentation). This class uses network specific features to generate the necessary network configuration files needed to initialize a simulation instance. The methods of this class are called by the base network class. The network files can be created in one of three ways: * Custom networks can be generated by defining the properties of the network's directed graph. This is done by defining the nodes and edges properties using the ``specify_nodes`` and ``specify_edges`` methods, respectively, as well as other properties via methods including ``specify_types``, ``specify_connections``, etc... For more on this, see the tutorial on creating custom networks or refer to some of the available networks. * Network data can be collected from an OpenStreetMap (.osm) file. The .osm file is specified in the NetParams object. For example: >>> from flow.core.params import NetParams >>> net_params = NetParams(osm_path='/path/to/osm_file.osm') In this case, no ``specify_nodes`` and ``specify_edges`` methods are needed. However, a ``specify_routes`` method is still needed to specify the appropriate routes vehicles can traverse in the network. * Network data can be collected from an sumo-specific network (.net.xml) file. This file is specified in the NetParams object. For example: >>> from flow.core.params import NetParams >>> net_params = NetParams(template='/path/to/template') In this case, no ``specify_nodes`` and ``specify_edges`` methods are needed. However, a ``specify_routes`` method is still needed to specify the appropriate routes vehicles can traverse in the network. This class can be instantiated once and reused in multiple experiments. Note that this function stores all the relevant parameters. The generate() function still needs to be called separately. Attributes ---------- orig_name : str the variable provided under the `name` parameter to this object upon instantiation name : str the variable provided under the `name` parameter to this object upon instantiation, appended with a timestamp variable. This timestamp is meant to differentiate generated network files during parallelism vehicles : flow.core.params.VehicleParams vehicle specific parameters, used to specify the types and number of vehicles at the start of a simulation net_params : flow.core.params.NetParams network specific parameters, used primarily to identify properties of a network such as the lengths of edges and the number of lanes in each edge. This attribute is very network-specific, and should contain the variables denoted by the `ADDITIONAL_NET_PARAMS` dict in each network class file initial_config : flow.core.params.InitialConfig specifies parameters that affect the positioning of vehicle in the network at the start of a simulation. For more, see flow/core/params.py traffic_lights : flow.core.params.TrafficLightParams used to describe the positions and types of traffic lights in the network. For more, see flow/core/params.py nodes : list of dict or None list of nodes that are assigned to the network via the `specify_nodes` method. All nodes in this variable are expected to have the following properties: * **name**: a unique identifier for the node * **x**: x-coordinate of the node, in meters * **y**: y-coordinate of the node, in meters If the network is meant to generate the network from an OpenStreetMap or template file, this variable is set to None edges : list of dict or None edges that are assigned to the network via the `specify_edges` method. This include the shape, position, and properties of all edges in the network. These properties include the following mandatory properties: * **id**: name of the edge * **from**: name of the node the edge starts from * **to**: the name of the node the edges ends at * **length**: length of the edge In addition, either the following properties need to be specifically defined or a **type** variable property must be defined with equivalent attributes in `self.types`: * **numLanes**: the number of lanes on the edge * **speed**: the speed limit for vehicles on the edge Moreover, the following attributes may optionally be available: * **shape**: the positions of intermediary nodes used to define the shape of an edge. If no shape is specified, then the edge will appear as a straight line. Note that, if the network is meant to generate the network from an OpenStreetMap or template file, this variable is set to None types : list of dict or None A variable used to ease the definition of the properties of various edges. Each element in the list consists of a dict consisting of the following property: * **id**: name of the edge type. Edges in the `self.edges` attribute with a similar value under the "type" key will adopt the properties of other components of this list, such as "speed" and "numLanes". 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. Note that, if the network is meant to generate the network from an OpenStreetMap or template file, this variable is set to None connections : list of dict or None A variable used to describe how any specific node's incoming and outgoing edges/lane pairs are connected. If no connections are specified, sumo generates default connections. If the connections attribute is set to None, then the connections within the network will be specified by the simulator. Note that, if the network is meant to generate the network from an OpenStreetMap or template file, this variable is set to None routes : dict A variable whose keys are the starting edge of a specific route, and whose values are the list of edges a vehicle is meant to traverse starting from that edge. These are only applied at the start of a simulation; vehicles are allowed to reroute within the environment immediately afterwards. edge_starts : list of (str, float) a list of tuples in which the first element of the tuple is the name of 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 ------- The following examples are derived from the `RingNetwork` Network class located in flow/networks/ring.py, and should serve as an example of the types of outputs to be expected from the different variables of a network class. First of all, the ring road network class can be instantiated by running the following commands (note if this this unclear please refer to Tutorial 1): >>> from flow.networks import RingNetwork >>> from flow.core.params import NetParams, VehicleParams >>> >>> network = RingNetwork( >>> name='test', >>> vehicles=VehicleParams(), >>> net_params=NetParams( >>> additional_params={ >>> 'length': 230, >>> 'lanes': 1, >>> 'speed_limit': 30, >>> 'resolution': 40, >>> } >>> ) >>> ) The various attributes then look as follows: >>> print(network.nodes) >>> [{'id': 'bottom', 'x': '0', 'y': '-36.60563691113593'}, >>> {'id': 'right', 'x': '36.60563691113593', 'y': '0'}, >>> {'id': 'top', 'x': '0', 'y': '36.60563691113593'}, >>> {'id': 'left', 'x': '-36.60563691113593', 'y': '0'}] >>> print(network.edges) >>> [ >>> {'id': 'bottom', >>> 'type': 'edgeType', >>> 'from': 'bottom', >>> 'to': 'right', >>> 'length': '57.5', >>> 'shape': '0.00,-36.61 1.47,-36.58 2.95,-36.49 4.41,-36.34 ' >>> '5.87,-36.13 7.32,-35.87 8.76,-35.54 10.18,-35.16 ' >>> '11.59,-34.72 12.98,-34.23 14.35,-33.68 15.69,-33.07 ' >>> '17.01,-32.41 18.30,-31.70 19.56,-30.94 20.79,-30.13 ' >>> '21.99,-29.26 23.15,-28.35 24.27,-27.40 25.36,-26.40 ' >>> '26.40,-25.36 27.40,-24.27 28.35,-23.15 29.26,-21.99 ' >>> '30.13,-20.79 30.94,-19.56 31.70,-18.30 32.41,-17.01 ' >>> '33.07,-15.69 33.68,-14.35 34.23,-12.98 34.72,-11.59 ' >>> '35.16,-10.18 35.54,-8.76 35.87,-7.32 36.13,-5.87 ' >>> '36.34,-4.41 36.49,-2.95 36.58,-1.47 36.61,0.00' >>> }, >>> {'id': 'right', >>> 'type': 'edgeType', >>> 'from': 'right', >>> 'to': 'top', >>> 'length': '57.5', >>> 'shape': '36.61,0.00 36.58,1.47 36.49,2.95 36.34,4.41 36.13,5.87 ' >>> '35.87,7.32 35.54,8.76 35.16,10.18 34.72,11.59 ' >>> '34.23,12.98 33.68,14.35 33.07,15.69 32.41,17.01 ' >>> '31.70,18.30 30.94,19.56 30.13,20.79 29.26,21.99 ' >>> '28.35,23.15 27.40,24.27 26.40,25.36 25.36,26.40 ' >>> '24.27,27.40 23.15,28.35 21.99,29.26 20.79,30.13 ' >>> '19.56,30.94 18.30,31.70 17.01,32.41 15.69,33.07 ' >>> '14.35,33.68 12.98,34.23 11.59,34.72 10.18,35.16 ' >>> '8.76,35.54 7.32,35.87 5.87,36.13 4.41,36.34 2.95,36.49 ' >>> '1.47,36.58 0.00,36.61' >>> }, >>> {'id': 'top', >>> 'type': 'edgeType', >>> 'from': 'top', >>> 'to': 'left', >>> 'length': '57.5', >>> 'shape': '0.00,36.61 -1.47,36.58 -2.95,36.49 -4.41,36.34 ' >>> '-5.87,36.13 -7.32,35.87 -8.76,35.54 -10.18,35.16 ' >>> '-11.59,34.72 -12.98,34.23 -14.35,33.68 -15.69,33.07 ' >>> '-17.01,32.41 -18.30,31.70 -19.56,30.94 -20.79,30.13 ' >>> '-21.99,29.26 -23.15,28.35 -24.27,27.40 -25.36,26.40 ' >>> '-26.40,25.36 -27.40,24.27 -28.35,23.15 -29.26,21.99 ' >>> '-30.13,20.79 -30.94,19.56 -31.70,18.30 -32.41,17.01 ' >>> '-33.07,15.69 -33.68,14.35 -34.23,12.98 -34.72,11.59 ' >>> '-35.16,10.18 -35.54,8.76 -35.87,7.32 -36.13,5.87 ' >>> '-36.34,4.41 -36.49,2.95 -36.58,1.47 -36.61,0.00' >>> }, >>> {'id': 'left', >>> 'type': 'edgeType', >>> 'from': 'left', >>> 'to': 'bottom', >>> 'length': '57.5', >>> 'shape': '-36.61,0.00 -36.58,-1.47 -36.49,-2.95 -36.34,-4.41 ' >>> '-36.13,-5.87 -35.87,-7.32 -35.54,-8.76 -35.16,-10.18 ' >>> '-34.72,-11.59 -34.23,-12.98 -33.68,-14.35 ' >>> '-33.07,-15.69 -32.41,-17.01 -31.70,-18.30 ' >>> '-30.94,-19.56 -30.13,-20.79 -29.26,-21.99 ' >>> '-28.35,-23.15 -27.40,-24.27 -26.40,-25.36 ' >>> '-25.36,-26.40 -24.27,-27.40 -23.15,-28.35 ' >>> '-21.99,-29.26 -20.79,-30.13 -19.56,-30.94 ' >>> '-18.30,-31.70 -17.01,-32.41 -15.69,-33.07 ' >>> '-14.35,-33.68 -12.98,-34.23 -11.59,-34.72 ' >>> '-10.18,-35.16 -8.76,-35.54 -7.32,-35.87 -5.87,-36.13 ' >>> '-4.41,-36.34 -2.95,-36.49 -1.47,-36.58 -0.00,-36.61' >>> } >>> ] >>> print(network.types) >>> [{'id': 'edgeType', 'numLanes': '1', 'speed': '30'}] >>> print(network.connections) >>> None >>> print(network.routes) >>> { >>> 'top': ['top', 'left', 'bottom', 'right'], >>> 'left': ['left', 'bottom', 'right', 'top'], >>> 'bottom': ['bottom', 'right', 'top', 'left'], >>> 'right': ['right', 'top', 'left', 'bottom'] >>> } >>> 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, name, vehicles, net_params, initial_config=InitialConfig(), traffic_lights=TrafficLightParams()): """Instantiate the base network class. Attributes ---------- name : str A tag associated with the network vehicles : flow.core.params.VehicleParams see flow/core/params.py net_params : flow.core.params.NetParams see flow/core/params.py initial_config : flow.core.params.InitialConfig see flow/core/params.py traffic_lights : flow.core.params.TrafficLightParams see flow/core/params.py """ self.orig_name = name # To avoid repeated concatenation upon reset self.name = name + time.strftime('_%Y%m%d-%H%M%S') + str(time.time()) self.vehicles = vehicles self.net_params = net_params self.initial_config = initial_config self.traffic_lights = traffic_lights # specify routes vehicles can take self.routes = self.specify_routes(net_params) if net_params.template is None and net_params.osm_path is None: # specify the attributes of the nodes self.nodes = self.specify_nodes(net_params) # collect the attributes of each edge self.edges = self.specify_edges(net_params) # specify the types attributes (default is None) self.types = self.specify_types(net_params) # specify the connection attributes (default is None) self.connections = self.specify_connections(net_params) # this is to be used if file paths other than the the network geometry # file is specified elif type(net_params.template) is dict: if 'rou' in net_params.template: veh, rou = self._vehicle_infos(net_params.template['rou']) vtypes = self._vehicle_type(net_params.template.get('vtype')) cf = self._get_cf_params(vtypes) lc = self._get_lc_params(vtypes) # add the vehicle types to the VehicleParams object for t in vtypes: vehicles.add(veh_id=t, car_following_params=cf[t], lane_change_params=lc[t], num_vehicles=0) # add the routes of the vehicles that will be departed later # under the name of the vehicle. This will later be identified # by k.vehicles._add_departed self.routes = rou # vehicles to be added with different departure times self.template_vehicles = veh self.types = None self.nodes = None self.edges = None self.connections = None # osm_path or template as type str else: self.nodes = None self.edges = None self.types = None self.connections = None # 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.intersection_edge_starts = [] # this will be deprecated # TODO: convert to property
[docs] def specify_edge_starts(self): """Define edge starts for road sections in the network. This is meant to provide some global reference frame for the road edges in the network. By default, the edge starts are specified from the network configuration file. Note that, the values are arbitrary but do not allow the positions of any two edges to overlap, thereby making them compatible with all starting position methods for vehicles. Returns ------- list of (str, float) list of edge names and starting positions, ex: [(edge0, pos0), (edge1, pos1), ...] """ return None
# TODO: convert to property
[docs] 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
[docs] def specify_nodes(self, net_params): """Specify the attributes of nodes in the network. Parameters ---------- net_params : flow.core.params.NetParams see flow/core/params.py Returns ------- list of dict A list of node attributes (a separate dict for each node). Nodes attributes must include: * id {string} -- name of the node * x {float} -- x coordinate of the node * y {float} -- y coordinate of the node Other attributes may also be specified. See: http://sumo.dlr.de/wiki/Networks/Building_Networks_from_own_XML-descriptions#Node_Descriptions """ raise NotImplementedError
# TODO: convert to property
[docs] def specify_edges(self, net_params): """Specify the attributes of edges connecting pairs on nodes. Parameters ---------- net_params : flow.core.params.NetParams see flow/core/params.py Returns ------- list of dict A list of edges attributes (a separate dict for each edge). Edge attributes must include: * id {string} -- name of the edge * from {string} -- name of node the directed edge starts from * to {string} -- name of the node the directed edge ends at In addition, the attributes must contain at least one of the following: * "numLanes" {int} and "speed" {float} -- the number of lanes and speed limit of the edge, respectively * type {string} -- a type identifier for the edge, which can be used if several edges are supposed to possess the same number of lanes, speed limits, etc... Other attributes may also be specified. See: http://sumo.dlr.de/wiki/Networks/Building_Networks_from_own_XML-descriptions#Edge_Descriptions """ raise NotImplementedError
# TODO: convert to property
[docs] def specify_types(self, net_params): """Specify the attributes of various edge types (if any exist). Parameters ---------- net_params : flow.core.params.NetParams see flow/core/params.py Returns ------- list of dict A list of type attributes for specific groups of edges. If none are specified, no .typ.xml file is created. For information on type attributes, see: http://sumo.dlr.de/wiki/Networks/Building_Networks_from_own_XML-descriptions#Type_Descriptions """ return None
# TODO: convert to property
[docs] def specify_connections(self, net_params): """Specify the attributes of connections. These attributes are used to describe how any specific node's incoming and outgoing edges/lane pairs are connected. If no connections are specified, sumo generates default connections. Parameters ---------- net_params : flow.core.params.NetParams see flow/core/params.py Returns ------- list of dict A list of connection attributes. If none are specified, no .con.xml file is created. For information on type attributes, see: http://sumo.dlr.de/wiki/Networks/Building_Networks_from_own_XML-descriptions#Connection_Descriptions """ return None
# TODO: convert to property
[docs] def specify_routes(self, net_params): """Specify the routes vehicles can take starting from any edge. Routes can be specified in one of three ways: * In this case of deterministic routes (as is the case in the ring road network), the routes can be specified as dictionary where the key element represents the starting edge and the element is a single list of edges the vehicle must traverse, with the first edge corresponding to the edge the vehicle begins on. Note that the edges must be connected for the route to be valid. For example (from flow/networks/ring.py): >>> def specify_routes(self, net_params): >>> return { >>> "top": ["top", "left", "bottom", "right"], >>> "left": ["left", "bottom", "right", "top"], >>> "bottom": ["bottom", "right", "top", "left"], >>> "right": ["right", "top", "left", "bottom"] >>> } * Alternatively, if the routes are meant to be stochastic, each element can consist of a list of (route, probability) tuples, where the first element in the tuple is one of the routes a vehicle can take from a specific starting edge, and the second element is the probability that vehicles will choose that route. Note that, in this case, the sum of probability values for each dictionary key must sum up to one. For example, if we were to imagine the edge "right" in the ring road examples where split into two edges, "right_0" and "right_1", the routes for vehicles in this network in the probabilistic setting can be: >>> def specify_routes(self, net_params): >>> return { >>> "top": [ >>> (["top", "left", "bottom", "right_0"], 0.9), >>> (["top", "left", "bottom", "right_1"], 0.1) >>> ], >>> "left": [ >>> (["left", "bottom", "right_0", "top"], 0.3), >>> (["left", "bottom", "right_1", "top"], 0.7) >>> ], >>> "bottom": [ >>> (["bottom", "right_0", "top", "left"], 0.5), >>> (["bottom", "right_1", "top", "left"], 0.5) >>> ], >>> "right_0": [ >>> (["right_0", "top", "left", "bottom"], 1) >>> ], >>> "right_1": [ >>> (["right_1", "top", "left", "bottom"], 1) >>> ] >>> } * Finally, if you would like to assign a specific starting edge and route to a vehicle with a specific ID, you can do so by adding a element into the dictionary whose key is the name of the vehicle and whose content is the list of edges the vehicle is meant to traverse as soon as it is introduced to the network. As an example, assume we have 4 vehicles named 'human_0', 'human_1', 'human_2', and 'human_3' in the original ring road. Then, an appropriate definition of the routes may look something like: >>> def specify_routes(self, net_params): >>> return { >>> "human_0": ["top", "left", "bottom", "right"], >>> "human_1": ["left", "bottom", "right", "top"], >>> "human_2": ["bottom", "right", "top", "left"], >>> "human_3": ["right", "top", "left", "bottom"] >>> } **Note**: This feature is experimental, and may not always work as expected (for example if the starting positions and routes of a specific vehicle do not match). The `define_routes` method is optional, and need not be defined. If it is not implemented, vehicles that enter a network are assigned routes consisting solely on their current edges, and exit the network once they reach the end of their edge. Routes, however, can be reassigned during simulation via a routing controller (see flow/controllers/routing_controllers.py). Parameters ---------- net_params : flow.core.params.NetParams see flow/core/params.py Returns ------- dict Key = name of the starting edge Element = list of edges a vehicle starting from this edge must traverse *OR* a list of (route, probability) tuples for each starting edge """ return None
[docs] @staticmethod def gen_custom_start_pos(cls, net_params, initial_config, num_vehicles): """Generate a user defined set of starting positions. Parameters ---------- cls : flow.core.kernel.network.BaseKernelNetwork flow network kernel, with all the relevant methods implemented net_params : flow.core.params.NetParams network-specific parameters initial_config : flow.core.params.InitialConfig see flow/core/params.py num_vehicles : int number of vehicles to be placed on the network Returns ------- list of tuple (float, float) list of start positions [(edge0, pos0), (edge1, pos1), ...] list of int list of start lanes list of float list of start speeds """ raise NotImplementedError
@staticmethod def _vehicle_infos(file_names): """Import of vehicle from a configuration file. This is a utility function for computing vehicle information. It imports a network configuration file, and returns the information on the vehicle and add it into the Vehicle object. Parameters ---------- file_names : list of str path to the xml file to load Returns ------- dict <dict> * Key = id of the vehicle * Element = dict of departure speed, vehicle type, depart Position, depart edges """ # this is meant to deal with the case that there is only one rou file if isinstance(file_names, str): file_names = [file_names] vehicle_data = dict() routes_data = dict() type_data = defaultdict(int) for filename in file_names: # import the .net.xml file containing all edge/type data parser = etree.XMLParser(recover=True) tree = ElementTree.parse(filename, parser=parser) root = tree.getroot() # collect the departure properties and routes and vehicles whose # properties are instantiated within the .rou.xml file. This will # only apply if such data is within the file (it is not implemented # by networks in Flow). for vehicle in root.findall('vehicle'): # collect the edges the vehicle is meant to traverse route = vehicle.find('route') route_edges = route.attrib["edges"].split(' ') # collect the names of each vehicle type and number of vehicles # of each type type_vehicle = vehicle.attrib['type'] type_data[type_vehicle] += 1 vehicle_data[vehicle.attrib['id']] = { 'departSpeed': vehicle.attrib['departSpeed'], 'depart': vehicle.attrib['depart'], 'typeID': type_vehicle, 'departPos': vehicle.attrib['departPos'], } routes_data[vehicle.attrib['id']] = route_edges # collect the edges the vehicle is meant to traverse for the given # sets of routes that are not associated with individual vehicles for route in root.findall('route'): route_edges = route.attrib["edges"].split(' ') routes_data[route.attrib['id']] = route_edges return vehicle_data, routes_data @staticmethod def _vehicle_type(filename): """Import vehicle type data from a *.add.xml file. This is a utility function for outputting all the type of vehicle. Parameters ---------- filename : str path to the vtypes.add.xml file to load Returns ------- dict or None the key is the vehicle_type id and the value is a dict we've type of the vehicle, depart edges, depart Speed, departPos. If no filename is provided, this method returns None as well. """ if filename is None: return None parser = etree.XMLParser(recover=True) tree = ElementTree.parse(filename, parser=parser) root = tree.getroot() veh_type = {} # this hack is meant to support the LuST network and Flow networks root = [root] if len(root.findall('vTypeDistribution')) == 0 \ else root.findall('vTypeDistribution') for r in root: for vtype in r.findall('vType'): # TODO: make for everything veh_type[vtype.attrib['id']] = { 'vClass': vtype.attrib.get('vClass', DEFAULT_VCLASS), 'accel': vtype.attrib['accel'], 'decel': vtype.attrib['decel'], 'sigma': vtype.attrib['sigma'], 'length': vtype.attrib.get('length', DEFAULT_LENGTH), 'minGap': vtype.attrib['minGap'], 'maxSpeed': vtype.attrib['maxSpeed'], 'probability': vtype.attrib.get( 'probability', DEFAULT_PROBABILITY), 'speedDev': vtype.attrib['speedDev'] } return veh_type @staticmethod def _get_cf_params(vtypes): """Return the car-following sumo params from vtypes.""" ret = {} for typ in vtypes: # TODO: add vClass ret[typ] = SumoCarFollowingParams( speed_mode='all_checks', accel=float(vtypes[typ]['accel']), decel=float(vtypes[typ]['decel']), sigma=float(vtypes[typ]['sigma']), length=float(vtypes[typ]['length']), min_gap=float(vtypes[typ]['minGap']), max_speed=float(vtypes[typ]['maxSpeed']), probability=float(vtypes[typ]['probability']), speed_dev=float(vtypes[typ]['speedDev']) ) return ret @staticmethod def _get_lc_params(vtypes): """Return the lane change sumo params from vtypes.""" ret = {} for typ in vtypes: ret[typ] = SumoLaneChangeParams(lane_change_mode=1621) return ret def __str__(self): """Return the name of the network and the number of vehicles.""" return 'Network ' + self.name + ' with ' + \ str(self.vehicles.num_vehicles) + ' vehicles.'