Demand responsive services¶
Flex is a GTFS extension project which was adopted officially into the GTFS specification in March 2024, its aims to facilitate discoverability of Demand Responsive Transportation Services.
The following example demonstrates how to model different demand responsive service use cases using Flex. Please note that the following examples are not necessarily an accurate or complete representation of the agencies’ services.
On-demand services within a single zone¶
Demand-repsonsive services can operate within a specific zone, allowing riders to book pickups at any point A within the zone and drop-offs at any point B within the same zone. An example of this is the Heartland Express Transit service in Minnesota, USA.
Download Heartland Express example dataset
Define trips¶
Heartland Express service hours are as follow:
- Weekdays:
- 8:00 AM - 5:00 PM
- 6:15 AM – 5:45 PM (New Ulm zone only)
- Sunday: 8:00 AM - Noon (New Ulm zone only)
The New Ulm city zone is contained within the Brown County zone. To avoid the "zone overlap constraint" issue, Heartland Express can be defined with four trips:
- Service in New Ulm zone from 6:15 AM to 8:00 AM on weekdays.
- County-wide service from 8:00 AM to 5:00 PM on weekdays.
- Service in New Ulm zone from 5:00 PM to 5:45 PM on weekdays.
- Service in New Ulm zone from 8:00 AM to 12:00 PM on Sundays.
route_id | service_id | trip_id |
---|---|---|
74362 | c_67295_b_77497_d_31 | t_5374945_b_77497_tn_0 |
74362 | c_67295_b_77497_d_31 | t_5374946_b_77497_tn_0 |
74362 | c_67295_b_77497_d_31 | t_5374944_b_77497_tn_0 |
74362 | c_67295_b_77497_d_64 | t_5374947_b_77497_tn_0 |
service_id = c_67295_b_77497_d_31
refers to weekdays, service_id = c_67295_b_77497_d_64
refers to Sunday.
Define zone (GeoJSON locations)¶
Using locations.geojson to define the operational zone of Heartland Express service, separate zones must be defined for Brown County and New Ulm City. Below is a simplified GeoJSON defining the zone of Brown County:
{
"type": "FeatureCollection",
"features": [
{
"id": "area_708",
"type": "Feature",
"geometry": {
"type": "Polygon",
# Simplified, only presenting 3 coordinates here.
"coordinates": [
[
[
-94.7805702,
44.4560958
],
[
-94.7805608,
44.4559928
],
[
-94.7805218,
44.4559649
]
]
]
},
"properties": {}
}
]
Define booking rules¶
Here are booking rules that apply to all Heartland Express services:
- Ride requests should be made between 8 AM and 3 PM weekdays.
- Rides must be requested one business day prior to day of the ride.
- Ride requests can be made up to 14 days in advance.
Using booking_type = 2
indicates that the service requires up to prior day(s) booking. prior_notice_last_day = 1
and prior_notice_start_day = 14
indicate indicate that the service can be booked as early as 14 days in advance and as late as the day before.
booking_rule_id | booking_type | prior_notice_start_day | prior_notice_start_time | prior_notice_last_day | prior_notice_last_time | message | phone_number | info_url |
---|---|---|---|---|---|---|---|---|
booking_route_74362 | 2 | 14 | 8:00:00 | 1 | 15:00:00 | Brown County Heartland Express provides door-to-door on-demand transportation. To request a ride, call 1-507-359-2717 or 1-800-707-2717 by 3pm at least one business day ahead of your trip. | (507) 359-2717 | https://www.co.brown.mn.us/heartland-express-transit |
Define stop times¶
The operating hours are defined using the start_pickup_drop_off_window
and end_pickup_drop_off_window
fields. Travel within the same zone requires two records in stop_times.txt with the same location_id
.
- The first record with
pickup_type = 2
anddrop_off_type = 1
indicates that booking pickup is allowed in the zone. - The second record with
pickup_type = 1
anddrop_off_type = 2
indicates that booking drop-off is allowed in the zone.
trip_id | location_id | stop_sequence | start_pickup_drop_off_window | end_pickup_drop_off_window | pickup_type | drop_off_type | pickup_booking_rule_id | drop_off_booking_rule_id |
---|---|---|---|---|---|---|---|---|
t_5374944_b_77497_tn_0 | area_715 | 1 | 06:15:00 | 08:00:00 | 2 | 1 | booking_route_74362 | booking_route_74362 |
t_5374944_b_77497_tn_0 | area_715 | 2 | 06:15:00 | 08:00:00 | 1 | 2 | booking_route_74362 | booking_route_74362 |
t_5374945_b_77497_tn_0 | area_708 | 1 | 08:00:00 | 17:00:00 | 2 | 1 | booking_route_74362 | booking_route_74362 |
t_5374945_b_77497_tn_0 | area_708 | 2 | 08:00:00 | 17:00:00 | 1 | 2 | booking_route_74362 | booking_route_74362 |
t_5374946_b_77497_tn_0 | area_715 | 1 | 17:00:00 | 17:45:00 | 2 | 1 | booking_route_74362 | booking_route_74362 |
t_5374946_b_77497_tn_0 | area_715 | 2 | 17:00:00 | 17:45:00 | 1 | 2 | booking_route_74362 | booking_route_74362 |
t_5374947_b_77497_tn_0 | area_715 | 1 | 08:00:00 | 12:00:00 | 2 | 1 | booking_route_74362 | booking_route_74362 |
t_5374947_b_77497_tn_0 | area_715 | 2 | 08:00:00 | 12:45:00 | 1 | 2 | booking_route_74362 | booking_route_74362 |
area_715
refers to New Ulm City zone, area_708
refers to Bronw County zone.
On-demand services across multiple zones¶
Some demand-responsive services operate across multiple distinct zones, where riders can book pickups at any location A within one area and drop-offs at any location within another area. For example, Minnesota River Valley Transit offers on-demand services between Saint Peter and Kasota cities:
Download River Valley Transit example dataset
Define trips¶
Similar to the previous example, because service hours vary on different days, it's necessary to define trips separately for weekdays and Saturdays.
route_id | service_id | trip_id |
---|---|---|
74375 | weekdays | t_5298036_b_77503_tn_0 |
74375 | saturdays | t_5298041_b_77503_tn_0 |
(Define booking rules and zones using booking_rules.txt and locations.geojson in the same way as the previous example)
Define stop times¶
The following data indicates that pickup is only allowed in one zone and drop-off is only allowed in another zone. pickup and drop-off in the same zone are not allowed.
trip_id | location_id | stop_sequence | start_pickup_drop_off_window | end_pickup_drop_off_window | pickup_type | drop_off_type | pickup_booking_rule_id | drop_off_booking_rule_id |
---|---|---|---|---|---|---|---|---|
t_5298036_b_77503_tn_0 | area_713 | 1 | 06:30:00 | 20:00:00 | 2 | 1 | booking_route_74375 | booking_route_74375 |
t_5298036_b_77503_tn_0 | area_714 | 2 | 06:30:00 | 20:00:00 | 1 | 2 | booking_route_74375 | booking_route_74375 |
t_5298041_b_77503_tn_0 | area_713 | 1 | 09:00:00 | 19:00:00 | 2 | 1 | booking_route_74375 | booking_route_74375 |
t_5298041_b_77503_tn_0 | area_714 | 2 | 09:00:00 | 19:00:00 | 1 | 2 | booking_route_74375 | booking_route_74375 |
On-demand services where riders must be picked up and dropped off at specific locations¶
In certain demand-responsive services, riders are unable to specify pickup and drop-off at any location within a zone. Instead, riders can only book to be picked up and dropped off at specific designated stops(collection points/ virtual stops). An example of this is the RufBus service in Angermünde and Gartz, Germany:
Define trips¶
Route 476 offers on-demand services between each stop in the Angermünde region. They operate two services (one for weekdays and the other for weekends), with each one having a single trip_id associated.
route_id | service_id | trip_id |
---|---|---|
476 | on_demand_weekdays | 476_weekdays |
476 | on_demand_weekends | 476_weekends |
Define location groups¶
As riders can book services between each stop, to avoid defining all stop-to-stop combinations in stop_times.txt, the appropriate approach is to define these stops as a location group using location_groups.txt and location_group_stops.txt.
location_group_id | location_group_name |
---|---|
476_stops | durch den RufBus 476 bedientes Gebiet im Raum Angermünde |
location_group_id | stop_id |
---|---|
476_stops | de:12073:900340004::1 |
476_stops | de:12073:900340004::2 |
476_stops | de:12073:900340004::3 |
476_stops | de:12073:900340004::4 |
476_stops | de:12073:900340100::1 |
476_stops | de:12073:900340100::2 |
476_stops | ... |
Define booking rules¶
The 476 route service requires booking at least one hour in advance. Using booking_type = 1
indicates that the service requires up to same-day booking with advance notice. The prior_notice_duration_min = 60
indicates a requirement for booking at least 60 minutes in advance.
There are slight differences between weekday and weekend bookings, so separate booking rules can be defined for weekday and holiday services. More details can be provided in the message
field. Information and booking page links can be provided in the info_url
and booking_url
fields.
booking_rule_id | booking_type | prior_notice_duration_min | message | phone_number | info_url | booking_url |
---|---|---|---|---|---|---|
flächenrufbus_angermünde_weekdays | 1 | 60 | Anmeldung mind. 60min vorher erforderlich, per Anruf zwischen 08:00 und 24:00 möglich, oder online rund um die Uhr | +49 3332 442 755 | https://uvg-online.com/rufbus-angermuende/ | https://uvg.tdimo.net/bapp/#/astBuchungenView |
flächenrufbus_angermünde_weekends | 1 | 60 | 1€ Komfortzuschlag pro Person; Anmeldung mind. 60min vorher erforderlich, per Anruf zwischen 08:00 und 24:00 möglich, oder online rund um die Uhr | +49 3332 442 755 | https://uvg-online.com/rufbus-angermuende/ | https://uvg.tdimo.net/bapp/#/astBuchungenView |
Define stop times¶
The 476 route operates from 5:30 PM to 10:00 PM on weekdays and from 8:00 AM to 10:00 PM on weekends. The operating hours are defined using the start_pickup_drop_off_window
and end_pickup_drop_off_window
fields. Travel within the same location group requires two records in stop_times.txt with the same location_group_id
.
- The first record with
pickup_type = 2
anddrop_off_type = 1
indicates that booking pickup is allowed at the location group. - The second record with
pickup_type = 1
anddrop_off_type = 2
indicates that booking drop-off is allowed at the location group.
trip_id | location_group_id | stop_sequence | start_pickup_drop_off_window | end_pickup_drop_off_window | pickup_type | drop_off_type | pickup_booking_rule_id | drop_off_booking_rule_id |
---|---|---|---|---|---|---|---|---|
476_weekdays | 476_stops | 1 | 17:30:00 | 22:00:00 | 2 | 1 | flächenrufbus_angermünde_weekdays | flächenrufbus_angermünde_weekdays |
476_weekdays | 476_stops | 2 | 17:30:00 | 22:00:00 | 1 | 2 | flächenrufbus_angermünde_weekdays | flächenrufbus_angermünde_weekdays |
476_weekends | 476_stops | 1 | 08:00:00 | 22:00:00 | 2 | 1 | flächenrufbus-angermünde_weekdays | flächenrufbus_angermünde_weekends |
476_weekends | 476_stops | 2 | 08:00:00 | 22:00:00 | 1 | 2 | flächenrufbus-angermünde_weekdays | flächenrufbus-angermünde_weekends |
Deviated route¶
"Route deviation" refers to services where the vehicle follows a fixed route with a set sequence of stops but has the flexibility to deviate from this route to pick up or drop off riders between stops. Typically, deviations are limited to maintain service punctuality, and prior booking is required for deviated pickups and drop-offs.
In this example, the Hermann Express service in New Ulm City allows users to be picked up only at fixed stops and to be droped off at any point within a specific deviation area between these stops.
The example below has been simplified, download the Hermann Express example dataset for more details.
Define trips¶
Since this type of service still involves a series of fixed stops and a fixed schedule, defining trips is similar to normal fixed-route bus services. It requires defining the trips served by each route throughout all relevant service periods.
route_id | service_id | trip_id | share_id |
---|---|---|---|
74513 | c_67295_b_77497_d_31 | t_5374704_b_77497_tn_0 | p_1426044 |
74513 | c_67295_b_77497_d_31 | t_5374699_b_77497_tn_0 | p_1426044 |
74513 | c_67295_b_77497_d_31 | t_5374698_b_77497_tn_0 | p_1426044 |
74513 | c_67295_b_77497_d_31 | t_5374697_b_77497_tn_0 | p_1426044 |
... | ... | ... | ... |
Define zones (GeoJSON location)¶
Using locations.geojson to define zones for deviated route. Typically, deviations are limited to keep the service on schedule. Therefore, as the vehicle travels, the deviation area between each fixed stop may vary accordingly. The area for route deviation may look like the image below:
Define stop times¶
For fixed stops, define fields such as arrival_time
, departure_time
, and stop_id
in a manner similar to normal bus routes. Between fixed stops, define the zones where deviation is allowed. pickup_type = 1
and drop_off_type = 3
indicates that deviated pickup is not allowed (limiting pickup to fixed stops only), and that riders must coordinate with the driver to be dropped off in the deviation zone.
trip_id | arrival_time | departure_time | stop_id | location_id | stop_sequence | start_pickup_drop_off_window | end_pickup_drop_off_window | pickup_type | drop_off_type | shape_dist_traveled | pickup_booking_rule_id | drop_off_booking_rule_id |
---|---|---|---|---|---|---|---|---|---|---|---|---|
t_5374696_b_77497_tn_0 | 08:00:00 | 08:00:00 | 4149546 | 1 | 0 | |||||||
t_5374696_b_77497_tn_0 | radius_300_s_4149546_s_4149547 | 2 | 08:00:00 | 8:02:22 | 1 | 3 | booking_route_74513 | booking_route_74513 | ||||
t_5374696_b_77497_tn_0 | 08:02:22 | 08:02:22 | 4149547 | 3 | 1221.627114 | |||||||
t_5374696_b_77497_tn_0 | radius_300_s_4149546_s_4149548 | 4 | 08:02:22 | 8:03:00 | 1 | 3 | booking_route_74513 | booking_route_74513 | ||||
t_5374696_b_77497_tn_0 | 08:03:22 | 08:03:22 | 4149548 | 5 | 1548.216356 | |||||||
t_5374696_b_77497_tn_0 | radius_300_s_4149546_s_4149549 | 6 | 08:03:22 | 8:05:00 | 1 | 3 | booking_route_74513 | booking_route_74513 | ||||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
t_5374696_b_77497_tn_0 | 08:50:00 | 08:50:00 | 4210601 | 35 | 23429.19558 | |||||||
t_5374696_b_77497_tn_0 | 08:56:00 | 08:56:00 | 4149564 | 36 | 25320.8471 |
Routing behavior¶
Ignoring intermediate stop times records with pickup/drop-off Windows¶
When providing routing or travel time between the origin and destination, data consumers should ignore intermediate stop_times.txt records that have start_pickup_drop_off_window
and end_pickup_drop_off_window
defined. For example:
trip_id | location_id | stop_sequence | pickup_type | drop_off_type | start_pickup_drop_off_window | end_pickup_drop_off_window |
---|---|---|---|---|---|---|
tripA | Zone1 | 1 | 2 | 1 | 08:00:00 | 18:00:00 |
tripA | Zone2 | 2 | 1 | 2 | 08:00:00 | 14:00:00 |
tripA | Zone3 | 3 | 1 | 2 | 10:00:00 | 18:00:00 |
Consumers should not take Zone2 into consideration when providing routing or travel time for a trip from Zone1 to Zone3.
Zone overlap constraint¶
Simultaneous overlap of locations.geojson id
geometry, start/end_pickup_drop_off_window
time, and pickup_type
or drop_off_type
between two or more stop_times.txt records with the same trip_id
is forbidden.
For example:
(Where northportland
refers to a zone within portland
)
Forbidden
trip_id | location_id | stop_sequence | pickup_type | drop_off_type | start_pickup_drop_off_window | end_pickup_drop_off_window |
---|---|---|---|---|---|---|
tripA | portland | 1 | 2 | 1 | 08:00:00 | 12:00:00 |
tripA | northportland | 2 | 2 | 1 | 10:00:00 | 14:00:00 |
tripA | vancouver | 3 | 1 | 2 | 10:00:00 | 14:00:00 |
Allowed
trip_id | location_id | stop_sequence | pickup_type | drop_off_type | start_pickup_drop_off_window | end_pickup_drop_off_window |
---|---|---|---|---|---|---|
tripA | portland | 1 | 2 | 1 | 08:00:00 | 12:00:00 |
tripA | northportland | 2 | 2 | 1 | 12:00:00 | 14:00:00 |
tripA | vancouver | 3 | 1 | 2 | 10:00:00 | 14:00:00 |
or
trip_id | location_id | stop_sequence | pickup_type | drop_off_type | start_pickup_drop_off_window | end_pickup_drop_off_window |
---|---|---|---|---|---|---|
tripA | portland | 1 | 2 | 1 | 08:00:00 | 12:00:00 |
tripA | northportland | 2 | 1 | 2 | 10:00:00 | 14:00:00 |
tripA | vancouver | 3 | 1 | 2 | 10:00:00 | 14:00:00 |
or
trip_id | location_id | stop_sequence | pickup_type | drop_off_type | start_pickup_drop_off_window | end_pickup_drop_off_window |
---|---|---|---|---|---|---|
tripA | portland | 1 | 2 | 1 | 08:00:00 | 12:00:00 |
tripA | gresham | 2 | 2 | 1 | 10:00:00 | 14:00:00 |
tripA | vancouver | 3 | 1 | 2 | 10:00:00 | 14:00:00 |