-
Notifications
You must be signed in to change notification settings - Fork 206
[GTFS-Fares v2] Add Distance-Based Fares #556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
I have a question about From what I read before, the Netherland system is that, for transfers across operators, the distance-based fares are completely separate (no joining); for transfers within the same operator, the distance accumulates (i.e. The whole |
|
@miklcct thank you for your remark. After reviewing the modeling for the Netherlands' fares, you are absolutely correct. It turns out that the current proposal misses a key piece in the fare calculation. As referenced in the notes for the 26/11/2024 Fares WGM, @skinkie shared an example with an equation explaining how the fare works. E.g. in the case of a GVB (4 km) + Arriva (2 km) trip, the fare should be calculated as follows: The current proposal overlooked We'll write something up to address this and try to figure out where this complex case fits in the proposal, or if other alternatives can be considered to address it. We'll share it soon. @skinkie can also probably provide more context into how NL fares are calculated. |
|
Hello @miklcct . As promised, we have created a document exploring the possibilities of modelling the Netherlands’ case and the limitations of Fares v2 in this context. The main outcomes are as follows:
The full investigation is available here. This is also relevant for @skinkie to take a look at. We can discuss this at the next working group meeting as well. |
Updated distance fields to use float instead of integer.
Updated formatting for better clarity and consistency.
|
Based on the conversation from October's Fares working group, the following adjustments were made:
|
gtfs/spec/en/reference.md
Outdated
| | `continuous_pickup` | Enum | **Conditionally Forbidden** | Indicates that the rider can board the transit vehicle at any point along the vehicle’s travel path as described by [shapes.txt](#shapestxt), from this `stop_time` to the next `stop_time` in the trip’s `stop_sequence`. Valid options are: <br><br>`0` - Continuous stopping pickup. <br>`1` or empty - No continuous stopping pickup. <br>`2` - Must phone agency to arrange continuous stopping pickup. <br>`3` - Must coordinate with driver to arrange continuous stopping pickup. <br><br>If this field is populated, it overrides any continuous pickup behavior defined in [routes.txt](#routestxt). If this field is empty, the `stop_time` inherits any continuous pickup behavior defined in [routes.txt](#routestxt).<br><br>**Conditionally Forbidden**:<br>- **Forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.<br> - Optional otherwise. | | ||
| | `continuous_drop_off` | Enum | **Conditionally Forbidden** | Indicates that the rider can alight from the transit vehicle at any point along the vehicle’s travel path as described by [shapes.txt](#shapestxt), from this `stop_time` to the next `stop_time` in the trip’s `stop_sequence`. Valid options are: <br><br>`0` - Continuous stopping drop off. <br>`1` or empty - No continuous stopping drop off. <br>`2` - Must phone agency to arrange continuous stopping drop off. <br>`3` - Must coordinate with driver to arrange continuous stopping drop off. <br><br>If this field is populated, it overrides any continuous drop-off behavior defined in [routes.txt](#routestxt). If this field is empty, the `stop_time` inherits any continuous drop-off behavior defined in [routes.txt](#routestxt).<br><br>**Conditionally Forbidden**:<br>- **Forbidden** if `start_pickup_drop_off_window` or `end_pickup_drop_off_window` are defined.<br> - Optional otherwise. | | ||
| | `shape_dist_traveled` | Non-negative float | Optional | Actual distance traveled along the associated shape, from the first stop to the stop specified in this record. This field specifies how much of the shape to draw between any two stops during a trip. Must be in the same units used in [shapes.txt](#shapestxt). Values used for `shape_dist_traveled` must increase along with `stop_sequence`; they must not be used to show reverse travel along a route.<br><br>Recommended for routes that have looping or inlining (the vehicle crosses or travels over the same portion of alignment in one trip). See [`shapes.shape_dist_traveled`](#shapestxt). <hr>*Example: If a bus travels a distance of 5.25 kilometers from the start of the shape to the stop,`shape_dist_traveled`=`5.25`.*| | ||
| | `fare_distance_units_traveled` | Non-negative integer | Conditionally Required | Fare distance units traveled along the trip, from the first stop to the stop specified in this record. `fare_distance_units_traveled` is used to match a fare leg rule from [fare_leg_rules.txt](#fare_leg_rulestxt) whose distance interval [`min_distance_units`, `max_distance_units`) includes `fare_distance_units_traveled`. <br><br> `fare_distance_units_traveled` does not have to be in the same unit as `stop_times.shape_dist_traveled`. <br><br> If the fare is calculated based on the distance covered by the route shape, `fare_distance_units_traveled` may correspond to `stop_times.shape_dist_traveled` (measured in meters) or to its rounded value (floor or ceiling), depending on the fare structure. If the fare is calculated based on stops, `fare_distance_units_traveled` may represent the number of stops crossed. `fare_distance_units_traveled` may also be adjusted by adding or subtracting arbitrary values to represent fare discounts or supplements. <br><br> **Conditionally Required** <br>- Required if the `route_id` of the `trip_id` of this stop time is part of a `network_id` which is associated to a distance-based `leg_group_id` in `fare_leg_rules.txt`.<br> - Forbidden otherwise.| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fare_distance_units_traveledis used to match a fare leg rule from fare_leg_rules.txt whose distance interval [min_distance_units,max_distance_units) includesfare_distance_units_traveled.
This may be interpreted as matching the cumulative distance from the first stop? But passengers may board mid-route.
nit: [min_distance_units, max_distance_units) bracket consistency
gtfs/spec/en/reference.md
Outdated
| | `from_stop_id` | Foreign ID referencing `stops.stop_id`| **Conditionally Required** | Matches a pre-transfer leg that ends at the specified stop (`location_type=0` or empty) or station (`location_type=1`).<br><br>Conditionally Required:<br> - **Required** if `to_stop_id` is defined.<br> - Optional otherwise. | | ||
| | `to_stop_id` | Foreign ID referencing `stops.stop_id`| **Conditionally Required** | Matches a post-transfer leg that starts at the specified stop (`location_type=0` or empty) or station (`location_type=1`).<br><br>Conditionally Required:<br> - **Required** if `from_stop_id` is defined.<br> - Optional otherwise. | | ||
| | `duration_limit` | Positive integer | **Optional** | Defines the duration limit of the transfer between the legs.<br><br>Must be expressed in integer increments of seconds.<br><br>If there is no duration limit, `fare_leg_join_rules.duration_limit` must be empty. | | ||
| | `duration_limit_type` | Enum | **Conditionally Required** | Defines the relative start and end of `fare_leg_join_rules.duration_limit`.<br><br>Valid options are:<br>`0` - Between the departure fare validation of the current leg and the arrival fare validation of the next leg.<br>`1` - Between the departure fare validation of the current leg and the departure fare validation of the next leg.<br>`2` - Between the arrival fare validation of the current leg and the departure fare validation of the next leg.<br>`3` - Between the arrival fare validation of the current leg and the arrival fare validation of the next leg.<br><br>Conditionally Required:<br>- Required if `fare_leg_join_rules.duration_limit` is defined.<br>- Forbidden if `fare_leg_join_rules.duration_limit` is empty. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps replace "current" and "next" by "first" and "last"
This PR adds distance-based fares, it covers two use cases:
The PR has a few adjustments to the spec:
fare_distance_units_traveledinstop_times.txtmin_distance_unitsabdmax_distance_unitsinfare_leg_rules.txtmin_distance_unitsandmax_distance_unitsto the primary key offare_leg_rules.txtfare_leg_join_rules.txtto cover distance-based legs and includeduration_limitandduration_limit_type(similar tofare_transfer_rules.txt) to limit the fare leg within a time window.For more details and examples, please refer to the distance-based fares proposal
The proposal doc includes an example showcasing how distance-based fares for TfNSW can be implemented in Fares v2.
Note: A previous version of this PR separated the leg join mechanism for distance-based legs in a file called
fare_leg_distance_rules.txtto cover distance-based fares of the Netherlands (Miro). However, the mechanism was still insufficient to fully model the fare structure. Therefore, we simplified the PR to be able to model most fares around the world usingfare_leg_rules.txtandfare_leg_join_rules.txt.