Skip to content

Commit 0fe833b

Browse files
Merge pull request opentripplanner#6909 from flaktack/feature/modified-gtfs-rt-patterns
Improve handling of realtime updated StopPatterns
2 parents 82839f5 + cfa755c commit 0fe833b

9 files changed

Lines changed: 1059 additions & 289 deletions

File tree

application/src/main/java/org/opentripplanner/routing/algorithm/raptoradapter/transit/mappers/RealTimeRaptorTransitDataUpdater.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,31 @@ public RealTimeRaptorTransitDataUpdater(TimetableRepository timetableRepository)
6666
this.timetableRepository = timetableRepository;
6767
}
6868

69+
/// Updates the real-time [RaptorTransitData] to use the modified timetables.
70+
///
71+
/// This method bridges the different update approaches:
72+
/// 1. `updatedTimetables` and `timetables` only contains [Timetable]s with real-time
73+
/// updates. This means that removed items are not present.
74+
/// 2. [RaptorTransitData] requires applying the changes to a previous snapshot: adding,
75+
/// updating and removing timetables.
76+
///
77+
/// To support this the method has three tasks:
78+
/// 1. Collect [TripPatternForDate]s which have invalidated data (`oldTripPatternsForDate`).
79+
/// Trips may change in multiple ways and because of that may move between [TripPattern]s. To
80+
/// track a [TripIdAndServiceDate] it's previous state needs to be stored so that all relevant
81+
/// places may be updated.
82+
/// * a trip may have a new (real-time) Timetable, which results in two updated [Timetable]s
83+
/// * a trip may move between scheduled [StopPattern]s and/or real-time [StopPattern]s
84+
/// 2. Collect [TripPatternForDate]s which have valid data (`newTripPatternsForDate`).
85+
/// There are two options:
86+
/// 1. an update was received
87+
/// 2. no update was received, and so the previous updated should be removed. If the update
88+
/// was for a scheduled trip, then the schedule should be restored.
89+
/// 3. Remove the `oldTripPatternsForDate` and add the `newTripPatternsForDate` to the
90+
/// [RaptorTransitData].
91+
///
92+
/// @param updatedTimetables that changed with the current snapshot
93+
/// @param timetables which are affected by real-time updates
6994
public void update(
7095
Collection<Timetable> updatedTimetables,
7196
Map<TripPattern, SortedSet<Timetable>> timetables
@@ -204,7 +229,8 @@ public void update(
204229
patternsForDate.remove(tripPatternForDate);
205230
}
206231
} else {
207-
LOG.warn("Could not fetch timetable for {}", pattern);
232+
LOG.warn("Could not fetch timetable for {}, removing.", pattern);
233+
patternsForDate.remove(tripPatternForDate);
208234
}
209235
}
210236
}

application/src/main/java/org/opentripplanner/updater/trip/gtfs/TripTimesUpdater.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.Iterator;
1616
import java.util.List;
1717
import java.util.Map;
18+
import java.util.Objects;
1819
import java.util.Optional;
1920
import java.util.OptionalInt;
2021
import javax.annotation.Nullable;
@@ -132,10 +133,26 @@ public static Result<TripTimesPatch, UpdateError> createUpdatedTripTimesFromGtfs
132133
}
133134

134135
if (match) {
135-
update.stopHeadsign().ifPresent(x -> builder.withStopHeadsign(index, x));
136-
update.pickup().ifPresent(x -> updatedPickups.put(index, x));
137-
update.dropoff().ifPresent(x -> updatedDropoffs.put(index, x));
138-
update.assignedStopId().ifPresent(x -> replacedStopIndices.put(index, x));
136+
var scheduledStopId = timetable.getPattern().getStop(i).getId().getId();
137+
var scheduledStopHeadsign = tripTimes.getHeadsign(i);
138+
var scheduledPickup = timetable.getPattern().getBoardType(i);
139+
var scheduledDropoff = timetable.getPattern().getAlightType(i);
140+
update
141+
.stopHeadsign()
142+
.filter(x -> !Objects.equals(x, scheduledStopHeadsign))
143+
.ifPresent(x -> builder.withStopHeadsign(index, x));
144+
update
145+
.pickup()
146+
.filter(x -> x != scheduledPickup)
147+
.ifPresent(x -> updatedPickups.put(index, x));
148+
update
149+
.dropoff()
150+
.filter(x -> x != scheduledDropoff)
151+
.ifPresent(x -> updatedDropoffs.put(index, x));
152+
update
153+
.assignedStopId()
154+
.filter(x -> !Objects.equals(x, scheduledStopId))
155+
.ifPresent(x -> replacedStopIndices.put(index, x));
139156

140157
var scheduleRelationship = update.scheduleRelationship();
141158
// Handle each schedule relationship case
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.opentripplanner.transit.model._data;
2+
3+
import java.time.Duration;
4+
import java.util.List;
5+
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters;
6+
import org.opentripplanner.routing.api.request.RouteRequest;
7+
import org.opentripplanner.transit.model.site.StopTransferPriority;
8+
9+
class TestTransitTuningParameters implements TransitTuningParameters {
10+
11+
@Override
12+
public boolean enableStopTransferPriority() {
13+
return false;
14+
}
15+
16+
@Override
17+
public Integer stopBoardAlightDuringTransferCost(StopTransferPriority key) {
18+
return 0;
19+
}
20+
21+
@Override
22+
public int transferCacheMaxSize() {
23+
return 0;
24+
}
25+
26+
@Override
27+
public Duration maxSearchWindow() {
28+
return null;
29+
}
30+
31+
@Override
32+
public List<Duration> pagingSearchWindowAdjustments() {
33+
return List.of();
34+
}
35+
36+
@Override
37+
public List<RouteRequest> transferCacheRequests() {
38+
return List.of();
39+
}
40+
}

application/src/test/java/org/opentripplanner/transit/model/_data/TransitTestEnvironment.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import java.time.ZoneId;
77
import org.opentripplanner.LocalTimeParser;
88
import org.opentripplanner.model.TimetableSnapshot;
9+
import org.opentripplanner.routing.algorithm.raptoradapter.transit.RaptorTransitData;
10+
import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.RaptorTransitDataMapper;
11+
import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.RealTimeRaptorTransitDataUpdater;
912
import org.opentripplanner.transit.service.DefaultTransitService;
1013
import org.opentripplanner.transit.service.TimetableRepository;
1114
import org.opentripplanner.transit.service.TransitService;
@@ -40,8 +43,14 @@ public static TransitTestEnvironmentBuilder of(LocalDate serviceDate, ZoneId tim
4043
this.timetableRepository = timetableRepository;
4144

4245
this.timetableRepository.index();
46+
this.timetableRepository.setRaptorTransitData(
47+
RaptorTransitDataMapper.map(new TestTransitTuningParameters(), timetableRepository)
48+
);
49+
this.timetableRepository.setRealtimeRaptorTransitData(
50+
new RaptorTransitData(timetableRepository.getRaptorTransitData())
51+
);
4352
this.snapshotManager = new TimetableSnapshotManager(
44-
null,
53+
new RealTimeRaptorTransitDataUpdater(timetableRepository),
4554
TimetableSnapshotParameters.PUBLISH_IMMEDIATELY,
4655
() -> defaultServiceDate
4756
);

application/src/test/java/org/opentripplanner/updater/trip/GtfsRtTestHelper.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static org.opentripplanner.updater.trip.UpdateIncrementality.FULL_DATASET;
44

55
import com.google.transit.realtime.GtfsRealtime;
6+
import java.time.LocalDate;
67
import java.util.List;
78
import org.opentripplanner.transit.model._data.TransitTestEnvironment;
89
import org.opentripplanner.updater.spi.UpdateResult;
@@ -20,7 +21,7 @@ public class GtfsRtTestHelper {
2021
this.gtfsAdapter = new GtfsRealTimeTripUpdateAdapter(
2122
transitTestEnvironment.timetableRepository(),
2223
transitTestEnvironment.timetableSnapshotManager(),
23-
() -> transitTestEnvironment.defaultServiceDate()
24+
transitTestEnvironment::defaultServiceDate
2425
);
2526
}
2627

@@ -32,13 +33,29 @@ public TripUpdateBuilder tripUpdateScheduled(String tripId) {
3233
return tripUpdate(tripId, GtfsRealtime.TripDescriptor.ScheduleRelationship.SCHEDULED);
3334
}
3435

36+
public TripUpdateBuilder tripUpdateScheduled(String tripId, LocalDate serviceDate) {
37+
return tripUpdate(
38+
tripId,
39+
serviceDate,
40+
GtfsRealtime.TripDescriptor.ScheduleRelationship.SCHEDULED
41+
);
42+
}
43+
44+
public TripUpdateBuilder tripUpdate(
45+
String tripId,
46+
GtfsRealtime.TripDescriptor.ScheduleRelationship scheduleRelationship
47+
) {
48+
return tripUpdate(tripId, transitTestEnvironment.defaultServiceDate(), scheduleRelationship);
49+
}
50+
3551
public TripUpdateBuilder tripUpdate(
3652
String tripId,
53+
LocalDate serviceDate,
3754
GtfsRealtime.TripDescriptor.ScheduleRelationship scheduleRelationship
3855
) {
3956
return new TripUpdateBuilder(
4057
tripId,
41-
transitTestEnvironment.defaultServiceDate(),
58+
serviceDate,
4259
scheduleRelationship,
4360
transitTestEnvironment.timeZone()
4461
);
@@ -55,6 +72,10 @@ public UpdateResult applyTripUpdate(
5572
return applyTripUpdates(List.of(update), incrementality);
5673
}
5774

75+
public UpdateResult applyTripUpdates(List<GtfsRealtime.TripUpdate> updates) {
76+
return applyTripUpdates(updates, FULL_DATASET);
77+
}
78+
5879
public UpdateResult applyTripUpdates(
5980
List<GtfsRealtime.TripUpdate> updates,
6081
UpdateIncrementality incrementality

application/src/test/java/org/opentripplanner/updater/trip/RealtimeTestConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ public interface RealtimeTestConstants {
1010
String STOP_B_ID = "B";
1111
String STOP_C_ID = "C";
1212
String STOP_D_ID = "D";
13+
String STOP_E_ID = "E";
1314
}

0 commit comments

Comments
 (0)