diff --git a/.travis.yml b/.travis.yml index 6c517751d..7149f6c53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: java - +dist: trusty # jdk 8 not available on xenial # This library uses Java 8 features and Travis doesn't (yet) support OpenJDK 8 jdk: - oraclejdk8 diff --git a/src/main/java/com/conveyal/gtfs/FrequencySummary.java b/src/main/java/com/conveyal/gtfs/FrequencySummary.java deleted file mode 100644 index a728f7fee..000000000 --- a/src/main/java/com/conveyal/gtfs/FrequencySummary.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.conveyal.gtfs; - -import com.conveyal.gtfs.model.Route; -import com.conveyal.gtfs.model.Stop; -import com.conveyal.gtfs.stats.FeedStats; -import com.conveyal.gtfs.stats.RouteStats; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; -import java.util.List; - -/** - * Summarize frequencies, designed for use in the KCMO transportation system. - */ -public class FrequencySummary { - private static final LocalTime[] windows = new LocalTime[] { - LocalTime.of(6, 0), - LocalTime.of(9, 0), - LocalTime.of(16, 0), - LocalTime.of(18, 0), - LocalTime.of(22, 0) - }; - - private static final LocalDate date = LocalDate.of(2016, 8, 30); - - public static void main(String... args) throws IOException { - GTFSFeed feed = GTFSFeed.fromFile(args[0]); - - FeedStats fs = new FeedStats(feed); - RouteStats stats = new RouteStats(feed, fs); - - FileWriter writer = new FileWriter(new File(args[1])); - - writer.write("Route,AM Peak Frequency,Midday Frequency,PM Peak Frequency,Evening Frequency,AM Peak Speed,Midday Speed,PM Peak Speed,Evening Speed,Trips/Day,First trip,Last trip\n"); - - for (String route_id : feed.routes.keySet()) { - for (int direction_id : new int[] { 0, 1 }) { - StringBuilder freq = new StringBuilder(); - StringBuilder speed = new StringBuilder(); - - Route r = feed.routes.get(route_id); - - freq.append(r.route_short_name); - freq.append(" "); - freq.append(r.route_long_name); - - // guess at the direction name by finding longest pattern - List stops = feed.patterns.values().stream() - .filter(p -> p.route_id.equals(route_id) && feed.trips.get(p.associatedTrips.get(0)).direction_id == direction_id) - .sorted((p1, p2) -> p1.orderedStops.size() - p2.orderedStops.size()) - .findFirst() - .get() - .orderedStops; - - Stop lastStop = feed.stops.get(stops.get(stops.size() - 1)); - - freq.append(" towards "); - freq.append(lastStop.stop_name); - - freq.append(","); - - for (int window = 0; window < windows.length - 1; window++) { - int headwaySecs = stats.getHeadwayForRouteDirection(route_id, direction_id, date, windows[window], windows[window + 1]); - freq.append(headwaySecs > 0 ? Math.round(headwaySecs / 60 ) : "-"); - freq.append(","); - - double speedMs = stats.getSpeedForRouteDirection(route_id, direction_id, date, windows[window], windows[window + 1]); - speed.append(Double.isNaN(speedMs) ? "-" : Math.round(speedMs * 3600 / 1609.0 )); - speed.append(","); - } - - speed.append(stats.getTripsPerDateOfService(route_id).get(date).stream().filter(t -> t.direction_id == direction_id).count()); - speed.append(","); - speed.append(stats.getStartTimeForRouteDirection(route_id, direction_id, date).format(DateTimeFormatter.ofPattern("K:mm a"))); - speed.append(","); - speed.append(stats.getEndTimeForRouteDirection(route_id, direction_id, date).format(DateTimeFormatter.ofPattern("K:mm a"))); - - writer.write(freq.toString()); - writer.write(speed.toString()); - writer.write("\n"); - } - } - - writer.flush(); - writer.close(); - } -} diff --git a/src/main/java/com/conveyal/gtfs/GTFSFeed.java b/src/main/java/com/conveyal/gtfs/GTFSFeed.java index 643feaefb..1e3c52f74 100644 --- a/src/main/java/com/conveyal/gtfs/GTFSFeed.java +++ b/src/main/java/com/conveyal/gtfs/GTFSFeed.java @@ -6,7 +6,6 @@ import com.conveyal.gtfs.model.*; import com.conveyal.gtfs.model.Calendar; import com.conveyal.gtfs.validator.Validator; -import com.conveyal.gtfs.stats.FeedStats; import com.conveyal.gtfs.validator.service.GeoUtils; import com.google.common.collect.*; import com.google.common.eventbus.EventBus; @@ -14,10 +13,8 @@ import com.vividsolutions.jts.algorithm.ConvexHull; import com.vividsolutions.jts.geom.*; import com.vividsolutions.jts.index.strtree.STRtree; -import com.vividsolutions.jts.simplify.DouglasPeuckerSimplifier; import org.geotools.referencing.GeodeticCalculator; import org.mapdb.BTreeMap; -import org.mapdb.Bind; import org.mapdb.DB; import org.mapdb.DBMaker; import org.mapdb.Fun; @@ -33,17 +30,12 @@ import java.io.IOError; import java.io.IOException; import java.io.OutputStream; -import java.time.LocalDate; -import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; import java.util.*; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import java.util.stream.IntStream; import java.util.stream.StreamSupport; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -86,13 +78,14 @@ public class GTFSFeed implements Cloneable, Closeable { // public final ConcurrentMap stopCountByStopTime; - /* Map from stop (stop_id) to stopTimes tuples (trip_id, stop_sequence) */ - public final NavigableSet> stopStopTimeSet; - public final ConcurrentMap stopCountByStopTime; - - public final NavigableSet> tripsPerService; - - public final NavigableSet> servicesPerDate; + // TODO: Remove these indexes from GTFSFeed. +// /* Map from stop (stop_id) to stopTimes tuples (trip_id, stop_sequence) */ +// public final NavigableSet> stopStopTimeSet; +// public final ConcurrentMap stopCountByStopTime; +// +// public final NavigableSet> tripsPerService; +// +// public final NavigableSet> servicesPerDate; /* A fare is a fare_attribute and all fare_rules that reference that fare_attribute. */ public final Map fares; @@ -196,29 +189,6 @@ else if (feedId == null || feedId.isEmpty()) { for (GTFSError error : errors) { LOG.info("{}", error); } - LOG.info("Building stop to stop times index"); - Bind.histogram(stop_times, stopCountByStopTime, (key, stopTime) -> stopTime.stop_id); - Bind.secondaryKeys(stop_times, stopStopTimeSet, (key, stopTime) -> new String[] {stopTime.stop_id}); - LOG.info("Building trips per service index"); - Bind.secondaryKeys(trips, tripsPerService, (key, trip) -> new String[] {trip.service_id}); - LOG.info("Building services per date index"); - Bind.secondaryKeys(services, servicesPerDate, (key, service) -> { - - LocalDate startDate = service.calendar != null - ? service.calendar.start_date - : service.calendar_dates.keySet().stream().sorted().findFirst().get(); - LocalDate endDate = service.calendar != null - ? service.calendar.end_date - : service.calendar_dates.keySet().stream().sorted().reduce((first, second) -> second).get(); - // end date for Period.between is not inclusive - int daysOfService = (int) ChronoUnit.DAYS.between(startDate, endDate.plus(1, ChronoUnit.DAYS)); - return IntStream.range(0, daysOfService) - .mapToObj(offset -> startDate.plusDays(offset)) - .filter(service::activeOn) - .map(date -> date.format(dateFormatter)) - .toArray(size -> new String[size]); - }); - loaded = true; } @@ -264,15 +234,7 @@ public void toFile (String file) { throw new RuntimeException(e); } } -// public void validate (EventBus eventBus, Validator... validators) { -// if (eventBus == null) { -// -// } -// for (Validator validator : validators) { -// validator.getClass().getSimpleName(); -// validator.validate(this, false); -// } -// } + public void validate (boolean repair, Validator... validators) { long startValidation = System.currentTimeMillis(); for (Validator validator : validators) { @@ -298,11 +260,6 @@ public void validate () { ///////////////// } - public FeedStats calculateStats() { - FeedStats feedStats = new FeedStats(this); - return feedStats; - } - /** * Static factory method returning a new instance of GTFSFeed containing the contents of * the GTFS file at the supplied filesystem path. @@ -604,87 +561,6 @@ public double getTripSpeed (String trip_id, boolean straightLine) { return distance / time; // meters per second } - /** Get list of stop_times for a given stop_id. */ - public List getStopTimesForStop (String stop_id) { - SortedSet> index = this.stopStopTimeSet - .subSet(new Tuple2<>(stop_id, null), new Tuple2(stop_id, Fun.HI)); - - return index.stream() - .map(tuple -> this.stop_times.get(tuple.b)) - .collect(Collectors.toList()); - } - - public List getTripsForService (String service_id) { - SortedSet> index = this.tripsPerService - .subSet(new Tuple2<>(service_id, null), new Tuple2(service_id, Fun.HI)); - - return index.stream() - .map(tuple -> this.trips.get(tuple.b)) - .collect(Collectors.toList()); - } - - /** Get list of services for each date of service. */ - public List getServicesForDate (LocalDate date) { - String dateString = date.format(dateFormatter); - SortedSet> index = this.servicesPerDate - .subSet(new Tuple2<>(dateString, null), new Tuple2(dateString, Fun.HI)); - - return index.stream() - .map(tuple -> this.services.get(tuple.b)) - .collect(Collectors.toList()); - } - - public List getDatesOfService () { - return this.servicesPerDate.stream() - .map(tuple -> LocalDate.parse(tuple.a, dateFormatter)) - .collect(Collectors.toList()); - } - - /** Get list of distinct trips (filters out multiple visits by a trip) a given stop_id. */ - public List getDistinctTripsForStop (String stop_id) { - return getStopTimesForStop(stop_id).stream() - .map(stopTime -> this.trips.get(stopTime.trip_id)) - .distinct() - .collect(Collectors.toList()); - } - - /** Get the likely time zone for a stop using the agency of the first stop time encountered for the stop. */ - public ZoneId getAgencyTimeZoneForStop (String stop_id) { - StopTime stopTime = getStopTimesForStop(stop_id).iterator().next(); - - Trip trip = this.trips.get(stopTime.trip_id); - Route route = this.routes.get(trip.route_id); - Agency agency = route.agency_id != null ? this.agency.get(route.agency_id) : this.agency.get(0); - - return ZoneId.of(agency.agency_timezone); - } - - // TODO: code review - public Geometry getMergedBuffers() { - if (this.mergedBuffers == null) { -// synchronized (this) { - Collection polygons = new ArrayList<>(); - for (Stop stop : this.stops.values()) { - if (getStopTimesForStop(stop.stop_id).isEmpty()) { - continue; - } - if (stop.stop_lat > -1 && stop.stop_lat < 1 || stop.stop_lon > -1 && stop.stop_lon < 1) { - continue; - } - Point stopPoint = gf.createPoint(new Coordinate(stop.stop_lon, stop.stop_lat)); - Polygon stopBuffer = (Polygon) stopPoint.buffer(.01); - polygons.add(stopBuffer); - } - Geometry multiGeometry = gf.buildGeometry(polygons); - this.mergedBuffers = multiGeometry.union(); - if (polygons.size() > 100) { - this.mergedBuffers = DouglasPeuckerSimplifier.simplify(this.mergedBuffers, .001); - } -// } - } - return this.mergedBuffers; - } - public Polygon getConvexHull() { if (this.convexHull == null) { synchronized (this) { @@ -788,11 +664,6 @@ private GTFSFeed (DB db) { tripPatternMap = db.getTreeMap("patternForTrip"); - stopCountByStopTime = db.getTreeMap("stopCountByStopTime"); - stopStopTimeSet = db.getTreeSet("stopStopTimeSet"); - tripsPerService = db.getTreeSet("tripsPerService"); - servicesPerDate = db.getTreeSet("servicesPerDate"); - errors = db.getTreeSet("errors"); } } diff --git a/src/main/java/com/conveyal/gtfs/GTFSMain.java b/src/main/java/com/conveyal/gtfs/GTFSMain.java index de7665dea..8003ef96d 100644 --- a/src/main/java/com/conveyal/gtfs/GTFSMain.java +++ b/src/main/java/com/conveyal/gtfs/GTFSMain.java @@ -1,6 +1,5 @@ package com.conveyal.gtfs; -import com.conveyal.gtfs.stats.FeedStats; import com.conveyal.gtfs.util.json.JsonManager; import com.conveyal.gtfs.validator.model.ValidationResult; import org.apache.commons.cli.CommandLine; @@ -41,7 +40,7 @@ public static void main (String[] args) throws Exception { if(cmd.hasOption("validate")) { feed.validate(); JsonManager json = new JsonManager(ValidationResult.class); - ValidationResult result = new ValidationResult(arguments[0], feed, new FeedStats(feed)); + ValidationResult result = new ValidationResult(arguments[0], feed); String resultString = json.writePretty(result); File resultFile; if (arguments.length >= 2) { diff --git a/src/main/java/com/conveyal/gtfs/stats/AgencyStats.java b/src/main/java/com/conveyal/gtfs/stats/AgencyStats.java deleted file mode 100644 index 5c4d847be..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/AgencyStats.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.Route; -import com.conveyal.gtfs.model.Service; -import com.conveyal.gtfs.model.Stop; -import com.conveyal.gtfs.model.StopTime; -import com.conveyal.gtfs.model.Trip; - -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; - -/** - * Created by landon on 9/2/16. - */ -public class AgencyStats { - private GTFSFeed feed = null; - - public static Integer getRouteCount(GTFSFeed feed, String agencyId) { - int count = 0; - for (Route route : feed.routes.values()) { - if (agencyId.equals(route.agency_id)) { - count++; - } - } - return count; - } - - public static Integer getTripCount(GTFSFeed feed, String agencyId) { - int count = 0; - for (Trip trip : feed.trips.values()) { - Route route = feed.routes.get(trip.route_id); - if (agencyId.equals(route.agency_id)) { - count++; - } - } - return count; - } - - public static Integer getStopCount(GTFSFeed feed, String agencyId) { - int count = 0; - for (Stop stop : feed.stops.values()) { -// AgencyAndId id = stop.stop_id; -// if (agencyId.equals(id.getAgencyId())) { - count++; -// } - } - return count; - } - - public static Integer getStopTimesCount(GTFSFeed feed, String agencyId) { - int count = 0; - for (StopTime stopTime : feed.stop_times.values()) { - Trip trip = feed.trips.get(stopTime.trip_id); - Route route = feed.routes.get(trip.route_id); - if (agencyId.equals(route.agency_id)) { - count++; - } - } - return count; - } - - public static LocalDate getCalendarServiceRangeStart(GTFSFeed feed, String agencyId) { - int startDate = 0; - for (Service service : feed.services.values()) { -// if (agencyId.equals(service.agency_id)) { -// if (startDate == 0 -// || service.calendar.start_date < startDate) -// startDate = service.calendar.start_date; -// } - } - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - return LocalDate.parse(String.valueOf(startDate), formatter); - } - - public static LocalDate getCalendarServiceRangeEnd(GTFSFeed feed, String agencyId) { - int endDate = 0; - - for (Service service : feed.services.values()) { -// if (agencyId.equals(service.agency_id)) { -// if (endDate == 0 -// || service.calendar.end_date > endDate) -// endDate = service.calendar.end_date; -// } - } - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - return LocalDate.parse(String.valueOf(endDate), formatter); - } - - public static LocalDate getCalendarDateStart(GTFSFeed feed, String agencyId) { - LocalDate startDate = null; - for (Service service : feed.services.values()) { - for (LocalDate date : service.calendar_dates.keySet()) { -// if (agencyId.equals(serviceCalendarDate.getServiceId().getAgencyId())) { - if (startDate == null - || date.isBefore(startDate)) - startDate = date; -// } - } - } - return startDate; - } - - public static LocalDate getCalendarDateEnd(GTFSFeed feed, String agencyId) { - LocalDate endDate = null; - for (Service service : feed.services.values()) { - for (LocalDate date : service.calendar_dates.keySet()) { -// if (agencyId.equals(serviceCalendarDate.getServiceId().getAgencyId())) { - if (endDate == null - || date.isAfter(endDate)) - endDate = date; -// } - } - } - return endDate; - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/CalendarStats.java b/src/main/java/com/conveyal/gtfs/stats/CalendarStats.java deleted file mode 100644 index 6a860435a..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/CalendarStats.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.Service; - -import java.time.LocalDate; -import java.time.temporal.ChronoUnit; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Created by landon on 9/2/16. - */ -public class CalendarStats { - private GTFSFeed feed = null; - private FeedStats stats = null; - -// public CalendarStats (GTFSFeed f, FeedStats fs) { -// feed = f; -// stats = fs; -// } - -// public Set getServiceIdsForDates (LocalDate from, LocalDate to) { -// long days = ChronoUnit.DAYS.between(from, to); -// -// return feed.services.values().stream() -// .filter(s -> { -// for (int i = 0; i < days; i++) { -// LocalDate date = from.plusDays(i); -// if (s.activeOn(date)) { -// return true; -// } -// } -// return false; -// }) -// .map(s -> s.service_id) -// .collect(Collectors.toSet()); -// } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/FeedStats.java b/src/main/java/com/conveyal/gtfs/stats/FeedStats.java deleted file mode 100644 index 4a134b274..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/FeedStats.java +++ /dev/null @@ -1,393 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.Agency; -import com.conveyal.gtfs.model.Service; -import com.conveyal.gtfs.model.Stop; -import com.conveyal.gtfs.model.Trip; -import com.conveyal.gtfs.stats.model.AgencyStatistic; -import com.vividsolutions.jts.geom.Geometry; - -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.time.DayOfWeek; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * Retrieves a base set of statistics from the GTFS. - * - */ -public class FeedStats { - - private GTFSFeed feed = null; - public String feed_id = null; - public PatternStats pattern = null; - public StopStats stop = null; - public RouteStats route = null; - - public FeedStats(GTFSFeed f) { - this.feed = f; - this.feed_id = f.feedId; - this.pattern = new PatternStats(feed, this); - this.stop = new StopStats(feed, this); - this.route = new RouteStats(feed, this); - } - - public Integer getAgencyCount() { - return feed.agency.size(); - } - - public Integer getRouteCount() { - return feed.routes.size(); - } - - public Integer getTripCount() { - return feed.trips.size(); - } - - public Integer getTripCount(LocalDate date) { - return getTripsForDate(date).size(); - } - - - public Integer getStopCount() { - return feed.stops.size(); - } - - public Integer getStopTimesCount() { - return feed.stop_times.size(); - } - - // calendar date range start/end assume a service calendar based schedule - // returns null for schedules without calendar service schedules - - public LocalDate getCalendarServiceRangeStart() { - - int startDate = 0; - for (Service service : feed.services.values()) { - if (service.calendar == null) - continue; -// if (startDate == 0 || service.calendar.start_date < startDate) { -// startDate = service.calendar.start_date; -// } - } - if (startDate == 0) - return null; - - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - return LocalDate.parse(String.valueOf(startDate), formatter); - } - - public LocalDate getCalendarServiceRangeEnd() { - - int endDate = 0; - - for (Service service : feed.services.values()) { - if (service.calendar == null) - continue; - -// if (endDate == 0 || service.calendar.end_date > endDate) { -// endDate = service.calendar.end_date; -// } - } - if (endDate == 0) - return null; - - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); - return LocalDate.parse(String.valueOf(endDate), formatter); - } - - public LocalDate getCalendarDateStart() { - LocalDate startDate = null; - for (Service service : feed.services.values()) { - for (LocalDate date : service.calendar_dates.keySet()) { - if (startDate == null - || date.isBefore(startDate)) - startDate = date; - } - } - return startDate; - } - - public LocalDate getCalendarDateEnd() { - LocalDate endDate = null; - for (Service service : feed.services.values()) { - for (LocalDate date : service.calendar_dates.keySet()) { - if (endDate == null - || date.isAfter(endDate)) - endDate = date; - } - } - return endDate; - } - - public Map getTripCountPerDateOfService() { - - Map> tripsPerDate = getTripsPerDateOfService(); - Map tripCountPerDate = new HashMap<>(); - for (Map.Entry> entry : tripsPerDate.entrySet()) { - LocalDate date = entry.getKey(); - Integer count = entry.getValue().size(); - tripCountPerDate.put(date, count); - } - - return tripCountPerDate; - } - public LocalDate getStartDate() { - LocalDate startDate = null; - - if (feed.hasFeedInfo()) startDate = feed.getFeedInfo().feed_start_date; - if (startDate == null) startDate = getCalendarServiceRangeStart(); - if (startDate == null) startDate = getCalendarDateStart(); - - return startDate; - } - - public LocalDate getEndDate() { - LocalDate endDate = null; - - if (feed.hasFeedInfo()) endDate = feed.getFeedInfo().feed_end_date; - if (endDate == null) endDate = getCalendarServiceRangeEnd(); - if (endDate == null) endDate = getCalendarDateEnd(); - - return endDate; - } - - public LocalTime getStartTime (LocalDate date) { - return this.pattern.getStartTimeForTrips(getTripsForDate(date)); - } - - public LocalTime getEndTime (LocalDate date) { - return this.pattern.getEndTimeForTrips(getTripsForDate(date)); - } - - /** Get total revenue time (in seconds) for all trips on a given date. */ - public long getTotalRevenueTimeForDate (LocalDate date) { - return this.pattern.getTotalRevenueTimeForTrips(getTripsForDate(date)); - } - - public long getAverageDailyRevenueTime (int dow) { - // int value of dow from 1 (Mon) to 7 (Sun) - DayOfWeek dayOfWeek = DayOfWeek.of(dow); - List dates = feed.getDatesOfService().stream() - .filter(date -> date.getDayOfWeek().equals(dayOfWeek)) - .collect(Collectors.toList()); - - return getRevenueTimeForDates(dates) / dates.size(); - } - - public long getAverageWeekdayRevenueTime () { - List dates = feed.getDatesOfService().stream() - .filter(date -> { - int dow = date.getDayOfWeek().getValue(); - boolean isWeekday = ((dow >= DayOfWeek.MONDAY.getValue()) && (dow <= DayOfWeek.FRIDAY.getValue())); - return isWeekday; - }) - .collect(Collectors.toList()); - if (dates.size() == 0) { - return 0; - } - return getRevenueTimeForDates(dates) / dates.size(); - } - public long getRevenueTimeForDates (List dates) { - Map timePerService = new HashMap<>(); - - // First, get revenue time for each service calendar used in feed dates - // NOTE: we don't simply get revenue time for each individual date of service - // because that ends up duplicating a lot of operations if service calendars - // are reused often. - dates.stream() - .map(date -> feed.getServicesForDate(date)) - .flatMap(List::stream) - .collect(Collectors.toSet()) - .stream() - .forEach(s -> { - List trips = feed.getTripsForService(s.service_id); - long time = this.pattern.getTotalRevenueTimeForTrips(trips); - timePerService.put(s.service_id, time); - }); - - // Next, sum up service calendars by dates of service - long total = dates.stream() - .map(date -> // get sum of services per date - feed.getServicesForDate(date).stream() - .map(s -> timePerService.get(s.service_id)) - .mapToLong(time -> time) - .sum() - ) - .mapToLong(time -> time) - .sum(); - return total; - } - - public long getTotalRevenueTime () { - return getRevenueTimeForDates(feed.getDatesOfService()); - } - - /** Get total revenue distance (in meters) for all trips on a given date. */ - public double getTotalDistanceForTrips (LocalDate date) { - return this.pattern.getTotalDistanceForTrips(getTripsForDate(date)); - } - - /** in seconds */ - public int getDailyAverageHeadway (LocalDate date, LocalTime from, LocalTime to) { - - OptionalDouble avg = feed.stops.values().stream() - .map(s -> this.stop.getAverageHeadwayForStop(s.stop_id, date, from, to)) - .mapToDouble(headway -> headway) - .average(); - - return (int) avg.getAsDouble(); - } - - public double getAverageTripSpeed (LocalDate date, LocalTime from, LocalTime to) { - List trips = getTripsForDate(date); - return this.pattern.getAverageSpeedForTrips(trips, from, to); - } - public Map> getTripsPerDateOfService () { - Map> tripsPerDate = new HashMap<>(); - Map> tripsPerService = new HashMap<>(); - - LocalDate startDate = getStartDate(); - LocalDate endDate = getEndDate(); - if (startDate == null || endDate == null) { - return tripsPerDate; - } - int allDates = (int) ChronoUnit.DAYS.between(startDate, endDate.plus(1, ChronoUnit.DAYS)); - List dates = IntStream.range(0, allDates) - .mapToObj(offset -> startDate.plusDays(offset)) - .collect(Collectors.toList()); - dates.stream() - .map(date -> feed.getServicesForDate(date)) - .flatMap(List::stream) - .collect(Collectors.toSet()) - .stream() - .forEach(s -> { - List trips = feed.getTripsForService(s.service_id); - tripsPerService.put(s.service_id, trips); - }); - dates.stream() - .forEach(date -> { - List trips = feed.getServicesForDate(date).stream() - .map(s -> tripsPerService.get(s.service_id)) - .flatMap(List::stream) - .collect(Collectors.toList()); - tripsPerDate.put(date, trips); - }); - return tripsPerDate; - } - - public List getTripsForDate (LocalDate date) { - return feed.getServicesForDate(date).stream() - .map(s -> feed.getTripsForService(s.service_id)) - .flatMap(List::stream) - .collect(Collectors.toList()); - } - - public Collection getAllAgencies() { - return feed.agency.values(); - } - - /** - * Get the bounding box of this GTFS feed. - * We use a Rectangle2D rather than a Geotools envelope because GTFS is always in WGS 84. - * Note that stops do not have agencies in GTFS. - */ - public Rectangle2D getBounds () { - Rectangle2D ret = null; - - for (Stop stop : feed.stops.values()) { - - // skip over stops that don't have any stop times - if (!feed.stopCountByStopTime.containsKey(stop.stop_id)) { - continue; - } - if (ret == null) { - ret = new Rectangle2D.Double(stop.stop_lon, stop.stop_lat, 0, 0); - } - else { - ret.add(new Point2D.Double(stop.stop_lon, stop.stop_lat)); - } - } - - return ret; - } - - public AgencyStatistic getStatistic(String agencyId) { - AgencyStatistic gs = new AgencyStatistic(); - gs.setAgencyId(agencyId); - gs.setRouteCount(AgencyStats.getRouteCount(feed, agencyId)); - gs.setTripCount(AgencyStats.getTripCount(feed, agencyId)); - gs.setStopCount(AgencyStats.getStopCount(feed, agencyId)); - gs.setStopTimeCount(AgencyStats.getStopTimesCount(feed, agencyId)); - gs.setCalendarStartDate(AgencyStats.getCalendarDateStart(feed, agencyId)); - gs.setCalendarEndDate(AgencyStats.getCalendarDateEnd(feed, agencyId)); - gs.setCalendarServiceStart(AgencyStats.getCalendarServiceRangeStart(feed, agencyId)); - gs.setCalendarServiceEnd(AgencyStats.getCalendarServiceRangeEnd(feed, agencyId)); - gs.setBounds(getBounds()); - return gs; - } - - public String getStatisticAsCSV(String agencyId) { - AgencyStatistic s = getStatistic(agencyId); - return formatStatisticAsCSV(s); - } - - public static String formatStatisticAsCSV(AgencyStatistic s) { - StringBuffer buff = new StringBuffer(); - buff.append(s.getAgencyId()); - buff.append(","); - buff.append(s.getRouteCount()); - buff.append(","); - buff.append(s.getTripCount()); - buff.append(","); - buff.append(s.getStopCount()); - buff.append(","); - buff.append(s.getStopTimeCount()); - buff.append(","); - buff.append(s.getCalendarServiceStart()); - buff.append(","); - buff.append(s.getCalendarServiceEnd()); - buff.append(","); - buff.append(s.getCalendarStartDate()); - buff.append(","); - buff.append(s.getCalendarEndDate()); - return buff.toString(); - } - - public long getFrequencyCount() { - return feed.frequencies.size(); - } - - public long getShapePointCount() { - return feed.shape_points.size(); - } - - public long getFareAttributeCount() { - return feed.fares.size(); - } - - public long getFareRulesCount() { - return feed.fares.values().stream() - .mapToInt(fare -> fare.fare_rules.size()) - .sum(); - } - - public long getServiceCount() { - return feed.services.size(); - } - - public List getDatesOfService() { - return feed.getDatesOfService(); - } - - public Geometry getMergedBuffers() { - return feed.getMergedBuffers(); - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/PatternStats.java b/src/main/java/com/conveyal/gtfs/stats/PatternStats.java deleted file mode 100644 index 3ab89442b..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/PatternStats.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.Pattern; -import com.conveyal.gtfs.model.StopTime; -import com.conveyal.gtfs.model.Trip; -import gnu.trove.list.TDoubleList; -import gnu.trove.list.TIntList; -import gnu.trove.list.array.TDoubleArrayList; -import gnu.trove.list.array.TIntArrayList; -import org.mapdb.Fun; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.Collection; -import java.util.List; -import java.util.Spliterator; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -/** - * Created by landon on 9/2/16. - */ -public class PatternStats { - - private GTFSFeed feed = null; - private FeedStats stats = null; - - public PatternStats (GTFSFeed f, FeedStats fs) { - feed = f; - stats = fs; - } - - /** - * Gets the pattern speed for a given pattern for a specified date and time window. - * @param pattern_id pattern ID - * @param date service date - * @param from beginning of time window - * @param to end of time window - * @return - */ - public double getPatternSpeed (String pattern_id, LocalDate date, LocalTime from, LocalTime to) { - - List trips = getTripsForDate(pattern_id, date); - - return getAverageSpeedForTrips(trips, from, to); - } - - /** - * Get average speed for set of trips that begin within the time window in meters per second. - * @param trips - * @param from - * @param to - * @return avg. speed (meters per second) - */ - public double getAverageSpeedForTrips (Collection trips, LocalTime from, LocalTime to) { - TDoubleList speeds = new TDoubleArrayList(); - - for (Trip trip : trips) { - StopTime firstStopTime = feed.stop_times.ceilingEntry(Fun.t2(trip.trip_id, null)).getValue(); - LocalTime tripBeginTime = LocalTime.ofSecondOfDay(firstStopTime.departure_time % 86399); // convert 24hr+ seconds to 0 - 86399 - - // skip trip if begin time is before or after specified time period - if (tripBeginTime.isAfter(to) || tripBeginTime.isBefore(from)) { - continue; - } - // TODO: swap straight lines for actual geometry? - double speed = feed.getTripSpeed(trip.trip_id, true); - - if (!Double.isNaN(speed)) { - speeds.add(speed); - } - } - - if (speeds.isEmpty()) return -1; - - return speeds.sum() / speeds.size(); - } - - /** - * Get earliest departure time for a set of trips. - * @param trips - * @return earliest departure time - */ - public LocalTime getStartTimeForTrips (Collection trips) { - int earliestDeparture = Integer.MAX_VALUE; - - for (Trip trip : trips) { - StopTime st = feed.getOrderedStopTimesForTrip(trip.trip_id).iterator().next(); - int dep = st.departure_time; - - // these trips begin on the next day, so we need to cast them to 0 - 86399 - if (dep > 86399) { - dep = dep % 86399; - } - - if (dep <= earliestDeparture) { - earliestDeparture = dep; - } - } - return LocalTime.ofSecondOfDay(earliestDeparture); - } - - /** - * Get last arrival time for a set of trips. - * @param trips - * @return last arrival time (if arrival occurs after midnight, time is expressed in terms of following day, e.g., 2:00 AM) - */ - public LocalTime getEndTimeForTrips (Collection trips) { - int latestArrival = Integer.MIN_VALUE; - - for (Trip trip : trips) { - StopTime st = feed.getOrderedStopTimesForTrip(trip.trip_id).iterator().next(); - - if (st.arrival_time >= latestArrival) { - latestArrival = st.arrival_time; - } - } - - // return end time as 2:00 am if last arrival occurs after midnight - return LocalTime.ofSecondOfDay(latestArrival % 86399); - } - - /** - * Get total revenue time (in seconds) for set of trips. - * @param trips - * @return total revenue time (in seconds) - */ - public long getTotalRevenueTimeForTrips (Collection trips) { - TIntList times = new TIntArrayList(); - for (Trip trip : trips) { - StopTime first; - StopTime last; - Spliterator stopTimes = feed.getOrderedStopTimesForTrip(trip.trip_id).spliterator();; - - first = StreamSupport.stream(stopTimes, false) - .findFirst() - .orElse(null); - - last = StreamSupport.stream(stopTimes, false) - .reduce((a, b) -> b) - .orElse(null); - - if (last != null && first != null) { - // revenue time should not include layovers at termini - int time = last.arrival_time - first.departure_time; - - times.add(time); - } - } - - return times.sum(); - } - - /** - * Get total revenue distance (in meters) for set of trips. - * @param trips - * @return total trip distance (in meters) - */ - public double getTotalDistanceForTrips (Collection trips) { - TDoubleList distances = new TDoubleArrayList(); - for (Trip trip : trips) { - distances.add(feed.getTripDistance(trip.trip_id, false)); - } - - return distances.sum(); - } - - /** - * Get distance for a pattern. Uses the first trip associated with the pattern. - * @param pattern_id - * @return distance (in meters) - */ - public double getPatternDistance (String pattern_id) { - Pattern pattern = feed.patterns.get(pattern_id); - - return feed.getTripDistance(pattern.associatedTrips.iterator().next(), false); - } - - /** - * Get average stop spacing for a pattern. - * @param pattern_id - * @return avg. stop spacing (in meters) - */ - public double getAverageStopSpacing (String pattern_id) { - Pattern pattern = feed.patterns.get(pattern_id); - return getPatternDistance(pattern_id) / pattern.orderedStops.size(); - } - - /** - * - * @param pattern_id pattern ID - * @param date service date - * @param from beginning of time window - * @param to end of time window - * @return - */ - public int getHeadwayForPattern (String pattern_id, LocalDate date, LocalTime from, LocalTime to) { - - List tripsForPattern = getTripsForDate(pattern_id, date); - - String commonStop = stats.route.getCommonStopForTrips(tripsForPattern); - if (commonStop == null) return -1; - - return stats.stop.getStopHeadwayForTrips(commonStop, tripsForPattern, from, to); - } - - /** - * - * @param pattern_id pattern ID - * @param date service date - * @return list of trips - */ - public long getTripCountForDate (String pattern_id, LocalDate date) { - return getTripsForDate(pattern_id, date).size(); - } - - /** - * - * @param pattern_id pattern ID - * @param date service date - * @return list of trips - */ - public List getTripsForDate (String pattern_id, LocalDate date) { - Pattern pattern = feed.patterns.get(pattern_id); - if (pattern == null) return null; - - return stats.getTripsForDate(date).stream() - .filter(trip -> pattern.associatedTrips.contains(trip.trip_id)) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/RouteStats.java b/src/main/java/com/conveyal/gtfs/stats/RouteStats.java deleted file mode 100644 index 127978000..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/RouteStats.java +++ /dev/null @@ -1,235 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.Pattern; -import com.conveyal.gtfs.model.Route; -import com.conveyal.gtfs.model.Service; -import com.conveyal.gtfs.model.Trip; -import com.conveyal.gtfs.stats.model.RouteStatistic; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Created by landon on 9/2/16. - */ -public class RouteStats { - private GTFSFeed feed = null; - private FeedStats stats = null; - private PatternStats patternStats = null; - private StopStats stopStats = null; - - public RouteStats (GTFSFeed f, FeedStats fs) { - feed = f; - stats = fs; - patternStats = stats.pattern; - stopStats = stats.stop; - } - - public List getStatisticForAll (LocalDate date, LocalTime from, LocalTime to) { - List stats = new ArrayList<>(); - - for (String id : feed.routes.keySet()) { - stats.add(getStatisticForRoute(id, date, from, to)); - } - return stats; - } - - public String getStatisticForAllAsCsv (LocalDate date, LocalTime from, LocalTime to) { - List stats = getStatisticForAll(date, from, to); - StringBuffer buffer = new StringBuffer(); - buffer.append(RouteStatistic.getHeaderAsCsv()); - for (RouteStatistic rs : stats) { - buffer.append(System.getProperty("line.separator")); - buffer.append(rs.asCsv()); - } - - return buffer.toString(); - } - - public String getRouteName (String route_id) { - Route route = feed.routes.get(route_id); - return route != null ? route.route_short_name + " - " + route.route_long_name : null; - } - - /** - * Get average speed on a direction of a route, in meters per second. - * @param route_id - * @param direction_id - * @param date - * @param from - * @param to - * @return avg. speed (meters per second) - */ - public double getSpeedForRouteDirection (String route_id, int direction_id, LocalDate date, LocalTime from, LocalTime to) { - List tripsForRouteDirection = getTripsForDate(route_id, date).stream() - .filter(t -> t.direction_id == direction_id) - .collect(Collectors.toList()); - - return patternStats.getAverageSpeedForTrips(tripsForRouteDirection, from, to); - } - - /** - * Get the average headway for a route direction for a specified service date and time window, in seconds. - * @param route_id - * @param direction_id - * @param date - * @param from - * @param to - * @return avg. headway in seconds - */ - public int getHeadwayForRouteDirection (String route_id, int direction_id, LocalDate date, LocalTime from, LocalTime to) { - List tripsForRouteDirection = getTripsForDate(route_id, date).stream() - .filter(t -> t.direction_id == direction_id) - .collect(Collectors.toList()); - - String commonStop = getCommonStopForTrips(tripsForRouteDirection); - if (commonStop == null) return -1; - - return stats.stop.getStopHeadwayForTrips(commonStop, tripsForRouteDirection, from, to); - } - - public String getCommonStopForTrips(List trips) { - Set commonStops = null; - - for (Trip trip : trips) { - List stops = feed.getOrderedStopListForTrip(trip.trip_id); - - if (commonStops == null) { - commonStops = new HashSet<>(stops); - } else { - commonStops.retainAll(stops); - } - } - - if (commonStops == null || commonStops.isEmpty()) return null; - - String commonStop = commonStops.iterator().next(); - return commonStop; - } - - /** - * Get earliest departure time for a given route direction on the specified date. - * @param route_id - * @param direction_id - * @param date - * @return earliest departure time - */ - public LocalTime getStartTimeForRouteDirection (String route_id, int direction_id, LocalDate date) { - - - List tripsForRouteDirection = getTripsForDate(route_id, date).stream() - .filter(t -> t.direction_id == direction_id) - .collect(Collectors.toList()); - - return patternStats.getStartTimeForTrips(tripsForRouteDirection); - } - - /** - * Get latest arrival time for a given route direction on the specified date. - * @param route_id - * @param direction_id - * @param date - * @return last arrival time - */ - public LocalTime getEndTimeForRouteDirection (String route_id, int direction_id, LocalDate date) { - List tripsForRouteDirection = getTripsForDate(route_id, date).stream() - .filter(t -> t.direction_id == direction_id) - .collect(Collectors.toList()); - - return patternStats.getEndTimeForTrips(tripsForRouteDirection); - } - - public Map getTripCountPerDateOfService(String route_id) { - - Route route = feed.routes.get(route_id); - if (route == null) return null; - - Map> tripsPerDate = getTripsPerDateOfService(route_id); - Map tripCountPerDate = new HashMap<>(); - for (Map.Entry> entry : tripsPerDate.entrySet()) { - LocalDate date = entry.getKey(); - Integer count = entry.getValue().size(); - tripCountPerDate.put(date, count); - } - - return tripCountPerDate; - } - - /** - * Returns a map of dates to list of trips for a given route. - * @param route_id - * @return mapping of trips to dates - */ - public Map> getTripsPerDateOfService(String route_id) { - Map> tripsPerDate = stats.getTripsPerDateOfService(); - for (Map.Entry> e : tripsPerDate.entrySet()) { - LocalDate date = e.getKey(); - List trips = e.getValue().stream() - .filter(t -> t.route_id.equals(route_id)) - .collect(Collectors.toList()); - tripsPerDate.put(date, trips); - } - - return tripsPerDate; - } - - /** - * Gets all trips for a given route that operate on the specified date. - * @param route_id - * @param date - * @return - */ - public List getTripsForDate (String route_id, LocalDate date) { - Route route = feed.routes.get(route_id); - if (route == null) return null; - - List trips = stats.getTripsForDate(date).stream() - .filter(trip -> route_id.equals(trip.route_id)) - .collect(Collectors.toList()); - return trips; - } - - public long getTripCountForDate (String route_id, LocalDate date) { - return getTripsForDate(route_id, date).size(); - } - - /** - * Get average stop spacing for a route. - * @param route_id - * @return avg. stop spacing (in meters) - */ - public double getAverageStopSpacing (String route_id) { - return feed.patterns.values().stream() - .filter(p -> p.route_id.equals(route_id)) - .map(p -> stats.pattern.getAverageStopSpacing(p.pattern_id)) - .mapToDouble(headway -> headway) - .average() - .getAsDouble(); - } - - public RouteStatistic getStatisticForRoute (String route_id, LocalDate date, LocalTime from, LocalTime to) { - RouteStatistic rs = new RouteStatistic(this, route_id, date, from, to); - - return rs; - } - - public String getKCMetroStatistics () { - for (Route route : feed.routes.values()) { - - } - return null; - } - - public String getStatisticsAsCsv () { - return null; - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/StopStats.java b/src/main/java/com/conveyal/gtfs/stats/StopStats.java deleted file mode 100644 index 703f24c50..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/StopStats.java +++ /dev/null @@ -1,281 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.model.Route; -import com.conveyal.gtfs.model.Service; -import com.conveyal.gtfs.model.StopTime; -import com.conveyal.gtfs.model.Trip; -import com.conveyal.gtfs.stats.model.TransferPerformanceSummary; -import gnu.trove.list.TIntList; -import gnu.trove.list.array.TIntArrayList; -import org.mapdb.Fun; - -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -/** - * Created by landon on 9/2/16. - */ -public class StopStats { - - private GTFSFeed feed = null; - private FeedStats stats = null; - private RouteStats routeStats = null; - - public StopStats (GTFSFeed f, FeedStats fs) { - feed = f; - stats = fs; - routeStats = stats.route; - } - - public List getRoutes (String stop_id) { - return feed.patterns.values().stream() - .filter(p -> p.orderedStops.contains(stop_id)) - .distinct() - .map(p -> feed.routes.get(p.route_id)) - .collect(Collectors.toList()); - } - - /** - * Gets count of routes that visit a stop. - * @param stop_id - * @return count of routes for stop - */ - public int getRouteCount (String stop_id) { - return getRoutes(stop_id).size(); - } - - /** - * Gets count of trips that visit a stop for a specified date of service. - * @param stop_id - * @param date - * @return count of trips for date - */ - public int getTripCountForDate (String stop_id, LocalDate date) { - return (int) getTripsForDate(stop_id, date).size(); - } - - /** - * Get list of trips that visit a stop for a specified date of service. - * @param stop_id - * @param date - * @return list of trips for date - */ - public List getTripsForDate (String stop_id, LocalDate date) { - List tripIds = stats.getTripsForDate(date).stream() - .map(trip -> trip.trip_id) - .collect(Collectors.toList()); - - return feed.getDistinctTripsForStop(stop_id).stream() - .filter(t -> tripIds.contains(t.trip_id)) // filter by trip_id list for date - .collect(Collectors.toList()); - } - - /** - * Get the average headway, in seconds, for all trips at a stop over a time window. - * @param stop_id - * @param date - * @param from - * @param to - * @return avg. headway (in seconds) - */ - public int getAverageHeadwayForStop (String stop_id, LocalDate date, LocalTime from, LocalTime to) { - List tripsForStop = getTripsForDate(stop_id, date); - - return getStopHeadwayForTrips(stop_id, tripsForStop, from, to); - } - - /** Get the route headway for a given service date at a stop over a time window, in seconds */ - public Map getRouteHeadwaysForStop (String stop_id, LocalDate date, LocalTime from, LocalTime to) { - Map routeHeadwayMap = new HashMap<>(); - List routes = feed.patterns.values().stream() - .filter(p -> p.orderedStops.contains(stop_id)) - .map(p -> feed.routes.get(p.route_id)) - .collect(Collectors.toList()); - - for (Route route : routes) { - routeHeadwayMap.put(route.route_id, getHeadwayForStopByRoute(stop_id, route.route_id, date, from, to)); - } - return routeHeadwayMap; - } - - /** - * Get the average headway, in seconds, for a set of trips at a stop over a time window. - * @param stop_id - * @param trips - * @param from - * @param to - * @return avg. headway (in seconds) - */ - //TODO: add direction_id? - //TODO: specified stop vs. first stop - public int getStopHeadwayForTrips (String stop_id, List trips, LocalTime from, LocalTime to) { - TIntList timesAtStop = new TIntArrayList(); - Set tripIds = trips.stream() - .map(t -> t.trip_id) - .collect(Collectors.toSet()); - - List stopTimes = feed.getStopTimesForStop(stop_id).stream() - .filter(st -> tripIds.contains(st.trip_id)) - .collect(Collectors.toList()); - - for (StopTime st : stopTimes) { - - // these trips are actually running on the next day, skip them - if (st.departure_time > 86399 || st.departure_time < 0) continue; - - LocalTime timeAtStop = LocalTime.ofSecondOfDay(st.departure_time); - - if (timeAtStop.isAfter(to) || timeAtStop.isBefore(from)) { - continue; - } - - timesAtStop.add(st.departure_time); - } - timesAtStop.sort(); - - // convert to deltas - TIntList deltas = new TIntArrayList(); - - for (int i = 0; i < timesAtStop.size() - 1; i++) { - int delta = timesAtStop.get(i + 1) - timesAtStop.get(i); - - if (delta > 60) deltas.add(delta); - } - - if (deltas.isEmpty()) return -1; - - return deltas.sum() / deltas.size(); - } - - /** - * Get the average headway, in seconds, for a route at a stop over a time window. - * @param stop_id - * @param route_id - * @param date - * @param from - * @param to - * @return avg. headway (in seconds) - */ - public int getHeadwayForStopByRoute (String stop_id, String route_id, LocalDate date, LocalTime from, LocalTime to) { - - List tripsForStop = feed.getDistinctTripsForStop(stop_id).stream() - .filter(trip -> feed.trips.get(trip.trip_id).route_id.equals(route_id)) - .filter(trip -> feed.services.get(trip.service_id).activeOn(date)) - .collect(Collectors.toList()); - - return getStopHeadwayForTrips(stop_id, tripsForStop, from, to); - } - - /** - * Returns a list of transfer performance summaries (max, min, and median wait times between routes) - * for each route pair at a stop for the specified date of service. - * @param stop_id - * @param date - * @return - */ - public List getTransferPerformance (String stop_id, LocalDate date) { - List stopTimes = feed.getStopTimesForStop(stop_id); - - Map> routeStopTimeMap = new HashMap<>(); - List transferPerformanceMap = new ArrayList<>(); - // TODO: do we need to handle interpolated stop times??? - - // first stream stopTimes for stop into route -> list of stopTimes map - stopTimes.stream() - .forEach(st -> { - Trip trip = feed.trips.get(st.trip_id); - Service service = feed.services.get(trip.service_id); - // only add to map if trip is active on given date - if (service != null && service.activeOn(date)) { - Route route = feed.routes.get(trip.route_id); - - List times = new ArrayList<>(); - if (routeStopTimeMap.containsKey(route.route_id)) { - times.addAll(routeStopTimeMap.get(route.route_id)); - } - times.add(st); - routeStopTimeMap.put(route.route_id, times); - } - }); - Map, TIntList> waitTimesByRoute = new HashMap<>(); - Map, Set>> missedTransfers = new HashMap<>(); - // iterate over every entry in route -> list of stopTimes map - for (Map.Entry> entry : routeStopTimeMap.entrySet()) { - final int MISSED_TRANSFER_THRESHOLD = 60 * 10; - List currentTimes = entry.getValue(); - - String currentRoute = entry.getKey(); - - for (StopTime currentTime : currentTimes) { - if (currentTime.arrival_time > 0) { - // cycle through all other routes that stop here. - for (Map.Entry> entry2 : routeStopTimeMap.entrySet()) { - - List compareTimes = entry2.getValue(); - String compareRoute = entry2.getKey(); - Fun.Tuple2 routeKey = new Fun.Tuple2(currentRoute, compareRoute); - if (compareRoute.equals(currentRoute)) { - continue; - } - if (!waitTimesByRoute.containsKey(routeKey)) { - waitTimesByRoute.put(routeKey, new TIntArrayList()); - } - - int shortestWait = Integer.MAX_VALUE; - // compare current time against departure times for route - for (StopTime compareTime : compareTimes) { - if (compareTime.departure_time > 0) { - int waitTime = compareTime.departure_time - currentTime.arrival_time; - - // if non-negative and shortest, save for later - if (waitTime >= 0 && waitTime < shortestWait){ - shortestWait = waitTime; - } - // otherwise, check for missed near-transfer opportunities - else { - if (waitTime < 0 && waitTime * -1 <= MISSED_TRANSFER_THRESHOLD) { - Fun.Tuple2 missedTransfer = new Fun.Tuple2(compareTime, currentTime); -// missedTransfer.add(currentTime); -// missedTransfer.add(compareTime); - if (!missedTransfers.containsKey(routeKey)) { - missedTransfers.put(routeKey, new HashSet<>()); - } - missedTransfers.get(routeKey).add(missedTransfer); - } - } - } - } - // add shortestWait for currentTime to map - if (shortestWait < Integer.MAX_VALUE) - waitTimesByRoute.get(routeKey).add(shortestWait); - } - } - } - } - for (Map.Entry, TIntList> entry : waitTimesByRoute.entrySet()) { - Fun.Tuple2 routeKey = entry.getKey(); - TIntList waitTimes = entry.getValue(); - if (waitTimes.isEmpty()) { - continue; - } - int min = waitTimes.min(); - int max = waitTimes.max(); - waitTimes.sort(); - int median = waitTimes.get(waitTimes.size() / 2); - TransferPerformanceSummary routeTransferPerformance = new TransferPerformanceSummary(routeKey.a, routeKey.b, min, max, median, missedTransfers.get(routeKey)); - transferPerformanceMap.add(routeTransferPerformance); - } - - return transferPerformanceMap; - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/model/AgencyStatistic.java b/src/main/java/com/conveyal/gtfs/stats/model/AgencyStatistic.java deleted file mode 100644 index 1f9046862..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/model/AgencyStatistic.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.conveyal.gtfs.stats.model; - -import java.awt.geom.Rectangle2D; -import java.io.Serializable; -import java.time.LocalDate; - -/** - * Model object representing statistics about GTFS. - * - */ -public class AgencyStatistic implements Serializable { - private String agencyId; - private Integer routeCount; - private Integer tripCount; - private Integer stopCount; - private Integer stopTimeCount; - private LocalDate calendarServiceStart; - private LocalDate calendarServiceEnd; - private LocalDate calendarStartDate; - private LocalDate calendarEndDate; - private Rectangle2D bounds; - - public String getAgencyId() { - return agencyId; - } - public void setAgencyId(String agencyId) { - this.agencyId = agencyId; - } - public Integer getRouteCount() { - return routeCount; - } - public void setRouteCount(Integer routeCount) { - this.routeCount = routeCount; - } - public Integer getTripCount() { - return tripCount; - } - public void setTripCount(Integer tripCount) { - this.tripCount = tripCount; - } - public Integer getStopCount() { - return stopCount; - } - public void setStopCount(Integer stopCount) { - this.stopCount = stopCount; - } - public Integer getStopTimeCount() { - return stopTimeCount; - } - public void setStopTimeCount(Integer stopTimeCount) { - this.stopTimeCount = stopTimeCount; - } - public LocalDate getCalendarStartDate() { - return calendarStartDate; - } - public void setCalendarStartDate(LocalDate calendarStartDate) { - this.calendarStartDate = calendarStartDate; - } - public LocalDate getCalendarEndDate() { - return calendarEndDate; - } - public void setCalendarEndDate(LocalDate calendarEndDate) { - this.calendarEndDate = calendarEndDate; - } - public LocalDate getCalendarServiceStart() { - return calendarServiceStart; - } - public void setCalendarServiceStart(LocalDate calendarServiceStart) { - this.calendarServiceStart = calendarServiceStart; - } - public LocalDate getCalendarServiceEnd() { - return calendarServiceEnd; - } - public void setCalendarServiceEnd(LocalDate calendarServiceEnd) { - this.calendarServiceEnd = calendarServiceEnd; - } - public Rectangle2D getBounds() { - return bounds; - } - public void setBounds(Rectangle2D bounds) { - this.bounds = bounds; - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/model/FeedStatistic.java b/src/main/java/com/conveyal/gtfs/stats/model/FeedStatistic.java deleted file mode 100644 index f7c987b44..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/model/FeedStatistic.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.conveyal.gtfs.stats.model; - -import com.conveyal.gtfs.stats.FeedStats; -import com.vividsolutions.jts.geom.Geometry; - -import java.awt.geom.Rectangle2D; -import java.io.Serializable; -import java.time.LocalDate; -import java.time.LocalTime; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Created by landon on 10/11/16. - */ -public class FeedStatistic implements Serializable { - - public String feed_id; - public int headway; - public Double avgSpeed; - public long revenueTime; - public LocalDate startDate; - public LocalDate endDate; - public long agencyCount; - public long routeCount; - public long stopCount; - public long tripCount; - public long frequencyCount; - public long stopTimeCount; - public long shapePointCount; - public long fareAttributeCount; - public long fareRuleCount; - public long serviceCount; - public List datesOfService; - public Rectangle2D bounds; - public Geometry mergedBuffers; - - public FeedStatistic (FeedStats stats, LocalDate date, LocalTime from, LocalTime to) { - feed_id = stats.feed_id; - headway = stats.getDailyAverageHeadway(date, from, to); - avgSpeed = stats.getAverageTripSpeed(date, from, to); - tripCount = stats.getTripCount(date); - revenueTime = stats.getTotalRevenueTimeForDate(date); - } - - public FeedStatistic (FeedStats stats) { - feed_id = stats.feed_id; - this.startDate = stats.getStartDate(); - this.endDate = stats.getEndDate(); - this.agencyCount = stats.getAgencyCount(); - this.routeCount = stats.getRouteCount(); - this.stopCount = stats.getStopCount(); - this.tripCount = stats.getTripCount(); - this.frequencyCount = stats.getFrequencyCount(); - this.stopTimeCount = stats.getStopTimesCount(); - this.shapePointCount = stats.getShapePointCount(); - this.fareAttributeCount = stats.getFareAttributeCount(); - this.fareRuleCount = stats.getFareRulesCount(); - this.serviceCount= stats.getServiceCount(); - this.datesOfService = stats.getDatesOfService(); - this.bounds = stats.getBounds(); - this.revenueTime = stats.getAverageWeekdayRevenueTime(); - this.mergedBuffers = stats.getMergedBuffers(); - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/model/PatternStatistic.java b/src/main/java/com/conveyal/gtfs/stats/model/PatternStatistic.java deleted file mode 100644 index 4fde536a0..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/model/PatternStatistic.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.conveyal.gtfs.stats.model; - -import com.conveyal.gtfs.stats.PatternStats; - -import java.io.Serializable; -import java.time.LocalDate; -import java.time.LocalTime; - -/** - * Created by landon on 10/11/16. - */ -public class PatternStatistic implements Serializable { - - public String pattern_id; - public int headway; - public Double avgSpeed; - public long tripCount; - public double stopSpacing; -// public Double avgSpeedOffPeak; -// private LocalDate calendarServiceEnd; -// private LocalDate calendarStartDate; -// private LocalDate calendarEndDate; -// private Rectangle2D bounds; - - public PatternStatistic (PatternStats stats, String pattern_id, LocalDate date, LocalTime from, LocalTime to) { - this.pattern_id = pattern_id; - headway = stats.getHeadwayForPattern(this.pattern_id, date, from, to); - avgSpeed = stats.getPatternSpeed(this.pattern_id, date, from, to); - tripCount = stats.getTripCountForDate(this.pattern_id, date); - stopSpacing = stats.getAverageStopSpacing(this.pattern_id); - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/model/RouteStatistic.java b/src/main/java/com/conveyal/gtfs/stats/model/RouteStatistic.java deleted file mode 100644 index e29a8cc57..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/model/RouteStatistic.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.conveyal.gtfs.stats.model; - -import com.conveyal.gtfs.GTFSFeed; -import com.conveyal.gtfs.stats.FeedStats; -import com.conveyal.gtfs.stats.RouteStats; - -import java.awt.geom.Rectangle2D; -import java.io.Serializable; -import java.time.LocalDate; -import java.time.LocalTime; - -/** - * Created by landon on 9/2/16. - */ -public class RouteStatistic implements Serializable { - public String route_id; - public String routeName; - public int headway; - public Double avgSpeed; - public long tripCount; - public double stopSpacing; -// public Double avgSpeedOffPeak; -// private LocalDate calendarServiceEnd; -// private LocalDate calendarStartDate; -// private LocalDate calendarEndDate; -// private Rectangle2D bounds; - - public RouteStatistic (RouteStats stats, String route_id, LocalDate date, LocalTime from, LocalTime to) { - this.route_id = route_id; - routeName = stats.getRouteName(route_id); - // TODO: add fields for inbound and outbound directions - headway = stats.getHeadwayForRouteDirection(this.route_id, 0, date, from, to); - avgSpeed = stats.getSpeedForRouteDirection(this.route_id, 0, date, from, to); - tripCount = stats.getTripCountForDate(this.route_id, date); - stopSpacing = stats.getAverageStopSpacing(this.route_id); - } - - public static String getHeaderAsCsv () { - StringBuffer buffer = new StringBuffer(); - - buffer.append("route_id"); - buffer.append(","); - buffer.append("routeName"); - buffer.append(","); - buffer.append("headway"); - buffer.append(","); - buffer.append("avgSpeed"); - - return buffer.toString(); - } - public String asCsv () { - StringBuffer buffer = new StringBuffer(); - - buffer.append(route_id); - buffer.append(","); - buffer.append(routeName); - buffer.append(","); - buffer.append(headway); - buffer.append(","); - buffer.append(avgSpeed); - - return buffer.toString(); - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/model/StopStatistic.java b/src/main/java/com/conveyal/gtfs/stats/model/StopStatistic.java deleted file mode 100644 index 85dfd2b39..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/model/StopStatistic.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.conveyal.gtfs.stats.model; - -import com.conveyal.gtfs.stats.StopStats; - -import java.io.Serializable; -import java.time.LocalDate; -import java.time.LocalTime; - -/** - * Created by landon on 10/4/16. - */ -public class StopStatistic implements Serializable { - public String stop_id; - public int headway; - public int routeCount; - public int tripCount; -// public TransferPerformanceSummary transferPerformanceSummary; - - public StopStatistic (StopStats stats, String stop_id, LocalDate date, LocalTime from, LocalTime to) { - this.stop_id = stop_id; - headway = stats.getAverageHeadwayForStop(stop_id, date, from, to); - routeCount = stats.getRouteCount(stop_id); - tripCount = stats.getTripCountForDate(stop_id, date); // TODO: filter by time window? -// transferPerformanceSummary = new TransferPerformanceSummary(stats, stop_id, date); - } -} diff --git a/src/main/java/com/conveyal/gtfs/stats/model/TransferPerformanceSummary.java b/src/main/java/com/conveyal/gtfs/stats/model/TransferPerformanceSummary.java deleted file mode 100644 index f9c6f55cb..000000000 --- a/src/main/java/com/conveyal/gtfs/stats/model/TransferPerformanceSummary.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.conveyal.gtfs.stats.model; - -import com.conveyal.gtfs.model.StopTime; -import org.mapdb.Fun; - -import java.io.Serializable; -import java.util.Set; - -/** - * Created by landon on 10/4/16. - */ -public class TransferPerformanceSummary implements Serializable { - public String fromRoute; - public String toRoute; - public int bestCase; - public int worstCase; - public int typicalCase; - public Set> missedOpportunities; - - /** - * - * @param fromRoute - * @param toRoute - * @param minWaitTime - * @param maxWaitTime - * @param avgWaitTime - * @param missedTransfers - */ - public TransferPerformanceSummary (String fromRoute, String toRoute, int minWaitTime, int maxWaitTime, int avgWaitTime, Set> missedTransfers) { - this.fromRoute = fromRoute; - this.toRoute = toRoute; - bestCase = minWaitTime; - worstCase = maxWaitTime; - typicalCase = avgWaitTime; - missedOpportunities = missedTransfers; - } - - public String toString () { - return String.format("From routes %s to %s, the best case transfer time is %d seconds, worst case is %d seconds, and typical case is %d seconds. %d missed near-transfer opportunities.", fromRoute, toRoute, bestCase, worstCase, typicalCase, missedOpportunities.size()); - } - -} diff --git a/src/main/java/com/conveyal/gtfs/validator/model/ValidationResult.java b/src/main/java/com/conveyal/gtfs/validator/model/ValidationResult.java index 09e5cd202..e1427c55a 100644 --- a/src/main/java/com/conveyal/gtfs/validator/model/ValidationResult.java +++ b/src/main/java/com/conveyal/gtfs/validator/model/ValidationResult.java @@ -2,8 +2,6 @@ import com.conveyal.gtfs.GTFSFeed; import com.conveyal.gtfs.error.GTFSError; -import com.conveyal.gtfs.stats.FeedStats; -import com.conveyal.gtfs.stats.model.FeedStatistic; import java.io.Serializable; import java.util.Date; @@ -13,14 +11,12 @@ public class ValidationResult implements Serializable { public String fileName; public String validationTimestamp; - public FeedStatistic feedStatistics; public long errorCount; public NavigableSet errors; - public ValidationResult (String fileName, GTFSFeed feed, FeedStats feedStats) { + public ValidationResult (String fileName, GTFSFeed feed) { this.fileName = fileName; this.validationTimestamp = new Date().toString(); - this.feedStatistics = new FeedStatistic(feedStats); this.errorCount = feed.errors.size(); this.errors = feed.errors; } diff --git a/src/main/java/com/conveyal/gtfs/validator/service/StatisticsService.java b/src/main/java/com/conveyal/gtfs/validator/service/StatisticsService.java deleted file mode 100644 index ca21cba8c..000000000 --- a/src/main/java/com/conveyal/gtfs/validator/service/StatisticsService.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.conveyal.gtfs.validator.service; - -import com.conveyal.gtfs.stats.model.AgencyStatistic; - -import java.awt.geom.Rectangle2D; -import java.time.LocalDate; - -/** - * Provides statistics for: - * - *
  • Agencies - *
  • Routes - *
  • Trips - *
  • Stops - *
  • Stop Times - *
  • Calendar Date ranges - *
  • Calendar Service exceptions - * - * @author dev - * - */ -public interface StatisticsService { - - Integer getAgencyCount(); - - Integer getRouteCount(); - - Integer getTripCount(); - - Integer getStopCount(); - - Integer getStopTimesCount(); - - LocalDate getCalendarDateStart(); - - LocalDate getCalendarDateEnd(); - - LocalDate getCalendarServiceRangeStart(); - - LocalDate getCalendarServiceRangeEnd(); - - Integer getRouteCount(String agencyId); - - Integer getTripCount(String agencyId); - - Integer getStopCount(String agencyId); - - Integer getStopTimesCount(String agencyId); - - LocalDate getCalendarDateStart(String agencyId); - - LocalDate getCalendarDateEnd(String agencyId); - - LocalDate getCalendarServiceRangeStart(String agencyId); - - LocalDate getCalendarServiceRangeEnd(String agencyId); - - Rectangle2D getBounds(); - - AgencyStatistic getStatistic(String agencyId); -} diff --git a/src/test/java/com/conveyal/gtfs/GTFSFeedTest.java b/src/test/java/com/conveyal/gtfs/GTFSFeedTest.java index f7f877069..f04c4b22a 100644 --- a/src/test/java/com/conveyal/gtfs/GTFSFeedTest.java +++ b/src/test/java/com/conveyal/gtfs/GTFSFeedTest.java @@ -170,18 +170,6 @@ public void canDoRoundtripLoadAndWriteToZipFile() throws IOException { } } - /** - * Make sure the correct timezone of a stop is returned - */ - @Test - public void canGetAgencyTimeZoneForStop() { - GTFSFeed feed = GTFSFeed.fromFile(simpleGtfsZipFileName); - assertThat( - feed.getAgencyTimeZoneForStop("4u6g").getId(), - equalTo("America/Los_Angeles") - ); - } - /** * Make sure that a GTFS feed with interpolated stop times have calculated times after feed processing * @throws GTFSFeed.FirstAndLastStopsDoNotHaveTimes @@ -232,18 +220,6 @@ public void canGetInterpolatedTimes() throws GTFSFeed.FirstAndLastStopsDoNotHave } } - /** - * Make sure a list of services for a date can be calculated - */ - @Test - public void canGetServicesForDate() { - GTFSFeed feed = GTFSFeed.fromFile(simpleGtfsZipFileName); - assertThat( - feed.getServicesForDate(LocalDate.of(2017,9,17)).get(0).service_id, - equalTo("04100312-8fe1-46a5-a9f2-556f39478f57") - ); - } - /** * Make sure a spatial index of stops can be calculated */ diff --git a/src/test/java/com/conveyal/gtfs/stats/FeedStatsTest.java b/src/test/java/com/conveyal/gtfs/stats/FeedStatsTest.java deleted file mode 100644 index da30e88c2..000000000 --- a/src/test/java/com/conveyal/gtfs/stats/FeedStatsTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.conveyal.gtfs.stats; - -import com.conveyal.gtfs.GTFSFeed; - -import org.junit.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -/** - * Unit tests to verify functionality of items with the FeedStats class. - */ -public class FeedStatsTest { - - /***************************************** - * getAverageWeekdayRevenueTime - *****************************************/ - - /** - * This test makes sure that a FeedStats is able to run the getAverageWeekdayRevenueTime method - * when given an empty GTFSFeed instance. - */ - @Test - public void canCalculateWithEmptyFeed() { - GTFSFeed feed = new GTFSFeed(); - FeedStats feedStats = new FeedStats(feed); - assertThat(feedStats.getAverageWeekdayRevenueTime(), equalTo(0L)); - } -}