cal-itp / operational-data-standard

The Transit Operational Data Standard is an open standard for representing the transit schedules used by drivers, dispatchers, and planners to carry out transit operations.
https://ods.calitp.org
Apache License 2.0
26 stars 6 forks source link

add runtimes.txt #42

Open BTollison opened 9 months ago

BTollison commented 9 months ago

The purpose of this proposal is to easily send running time information between software packages. In the current state, software must interpolate the running times from trips. However, if a trip is modified or if trips were generated with runtimes that are not "segment" based, it may be impossible to interpolate them. This is especially problematic in network planning software, where a user may want to modify trips and frequency but has no insight into when running times change during the day.

service_Id From calendar.txt or calendar_dates.txt, runtimes are tied to a service_id to ensure that they are up to date and relevant for the selected route and trips.

route_id From routes.txt, route_id is used to tie the runtime back to a route if relevant. When it is left blank it is assumed to be global.

direction_id From trips.txt, direction_id is required when route_id is present to differentiate runtime direction.

shape_id Shape_id is used to tie a runtime to a particular route_id and shape_id. If shape_id is present then route_id and direction_id should have values.

from The from location that the runtime applies to.

to The to location that the runtime applies to.

start_time The start time of the period of which the runtime applies.

end_time The end time of the period of which the runtime applies.

runtime The amount of time it takes to travel from one point to another in seconds.

is_deadhead Denotes if the runtime applies to in service trips or only deadhead trips.

runtime_style Enum value for types of runtime. There are various methods for distributing running time, however it is not possible at the time of this proposal to add all of them due to a lack of information on how some of these runtimes are applied by some software.

  1. Requires proposed runtime_build_point = 1 in stop_times.txt from issue #43
  2. Example: f there are 2 running time periods, the first being between 6:00:00 and 6:29:59 and the second between 6:30:00 and 6:59:59 all between segments A, B, C, and D (A > B, B > C, C > D). For the first running time period, all segments receive 5 minutes and for the second period all segments receive 6 minutes. If we set runtime_build_point at point B and the trip passes that point at 6:29, every segment of this trip will receive running time from the first period of run times including segment A > B. So the total trip duration will be 15 minutes. If the trip were to depart at 6:30 at point B, all segments of this trip would receive 18 minutes.
skyqrose commented 9 months ago

It should be a stop_id when route_id is present or ops_location_id when is_deadhead = 1 Deadheads can happen to/from revenue stops.

In revenue service, how do the runtimes interact with dwell times? Are the runtimes always between adjacent stops, or could you have a runtime that covers multiple stations including their dwell times? Are the start/end always the arrival at a station, always the departure, or could it be either?

Would this proposal also need a way to describe typical dwell times and turnaround times?

jeffkessler-keolis commented 9 months ago

I realize this is not currently supported in ODS, but I'll reiterate something I brought forth in some of the preliminary working group sessions (to minimize headache in adoption/extension down the road): the rail world often includes a number of non-public locations and/or timepoints on revenue trips.

The broader implication is that, in order for ODS to be adopted in the rail world, we need a mechanism to supplement existing stop_times.txt entries with times at ops_location.txt locations.

The specific implication relevant to this thread, though, is that the rail world requires the ability to have from and to locations reflect a pairing of both a stop_id AND an ops_location_id. Otherwise, as an example, an export from our scheduling system's database would omit standardized runtimes for any pair of subsequent passenger stops for which a switch or signal is located between the two stations.

Likewise, to Sky's point as it applies to default dwells, I think it's worth including standardized dwell times in this file, too. I believe many systems already model dwell as simply a runtime between a location and itself.

BTollison commented 9 months ago

For dwell times, I think it would be valid to have a runtime between 1 point.

runtimes.txt        
start_time end_time from to runtime
6:00 6:29:59 a b 5
6:00 6:29:59 b b 2
6:00 6:29:59 b c 5

So where to from / to is both B that means that the vehicle should not move for 2 minutes.

For the situation where a runtime is between a service and non-service location, I guess in theory that could work right? The main thing would be the ops_location_id's and stop_id's need to be generated in a way where all values are unique. Is that currently how we think about this? I am definitely for this, that would eliminate the need to have separate deadhead and stop_id fields when looking to assign a from and a to location.

skyqrose commented 9 months ago

deadhead_times.txt already has separate stop_id and ops_location_id columns, so I wouldn't mind this file, having four from_ops_location_id | from_stop_id | to_ops_location_id | to_stop_id columns, but I think we should also separately note in ops_locations.txt that the ops_location_ids should ("SHOULD"? "MUST"?) be different from stop_ids.

Edit: ops location ids are now going to be added as a _supplement into stops.txt so the column will just be to/from_stop_id now.

skyqrose commented 9 months ago

If we represent dwell times as a runtime from a station to itself, is there a way to represent turnaround times at the end of the route? That might be useful for, e.g., generating predictions for when a return trip is going to start.

skyqrose commented 9 months ago

Minor idea: If the end_time is exclusive instead of inclusive, then the end_times could be like 07:00:00 instead of 06:59:59, which might be easier to deal with and prevent bugs. (E.g. if someone looks up the current runtime when it's 06:59:59.581.)

BTollison commented 9 months ago

Yeah, I see how stop_id and ops_location_id have been incorporated into the other files, it feels like more of a workaround because there's no explicit "they must all be unique" clause. So, I am fully agreed that this would be the best approach.

We currently represent turnaround times that way. So long as the scheduling team has deadheads (ideally with distance), that should work.

I like the idea of exclusive, :) although I have never encountered a scheduling team that goes beyond seconds I could see how a real-time system may get tripped up!

jeffkessler-keolis commented 6 months ago

To follow up on my earlier comment (https://github.com/cal-itp/operational-data-standard/issues/42#issuecomment-1836723950) which perhaps foreshadowed the supplemental GTFS concept (https://github.com/cal-itp/operational-data-standard/issues/55), we should be all set here with the caveat that from and to must now always equal a stop_id in the ODS-supplemented GTFS data (i.e. public GTFS after processing the _supplement files).

For dwells, I support treating them as runtime from x to x (akin to how most scheduling systems support it). Should the need ever arise to define turnaround times, I'd suggest those just be modeled as runtimes from a1 to a2 where a1 and a2 are children of the same parent (presumably a in this example) in the ODS-supplemented GTFS, even if modeled to the same stop in the public GTFS.

And yes, I very much like @skyqrose's suggestion of exclusive for end_time, even if most scheduling systems are currently inclusive.

safrazier17 commented 6 months ago

@BTollison do you agree with @skyqrose and @jeffkessler-keolis 's comments above on handling?

BTollison commented 6 months ago

@safrazier17 Agreed.

@jeffkessler-keolis Turnaround times are often modeled as runtimes between two children of a parent stop, so this indeed is covered (although perhaps different for rail due to collision avoidance needs?)

BTollison commented 1 week ago

Revised for TODS 2.0

service_Id From calendar.txt or calendar_dates.txt, runtimes.txtentries are tied to a service_id to ensure that they are up to date and relevant for the selected route and trips.

route_id From routes.txt, route_id is used to tie the entry back to a route if relevant. When it is left blank it is assumed to be global.

direction_id From trips.txt, direction_id is required when route_id is present to differentiate runtime direction.

shape_id Shape_id is used to tie a runtime to a particular route_id and shape_id. If shape_id is present then route_id and direction_id should have values.

from The from location that the runtime applies to.

to The to location that the runtime applies to.

start_time The start time of the period of which the runtime applies.

end_time The end time of the period of which the runtime applies.

runtime The amount of time it takes to travel from one point to another in seconds.

is_revenue Denotes if the runtime applies to in service trips or only non-revenue trips.

runtime_style Enum value for types of runtime. There are various methods for distributing running time, however it is not possible at the time of this proposal to add all of them due to a lack of information on how some of these runtimes are applied by some software.

  1. Requires proposed runtime_build_point = 1 in stop_times_supplement.txtfrom issue #43
  2. Example: f there are 2 running time periods, the first being between 6:00:00 and 6:29:59 and the second between 6:30:00 and 6:59:59 all between segments A, B, C, and D (A > B, B > C, C > D). For the first running time period, all segments receive 5 minutes and for the second period all segments receive 6 minutes. If we set runtime_build_point at point B and the trip passes that point at 6:29, every segment of this trip will receive running time from the first period of run times including segment A > B. So the total trip duration will be 15 minutes. If the trip were to depart at 6:30 at point B, all segments of this trip would receive 18 minutes.
BTollison commented 1 week ago

@jeffkessler-keolis has a concern about running times that are regardling vehicles that are intended to stop and vehicles that are inteded to pass through locations. not_stopping as a boolean value could be a solution, where 0 = stopping and 1 would mean that the vehicle does not stop. You can have two entries with the opposite boolean value to describe both situations. I shall investigate if this applies to other parts of the world to ensure completeness.

jeffkessler-keolis commented 1 week ago

@BTollison's note is correct; for further context, the distinction that matters is whether something is passing at full-speed or a reduced speed (either stopping at a passenger station or slowing to diverge/"turn" at a switch). The default assumption for all points should be "stopping," unless otherwise designated. Since this parameter is dependent on the condition at both the start and end locations, this could either be Boolean fields of passing_from and passing_to, that each default to 0 ("stopping" / slowing for a reduced speed diverging move), or 1 ("passing" the point at full-speed). Another valid approach, per @BTollison's suggestion, would be to use a single field with an enum, such as: