Skip to content

Commit

Permalink
committing odpopulator package
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed Oct 11, 2013
1 parent f37fddb commit 956143e
Show file tree
Hide file tree
Showing 6 changed files with 948 additions and 0 deletions.
83 changes: 83 additions & 0 deletions src/odpopulator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'''
OD populator package main file
Contains functions to generate the od_matrix and parse .taz.xml and .odm files
'''

import xml.etree.ElementTree as ET
import odmatrix
import odparser
import odloader

def generate_odmatrix(taz_file, odm_file):
'''
Generates an ODMatrix from the .taz.xml and .odm files
:param taz_file: the path to the .taz.xml file
:type taz_file: str
:param odm_file: the path to the .odm file
:type odm_file: str
return: the OD matrix loaded with the districts and trips from the files
:rtype: odmatrix.ODMatrix
'''
od_matrix = odmatrix.ODMatrix()

parse_taz_file(od_matrix, taz_file)
parse_odm_file(od_matrix, odm_file)

return od_matrix

def parse_taz_file(od_matrix, taz_file):
'''
Fills the od_matrix with the districts found in the taz_file
:param od_matrix: the OD matrix to be filled
:type od_matrix: odmatrix.ODMatrix
:param taz_file: the path to the .taz.xml file
:type taz_file: str
return: the OD matrix loaded with the districts information
:rtype: odmatrix.ODMatrix
'''
taz_tree = ET.parse(taz_file)


for element in taz_tree.getroot():
sources = []
sinks = []
for src_snk in element:

if src_snk.tag == 'tazSource':

sources.append({
'id': src_snk.get('id'),
'weight': float(src_snk.get('weight'))
})

else:
sinks.append({
'id': src_snk.get('id'),
'weight': float(src_snk.get('weight'))
})



taz = odmatrix.TAZ(element.get('id'), sources, sinks)
od_matrix.add_taz(taz)

return odmatrix

def parse_odm_file(od_matrix, odm_file):
'''
Fills the od_matrix with trip information of the odm_file.
The matrix must be already filled with the districts information
:param od_matrix: the OD matrix to be filled
:type od_matrix: odmatrix.ODMatrix
:param odm_file: the path to the .odm file
:type odm_file: str
return: the OD matrix loaded with the trip information
:rtype: odmatrix.ODMatrix
'''
odm_parser = odparser.create_parser(odm_file, od_matrix)
odm_parser.parse()
return od_matrix
170 changes: 170 additions & 0 deletions src/odpopulator/odkeeper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
'''
This script can be used standalone or imported in another script.
As a standalone, it connects to a SUMO simulation and when a vehicle leaves
the simulation, it is replaced by a new one.
The origins and destinations of inserted vehicles respect a given OD matrix.
When imported, the user can use the ODKeeper methods act and replace
vehicles in the road network
This script requires the search module available at maslab-googlecode
Created on Jan 12, 2013
@author: anderson
'''
import traci, sumolib
import os, sys
from optparse import OptionParser

sys.path.append('..')
import odpopulator

#looks up on ../lib to import Guilherme's implementation of Dijkstra algorithm
path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'lib'))
if not path in sys.path: sys.path.append(path)
import search

class ODKeeper(object):
'''
Keeps the load in the road network by replacing vehicles who leave
with new ones, respecting the proportions defined in an OD matrix
'''


def __init__(self, road_net, od_matrix, num_veh = 900, max_per_action = 0, aux_prefix = 'aux',
exclude_prefix = None):
'''
Initializes the od-keeper
:param road_net: the road network
:type road_net: sumolib.net.Net
:param od_matrix: the OD matrix loaded with districts and trip information
:type od_matrix: odmatrix.ODMatrix
:param num_veh: the number of vehicles to be kept in the network
:type num_veh: int
:param max_per_action: the max. number of insertions per action of the controller
:type max_per_action: int
:param aux_prefix: the prefix of the vehicles created by the ODLoader
:type aux_prefix: str
:param exclude_prefix: the prefix of the vehicle ID's to be discounted while checking the total
:type exclude_prefix: str
'''
self._road_net = road_net
self._od_matrix = od_matrix
self._num_veh = num_veh
self._max_per_action = max_per_action
self._aux_prefix = aux_prefix
self._exclude_prefix = exclude_prefix
self._insertions = 0

def act(self):
'''
Must be called at each timestep. Stores the drivers that departed for
writing them later in an output file
'''

thisTs = traci.simulation.getCurrentTime() / 1000

#does nothing if we have more vehicles than the desired number
if len(traci.vehicle.getIDList()) > self._num_veh:
return

for vehId in traci.simulation.getArrivedIDList():

if self._exclude_prefix is not None and self._exclude_prefix in vehId:
continue

(orig_taz, dest_taz) = self._od_matrix.select_od_taz()
orig_edg = self._road_net.getEdge(orig_taz.select_source()['id'])
dest_edg = self._road_net.getEdge(dest_taz.select_sink()['id'])

theRoute = search.dijkstra(
self._road_net,
orig_edg,
dest_edg, None, True
)
#tries again if dest is not reachable from orig
if theRoute is None:
continue

edges = [edge.getID().encode('utf-8') for edge in theRoute]

vehId = str(thisTs) + '-' + vehId
traci.route.add(vehId, edges)
traci.vehicle.add(vehId, vehId, traci.vehicle.DEPART_NOW, 5.10, 0)

#print '%s\t%s\t%d' % (orig.getID(), dest.getID(), traci.simulation.getCurrentTime() / 1000)

#print ['%.2f' % traci.edge.getLastStepOccupancy(e) for e in edges], traci.simulation.getCurrentTime() / 1000


if __name__ == "__main__":
optParser = OptionParser()

optParser.add_option("-n", "--net-file", dest="netfile",
help="road network file (mandatory)")
optParser.add_option("-t", "--taz-file", dest="tazfile",
help="traffic assignment zones definition file (mandatory)")
optParser.add_option("-m", "--odm-file", dest="odmfile",
help="OD matrix trips definition file (mandatory)")
optParser.add_option("-l", "--limit-per-ts", type='int', dest="max_per_ts", default=0,
help="Limit the number of vehicles to be inserted at each timestep")
# optParser.add_option("-r", "--route-file", dest="routefile",
# help="route file to be generated")
optParser.add_option("-d", "--driver-number", type="int", dest="numveh",
default=1000, help="desired number of drivers to keep")
optParser.add_option("-b", "--begin", type="int", default=0, help="begin time")
optParser.add_option("-e", "--end", type="int", default=7200, help="end time")
optParser.add_option("-p", "--port", type="int", default=8813, help="TraCI port")
optParser.add_option("-x", "--exclude", type="string", default=None, dest='exclude',
help="Exclude replacing drivers whose ID have the given value")
#optParser.add_option("-s", "--seed", type="int", help="random seed")

(options, args) = optParser.parse_args()
# if not options.netfile or not options.routefile:
# optParser.print_help()
# sys.exit()

net = sumolib.net.readNet(options.netfile)

traci.init(options.port)

drivers = {} #stores drivers information when they depart

if options.begin > 0:
print 'Skipping %d timesteps.' % options.begin
traci.simulationStep(options.begin * 1000)

# for drvid in traci.simulation.getDepartedIDList():
# drivers[drvid] = {
# 'depart': traci.simulation.getCurrentTime() / 1000,
# 'route': traci.vehicle.getRoute(drvid)
# }

print 'From ts %d to %d, will replace vehicles' % (options.begin, options.end)

#creates the odloader and initializes it with the drivers already recorded
od_matrix = odpopulator.generate_odmatrix(options.tazfile, options.odmfile)
loadkeeper = ODKeeper(net, od_matrix, options.numveh, options.max_per_ts, 'aux', options.exclude)

for i in range(options.begin, options.end):
traci.simulationStep()
loadkeeper.act()

print 'Now, simulating until all drivers leave the network'
while (True): #simulates the remaining steps till the end
traci.simulationStep()
if len(traci.vehicle.getIDList()) == 0:
break

traci.close()

print 'DONE.'


Loading

0 comments on commit 956143e

Please sign in to comment.