Utah Transit Agency Example#

In this example, we'll predict the energy consumption for some trips operated by the Utah Transit Authority (UTA) in Salt Lake City. This requires specifying the GTFS data we are analyzing, processing it to produce RouteE-Powertrain inputs, and running a RouteE-Powertrain model to produce energy estimates.

This example uses the GTFSEnergyPredictor class, which provides a clean, extensible API for transit energy prediction.

import logging
import os

from routee.transit import GTFSEnergyPredictor, sample_inputs_path

# Set up logging: Clear any existing handlers
logging.getLogger().handlers.clear()

# Configure basic logging
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s - %(message)s"
)

# Suppress GDAL/PROJ warnings, which flood the output when we run gradeit
os.environ["PROJ_DEBUG"] = "0"

# Specify input data location
input_directory = sample_inputs_path() / "saltlake/gtfs"
output_directory = "./reports/saltlake"

Quick Start: Using the run() Method#

For most use cases, the run() method provides the simplest way to perform the complete energy prediction workflow. This single method call chains together all processing steps and returns trip-level energy predictions.

We'll analyze routes 806 and 807 on August 2nd, 2023, using the Battery Electric Bus model with HVAC energy impacts included.

Note: depot_path is not specified, so the predictor will use default depot locations from the National Transit Database's "Public Transit Facilities and Stations - 2023" dataset (https://data.transportation.gov/stories/s/gd62-jzra).

predictor = GTFSEnergyPredictor(
    gtfs_path=input_directory,
    output_dir=output_directory,
    vehicle_models=["Transit_Bus_Battery_Electric"],
)

trip_results = predictor.run(
    date="2023/08/02",
    routes=["806", "807"],
    add_depot_deadhead=True,
    add_mid_block_deadhead=True,
    add_hvac=True,
    save_results=False,
)
2026-03-05 00:46:01,550 [INFO] routee.transit.predictor - Initialized GTFSEnergyPredictor for /opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/site-packages/routee/transit/resources/sample_inputs/saltlake/gtfs
2026-03-05 00:46:01,551 [INFO] routee.transit.predictor - Loading GTFS data...
2026-03-05 00:46:02,910 [INFO] routee.transit.predictor - Feed includes 1 agencies: ['Utah Transit Authority']. Total trips: 12037, shapes: 238
2026-03-05 00:46:02,919 [INFO] routee.transit.predictor - Loaded 12037 trips and 199 shapes
2026-03-05 00:46:02,920 [INFO] routee.transit.predictor - Filtering trips (date=2023/08/02, routes=['806', '807'])...
2026-03-05 00:46:02,958 [INFO] routee.transit.predictor - Filtered to 16 trips and 4 shapes
2026-03-05 00:46:02,989 [INFO] routee.transit.predictor - Preparing mid-block deadhead trips...
2026-03-05 00:46:03,081 [INFO] routee.transit.predictor - Preparing depot deadhead trips...
2026-03-05 00:46:03,226 [INFO] routee.transit.predictor - Building CompassApp from bounding box: (-112.03101, 40.22523, -111.65814, 40.482409999999994)
2026-03-05 00:47:28,952 [INFO] nrel.routee.compass.io.generate_dataset - running pipeline import with phases: [['GRAPH', 'CONFIG', 'POWERTRAIN']]
2026-03-05 00:47:28,953 [INFO] nrel.routee.compass.io.generate_dataset - processing graph topology and speeds
2026-03-05 00:47:29,509 [INFO] nrel.routee.compass.io.generate_dataset - adding grade information
2026-03-05 00:47:30,102 [INFO] nrel.routee.compass.io.utils - downloading n41w113
2026-03-05 00:47:30,879 [INFO] nrel.routee.compass.io.utils - downloading n41w112
2026-03-05 00:47:33,278 [INFO] nrel.routee.compass.io.generate_dataset - processing vertices
2026-03-05 00:47:33,281 [INFO] nrel.routee.compass.io.generate_dataset - processing edges
2026-03-05 00:47:36,831 [INFO] nrel.routee.compass.io.generate_dataset - writing vertex files
2026-03-05 00:47:37,538 [INFO] nrel.routee.compass.io.generate_dataset - writing edge files
2026-03-05 00:47:40,039 [INFO] nrel.routee.compass.io.generate_dataset - writing edge attribute files
2026-03-05 00:47:44,450 [INFO] nrel.routee.compass.io.generate_dataset - copying default configuration TOML files
2026-03-05 00:47:44,500 [INFO] nrel.routee.compass.io.generate_dataset - downloading the default RouteE Powertrain models
2026-03-05 00:48:58,740 [INFO] nrel.routee.compass.io.generate_dataset - copying vehicle configuration files
2026-03-05 00:48:58,746 [INFO] nrel.routee.compass.io.generate_dataset - running 2 dataset generation hooks
2026-03-05 00:49:19,885 [INFO] gtfs_processing - Wrote 119313 stop-edge mappings to reports/saltlake/compass_app/gtfs_stops.csv
2026-03-05 00:49:19,978 [INFO] gtfs_processing - Copied transit_energy.toml to reports/saltlake/compass_app/transit_energy.toml
graph edge list 0: /home/runner/work/routee-transit/routee-transit/docs/examples/reports/saltlake/compass_app/edges-compass.csv.gz: 46711it [00:00, 1660470.62it/s]2026-03-05 00:49:23,090 [INFO] routee.transit.predictor - CompassApp initialized



building adjacencies: 100%|██████████| 46711/46711 [00:00<00:00, 4233188.50it/s]
building adjacencies: 100%|██████████| 46711/46711 [00:00<00:00, 4224197.50it/s]
2026-03-05 00:49:23,091 [INFO] routee.transit.predictor - Routing mid-block deadhead trips...
2026-03-05 00:49:23,093 [INFO] routee.transit.deadhead_router - Deadhead routing: 7 trips reduced to 3 unique O-D pairs

applying input plugin 1: 100%|██████████| 3/3 [00:00<00:00, 10635.92it/s]

applying input plugin 2: 100%|██████████| 3/3 [00:00<00:00, 112237.65it/s]



search: 100%|██████████| 3/3 [00:00<00:00, 94.01it/s]
2026-03-05 00:49:23,194 [INFO] routee.transit.predictor - Added 7 mid-block deadhead trips
2026-03-05 00:49:23,194 [INFO] routee.transit.predictor - Routing depot deadhead trips...
2026-03-05 00:49:23,197 [INFO] routee.transit.deadhead_router - Deadhead routing: 9 trips reduced to 3 unique O-D pairs

applying input plugin 1: 100%|██████████| 3/3 [00:00<00:00, 52949.28it/s]

applying input plugin 2: 100%|██████████| 3/3 [00:00<00:00, 170019.84it/s]



search: 100%|██████████| 3/3 [00:00<00:00, 37.16it/s]
2026-03-05 00:49:23,299 [INFO] routee.transit.deadhead_router - Deadhead routing: 9 trips reduced to 3 unique O-D pairs

applying input plugin 1: 100%|██████████| 3/3 [00:00<00:00, 53504.55it/s]

applying input plugin 2: 100%|██████████| 3/3 [00:00<00:00, 168133.16it/s]



search: 100%|██████████| 3/3 [00:00<00:00, 69.88it/s]
2026-03-05 00:49:23,392 [INFO] routee.transit.predictor - Added 18 depot deadhead trips
2026-03-05 00:49:23,393 [INFO] routee.transit.predictor - Predicting energy for 1 vehicle model(s)...
2026-03-05 00:49:24,738 [INFO] routee.transit.predictor - Running map matching for 13 shapes...
map matching:  15%|█▅        |  2/13 [00:00<00:00, 18.53it/s]
map matching:  31%|███▂      |  4/13 [00:00<00:00, 13.19it/s]
map matching:  62%|██████▃   |  8/13 [00:00<00:00, 13.71it/s]
map matching:  77%|███████▆  | 10/13 [00:00<00:00, 13.74it/s]
map matching:  85%|████████▅ | 11/13 [00:01<00:00, 10.82it/s]
map matching:  92%|█████████▃| 12/13 [00:01<00:00, 9.36it/s]
map matching: 100%|██████████| 13/13 [00:01<00:00, 8.49it/s]
2026-03-05 00:49:26,482 [INFO] routee.transit.predictor - Running energy prediction via CompassApp for: Transit_Bus_Battery_Electric
calculating paths: 100%|██████████| 13/13 [00:00<00:00, 875.24it/s]
2026-03-05 00:49:26,525 [INFO] routee.transit.predictor - Adding HVAC energy impacts...
Downloaded: G4900350.csv
Downloaded: G4900490.csv
Downloaded: G4900450.csv
Downloaded: G4900110.csv
Downloaded: G4900570.csv
Downloaded: G4900030.csv
Downloaded: G4900430.csv
2026-03-05 00:49:29,158 [INFO] routee.transit.predictor - Energy prediction complete

The run() method automatically performs all these steps:

  1. Loads the GTFS feed

  2. Filters trips by date and routes

  3. Adds mid-block deadhead trips (between consecutive trips)

  4. Adds depot deadhead trips (to/from depot)

  5. Matches shapes to OpenStreetMap road network

  6. Adds road grade information using USGS elevation data

  7. Predicts energy consumption with RouteE-Powertrain

  8. Adds estimated HVAC energy impacts

  9. Saves results to CSV files

Let's examine the results:

print(trip_results.head())
   energy_used      miles                       vehicle energy_unit  \
0    16.953909  15.492026  Transit_Bus_Battery_Electric         kWh   
1    16.011903  15.492026  Transit_Bus_Battery_Electric         kWh   
2    44.525431  15.492026  Transit_Bus_Battery_Electric         kWh   
3    12.586445  15.492026  Transit_Bus_Battery_Electric         kWh   
4    12.573726  15.492026  Transit_Bus_Battery_Electric         kWh   

              trip_id route_id service_id block_id  \
0  5181298_to_5181301     2152          4  1156079   
1  5181298_to_5181301     2152          4  1156079   
2  5181298_to_5181301     2152          4  1156079   
3  5181297_to_5181299     2152          4  1156088   
4  5181297_to_5181299     2152          4  1156088   

                           shape_id route_short_name  ...  agency_id  \
0  -111.712,40.276->-111.895,40.426             None  ...        NaN   
1  -111.712,40.276->-111.895,40.426             None  ...        NaN   
2  -111.712,40.276->-111.895,40.426             None  ...        NaN   
3  -111.712,40.276->-111.895,40.426             None  ...        NaN   
4  -111.712,40.276->-111.895,40.426             None  ...        NaN   

            trip_type start_time  end_time trip_duration_minutes trip_count  \
0  mid_block_deadhead   06:55:00  07:22:00                  27.0         87   
1  mid_block_deadhead   06:55:00  07:22:00                  27.0         87   
2  mid_block_deadhead   06:55:00  07:22:00                  27.0         87   
3  mid_block_deadhead   07:25:00  07:52:00                  27.0         87   
4  mid_block_deadhead   07:25:00  07:52:00                  27.0         87   

   from_trip  to_trip scenario hvac_energy_kWh  
0    5181298  5181301   median        4.607329  
1    5181298  5181301   summer        3.665324  
2    5181298  5181301   winter       32.178852  
3    5181297  5181299   median        0.239866  
4    5181297  5181299   summer        0.227146  

[5 rows x 22 columns]

Calculate Energy Efficiency Metrics#

We can calculate energy efficiency in kWh per mile, including HVAC loads. The results now include a 'scenario' column (summer/winter) for HVAC impacts.

if "scenario" in trip_results.columns:
    trip_results["kwh_per_mi"] = trip_results["energy_used"] / trip_results["miles"]

print(trip_results.groupby("scenario")["kwh_per_mi"].mean())
scenario
median    1.668295
summer    1.957103
winter    5.350892
Name: kwh_per_mi, dtype: float64

Access Additional Results#

After running predictions, you can access link-level results and RouteE inputs:

# Link-level predictions show energy for each road segment
link_results = predictor.get_link_predictions()
print(link_results.head())
   match_id  edge_index  edge_list_id  edge_id  edge_distance  trip_distance  \
0         0           0             0    30126       0.025420       0.025420   
1         0           1             0    30127       0.029904       0.055324   
2         0           2             0      246       0.091411       0.146736   
3         0           3             0    40098       0.020931       0.167667   
4         0           4             0      259       0.017637       0.185304   

   trip_soc  trip_time  edge_energy_electric  edge_turn_delay  ...  \
0  0.999840   0.055813              0.080132              0.0  ...   
1  0.999494   0.138138              0.172851              1.0  ...   
2  0.999959   0.497176             -0.232710              9.5  ...   
3  0.999906   0.551467              0.026962              0.5  ...   
4  0.999897   0.582071              0.004460              0.0  ...   

   edge_speed  battery_capacity  trip_energy_electric  trip_elevation_loss  \
0   27.327045             500.0              0.080132             0.000000   
1   27.327045             500.0              0.252983             0.000000   
2   27.327045             500.0              0.020274            -0.006952   
3   27.327045             500.0              0.047235            -0.006952   
4   34.578084             500.0              0.051695            -0.007189   

   edge_grade                                           geometry  \
0    0.034760  LINESTRING (-111.71143 40.27542, -111.71156 40...   
1    0.088317  LINESTRING (-111.71166 40.27568, -111.71109 40...   
2   -0.076052  LINESTRING (-111.71109 40.27571, -111.71139 40...   
3    0.001036  LINESTRING (-111.71275 40.27596, -111.71275 40...   
4   -0.013422  LINESTRING (-111.71305 40.27608, -111.7131 40....   

                           shape_id                       vehicle energy_used  \
0  -111.712,40.276->-111.895,40.426  Transit_Bus_Battery_Electric    12.34658   
1  -111.712,40.276->-111.895,40.426  Transit_Bus_Battery_Electric    12.34658   
2  -111.712,40.276->-111.895,40.426  Transit_Bus_Battery_Electric    12.34658   
3  -111.712,40.276->-111.895,40.426  Transit_Bus_Battery_Electric    12.34658   
4  -111.712,40.276->-111.895,40.426  Transit_Bus_Battery_Electric    12.34658   

  energy_unit  
0         kWh  
1         kWh  
2         kWh  
3         kWh  
4         kWh  

[5 rows x 22 columns]