Highway Network Processing Pipeline ¶
This document describes the complete flow of highway network data through tm2py, including scenario IDs, emmebank locations, and attribute transformations at each step.
Overview Diagram ¶
┌─────────────────────────────────────────────────────────────────────────────────┐
│ INPUT (Base Network) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ Emmebank: Database_highway/emmebank │
│ Scenario ID: 1 (all_day_scenario_id from config) │
│ Title: "Base Network" or similar │
│ │
│ LINK ATTRIBUTES (period-specific, lowercase suffix): │
│ @lanes_ea, @lanes_am, @lanes_md, @lanes_pm, @lanes_ev │
│ @useclass_ea, @useclass_am, @useclass_md, @useclass_pm, @useclass_ev │
│ @ft (facility type: 1-8, 99) │
│ @free_flow_speed (may be 0, set later from capclass lookup) │
│ @tollbooth, @tollseg (toll facility coding, optional) │
│ @drive_link (1=driveable, 0=walk/bike only) │
│ @bike_link, @bus_only │
│ #link_county (county ID) │
│ │
│ STANDARD ATTRIBUTES: │
│ num_lanes (EMME standard, may be 0 in some networks) │
│ length (link length in miles) │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ STEP 1: create_tod_scenarios │
│ Component: CreateTODScenarios │
├─────────────────────────────────────────────────────────────────────────────────┤
│ 1a. _create_highway_scenarios() │
│ - Creates/ensures these attributes exist on ref scenario: │
│ @area_type, @capclass, @free_flow_speed, @free_flow_time, @lanes │
│ - If @lanes is all zeros, copies from num_lanes (legacy network fix) │
│ - Calls _set_area_type(): calculates @area_type from MAZ density │
│ - Calls _set_capclass(): @capclass = 10*@area_type + @ft │
│ - Calls _set_speed(): @free_flow_speed from capclass_lookup table │
│ @free_flow_time = 60 * length / speed │
│ │
│ 1b. _prepare_scenarios_and_attributes() │
│ - Copies Scenario 1 → Scenario 11, 12, 13, 14, 15 (per time period) │
│ - For each period scenario: │
│ • Copies @lanes_am → @lanes (case-insensitive matching) │
│ • Copies @useclass_am → @useclass │
│ • Deletes other period suffixes (@lanes_ea, @lanes_pm, etc.) │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ INTERMEDIATE STATE (After create_tod_scenarios) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ Emmebank: Database_highway/emmebank │
│ │
│ Scenario 1 (Reference, unchanged): │
│ Still has @lanes_am, @lanes_pm, etc. │
│ │
│ Scenario 11 (EA), 12 (AM), 13 (MD), 14 (PM), 15 (EV): │
│ @lanes ← copied from @lanes_{period} │
│ @useclass ← copied from @useclass_{period} │
│ @area_type ← calculated from MAZ density (1=CBD to 5=rural) │
│ @capclass ← 10*area_type + ft (e.g., 34 = suburban arterial) │
│ @free_flow_speed ← from capclass lookup table │
│ @free_flow_time ← 60 * length / speed │
│ @ft ← unchanged from base │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ STEP 2: prepare_network_highway │
│ Component: PrepareHighwayNetwork │
├─────────────────────────────────────────────────────────────────────────────────┤
│ For each time period scenario (11, 12, 13, 14, 15): │
│ │
│ 2a. _set_tolls() - from inputs/hwy/tolls.csv │
│ @toll_{class} ← toll cost by vehicle class (da, s2, s3, vsm, etc.) │
│ @bridgetoll_{class} │
│ @valuetoll_{class} │
│ │
│ 2b. _set_vdfs() - Volume Delay Functions │
│ Sets emmebank.extra_function_parameters: │
│ el1 = @free_flow_time │
│ el2 = @capacity │
│ el3 = @ja (Akcelik parameter) │
│ el4 = @static_rel (reliability factor) │
│ │
│ 2c. _set_capacity_speed_vdf() │
│ @capacity = cap_lanehour * highway_capacity_factor * @lanes │
│ @ja ← Akcelik parameter for VDF types 3,4,5,7,8,10-14 │
│ link.volume_delay_func = @ft (VDF number 1-8) │
│ link.num_lanes = max(min(9.9, @lanes), 1.0) │
│ │
│ 2d. _set_link_modes() │
│ Sets allowed modes on each link based on @useclass: │
│ d=drive, h=HOV2, i=HOV3, H=HOV2toll, I=HOV3toll, etc. │
│ │
│ 2e. _set_link_costs() │
│ @cost_{class} = @free_flow_time + VOT_factor * @toll_{class} │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ OUTPUT STATE (Ready for Assignment) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ Emmebank: Database_highway/emmebank │
│ │
│ Scenario 11 (EA), 12 (AM), 13 (MD), 14 (PM), 15 (EV): │
│ │
│ LINK ATTRIBUTES FOR ASSIGNMENT: │
│ @lanes Number of lanes for this period │
│ @capacity Hourly capacity (lanes × cap/lane × period_factor) │
│ @free_flow_time Minutes at free-flow speed │
│ @free_flow_speed Speed in mph │
│ @useclass HOV/toll restriction class │
│ @ft Facility type (VDF selector) │
│ @capclass Capacity class (area_type*10 + ft) │
│ @area_type 1=CBD, 2=urban business, 3=urban, 4=suburban, 5=rural │
│ @ja Akcelik VDF parameter │
│ @static_rel Static reliability factor │
│ │
│ TOLL ATTRIBUTES (per vehicle class): │
│ @toll_da, @toll_s2, @toll_s3, @toll_vsm, @toll_sml, @toll_med, @toll_lrg │
│ @bridgetoll_{class}, @valuetoll_{class} │
│ │
│ COST ATTRIBUTES (per vehicle class): │
│ @cost_da, @cost_s2, @cost_s3, @cost_vsm, @cost_sml, @cost_med, @cost_lrg │
│ @cost_datoll, @cost_s2toll, @cost_s3toll │
│ │
│ LINK MODES: │
│ d=drive, h=HOV2, i=HOV3, c=truck, x=MAZ, w=walk, b=bike │
│ H=HOV2toll, I=HOV3toll, D=SOVtoll │
└─────────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ STEP 3: highway (Assignment) │
│ Component: HighwayAssignment │
├─────────────────────────────────────────────────────────────────────────────────┤
│ SOLA Traffic Assignment using: │
│ - VDFs fd1-fd8, fd99 (indexed by @ft) │
│ - el1=@free_flow_time, el2=@capacity, el3=@ja, el4=@static_rel │
│ - Demand matrices from TAZ_Demand_{period}.omx │
│ │
│ OUTPUT ATTRIBUTES (added during assignment): │
│ volau Auto volume (vehicles/period) │
│ volad Additional volume │
│ @vol_{class} Volume by vehicle class │
│ │
│ SKIM MATRICES: │
│ Time, distance, cost, toll skims by vehicle class │
└─────────────────────────────────────────────────────────────────────────────────┘
Scenario ID Mapping ¶
| Config Setting | Period | Scenario ID | Title |
|---|---|---|---|
emme.all_day_scenario_id |
Reference | 1 | Base Network |
time_periods[0].emme_scenario_id |
EA | 11 | EA Base Network |
time_periods[1].emme_scenario_id |
AM | 12 | AM Base Network |
time_periods[2].emme_scenario_id |
MD | 13 | MD Base Network |
time_periods[3].emme_scenario_id |
PM | 14 | PM Base Network |
time_periods[4].emme_scenario_id |
EV | 15 | EV Base Network |
Emmebank Structure ¶
{run_directory}/
└── emme_project/
├── mtc_emme.emp # EMME project file
├── Database_highway/
│ └── emmebank # Highway emmebank
│ ├── Scenario 1 (reference)
│ ├── Scenario 11 (EA)
│ ├── Scenario 12 (AM) # ← Used for AM assignment
│ ├── Scenario 13 (MD)
│ ├── Scenario 14 (PM)
│ └── Scenario 15 (EV)
└── Database_transit/
└── emmebank # Transit emmebank (separate)
Attribute Reference ¶
Input Attributes (Base Network) ¶
| Attribute | Type | Domain | Description |
|---|---|---|---|
@lanes_{period} |
float | LINK | Number of lanes by time period (ea, am, md, pm, ev) |
@useclass_{period} |
int | LINK | HOV/toll restriction by time period |
@ft |
int | LINK | Facility type: 1=freeway, 2=expressway, 3-4=arterial, 5-6=collector, 7=local, 8=ramp, 99=connector |
@tollbooth |
int | LINK | Toll booth ID (0=no toll) |
@tollseg |
int | LINK | Toll segment ID |
@drive_link |
int | LINK | 1=driveable, 0=walk/bike only |
num_lanes |
float | LINK | EMME standard lanes (fallback if @lanes is empty) |
Calculated Attributes (create_tod_scenarios) ¶
| Attribute | Formula/Source | Description |
|---|---|---|
@area_type |
MAZ density calculation | 1=CBD, 2=urban business, 3=urban, 4=suburban, 5=rural |
@capclass |
10 * @area_type + @ft |
Combined capacity class (e.g., 34=suburban minor arterial) |
@free_flow_speed |
capclass_lookup table | Speed in mph |
@free_flow_time |
60 * length / @free_flow_speed |
Minutes at free-flow |
@lanes |
Copied from @lanes_{period} |
Period-specific lanes |
@useclass |
Copied from @useclass_{period} |
Period-specific restrictions |
Calculated Attributes (prepare_network_highway) ¶
| Attribute | Formula/Source | Description |
|---|---|---|
@capacity |
cap_lanehour * capacity_factor * @lanes |
Hourly capacity |
@ja |
Akcelik formula | VDF parameter for congested conditions |
@toll_{class} |
tolls.csv lookup | Toll cost by vehicle class |
@cost_{class} |
@free_flow_time + VOT * @toll_{class} |
Generalized cost |
Volume Delay Function Parameters ¶
el1 = @free_flow_time (minutes)
el2 = @capacity (vehicles/hour)
el3 = @ja (Akcelik parameter)
el4 = @static_rel (reliability factor)
VDF Formulas by Facility Type ¶
| VDF | Facility Type | Formula Type |
|---|---|---|
| fd1 | Freeway | BPR with reliability adjustments |
| fd2 | Expressway | BPR with reliability adjustments |
| fd3-fd7 | Arterials/Collectors | Akcelik with reliability adjustments |
| fd8 | Ramps/Connectors | Free-flow only (el1) |
| fd99 | Special | Akcelik |
Common Issues ¶
@capacity = 0 (Division by Zero) ¶
Symptom: “Illegal character ‘+’” error during assignment
Root Cause Chain:
1. @lanes_{period} not copied to @lanes (case sensitivity issue)
2. @capacity = cap_lanehour * @lanes = 0
3. VDF divides by @capacity → infinity
4. EMME formats as 0.135972+124 → lexer crash
Fix: Case-insensitive matching for period attribute names (applied January 2026)
Missing @useclass ¶
Symptom: “MISSING NETWORK ATTRIBUTES” warning, tolls skipped
Cause: Network doesn’t have @useclass_{period} attributes coded
Solution: Either: - Add toll coding to base network - Accept that toll assignment will be skipped