Skip to content

Commit

Permalink
Copy of CHAMP 5.0 Network Wrangler
Browse files Browse the repository at this point in the history
Copied from github/sfcta/champ/lib/wrangler CHAMP5.0 release.
  • Loading branch information
Elizabeth Sall committed Aug 4, 2014
1 parent c54f842 commit 8d22919
Show file tree
Hide file tree
Showing 22 changed files with 5,552 additions and 0 deletions.
186 changes: 186 additions & 0 deletions HighwayNetwork.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import os, re, shutil, subprocess
from socket import gethostname

from .HwySpecsRTP import HwySpecsRTP
from .Logger import WranglerLogger
from .Network import Network
from .NetworkException import NetworkException

__all__ = ['HighwayNetwork']

class HighwayNetwork(Network):
"""
Representation of a roadway network.
"""

def __init__(self, champVersion, basenetworkpath, isTiered=False, tag=None,
hwyspecsdir=None, hwyspecs=None, tempdir=None, networkName=None):
"""
*basenetworkpath* should be a starting point for this network, and include a ``FREEFLOW.net``,
as well as ``turns[am,pm,op].pen`` files.
Also a shapefile export: FREEFLOW.[dbf,prj,shp] and FREEFLOW_nodes.[dbf,prj,shp]
*isTiered*: when False, checks out the *basenetworkpath* from Y:\networks. When True,
expects the basenetwork path to be a fullpath and uses that.
*tag*: when not *isTiered*, a tag can optionally be used for cloning the base network
*hwyspecs*, if passed in, should be an instance of :py:class:`HwySpecsRTP`. It
is only used for logging.
"""
Network.__init__(self, champVersion, networkName)

if isTiered:
(head,tail) = os.path.split(basenetworkpath)
self.applyBasenetwork(head,tail,None)
else:
self.applyingBasenetwork = True
self.cloneAndApplyProject(networkdir=basenetworkpath, tempdir=tempdir, tag=tag)

# keep a reference of the hwyspecsrtp for logging
self.hwyspecsdir = hwyspecsdir
self.hwyspecs = hwyspecs

def getProjectVersion(self, parentdir, networkdir, gitdir, projectsubdir=None):
"""
Returns champVersion for this project
See :py:meth:`Wrangler.Network.applyProject` for argument details.
"""
if projectsubdir:
champversionFilename = os.path.join(parentdir, networkdir, projectsubdir,"champVersion.txt")
else:
champversionFilename = os.path.join(parentdir, networkdir,"champVersion.txt")

try:
WranglerLogger.debug("Reading %s" % champversionFilename)
champVersion = open(champversionFilename,'r').read()
champVersion = champVersion.strip()
except:
champVersion = Network.CHAMP_VERSION_DEFAULT
return champVersion

def applyBasenetwork(self, parentdir, networkdir, gitdir):

# copy the base network file to my workspace
shutil.copyfile(os.path.join(parentdir,networkdir,"FREEFLOW.net"), "FREEFLOW.BLD")
for filename in ["turnsam.pen", "turnspm.pen", "turnsop.pen"]:
shutil.copyfile(os.path.join(parentdir,networkdir,filename), filename)

# done
self.applyingBasenetwork = False

def applyProject(self, parentdir, networkdir, gitdir, projectsubdir=None, **kwargs):
"""
Applies a roadway project by calling ``runtpp`` on the ``apply.s`` script.
By convention, the input to ``apply.s`` is ``FREEFLOW.BLD`` and the output is
``FREEFLOW.BLDOUT`` which is copied to ``FREEFLOW.BLD`` at the end of ``apply.s``
See :py:meth:`Wrangler.Network.applyProject` for argument details.
"""
# special case: base network
if self.applyingBasenetwork:
self.applyBasenetwork(parentdir, networkdir, gitdir)
self.logProject(gitdir=gitdir,
projectname=(networkdir + "\\" + projectsubdir if projectsubdir else networkdir),
projectdesc="Base network")
return

if projectsubdir:
applyDir = os.path.join(parentdir, networkdir, projectsubdir)
applyScript = "apply.s"
descfilename = os.path.join(parentdir, networkdir, projectsubdir,"desc.txt")
turnsfilename = os.path.join(parentdir, networkdir, projectsubdir, "turns.pen")
else:
applyDir = os.path.join(parentdir, networkdir)
applyScript = "apply.s"
descfilename = os.path.join(parentdir, networkdir,'desc.txt')
turnsfilename = os.path.join(parentdir, networkdir, "turns.pen")

# read the description
desc = None
try:
desc = open(descfilename,'r').read()
except:
pass

# move the FREEFLOW.BLD into place
shutil.move("FREEFLOW.BLD", os.path.join(applyDir,"FREEFLOW.BLD"))

# dispatch it, cube license
hostname = gethostname().lower()
if hostname not in ['berry','eureka','taraval','townsend','dolores','stockton','db0v07k1']:
f = open('runtpp_dispatch.tmp', 'w')
f.write("runtpp " + applyScript + "\n")
f.close()
(cuberet, cubeStdout, cubeStderr) = self._runAndLog("Y:/champ/util/bin/dispatch.bat runtpp_dispatch.tmp taraval", run_dir=applyDir)
else:
(cuberet, cubeStdout, cubeStderr) = self._runAndLog(cmd="runtpp "+applyScript, run_dir=applyDir)


nodemerge = re.compile("NODEMERGE: \d+")
linkmerge = re.compile("LINKMERGE: \d+-\d+")
for line in cubeStdout:
line = line.rstrip()
if re.match(nodemerge,line): continue
if re.match(linkmerge,line): continue
WranglerLogger.debug(line)

if cuberet != 0 and cuberet != 1:
WranglerLogger.fatal("FAIL! Project: "+applyScript)
raise NetworkException("HighwayNetwork applyProject failed; see log file")

# move it back
shutil.move(os.path.join(applyDir,"FREEFLOW.BLD"), "FREEFLOW.BLD")

# append new turn penalty file to mine
if os.path.exists(turnsfilename):
for filename in ["turnsam.pen", "turnspm.pen", "turnsop.pen"]:
newturnpens = open(turnsfilename, 'r').read()
turnfile = open(filename, 'a')
turnfile.write(newturnpens)
turnfile.close()
WranglerLogger.debug("Appending turn penalties from "+turnsfilename)

WranglerLogger.debug("")
WranglerLogger.debug("")

year = None
county = None
if (networkdir==self.hwyspecsdir and
self.hwyspecs and
projectsubdir in self.hwyspecs.projectdict):
year = self.hwyspecs.projectdict[projectsubdir]["MOD YEAR"]
county = self.hwyspecs.projectdict[projectsubdir]["County"]
desc = (self.hwyspecs.projectdict[projectsubdir]["Facility"] + ", " +
self.hwyspecs.projectdict[projectsubdir]["Action"] + ", " +
self.hwyspecs.projectdict[projectsubdir]["Span"])

self.logProject(gitdir=gitdir,
projectname=(networkdir + "\\" + projectsubdir if projectsubdir else networkdir),
year=year, projectdesc=desc, county=county)

def write(self, path='.', name='FREEFLOW.NET', writeEmptyFiles=True, suppressQuery=False, suppressValidation=False):
if not os.path.exists(path):
WranglerLogger.debug("\nPath [%s] doesn't exist; creating." % path)
os.mkdir(path)

else:
netfile = os.path.join(path,"FREEFLOW.net")
if os.path.exists(netfile) and not suppressQuery:
print "File [%s] exists already. Overwrite contents? (y/n/s) " % netfile
response = raw_input("")
WranglerLogger.debug("response = [%s]" % response)
if response == "s" or response == "S":
WranglerLogger.debug("Skipping!")
return

if response != "Y" and response != "y":
exit(0)

shutil.copyfile("FREEFLOW.BLD",os.path.join(path,name))
WranglerLogger.info("Writing into %s\\%s" % (path, name))
WranglerLogger.info("")

for filename in ["turnsam.pen", "turnspm.pen", "turnsop.pen"]:
shutil.copyfile(filename, os.path.join(path, filename))
58 changes: 58 additions & 0 deletions HwySpecsRTP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import logging

class HwySpecsRTP:
""" Simple class to read in the RTP specifications from a CSV file.
"""

def __init__(self,specsFile):
"""
Read and cache specifications. Will apply in order read in.
"""
self.projects = [] # list of RTP reference numbers
self.projectdict = {} # RTP reference number => dictionary of attributes

specs = open(specsFile,'r')
i=0
for line in specs:
i+=1
if i==1:
head=line.strip().split(',')
else:
l = line.strip().split(',')
#print l
RTPref = l[head.index("RTP Ref#")]
self.projectdict[RTPref] = {}
self.projects.append(RTPref)

self.projectdict[RTPref]["Facility"]=l[head.index("Corridor")]
self.projectdict[RTPref]["Action"]=l[head.index("Action")]
self.projectdict[RTPref]["Span"]=l[head.index("Span")]
self.projectdict[RTPref]["County"]=l[head.index("County")]
self.projectdict[RTPref]["MOD YEAR"]=int(l[head.index("MOD YEAR")])
self.projectdict[RTPref]["RTP FUNDING"]=l[head.index("RTP FUNDING")]


def listOfProjects(self,maxYear=2035,baseYear=2000):
"""
Returns the project RTP Reference numbers that qualify (after *baseYear*, before and including *maxYear*)
"""
projectList = []
for pref in self.projects:
if self.projectdict[pref]["MOD YEAR"]<=maxYear and self.projectdict[pref]["MOD YEAR"]>baseYear:
projectList.append(pref)
return projectList

def printProjects(self,fileObj):
fileObj.write("YEAR RTP FACILITY COUNTY ACTION \n")
fileObj.write("----------------------------------------------------\n")
for p in self.projects:
fileObj.write( str(p["MOD YEAR"])+" "+p["RTP REF"]+" "+p["Facility"]+" "+p["Action"]+" "+p["County"]+"\n")

def logProjects(self, logger):
logger.info("YEAR RTP FACILITY COUNTY ACTION ")
logger.info("----------------------------------------------------")
for p in self.projects:
logger.info( str(p["MOD YEAR"])+" "+p["RTP REF"]+" "+p["Facility"]+" "+p["Action"]+" "+p["County"])



28 changes: 28 additions & 0 deletions Linki.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Linki(dict):
""" Linki Link. Has A-node, B-node, possibly a comment and a distance.
"""
def __init__(self):
dict.__init__(self)
self.A=''
self.B=''
self.comment=''
self.distance=''
self.xferTime=''
self.accessType=''

def __repr__(self):
s = "%8s %8s" % (self.A, self.B)

# access links have a type and a transfer time
if self.accessType != '':
s += " %s" % self.accessType

if self.xferTime != '':
s += " %3s" % self.xferTime
elif self.distance != '':
s += " %8s" % self.distance

if self.comment != '':
s += " %s" % (self.comment)
return s

39 changes: 39 additions & 0 deletions Logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import logging

__all__ = ['WranglerLogger', 'setupLogging']


# for all the Wrangler logging needs!
WranglerLogger = logging.getLogger("WranglerLogger")


def setupLogging(infoLogFilename, debugLogFilename, logToConsole=True):
""" Sets up the logger. The infoLog is terse, just gives the bare minimum of details
so the network composition will be clear later.
The debuglog is very noisy, for debugging.
Pass none to either.
Spews it all out to console too, if logToConsole is true.
"""
# create a logger
WranglerLogger.setLevel(logging.DEBUG)

if infoLogFilename:
infologhandler = logging.StreamHandler(open(infoLogFilename, 'w'))
infologhandler.setLevel(logging.INFO)
infologhandler.setFormatter(logging.Formatter('%(message)s'))
WranglerLogger.addHandler(infologhandler)

if debugLogFilename:
debugloghandler = logging.StreamHandler(open(debugLogFilename,'w'))
debugloghandler.setLevel(logging.DEBUG)
debugloghandler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%Y-%m-%d %H:%M'))
WranglerLogger.addHandler(debugloghandler)

if logToConsole:
consolehandler = logging.StreamHandler()
consolehandler.setLevel(logging.DEBUG)
consolehandler.setFormatter(logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s'))
WranglerLogger.addHandler(consolehandler)


Loading

0 comments on commit 8d22919

Please sign in to comment.