Search in sources :

Example 6 with StopTimeUpdate

use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate in project onebusaway-application-modules by camsys.

the class GtfsRealtimeTripLibraryTest method testTprInterpolation_0.

/**
 * This method tests that we create timepoint prediction records for stops
 * that have not been served yet if there are TPRs downstream. If TPRs exist
 * downstream of a stop, the bus is assumed to be ahead of that stop. This
 * assumption is not necessarily true for stop time updates. We require that
 * the trip update delay indicates realtime schedule adherence for this
 * behavior to make sense.
 *
 * Current time = 7:31. Trip update delay = 2 minutes
 *          Schedule time    Real-time from feed  Timepoint predicted departure time
 * Stop A   7:30             -----                7:32
 * Stop B   7:40             7:43                 7:43
 */
@Test
public void testTprInterpolation_0() {
    _library.setCurrentTime(time(7, 31) * 1000);
    TripEntryImpl tripA = trip("tripA");
    stopTime(0, stop("stopA", 0, 0), tripA, time(7, 30), 0.0);
    stopTime(1, stop("stopB", 0, 0), tripA, time(7, 40), 10.0);
    BlockEntryImpl blockA = block("blockA");
    BlockConfigurationEntry blockConfigA = blockConfiguration(blockA, serviceIds("s1"), tripA);
    BlockInstance blockInstanceA = new BlockInstance(blockConfigA, 0L);
    StopTimeUpdate.Builder stopTimeUpdate = stopTimeUpdateWithDepartureDelay("stopB", 180);
    TripUpdate.Builder tripUpdate = tripUpdate("tripA", _library.getCurrentTime() / 1000, 120, stopTimeUpdate);
    Mockito.when(_entitySource.getTrip("tripA")).thenReturn(tripA);
    Mockito.when(_blockCalendarService.getActiveBlocks(Mockito.eq(blockA.getId()), Mockito.anyLong(), Mockito.anyLong())).thenReturn(Arrays.asList(blockInstanceA));
    VehicleLocationRecord record = vehicleLocationRecord(tripUpdate);
    long stopADept = getPredictedDepartureTimeByStopId(record, "stopA");
    assertEquals(stopADept, time(7, 32) * 1000);
    long stopBDept = getPredictedDepartureTimeByStopId(record, "stopB");
    assertEquals(stopBDept, time(7, 43) * 1000);
}
Also used : TripUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate) BlockInstance(org.onebusaway.transit_data_federation.services.blocks.BlockInstance) StopTimeUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate) VehicleLocationRecord(org.onebusaway.realtime.api.VehicleLocationRecord) BlockEntryImpl(org.onebusaway.transit_data_federation.impl.transit_graph.BlockEntryImpl) BlockConfigurationEntry(org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry) TripEntryImpl(org.onebusaway.transit_data_federation.impl.transit_graph.TripEntryImpl) Test(org.junit.Test)

Example 7 with StopTimeUpdate

use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate in project onebusaway-application-modules by camsys.

the class GtfsRealtimeTripLibraryTest method testTprInterpolation_1.

/**
 * Same as above, but we should NOT create new timepoint prediction records
 * because the stop has already been served. Only thing different is current
 * time.
 *
 * Current time = 7:33. Trip update delay = 2 minutes
 *          Schedule time    Real-time from feed  Timepoint predicted departure time
 * Stop A   7:30             -----                ----
 * Stop B   7:40             7:43                 7:43
 */
@Test
public void testTprInterpolation_1() {
    _library.setCurrentTime(time(7, 33) * 1000);
    TripEntryImpl tripA = trip("tripA");
    stopTime(0, stop("stopA", 0, 0), tripA, time(7, 30), 0.0);
    stopTime(1, stop("stopB", 0, 0), tripA, time(7, 40), 10.0);
    BlockEntryImpl blockA = block("blockA");
    BlockConfigurationEntry blockConfigA = blockConfiguration(blockA, serviceIds("s1"), tripA);
    BlockInstance blockInstanceA = new BlockInstance(blockConfigA, 0L);
    StopTimeUpdate.Builder stopTimeUpdate = stopTimeUpdateWithDepartureDelay("stopB", 180);
    TripUpdate.Builder tripUpdate = tripUpdate("tripA", _library.getCurrentTime() / 1000, 120, stopTimeUpdate);
    Mockito.when(_entitySource.getTrip("tripA")).thenReturn(tripA);
    Mockito.when(_blockCalendarService.getActiveBlocks(Mockito.eq(blockA.getId()), Mockito.anyLong(), Mockito.anyLong())).thenReturn(Arrays.asList(blockInstanceA));
    VehicleLocationRecord record = vehicleLocationRecord(tripUpdate);
    long stopADept = getPredictedDepartureTimeByStopId(record, "stopA");
    // no tpr for this stop
    assertEquals(stopADept, -1);
    long stopBDept = getPredictedDepartureTimeByStopId(record, "stopB");
    assertEquals(stopBDept, time(7, 43) * 1000);
}
Also used : TripUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate) BlockInstance(org.onebusaway.transit_data_federation.services.blocks.BlockInstance) StopTimeUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate) VehicleLocationRecord(org.onebusaway.realtime.api.VehicleLocationRecord) BlockEntryImpl(org.onebusaway.transit_data_federation.impl.transit_graph.BlockEntryImpl) BlockConfigurationEntry(org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry) TripEntryImpl(org.onebusaway.transit_data_federation.impl.transit_graph.TripEntryImpl) Test(org.junit.Test)

Example 8 with StopTimeUpdate

use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate in project onebusaway-application-modules by camsys.

the class GtfsRealtimeRetrieverImpl method writeTripUpdate.

private TripUpdate writeTripUpdate(TripUpdateModel model) {
    TripUpdate.Builder tu = TripUpdate.newBuilder();
    TripDescriptor.Builder t = TripDescriptor.newBuilder();
    if (model.getDelay() != null) {
        tu.setDelay(model.getDelay());
    }
    if (model.getTripId() != null) {
        t.setTripId(parseId(model.getTripId()));
    }
    if (model.getRouteId() != null) {
        t.setRouteId(parseId(model.getRouteId()));
    }
    if (model.getTripStart() != null) {
        Date date = model.getTripStart();
        String startDate = new SimpleDateFormat(GTFS_RT_DATE_FORMAT).format(date);
        String startTime = new SimpleDateFormat(GTFS_RT_TIME_FORMAT).format(date);
        t.setStartDate(startDate);
        t.setStartTime(startTime);
    }
    TripDescriptor.ScheduleRelationship sr = TripDescriptor.ScheduleRelationship.valueOf(model.getScheduleRelationship());
    if (sr != null) {
        t.setScheduleRelationship(sr);
    }
    if (model.getVehicleId() != null) {
        VehicleDescriptor.Builder v = VehicleDescriptor.newBuilder();
        v.setId(model.getVehicleId());
        if (!StringUtils.isEmpty(model.getVehicleLabel())) {
            v.setLabel(model.getVehicleLabel());
        }
        if (!StringUtils.isEmpty(model.getVehicleLicensePlate())) {
            v.setLicensePlate(model.getVehicleLicensePlate());
        }
        tu.setVehicle(v.build());
    }
    for (StopTimeUpdateModel stum : model.getStopTimeUpdates()) {
        StopTimeUpdate stu = writeStopTimeUpdate(stum);
        if (stum != null) {
            tu.addStopTimeUpdate(stu);
        }
    }
    tu.setTrip(t);
    return tu.build();
}
Also used : TripUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate) StopTimeUpdateModel(org.onebusaway.gtfs_realtime.model.StopTimeUpdateModel) TripDescriptor(com.google.transit.realtime.GtfsRealtime.TripDescriptor) StopTimeUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate) SimpleDateFormat(java.text.SimpleDateFormat) VehicleDescriptor(com.google.transit.realtime.GtfsRealtime.VehicleDescriptor) Date(java.util.Date)

Example 9 with StopTimeUpdate

use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate in project OpenTripPlanner by opentripplanner.

the class Timetable method createUpdatedTripTimes.

/**
 * Apply the TripUpdate to the appropriate TripTimes from this Timetable. The existing TripTimes
 * must not be modified directly because they may be shared with the underlying
 * scheduledTimetable, or other updated Timetables. The {@link TimetableSnapshot} performs the
 * protective copying of this Timetable. It is not done in this update method to avoid
 * repeatedly cloning the same Timetable when several updates are applied to it at once. We
 * assume here that all trips in a timetable are from the same feed, which should always be the
 * case.
 *
 * @param tripUpdate GTFS-RT trip update
 * @param timeZone time zone of trip update
 * @param updateServiceDate service date of trip update
 * @return new copy of updated TripTimes after TripUpdate has been applied on TripTimes of trip
 *         with the id specified in the trip descriptor of the TripUpdate; null if something
 *         went wrong
 */
public TripTimes createUpdatedTripTimes(TripUpdate tripUpdate, TimeZone timeZone, ServiceDate updateServiceDate) {
    if (tripUpdate == null) {
        LOG.error("A null TripUpdate pointer was passed to the Timetable class update method.");
        return null;
    }
    // However, we want to apply trip updates on top of *scheduled* times
    if (!tripUpdate.hasTrip()) {
        LOG.error("TripUpdate object has no TripDescriptor field.");
        return null;
    }
    TripDescriptor tripDescriptor = tripUpdate.getTrip();
    if (!tripDescriptor.hasTripId()) {
        LOG.error("TripDescriptor object has no TripId field");
        return null;
    }
    String tripId = tripDescriptor.getTripId();
    int tripIndex = getTripIndex(tripId);
    if (tripIndex == -1) {
        LOG.info("tripId {} not found in pattern.", tripId);
        return null;
    } else {
        LOG.trace("tripId {} found at index {} in timetable.", tripId, tripIndex);
    }
    TripTimes newTimes = new TripTimes(getTripTimes(tripIndex));
    if (tripDescriptor.hasScheduleRelationship() && tripDescriptor.getScheduleRelationship() == TripDescriptor.ScheduleRelationship.CANCELED) {
        newTimes.cancel();
    } else {
        // The GTFS-RT reference specifies that StopTimeUpdates are sorted by stop_sequence.
        Iterator<StopTimeUpdate> updates = tripUpdate.getStopTimeUpdateList().iterator();
        if (!updates.hasNext()) {
            LOG.warn("Won't apply zero-length trip update to trip {}.", tripId);
            return null;
        }
        StopTimeUpdate update = updates.next();
        int numStops = newTimes.getNumStops();
        Integer delay = null;
        for (int i = 0; i < numStops; i++) {
            boolean match = false;
            if (update != null) {
                if (update.hasStopSequence()) {
                    match = update.getStopSequence() == newTimes.getStopSequence(i);
                } else if (update.hasStopId()) {
                    match = pattern.getStop(i).getId().getId().equals(update.getStopId());
                }
            }
            if (match) {
                StopTimeUpdate.ScheduleRelationship scheduleRelationship = update.hasScheduleRelationship() ? update.getScheduleRelationship() : StopTimeUpdate.ScheduleRelationship.SCHEDULED;
                if (scheduleRelationship == StopTimeUpdate.ScheduleRelationship.SKIPPED) {
                    LOG.warn("Partially canceled trips are unsupported by this method." + " Skipping TripUpdate.");
                    return null;
                } else if (scheduleRelationship == StopTimeUpdate.ScheduleRelationship.NO_DATA) {
                    newTimes.updateArrivalDelay(i, 0);
                    newTimes.updateDepartureDelay(i, 0);
                    delay = 0;
                } else {
                    long today = updateServiceDate.getAsDate(timeZone).getTime() / 1000;
                    if (update.hasArrival()) {
                        StopTimeEvent arrival = update.getArrival();
                        if (arrival.hasDelay()) {
                            delay = arrival.getDelay();
                            if (arrival.hasTime()) {
                                newTimes.updateArrivalTime(i, (int) (arrival.getTime() - today));
                            } else {
                                newTimes.updateArrivalDelay(i, delay);
                            }
                        } else if (arrival.hasTime()) {
                            newTimes.updateArrivalTime(i, (int) (arrival.getTime() - today));
                            delay = newTimes.getArrivalDelay(i);
                        } else {
                            LOG.error("Arrival time at index {} is erroneous.", i);
                            return null;
                        }
                    } else {
                        if (delay == null) {
                            newTimes.updateArrivalTime(i, TripTimes.UNAVAILABLE);
                        } else {
                            newTimes.updateArrivalDelay(i, delay);
                        }
                    }
                    if (update.hasDeparture()) {
                        StopTimeEvent departure = update.getDeparture();
                        if (departure.hasDelay()) {
                            delay = departure.getDelay();
                            if (departure.hasTime()) {
                                newTimes.updateDepartureTime(i, (int) (departure.getTime() - today));
                            } else {
                                newTimes.updateDepartureDelay(i, delay);
                            }
                        } else if (departure.hasTime()) {
                            newTimes.updateDepartureTime(i, (int) (departure.getTime() - today));
                            delay = newTimes.getDepartureDelay(i);
                        } else {
                            LOG.error("Departure time at index {} is erroneous.", i);
                            return null;
                        }
                    } else {
                        if (delay == null) {
                            newTimes.updateDepartureTime(i, TripTimes.UNAVAILABLE);
                        } else {
                            newTimes.updateDepartureDelay(i, delay);
                        }
                    }
                }
                if (updates.hasNext()) {
                    update = updates.next();
                } else {
                    update = null;
                }
            } else {
                if (delay == null) {
                    newTimes.updateArrivalTime(i, TripTimes.UNAVAILABLE);
                    newTimes.updateDepartureTime(i, TripTimes.UNAVAILABLE);
                } else {
                    newTimes.updateArrivalDelay(i, delay);
                    newTimes.updateDepartureDelay(i, delay);
                }
            }
        }
        if (update != null) {
            LOG.error("Part of a TripUpdate object could not be applied successfully to trip {}.", tripId);
            return null;
        }
    }
    if (!newTimes.timesIncreasing()) {
        LOG.error("TripTimes are non-increasing after applying GTFS-RT delay propagation to trip {}.", tripId);
        return null;
    }
    LOG.debug("A valid TripUpdate object was applied to trip {} using the Timetable class update method.", tripId);
    return newTimes;
}
Also used : StopTimeEvent(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent) TripDescriptor(com.google.transit.realtime.GtfsRealtime.TripDescriptor) TripTimes(org.opentripplanner.routing.trippattern.TripTimes) StopTimeUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate)

Example 10 with StopTimeUpdate

use of com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate in project OpenTripPlanner by opentripplanner.

the class TimetableSnapshotSource method checkNewStopTimeUpdatesAndFindStops.

/**
 * Check stop time updates of trip update that results in a new trip (ADDED or MODIFIED) and
 * find all stops of that trip.
 *
 * @param feedId feed id this trip update is intented for
 * @param tripUpdate trip update
 * @return stops when stop time updates are correct; null if there are errors
 */
private List<Stop> checkNewStopTimeUpdatesAndFindStops(final String feedId, final TripUpdate tripUpdate) {
    Integer previousStopSequence = null;
    Long previousTime = null;
    final List<StopTimeUpdate> stopTimeUpdates = tripUpdate.getStopTimeUpdateList();
    final List<Stop> stops = new ArrayList<>(stopTimeUpdates.size());
    for (int index = 0; index < stopTimeUpdates.size(); ++index) {
        final StopTimeUpdate stopTimeUpdate = stopTimeUpdates.get(index);
        // Determine whether stop is skipped
        final boolean skippedStop = isStopSkipped(stopTimeUpdate);
        // Check stop sequence
        if (stopTimeUpdate.hasStopSequence()) {
            final Integer stopSequence = stopTimeUpdate.getStopSequence();
            // Check non-negative
            if (stopSequence < 0) {
                LOG.warn("Trip update contains negative stop sequence, skipping.");
                return null;
            }
            // Check whether sequence is increasing
            if (previousStopSequence != null && previousStopSequence > stopSequence) {
                LOG.warn("Trip update contains decreasing stop sequence, skipping.");
                return null;
            }
            previousStopSequence = stopSequence;
        } else {
        // Allow missing stop sequences for ADDED and MODIFIED trips
        }
        // Find stops
        if (stopTimeUpdate.hasStopId()) {
            // Find stop
            final Stop stop = getStopForStopId(feedId, stopTimeUpdate.getStopId());
            if (stop != null) {
                // Remember stop
                stops.add(stop);
            } else if (skippedStop) {
                // Set a null value for a skipped stop
                stops.add(null);
            } else {
                LOG.warn("Graph doesn't contain stop id \"{}\" of trip update, skipping.", stopTimeUpdate.getStopId());
                return null;
            }
        } else {
            LOG.warn("Trip update misses some stop ids, skipping.");
            return null;
        }
        // Only check arrival and departure times for non-skipped stops
        if (!skippedStop) {
            // Check arrival time
            if (stopTimeUpdate.hasArrival() && stopTimeUpdate.getArrival().hasTime()) {
                // Check for increasing time
                final Long time = stopTimeUpdate.getArrival().getTime();
                if (previousTime != null && previousTime > time) {
                    LOG.warn("Trip update contains decreasing times, skipping.");
                    return null;
                }
                previousTime = time;
            } else {
                // TODO: should we support only requiring an arrival time on the last stop and interpolate?
                for (int earlierIndex = 0; earlierIndex < index; earlierIndex++) {
                    final StopTimeUpdate earlierStopTimeUpdate = stopTimeUpdates.get(earlierIndex);
                    // Determine whether earlier stop is skipped
                    final boolean earlierSkippedStop = isStopSkipped(earlierStopTimeUpdate);
                    if (!earlierSkippedStop) {
                        LOG.warn("Trip update misses arrival time, skipping.");
                        return null;
                    }
                }
            }
            // Check departure time
            if (stopTimeUpdate.hasDeparture() && stopTimeUpdate.getDeparture().hasTime()) {
                // Check for increasing time
                final Long time = stopTimeUpdate.getDeparture().getTime();
                if (previousTime != null && previousTime > time) {
                    LOG.warn("Trip update contains decreasing times, skipping.");
                    return null;
                }
                previousTime = time;
            } else {
                // TODO: should we support only requiring a departure time on the first stop and interpolate?
                for (int laterIndex = stopTimeUpdates.size() - 1; laterIndex > index; laterIndex--) {
                    final StopTimeUpdate laterStopTimeUpdate = stopTimeUpdates.get(laterIndex);
                    // Determine whether later stop is skipped
                    final boolean laterSkippedStop = isStopSkipped(laterStopTimeUpdate);
                    if (!laterSkippedStop) {
                        LOG.warn("Trip update misses departure time, skipping.");
                        return null;
                    }
                }
            }
        }
    }
    return stops;
}
Also used : Stop(org.onebusaway.gtfs.model.Stop) ArrayList(java.util.ArrayList) StopTimeUpdate(com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate)

Aggregations

StopTimeUpdate (com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeUpdate)15 TripUpdate (com.google.transit.realtime.GtfsRealtime.TripUpdate)9 BlockInstance (org.onebusaway.transit_data_federation.services.blocks.BlockInstance)8 Test (org.junit.Test)7 BlockConfigurationEntry (org.onebusaway.transit_data_federation.services.transit_graph.BlockConfigurationEntry)7 VehicleLocationRecord (org.onebusaway.realtime.api.VehicleLocationRecord)6 BlockEntryImpl (org.onebusaway.transit_data_federation.impl.transit_graph.BlockEntryImpl)6 TripEntryImpl (org.onebusaway.transit_data_federation.impl.transit_graph.TripEntryImpl)6 StopTimeEvent (com.google.transit.realtime.GtfsRealtime.TripUpdate.StopTimeEvent)5 TimepointPredictionRecord (org.onebusaway.realtime.api.TimepointPredictionRecord)5 ArrayList (java.util.ArrayList)4 Date (java.util.Date)4 TripDescriptor (com.google.transit.realtime.GtfsRealtime.TripDescriptor)3 FeedMessage (com.google.transit.realtime.GtfsRealtime.FeedMessage)2 VehicleDescriptor (com.google.transit.realtime.GtfsRealtime.VehicleDescriptor)2 AgencyAndId (org.onebusaway.gtfs.model.AgencyAndId)2 Stop (org.onebusaway.gtfs.model.Stop)2 StopTimeUpdateModel (org.onebusaway.gtfs_realtime.model.StopTimeUpdateModel)2 TripTimes (org.opentripplanner.routing.trippattern.TripTimes)2 FeedEntity (com.google.transit.realtime.GtfsRealtime.FeedEntity)1