GTFS Carriage Position - #650
Conversation
carriage_positions.txt lets producers recommend which carriage a rider should board to minimize walking at their destination, either when transferring to another platform or when leaving the station. Pathways describe navigation once a rider is off the train, but nothing said where to stand on the platform before boarding. Recommendations are relative to the front of the train at the arrival platform while riders board at the departure platform, so station_directions.txt records which side of each platform the front carriage stops at and the mirroring formula trip planners apply when the two platforms disagree.
|
@gcamp thank you for raising this proposal. Best carriage information is an important addition to the spec.
|
|
@skalexch thank you for the comments!
👍
👍
I'm mixed on that one. I don't want to complexify the implementation too much, but I see the benefits. I'm going to change but if others think it's too much let me know.
I guess my counter question is why would a consumer care about if the num carriage is true or not in the context of boarding location? If we added a field I'm not sure how we would use it (re guiding principles of speculative features) |
Review feedback on google#650. front_car_position becomes front_carriage_position, matching the "carriage" wording used everywhere else in both files. carriage_positions.txt takes the whole row as its primary key. More than one carriage can be equally good for the same destination — a platform with stairs at both ends leading to the same transfer platform is served just as well by the first or the last carriage — and the old key (stop_id, to_stop_id, via_pathway_mode, carriage_count) left room for only one of them. to_stop_id also accepts generic nodes and boarding areas now; only stations stay forbidden. A junction riders continue through, or a specific boarding area on a transfer platform, are both legitimate destinations for a recommendation, and forbidding them forced producers to point at a coarser location instead. The same-station sentence drops its stops.parent_station reference, which does not hold for boarding areas: their parent is a platform, not a station.
Review feedback on google#650, point 2. recommended_carriage counts carriages from the front of the train, the same frame as GTFS-realtime CarriageDetails.carriage_sequence, so the index does not change along a trip. Mirroring it when the two platforms disagree converts it a second time and sends riders to the opposite end of the train: a recommendation of carriage 1, authored because the exit stairs are at the nose of the train, became carriage 8 whenever the boarding platform's front_carriage_position differed, which is routine for platform pairs that merely differ in track layout. Consumers need front_carriage_position for the boarding platform only, and they need it to render the recommendation at all: a bare carriage index is not something a rider can act on, so the paragraph now shows how the index becomes an end of the platform the rider is standing on. The one case where the front of the train genuinely changes mid-trip is a physical reversal, which front_carriage_position cannot express since it describes platform geometry rather than train orientation.
|
@gcamp thanks for the changes! For the two remaining questions:
As it currently stands, the proposal works 100% clearly and correctly only if the consumer shows a graphic of the relative position of the rider after doing the calculation I like both concepts of being able to show either the actual carriage or a relative position [FRONT, MIDDLE, BACK]. But I think both of them being modelled using the same fields might cause misinterpretation. |
My point is that is not something we want to do. I'm not against this use case, but it's a speculative feature unless somebody else ask. What we could do is rename the field and state that it's only a virtual representation of the carriage length, and keep the door open for an other field in the future. |
|
|
||
| | Field Name | Type | Presence | Description | | ||
| | ------ | ------ | ------ | ------ | | ||
| | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform.<br><br>Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).<br><br>Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | |
There was a problem hiding this comment.
since station_directions.txt is actually concerned with only "stops" or "platforms" (location_type = 0), and actually forbids stations (location_type = 1), should the name of this file be changed? Possibly to stop_directions.txt or platform_directions.txt?
There was a problem hiding this comment.
Good point, platform_directions.txt makes sense to me
|
|
||
| | Field Name | Type | Presence | Description | | ||
| | ------ | ------ | ------ | ------ | | ||
| | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the platform.<br><br>Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).<br><br>Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | |
There was a problem hiding this comment.
what would an empty stop_id in station_directions.txt signify? Would this select all stops in one direction? I think this behavior should be clarified
There was a problem hiding this comment.
That field is set as required, so you can't have it empty(?)
There was a problem hiding this comment.
ahh sorry, I incorrectly read "location_type=0 or empty" as meaning that the stop could be a stop of location_type=0 or stop_id could be empty. and Github isn't letting me resolve for some reason 🙃
| | `stop_id` | Foreign ID referencing `stops.stop_id` | **Required** | Identifies the arrival platform.<br><br>Must contain a `stop_id` that identifies a platform (`location_type=0` or empty).<br><br>Values for `stop_id` that identify stations (`location_type=1`), entrances/exits (`location_type=2`), generic nodes (`location_type=3`) or boarding areas (`location_type=4`) are forbidden. | | ||
| | `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination: a transfer platform or one of its boarding areas, a station entrance/exit, or a generic node such as a junction riders continue through.<br><br>Must contain a `stop_id` that identifies a platform (`location_type=0` or empty), an entrance/exit (`location_type=2`), a generic node (`location_type=3`) or a boarding area (`location_type=4`). Values for `stop_id` that identify stations (`location_type=1`) are forbidden.<br><br>Should belong to the same station as `stop_id`, as the recommendation describes walking within a station, but may reference a location in another station when physically connected platforms are modeled separately.<br><br>When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | | ||
| | `recommended_carriage` | Positive integer | **Required** | The recommended carriage to board, numbered from the first carriage in the direction of travel, which has a value of `1`, as in GTFS-realtime `CarriageDetails.carriage_sequence`. May represent a logical position rather than an exact carriage number. Must be less than or equal to `carriage_count`. | | ||
| | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | |
There was a problem hiding this comment.
| | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | | |
| | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. If `carriage_count_precision=0` or empty, represents logical divisions (e.g., 3 for front/middle/back). If `carriage_count_precision=1`, represents an exact carriage count. | | |
| | `carriage_count_precision` | Enum | Optional | Indicates if `carriage_count` represents relative divisions or an exact carriage count. Valid options are:<br><br>`0` or empty - `carriage_count` represents relative divisions (e.g., 3 for front/middle/back). <br>`1` - `carriage_count` is an actual count of discrete carriages. <br><br> If no values are provided, all `carriage_count` values should be considered to represent relative divisions. | |
@skalexch I had a similar reservation about interpretations of logical vs. exact carriage counts. I think it's important that the producer be able to communicate to the consumer how exactly to interpret these values. What do you and @gcamp think of this option?
There was a problem hiding this comment.
@nlee-septa +1 for any field that clarifies how the boarding position should be considered.
Just one thought: I'd change the name to something other than "precision" (if there is any word that conveys that the distinction is between actual number and category). To me, "precision" give an impression of mathematical approximation.
There was a problem hiding this comment.
carriage_count_is_virtual would be what I would suggest.
I think this opens the door to having a label on each carriage, I asked the questions on how to model that in the vehicle proposal here.
There was a problem hiding this comment.
Maybe carriage_count_exactness (or carriage_count_relativeness, since the default is "relative")? Or simply carriage_count_type, though I prefer more descriptive field names where possible.
Inspiration for this field comes from stop_times.timepoint, which conveys a similar meaning of "another field should be taken as exact or inexact". Unfortunately the nomenclature doesn't transfer well.
There was a problem hiding this comment.
Missed your earlier response, sorry! I like carriage_count_is_virtual or carriage_count_is_relative.
| | `to_stop_id` | Foreign ID referencing `stops.stop_id` | Optional | Identifies a specific destination: a transfer platform or one of its boarding areas, a station entrance/exit, or a generic node such as a junction riders continue through.<br><br>Must contain a `stop_id` that identifies a platform (`location_type=0` or empty), an entrance/exit (`location_type=2`), a generic node (`location_type=3`) or a boarding area (`location_type=4`). Values for `stop_id` that identify stations (`location_type=1`) are forbidden.<br><br>Should belong to the same station as `stop_id`, as the recommendation describes walking within a station, but may reference a location in another station when physically connected platforms are modeled separately.<br><br>When empty, the recommendation applies as a general default for the station. When provided, it gives a destination-specific recommendation that takes priority over the general default. | | ||
| | `recommended_carriage` | Positive integer | **Required** | The recommended carriage to board, numbered from the first carriage in the direction of travel, which has a value of `1`, as in GTFS-realtime `CarriageDetails.carriage_sequence`. May represent a logical position rather than an exact carriage number. Must be less than or equal to `carriage_count`. | | ||
| | `carriage_count` | Positive integer | **Required** | Number of carriage positions in this configuration. May represent logical divisions (e.g., 3 for front/middle/back) rather than actual carriage count. | | ||
| | `via_pathway_mode` | Enum | Optional | Mode of the pathway the rider takes to reach `to_stop_id`, for which `recommended_carriage` is the closest carriage. Valid options are a subset of [pathways.txt](#pathwaystxt) `pathway_mode`:<br><br>`2` - Stairs.<br>`4` - Escalator.<br>`5` - Elevator.<br><br>Riders with different accessibility needs take different pathways out of the same platform, so a producer may publish one record per mode. When empty, the recommendation applies regardless of how the rider continues. | |
There was a problem hiding this comment.
| | `via_pathway_mode` | Enum | Optional | Mode of the pathway the rider takes to reach `to_stop_id`, for which `recommended_carriage` is the closest carriage. Valid options are a subset of [pathways.txt](#pathwaystxt) `pathway_mode`:<br><br>`2` - Stairs.<br>`4` - Escalator.<br>`5` - Elevator.<br><br>Riders with different accessibility needs take different pathways out of the same platform, so a producer may publish one record per mode. When empty, the recommendation applies regardless of how the rider continues. | | |
| | `via_pathway_mode` | Enum | Optional | Mode of the pathway (or series of successive pathways) the rider takes to reach `to_stop_id`, for which `recommended_carriage` is the closest carriage. Valid options are a subset of [pathways.txt](#pathwaystxt) `pathway_mode`:<br><br>`2` - Stairs.<br>`4` - Escalator.<br>`5` - Elevator.<br><br>Riders with different accessibility needs take different pathways out of the same platform, so a producer may publish one record per mode. When empty, the recommendation applies regardless of how the rider continues.<br><br>If `via_pathway_mode=2`, the connecting pathway(s) MAY have any `pathway_mode` value.<br>If `via_pathway_mode=4`, the connecting pathway(s), MUST NOT have `pathway_mode=2` (stairs).<br>If `via_pathway_mode=5`, the connecting pathway(s) MUST NOT have `pathway_mode=2` (stairs) or `pathway_mode=4` (escalator).| |
Adding language like this will prevent a possible conflict where carriage_positions.txt indicates an elevator is available, but pathways.txt only contains stair pathways.
There was a problem hiding this comment.
I know that in most stations the hierarchy is this: Either stairs or stairs+escalator or stairs+escalator+elevator.
But to truly avoid conflicts, pathways.txt (if exists) should cover all possible pathways for that pair of station nodes.
So a cleaner logic would be:
If pathways.txt has at least one entry from stop_id to to_stop_id or a bidirectional entry between stop_id and to_stop_id, the value for via_pathway_mode should exist in pathways.txt for that pair of stop_ids.
That would lead to:
- If pathways for that pair of nodes do not exist, no check is necessary. In this case,
carriage_positions.txtis the direct source of truth. - If at least one pathway for that pair of nodes exists, then all possible pathways should be in
pathways.txt. In this case,carriage_positions.txtis pulling from the COMPLETE source of truth.
There was a problem hiding this comment.
What if carriage_positions.txt indicates that an elevator pathway is available between stop_id and to_stop_id, but no such pathway is in pathways.txt? I think the spec should explicitly state that is not valid, because either pathways.txt does not contain all possible pathways, or carriage_positions.txt describes a pathway that does not exist (and it's not obvious which file has the error). Alternatively, instruction on which should prevail could be added.
Summary
This proposal adds two new files,
station_directions.txtandcarriage_positions.txt, that let a feed express which carriage a rider should board to minimize walking at their destination.Describe the Problem
To speed up their trip, passengers want to know which carriage to board for a fast transfer or a fast exit at their destination.
pathways.txtcan give a rider turn-by-turn directions inside a station, yet nothing tells them where to stand on the platform before boarding. Agencies often have this information but GTFS has no way to encode it.Discussion started in #614. Thanks @vikiawv @jfabi for the comments and suggestions!
Proposed Solution
Two new files:
station_directions.txtdefines which side of the platform the front carriage stops at. One record per platform covers all trips, and optionalroute_idanddirection_idrecords take priority over that default so special configurations can be modeled, such as a platform on a bidirectional single-track section. Conditionally Required: required whencarriage_positions.txtis provided, since a recommendation cannot be interpreted without knowing platform orientation.carriage_positions.txtmaps an arrival platform, and optionally a specific transfer platform or station entrance/exit, to the recommended carriage to board. The optionalfacility_type, which reuses thepathways.txtpathway_modevalues for stairs, escalator and elevator, covers cases where the elevator serving a destination is several carriages away from the stairs serving the same destination, so riders needing step-free access can be sent to a different carriage.Recommendations are expressed relative to the front of the train at the arrival platform. When the departure platform is oriented the other way, planners mirror the carriage with
carriage_count - recommended_carriage + 1, so a single record stays usable regardless of which end of the train the rider boards from.recommended_carriageis numbered from1for the first carriage in the direction of travel, matching GTFS-realtimeCarriageDetails.carriage_sequence. Consumers that already show per-carriage occupancy from real-time data can then combine both without translating between two numbering schemes for the same concept, which would be a likely source of off-by-one errors.carriage_countis part of the primary key, which lets a platform carry different recommendations for trains of different lengths, and producers without exact carriage positions can use logical divisions instead:carriage_count=3withrecommended_carriage=1simply means "board near the front".Here is an example of a dataset I made from the Paris GTFS and the open data carriage position CSV they have.
Type of change
GTFS Schedule
Additional Information
This proposal is deliberately a small subset of what GTFS-VehicleBoardings attempted: it does not model platform sections or train formations, and instead encodes only the boarding recommendation itself.
PR #636 proposes
vehicles.txtalong with avehicle_classon routes.txt and trips.txt. This proposal does not depend on it and stays usable on its own throughcarriage_count, but if #636 is adopted, an optionalvehicle_classincarriage_positions.txtwould be a natural follow-up to select the right configuration for a trip.Proposed Discussion Period
I recommend reserving one month for discussion, since this adds two new files and affects station modeling.
Testing Details
Proposal Update Tracker