Public Transport

Contents

Public Transport#

The public transport module currently available on this library allow users to import GTFS feeds into supply models, including map-matching to the road network.

It does not, however, allow for traditional editing of transit networks, such as definition of new routes/services, changes to transit stops or stopping patterns.

Editing triggers#

The transit route system does not have the same level of editing capabilities as the roadway layer, but a series of triggers have been implemented to greatly reduce the amount of unecessary data leftover when deleting transit routes/patterns.

These triggers are the following:

When deleting a route:

  • Delete all patterns for that route

  • Delete all transit fare rules specific to that route

When deleting a pattern:

  • Delete all data from Transit_Pattern_Mapping regarding that pattern

  • Delete all trips from Transit_Trips for that pattern

  • Delete all links from Transit_Links for that pattern

  • Delete the sequence of links from Transit_Pattern_Links for that pattern

When deleting a trip:

  • Delete all scheduled arrivals and departures for that trip from Transit_Trips_Schedule

GTFS IMPORTER#

Since the main purpose of this model is to import GTFS feeds, key software operations are done on a class capable of reading a GTFS feed and querying it in memory.

You can also read a detailed explanation of the Transit Map-Matching algorithm

class polaris.network.transit.lib_gtfs.GTFSRouteSystemBuilder(network, agency_id, file_path, day='', description='', capacities: dict | None = None)#

Bases: WorkerThread

Container for GTFS feeds providing data retrieval for the importer

from polaris.network.network import Network

network_path = 'D:/Argonne/GTFS/CHICAGO/chicago2018-Supply.sqlite'
GTFS_path = 'D:/Argonne/GTFS/CHICAGO/METRA/2019-10-04.zip'

my_network = Network()
my_network.open(network_path)

transit = my_network.transit()

feed = transit.new_gtfs(file_path=GTFS_path
                        description='METRA Commuter Rail',
                        agency_identifier='METRA')

# In case you created the feed without providing an agency ID or description
feed.set_description('METRA Commuter Air Force')

# For a least of all dates covered by this feed
feed.dates_available()

# If you set it with the wrong feed and want to change it
feed.set_feed('D:/Argonne/GTFS/CHICAGO/METRA/2073-12-03.zip')

# To prevent map-matching to be performed and execute a faster import
feed.set_allow_map_match(False)

feed.load_date('2019-10-15')

# To save the transit raw-shapes to the database for later consult
feed.create_raw_shapes()

# To map-match the services in this feed
feed.map_match()
feed.execute_import()
signal = <polaris.utils.python_signal.PythonSignal object>#
__init__(network, agency_id, file_path, day='', description='', capacities: dict | None = None)#

Instantiates a transit class for the network

Args:

polaris network (Network): Supply model to which this GTFS will be imported agency_identifier (str): ID for the agency this feed refers to (e.g. ‘CTA’) file_path (str): Full path to the GTFS feed (e.g. ‘D:/project/my_gtfs_feed.zip’) day (str, Optional): Service data contained in this field to be imported (e.g. ‘2019-10-04’) description (str, Optional): Description for this feed (e.g. ‘CTA19 fixed by John after coffee’)

archive_dir: str#
trip_by_service: Dict[str, Trip]#
patterns: Dict[int, Pattern]#
graphs: Dict[int, Any]#
select_routes: Dict[int, Route]#
select_trips: List[Trip]#
select_stops: Dict[int, Stop]#
select_patterns: Dict[int, Pattern]#
set_capacities(capacities: dict)#

Sets default capacities for modes/vehicles.

Args:
capacities (dict): Dictionary with GTFS types as keys, each with a list

of 3 items for values for capacities: seated, design and total i.e. -> “{0: [150, 300, 300],…}”

set_maximum_speeds(max_speeds: DataFrame)#

Sets the maximum speeds to be enforced at segments.

Args:

max_speeds (pd.DataFrame): Requires 4 fields: mode, min_distance, max_distance, speed. Modes not covered in the data will not be touched and distance brackets not covered will receive the maximum speed, with a warning

dates_available() list#

Returns a list of all dates available for this feed

Returns:

feed dates (list): list of all dates available for this feed

set_allow_map_match(allow=True)#

Changes behavior for finding transit-link shapes

Defaults to True

Args:

allow (bool optional): If True, allows uses map-matching in search of precise transit_link shapes. If False, sets transit_link shapes equal to straight lines between stops. In the presence of GTFS raw shapes it has no effect.

map_match(route_types: List[int] | None = None) None#

Performs map-matching for all routes of one or more types

Defaults to map-matching Bus routes (type 3) only For a reference of route types, see https://developers.google.com/transit/gtfs/reference#routestxt

Args:

route_types (List[int] or Tuple[int]): Default is [3], for bus only

set_agency_identifier(agency_id: str) None#

Adds agency ID to this GTFS for use on import

Args:

agency_id (str): ID for the agency this feed refers to (e.g. ‘CTA’)

set_feed(feed_path: str) None#

Sets GTFS feed source to be used

Args:

file_path (str): Full path to the GTFS feed (e.g. ‘D:/project/my_gtfs_feed.zip’)

set_description(description: str) None#

Adds description to be added to the imported layers metadata

Args:

description (str): Description for this feed (e.g. ‘CTA2019 fixed by John Doe after strong coffee’)

set_date(service_date: str) None#

Sets the date for import without doing any of data processing, which is left for the importer

load_date(service_date: str) None#

Loads the transit services available for service_date

Args:

service_date (str): Day for which services are to be imported (e.g. ‘2019-10-04’)

set_do_raw_shapes(do_shapes: bool)#

Sets the raw shapes importer to True for execution by the importer

create_raw_shapes()#

Adds all shapes provided in the GTFS feeds to the TRANSIT_RAW_SHAPES table in the network file

This table is for debugging purposes, as allows the user to compare it with the result of the map-matching procedure.

All previously existing entries with this feed’s prefix ID are removed. For patterns with no corresponding shape on shapes.txt or in the absence of shapes.txt, the raw shape is generated by connecting stops directly.

doWork()#

Alias for execute_import

execute_import()#
save_to_disk()#

Saves all transit elements built in memory to disk

finished()#

Build the graph for links for a certain mode while splitting the closest links at stops’ projection

Args:

mode_id (int): Mode ID for which we will build the graph for

GTFSRouteSystemBuilder

Container for GTFS feeds providing data retrieval for the importer

This class is designed to read standard GTFS feeds and might not work with poorly formatted feeds. For more information on GTFS, please refer to GTFS reference documentation.

Import process#

Although bus-on-traffic is not used by default on most of Polaris models, map-matching is still used by default for all routes (not only bus) whenever the GTFS feed being imported lacks route shapes. This is done in order to obtain route and transit_link shapes for display, as the old straight lines are less intuitive to some of those looking at model results.

Since the map-matching process is rather time-consuming, it is possible to turn it off and force the creation of straight-lines in the absence of route shapes with a single line of code

feed.set_allow_map_match(False)

Preventing excess speed#

During the development of multiple Polaris models, we have detected unusually high speeds for a number of route segments. As some of these segment speeds were in excess of 200 mph, a procedure to limit these speeds was put in place.

The process consists of delaying the arrival at a stop (and consequently at all subsequent stops in that trip) any time the segment speed is below a certain threshold.

The use of posted speeds is, however, impossible at that stage of the import process, as the route is yet to be map-matched to the network. For this reason, data analysis was conducted for all networks currently in existence to determine the threshold speeds to be used.

In time, these threshold speeds are mode-specific and vary according to the length of the route segment as to account for express routes.

As the distribution of segment lengths is likely to change significantly across modes and urban areas, the analysis was made for 20 bins with equal number of elements for each model/mode, rounded to the nearest 5m. We understand that this approach may cut off a possibly long tail for the segment length distribution, but we do not believe that this will have substantial effect on the GTFS processing outcome.

Chicago#

Chicago has routes for 3 GTFS modes, as follows:

GTFS mode 1 (Subway/metro)#
Chicago GTFS mode 1

There are no clearly absurd route speeds, but some substantially higher speeds for the 99.5% percentile suggest that imposing some lower limits might be necessary.

Looking at the charts we have established that the appropriate speed limits to be imposed on import were approximate the following.

From Length

to length

Percentile

Speed (mph)

0

365

0.975

~21.9

365

480

0.975

~18.5

480

705

0.975

~23.3

705

785

0.975

~29.0

785

855

0.975

~31.3

855

1,020

0.985

~32.0

1,020

1,285

0.975

~31.9

1,285

1,600

0.980

~36.5

1,600

1,755

0.985

~39.5

1,755

MAX

0.975

~55.5

There is a somewhat constant low maximum speed for segments shorter than 705m and another plateau of speed between 700 and 1,775m, so we simplify the table as follows:

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

700

0.970

22.9

10.2

700

1,285

0.970

31.3

14.0

1,285

MAX

0.985

36.4

16.3

GTFS mode 2 (Suburban rail)#
Chicago GTFS mode 2

From Length

to length

Percentile

Speed (mph)

0

815

0.975

~30.3

815

935

0.975

~33.2

935

1,430

0.975

~42.5

1,430

1,955

0.975

~37.0

1,955

2,405

0.975

~37.0

2,405

2,965

0.975

~37.0

2,965

3,885

0.970

~43.5

3,885

5,070

0.975

~53.0

5,070

8,500

0.975

~49.0

8,500

MAX

0.975

~53.5

The variability for these modes is a little more extreme than for the other two, but we can establish a difference in general pattern for segments under 935m between 935 and 3,885 and over 3,885m. The resulting simplified limit table is:

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

1,000

0.975

31.6

14.1

1,000

4,000

0.975

42.5

19.0

4,000

MAX

0.975

52.6

23.5

GTFS mode 3 (Bus)#
Chicago GTFS mode 3

From Length

to length

Percentile

Speed

0

120

0.975

~23.0

120

155

0.970

~23.0

155

180

0.975

~23.0

180

195

0.975

~23.0

195

205

0.985

~23.0

205

210

0.985

~23.5

210

235

0.985

~26.0

235

270

0.970

~27.5

270

370

0.955

~31.0

370

MAX

0.985

~49.0

As there is a clear constant pattern for maximum speed for the segments up to 210m, we have simplified the table and retrieved the precise values for the percentiles above.

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

210

0.975

22.7

10.2

210

270

0.975

26.9

12.0

270

370

0.955

30.4

13.6

370

MAX

0.975

49.0

21.9

Atlanta#

Atlanta also has routes for 3 GTFS modes, as follows:

GTFS mode 0 (Tram/Light rail)#
Atlanta GTFS mode 0

The maximum speeds for light rail segments for Atlanta are incredibly well behaved, so we will use the maximum available speed (12.8 mph) as the threshold across all distance brackets:

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

MAX

1.000

12.9

5.8

GTFS mode 1 (Subway/metro)#
Atlanta GTFS mode 1

The maximum speeds for rail/metro segments for Atlanta are also incredibly well behaved, so we will use only a few brackets to threshold across all distance brackets:

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

705

0.975

24.5

11.0

705

3,000

0.975

46.1

20.6

3,000

MAX

0.985

53.3

23.8

GTFS mode 3 (Bus)#
Atlanta GTFS mode 3

From Length

to length

Percentile

Speed

0

130

0.985

~23.0

130

160

0.985

~25.0

160

190

0.975

~23.8

190

220

0.975

~23.8

220

250

0.975

~24.0

250

285

0.980

~24.5

285

325

0.970

~23.5

325

385

0.975

~25.5

385

500

0.985

~26.0

500

MAX

0.975

~31.0

There are basically three distance segments that should be interpreted independently, which are consolidated below:

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

325

0.975

23.6

10.6

325

500

0.975

25.2

11.3

500

MAX

0.985

29.4

13.1

Campo#

The Austin metro model has routes for 2 GTFS modes, as follows:

GTFS mode 0 (Tram/Light rail)#
Campo GTFS mode 0

The maximum speeds for light rail segments for Austin are pretty well behaved, but also very choppy. For this reason, we have decided to use 4 distance brackets of equal size and loosely correlated with what we see on the charts above and stipulated that the quantile to use is 0.975, as that is often the point where speeds tend to start becoming unreasonable in other cities.

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

2,500

0.975

15.1

6.8

2,500

5,000

0.975

16.5

7.4

5,000

10,000

0.975

32.8

14.7

10,000

MAX

0.975

38.6

17.3

GTFS mode 3 (Bus)#

The behavior for transit speeds for Bus in Campo follows the example for Chicago, where some clearly absurd speeds are recorded as maximum for different distance brackets.

Campo GTFS mode 3

From Length

to length

Percentile

Speed

0

165

0.975

~24.2

165

215

0.985

~21.0

215

255

0.980

~20.5

255

305

0.975

~20.5

305

350

0.975

~20.5

350

400

0.980

~21.5

400

465

0.975

~20.5

465

575

0.980

~22.0

575

860

0.975

~22.5

860

MAX

0.985

~26.5

Different than Chicago, however, the constant maximum speed pattern is observed for most of the distance segment brackets, which suggests three different brackets to be used:

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

600

0.975

21.4

9.6

600

1,000

0.975

22.6

10.1

1,000

MAX

0.985

26.6

11.9

Detroit#

The Detroit model has routes for 2 GTFS modes, as follows:

GTFS mode 0 (Tram/Light rail)#
Detroit GTFS mode 0

The maximum speeds for light rail segments for Detroit are pretty well behaved throughout all segment distance brackets, so we have established a unique maximum speed to be applied for all segments and equal to the maximum speed registered in the dataset.

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

MAX

1.000

9.7

4.3

GTFS mode 3 (Bus)#

Again, Bus presents the most inconsistencies with regards to maximum speeds.

Detroit GTFS mode 0

From Length

to length

Percentile

Speed

0

160

0.97

~21.0

160

185

0.975

~26.0

185

200

0.975

~28.0

200

220

0.965

~25.0

220

245

0.965

~27.0

245

275

0.985

~31.2

275

305

0.980

~34.1

305

355

0.985

~39.0

355

440

0.975

~45.0

440

MAX

0.970

~53.0

Different than other cities, Detroit speeds increase gradually for growing segment length brackets, and therefore the limits set for it must recognize that, resulting in 6 segment length brackets.

From Length

to length

Percentile

Speed (mph)

Speed (m/s)

0

160

0.975

22.4

10.0

160

245

0.975

27.5

12.3

245

305

0.985

33.9

15.2

305

355

0.985

39.5

17.7

355

440

0.975

44.9

20.1

440

MAX

0.970

53.2

23.7

Other cities#

For all other cities, the limits to be observed are the following

GTFS mode 0 (Tram/Light rail)#

From Length

to length

Source

Speed (mph)

Speed (m/s)

0

MAX

Atlanta

12.9

5.8

GTFS mode 1 (Subway/metro)#

From Length

to length

Source

Speed (mph)

Speed (m/s)

0

705

Atlanta

24.5

11.0

705

3,000

Atlanta

46.1

20.6

3,000

MAX

Atlanta

53.3

23.8

GTFS mode 3 (Bus)#

From Length

to length

Source

Speed (mph)

Speed (m/s)

0

325

Atlanta

23.6

10.6

325

500

Atlanta

25.2

11.3

500

MAX

Atlanta

29.4

13.1

Map-matching#

Due to the complex nature of the Map-matching procedure, particularly in face of the fact that the network models are simplified and often do not include roadways in which there are active transit services, access to the GTFS importer components might be needed for debugging and/or detailed analysis purposes.

As the importer improves this need should disappear, but the documentation of this component is crucial also to understand its impacts on the final model results.

Pattern

Represents a stop pattern for a particular route, as defined in GTFS

Although not relevant during regular software use, the other classes employed by the GTFS importer are documented below in order to aid debugging.

Link

Transit link element to feed into Transit_links

Route

Transit route element to feed into Transit_routes

Service

Transit service built with data from calendar.txt and calendar_dates.txt from GTFS

Stop

Transit stop as read from the GTFS feed

Trip

Transit trips read from trips.txt

Post-Import processes#

Building walk and bike networks is necessary in order to ensure access and connectivity to the transit network, but needs to be explicitly executed.

GTFS EXPORTER#

The Polaris GTFS exporter is designed to pass the minimum requirements of the standard, and is continuously tested against the MobilityData validator.

To meet these requirements while generating GTFS feeds with as much of the original data as possible, a few simplifications/assumptions are made to each of the tables.

As a standard, all transit geo-data is converted to WGS84.

Agencies#

All agencies available in the model are included in the same GTFS feed, and the agency.txt file can therefore have multiple records. The timezone adopted for ALL agencies is the same

The timezone used for ALL agencies is obtained from an online service for the geographic center of the model zones. If no data can be retrieved, the timezone for Chicago is used. This exception, however, is not used when testing the software, which guarantees the resource should be robust.

An agency URL is also required, and we used the Polaris website as the placeholder.

Routes#

The Process of building route systems for Polaris replaces the route ID with an internal ID does not correspond to the ID in the source GTFS used to build the Polaris Transit Route System.

For this reason, and to as much of the original data as possible, the original ID information is concatenated with the route description when the data is exported, which gets formatted as a json.

Shapes#

The cumulative segment distances are kept in meters, despite the use of WGS84 for the point coordinates.