class GetStationAccessFile(_m.Tool()): version = '1.0.0' tool_run_msg = "" number_of_tasks = 6 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only Scenario = _m.Attribute(_m.InstanceType) # common variable or parameter SearchRadius = _m.Attribute(float) GoStationSelectorExpression = _m.Attribute(str) ExportFile = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario self.SearchRadius = 1000.0 self.GoStationSelectorExpression = "i=7000,8000" def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Get Station Access File v%s" % self.version, description= "<p class='tmg_left'> Produces a table indicating which zones are within a 1km \ (or other user-specified distance) from subway or GO train stations. \ Subway stations are identified as stops of lines with mode = <b>'m'</b>. \ GO stations can be identified in one of two ways: \ <ol class='tmg_left'><li> Station centroids, \ identified by a node selector expression; or</li><li> Stops of lines with mode \ = <b>'r'.</b></li></ol> \ <p class='tmg_left'> This data is saved into a CSV file with three columns: \ <em>'Zone', 'NearSubway' , 'NearGO'</em>. The first column identifies the zone, \ the second column indicates whether a zone is within the radius of a subway \ station (0 or 1), and the third column indicates whether a zone is within the \ radius of a GO Train station (0 or 1). Zones not in the radius of either are not \ listed.</p>", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) pb.add_text_box(tool_attribute_name='SearchRadius', size=10, title="Search Radius", note="In coordinate units (m)") basepath = _path.dirname(_MODELLER.desktop.project_file_name()) pb.add_select_file(tool_attribute_name='ExportFile', window_type='save_file', file_filter="*.csv", start_path=basepath, title="Output File") pb.add_text_box(tool_attribute_name='GoStationSelectorExpression', size=100, multi_line=True, title="GO Station Selector", note="<font color='green'><b>Optional:</b></font> \ Write a zone filter expression to select GO Station centroids.\ <br>If ommitted, this tool will use GO rail line stops." ) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Run complete.") def __call__(self, xtmf_ScenarioNumber, SearchRadius, GoStationSelectorExpression, ExportFile): #---1 Set up scenario self.Scenario = _m.Modeller().emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) self.SearchRadius = SearchRadius self.GoStationSelectorExpression = GoStationSelectorExpression self.ExportFile = ExportFile try: self._Execute() except Exception as e: raise Exception(_traceback.format_exc()) ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): #self.ExportFile = _path.splitext(self.ExportFile)[0] + ".csv" with self._FlagAttributeMANAGER(): try: netCalcTool = _MODELLER.tool( 'inro.emme.network_calculation.network_calculator') except Exception as e: netCalcTool = _MODELLER.tool( 'inro.emme.standard.network_calculation.network_calculator' ) if self.GoStationSelectorExpression: _m.logbook_write("Flagging GO station centroids.") self.TRACKER.runTool(netCalcTool, self._GetCentroidFlagSpec(), scenario=self.Scenario) else: self.TRACKER.completeTask() _m.logbook_write("Building search grid") network = self.Scenario.get_network() self.TRACKER.completeTask() network.create_attribute('NODE', 'subStation', 0) network.create_attribute('NODE', 'goStation', 0) with _m.logbook_trace("Getting station coordinates"): self._FlagTransitStops(network) subwayStations, goStations = self._GetNodeSet(network) with nested(_m.logbook_trace("Performing search"), open(self.ExportFile, 'w')) as (log, writer): #Prepare the search grid extents = _spindex.get_network_extents(network) spatialIndex = _spindex.GridIndex(extents, marginSize=1.0) for zone in network.centroids(): spatialIndex.insertPoint(zone) self.TRACKER.startProcess( len(subwayStations) + len(goStations)) for station in subwayStations: nearbyNodes = spatialIndex.queryCircle( station.x, station.y, self.SearchRadius) for node in nearbyNodes: dist = sqrt((node.x - station.x)**2 + (node.y - station.y)**2) if dist > self.SearchRadius: continue node.subStation = 1 self.TRACKER.completeSubtask() for station in goStations: nearbyNodes = spatialIndex.queryCircle( station.x, station.y, self.SearchRadius) for node in nearbyNodes: dist = sqrt((node.x - station.x)**2 + (node.y - station.y)**2) if dist > self.SearchRadius: continue node.goStation = 1 self.TRACKER.completeSubtask() #Prepare the file writer.write("Zone,NearSubway,NearGO") for centroid in network.centroids(): writer.write("\n%s,%s,%s" % (centroid.number, centroid.subStation, centroid.goStation)) self.TRACKER.completeTask() ########################################################################################################## #----CONTEXT MANAGERS--------------------------------------------------------------------------------- ''' Context managers for temporary database modifications. ''' @contextmanager def _FlagAttributeMANAGER(self): if self.GoStationSelectorExpression: att = self.Scenario.create_extra_attribute('NODE', '@xflag') try: yield finally: if self.GoStationSelectorExpression: self.Scenario.delete_extra_attribute('@xflag') #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Scenario": str(self.Scenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _GetCentroidFlagSpec(self): spec = { "result": "@xflag", "expression": "1", "aggregation": None, "selections": { "node": self.GoStationSelectorExpression }, "type": "NETWORK_CALCULATION" } return spec def _GetCheckMode(self, network, modeId): mode = network.mode(modeId) if mode is None: raise Exception("Scenario %s does not have mode '%s' defined!" % (self.Scenario.id, modeId)) elif mode.type != 'TRANSIT': raise Exception("Scenario %s mode '%s' is not a transit mode!" % (self.Scenario.id, modeId)) return mode def _FlagTransitStops(self, network): network.create_attribute('NODE', 'isStop', default_value=0) subwayMode = self._GetCheckMode(network, 'm') trainMode = self._GetCheckMode(network, 'r') self.TRACKER.startProcess(network.element_totals['transit_lines']) for line in network.transit_lines(): if line.mode == subwayMode: for segment in line.segments(include_hidden=True): if segment.allow_alightings or segment.allow_boardings: segment.i_node.isStop = 1 #SUBWAY STOP elif line.mode == trainMode: for segment in line.segments(include_hidden=True): if segment.allow_alightings or segment.allow_boardings: segment.i_node.isStop = 2 #GO TRAIN STOP self.TRACKER.completeSubtask() self.TRACKER.completeTask() def _GetNodeSet(self, network): subwayStations = set() goStations = set() subStopCount = 0 goStopCount = 0 self.TRACKER.startProcess(network.element_totals['regular_nodes']) for node in network.regular_nodes(): if node.isStop == 1: subwayStations.add(node) subStopCount += 1 elif node.isStop == 2 and not self.GoStationSelectorExpression: goStations.add(node) goStopCount += 1 self.TRACKER.completeSubtask() self.TRACKER.completeTask() if self.GoStationSelectorExpression: self.TRACKER.startProcess(network.element_totals['centroids']) for centroid in network.centroids(): if centroid['@xflag'] == 1: goStations.add(centroid) goStopCount += 1 self.TRACKER.completeSubtask() self.TRACKER.completeTask() _m.logbook_write("Found %s subway stations and %s GO train stations." % (subStopCount, goStopCount)) return (subwayStations, goStations) @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class AddNodeWeights(_m.Tool()): version = '0.1.0' tool_run_msg = "" report_html = "" Scenario = _m.Attribute(_m.InstanceType) MassAttribute = _m.Attribute(_m.InstanceType) def __init__(self): self.Scenario = _MODELLER.scenario self._tracker = _util.ProgressTracker(5) def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Add Node Weights v%s" % self.version, description="Adds node weights to existing network nodes \ for use in centroid generation. Higher weights are \ more likely to be connected to centroid connectors in CCGEN.\ <br><br>The node weights are assigned as follows: \ <br> <ul style=\"list-style-type:none\">\ <li><b>1</b>: default value \ <li><b>2</b>: nodes at intersections with transit stop(s) \ <li><b>3</b>: mid-block nodes without any transit stops \ <li><b>4</b>: mid-block nodes with transit stop(s) \ <li><b>5</b>: dead-end nodes without any transit stops \ <li><b>6</b>: dead-end nodes with transit stop(s)</ul>\ ", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name="Scenario", title="Select Scenario", allow_none=False) pb.add_select_attribute( tool_attribute_name="MassAttribute", filter='NODE', allow_none=True, title="Node weight attribute", note="Attribute which node weights will be stored in.") return pb.render() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg def run(self): self.tool_run_msg = "" '''Run is called from Modeller.''' try: self._execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise def _execute(self): network = self.Scenario.get_network() print 'loaded network' network.create_attribute('NODE', 'is_stop', False) for segment in network.transit_segments(): if segment.allow_boardings or segment.allow_alightings: segment.i_node.is_stop = True print 'flagged all transit stops' network.create_attribute('NODE', 'degree', 0) for node in network.regular_nodes(): neighbours = set() for link in node.outgoing_links(): j_node = link.j_node if j_node.is_centroid: continue #Skip connected centroids neighbours.add(j_node.number) for link in node.incoming_links(): i_node = link.i_node if i_node.is_centroid: continue #Skip connected centroids neighbours.add(i_node.number) node.degree = len(neighbours) print "calculated degrees" for node in network.regular_nodes(): weight = 1 degree = node.degree if degree == 1: weight = 5 elif degree == 2: weight = 3 if node.is_stop: weight += 1 node[self.MassAttribute.id] = weight print "processed node weight" self.Scenario.publish_network(network, resolve_attributes=True) print "published network" self.tool_run_msg = _m.PageBuilder.format_info( "Node weights have successfully been added to %s." % (self.MassAttribute.id))
class ExtractStationBoardingsAlightings(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here COLON = ':' COMMA = ',' #---PARAMETERS xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only Scenario = _m.Attribute(_m.InstanceType) # common variable or parameter StationNodeFile = _m.Attribute(str) ReportFile = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): if EMME_VERSION < (4, 1, 5): raise ValueError( "Tool not compatible. Please upgrade to version 4.1.5+") pb = _tmgTPB.TmgToolPageBuilder( self, title="Export Station Boardings and Alightings v%s" % self.version, description="Extracts total boardings and alightings for a list \ of nodes defined in a CSV file.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) pb.add_select_file(tool_attribute_name='ReportFile', title="Report file", file_filter="*.csv", window_type='save_file') pb.add_select_file( tool_attribute_name='StationNodeFile', title="Station Node file:", window_type='file', file_filter="*.csv", note="Station node file contains the following two columns: \ <ul><li>node_id</li>\ <li>label</li></ul> \ where label is whatever you wish to label the node in the output." ) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg ########################################################################################################## def __call__(self, xtmf_ScenarioNumber, ReportFile, StationNodeFile): if EMME_VERSION < (4, 1, 5): raise ValueError( "Tool not compatible. Please upgrade to version 4.1.5+") #---1 Set up scenario self.Scenario = _MODELLER.emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) if ReportFile: self.ReportFile = ReportFile else: raise Exception("Report file location not indicated!") if StationNodeFile: self.StationNodeFile = StationNodeFile else: raise Exception("No station node file selected") try: self._Execute() except Exception as e: msg = str(e) + "\n" + _traceback.format_exc() raise Exception(msg) ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): if not self.Scenario.has_transit_results: raise Exception("Scenario %s has no transit results" % self.Scenario) network = self.Scenario.get_network() stations, badNodes = self._LoadStationNodeFile(network) if len(badNodes) > 0: print "%s node IDs were not found in the network and were skipped." % len( badNodes) pb = _m.PageBuilder("NodeIDs not in network") pb.add_text_element( "<b>The following node IDs were not found in the network:</b>" ) for id in badNodes: pb.add_text_element(id) _m.logbook_write( "Some IDs were not found in the network. Click for details.", value=pb.render()) nodeValues = self._CalcBoardingAlighting(network, stations) self._OutputResults(nodeValues) ########################################################################################################## def _GetAtts(self): atts = { "Scenario": str(self.Scenario), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _LoadStationNodeFile(self, network): badIds = set() nodeDict = {} with open(self.StationNodeFile) as reader: header = reader.readline() cells = header.strip().split(self.COMMA) nodeCol = cells.index('node_id') labelCol = cells.index('label') for num, line in enumerate(reader): cells = line.strip().split(self.COMMA) id = cells[nodeCol] label = cells[labelCol] node = network.node(id) if node is None: badIds.add(id) continue #Skip and report else: nodeDict[node.id] = [node.id] nodeDict[node.id].append(label) return nodeDict, badIds def _CalcBoardingAlighting(self, network, nodeIds): for id in nodeIds: baseNode = network.node(id) checkNodes = [] for node in network.nodes(): if node.x == baseNode.x: if node.y == baseNode.y: checkNodes.append(node) totalBoard = 0 totalAlight = 0 initialBoards = 0 finalAlights = 0 for node in checkNodes: for segment in node.outgoing_segments(include_hidden=True): board = segment.transit_boardings totalBoard += board voltr = segment.transit_volume index = segment.number - 1 voltrLast = segment.line.segment(index).transit_volume totalAlight += (voltrLast + board - voltr) initialBoards += node.initial_boardings finalAlights += node.final_alightings nodeIds[id].append(round(totalBoard)) nodeIds[id].append(round(totalBoard - initialBoards)) nodeIds[id].append(round(totalAlight - finalAlights)) nodeIds[id].append(round(totalAlight)) return nodeIds def _OutputResults(self, valueDict): with open(self.ReportFile, 'wb') as csvfile: nodeWrite = csv.writer(csvfile, delimiter=',') nodeWrite.writerow([ 'node_id', 'label', 'boardings', 'transfer_boardings', 'transfer_alightings', 'alightings' ]) for key, values in sorted(valueDict.iteritems()): nodeWrite.writerow(values)
class TollBasedRoadAssignment(_m.Tool()): version = '2.2.1' tool_run_msg = "" number_of_tasks = 4 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) #---Variable definitions xtmf_ScenarioNumber = _m.Attribute(int) Scenario = _m.Attribute(_m.InstanceType) xtmf_DemandMatrixNumber = _m.Attribute(int) DemandMatrix = _m.Attribute(_m.InstanceType) LinkTollAttributeId = _m.Attribute(str) TimesMatrixId = _m.Attribute(str) CostMatrixId = _m.Attribute(str) TollsMatrixId = _m.Attribute(str) RunTitle = _m.Attribute(str) PeakHourFactor = _m.Attribute(float) LinkCost = _m.Attribute(float) TollCost = _m.Attribute(float) TollWeight = _m.Attribute(float) Iterations = _m.Attribute(int) rGap = _m.Attribute(float) brGap = _m.Attribute(float) normGap = _m.Attribute(float) PerformanceFlag = _m.Attribute(bool) SOLAFlag = _m.Attribute(bool) def __init__(self): self._tracker = _util.ProgressTracker(self.number_of_tasks) self.Scenario = _MODELLER.scenario mf10 = _MODELLER.emmebank.matrix('mf10') if mf10 != None: self.DemandMatrix = mf10 self.PeakHourFactor = 0.43 self.LinkCost = 0 self.TollCost = 0 self.TollWeight = 0 self.Iterations = 100 self.rGap = 0 self.brGap = 0.1 self.normGap = 0.05 self.PerformanceFlag = False self.RunTitle = "" self.LinkTollAttributeId = "@toll" if EMME_VERSION >= 4.1: self.SOLAFlag = True else: self.SOLAFlag = False def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Toll Based Road Assignment v%s" % self.version, description= "Executes a standard Emme traffic assignment using tolls for link \ costs converted to a time penalty, using a specified link extra attribute \ containing the toll value. The actual times and costs are recovered \ by running a second 'all-or-nothing' assignment. This version uses a link \ extra attribute already containing the link toll cost.\ <br><br><b>Temporary Storage Requirements:</b> 1 extra \ link attributes, 1 full matrix, 1 scenario.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_header("SCENARIO") pb.add_select_scenario(tool_attribute_name="Scenario", title="Select a Scenario", allow_none=False) matrixCount = sum( [1 for m in _MODELLER.emmebank.matrices() if m.type == 'FULL']) demandMatrixNote = "" if matrixCount == 0: demandMatrixNote = "<font color=red><b>No full matrices in emmebank!</b></font>" pb.runnable = False pb.add_select_matrix(tool_attribute_name="DemandMatrix", title="Select a demand matrix", filter="FULL", note=demandMatrixNote, allow_none=False) keyval = {} for att in self.Scenario.extra_attributes(): if not att.type == 'LINK': continue label = "{id} ({domain}) - {name}".format(id=att.name, domain=att.type, name=att.description) keyval[att.name] = label pb.add_select(tool_attribute_name='LinkTollAttributeId', keyvalues=keyval, title="Link Toll Attribute") pb.add_header("OUTPUT MATRICES") with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_select_new_matrix(tool_attribute_name='TimesMatrixId', overwrite_existing=True, matrix_type='FULL', note='Create or override', title='Travel times matrix') with t.table_cell(): pb.add_select_new_matrix(tool_attribute_name="CostMatrixId", overwrite_existing=True, matrix_type='FULL', note='Create or override', title='Travel costs matrix') with t.table_cell(): pb.add_select_new_matrix(tool_attribute_name="TollsMatrixId", overwrite_existing=True, matrix_type='FULL', note='Create or override', title='Tolls matrix') pb.add_text_box(tool_attribute_name='RunTitle', size=25, title="Run Title", note="25-char run descriptor") pb.add_header("PARAMETERS") with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_html("<b>Peak Hour Factor</b>") with t.table_cell(): pb.add_text_box(tool_attribute_name="PeakHourFactor", size=10) with t.table_cell(): pb.add_html( "Converts peak period demand to a single assignment hour.") t.new_row() with t.table_cell(): pb.add_html("<b>Link Unit Cost</b>") with t.table_cell(): pb.add_text_box(tool_attribute_name="LinkCost", size=10) with t.table_cell(): pb.add_html("Link base cost, in $/km") t.new_row() with t.table_cell(): pb.add_html("<b>Toll Perception</b>") with t.table_cell(): pb.add_text_box(tool_attribute_name="TollWeight", size=10) with t.table_cell(): pb.add_html("The generalized perception of toll, in $/hr") pb.add_header("CONVERGANCE CRITERIA") with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_text_box(tool_attribute_name="Iterations", size=5, title='Iterations') with t.table_cell(): pb.add_text_box(tool_attribute_name="rGap", size=12, title='Relative gap') #t.new_row() with t.table_cell(): pb.add_text_box(tool_attribute_name="brGap", size=12, title='Best relative gap') with t.table_cell(): pb.add_text_box(tool_attribute_name="normGap", size=12, title='Normalized gap') pb.add_header("Tool Options") pb.add_checkbox( tool_attribute_name="PerformanceFlag", label="Enable high performance mode?", note="This mode will use more cores for assignment,<br>\ at the cost of slowing down other processes.") if EMME_VERSION >= 4.1: pb.add_checkbox(tool_attribute_name='SOLAFlag', label="Use SOLA traffic assignment?") pb.add_html(""" <script type="text/javascript"> $(document).ready( function () { var tool = new inro.modeller.util.Proxy(%s) ; $("#Scenario").bind('change', function() { $(this).commit(); $("#LinkTollAttributeId") .empty() .append(tool._GetSelectAttributeOptionsHTML()) inro.modeller.page.preload("#LinkTollAttributeId"); $("#LinkTollAttributeId").trigger('change'); }); }); </script>""" % pb.tool_proxy_tag) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" '''Run is called from Modeller.''' self.isRunningFromXTMF = False if self.DemandMatrix == None: raise NullPointerException("Demand matrix not specified") if self.LinkTollAttributeId == None: raise NullPointerException("Link toll attribute not specified") if self.PeakHourFactor == None: raise NullPointerException("Peak hour factor not specified") if self.LinkCost == None: raise NullPointerException("Link unit cost not specified") if self.TollCost == None: raise NullPointerException("Toll unit cost not specified") if self.TollWeight == None: raise NullPointerException("Toll perception not specified") if self.Iterations == None: raise NullPointerException("Max iterations not specified") if self.rGap == None: raise NullPointerException("Relative gap not specified") if self.brGap == None: raise NullPointerException("Best relative gap not specified") if self.normGap == None: raise NullPointerException("Normalized gap not specified") try: self._execute() except Exception, e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Run complete.")
class ReturnBoardings(_m.Tool()): version = '0.1.0' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters necessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get initialized during construction (__init__) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only xtmf_LineAggregationFile = _m.Attribute(str) xtmf_CheckAggregationFlag = _m.Attribute(bool) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker def page(self): pb = _m.ToolPageBuilder(self, title="Return Boardings", description="Cannot be called from Modeller.", runnable=False, branding_text="XTMF") return pb.render() ########################################################################################################## def __call__(self, xtmf_ScenarioNumber, xtmf_LineAggregationFile, xtmf_CheckAggregationFlag): _m.logbook_write("Extracting boarding results") #---1 Set up scenario scenario = _m.Modeller().emmebank.scenario(xtmf_ScenarioNumber) if (scenario is None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) if not scenario.has_transit_results: raise Exception( "Scenario %s does not have transit assignment results" % xtmf_ScenarioNumber) self.xtmf_LineAggregationFile = xtmf_LineAggregationFile self.xtmf_CheckAggregationFlag = xtmf_CheckAggregationFlag try: return self._Execute(scenario) except Exception as e: msg = str(e) + "\n" + _traceback.format_exc() raise Exception(msg) ########################################################################################################## def _Execute(self, scenario): lineAggregation = self._LoadLineAggregationFile() lineBoardings = self._GetLineResults(scenario) netSet = set([key for key in lineBoardings.iterkeys()]) if self.xtmf_CheckAggregationFlag: self._CheckAggregationFile(netSet, lineAggregation) self.TRACKER.completeTask() results = {} self.TRACKER.startProcess(len(lineBoardings)) for lineId, lineCount in lineBoardings.iteritems(): if not lineId in lineAggregation: self.TRACKER.completeSubtask() continue #Skip unmapped lines lineGroupId = lineAggregation[lineId] if lineGroupId in results: results[lineGroupId] += lineCount else: results[lineGroupId] = lineCount self.TRACKER.completeSubtask() print "Extracted results from Emme" return str(results) def _LoadLineAggregationFile(self): mapping = {} with open(self.xtmf_LineAggregationFile) as reader: reader.readline() for line in reader: cells = line.strip().split(',') key = cells[0].strip() val = cells[1].strip() mapping[key] = val return mapping def _GetLineResults(self, scenario): results = _util.fastLoadSummedSegmentAttributes( scenario, ['transit_boardings']) retVal = {} for lineId, attributes in results.iteritems(): id = str(lineId) retVal[id] = attributes['transit_boardings'] return retVal def _CheckAggregationFile(self, netSet, lineAggregation): aggSet = set([key for key in lineAggregation.iterkeys()]) linesInNetworkButNotMapped = [id for id in (netSet - aggSet)] linesMappedButNotInNetwork = [id for id in (aggSet - netSet)] if len(linesMappedButNotInNetwork) > 0: msg = "%s lines have been found in the network without a line grouping: " % len( linesInNetworkButNotMapped) msg += ",".join(linesInNetworkButNotMapped[:10]) if len(linesInNetworkButNotMapped) > 10: msg += "...(%s more)" % (len(linesInNetworkButNotMapped) - 10) print msg if len(linesMappedButNotInNetwork) > 0: msg = "%s lines have been found in the aggregation file but do not exist in the network: " % len( linesMappedButNotInNetwork) msg += ",".join(linesMappedButNotInNetwork[:10]) if len(linesMappedButNotInNetwork) > 10: msg += "...(%s more)" % (len(linesMappedButNotInNetwork) - 10) print msg ########################################################################################################## @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class OperatorTransferMatrix(_m.Tool()): version = '1.1.2' tool_run_msg = "" number_of_tasks = 8 # For progress reporting, enter the integer number of tasks here #---PARAMETERS Scenario = _m.Attribute(_m.InstanceType) xtmf_ScenarioNumber = _m.Attribute(int) DemandMatrixId = _m.Attribute(str) ClassName = _m.Attribute(str) ExportTransferMatrixFlag = _m.Attribute(bool) LineGroupOptionOrAttributeId = _m.Attribute(str) TransferMatrixFile = _m.Attribute(str) ExportWalkAllWayMatrixFlag = _m.Attribute(bool) AggregationPartition = _m.Attribute(_m.InstanceType) xtmf_AggregationPartition = _m.Attribute(str) WalkAllWayExportFile = _m.Attribute(str) NumberOfProcessors = _m.Attribute(int) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker(self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario self.ExportTransferMatrixFlag = True self.ExportWalkAllWayMatrixFlag = False self.NumberOfProcessors = cpu_count() ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): pb = _tmgTPB.TmgToolPageBuilder(self, title="Operator Transfer Matrix v%s" %self.version, description="Extracts and exports a matrix of passenger volumes transferring \ from and to each operator, including initial boardings, final alightings \ and total walk-all-way volumes. Summing over each column is equivalent \ to aggregating the boardings for each operator; but only if the each line\ has a non-zero group number (i.e. full coverage).\ <br><br>Each operator (or <em>line group</em>) is identified numerically \ (e.g. <b>1</b> for the first group, <b>2</b> for the second, etc.) based on \ several pre-set schemes. The 0<sup>th</sup> 'group' is special: the 0<sup>th</sup> \ row corresponds to initial boardings, and the 0<sup>th</sup> column to \ final alightings. The cell at 0,0 contains the total walk-all-way volumes \ for the scenario.\ <br><br><b>Walk-all-way matrix:</b> This tool also calculates, for each OD \ the fraction of trips walking all-way. If desired, this tool can aggregate \ this matrix (based on an existing <em>Zone Partition</em>) and export it.\ <br><br><b>Temporary storage requirements:</b> 1 full matrix, 2 transit \ segment attributes, and 1 transit line attribute (if using a pre-built \ grouping scheme). ", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) if EMME_VERSION >= (4,1): pb.add_text_element("<em><b>Performance note for Emme 4.1 and newer:</b> \ When analyzing the results of a congested transit assignment, this \ tool will automatically blend the results over all iterations in \ order to keep the results consistent with those saved to the network. \ This is a slow operation so allow for additional run time when \ analyzing many iterations.</em>") pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) pb.add_select_matrix(tool_attribute_name= 'DemandMatrixId', filter=['FULL'], allow_none=True, id=True, title= "Demand to Analyze", note= "If set to None, the tool will use the demand matrix from the assignment, \ however this will affect run time for this tool.") if self._GetAssignmentType() == "MULTICLASS_TRANSIT_ASSIGNMENT" or self._GetMulticlass() == True: classes = self._LoadClassNames() keyval1 = {} for className in classes: keyval1[className] = className #keyval1.append((className, className)) else: keyval1 = {-1: "Multiclass assignment not available"} print keyval1 pb.add_select(tool_attribute_name= 'ClassName', keyvalues= keyval1, title= "Class Name", note= "The name of the assignment class to analyze. \ <br>Only required if a multiclass transit assignment has been run \ (Emme 4.1 and newer).") pb.add_header("TRANSFER MATRIX") pb.add_checkbox(tool_attribute_name= 'ExportTransferMatrixFlag', label= "Export Transfer Matrix?") keyval2 = [(1, "<em>Pre-built:</em> NCS11 operator codes"), (2, "<em>Pre-built:</em> Alphabetical by operator"), (3, "<em>Pre-built:</em> Alphabetical by operator and mode"), (4, "<em>Pre-built:</em> GTAModel V4 line groups"), (5, "<em>Pre-built:</em> GTAModel V4 groups + TTC prem. bus"), ("ut1", "<em>Custom:</em> Group IDs stored in UT1"), ("ut2", "<em>Custom:</em> Group IDs stored in UT2"), ("ut3", "<em>Custom:</em> Group IDs stored in UT3")] for exatt in self.Scenario.extra_attributes(): if exatt.type != "TRANSIT_LINE": continue text = "<em>Custom:</em> Group IDs stored in %s - %s" %(exatt.name, exatt.description) keyval2.append((exatt.name, text)) pb.add_select(tool_attribute_name= 'LineGroupOptionOrAttributeId', keyvalues= keyval2, title= "Line Groups \ Grouping Scheme", note= "Select a pre-built option or an existing transit line \ attribute with group codes") pb.add_select_file(tool_attribute_name= 'TransferMatrixFile', window_type= 'save_file', file_filter= "*.csv", title= "Transit Matrix File", note= "CSV file to save the transfer matrix to.") pb.add_header("WALK-ALL-WAY MATRIX") pb.add_checkbox(tool_attribute_name= 'ExportWalkAllWayMatrixFlag', label= "Export walk-all-way matrix?") pb.add_select_partition(tool_attribute_name= 'AggregationPartition', allow_none= True, title= "Aggregation Partition", note= "<font color='green'><b>Optional:</b></font> \ Select none to disable exporting the walk all-way matrix.") pb.add_select_file(tool_attribute_name= 'WalkAllWayExportFile', window_type= 'save_file', file_filter= "*.csv", title= "Walk-all-way Matrix File", note= "<font color='green'><b>Optional</b></font>") #---JAVASCRIPT pb.add_html(""" <script type="text/javascript"> $(document).ready( function () { var tool = new inro.modeller.util.Proxy(%s) ; if (tool.class_name_is_required()) { $("#ClassName").prop('disabled', false); } else { // $("#ClassName").prop('disabled', true); } if (! tool.preload_transfer_matrix_flag()) { $("#LineGroupOptionOrAttributeId").prop('disabled', true); $("#TransferMatrixFile").prop('disabled', true); } if (! tool.preload_waw_matrix_flag()) { $("#AggregationPartition").prop('disabled', true); $("#WalkAllWayExportFile").prop('disabled', true); } $("#Scenario").bind('change', function() { $(this).commit(); $("#LineGroupOptionOrAttributeId") .empty() .append(tool.preload_line_group_options()); inro.modeller.page.preload("#LineGroupOptionOrAttributeId"); $("#LineGroupOptionOrAttributeId").trigger('change'); if (tool.class_name_is_required()) { $("#ClassName") .empty() .append(tool.preload_class_names()); inro.modeller.page.preload("#ClassName"); $("#ClassName").trigger('change'); $("#ClassName").prop('disabled', false); } else { $("#ClassName") .empty() .append("<option value='-1'>Multiclass assignment not available</option>"); inro.modeller.page.preload("#ClassName"); $("#ClassName").trigger('change'); $("#ClassName").prop('disabled', true); } }); $("#ExportTransferMatrixFlag").bind('change', function() { $(this).commit(); var flag = ! tool.preload_transfer_matrix_flag(); $("#LineGroupOptionOrAttributeId").prop('disabled', flag); $("#TransferMatrixFile").prop('disabled', flag); }); $("#ExportWalkAllWayMatrixFlag").bind('change', function() { $(this).commit(); var flag = ! tool.preload_waw_matrix_flag(); $("#AggregationPartition").prop('disabled', flag); $("#WalkAllWayExportFile").prop('disabled', flag); }); }); </script>""" % pb.tool_proxy_tag) return pb.render() def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: if self.ExportTransferMatrixFlag or self.ExportWalkAllWayMatrixFlag: if self.ExportTransferMatrixFlag and not self.TransferMatrixFile: raise IOError("No transfer matrix file specified.") if self.ExportWalkAllWayMatrixFlag: if not self.WalkAllWayExportFile: raise TypeError("No walk-all-way matrix file specified") self._Execute() _MODELLER.desktop.refresh_needed(False) except Exception as e: _MODELLER.desktop.refresh_needed(False) self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") def __call__(self, xtmf_ScenarioNumber, ExportTransferMatrixFlag, ExportWalkAllWayMatrixFlag, TransferMatrixFile, xtmf_AggregationPartition, WalkAllWayExportFile, LineGroupOptionOrAttributeId): self.tool_run_msg = "" self.TRACKER.reset() self.Scenario = _MODELLER.emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" %xtmf_ScenarioNumber) if(xtmf_AggregationPartition.lower() == "none"): self.AggregationPartition is None; else: self.AggregationPartition = _MODELLER.emmebank.partition(xtmf_AggregationPartition) try: if self.ExportTransferMatrixFlag or self.ExportWalkAllWayMatrixFlag: if self.ExportTransferMatrixFlag and not self.TransferMatrixFile: raise IOError("No transfer matrix file specified.") if self.ExportWalkAllWayMatrixFlag: if not self.WalkAllWayExportFile: raise TypeError("No walk-all-way matrix file specified") self._Execute() except Exception as e: raise @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg @_m.method(return_type= bool) def class_name_is_required(self): return self._GetAssignmentType() == 'MULTICLASS_TRANSIT_ASSIGNMENT' @_m.method(return_type=unicode) def preload_class_names(self): classInfo = self._LoadClassInfo() options = [] for name, alpha in classInfo: options.append("<option value='%s'>%s</option>" %(name, name)) return "\n".join(options) @_m.method(return_type=unicode) def preload_line_group_options(self): options = [(1, "<em>Pre-built:</em> NCS11 operator codes"), (2, "<em>Pre-built:</em> Alphabetical by operator"), (3, "<em>Pre-built:</em> Alphabetical by operator and mode"), (4, "<em>Pre-built:</em> GTAModel V4 line groups"), (5, "<em>Pre-built:</em> GTAModel V4 groups + TTC prem. bus"), ("<em>Custom:</em> ut1", "Group IDs stored in UT1"), ("<em>Custom:</em> ut2", "Group IDs stored in UT2"), ("<em>Custom:</em> ut3", "Group IDs stored in UT3")] for exatt in self.Scenario.extra_attributes(): if exatt.type != "TRANSIT_LINE": continue text = "<em>Custom:</em> Group IDs stored in %s - %s" %(exatt.name, exatt.description) options.append((exatt.name, text)) options = ["<option value=%s>%s</option>" %tup for tup in options] return "\n".join(options) @_m.method(return_type= bool) def preload_transfer_matrix_flag(self): return self.ExportTransferMatrixFlag @_m.method(return_type= bool) def preload_waw_matrix_flag(self): return self.ExportWalkAllWayMatrixFlag ########################################################################################################## #--- #---MAIN EXECUTION CODE def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format(classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): managers = [_util.tempMatrixMANAGER("Walk-all-way matrix"), _util.tempExtraAttributeMANAGER(self.Scenario, 'TRANSIT_SEGMENT', description= "Initial boardings attribute"), _util.tempExtraAttributeMANAGER(self.Scenario, 'TRANSIT_SEGMENT', description= "Final alightings attribute"), getTemporaryFolder()] #Handle creating the transit line attribute in which to flag groups (if required). if self.LineGroupOptionOrAttributeId.isdigit(): managers.insert(0, _util.tempExtraAttributeMANAGER(self.Scenario, 'TRANSIT_LINE', description= "Line group ID", returnId= True)) lineGroupOption = int(self.LineGroupOptionOrAttributeId) else: managers.insert(0, blankContextManager(self.LineGroupOptionOrAttributeId)) lineGroupOption = 0 with nested(*managers) as (lineGroupAtributeID, walkAllWayMatrix, boardAttribute, alightAttribute, tempFolder): #---1. Flag pre-built groupings, if needed if lineGroupOption and self.ExportTransferMatrixFlag: with _m.logbook_trace("Applying pre-built groupings"): self._ApplyPreBuiltCodes(lineGroupOption, lineGroupAtributeID) self.TRACKER.completeTask() #---2. Get the traversal matrix if self.ExportTransferMatrixFlag: transferMatrix = self._GetTraversalMatrix(lineGroupAtributeID, tempFolder) #---3. Attach initial boarding and final alighting data to matrix self._GetBoardingsAndAlightings(transferMatrix, lineGroupAtributeID, boardAttribute.id, alightAttribute.id) print "Loaded initial boardings and final alightings" else: transferMatrix = None #---4. Get the walk-all-way matrix self._GetWalkAllWayMatrix(walkAllWayMatrix, transferMatrix) print "Loaded walk all-way matrix" #---5. Export the transfer matrix if self.ExportTransferMatrixFlag: self._WriteExportFile(transferMatrix) #---6. Export the aggregated walk-all-way matrix (if desired) if self.ExportWalkAllWayMatrixFlag: self._ExportWalkAllWayMatrix(walkAllWayMatrix) ########################################################################################################## #----Sub functions def _GetAtts(self): atts = { "Scenario" : str(self.Scenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__} return atts def _GetAssignmentType(self): if not self.Scenario.has_transit_results: return None configPath = dirname(_MODELLER.desktop.project_file_name()) \ + "/Database/STRATS_s%s/config" %self.Scenario if not exists(configPath): return self.Scenario.transit_assignment_type with open(configPath) as reader: config = _parsedict(reader.read()) data = config['data'] return data['type'] def _GetMulticlass(self): if not self.Scenario.has_transit_results: return None configPath = dirname(_MODELLER.desktop.project_file_name()) \ + "/Database/STRATS_s%s/config" %self.Scenario if not exists(configPath): return self.Scenario.transit_assignment_type with open(configPath) as reader: config = _parsedict(reader.read()) data = config['data'] if 'multi_class' in data: return data['multi_class'] else: return False def _LoadClassInfo(self): if not self.Scenario.has_transit_results: return [] configPath = dirname(_MODELLER.desktop.project_file_name()) \ + "/Database/STRATS_s%s/config" %self.Scenario if not exists(configPath): return [] with open(configPath) as reader: config = _parsedict(reader.read()) classes = [] for info in config['strat_files']: className = info['name'] if(info['data'] is not None): if not 'alpha' in info['data']: alpha = 0.0 else: alpha = info['data']['alpha'] classes.append((className, alpha)) return classes def _LoadClassNames(self): if not self.Scenario.has_transit_results: return [] configPath = dirname(_MODELLER.desktop.project_file_name()) \ + "/Database/STRATS_s%s/config" %self.Scenario if not exists(configPath): return [] with open(configPath) as reader: config = _parsedict(reader.read()) classes = [] if self._GetAssignmentType() == 'MULTICLASS_TRANSIT_ASSIGNMENT': for classz in config['strat_files']: className = classz['name'] classes.append(className) else: info = config['data'] for classz in info['classes']: className = classz['name'] classes.append(className) return classes def _ApplyPreBuiltCodes(self, option, attributeId): options = {1: LINE_GROUPS_NCS11, 2: LINE_GROUPS_ALPHA_OP, 3: LINE_GROUPS_ALPHA_OP_MODE, 4: LINE_GROUPS_GTAMV4, 5: LINE_GROUPS_GTAMV4_PREM} def flagGroup(value, selector, descr): spec= { "result": attributeId, "expression": str(value), "aggregation": None, "selections": { "transit_line": selector }, "type": "NETWORK_CALCULATION" } with _m.logbook_trace("Flagging %s lines as %s" %(descr, value)): networkCalculator(spec, scenario=self.Scenario) groupings = options[option] self.TRACKER.startProcess(len(groupings)) for groupId, selector, name in groupings: flagGroup(groupId, selector, name) self.TRACKER.completeSubtask() def _GetTraversalMatrix(self, lineGroupAtributeID, tempFolder): #---2. Load class / iteration information for traversal analysis if self._GetAssignmentType() == "MULTICLASS_TRANSIT_ASSIGNMENT" or self._GetMulticlass() == True: classWeights = [(self.ClassName, 1.0)] elif self._GetAssignmentType() == "CONGESTED_TRANSIT_ASSIGNMENT": if EMME_VERSION >= (4,1,0): classWeights = [] else: classWeights = self._LoadClassInfo() else: classWeights = [] #---3. Run the traversal analysis tool for each class (if needed) files = {} nTasks = max(len(classWeights), 1) self.TRACKER.startProcess(nTasks) if classWeights: for className, weight in classWeights: filepath = _tf.mktemp(".csv", dir= tempFolder) files[className] = filepath self._RunTraversalAnalysis(lineGroupAtributeID, filepath, className) self.TRACKER.completeSubtask() else: filepath = _tf.mktemp(".csv", dir= tempFolder) self._RunTraversalAnalysis(lineGroupAtributeID, filepath) files = filepath self.TRACKER.completeTask() print "Processed traversal matrices" #---4. Load or load and combine traversal matrices self.TRACKER.startProcess(nTasks) if classWeights: transferMatrix = {} for className, weight in classWeights: filepath = files[className] classMatrix = self._ParseTraversalResults(filepath) for key, value in classMatrix.iteritems(): weightedValue = weight * value if key in transferMatrix: transferMatrix[key] += weightedValue else: transferMatrix[key] = weightedValue self.TRACKER.completeSubtask() print "Loaded class %s" %className else: filepath = files transferMatrix = self._ParseTraversalResults(filepath) self.TRACKER.completeTask() print "Aggregated transfer matrix." return transferMatrix def _RunTraversalAnalysis(self, attributeId, filepath, className= None): spec = { "portion_of_path": "COMPLETE", "gates_by_trip_component": { "in_vehicle": None, "aux_transit": None, "initial_boarding": None, "transfer_boarding": attributeId, "transfer_alighting": attributeId, "final_alighting": None }, "analyzed_demand": self.DemandMatrixId, "path_analysis": None, "type": "EXTENDED_TRANSIT_TRAVERSAL_ANALYSIS" } if self.DemandMatrixId is not None: spec['constraint'] = { "by_value": { "interval_min": 0, "interval_max": 0, "condition": "EXCLUDE", "od_values": self.DemandMatrixId }, "by_zone": None } else: spec['constraint'] = None print "Running traversal analysis on class %s" %className if className is not None: traversalAnalysisTool(spec, filepath, scenario= self.Scenario, class_name= className) else: traversalAnalysisTool(spec, filepath, scenario= self.Scenario) def _ParseTraversalResults(self, filepath): retval = {} with open(filepath) as reader: line = "" while not line.startswith("a"): line = reader.readline() for line in reader: cells = line.strip().split() if len(cells) != 3: continue o = int(cells[0]) d = int(cells[1]) try: val = float(cells[2]) except ValueError: val = cells[2].replace('u', '.') val = float(val) od = (o,d) retval[od] = val return retval def _GetBoardingsAndAlightings(self, transferMatrix, lineGroupAtributeID, boardingAttributeId, alightingAttributeId): self._RunNetworkResults(boardingAttributeId, alightingAttributeId) self._LoadBoardingsAndAlightings(lineGroupAtributeID, boardingAttributeId, alightingAttributeId, transferMatrix) def _RunNetworkResults(self, boardingAttributeId, alightingAttributeId): spec= { "on_links": None, "on_segments": { "initial_boardings": boardingAttributeId, "final_alightings": alightingAttributeId }, "aggregated_from_segments": None, "analyzed_demand": self.DemandMatrixId, "constraint": None, "type": "EXTENDED_TRANSIT_NETWORK_RESULTS" } if self.ClassName: self.TRACKER.runTool(networkResultsTool, spec, self.Scenario, class_name= self.ClassName) else: self.TRACKER.runTool(networkResultsTool, spec, self.Scenario) def _LoadBoardingsAndAlightings(self, lineGroupAtributeID, boardingAttributeId, alightingAttributeId, transferMatrix): lineGroups = _util.fastLoadTransitLineAttributes(self.Scenario, [lineGroupAtributeID]) lineActivity = _util.fastLoadSummedSegmentAttributes(self.Scenario, [boardingAttributeId, alightingAttributeId]) groupActivity = {} for lineId, lineAtts in lineGroups.iteritems(): groupId = int(lineAtts[lineGroupAtributeID]) if lineId in lineActivity: initialBoardings = lineActivity[lineId][boardingAttributeId] finalAlightings = lineActivity[lineId][alightingAttributeId] else: initialBoardings = 0.0 finalAlightings = 0.0 if groupId in groupActivity: activity = groupActivity[groupId] activity[0] += initialBoardings activity[1] += finalAlightings else: groupActivity[groupId] = [initialBoardings, finalAlightings] for groupId, activity in groupActivity.iteritems(): initialBoardings, finalAlightings = activity transferMatrix[(0, groupId)] = initialBoardings transferMatrix[(groupId, 0)] = finalAlightings self.TRACKER.completeTask() def _GetWalkAllWayMatrix(self, wawMatrix, transferMatrix): self._RunStrategyAnalysis(wawMatrix.id) wawSum = self._SumWalkAllWayMatrix(wawMatrix.id) if self.ExportTransferMatrixFlag: transferMatrix[(0,0)] = wawSum def _RunStrategyAnalysis(self, wawMatrixId): spec = { "trip_components": { "boarding": None, "in_vehicle": "length", "aux_transit": None, "alighting": None }, "sub_path_combination_operator": "+", "sub_strategy_combination_operator": ".min.", "selected_demand_and_transit_volumes": { "sub_strategies_to_retain": "FROM_COMBINATION_OPERATOR", "selection_threshold": { "lower": 0, "upper": 0 } }, "analyzed_demand": self.DemandMatrixId, "constraint": None, "results": { "strategy_values": None, "selected_demand": wawMatrixId, "transit_volumes": None, "aux_transit_volumes": None, "total_boardings": None, "total_alightings": None }, "type": "EXTENDED_TRANSIT_STRATEGY_ANALYSIS" } if self.ClassName: strategyAnalysisTool(spec, scenario= self.Scenario, class_name= self.ClassName) else: strategyAnalysisTool(spec, scenario= self.Scenario) def _SumWalkAllWayMatrix(self, wawMatrixId): spec = { "expression": wawMatrixId, "result": None, "constraint": { "by_value": None, "by_zone": None }, "aggregation": { "origins": "+", "destinations": "+" }, "type": "MATRIX_CALCULATION" } if EMME_VERSION >= (4,2,1): return self.TRACKER.runTool(matrixCalculator, spec, scenario=self.Scenario, num_processors=self.NumberOfProcessors)['result'] else: return self.TRACKER.runTool(matrixCalculator, spec, scenario=self.Scenario)['result'] def _WriteExportFile(self, transferMatrix): with open(self.TransferMatrixFile, 'w') as writer: headerSet = set() for origin, destination in transferMatrix.iterkeys(): headerSet.add(origin) headerSet.add(destination) headers = [h for h in headerSet] headers.sort() header = ",".join( [""] + [str(h) for h in headers]) writer.write(header) for origin in headers: row = [str(origin)] for destination in headers: key = (origin, destination) if key in transferMatrix: value = transferMatrix[key] else: value = 0.0 row.append(str(value)) writer.write("\n" + ",".join(row)) def _ExportWalkAllWayMatrix(self, walkAllWayMatrix): partSpec = {'origins': self.AggregationPartition.id, 'destinations': self.AggregationPartition.id, 'operator': 'sum'} matrixExportTool([walkAllWayMatrix], partition_aggregation= partSpec, export_file= self.WalkAllWayExportFile, field_separator= ',', full_matrix_line_format= 'SQUARE', scenario = self.Scenario)
class BasicTransitAssignment(_m.Tool()): version = '0.1.0' tool_run_msg = "" #---Variable definitions ScenarioNumber = _m.Attribute(int) DemandMatrixNumber = _m.Attribute(int) ModeString = _m.Attribute(str) WaitPerception = _m.Attribute(float) # WalkPerception = _m.Attribute(float) # InVehiclePerception = _m.Attribute(float) # BoardingPerception = _m.Attribute(float) # UseAdditiveDemand = _m.Attribute(bool) # UseEM4Options = _m.Attribute(bool) # Not yet used. Future proofing. WaitFactor = _m.Attribute(float) # #---Special instance types scenario = _m.Attribute(_m.InstanceType) # demandMatrix = _m.Attribute(_m.InstanceType) # modes = _m.Attribute(_m.ListType) #---Internal variables _modeList = [] # def __init__(self): self._tracker = _util.ProgressTracker(2) self.WaitFactor = 0.5 self.UseAdditiveDemand = False self.UseEM4Options = False def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Basic Transit Assignment v%s" % self.version, description= "Executes a basic transit assignment. Boarding penalties are \ assumed to be loaded into <b>UT3</b>.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_header("ASSIGNMENT OPTIONS") #---------------------------------- pb.add_select_scenario(tool_attribute_name='scenario', title='Scenario:', allow_none=False) pb.add_select_matrix( tool_attribute_name='demandMatrix', title='Demand Matrix:', note="If no matrix is selected, a scalar matrix of value '0' will\ be assigned.", allow_none=True) pb.add_select_mode(tool_attribute_name='modes', filter=['TRANSIT', 'AUX_TRANSIT'], allow_none=False, title='Modes:') pb.add_checkbox(tool_attribute_name='UseAdditiveDemand', title="Use additive demand?") pb.add_header("PERCEPTION FACTORS") #---------------------------------- pb.add_text_box(tool_attribute_name='WaitFactor', size=4, title='Wait factor:', note='Default is 0.5') pb.add_text_box(tool_attribute_name='WaitPerception', size=4, title='Wait time perception:') pb.add_text_box(tool_attribute_name='WalkPerception', size=4, title='Walk perception:') pb.add_text_box(tool_attribute_name='InVehiclePerception', size=4, title='In-vehicle perception:') pb.add_text_box(tool_attribute_name='BoardingPerception', size=4, title='Boarding perception:') return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" #Run is called from Modeller. self.isRunningFromXTMF = False # Fix the checkbox problem if self.UseAdditiveDemand is None: #If the checkbox hasn't been clicked, this variable will be set to None by Modeller self.UseAdditiveDemand = False # Convert the list of mode objects to a list of mode characters for m in self.modes: self._modeList.append(m.id) # Execute try: self._execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Run complete.") def __call__(self, ScenarioNumber, DemandMatrixNumber, ModeString, WaitPerception, WalkPerception, InVehiclePerception, BoardingPerception, UseAdditiveDemand, WaitFactor, UseEM4Options): #---1 Set up scenario self.scenario = _m.Modeller().emmebank.scenario(ScenarioNumber) if (self.scenario is None): raise Exception("Scenario %s was not found!" % ScenarioNumber) #---2 Set up Demand matrix if DemandMatrixNumber == 0: self.demandMatrix = None else: self.demandMatrix = _m.Modeller().emmebank.matrix( "mf%s" % DemandMatrixNumber) if self.demandMatrix is None: raise Exception("Matrix %s does not exist!" % DemandMatrixNumber) #---3 Set up modes for i in range(0, len(ModeString)): if not self._modeList.__contains__(ModeString[i]): self._modeList.append(ModeString[i]) #---4 Pass in remaining args self.WaitPerception = WaitPerception self.WalkPerception = WalkPerception self.InVehiclePerception = InVehiclePerception self.BoardingPerception = BoardingPerception self.UseAdditiveDemand = UseAdditiveDemand self.WaitFactor = WaitFactor self.UseEM4Options = UseEM4Options self.isRunningFromXTMF = True try: self._execute() except Exception as e: raise Exception(_traceback.format_exc()) ########################################################################################################## def _execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._getAtts()): self._tracker.completeTask() try: transitAssignmentTool = _m.Modeller().tool( "inro.emme.standard.transit_assignment.extended_transit_assignment" ) except Exception as e: transitAssignmentTool = _m.Modeller().tool( "inro.emme.transit_assignment.extended_transit_assignment") with self._demandMatrixMANAGER(): self._tracker.runTool( transitAssignmentTool, self._getAssignmentSpec(), # Specification self.scenario, # Scenario self.UseAdditiveDemand) # Use additional volumes self._tracker.reset() ########################################################################################################## #----CONTEXT MANAGERS--------------------------------------------------------------------------------- ''' Context managers for temporary database modifications. ''' @contextmanager def _demandMatrixMANAGER(self): #Code here is executed upon entry usingScalar = False if self.demandMatrix is None: _m.logbook_write("Initializing temporary scalar demand matrix.") #def initializeMatrix(id=None, default=0, name="", description="", matrix_type='FULL'): self.demandMatrix = _util.initializeMatrix( matrix_type='SCALAR', name='trscal', description="Scalar matrix to get transit times") if self.demandMatrix is None: raise Exception( "Could not create temporary scalar demand matrix!") usingScalar = True try: yield # Code here is executed upon clean exit finally: # Code here is executed in all cases. if usingScalar == True: _m.logbook_write("Deleting temporary scalar demand matrix.") _m.Modeller().emmebank.delete_matrix(self.demandMatrix.id) #----SUB FUNCTIONS--------------------------------------------------------------------------------- ''' ScenarioNumber = _m.Attribute(int) DemandMatrixNumber = _m.Attribute(int) ModeString = _m.Attribute(str) WaitPerception = _m.Attribute(float) # WalkPerception = _m.Attribute(float) # InVehiclePerception = _m.Attribute(float) # BoardingPerception = _m.Attribute(float) # UseAdditiveDemand = _m.Attribute(bool) # UseEM4Options = _m.Attribute(bool) # Not yet used. Future proofing. WaitFactor = _m.Attribute(float) # #---Special instance types scenario = _m.Attribute(_m.InstanceType) # demandMatrix = _m.Attribute(_m.InstanceType) # modes = _m.Attribute(_m.ListType) #---Internal variables _modeList = [] # ''' def _getAtts(self): atts = { "Scenario": str(self.scenario.id), "Version": self.version, "Demand Matrix": str(self.demandMatrix), "Modes": str(self._modeList), "Wait Perception": self.WaitPerception, "Walk Perception": self.WalkPerception, "In Vehicle Perception": self.InVehiclePerception, "Boarding Perception": self.BoardingPerception, "Headway Fraction": self.WaitFactor, "Use Additive Demand Flag": self.UseAdditiveDemand, "Use Emme 4 Options Flag": self.UseEM4Options, "self": self.__MODELLER_NAMESPACE__ } return atts def _getAssignmentSpec(self): spec = { "modes": self._modeList, #---MODES "demand": self.demandMatrix.id, #---DEMAND MATRIX "waiting_time": { "headway_fraction": self.WaitFactor, #---WAIT FACTOR "effective_headways": "hdw", "spread_factor": 1, "perception_factor": self.WaitPerception #---WAIT PERCEPTION }, "boarding_time": { "at_nodes": None, "on_lines": { "penalty": "ut3", #---BOARDING ATTRIBUTE "perception_factor": self.BoardingPerception #---BOARDING PERCEPTION } }, "boarding_cost": { "at_nodes": { "penalty": 0, # For some reason, I can't just leave this blank. "perception_factor": 0 }, "on_lines": None }, "in_vehicle_time": { "perception_factor": self.InVehiclePerception #---IVTT PERCEPTION }, "in_vehicle_cost": None, #---IN VEHICLE FARES "aux_transit_time": { "perception_factor": self.WalkPerception #---WALK PERCEPTION }, "aux_transit_cost": None, "flow_distribution_at_origins": { "by_time_to_destination": "BEST_CONNECTOR", "by_fixed_proportions": None }, "flow_distribution_between_lines": { "consider_travel_time": False }, "connector_to_connector_path_prohibition": None, "save_strategies": True, "od_results": None, "type": "EXTENDED_TRANSIT_ASSIGNMENT" } if EMME_VERSION[0] + 0.1 * EMME_VERSION[1] >= 4.1: spec["performance_settings"] = { "number_of_processors": cpu_count() } return spec @_m.method(return_type=_m.TupleType) def percent_completed(self): return self._tracker.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class ExportBinaryMatrix(_m.Tool()): version = '1.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here MATRIX_TYPES = {1: 'ms', 2: 'mo', 3: 'md', 4: 'mf'} def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): return "" @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg @_m.method(return_type=bool) def scenario_required(self): retval = _util.databankHasDifferentZones(_bank) print retval return retval #--- #---XTMF INTERFACE METHODS def run_xtmf(self, parameters): # xtmf_MatrixType, xtmf_MatrixNumber, ExportFile, xtmf_ScenarioNumber xtmf_MatrixType = parameters["matrix_type"] xtmf_MatrixNumber = parameters["matrix_number"] self.ExportFile = parameters["file_location"] xtmf_ScenarioNumber = parameters["scenario_number"] if not xtmf_MatrixType in self.MATRIX_TYPES: raise IOError( "Matrix type '%s' is not recognized. Valid types are " % xtmf_MatrixType + "1 for scalar, 2 for origin, 3 for destination, and " + "4 for full matrices.") self.MatrixId = self.MATRIX_TYPES[xtmf_MatrixType] + str( xtmf_MatrixNumber) if _bank.matrix(self.MatrixId) == None: raise IOError("Matrix %s does not exist." % self.MatrixId) if _util.databankHasDifferentZones(_bank): self.Scenario = _bank.scenario(xtmf_ScenarioNumber) if self.Scenario == None: raise Exception( "A valid scenario must be specified as there are " + "multiple zone systems in this Emme project. " + "'%s' is not a valid scenario." % xtmf_ScenarioNumber) try: self._Execute() except Exception, e: msg = str(e) + "\n" + _traceback.format_exc(e) raise Exception(msg)
class LegacyFBTA(_m.Tool()): version = '0.2.2' tool_run_msg = "" # Variables marked with a '#' are used in the main block, and are assigned by both run and call #---Variable definitions ScenarioNumber = _m.Attribute(int) DemandMatrixNumber = _m.Attribute(int) ModeString = _m.Attribute(str) WalkSpeed = _m.Attribute(float) # WaitPerception = _m.Attribute(float) # WalkPerception = _m.Attribute(float) # InVehiclePerception = _m.Attribute(float) # BoardingPerception = _m.Attribute(float) # FarePerception = _m.Attribute(float) # '''To disable fare-based impedances, set this parameter to 0.0''' UseAdditiveDemand = _m.Attribute(bool) # WaitFactor = _m.Attribute(float) # #---Special instance types, used only from Modeller scenario = _m.Attribute(_m.InstanceType) # demandMatrix = _m.Attribute(_m.InstanceType) # modes = _m.Attribute(_m.ListType) #---Private vars _appliedFareFactor = 0 # _modeList = [] # def __init__(self): # Set up all Emme tools and data structures self.databank = _m.Modeller().emmebank try: self.transitAssignmentTool = _m.Modeller().tool( "inro.emme.standard.transit_assignment.extended_transit_assignment" ) except Exception as e: self.transitAssignmentTool = _m.Modeller().tool( "inro.emme.transit_assignment.extended_transit_assignment") def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Legacy Fare-Based Transit Assignment", description= "Executes a fare-based transit assignment (FBTA) as described \ in the GTAModel Version 3 documentation: Using special functions \ on centroid connectors and transit time functions. This requires \ a compatible network, which can currently only be created by \ <em>macro_EditNetwork.mac.</em><br><br>\ This Tool can also be used to execute a more standard transit \ assignment procedure by using a fare perception of <b>'0'</b>.\ <br><br>This Tool executes an Extended Transit Assignment, which allows\ for subsequent analyses; such as those that can be found in \ <em>TMG2.Assignment.TransitAnalysis</em>.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_header("ASSIGNMENT SETUP") #---------------------------------- pb.add_select_scenario(tool_attribute_name='scenario', title='Scenario:', allow_none=False) pb.add_select_matrix( tool_attribute_name='demandMatrix', title='Demand Matrix:', note="If no matrix is selected, a scalar matrix of value '0' will\ be assigned.", allow_none=True) pb.add_select_mode(tool_attribute_name='modes', filter=['TRANSIT', 'AUX_TRANSIT'], allow_none=False, title='Modes:') pb.add_checkbox(tool_attribute_name='UseAdditiveDemand', title="Use additive demand?") pb.add_header("PERCEPTION FACTORS") #---------------------------------- pb.add_text_box(tool_attribute_name='WaitFactor', size=4, title='Wait factor:', note='Default is 0.5') pb.add_text_box(tool_attribute_name='WaitPerception', size=4, title='Wait time perception:') pb.add_text_box(tool_attribute_name='WalkSpeed', size=6, title='Walk speed:', note='In km/hr') pb.add_text_box(tool_attribute_name='WalkPerception', size=4, title='Walk perception:') pb.add_text_box(tool_attribute_name='InVehiclePerception', size=4, title='In-vehicle perception:') pb.add_text_box(tool_attribute_name='BoardingPerception', size=4, title='Boarding perception:') pb.add_text_box(tool_attribute_name='FarePerception', size=6, title='Fare perception:', note="Enter '0' to disable fare-based impedances.") return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" #Run is called from Modeller. self.isRunningFromXTMF = False # Fix the checkbox problem if self.UseAdditiveDemand is None: #If the checkbox hasn't been clicked, this variable will be set to None by Modeller self.UseAdditiveDemand = False # Convert the list of mode objects to a list of mode characters for m in self.modes: self._modeList.append(m.id) # Execute try: self._execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Run complete.") def __call__(self, ScenarioNumber, DemandMatrixNumber, ModeString, WalkSpeed, WaitPerception, \ WalkPerception, InVehiclePerception, BoardingPerception, FarePerception, \ UseAdditiveDemand, WaitFactor): #---1 Set up scenario self.scenario = _m.Modeller().emmebank.scenario(ScenarioNumber) if (self.scenario is None): raise Exception("Scenario %s was not found!" % ScenarioNumber) #---2 Set up Demand matrix if DemandMatrixNumber == 0: self.demandMatrix = None else: self.demandMatrix = self.databank.matrix("mf%s" % DemandMatrixNumber) if self.demandMatrix is None: raise Exception("Matrix %s does not exist!" % DemandMatrixNumber) #---3 Set up modes for i in range(0, len(ModeString)): if not self._modeList.__contains__(ModeString[i]): self._modeList.append(ModeString[i]) #---4 Pass in remaining args self.WalkSpeed = WalkSpeed self.WaitPerception = WaitPerception self.WalkPerception = WalkPerception self.InVehiclePerception = InVehiclePerception self.BoardingPerception = BoardingPerception self.FarePerception = FarePerception self.UseAdditiveDemand = UseAdditiveDemand self.WaitFactor = WaitFactor self.isRunningFromXTMF = True #---5 Execute the tool try: self._execute() except Exception as e: raise Exception(_traceback.format_exc(e)) ########################################################################################################## def _execute(self): with _m.logbook_trace(name="Legacy Fare Based Transit Assignment v%s" % self.version, attributes=self._getAtts()): self._calculateFareFactor() with nested(self._demandMatrixMANAGER(), self._walkLinksMANAGER(), self._transitFunctionsMANAGER()): self._calculateUL1() _m.logbook_write(name="Running extended transit assignment") self.transitAssignmentTool( self._setUpAssignment(), # Specification self.scenario, # Scenario self.UseAdditiveDemand) # Use additional volumes # Cleanup is handled automatically. ########################################################################################################## #----CONTEXT MANAGERS--------------------------------------------------------------------------------- ''' Context managers for temporary database modifications. ''' @contextmanager def _demandMatrixMANAGER(self): #Code here is executed upon entry usingScalar = False if self.demandMatrix is None: _m.logbook_write("Initializing temporary scalar demand matrix.") self.demandMatrix = _util.initializeMatrix( matrix_type='SCALAR', name='trscal', description="Scalar matrix to get transit times") if self.demandMatrix is None: raise Exception( "Could not create temporary scalar demand matrix!") usingScalar = True try: yield # Code here is executed upon clean exit finally: # Code here is executed in all cases. if usingScalar == True: _m.logbook_write("Deleting temporary scalar demand matrix.") self.databank.delete_matrix(self.demandMatrix.id) @contextmanager def _walkLinksMANAGER(self): #Code here is executed upon entry with _m.logbook_trace("Changing speed of modes tuv."): net = self.scenario.get_network() tMode = net.mode('t') uMode = net.mode('u') vMode = net.mode('v') tSpeed = tMode.speed uSpeed = uMode.speed vSpeed = vMode.speed tMode.speed = 'ul1*1.0' _m.logbook_write("Changed speed of mode 't' to 'ul1*1.0'.") uMode.speed = 'ul1*1.0' _m.logbook_write("Changed speed of mode 'u' to 'ul1*1.0'.") vMode.speed = 'ul1*1.0' _m.logbook_write("Changed speed of mode 'u' to 'ul1*1.0'.") self.scenario.publish_network(net) _m.logbook_write("Changes saved to databank.") try: yield # Code here is executed upon clean exit finally: # Code here is executed in all cases. with _m.logbook_trace("Resetting modes tuv."): net = self.scenario.get_network() tMode = net.mode('t') uMode = net.mode('u') vMode = net.mode('v') tMode.speed = str(tSpeed) _m.logbook_write("Reset speed of mode 't' to '%s'." % tSpeed) uMode.speed = str(uSpeed) _m.logbook_write("Reset speed of mode 'u' to '%s'." % uSpeed) vMode.speed = str(vSpeed) _m.logbook_write("Reset speed of mode 'v' to '%s'." % vSpeed) self.scenario.publish_network(net) _m.logbook_write("Changes saved to databank.") @contextmanager def _transitFunctionsMANAGER(self): #Code here is executed upon entry functionChanger = None #Use the standard tools; it is faster and more verbose. try: functionChanger = _m.Modeller().tool( "inro.emme.data.function.change_function") except Exception as e: functionChanger = _m.Modeller().tool( "inro.emme.standard.data.function.change_function") expressionArchive = {} with _m.logbook_trace("Modifying transit time functions."): for f in self.databank.functions(): if f.type == "TRANSIT_TIME": expressionArchive[f.id] = f.expression functionChanger( f, f.expression + " + (us3 * %s)" % (self._appliedFareFactor)) #f.expression += " + (us3 * %s)" %(self._appliedFareFactor) try: yield # Code here is executed upon clean exit finally: # Code here is executed in all cases. with _m.logbook_trace("Resetting transit time functions."): for item in expressionArchive.iteritems(): f = self.databank.function(item[0]) functionChanger(f, item[1]) #f.expression = item[1] #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _getAtts(self): atts = { "Scenario": str(self.scenario.id), "ModeString": str(self._modeList), "Walk Speed": str(self.WalkSpeed), "Wait Perception": self.WaitPerception, "Walk Perception": self.WalkPerception, "IVTT Perception": self.InVehiclePerception, "Boarding Perception": self.BoardingPerception, "Fare Perception": self.FarePerception, "Is using additive demand?": self.UseAdditiveDemand, "Wait Factor": self.WaitFactor, "Is running from XTMF?": str(self.isRunningFromXTMF), "self": self.__MODELLER_NAMESPACE__ } if self.demandMatrix is None: atts['Demand Matrix'] = "SCALAR" else: atts['Demand Matrix'] = "FULL: %s" % self.demandMatrix.id return atts def _reportProgress(self, current, total): if self.isRunningFromXTMF: self.XTMFBridge.ReportProgress(float( float(current) / float(total))) def _calculateFareFactor(self): self._appliedFareFactor = 0 if self.FarePerception != 0: self._appliedFareFactor = 60.0 / self.FarePerception def _calculateUL1(self): _m.logbook_write("Calculating UL1 for tuv links.") networkCalculator = None #Use the standard tools; it is faster and more verbose. try: networkCalculator = _m.Modeller().tool( "inro.emme.network_calculation.network_calculator") except Exception as e: networkCalculator = _m.Modeller().tool( "inro.emme.standard.network_calculation.network_calculator") # link.data1 = 60 / link.length + self._appliedFareFactor * link.__getattribute__('@tfare') / self.WalkPerception spec = { "result": "ul1", "expression": "(60 * length / {0}) + ({1} * @tfare / {2})".format( self.WalkSpeed, self._appliedFareFactor, self.WalkPerception), "aggregation": None, "selections": { "link": "modes=tuv" }, "type": "NETWORK_CALCULATION" } networkCalculator(spec, scenario=self.scenario) def _setUpAssignment(self): # Ensure that modes t, u, and v are enabled if not self._modeList.__contains__('t'): self._modeList.append('t') if not self._modeList.__contains__('u'): self._modeList.append('u') if not self._modeList.__contains__('v'): self._modeList.append('v') spec = { "modes": self._modeList, #---MODES "demand": self.demandMatrix.id, #---DEMAND MATRIX "waiting_time": { "headway_fraction": self.WaitFactor, #---WAIT FACTOR "effective_headways": "hdw", "spread_factor": 1, "perception_factor": self.WaitPerception #---WAIT PERCEPTION }, "boarding_time": { "at_nodes": None, "on_lines": { "penalty": "ut3", #---BOARDING ATTRIBUTE "perception_factor": self.BoardingPerception #---BOARDING PERCEPTION } }, "boarding_cost": { "at_nodes": { "penalty": 0, # For some reason, I can't just leave this blank. "perception_factor": 0 }, "on_lines": None }, "in_vehicle_time": { "perception_factor": self.InVehiclePerception #---IVTT PERCEPTION }, "in_vehicle_cost": None, #---IN VEHICLE FARES "aux_transit_time": { "perception_factor": self.WalkPerception #---WALK PERCEPTION }, "aux_transit_cost": None, #---WALK FARES "flow_distribution_at_origins": { "by_time_to_destination": "BEST_CONNECTOR", "by_fixed_proportions": None }, "flow_distribution_between_lines": { "consider_travel_time": False }, "connector_to_connector_path_prohibition": None, "save_strategies": True, "od_results": None, "type": "EXTENDED_TRANSIT_ASSIGNMENT" } if EMME_VERSION >= (4, 1, 0): spec["performance_settings"] = { "number_of_processors": cpu_count() } return spec @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class SupplementalTransitMatrices(_m.Tool()): version = '0.0.2' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only xtmf_PartitionId = _m.Attribute(str) xtmf_DemandMatrixId = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario def page(self): pb = _m.ToolPageBuilder(self, title="Return Supplemental Matrices", description="Cannot be called from Modeller.", runnable=False, branding_text="XTMF") return pb.render() ########################################################################################################## def __call__(self, xtmf_ScenarioNumber, xtmf_PartitionId, xtmf_DemandMatrixId): database = _MODELLER.emmebank #---1 Set up scenario scenario = database.scenario(xtmf_ScenarioNumber) if (scenario is None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) if not scenario.has_transit_results: raise Exception("Scenario %s has no transit assignment results" % xtmf_ScenarioNumber) partition = database.partition(xtmf_PartitionId) if partition is None: raise Exception("Partition '%s' does not exist" % xtmf_PartitionId) demandMatrix = database.matrix(xtmf_DemandMatrixId) if demandMatrix is None: raise Exception("Demand matrix '%s' does not exist" % xtmf_DemandMatrixId) try: return self._Execute(scenario, partition, demandMatrix) except Exception as e: msg = str(e) + "\n" + _traceback.format_exc() raise Exception(msg) ########################################################################################################## def _Execute(self, scenario, partition, demandMatrix): modes = [ id for id, type, description in _util.getScenarioModes( scenario, ['TRANSIT', 'AUX_TRANSIT']) ] strategyAnalysisTool = _MODELLER.tool( 'inro.emme.transit_assignment.extended.strategy_based_analysis') matrixResultsTool = _MODELLER.tool( 'inro.emme.transit_assignment.extended.matrix_results') partitionAggTool = _MODELLER.tool( 'inro.emme.matrix_calculation.matrix_partition_aggregation') partitionAverageTool = _MODELLER.tool( 'TMG2.Analysis.ExportPartitionAverage') with nested(_util.tempMatrixMANAGER('Avg Boardings'),\ _util.tempMatrixMANAGER('In Vehicle Times')) \ as (avgBoardingsMatrix, walkAllWayMatrix): #Extract walk-all-way matrix spec = { "trip_components": { "boarding": None, "in_vehicle": "length", "aux_transit": None, "alighting": None }, "sub_path_combination_operator": "+", "sub_strategy_combination_operator": ".min.", "selected_demand_and_transit_volumes": { "sub_strategies_to_retain": "FROM_COMBINATION_OPERATOR", "selection_threshold": { "lower": 0, "upper": 0 } }, "analyzed_demand": None, "constraint": None, "results": { "strategy_values": None, "selected_demand": walkAllWayMatrix.id, "transit_volumes": None, "aux_transit_volumes": None, "total_boardings": None, "total_alightings": None }, "type": "EXTENDED_TRANSIT_STRATEGY_ANALYSIS" } strategyAnalysisTool(spec, scenario) #Extract avg boardings spec = { "by_mode_subset": { "modes": modes, "avg_boardings": avgBoardingsMatrix.id, }, "type": "EXTENDED_TRANSIT_MATRIX_RESULTS" } matrixResultsTool(spec, scenario) #Get the partition-aggregated results #The tool returns the MatrixData object walkOnlyResults = partitionAggTool(walkAllWayMatrix, partition, partition, scenario=scenario) avgBoardingResults = partitionAverageTool(scenario.id, partition.id, avgBoardingsMatrix.id, demandMatrix.id) results = {} for i, row in enumerate(avgBoardingResults.raw_data): origin = avgBoardingResults.indices[0][i] for j, cell in enumerate(row): destination = avgBoardingResults.indices[1][j] key = (origin, destination) results[key] = [cell] for i, row in enumerate(walkOnlyResults.raw_data): origin = walkOnlyResults.indices[0][i] for j, cell in enumerate(row): destination = walkOnlyResults.indices[1][j] key = (origin, destination) if not key in results: results[key] = [0.0, cell] else: results[key].append(cell) resultList = [] for key, val in results.iteritems(): origin, destination = key col1 = val[0] col2 = val[1] resultList.append("%s %s %s %s" % (origin, destination, col1, col2)) resultList.sort() return "\n".join(resultList) @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class ApplyBatchLineEdits(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here COLON = ':' COMMA = ',' # Tool Input Parameters # Only those parameters necessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get initialized during construction (__init__) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only inputFile = _m.Attribute(str) # file should have the following header: # filter|x_hdwchange|x_spdchange # where filter is a network calculator filter expression # x refers to the scenario number # the x columns can be multiple (ie. multiple definitions # in a single file) # hdwchange and spdchange are factors by which # to change headways and speeds for the filtered # lines additionalInputFiles = _m.Attribute(str) #Either a string containing 'None' or a list of additional alt files ; separated. def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker(self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario def page(self): pb = _m.ToolPageBuilder(self, title="Apply Batch Line Edits", description="Cannot be called from Modeller.", runnable=False, branding_text="XTMF") return pb.render() ########################################################################################################## def __call__(self, xtmf_ScenarioNumber, inputFile, additionalInputFiles = None): #---1 Set up scenario self.Scenario = _m.Modeller().emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" %xtmf_ScenarioNumber) #---2 Set up instruction file self.InstructionFile = inputFile if (self.InstructionFile is None): raise Exception("Need to provide an input file.") # Process the additional files, if it is the string None then there are no additional files otherwise they are ; separated if additionalInputFiles is None or additionalInputFiles == "None": self.InputFiles = [] else: self.InputFiles = additionalInputFiles.split(';') # Add the base transaction file to the beginning self.InputFiles.insert(0, self.InstructionFile) try: self._Execute() except Exception as e: msg = str(e) + "\n" + _traceback.format_exc(e) raise Exception(msg) ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format(classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): #init the ProgressTracker now that we know how many files we need to load self.TRACKER = _util.ProgressTracker(len(self.InputFiles)) for altFile in self.InputFiles: changesToApply = self._LoadFile(altFile) print "Instruction file loaded" if changesToApply: self._ApplyLineChanges(changesToApply) print "Headway and speed changes applied" else: print "No changes available in this scenario" self.TRACKER.completeTask() ########################################################################################################## #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Scenario" : str(self.Scenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__} return atts def _LoadFile(self, fileName): with open(fileName) as reader: header = reader.readline() cells = header.strip().split(self.COMMA) filterCol = cells.index('filter') headwayTitle = self.Scenario.id + '_hdwchange' speedTitle = self.Scenario.id + '_spdchange' try: headwayCol = cells.index(headwayTitle) except Exception as e: msg = "Error. No headway match for specified scenario: '%s'." %self.Scenario.id _m.logbook_write(msg) print msg return try: speedCol = cells.index(speedTitle) except Exception as e: msg = "Error. No speed match for specified scenario: '%s'." %self.Scenario.id _m.logbook_write(msg) print msg return instructionData = {} for num, line in enumerate(reader): cells = line.strip().split(self.COMMA) filter = cells[filterCol] if cells[headwayCol]: hdw = cells[headwayCol] else: hdw = 1 # if the headway column is left blank, carry forward a factor of 1 if cells[speedCol]: spd = cells[speedCol] else: spd = 1 instructionData[filter] = (float(hdw),float(spd)) return instructionData def _ApplyLineChanges(self, inputData): for filter, factors in inputData.iteritems(): if factors[0] != 1: spec = { "type": "NETWORK_CALCULATION", "expression": str(factors[0]) + "*hdw", "result": "hdw", "selections": { "transit_line": filter}} netCalc(spec, self.Scenario) if factors[1] != 1: spec = { "type": "NETWORK_CALCULATION", "expression": str(factors[1]) + "*speed", "result": "speed", "selections": { "transit_line": filter}} netCalc(spec, self.Scenario) @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class ExtractStationBoardingsAlightings(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here COLON = ':' COMMA = ',' #---PARAMETERS xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only Scenario = _m.Attribute(_m.InstanceType) # common variable or parameter StationNodeFile = _m.Attribute(str) ReportFile = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): if EMME_VERSION < (4, 1, 5): raise ValueError( "Tool not compatible. Please upgrade to version 4.1.5+") pb = _tmgTPB.TmgToolPageBuilder( self, title="Export Station Boardings and Alightings v%s" % self.version, description="Extracts total boardings and alightings for a list \ of nodes defined in a CSV file.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) pb.add_select_file(tool_attribute_name='ReportFile', title="Report file", file_filter="*.csv", window_type='save_file') pb.add_select_file( tool_attribute_name='StationNodeFile', title="Station Node file:", window_type='file', file_filter="*.csv", note="Station node file contains the following two columns: \ <ul><li>node_id</li>\ <li>label</li></ul> \ where label is whatever you wish to label the node in the output." ) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception, e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.")
class MergeFunctions(_m.Tool()): version = '1.0.0' tool_run_msg = "" number_of_tasks = 3 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) FunctionFile = _m.Attribute(str) RevertOnError = _m.Attribute(bool) ConflictOption = _m.Attribute(str) RAISE_OPTION = "RAISE" PRESERVE_OPTION = "PRESERVE" OVERWRITE_OPTION = "OVERWRITE" EDIT_OPTION = "EDIT" OPTIONS_LIST = [ (EDIT_OPTION, "EDIT - Launch an editor GUI to resolve conflicts manually."), (RAISE_OPTION, "RAISE - Raise an error if any conflicsts are detected."), (PRESERVE_OPTION, "PRESERVE - Preserve functional definitions from the current Emme project." ), (OVERWRITE_OPTION, "OVERWRITE - Overwrite functional definitions from the function file." ) ] def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.RevertOnError = True self.ConflictOption = 'EDIT' #--- event to block GUI / merge edit self.event = None self.function_conflicts = None self.function_changes = [] # -- hold dialog reference self.dialog = None # -- showing dialog self.show_edit_dialog = False self.is_sub_call = False def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Merge Functions v%s" % self.version, description= "Merges into this emmebank functions defined in a standard \ function transaction file. Delete and modify commands are ignored.\ <br><br>Detects conflicts in functional definitions and prompts \ user for input. New functions as simply merged in.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) baseFolder = _path.dirname(_MODELLER.desktop.project_file_name()) pb.add_select_file(tool_attribute_name='FunctionFile', window_type='file', start_path=baseFolder, title="Functions File") pb.add_select(tool_attribute_name='ConflictOption', keyvalues=self.OPTIONS_LIST, title="Conflict resolution option", note="Select an option for this tool to perform if \ conflicts in functional definitions are detected.") pb.add_checkbox(tool_attribute_name='RevertOnError', label="Revert on error?") pb.add_html(""" <script type="text/javascript"> $(document).ready( function () { var tool = new inro.modeller.util.Proxy(%s); }); </script>""" % pb.tool_proxy_tag) return pb.render() ########################################################################################################## def run(self, event=None, is_sub_call=False): self.tool_run_msg = "" self.event = event self.TRACKER.reset() if self.FunctionFile is None: raise IOError("Import file not specified") try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): file_functions = self._LoadFunctionFile() self.TRACKER.completeTask() database_functions = self._LoadFunctionsInDatabank() self.TRACKER.completeTask() newFuncCount, modFuncCount = self._MergeFunctions( database_functions, file_functions) self.TRACKER.completeTask() msg = "Done." if newFuncCount > 0: msg += " %s functions added." % newFuncCount if modFuncCount > 0: msg += " %s functions modified." % modFuncCount self.tool_run_msg = _m.PageBuilder.format_info(msg) _m.logbook_write(msg) ########################################################################################################## #----CONTEXT MANAGERS--------------------------------------------------------------------------------- ''' Context managers for temporary database modifications. ''' @contextmanager def _NewFunctionMANAGER(self, newFunctions, modifiedFunctions): emmebank = _MODELLER.emmebank try: yield # Yield return a temporary object except Exception as e: if self.RevertOnError: for id in newFunctions: emmebank.delete_function(id) for id, expression in modifiedFunctions.iteritems(): emmebank.function(id).expression = expression raise #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Functions File": self.FunctionFile, "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _LoadFunctionFile(self): functions = {} with open(self.FunctionFile) as reader: expressionBuffer = "" trecord = False currentId = None for line in reader: line = line.rstrip() linecode = line[0] record = line[2:] if linecode == 'c': pass elif linecode == 't': if not record.startswith("functions"): raise IOError("Wrong t record!") trecord = True elif linecode == 'a': if not trecord: raise IOError("A before T") index = record.index('=') currentId = record[:index].strip() expressionBuffer = record[(index + 1):].replace(' ', '') if currentId is not None: functions[currentId] = expressionBuffer elif linecode == ' ': if currentId is not None and trecord: s = record.strip().replace(' ', '') expressionBuffer += s functions[currentId] = expressionBuffer elif linecode == 'd' or linecode == 'm': currentId = None expressionBuffer = "" else: raise KeyError(linecode) return functions def _LoadFunctionsInDatabank(self): functions = {} for func in _MODELLER.emmebank.functions(): expr = func.expression.replace(' ', '') functions[func.id] = expr return functions def _MergeFunctions(self, databaseFunctions, fileFunctions): emmebank = _MODELLER.emmebank databaseIds = set([key for key in databaseFunctions.iterkeys()]) fileIds = set([key for key in fileFunctions.iterkeys()]) newFunctions = [] modifiedFunctions = {} with self._NewFunctionMANAGER(newFunctions, modifiedFunctions): for id in (fileIds - databaseIds): #Functions in the new source only expression = fileFunctions[id] emmebank.create_function(id, expression) _m.logbook_write("Added %s : %s" % (id, expression)) newFunctions.append(id) conflicts = [] conflicts_obj = [] for id in (fileIds & databaseIds): #Functions in both sources database_expression = databaseFunctions[id] file_expression = fileFunctions[id] if file_expression != database_expression: conflicts.append( (id, database_expression, file_expression)) conflicts_obj.append({ 'id': id, 'database_expression': database_expression, 'file_expression': file_expression }) if len(conflicts) > 0: conflicts.sort() #If the PRESERVE option is selected, do nothing if self.ConflictOption == self.OVERWRITE_OPTION: #Overwrite exisiting functions with new ones for fid, database_expression, file_expression in conflicts: func = emmebank.function(fid) func.expression = file_expression modifiedFunctions[fid] = database_expression with _m.logbook_trace("Changed function %s" % fid): _m.logbook_write("Old expression: %s" % database_expression) _m.logbook_write("New expresion: %s" % file_expression) elif self.ConflictOption == self.EDIT_OPTION: #self.event.clear() conflicts_obj.sort(key=lambda x: x['id']) self.function_conflicts = conflicts_obj # self._LaunchGUI(conflicts,modifiedFunctions) if not self.is_sub_call: self.show_edit_dialog = True else: self._LaunchGUI(conflicts, modifiedFunctions) # self.event.wait() elif self.ConflictOption == self.RAISE_OPTION: tup = len(conflicts), ', '.join([t[0] for t in conflicts]) msg = "The following %s functions have conflicting definitions: %s" % tup raise Exception(msg) return len(newFunctions), len(modifiedFunctions) def save_modified_functions(functions): return def _LaunchGUI(self, conflicts, modifiedFunctions): self.dialog = FunctionConflictDialog(conflicts, self) #self.dialog = dialog result = self.dialog.exec_() # self.event.wait() #if result == dialog.Accepted: # acceptedChanges = dialog.getFunctionsToChange() # for fid, expression in acceptedChanges.iteritems(): # func = _MODELLER.emmebank.function(fid) # oldExpression = func.expression # func.expression = expression # modifiedFunctions[fid] = oldExpression # with _m.logbook_trace("Modified function %s" %fid.upper()): # _m.logbook_write("Old expression: %s" %oldExpression) # _m.logbook_write("New expression: %s" %expression) # self.dialog.deleteLater() def merge_changes(self, changes): for change in changes: if change['resolve'] == 'file' or change['resolve'] == 'expression': print(change) func = _MODELLER.emmebank.function(change['id']) oldExpression = func.expression func.expression = change['expression'] # modifiedFunctions[change['id']] = oldExpression with _m.logbook_trace("Modified function %s" % change['id'].upper()): _m.logbook_write("Old expression: %s" % oldExpression) _m.logbook_write("New expression: %s" % change['expression']) @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=six.u) def tool_run_msg_status(self): return self.tool_run_msg def update_data(self): # dialog = self.dialog acceptedChanges = self.dialog.getFunctionsToChange() for fid, expression in acceptedChanges.iteritems(): func = _MODELLER.emmebank.function(fid) oldExpression = func.expression func.expression = expression modifiedFunctions[fid] = oldExpression with _m.logbook_trace("Modified function %s" % fid.upper()): _m.logbook_write("Old expression: %s" % oldExpression) _m.logbook_write("New expression: %s" % expression)
class Station2StationAssignment(_m.Tool()): version = '0.1.0' tool_run_msg = "" #---Variable definitions ScenarioNumber = _m.Attribute(int) DemandMatrixNumber = _m.Attribute(int) WaitTimeMatrixNumber = _m.Attribute(int) # InVehicleTimeMatrixNumber = _m.Attribute(int) # StationSelectorExpression = _m.Attribute(str) # ModeString = _m.Attribute(str) WaitFactor = _m.Attribute(float) # WaitPerception = _m.Attribute(float) # WalkPerception = _m.Attribute(float) # UseAdditiveDemand = _m.Attribute(bool) # UseEM4Options = _m.Attribute(bool) # Not yet used. Future proofing. #---Special instance types scenario = _m.Attribute(_m.InstanceType) # modes = _m.Attribute(_m.ListType) # demandMatrix = _m.Attribute(_m.InstanceType) # #---Internal variables _modeList = [] def __init__(self): #ENTER IN THE NUMBER OF TASKS. THIS WILL CRASH OTHERWISE. #****************************************************************************** self._tracker = _util.ProgressTracker(6) # Enter in the correct number of tasks #****************************************************************************** # Set up variable defaults self.WaitFactor = 0.5 self.StationSelectorExpression = "7000-8000" self.WaitPerception = 2.0 self.WalkPerception = 2.0 self.UseAdditiveDemand = False self.UseEM4Options = False def page(self): pb = _tmgTPB.TmgToolPageBuilder(self, title="Station to Station Assignment v%s" %self.version, description="Assigns a limited matrix of demand to centroids which represent \ GO train stations. Can assign a scalar matrix of 0 or a full matrix of \ demand (constrained by the station selector). Unlike most other transit \ assignment tools, this tool saves the constrained IVTT and wait times \ matrices as outputs.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_header("ASSIGNMENT SETUP") #----------------------------------------------------------------------------- pb.add_select_scenario(tool_attribute_name='scenario', title='Scenario:', allow_none=False) pb.add_select_matrix(tool_attribute_name='demandMatrix', title='Demand Matrix:', note="If no matrix is selected, a scalar matrix of value '0' will\ be assigned.", allow_none=True) pb.add_select_mode(tool_attribute_name='modes', title='Assignment Modes', filter=['TRANSIT', 'AUX_TRANSIT'], note="<font color='red'><b>Modes are available for the primary scenario only.</b></font>\ <br>Actual assignment is based on mode ids, so this is only a problem\ <br>if modes differ across scenarios.") pb.add_text_box(tool_attribute_name='StationSelectorExpression', size=150, title="Station centroid selection:", note="Write an expression to select which centroids are stations.<br>\ A single range is written as '[start]-[stop]' (e.g., '7000-8000') <br>\ with multiple ranges separated by ';'", multi_line=True) with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_checkbox(tool_attribute_name='UseAdditiveDemand') with t.table_cell(): pb.add_html("Assign additional demand?") with t.table_cell(): pb.add_checkbox(tool_attribute_name='UseEM4Options') with t.table_cell(): pb.add_html("Use new Emme 4 options?") pb.add_header("ROUTE CHOICE PARAMETERS") #----------------------------------------------------------------------------- with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_text_box(tool_attribute_name='WaitPerception', size=6, title="Wait Time Perception") with t.table_cell(): pb.add_text_box(tool_attribute_name='WaitFactor', size=6, title="Headway Fraction") with t.table_cell(): pb.add_text_box(tool_attribute_name='WalkPerception', size=6, title="Walk Time Perception") pb.add_header("ASSIGNMENT OUTPUT") #----------------------------------------------------------------------------- with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_text_box(tool_attribute_name='WaitTimeMatrixNumber', size=2, title="Wait Times Matrix Number", note="If left blank, an available matrix will be created.") with t.table_cell(): pb.add_text_box(tool_attribute_name='InVehicleTimeMatrixNumber', size=2, title="In-Vehicle Times Matrix Number", note="If left blank, an available matrix will be created.") return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" '''Run is called from Modeller.''' self.isRunningFromXTMF = False #Setup self._modeList = [str(m) for m in self.modes] try: self._execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Run complete.") def __call__(self, ScenarioNumber, DemandMatrixNumber, WaitTimeMatrixNumber, InVehicleTimeMatrixNumber, \ StationSelectorExpression, ModeString, WaitFactor, WaitPerception, WalkPerception,\ UseAdditiveDemand, UseEM4Options): #---1 Set up scenario self.scenario = _m.Modeller().emmebank.scenario(ScenarioNumber) if (self.scenario is None): raise Exception("Scenario %s was not found!" %ScenarioNumber) #---2 Set up the demand matrix if DemandMatrixNumber == 0: self.demandMatrix = None else: self.demandMatrix = _m.Modeller().emmebank.matrix('mf%s' %DemandMatrixNumber) if self.demandMatrix is None: raise Exception("Could not find matrix 'mf%s' in the databank!" %DemandMatrixNumber) #---3 Set up modes self._modeList = [c for c in ModeString] #---4 Pass in remaining args self.WaitTimeMatrixNumber = WaitTimeMatrixNumber self.InVehicleTimeMatrixNumber = InVehicleTimeMatrixNumber self.StationSelectorExpression = StationSelectorExpression self.WaitFactor = WaitFactor self.WalkPerception = WalkPerception self.UseAdditiveDemand = UseAdditiveDemand self.UseEM4Options = UseEM4Options self.isRunningFromXTMF = True #---Execute try: self._execute() except Exception as e: raise Exception(_traceback.format_exc(e)) ########################################################################################################## def _execute(self): self._tracker.reset() with _m.logbook_trace(name="{classname} v{version}".format(classname=(self.__class__.__name__), version=self.version), attributes=self._getAtts()): try: transitAssignmentTool = _m.Modeller().tool("inro.emme.standard.transit_assignment.extended_transit_assignment") matrixResultsTool = _m.Modeller().tool('inro.emme.standard.transit_assignment.extended.matrix_results') matrixCalcTool = _m.Modeller().tool("inro.emme.standard.matrix_calculation.matrix_calculator") except Exception as e: transitAssignmentTool = _m.Modeller().tool("inro.emme.transit_assignment.extended_transit_assignment") matrixResultsTool = _m.Modeller().tool('inro.emme.transit_assignment.extended.matrix_results') matrixCalcTool = _m.Modeller().tool("inro.emme.matrix_calculation.matrix_calculator") with self._demandMatrixMANAGER(): # TASK 1 with _m.logbook_trace("Initializing output matrices"): ivttMatrix = _util.initializeMatrix(id=self.InVehicleTimeMatrixNumber, matrix_type='FULL', description="Station-station IVTT matrix") waitMatrix = _util.initializeMatrix(id=self.WaitTimeMatrixNumber, matrix_type='FULL', description="Station-station wait time matrix") self._tracker.completeTask() # TASK 2 with _m.logbook_trace("Running transit assignment"): self._tracker.runTool(transitAssignmentTool, self._getAssignmentSpec(), scenario=self.scenario, add_volumes=self.UseAdditiveDemand) #TASK 3 # some error with progress reporting is occurring here. with _m.logbook_trace("Extracting output matrices"): self._tracker.runTool(matrixResultsTool, self._getMatrixResultSpec(ivttMatrix, waitMatrix), scenario=self.scenario) # TASK 4 with _m.logbook_trace("Constraining output matrices"): self._tracker.runTool(matrixCalcTool, self._getConstraintSpec(ivttMatrix, ivttMatrix), scenario=self.scenario) # TASK 5 self._tracker.runTool(matrixCalcTool, self._getConstraintSpec(waitMatrix, waitMatrix), scenario=self.scenario) # TASK 6 ########################################################################################################## #----CONTEXT MANAGERS--------------------------------------------------------------------------------- ''' Context managers for temporary database modifications. ''' @contextmanager def _demandMatrixMANAGER(self): #Code here is executed upon entry with _m.logbook_trace("Initializing temporary demand matrix"): id=None if self.demandMatrix is None: self.demandMatrix = _util.initializeMatrix(id, matrix_type='SCALAR', name='trscal', description='Scalar matrix to get transit times') self._tracker.completeTask() else: cachedMatrix = self.demandMatrix self.demandMatrix = _util.initializeMatrix(matrix_type='FULL', description="Constrained full matrix for station-to-station assignment") _m.logbook_write("Created temporary constrained full demand matrix '%s'" %id) try: matrixCalcTool = _m.Modeller().tool("inro.emme.standard.matrix_calculation.matrix_calculator") except Exception as e: matrixCalcTool = _m.Modeller().tool("inro.emme.matrix_calculation.matrix_calculator") self._tracker.runTool(matrixCalcTool, self._getConstraintSpec(cachedMatrix, self.demandMatrix), scenario=self.scenario) #TASK 1 try: yield # Code here is executed upon clean exit finally: # Code here is executed in all cases. id = self.demandMatrix.id _m.Modeller().emmebank.delete_matrix(id) _m.logbook_write("Temporary matrix %s deleted." %id) #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _getAtts(self): atts = { "Scenario" : str(self.scenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__} return atts def _getConstraintSpec(self, baseMatrix, resultMatrix): return { "expression": baseMatrix.id, "result": resultMatrix.id, "constraint": { "by_value": None, "by_zone": { "origins": self.StationSelectorExpression, "destinations": self.StationSelectorExpression } }, "aggregation": { "origins": None, "destinations": None }, "type": "MATRIX_CALCULATION" } def _getAssignmentSpec(self): spec = { "modes": self._modeList, "demand": self.demandMatrix.id, "waiting_time": { "headway_fraction": self.WaitFactor, "effective_headways": "hdw", "spread_factor": 1, "perception_factor": self.WaitPerception }, "boarding_time": { "at_nodes": None, "on_lines": { "penalty": "ut3", "perception_factor": 1 } }, "boarding_cost": { "at_nodes": { "penalty": 0, "perception_factor": 1 }, "on_lines": None }, "in_vehicle_time": { "perception_factor": 1 }, "in_vehicle_cost": None, "aux_transit_time": { "perception_factor": self.WalkPerception }, "aux_transit_cost": None, "flow_distribution_at_origins": { "by_time_to_destination": "BEST_CONNECTOR", "by_fixed_proportions": None }, "flow_distribution_between_lines": { "consider_travel_time": False }, "connector_to_connector_path_prohibition": None, "save_strategies": True, "od_results": None, "type": "EXTENDED_TRANSIT_ASSIGNMENT" } if EMME_VERSION >= (4,1,0): spec["performance_settings"] = { "number_of_processors": cpu_count() } return spec def _getMatrixResultSpec(self, ivttMatrix, waitMatrix): return { "by_mode_subset": { "modes": self._modeList, "actual_in_vehicle_times": ivttMatrix.id }, "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", "actual_total_waiting_times": waitMatrix.id } @_m.method(return_type=_m.TupleType) def percent_completed(self): try: return self._tracker.getProgress() except Exception as e: print "Exception occurred during progress reporting." print "Tracker progress = %s" %self._tracker._progress print _traceback.format_exc(e) raise @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class CreateNetworkCorrespondenceFile(_m.Tool()): version = '0.1.2' tool_run_msg = "" number_of_tasks = 7 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) PrimaryScenario = _m.Attribute(_m.InstanceType) SecondaryScenario = _m.Attribute(_m.InstanceType) SearchBuffer = _m.Attribute(float) MaxSplitLinks = _m.Attribute(int) MaxBearingDifference = _m.Attribute(int) CorrespondenceFile = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.PrimaryScenario = _MODELLER.scenario #Default is primary scenario self.SearchBuffer = 50.0 self.MaxSplitLinks = 10 self.MaxBearingDifference = 5 def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Create Network Correspondence File v%s" % self.version, description= "<p class='tmg_left'>Twins together nodes and links in two networks. \ Node correspondence \ is based on proximity (Manhattan distance). Link correspondence is based on \ node correspondence - e.g., if both ends of a link in the primary correspond \ to both ends of another link in the secondary network, then those two links \ are twinned. If no link twin is found, this tool attempts to determine if a \ split has occurred; based on the bearing of links attached to it's twinned \ nodes.\ <br><br>The results are saved into a zip file, containing three files: \ <ul class='tmg_left'><li><b>config.txt</b> contains the parameters used to \ write the file</li>\ <li><b>nodes.txt</b> contains the node correspondence</li>\ <li><b>links.txt</b> contains the link correspondence</li></ul></p>", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_header("SCENARIOS") #------------------------------------------------------------ with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_select_scenario(tool_attribute_name='PrimaryScenario', title='Primary Scenario', allow_none=False) with t.table_cell(): pb.add_select_scenario(tool_attribute_name='SecondaryScenario', title='Secondary Scenario', allow_none=False) pb.add_header("CORRESPONDANCE PARAMETERS") #------------------------------------------------------------ with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_text_box(tool_attribute_name='SearchBuffer', title="Node Search Buffer", size=10, note="Search radius, in coordinate units.") with t.table_cell(): pb.add_text_box( tool_attribute_name='MaxSplitLinks', size=2, title="Max split links", note="Maximum number of split links to look for.") with t.table_cell(): pb.add_text_box(tool_attribute_name='MaxBearingDifference', size=2, title="Max bearing difference", note="In degrees.") pb.add_header("OUTPUT FILE") #------------------------------------------------------------ pb.add_select_file(tool_attribute_name='CorrespondenceFile', window_type='save_file', title="Correspondence File", file_filter="*.zip") return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() if self.CorrespondenceFile is None: raise IOError("Export file not specified") self.CorrespondenceFile = _path.splitext( self.CorrespondenceFile)[0] + ".zip" try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info( "Run complete.<br>\ <a href=%s target='_top'>%s</a>" % (self.CorrespondenceFile, _path.basename(self.CorrespondenceFile)), escape=False) ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): self._maxBearingDiffRadians = abs( 2 * _math.pi * self.MaxBearingDifference / 360.0) #Load the networks self.TRACKER.startProcess(2) primaryNetwork = self.PrimaryScenario.get_network() self.TRACKER.completeSubtask() secondaryNetwork = self.SecondaryScenario.get_network() self.TRACKER.completeSubtask() self.TRACKER.completeTask() with _m.logbook_trace("Associating node twins"): self._ConnectTwinNodes(primaryNetwork, secondaryNetwork) with _m.logbook_trace("Associating link twins"): maxTwins = self._ConnectTwinLinks(primaryNetwork, secondaryNetwork) with _m.logbook_trace("Writing results to file"): self._WriteFile(primaryNetwork, maxTwins) _m.logbook_write("Done.") ########################################################################################################## #----CONTEXT MANAGERS--------------------------------------------------------------------------------- ''' Context managers for temporary database modifications. ''' @contextmanager def _zipFileMANAGER(self): file = _zf.ZipFile(self.CorrespondenceFile, 'w', _zf.ZIP_DEFLATED) try: yield file finally: file.close() #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Primary Scenario": self.PrimaryScenario.id, "Secondary Scenario": self.SecondaryScenario.id, "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _ConnectTwinNodes(self, primaryNetwork, secondaryNetwork): self.TRACKER.startProcess( primaryNetwork.element_totals['regular_nodes']) primaryNetwork.create_attribute('NODE', "twin_node", default_value=None) secondaryNetwork.create_attribute('NODE', "twin_node", default_value=None) extents = _spindex.get_network_extents(secondaryNetwork) grid = _spindex.GridIndex(extents, marginSize=1.0) for node in secondaryNetwork.regular_nodes(): grid.insertPoint(node) for primaryNode in primaryNetwork.regular_nodes(): twin = grid.getNearestNode(primaryNode.x, primaryNode.y, self.SearchBuffer) candidates = grid.queryCircle(primaryNode.x, primaryNode.y, self.SearchBuffer) twin = None minDistance = float('inf') for node in candidates: dx = node.x - primaryNode.x dy = node.y - primaryNode.y d = sqrt(dx * dx + dy * dy) if d < minDistance: twin = node minDistance = d if twin is None: self.TRACKER.completeSubtask() continue primaryNode['twin_node'] = twin twin['twin_node'] = primaryNode self.TRACKER.completeSubtask() self.TRACKER.completeTask() def _ConnectTwinLinks(self, primaryNetwork, secondaryNetwork): primaryNetwork.create_attribute('LINK', "twin_links", default_value=[]) secondaryNetwork.create_attribute('LINK', "twin_links", default_value=[]) maxTwins = 0 # First pass. pLinksTwinned = 0 sLinksTwinned = 0 self.TRACKER.startProcess(primaryNetwork.element_totals['links']) for primaryLink in primaryNetwork.links(): if primaryLink.i_node.is_centroid or primaryLink.j_node.is_centroid: self.TRACKER.completeSubtask() continue # Skip centroid connectors twins = self._GetTwinLinks(primaryLink) if twins is None: self.TRACKER.completeSubtask() continue if len(twins) > maxTwins: maxTwins = len(twins) primaryLink['twin_links'] = twins pLinksTwinned += 1 for secondaryLink in twins: secondaryLink['twin_links'] = [primaryLink] sLinksTwinned += 1 self.TRACKER.completeTask() _m.logbook_write( "Finished first pass. %s primary links twinned to %s secondary links." % (pLinksTwinned, sLinksTwinned)) # Second Pass pLinksTwinned = 0 sLinksTwinned = 0 self.TRACKER.startProcess(secondaryNetwork.element_totals['links']) for secondaryLink in secondaryNetwork.links(): if secondaryLink.i_node.is_centroid or secondaryLink.j_node.is_centroid: self.TRACKER.completeSubtask() continue # Skip centroid connectors if len(secondaryLink['twin_links']) > 0: continue # Skip if link is already twinned. twins = self._GetTwinLinks(secondaryLink) if twins is None: self.TRACKER.completeSubtask() continue if len(twins) > maxTwins: maxTwins = len(twins) secondaryLink['twin_links'] = twins sLinksTwinned += 1 for primaryLink in twins: primaryLink['twin_links'] = [secondaryLink] pLinksTwinned += 1 self.TRACKER.completeTask() _m.logbook_write( "Finished second pass. %s additional secondary links twinned to %s primary links." % (sLinksTwinned, pLinksTwinned)) return maxTwins def _GetTwinLinks(self, originalLink): if originalLink.i_node['twin_node'] is None or originalLink.j_node[ 'twin_node'] is None: return None #Cannot ever find a corresponding originalLink for a originalLink with no twin nodes # Check for the same link in the other network for outLink in originalLink.i_node['twin_node'].outgoing_links(): if outLink.j_node == originalLink.j_node['twin_node']: return [outLink] # If not, try and get the collection of links which were created by splitting this link # (if such links exist). This function returns None if a valid split path cannot be found. return self._GetCorrespondingSplitLinks(originalLink) def _GetCorrespondingSplitLinks(self, originalLink): #don't call this method unless both node-ends of the original link have twins originalBearing = self._GetLinkBearing(originalLink) linkSequece = [] prevNode = originalLink.i_node['twin_node'] for i in range(0, self.MaxSplitLinks): candidateLinks = [ ] #tuple of 0. Bearing difference, 1. outgoing link outgoingLinks = [link for link in prevNode.outgoing_links()] for link in outgoingLinks: bearingDiff = abs(self._GetLinkBearing(link) - originalBearing) if bearingDiff > self._maxBearingDiffRadians: continue candidateLinks.append((bearingDiff, link)) if len(candidateLinks) == 0: return None # If there are no links within the search arc, since we haven't reached the # end node of the original link, therefore no straight path exists. bestLink = min( candidateLinks )[1] #If there are more than one links within the search arc, pick # the closest. linkSequece.append(bestLink) if bestLink.j_node == originalLink.j_node[ 'twin_node']: # We've reached the end node of the original return linkSequece # link. So, return the sequence prevNode = bestLink.j_node #continue searching for candidate links in the sequences def _GetLinkBearing(self, link): rad = _math.atan2(link.j_node.x - link.i_node.x, link.j_node.y - link.i_node.y) if rad < 0: return rad + _math.pi * 2 return rad def _WriteFile(self, primaryNetwork, maxLinkTwins): folderName = _path.dirname(self.CorrespondenceFile) with open("%s/config.txt" % folderName, 'w') as writer: s = "project_path: {projPath}\ \nprimary_scenario: {pSc}\ \nsecondary_scenario: {sSc}\ \nsearch_radius: {rad}\ \nmax_twins: {max}\ \narc_tolerance: {arc}\ \ncreated: {date}".format( projPath=_MODELLER.desktop.project_file_name(), pSc=self.PrimaryScenario.id, sSc=self.SecondaryScenario.id, rad=str(self.SearchBuffer), max=str(self.MaxSplitLinks), arc=str(self.MaxBearingDifference), date=_dt.now()) writer.write(s) with open("%s/nodes.txt" % folderName, 'w') as writer: self.TRACKER.startProcess( primaryNetwork.element_totals['regular_nodes']) writer.write("primary_node,secondary_node") for node in primaryNetwork.nodes(): twin = node['twin_node'] if twin is None: writer.write("\n%s,null" % node) else: writer.write("\n%s,%s" % (node, twin)) self.TRACKER.completeSubtask() self.TRACKER.completeTask() with open("%s/links.txt" % folderName, 'w') as writer: self.TRACKER.startProcess(primaryNetwork.element_totals['links']) writer.write("primary_link") for i in range(0, maxLinkTwins): writer.write(",twin_link_%s" % (i + 1)) for primaryLink in primaryNetwork.links(): writer.write("\n(%s-%s)" % (primaryLink.i_node, primaryLink.j_node)) twins = primaryLink['twin_links'] if len(twins) == 0: for i in range(0, maxLinkTwins): writer.write(",null") continue for secondaryLink in twins: writer.write(",(%s-%s)" % (secondaryLink.i_node, secondaryLink.j_node)) for i in range(len(twins), maxLinkTwins): writer.write(",null") self.TRACKER.completeSubtask() self.TRACKER.completeTask() with self._zipFileMANAGER() as zf: zf.write("%s/config.txt" % folderName, arcname="config.txt") zf.write("%s/links.txt" % folderName, arcname="links.txt") zf.write("%s/nodes.txt" % folderName, arcname="nodes.txt") os.remove("%s/config.txt" % folderName) os.remove("%s/links.txt" % folderName) os.remove("%s/nodes.txt" % folderName) self.TRACKER.completeTask() @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class MatrixSummary(_m.Tool()): version = '1.0.0' tool_run_msg = "" number_of_tasks = 8 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) ValueMatrix = _m.Attribute(_m.InstanceType) WeightingMatrix = _m.Attribute(_m.InstanceType) Scenario = _m.Attribute(_m.InstanceType) ReportFile = _m.Attribute(str) OriginFilterExpression = _m.Attribute(str) DestinationFilterExpression = _m.Attribute(str) CellFilterExpression = _m.Attribute(str) HistogramMin = _m.Attribute(float) HistogramMax = _m.Attribute(float) HistogramStepSize = _m.Attribute(float) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only xtmf_ValueMatrixNumber = _m.Attribute(int) xtmf_WeightingMatrixNumber = _m.Attribute(int) xtmf_OriginRangeSetString = _m.Attribute(str) xtmf_DestinationRangeSetString = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker(self.number_of_tasks) #init the ProgressTracker self.HistogramMin = 0.0 self.HistogramMax = 200.0 self.HistogramStepSize = 10.0 self.OriginFilterExpression = "return p < 9000" self.DestinationFilterExpression = "return q < 9000" self.CellFilterExpression = "return pq < 1000.0" def page(self): pb = _tmgTPB.TmgToolPageBuilder(self, title="Export Matrix Summary v%s" %self.version, description="Computes using <em>numpy</em> a several aggregate statistics \ for a given matrix: average, median, standard deviation, and \ a histogram of values. Users can also specify an optional matrix \ of weights, and the tool will also compute weighted average, \ standard deviation, and histogram values.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_matrix(tool_attribute_name='ValueMatrix', filter=['FULL'], allow_none=False, title="Value Matrix") pb.add_select_matrix(tool_attribute_name='WeightingMatrix', filter=['FULL'], allow_none=True, title="Weighting Matrix", note="<font color='green'><b>Optional:</b></font> Matrix of weights") pb.add_select_file(tool_attribute_name='ReportFile', window_type='save_file', file_filter='*.txt', title="Report File", note="<font color='green'><b>Optional.</b></font> Matrix data will be \ saved to the logbook.") pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=True, note="<font color='green'><b>Optional:</b></font> Only required if \ scenarios have differing zone systems.") pb.add_header('FILTERS') pb.add_text_box(tool_attribute_name='OriginFilterExpression', size=100, multi_line=False, title="def OriginFilter(p):", note="Enter a Python expression. Include the return statement.") pb.add_text_box(tool_attribute_name='DestinationFilterExpression', size=100, multi_line=False, title="def DestinationFilter(q):", note="Enter a Python expression. Include the return statement") #TODO: Figure out how to apply the filter expression #simultaeneously to both the value and weight matrix #using numpy ''' pb.add_text_box(tool_attribute_name='CellFilterExpression', size=100, multi_line=True, title="def CellFilter(pq):", note="Enter a Python expression.") ''' pb.add_header("HISTOGRAM") with pb.add_table(visible_border=False) as t: with t.table_cell(): pb.add_text_box(tool_attribute_name='HistogramMin', title= "Min", size=10) with t.table_cell(): pb.add_text_box(tool_attribute_name='HistogramMax', title= "Max", size=10) with t.table_cell(): pb.add_text_box(tool_attribute_name='HistogramStepSize', title= "Step Size", size=10) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: originFilter = self._GetOriginFilterFunction() destinationFilter = self._GetDestinationFilterFunction() self._Execute(originFilter, destinationFilter) except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") def __call__(self, xtmf_ValueMatrixNumber, xtmf_WeightingMatrixNumber, xtmf_ScenarioNumber, ReportFile, HistogramMin, HistogramMax, HistogramStepSize, xtmf_OriginRangeSetString, xtmf_DestinationRangeSetString): self.ValueMatrix = _MODELLER.emmebank.matrix('mf%s' %xtmf_ValueMatrixNumber) if self.ValueMatrix is None: raise Exception("Full matrix mf%s was not found!" %xtmf_ValueMatrixNumber) if xtmf_WeightingMatrixNumber == 0: self.WeightingMatrix = None else: self.WeightingMatrix = _MODELLER.emmebank.matrix('mf%s' %xtmf_WeightingMatrixNumber) if self.WeightingMatrix is None: raise Exception("Full matrix mf%s was not found!" %xtmf_WeightingMatrixNumber) if xtmf_ScenarioNumber == 0: self.Scenario is None else: self.Scenario = _m.Modeller().emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" %xtmf_ScenarioNumber) originFilter = self._ParseRangeSetString(xtmf_OriginRangeSetString) destinationFilter = self._ParseRangeSetString(xtmf_DestinationRangeSetString) self.ReportFile = ReportFile self.HistogramMin = HistogramMin self.HistogramMax = HistogramMax self.HistogramStepSize = HistogramStepSize try: self._Execute(originFilter, destinationFilter) except Exception as e: msg = str(e) + "\n" + _traceback.format_exc(e) raise Exception(msg) ########################################################################################################## def _Execute(self, originFilter, destinationFilter): with _m.logbook_trace(name="{classname} v{version}".format(classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): if self.Scenario: valueData = self.ValueMatrix.get_data(self.Scenario.number) else: valueData = self.ValueMatrix.get_data() self.TRACKER.completeTask() #1 validIndices = [[p for p in valueData.indices[0] if originFilter(p)], [q for q in valueData.indices[1] if destinationFilter(q)]] self.TRACKER.completeTask() #2 valueSubmatrix = get_submatrix(valueData, validIndices) valueArray = array(valueSubmatrix.raw_data).flatten() self.TRACKER.completeTask() #3 self.TRACKER.startProcess(6) #Start getting the relevant data from the matrix unweightedAverage = average(valueArray) self.TRACKER.completeSubtask() minVal = min(valueArray) self.TRACKER.completeSubtask() maxVal = max(valueArray) self.TRACKER.completeSubtask() unweightedStdDev = std(valueArray) self.TRACKER.completeSubtask() unweightedMedian = median(valueArray) self.TRACKER.completeSubtask() #Create the array of bins bins = [self.HistogramMin] if minVal < self.HistogramMin: bins.insert(0, minVal) c = self.HistogramMin + self.HistogramStepSize while c < self.HistogramMax: bins.append(c) c += self.HistogramStepSize bins.append(self.HistogramMax) if maxVal > self.HistogramMax: bins.append(maxVal) unweightedHistogram, ranges = histogram(valueArray, bins) self.TRACKER.completeSubtask() self.TRACKER.completeTask() #4 #Get weighted values if neccessary if self.WeightingMatrix is not None: if self.Scenario: weightData = self.WeightingMatrix.get_data(self.Scenario.number) else: weightData = self.WeightingMatrix.get_data() self.TRACKER.completeTask() #5 weightSubmatrix = get_submatrix(weightData, validIndices) weightArray = array(weightSubmatrix.raw_data).flatten() self.TRACKER.completeTask() #6 self.TRACKER.startProcess(3) weightedAverage = average(valueArray, weights= weightArray) self.TRACKER.completeSubtask() weightedStdDev = self._WtdStdDev(valueArray, weightArray) self.TRACKER.completeSubtask() weightedHistogram, ranges = histogram(valueArray, weights= weightArray, bins = bins) self.TRACKER.completeSubtask() self.TRACKER.completeTask() #7 if self.ReportFile: self._WriteReportToFile(unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins, weightedAverage, weightedStdDev, weightedHistogram) print "Report written to %s" %self.ReportFile self._WriteReportToLogbook(unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins, weightedAverage, weightedStdDev, weightedHistogram) print "Report written to logbook." elif self.ReportFile: for i in range(3): self.TRACKER.completeTask() self._WriteReportToFile(unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins) print "Report written to %s" %self.ReportFile self._WriteReportToLogbook(unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins) print "Report written to logbook." else: self._WriteReportToLogbook(unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins) print "Report written to logbook." self.TRACKER.completeTask() #8 ########################################################################################################## #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Scenario" : str(self.Scenario), "Version": self.version, "self": self.__MODELLER_NAMESPACE__} return atts def _ParseRangeSetString(self, rss): ranges = [] cells = rss.split(',') for c in cells: r = c.split('-') start = int(r[0]) end = int(r[1]) rs = _util.IntRange(start, end) ranges.append(rs) def filter(v): for r in ranges: if v in r: return True return False return filter def _GetOriginFilterFunction(self): exec('''def filter(p): %s''' %self.OriginFilterExpression) return filter def _GetDestinationFilterFunction(self): exec('''def filter(q): %s''' %self.DestinationFilterExpression) return filter def _WtdStdDev(self, values, weights): avg = average(values, weights=weights) variance = average((values-avg)**2, weights=weights) return sqrt(variance) def _WriteReportToLogbook(self, unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins, weightedAverage=None, weightedStdDev=None, weightedHistogram=None): #print "CURRENTLY DOES NOT WRITE REPORT TO LOGBOOK" #return pb = _m.PageBuilder(title="Matrix Summary Report") bodyText = "Summary for matrix: <b>{mtx1!s} - {desc1}</b> ({stamp1!s})\ <br>Weighting Matrix: <b>{mtx2!s}".format( mtx1= self.ValueMatrix, mtx2= self.WeightingMatrix, desc1= self.ValueMatrix.description, stamp1= self.ValueMatrix.timestamp) if self.WeightingMatrix is not None: bodyText += " - %s" %self.WeightingMatrix.description bodyText += "</b><br>" rows = [] rows.append("<b>Average:</b> %s" %unweightedAverage) rows.append("<b>Minimum:</b> %s" %minVal) rows.append("<b>Maximum:</b> %s" %maxVal) rows.append("<b>Standard Deviation:</b> %s" %unweightedStdDev) rows.append("<b>Median:</b> %s" %unweightedMedian) if weightedAverage is not None: rows.append("<br><br><b>Weighted Average:</b> %s" %weightedAverage) rows.append("<b>Weighted Standard Deviation:</b> %s" %weightedStdDev) bodyText += "<h3>Matrix Statistics</h3>" + "<br>".join(rows) pb.add_text_element(bodyText) #Build the chart data uwData = [] wData = [] for i, binEdge in enumerate(bins): if i == 0: prevEdge = binEdge continue #Skip the first if (i - 1) >= len(unweightedHistogram): uwVal = 0.0 else: uwVal = unweightedHistogram[i - 1] uwData.append((int(prevEdge), float(uwVal))) if weightedHistogram is not None: if (i - 1) >= len(weightedHistogram): wVal = 0.0 else: wVal = weightedHistogram[i - 1] wData.append((int(prevEdge), float(wVal))) prevEdge = binEdge cds = [{"title": "Unweighted frequency", "data": uwData, "color": "red"}] if weightedHistogram is not None: cds.append({"title": "Weighted frequency", "data": wData, "color": "blue"}) try: pb.add_chart_widget(chart_data_series=cds, options= {'table': True, "plot_parameters": { "series": { "stack": False, #"points": {"show": False}, #"lines": {"show": False}, "bars": {"show": True}, } } }) except Exception as e: print cds raise _m.logbook_write("Matrix Summary Report for %s" %self.ValueMatrix, value= pb.render()) def _WriteReportToFile(self, unweightedAverage, minVal, maxVal, unweightedStdDev, unweightedMedian, unweightedHistogram, bins, weightedAverage=None, weightedStdDev=None, weightedHistogram=None): with open(self.ReportFile, 'w') as writer: writer.write('''Matrix Summary Report ##################### Generated on %s\n\n''' %dt.now()) writer.write("Matrix: {id!s} - {desc!s} ({stamp!s})".format(id= self.ValueMatrix, desc= self.ValueMatrix.description, stamp= self.ValueMatrix.timestamp)) writer.write("\nWeight Matrix: %s" %self.WeightingMatrix) if self.WeightingMatrix is not None: writer.write(" - {desc!s} ({stamp!s})".format(desc= self.WeightingMatrix.description, stamp = self.WeightingMatrix.timestamp)) writer.write("\n\nAverage:\t%s" %unweightedAverage) writer.write("\nMinimum:\t%s" %minVal) writer.write("\nMaximum:\t%s" %maxVal) writer.write("\nStd. Dev:\t%s" %unweightedStdDev) writer.write("\n Median:\t%s" %unweightedMedian) if weightedAverage is not None: writer.write("\nWeighted Avg.:\t%s" %weightedAverage) if weightedStdDev is not None: writer.write("\nWeighted StDv:\t%s" %weightedStdDev) writer.write(''' ------------------------- HISTOGRAM BinMin,BinMax,Freq''') if weightedHistogram is not None: writer.write(",wFreq") for i, binEdge in enumerate(bins): if i == 0: prevEdge = binEdge continue #Skip the first if (i - 1) >= len(unweightedHistogram): uwVal = 0.0 else: uwVal = unweightedHistogram[i - 1] writer.write("\n%s,%s,%s" %(prevEdge, binEdge, uwVal)) if weightedHistogram is not None: if (i - 1) >= len(weightedHistogram): wVal = 0.0 else: wVal = weightedHistogram[i - 1] writer.write(",%s" %wVal) prevEdge = binEdge @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class ExtractPathsEMME(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 xtmf_ScenarioNumber = _m.Attribute(int) #xtmf_ClassName = _m.Attribute(str) #xtmf_IterationNumber = _m.Attribute(str) #xtmf_PathDetails = _m.Attribute(str) xtmf_OutputPathFile = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker def page(self): pb = _m.ToolPageBuilder(self, title="Path Analysis", description="Cannot be called from Modeller.", runnable=False, branding_text="XTMF") return pb.render() def __call__(self, xtmf_ScenarioNumber, xtmf_OutputPathFile, xtmf_ODdist): self.ScenarioNumber = int(xtmf_ScenarioNumber) self.scenario = _m.Modeller().emmebank.scenario(self.ScenarioNumber) if (self.scenario == None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) if not self.scenario.has_transit_results: raise Exception( "Scenario %s does not have transit assignment results" % xtmf_ScenarioNumber) self.OutputPathFile = xtmf_OutputPathFile self.ODdist = xtmf_ODdist self.NumberOfProcessors = cpu_count() '''self.ClassName = xtmf_ClassName self.IterationNumber = xtmf_IterationNumber''' self.demandMatrices = _util.DetermineAnalyzedTransitDemandId( EMME_VERSION, self.scenario) configPath = dirname(_MODELLER.desktop.project_file_name()) \ + "/Database/STRATS_s%s/config" %self.ScenarioNumber with open(configPath) as reader: config = _parsedict(reader.readline()) data = config['data'] if 'multi_class' in data: if data['multi_class'] == True: self.Multiclass = True else: self.Multiclass = False else: if data['type'] == "MULTICLASS_TRANSIT_ASSIGNMENT": self.Multiclass = True else: self.Multiclass = False '''if self.Multiclass == True: self.AnalyzedDemandMatrixID = demandMatrices[self.ClassName] else: self.AnalyzedDemandMatrixID = demandMatrices self.SelectedPaths = xtmf_SelectedPaths self.SelectPathsBy = xtmf_SelectPathsBy self.SelectedPathsCriteria = xtmf_SelectedPathsCriteria self.SelectedPathsThresholdLower = xtmf_SelectedPathsThresholdLower self.SelectedPathsThresholdUpper = xtmf_SelectedPathsThresholdUpper self.PathDetail = xtmf_PathsDetails.split(',') #self.PathsToOutput = self._VerifyNonNullWithError(self.PathDetail[0],"Paths to Output must be specfied") self.TotalImpedenceDetails = self._ConvertToBool(self.PathDetail[0]) self.AverageBoardingDetails = self._ConvertToBool(self.PathDetail[1]) self.DistanceDetails = self._ConvertToBool(self.PathDetail[2]) self.TimesAndCostsType = self._VerifyNonNullWithError(self.PathDetail[3],"Times and cost type must be defined") self.FirstWaitingTime = self._ConvertToBool(self.PathDetail[4]) self.TotalWaitingTime = self._ConvertToBool(self.PathDetail[5]) self.FirstBoardingTime = self._ConvertToBool(self.PathDetail[6]) self.TotalBoardingTime = self._ConvertToBool(self.PathDetail[7]) self.InVehicleTime = self._ConvertToBool(self.PathDetail[8]) self.AuxTransitTime = self._ConvertToBool(self.PathDetail[9]) self.FirstBoardingCost = self._ConvertToBool(self.PathDetail[10]) self.TotalBoardingCost = self._ConvertToBool(self.PathDetail[11]) self.InVehicleCost = self._ConvertToBool(self.PathDetail[12]) self.AuxTransitCost = self._ConvertToBool(self.PathDetail[13]) self.ZonesDetails = self._ConvertToBool(self.PathDetail[14]) self.PathNumberDetails =self._ConvertToBool(self.PathDetail[15]) self.ProportionDetails = self._ConvertToBool(self.PathDetail[16]) self.SelectedVolumeDetails = self._ConvertToBool(self.PathDetail[17]) self.VolumeDetails = self._ConvertToBool(self.PathDetail[18]) self.PathValueDetails = self._ConvertToBool(self.PathDetail[19]) self.PathItemDetails = self._ConvertToBool(self.PathDetail[20]) self.NodesDetails = self._ConvertToBool(self.PathDetail[21]) self.ModeDetails = self._ConvertToBool(self.PathDetail[22]) self.TransitLineDetails = self._ConvertToBool(self.PathDetail[23]) self.AuxTransitSubPathDetails = self._ConvertToBool(self.PathDetail[24]) self.SubPathDetails = self._ConvertToBool(self.PathDetail[25]) self.ODZoneDetails = self._ConvertToBool(self.PathDetail[26]) self.ODPathStatDetails = self._ConvertToBool(self.PathDetail[27]) self.ODPathNumberDetails = self._ConvertToBool(self.PathDetail[28]) self.ODSelectedDemandDetails = self._ConvertToBool(self.PathDetail[29]) self.ODDemandDetails = self._ConvertToBool(self.PathDetail[30]) self.ODAggPathValue = self._ConvertToBool(self.PathDetail[31]) self.ODDetails = self._ConvertToBool(self.PathDetail[32])''' try: self._Execute() except Exception, e: msg = str(e) + "\n" + _traceback.format_exc(e) raise Exception(msg)
class RotateNetwork(_m.Tool()): version = '0.1.0' tool_run_msg = "" number_of_tasks = 6 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) Scenario = _m.Attribute(_m.InstanceType) # common variable or parameter ReferenceLinkINode = _m.Attribute(int) ReferenceLinkJNode = _m.Attribute(int) CorrespondingX0 = _m.Attribute(float) CorrespondingX1 = _m.Attribute(float) CorrespondingY0 = _m.Attribute(float) CorrespondingY1 = _m.Attribute(float) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Rotate Network v%s" % self.version, description= "Rotates & translates network based on two corresponding links.\ Select the node ids of a link in the network you want to rotate and \ translate, and then enter in the coordinates of the exact same link \ in your reference network.\ <br><br>Warning: this tool makes irreversible changes to your scenario! \ make sure you copy before running.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) pb.add_text_box(tool_attribute_name='ReferenceLinkINode', size=7, title='Reference link i-node') pb.add_text_box(tool_attribute_name='ReferenceLinkJNode', size=7, title='Reference link j-node') with pb.add_table(visible_border=False, title="Corresponding vector") as t: with t.table_cell(): pb.add_html("Coordinate 0: ") with t.table_cell(): pb.add_html("X=") with t.table_cell(): pb.add_text_box(tool_attribute_name='CorrespondingX0', size=10) with t.table_cell(): pb.add_html("Y=") with t.table_cell(): pb.add_text_box(tool_attribute_name='CorrespondingY0', size=10) t.new_row() with t.table_cell(): pb.add_html("Coordinate 1: ") with t.table_cell(): pb.add_html("X=") with t.table_cell(): pb.add_text_box(tool_attribute_name='CorrespondingX1', size=10) with t.table_cell(): pb.add_html("Y=") with t.table_cell(): pb.add_text_box(tool_attribute_name='CorrespondingY1', size=10) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): network = self.Scenario.get_network() self.TRACKER.completeTask() anchorVecotr = ((self.CorrespondingX0, self.CorrespondingY0), (self.CorrespondingX1, self.CorrespondingY1)) refLink = self._GetRefLink(network) referenceVector = self._GetLinkVector(refLink) _m.logbook_write( "Found reference link '%s-%s'" % (self.ReferenceLinkINode, self.ReferenceLinkJNode)) angle = self._GetRotationAngle(anchorVecotr, referenceVector) # + math.pi / 2 _m.logbook_write("Rotation: %s degrees" % math.degrees(angle)) cosTheta = math.cos(angle) sinTheta = math.sin(angle) self.TRACKER.startProcess(network.element_totals['centroids'] + network.element_totals['regular_nodes']) for node in network.nodes(): self._RotateNode(node, cosTheta, sinTheta) self.TRACKER.completeSubtask() self.TRACKER.completeTask() _m.logbook_write("Finished rotating nodes.") self.TRACKER.startProcess(network.element_totals['links']) count = 0 for link in network.links(): if len(link.vertices) > 0: self._RotateLinkVertices(link, cosTheta, sinTheta) count += 1 self.TRACKER.completeSubtask() self.TRACKER.completeTask() _m.logbook_write("Rotated %s links with vertices." % count) referenceVector = self._GetLinkVector( refLink) # Reset the reference vector delta = self._GetTranslation(referenceVector, anchorVecotr) _m.logbook_write("Translation: %s" % str(delta)) self.TRACKER.startProcess(network.element_totals['centroids'] + network.element_totals['regular_nodes']) for node in network.nodes(): self._TranslateNode(node, delta) self.TRACKER.completeSubtask() self.TRACKER.completeTask() _m.logbook_write("Finished translating nodes.") self.TRACKER.startProcess(network.element_totals['links']) count = 0 for link in network.links(): if len(link.vertices) > 0: self._TranslateLink(link, delta) count += 1 self.TRACKER.completeSubtask() self.TRACKER.completeTask() _m.logbook_write("Translated %s links with vertices." % count) self.Scenario.publish_network(network, resolve_attributes=True) self.TRACKER.completeTask() ######################################################################################################### #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Scenario": str(self.Scenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _GetRefLink(self, network): link = network.link(self.ReferenceLinkINode, self.ReferenceLinkJNode) if link is None: raise Exception( "Reference link '%s-%s' does not exist in the network!" % (self.ReferenceLinkINode, self.ReferenceLinkJNode)) return link def _GetLinkVector(self, link): return ((link.i_node.x, link.i_node.y), (link.j_node.x, link.j_node.y)) def _GetVectorBearing(self, vector): return math.atan2(vector[1][0] - vector[0][0], vector[1][1] - vector[0][1]) def _GetRotationAngle(self, vector1, vector2): bearing1 = self._GetVectorBearing(vector1) bearing2 = self._GetVectorBearing(vector2) return bearing2 - bearing1 def _GetTranslation(self, vector1, vector2): return (vector2[0][0] - vector1[0][0], vector2[0][1] - vector1[0][1]) def _RotateNode(self, node, cosTheta, sinTheta): # Make copies of the coordinates x = node.x y = node.y node.x = (cosTheta * x) + (-sinTheta * y) node.y = (sinTheta * x) + (cosTheta * y) def _TranslateNode(self, node, delta): node.x += delta[0] node.y += delta[1] def _RotateLinkVertices(self, link, cosTheta, sinTheta): vertices = [link.vertices.pop() for i in range(0, len(link.vertices))] vertices.reverse() # Link's vertices have been removed and copied in-order to #this new list for vertex in vertices: tup = (cosTheta * vertex[0] - sinTheta * vertex[1], sinTheta * vertex[0] + cosTheta * vertex[1]) link.vertices.append(tup) def _TranslateLink(self, link, delta): vertices = [link.vertices.pop() for i in range(0, len(link.vertices))] vertices.reverse() # Link's vertices have been removed and copied in-order to #this new list for vertex in vertices: tup = (vertex[0] + delta[0], vertex[1] + delta[1]) link.vertices.append(tup) @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class ExtractTransitLineBoardings(_m.Tool()): version = '1.0.2' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here #---PARAMETERS xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only Scenario = _m.Attribute(_m.InstanceType) # common variable or parameter LineAggregationFile = _m.Attribute(str) ReportFile = _m.Attribute(str) WriteIndividualRoutesFlag = _m.Attribute(bool) ReportErrorsToLogbookFlag = _m.Attribute(bool) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario self.WriteIndividualRoutesFlag = True ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Export Boardings v%s" % self.version, description= "Extracts total boardings for each transit line and exports \ them in a CSV file. Optionally, lines can be aggregated using an \ external file (two-column CSV).", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) pb.add_select_file(tool_attribute_name='ReportFile', title="Report file", file_filter="*.csv", window_type='save_file') pb.add_header("AGGREGATION FILE") pb.add_select_file(tool_attribute_name='LineAggregationFile', title="Line aggregation file:", window_type='file', file_filter="*.csv", note="<font color='green'><b>Optional: \ </b></font>Aggregation file contains two columns with no headers, matching transit\ <br>line IDs to their aliases or groups in another data source (e.g., TTS line IDs). The\ <br>first column must be Emme transit line IDs. Any errors are skipped." ) pb.add_checkbox( tool_attribute_name='WriteIndividualRoutesFlag', label="Write individual routes?", note= "Write individual routes that are not found in the aggregation file. \ <br>This is the default behaviour if no aggregation file is specified." ) pb.add_checkbox( tool_attribute_name='ReportErrorsToLogbookFlag', label="Report errors to the Logbook?", note= "Write a report if there are lines referenced in the aggregation file but are not in the network." ) #---JAVASCRIPT pb.add_html(""" <script type="text/javascript"> $(document).ready( function () { var tool = new inro.modeller.util.Proxy(%s) ; if (tool.check_agg_file()) { $("#WriteIndividualRoutesFlag").prop('disabled', false); $("#ReportErrorsToLogbookFlag").prop('disabled', false); } else { $("#WriteIndividualRoutesFlag").prop('disabled', true); $("#ReportErrorsToLogbookFlag").prop('disabled', true); } $("#LineAggregationFile").bind('change', function() { $(this).commit(); $("#WriteIndividualRoutesFlag").prop('disabled', false); $("#ReportErrorsToLogbookFlag").prop('disabled', false); }); }); </script>""" % pb.tool_proxy_tag) return pb.render() def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg @_m.method(return_type=bool) def check_agg_file(self): return bool(self.LineAggregationFile) #--- #---XTMF INTERFACE METHODS def __call__(self, xtmf_ScenarioNumber, ReportFile, LineAggregationFile, WriteIndividualRoutesFlag): #---1 Set up scenario self.Scenario = _MODELLER.emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) self.ReportFile = ReportFile if LineAggregationFile: self.LineAggregationFile = LineAggregationFile self.ReportErrorsToLogbookFlag = False self.WriteIndividualRoutesFlag = WriteIndividualRoutesFlag try: self._Execute() except Exception as e: msg = str(e) + "\n" + _traceback.format_exc() raise Exception(msg) ########################################################################################################## #--- #---MAIN EXECUTION CODE def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): if not self.Scenario.has_transit_results: raise Exception("Scenario %s has no transit results" % self.Scenario) if self.LineAggregationFile: groupLines = self._LoadAggregationFile() else: groupLines = {} fileKeys, networkKeys = self._CheckAggregation(groupLines) self._ExportResults(fileKeys, networkKeys, groupLines) ########################################################################################################## #----Sub functions def _GetAtts(self): atts = { "Scenario": str(self.Scenario), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _LoadAggregationFile(self): with open(self.LineAggregationFile) as reader: groupLines = {} for line in reader: if line.isspace(): continue lineId, groupId = line.strip().split(',') if groupId in groupLines: groupLines[groupId].add(lineId) else: groupLines[groupId] = set([lineId]) return groupLines def _CheckAggregation(self, groupLines): fileLineIDs = set() for IDs in groupLines.itervalues(): for id in IDs: fileLineIDs.add(id) data = _util.fastLoadTransitLineAttributes(self.Scenario, ['headway']) networkLineIDs = set(data.keys()) linesMissingInNetwork = fileLineIDs - networkLineIDs linesNotInAggregationFile = networkLineIDs - fileLineIDs if self.ReportErrorsToLogbookFlag and len(linesMissingInNetwork) > 0: self._WriteErrorReport(linesMissingInNetwork) if self.WriteIndividualRoutesFlag: return list(groupLines.keys()), list(linesNotInAggregationFile) else: return list(groupLines.keys()), [] def _WriteErrorReport(self, linesMissingInNetwork): h = HTML() t = h.table() tr = t.tr() tr.th("Line ID") for id in linesMissingInNetwork: tr = t.tr() tr.td(str(id)) pb = _m.PageBuilder(title="Lines not in network report") pb.wrap_html("Lines references in file but not in network", body=str(t)) _m.logbook_write("Error report", value=pb.render()) def _ExportResults(self, fileKeys, networkKeys, groupLines): fileKeys.sort() networkKeys.sort() lineBoardings = _util.fastLoadSummedSegmentAttributes( self.Scenario, ['transit_boardings']) with open(self.ReportFile, 'w') as writer: writer.write("Line,Boardings") for key in fileKeys: boardings = 0.0 if key in groupLines: lineIDs = groupLines[key] for id in lineIDs: if not id in lineBoardings: continue boardings += lineBoardings[id]['transit_boardings'] writer.write("\n%s,%s" % (key, boardings)) for key in networkKeys: boardings = 0.0 if key in lineBoardings: boardings = lineBoardings[key]['transit_boardings'] writer.write("\n%s,%s" % (key, boardings))
class ExtractTransitMatrixResults(_m.Tool()): version = '1.0.0' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here #---PARAMETERS xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only scenario = _m.Attribute(_m.InstanceType) # common variable or parameter xtmf_ModeList = _m.Attribute(str) xtmf_MatrixNumbers = _m.Attribute(str) xtmf_AnalysisTypes = _m.Attribute(str) xtmf_ClassNames = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.scenario = _MODELLER.scenario #Default is primary scenario ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): pb = _m.ToolPageBuilder(self, title="Multi-Class Road Assignment", description="Cannot be called from Modeller.", runnable=False, branding_text="XTMF") return pb.render() def __call__(self, xtmf_ScenarioNumber, xtmf_ModeList, xtmf_MatrixNumbers, xtmf_AnalysisTypes, xtmf_ClassNames): # Set up scenario self.scenario = _MODELLER.emmebank.scenario(xtmf_ScenarioNumber) if (self.scenario is None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) #set up mode lists modes = xtmf_ModeList.strip(" ").split(",") self.ModeList = [] for i in range(0, len(modes)): self.ModeList.append([]) for mode in modes[i]: self.ModeList[i].append(mode) self.MatrixIDList = xtmf_MatrixNumbers.strip(" ").split(",") if len(self.ModeList) != len(self.MatrixIDList): raise Exception( "Each analysis must have mode(s) and matrices defined") self.AnalysisTypeList = [] types = xtmf_AnalysisTypes.strip(" ").split(",") for i in range(0, len(types)): if types[i].lower() == "distance": self.AnalysisTypeList.append(1) elif types[i].lower() == "actualtime": self.AnalysisTypeList.append(2) elif types[i].lower() == "actualcost": self.AnalysisTypeList.append(3) elif types[i].lower() == "perceivedtime": self.AnalysisTypeList.append(4) elif types[i].lower() == "perceivedcost": self.AnalysisTypeList.append(5) else: raise Exception("You must specify a proper analysis type") self.ClassNames = xtmf_ClassNames.strip(" ").split(",") names = _util.DetermineAnalyzedTransitDemandId(EMME_VERSION, self.scenario) if isinstance(names, dict): self.Multiclass = True for name in self.ClassNames: if name not in names.keys(): raise Exception("Class Name %s is not correct" % name) else: self.Multiclass = False try: self._Execute() except Exception as e: msg = str(e) + "\n" + _traceback.format_exc(e) raise Exception(msg) ########################################################################################################## #--- #---MAIN EXECUTION CODE def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): print "Extracting Transit Result Matrices" if not self.scenario.has_transit_results: raise Exception("Scenario %s has no transit results" % self.scenario) #initialize the matrices for matrix in self.MatrixIDList: _util.initializeMatrix(matrix) with self._getTempMatrices(): #Get Spec and do Analysis for i in range(0, len(self.ModeList)): spec = self._GetBaseSpec(self.ModeList[i], self.TempMatrices, self.AnalysisTypeList[i]) if self.Multiclass == True: report = self.TRACKER.runTool( matrixResultsTool, specification=spec, scenario=self.scenario, class_name=self.ClassNames[i]) else: report = self.TRACKER.runTool(matrixResultsTool, specification=spec, scenario=self.scenario) spec = { "type": "MATRIX_CALCULATION", "result": self.MatrixIDList[i], "expression": str(self.TempMatrices[0].id) + "+" + str(self.TempMatrices[1].id), "constraint": None } report = self.TRACKER.runTool(matrixCalcTool, specification=spec, scenario=self.scenario) print "Finished Extracting Transit Result Matrices" ########################################################################################################## #----Sub functions def _GetAtts(self): atts = { "Scenario": str(self.scenario), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _GetBaseSpec(self, modeList, matrix, analysisType): spec = { "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", "by_mode_subset": { "modes": modeList, "distance": None, "avg_boardings": None, "actual_total_boarding_times": None, "actual_in_vehicle_times": None, "actual_aux_transit_times": None, "actual_total_boarding_costs": None, "actual_in_vehicle_costs": None, "actual_aux_transit_costs": None, "perceived_total_boarding_times": None, "perceived_in_vehicle_times": None, "perceived_aux_transit_times": None, "perceived_total_boarding_costs": None, "perceived_in_vehicle_costs": None, "perceived_aux_transit_costs": None, } } if analysisType == 1: spec["by_mode_subset"]["distance"] = matrix[0].id if analysisType == 2: spec["by_mode_subset"]["actual_in_vehicle_times"] = matrix[0].id spec["by_mode_subset"]["actual_aux_transit_times"] = matrix[1].id if analysisType == 3: spec["by_mode_subset"]["actual_in_vehicle_costs"] = matrix[0].id spec["by_mode_subset"]["actual_aux_transit_costs"] = matrix[1].id if analysisType == 4: spec["by_mode_subset"]["perceived_in_vehicle_times"] = matrix[0].id spec["by_mode_subset"]["perceived_aux_transit_times"] = matrix[ 1].id if analysisType == 5: spec["by_mode_subset"]["perceived_in_vehicle_costs"] = matrix[0].id spec["by_mode_subset"]["perceived_aux_transit_costs"] = matrix[ 1].id return spec @contextmanager def _getTempMatrices(self): self.TempMatrices = [] created = {} for i in range(0, 2): matrixCreated = True mtx = _util.initializeMatrix(default=0.0, description= 'Temporary matrix for matrix results', \ matrix_type='FULL') self.TempMatrices.append(mtx) created[mtx.id] = matrixCreated try: yield self.TempMatrices finally: for key in created: if created[key] == True: _bank.delete_matrix(key)
class Volume_Extractor(_m.Tool()): BaseScenario = _m.Attribute(_m.InstanceType) SegmentAttribute = _m.Attribute(str) LinkAttribute = _m.Attribute(str) tool_run_msg = "" number_of_tasks = 4 def __init__(self): self.BaseScenario = _MODELLER.scenario #Default is primary scenario self.SegmentAttribute = "@cvolt" self.LinkAttribute = "@volut" self.TRACKER = _util.ProgressTracker(self.number_of_tasks) def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Transit Volume Extractor from a Hypernetwork", description= "Extracts the ca_voltr values from the Hypernetwork and assigns it to a Link Extra Attribute,\ This allows for the visualization of Transit Volumes in aggregate.\ <br><br><em> Requires storage space for two extra attributes. </em>", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_header("SCENARIO") pb.add_select_scenario(tool_attribute_name='BaseScenario', title='Scenario:', allow_none=False) pb.add_header("DEFINING ATTRIBUTES") keyval2 = [] keyval3 = [] keyval4 = [(-1, "None - Do not save segment base info")] for exatt in self.BaseScenario.extra_attributes(): if exatt.type == 'TRANSIT_SEGMENT': val = "%s - %s" % (exatt.name, exatt.description) keyval2.append((exatt.name, val)) elif exatt.type == 'LINK': val = "%s - %s" % (exatt.name, exatt.description) keyval3.append((exatt.name, val)) keyval4.append((exatt.name, val)) pb.add_select( tool_attribute_name='SegmentAttribute', keyvalues=keyval2, title="Segment Attribute Selector", note="Select a TRANSIT SEGMENT extra attribute in which to save \ Transit Volumes") pb.add_select(tool_attribute_name='LinkAttribute', keyvalues=keyval3, title="Link Attribute Selector", note="Select a LINK extra attribute in which \ to the Transit Segment Volumes.") return pb.render() def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception, e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.")
class ExportCountpostResults(_m.Tool()): version = '1.1.3' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only Scenario = _m.Attribute(_m.InstanceType) # common variable or parameter CountpostAttributeId = _m.Attribute(str) AlternateCountpostAttributeId = _m.Attribute(str) ExportFile = _m.Attribute(str) version = '1.1.2' def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker(self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario self.CountpostAttributeId = "@stn1" self.AlternateCountpostAttributeId = "@stn2" def page(self): pb = _tmgTPB.TmgToolPageBuilder(self, title="Export Countpost Results v%s" %self.version, description="Exports traffic assignment results on links flagged with \ a countpost number.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) keyval1 = [] keyval2 = [(-1, 'None - No attribute')] for att in _MODELLER.scenario.extra_attributes(): if att.type == 'LINK': text = "%s - %s" %(att.id, att.description) keyval1.append((att.id, text)) keyval2.append((att.id, text)) pb.add_select(tool_attribute_name='CountpostAttributeId', keyvalues=keyval1, title="Countpost Attribute", note="LINK attribute containing countpost id numbers") pb.add_select(tool_attribute_name='AlternateCountpostAttributeId', keyvalues=keyval2, title="Alternate Countpost Attribute", note="<font color='green'><b>Optional:</b></font> Alternate countpost attribute \ for multiple post per link") pb.add_select_file(tool_attribute_name='ExportFile', window_type='save_file', file_filter="*.csv", title="Export File") pb.add_html(""" <script type="text/javascript"> $(document).ready( function () { var tool = new inro.modeller.util.Proxy(%s) ; $("#Scenario").bind('change', function() { $(this).commit(); $("#CountpostAttributeId") .empty() .append(tool.preload_scenario_attributes()) inro.modeller.page.preload("#CountpostAttributeId"); $("#CountpostAttributeId").trigger('change'); $("#AlternateCountpostAttributeId") .empty() .append("<option value='-1'>None - No attribute</option>") .append(tool.preload_scenario_attributes()) inro.modeller.page.preload("#AlternateCountpostAttributeId"); $("#AlternateCountpostAttributeId").trigger('change'); }); }); </script>""" % pb.tool_proxy_tag) return pb.render() @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg @_m.method(return_type=unicode) def preload_scenario_attributes(self): list = [] for att in self.Scenario.extra_attributes(): label = "{id} - {name}".format(id=att.name, name=att.description) html = unicode('<option value="{id}">{text}</option>'.format(id=att.name, text=label)) list.append(html) return "\n".join(list) ########################################################################################################## def run(self): self.tool_run_msg = "" try: if not self.Scenario.has_traffic_results: raise Exception("Scenario %s has no traffic assignment results" %self.Scenario.number) if self.CountpostAttributeId is None: raise NullPointerException("Countpost Attribute not specified") if self.ExportFile is None: raise NullPointerException("Export File not specified") except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") def __call__(self, xtmf_ScenarioNumber, CountpostAttributeId, AlternateCountpostAttributeId, ExportFile): #---1 Set up scenario self.Scenario = _m.Modeller().emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario is None): raise Exception("Scenario %s was not found!" %xtmf_ScenarioNumber) if not self.Scenario.has_traffic_results: raise Exception("Scenario %s has no traffic assignment results" %self.Scenario.number) linkAtts = set([att.id for att in self.Scenario.extra_attributes() if att.type == 'LINK']) if not CountpostAttributeId in linkAtts: raise NullPointerException("'%s' is not a valid link attribute" %CountpostAttributeId) if AlternateCountpostAttributeId != "" and not AlternateCountpostAttributeId in linkAtts: raise NullPointerException("'%s' is not a valid link attribute" %AlternateCountpostAttributeId) self.CountpostAttributeId = CountpostAttributeId self.AlternateCountpostAttributeId = AlternateCountpostAttributeId self.ExportFile = ExportFile try: self._Execute() except Exception as e: msg = str(e) + "\n" + _traceback.format_exc() raise Exception(msg) ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format(classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): self.TRACKER.reset() linkResults = _util.fastLoadLinkAttributes(self.Scenario, [self.CountpostAttributeId, 'auto_volume', 'additional_volume', 'auto_time']) alternateLinkResults = {} if self.AlternateCountpostAttributeId and self.AlternateCountpostAttributeId != "": alternateLinkResults = _util.fastLoadLinkAttributes(self.Scenario, [self.AlternateCountpostAttributeId]) #Remove entries not flagged with a countpost self._CleanResults(linkResults, alternateLinkResults) #Get the countpost data, sorted lines = self._ProcessResults(linkResults, alternateLinkResults) #Write countpost data to file self._WriteReport(lines) ########################################################################################################## #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Scenario" : str(self.Scenario.id), "Countpost Attribute": self.CountpostAttributeId, "Alternate Countpost Attribute": self.AlternateCountpostAttributeId, "Export File": self.ExportFile, "Version": self.version, "self": self.__MODELLER_NAMESPACE__} return atts def _CleanResults(self, linkResults, alternateLinkResults): idsToRemove = [] for linkId, attributes in linkResults.iteritems(): post1 = attributes[self.CountpostAttributeId] post2 = 0 if linkId in alternateLinkResults: post2 = alternateLinkResults[linkId][self.AlternateCountpostAttributeId] if not post1 and not post2: idsToRemove.append(linkId) for key in idsToRemove: linkResults.pop(key) def _ProcessResults(self, linkResults, alternateLinkResults): lines = [] posts = 0 self.TRACKER.startProcess(len(linkResults)) for linkIdTuple, attributes in linkResults.iteritems(): linkId = "%s-%s" %linkIdTuple post1 = attributes[self.CountpostAttributeId] post2 = 0 if linkIdTuple in alternateLinkResults: post2 = alternateLinkResults[linkIdTuple][self.AlternateCountpostAttributeId] volau = attributes['auto_volume'] volad = attributes['additional_volume'] timau = attributes['auto_time'] data = [linkId, volau, volad, timau] if post1: lines.append((post1, linkId, volau, volad, timau)) posts += 1 if post2: lines.append((post2, linkId, volau, volad, timau)) posts += 1 self.TRACKER.completeSubtask() _m.logbook_write("Found %s countposts in network" %posts) lines.sort() return lines def _WriteReport(self, lines): with open(self.ExportFile, 'w') as writer: writer.write("Countpost,Link,Auto Volume,Additional Volume,Auto Time") for line in lines: line = [str(c) for c in line] writer.write("\n" + ','.join(line)) _m.logbook_write("Wrote report to %s" %self.ExportFile)
class CreateTimePeriodNetworks(_m.Tool()): version = '0.1.5' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here COLON = ':' COMMA = ',' # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) BaseScenario = _m.Attribute(_m.InstanceType) NewScenarioNumber = _m.Attribute(int) NewScenarioDescription = _m.Attribute(str) TransitServiceTableFile = _m.Attribute(str) AggTypeSelectionFile = _m.Attribute(str) AlternativeDataFile = _m.Attribute(str) TimePeriodStart = _m.Attribute(int) TimePeriodEnd = _m.Attribute(int) DefaultAgg = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.BaseScenario = _MODELLER.scenario #Default is primary scenario self.DefaultAgg = 'n' def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Create Time Period Network v%s" % self.version, description= "Creates a network for use in a given time period, from a \ 24-hour base network and corresponding transit service table. \ Line speeds and headways are calculated from the service table.\ Transit lines with no service in the time period are removed.\ Headway calculations are performed based on a choice of\ aggregation type. Agg type by line is loaded in from a file\ which can be generated using the Create Aggregation\ Selection File tool.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='BaseScenario', title='Base Scenario', allow_none=False) with pb.add_table(False) as t: with t.table_cell(): pb.add_new_scenario_select( tool_attribute_name='NewScenarioNumber', title="New scenario to create") with t.table_cell(): pb.add_text_box(tool_attribute_name='NewScenarioDescription', title="Description", size=40) pb.add_header("DATA FILES") pb.add_select_file(tool_attribute_name='TransitServiceTableFile', window_type='file', file_filter='*.csv', title="Transit service table", note="Requires three columns:\ <ul><li>emme_id</li>\ <li>trip_depart</li>\ <li>trip_arrive</li></ul>") pb.add_select_file(tool_attribute_name='AlternativeDataFile', window_type='file', file_filter='*.csv', title="Data for non-service table lines (optional)", note="Requires columns as follows,\ where xxxx corresponds to\ the desired time period start:\ <ul><li>emme_id</li>\ <li>xxxx_hdw</li>\ <li>xxxx_spd</li></ul>.\ Note: this will override\ values calculated from\ the service table") pb.add_select_file(tool_attribute_name='AggTypeSelectionFile', window_type='file', file_filter='*.csv', title="Aggregation Type Selection", note="Requires two columns:\ <ul><li>emme_id</li>\ <li>agg_type</li></ul>") pb.add_header("TOOL INPUTS") keyval1 = {'n': 'Naive', 'a': 'Average'} pb.add_radio_group(tool_attribute_name='DefaultAgg', keyvalues=keyval1, title="Default Aggregation Type", note="Used if line not in\ agg selection file") with pb.add_table(False) as t: with t.table_cell(): pb.add_text_box(tool_attribute_name='TimePeriodStart', size=4, title="Time period start", note="In integer hours e.g. 2:30 PM = 1430") with t.table_cell(): pb.add_text_box(tool_attribute_name='TimePeriodEnd', size=4, title="Time period end", note="In integer hours e.g. 2:30 PM = 1430") return pb.render() ########################################################################################################## # allows for the tool to be called from another tool def __call__(self, baseScen, newScenNum, newScenDescrip, serviceFile, aggFile, altFile, defAgg, start, end, additionalAltFiles): self.tool_run_msg = "" self.TRACKER.reset() self.BaseScenario = baseScen self.NewScenarioNumber = newScenNum self.NewScenarioDescription = newScenDescrip self.TransitServiceTableFile = serviceFile self.AggTypeSelectionFile = aggFile self.AlternativeDataFile = altFile # Process the additional files, if it is the string None then there are no additional files otherwise they are ; separated if additionalAltFiles is None or additionalAltFiles == "None": self.InputFiles = [] else: self.InputFiles = additionalAltFiles.split(';', 1) # Add the base transaction file to the beginning if altFile: self.InputFiles.insert(0, altFile) self.DefaultAgg = defAgg self.TimePeriodStart = start self.TimePeriodEnd = end try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() if self.AlternativeDataFile is None: self.InputFiles = [] else: self.InputFiles = [self.AlternativeDataFile] try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc()) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") ########################################################################################################## def _Execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._GetAtts()): network = self.BaseScenario.get_network() self.TRACKER.completeTask() print("Loaded network") start = self._ParseIntTime(self.TimePeriodStart) end = self._ParseIntTime(self.TimePeriodEnd) badIdSet = self._LoadServiceTable(network, start, end).union( self._LoadAggTypeSelect(network)) self.TRACKER.completeTask() print("Loaded service table") if len(badIdSet) > 0: print( "%s transit line IDs were not found in the network and were skipped." % len(badIdSet)) pb = _m.PageBuilder("Transit line IDs not in network") pb.add_text_element( "<b>The following line IDs were not found in the network:</b>" ) for id in badIdSet: pb.add_text_element(id) _m.logbook_write( "Some IDs were not found in the network. Click for details.", value=pb.render()) if len(self.InputFiles) <= 0: self._ProcessTransitLines(network, start, end, None) else: if self.AlternativeDataFile: altData = self._LoadAltFile(self.InputFiles) else: altData = None self._ProcessTransitLines(network, start, end, altData) if altData: self._ProcessAltLines(network, altData) print("Done processing transit lines") newScenario = _MODELLER.emmebank.copy_scenario( self.BaseScenario.id, self.NewScenarioNumber) newScenario.title = self.NewScenarioDescription print("Publishing network") network.delete_attribute('TRANSIT_LINE', 'trips') network.delete_attribute('TRANSIT_LINE', 'aggtype') newScenario.publish_network(network) ########################################################################################################## #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _GetAtts(self): atts = { "Scenario": str(self.BaseScenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _ParseIntTime(self, i): try: hours = i / 100 minutes = i % 100 return hours * 3600.0 + minutes * 60.0 except Exception as e: raise IOError("Error parsing time %s: %s" % (i, e)) def _ParseStringTime(self, s): try: hms = s.split(self.COLON) if len(hms) != 3: raise IOError() hours = int(hms[0]) minutes = int(hms[1]) seconds = int(hms[2]) return hours * 3600.0 + minutes * 60.0 + float(seconds) except Exception as e: raise IOError("Error parsing time %s: %s" % (s, e)) def _ParseAggType(self, a): choiceSet = ('n', 'a') try: agg = a[0].lower() if agg not in choiceSet: raise IOError() else: return agg except Exception as e: raise IOError( "You must select either naive or average as an aggregation type %s: %s" % (a, e)) def _LoadServiceTable(self, network, start, end): network.create_attribute('TRANSIT_LINE', 'trips', None) bounds = _util.FloatRange(start, end) badIds = set() if self.TransitServiceTableFile: with open(self.TransitServiceTableFile) as reader: header = reader.readline() cells = header.strip().split(self.COMMA) emmeIdCol = cells.index('emme_id') departureCol = cells.index('trip_depart') arrivalCol = cells.index('trip_arrive') for num, line in enumerate(reader): cells = line.strip().split(self.COMMA) id = cells[emmeIdCol] transitLine = network.transit_line(id) if transitLine is None: badIds.add(id) continue #Skip and report try: departure = self._ParseStringTime(cells[departureCol]) arrival = self._ParseStringTime(cells[arrivalCol]) except Exception as e: print("Line " + str(num) + " skipped: " + str(e)) continue if not departure in bounds: continue #Skip departures not in the time period trip = (departure, arrival) if transitLine.trips is None: transitLine.trips = [trip] else: transitLine.trips.append(trip) return badIds def _LoadAggTypeSelect(self, network): network.create_attribute('TRANSIT_LINE', 'aggtype', None) badIds = set() if self.AggTypeSelectionFile: with open(self.AggTypeSelectionFile) as reader: header = reader.readline() cells = header.strip().split(self.COMMA) emmeIdCol = cells.index('emme_id') aggCol = cells.index('agg_type') for num, line in enumerate(reader): cells = line.strip().split(self.COMMA) id = cells[emmeIdCol] transitLine = network.transit_line(id) if transitLine is None: badIds.add(id) continue #Skip and report try: aggregation = self._ParseAggType(cells[aggCol]) except Exception as e: print("Line " + num + " skipped: " + str(e)) continue if transitLine.aggtype is None: transitLine.aggtype = aggregation return badIds def _LoadAltFile(self, fileNames): altData = {} for fileName in fileNames: with open(fileName) as reader: header = reader.readline() cells = header.strip().split(self.COMMA) emmeIdCol = cells.index('emme_id') headwayTitle = "{:0>4.0f}".format( self.TimePeriodStart) + '_hdw' speedTitle = "{:0>4.0f}".format(self.TimePeriodStart) + '_spd' try: headwayCol = cells.index(headwayTitle) except Exception as e: msg = "Error. No headway match for specified time period start: '%s'." % self._ParseIntTime( self.TimePeriodStart) _m.logbook_write(msg) print(msg) try: speedCol = cells.index(speedTitle) except Exception as e: msg = "Error. No speed match for specified time period start: '%s'." % self._ParseIntTime( self.TimePeriodStart) _m.logbook_write(msg) print(msg) localAltData = {} for num, line in enumerate(reader): cells = line.strip().split(self.COMMA) id = cells[emmeIdCol] hdw = cells[headwayCol] spd = cells[speedCol] if id not in localAltData: localAltData[id] = (float(hdw), float(spd)) else: raise ValueError( 'Line %s has multiple entries. Please revise your alt file.' % id) #now that the file has been loaded in move it into the combined altFile dictionary for id, data in six.iteritems(localAltData): altData[id] = data return altData def _ProcessTransitLines(self, network, start, end, altData): bounds = _util.FloatRange(0.01, 1000.0) toDelete = set() if altData is not None: for k, v in altData.items( ): #check if any headways or speeds are zero. Allow those lines to be deletable if v[0] == 0 or v[1] == 0: del altData[k] #if v[0] == 9999: #prep an unused line for deletion # toDelete.add(k) doNotDelete = altData.keys() else: doNotDelete = [] self.TRACKER.startProcess(network.element_totals['transit_lines']) for line in network.transit_lines(): #Pick aggregation type for given line if line.aggtype == 'n': aggregator = naiveAggregation elif line.aggtype == 'a': aggregator = averageAggregation elif self.DefaultAgg == 'n': aggregator = naiveAggregation _m.logbook_write("Default aggregation was used for line %s" % (line.id)) else: aggregator = averageAggregation _m.logbook_write("Default aggregation was used for line %s" % (line.id)) if not line.trips: #Line trips list is empty or None if doNotDelete: if line.id not in doNotDelete: #don't delete lines whose headways we wish to manually set toDelete.add(line.id) elif line.id not in toDelete: toDelete.add(line.id) self.TRACKER.completeSubtask() continue #Calc line headway departures = [dep for dep, arr in line.trips] departures.sort() headway = aggregator(departures, start, end) / 60.0 #Convert from seconds to minutes if not headway in bounds: print("%s: %s" % (line.id, headway)) line.headway = headway #Calc line speed sumTimes = 0 for dep, arr in line.trips: sumTimes += arr - dep avgTime = sumTimes / len( line.trips) / 3600.0 #Convert from seconds to hours length = sum([seg.link.length for seg in line.segments()]) #Given in km speed = length / avgTime #km/hr if not speed in bounds: print("%s: %s" % (line.id, speed)) line.speed = speed self.TRACKER.completeSubtask() for id in toDelete: network.delete_transit_line(id) self.TRACKER.completeTask() def _ProcessAltLines(self, network, altData): bounds = _util.FloatRange(0.01, 1000.0) for key, data in six.iteritems(altData): line = network.transit_line(key) if line: if data[0] == 9999: #a headway of 9999 indicates an unused line network.delete_transit_line(line.id) continue elif data[ 0] == 0: #a headway of 0 allows for a line to be in the alt data file without changing existing headway print("%s: %s" % (line.id, data[0])) _m.logbook_write( "Headway = 0 in alt file. Headway remains as in base. %s" % line.id) elif not data[0] in bounds: print("%s: %s" % (line.id, data[0])) _m.logbook_write( "Headway out of bounds line %s: %s minutes. Line removed from network." % (line.id, data[0])) network.delete_transit_line(line.id) continue line.headway = data[0] if not data[1] in bounds: print("%s: %s" % (line.id, data[1])) _m.logbook_write( "Speed out of bounds line %s: %s km/h. Speed remains as in base." % (line.id, data[1])) continue line.speed = data[1] @_m.method(return_type=_m.TupleType) def percent_completed(self): return self.TRACKER.getProgress() @_m.method(return_type=six.u) def tool_run_msg_status(self): return self.tool_run_msg
class ExportGtfsStopsAsShapefile(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here # Tool Input Parameters # Only those parameters neccessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get intitialized during construction (__init__) GtfsFolderName = _m.Attribute(str) ShapefileName = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="Export GTFS Stops As Shapefile v%s" % self.version, description= "Converts the <b>stops.txt</b> file to a shapefile, flagging which \ modes it serves as well.", branding_text="- TMG Toolbox 2") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_file(tool_attribute_name="GtfsFolderName", window_type='directory', title="GTFS Folder Directory") pb.add_select_file(tool_attribute_name="ShapefileName", window_type='save_file', title="Shapefile Name for Export") return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Tool is completed.") ########################################################################################################## def run_xtmf(self, parameters): self.GtfsFolderName = parameters['gtfs_folder'] self.ShapefileName = parameters['shapefile_name'] try: self._Execute() except Exception, e: raise Exception(_traceback.format_exc(e))
class FlagPremiumBusLines(_m.Tool()): version = '0.1.0' tool_run_msg = "" #---Variable definitions ScenarioNumber = _m.Attribute(int) FlagGO = _m.Attribute(bool) FlagPremTTC = _m.Attribute(bool) FlagVIVA = _m.Attribute(bool) FlagZum = _m.Attribute(bool) #---Special instance types, used only from Modeller scenario = _m.Attribute(_m.InstanceType) def __init__(self): self.counter = 0 def page(self): pb = _m.ToolPageBuilder( self, title="Flag Premium Bus Lines", description= "Flags certain premium lines by assigning '1' to line extra attribute '@lflag'. Initializes \ @lflag to 0 first.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='scenario', title='Scenario:', allow_none=False) pb.add_checkbox(tool_attribute_name='FlagGO', title="Flag GO Bus lines?") pb.add_checkbox(tool_attribute_name='FlagPremTTC', title="Flag Premium TTC bus lines?") pb.add_checkbox(tool_attribute_name='FlagVIVA', title="Flag VIVA bus lines?", note="Assumes NCS11 line ids.") pb.add_checkbox(tool_attribute_name='FlagZum', title="Flag ZUM bus lines?", note="CURRENTLY UNSUPPORTED.") return pb.render() def run(self): '''Run is called from Modeller.''' self.tool_run_msg = "" self.isRunningFromXTMF = False # Run the tool try: self._execute() except Exception, e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info( "Tool completed. %s lines were flagged." % self.counter)
class ConvertVehicles(_m.Tool()): version = '0.1.2' tool_run_msg = "" #---Variable definitions ScenarioNumber = _m.Attribute(int) #---Special instance types scenario = _m.Attribute(_m.InstanceType) # def page(self): pb = _m.ToolPageBuilder( self, title="Convert Vehicles v%s" % self.version, description="Converts vehicle definitions and properties \ according to NCS11 definitions.", branding_text="- TMG Toolbox") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name="scenario", title="Select scenario", allow_none=False) return pb.render() ########################################################################################################## def run(self): self.tool_run_msg = "" '''Run is called from Modeller.''' self.isRunningFromXTMF = False try: self._execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Run complete.") ########################################################################################################## def _execute(self): with _m.logbook_trace(name="{classname} v{version}".format( classname=(self.__class__.__name__), version=self.version), attributes=self._getAtts()): network = self.scenario.get_network() self._prepVehicleLineMap(network) #---Create new vehicle ids with _m.logbook_trace("Adding vehicle 19"): v19 = network.create_transit_vehicle(19, 'g') # Unused. self._changeVehicleProperties(v19, "DblDeckBus", 2.5, 80, 80) with _m.logbook_trace("Adding vehicle 18"): v18 = network.create_transit_vehicle(18, 'g') self._replaceVehicle(network.transit_vehicle(10), v18) #Copy old V10 self._changeVehicleProperties(v18, "GoBus", 2.5, 55, 55) with _m.logbook_trace("Adding vehicle 17"): v17 = network.create_transit_vehicle(17, 'q') # Reserved. self._changeVehicleProperties(v17, description="BRT") with _m.logbook_trace("Adding vehicle 16"): v16 = network.create_transit_vehicle(16, 'b') #Copy old V7 self._replaceVehicle(network.transit_vehicle(7), v16) self._changeVehicleProperties(v16, "Bus18", aeq=3.0, scap=55, tcap=85) with _m.logbook_trace("Adding vehicle 15"): v15 = network.create_transit_vehicle( 15, 'b') # Maybe this should be 'q'? self._changeVehicleProperties(v15, "Deluxe18", 3.0, 70, 70) with _m.logbook_trace("Adding vehicle 14"): v14 = network.create_transit_vehicle( 14, 'b') # Maybe this should be 'q'? self._changeVehicleProperties(v14, "Deluxe12", 2.5, 45, 45) with _m.logbook_trace("Adding vehicle 13"): v13 = network.create_transit_vehicle(13, 'b') # Copy old V8 self._replaceVehicle(network.transit_vehicle(8), v13) self._changeVehicleProperties(v13, "Bus12", 2.5, 35, 55) with _m.logbook_trace("Adding vehicle 12"): v12 = network.create_transit_vehicle(12, 'b') self._replaceVehicle(network.transit_vehicle(9), v12) # Copy old V9 self._changeVehicleProperties(v12, "Bus9", 2.5, 25, 40) with _m.logbook_trace("Adding vehicle 11"): v11 = network.create_transit_vehicle( 11, 's') # Unused (new TTC SC) self._changeVehicleProperties(v11, "LFLRV30", 3.5, 70, 130) #---Move old vehicle ids with _m.logbook_trace("Modifying vehicle 10"): v10 = network.transit_vehicle(10) self._changeVehicleMode(network, v10, 's') self._replaceVehicle(network.transit_vehicle(6), v10) # Copy old V6 self._changeVehicleProperties(v10, "ALRV23", 3.5, 60, 110) with _m.logbook_trace("Modifying vehicle 9"): v9 = network.transit_vehicle(9) self._changeVehicleMode(network, v9, 's') self._replaceVehicle(network.transit_vehicle(5), v9) # Copy old V5 self._changeVehicleProperties(v9, "CLRV16", 3.0, 45, 75) with _m.logbook_trace("Modifying vehicle 8"): v8 = network.transit_vehicle(8) self._changeVehicleMode( network, v8, 'l') # Reserved (Eglinton Crosstown LRT) self._changeVehicleProperties(v8, "LRV") with _m.logbook_trace("Modifying vehicle 7"): v7 = network.transit_vehicle(7) self._changeVehicleMode(network, v7, 'l') self._replaceVehicle(network.transit_vehicle(4), v7) # Copy old V4 self._changeVehicleProperties(v7, "SCxROW", scap=45, tcap=75) with _m.logbook_trace("Modifying vehicle 6"): v6 = network.transit_vehicle(6) self._changeVehicleMode(network, v6, 'm') # Unused (new subway Rocket cars) self._changeVehicleProperties(v6, "Sub6carRkt", scap=400, tcap=1100) with _m.logbook_trace("Modifying vehicle 5"): v5 = network.transit_vehicle(5) self._changeVehicleMode(network, v5, 'm') self._replaceVehicle(network.transit_vehicle(2), v5) # Copy old V2 self._changeVehicleProperties(v5, "Sub6carT1", scap=400, tcap=1000) ''' TODO: - Hard code the re-coding of Sheppard subway ''' with _m.logbook_trace("Modifying vehicle 4"): v4 = network.transit_vehicle(4) self._changeVehicleMode(network, v4, 'm') self._changeVehicleProperties(v4, "Sub4carT1", scap=260, tcap=670) with _m.logbook_trace("Modifying vehicle 3"): v3 = network.transit_vehicle(3) self._changeVehicleProperties(v3, "SRT4car", scap=120, tcap=220) with _m.logbook_trace("Modifying vehicle 2"): v2 = network.transit_vehicle(2) self._changeVehicleMode(network, v2, 'r') self._changeVehicleProperties(v2, "GoTrain12", scap=1900, tcap=1900) with _m.logbook_trace("Modifying vehicle 1"): #v1 remains unchanged. v1 = network.transit_vehicle(1) self._changeVehicleProperties(v1, "GoTrain10", scap=1600, tcap=1900) self.scenario.publish_network(network) ########################################################################################################## #----SUB FUNCTIONS--------------------------------------------------------------------------------- def _getAtts(self): atts = { "Scenario": str(self.scenario.id), "Version": self.version, "self": self.__MODELLER_NAMESPACE__ } return atts def _prepVehicleLineMap(self, network): self.vm = {} # Set up vehicle map for line in network.transit_lines(): try: self.vm[line.vehicle].append(line) except KeyError: self.vm[line.vehicle] = [line] def _checkFixScenario(self, network): vehiclesToBeDeleted = [] for veh in network.transit_vehicles(): if self.veh.number <= 10: continue if self.veh in self.vm: raise Exception( "A vehicle id not compliant with DMG2001 was used in \ the network and cannot be removed as it is being used by %s transit \ line(s)." % len(self.vm[veh])) vehiclesToBeDeleted.append(veh.number) for id in vehiclesToBeDeleted: network.delete_transit_vehicle(id) _m.logbook_write("Deleted unused vehicle %s" % id) def _replaceVehicle(self, oldVehicle, newVehicle): if not oldVehicle in self.vm: return for line in self.vm[oldVehicle]: line.vehicle = newVehicle _m.logbook_write("Changed {0} line(s) with vehicle \ {1} to use {2}.".format(len(self.vm[oldVehicle]), oldVehicle.number, newVehicle.number)) def _changeVehicleProperties(self, vehicle, description="", aeq=0.0, scap=0, tcap=0): if description != "" and description is not None: vehicle.description = description _m.logbook_write("Description = '%s'" % description) if aeq != 0.0: vehicle.auto_equivalent = aeq _m.logbook_write("Auto equivalence = %s" % aeq) if scap != 0: vehicle.seated_capacity = scap _m.logbook_write("Seated capacity = %s" % scap) if tcap < scap: tcap = scap if tcap != 0: vehicle.total_capacity = tcap _m.logbook_write("Total capacity = %s" % tcap) def _changeVehicleMode(self, network, vehicle, modeChar): oldMode = vehicle.mode.id vehicle._mode = network.mode(modeChar) _m.logbook_write("Changed mode of vehicle {0} \ from {1} to {2}.".format(vehicle.id, oldMode, modeChar)) @_m.method(return_type=unicode) def tool_run_msg_status(self): return self.tool_run_msg
class GTFStoEmmeMap(_m.Tool()): version = '0.0.2' tool_run_msg = "" number_of_tasks = 1 #Tool Parameters FileName = _m.Attribute(str) MappingFileName = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker def page(self): pb = _tmgTPB.TmgToolPageBuilder( self, title="GTFS Stops to Emme Node File v%s" % self.version, description= "Takes the <b>stops.txt</b> file or a <b>shapefile</b> to create a mapping file that shows \ the node in the EMME network which it corresponds to.", branding_text="- TMG Toolbox 2") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_file( tool_attribute_name="FileName", window_type='file', file_filter="*.txt *.shp", title= "stops.txt file from the GTFS folder or stops file in *.shp format" ) pb.add_select_file(tool_attribute_name="MappingFileName", window_type='save_file', file_filter='*.csv', title="Map file to export") return pb.render() def __call__(self, StopFileName, MappingFileName): self.FileName = StopFileName self.MappingFileName = MappingFileName self.scenarioNumber = ScenarioNumber self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.") def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception as e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done") ########################################################################################################## def run_xtmf(self, parameters): self.FileName = parameters['input_stop_file'] self.MappingFileName = parameters['output_mapping_file'] try: self._Execute() except Exception, e: raise Exception(_traceback.format_exc(e))
class ApplyBatchLineEdits(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here COLON = ':' COMMA = ',' # Tool Input Parameters # Only those parameters necessary for Modeller and/or XTMF to dock with # need to be placed here. Internal parameters (such as lists and dicts) # get initialized during construction (__init__) xtmf_ScenarioNumber = _m.Attribute(int) # parameter used by XTMF only InstructionFile = _m.Attribute( str) # file should have the following header: # filter|x_hdwchange|x_spdchange # where filter is a network calculator filter expression # x refers to the scenario number # the x columns can be multiple (ie. multiple definitions # in a single file) # hdwchange and spdchange are factors by which # to change headways and speeds for the filtered # lines additionalInputFiles = _m.Attribute( str ) #Either a string containing 'None' or a list of additional alt files ; separated. def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario def page(self): pb = _m.ToolPageBuilder(self, title="Apply Batch Line Edits", description="Cannot be called from Modeller.", runnable=False, branding_text="XTMF") return pb.render() ########################################################################################################## def __call__(self, xtmf_ScenarioNumber, inputFile, additionalInputFiles=None): #---1 Set up scenario self.Scenario = _m.Modeller().emmebank.scenario(xtmf_ScenarioNumber) if (self.Scenario == None): raise Exception("Scenario %s was not found!" % xtmf_ScenarioNumber) #---2 Set up instruction file self.InstructionFile = inputFile if (self.InstructionFile == None): raise Exception("Need to provide an input file.") # Process the additional files, if it is the string None then there are no additional files otherwise they are ; separated if additionalInputFiles == None or additionalInputFiles == "None": self.InputFiles = [] else: self.InputFiles = additionalInputFiles.split(';') # Add the base transaction file to the beginning self.InputFiles.insert(0, self.InstructionFile) try: self._Execute() except Exception, e: msg = str(e) + "\n" + _traceback.format_exc(e) raise Exception(msg)
class ExtractGoInVehicleTime(_m.Tool()): version = '0.0.1' tool_run_msg = "" number_of_tasks = 1 # For progress reporting, enter the integer number of tasks here #---PARAMETERS xtmf_ScenarioNumber = _m.Attribute(int) Scenario = _m.Attribute(_m.InstanceType) ResultMatrixId = _m.Attribute(str) def __init__(self): #---Init internal variables self.TRACKER = _util.ProgressTracker( self.number_of_tasks) #init the ProgressTracker #---Set the defaults of parameters used by Modeller self.Scenario = _MODELLER.scenario #Default is primary scenario ########################################################################################################## #--- #---MODELLER INTERACE METHODS def page(self): pb = _tmgTPB.TmgToolPageBuilder(self, title="[TOOL NAME] v%s" % self.version, description="[DESCRIPTION]", branding_text="TMG") if self.tool_run_msg != "": # to display messages in the page pb.tool_run_status(self.tool_run_msg_status) pb.add_select_scenario(tool_attribute_name='Scenario', title='Scenario:', allow_none=False) ''' def add_select_output_matrix(self, tool_attribute_name, matrix_types= ['FULL'], title= "", note= "", include_none= True, include_next= True, include_existing= False, include_new= False): ''' pb.add_select_output_matrix(tool_attribute_name='ResultMatrixId', include_none=False, include_existing=True, include_new=True, title="Result Matrix") return pb.render() def run(self): self.tool_run_msg = "" self.TRACKER.reset() try: self._Execute() except Exception, e: self.tool_run_msg = _m.PageBuilder.format_exception( e, _traceback.format_exc(e)) raise self.tool_run_msg = _m.PageBuilder.format_info("Done.")
class AttachCentriodsToNodes(_m.Tool()): version = '0.0.1' ScenarioNumber = _m.Attribute(int) Centroids = _m.Attribute(str) Nodes = _m.Attribute(str) def page(self): pb = _m.ToolPageBuilder(self, title="Attach Centroids To Nodes", runnable=False, description="Cannot be called from Modeller.", branding_text="XTMF") return pb.render() def run(self): pass def __call__(self, ScenarioNumber, Nodes, Centroids): try: self._execute(ScenarioNumber, Nodes, Centroids) except Exception as e: raise Exception(_traceback.format_exc(e)) def _execute(self, ScenarioNumber, Nodes, Centroids): nodesToAttachTo = Nodes.split(";") centroidNumbers = Centroids.split(";") project = _MODELLER.emmebank scenario = project.scenario(str(ScenarioNumber)) network = scenario.get_network() #TODO: Un-hardcode this to read in the modes from XTMF linkType = 1 linkSpeed = 40 lanes = 2.0 centroidSet = set([network.mode('c'), network.mode('h'), network.mode('i'), network.mode('f'), network.mode('e'), network.mode('d'), network.mode('v')]) for i in range(len(nodesToAttachTo)): nodeToAttachTo = self._get_node(network, nodesToAttachTo[i]) if nodeToAttachTo is None: raise Exception("Unable to find a node with the ID " + nodesToAttachTo[i]) #check to see if the centroid already exists centroidNode = self._get_node(network, centroidNumbers[i]) if centroidNode is not None: network.delete_node(centroidNode.id, True) centroidNode = network.create_centroid(centroidNumbers[i]) centroidNode.x = nodeToAttachTo.x centroidNode.y = nodeToAttachTo.y linkTo = network.create_link(centroidNumbers[i], nodesToAttachTo[i], centroidSet) linkFrom = network.create_link(nodesToAttachTo[i], centroidNumbers[i], centroidSet) linkTo.length = 0.0 linkFrom.length = 0.0 linkTo.type = linkType linkTo.num_lanes = lanes linkTo.data2 = linkSpeed linkTo.data3 = 9999 linkFrom.type = linkType linkFrom.num_lanes = lanes linkFrom.data2 = linkSpeed linkFrom.data3 = 9999 scenario.publish_network(network) def _get_node(self, network, nodeString): return network.node(nodeString)