-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Copied from github/sfcta/champ/lib/wrangler CHAMP5.0 release.
- Loading branch information
Elizabeth Sall
committed
Aug 4, 2014
1 parent
c54f842
commit 8d22919
Showing
22 changed files
with
5,552 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"]) | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
||
|
Oops, something went wrong.