use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class ConvertToFrequencyTest method testSimpleConversion.
/**
* The simplest case of frequency conversion: no weird loop routes or anything like that, travel times always same, etc.
*/
@Test
public void testSimpleConversion() throws Exception {
Graph gg = buildGraphNoTransit();
addTransit(gg);
link(gg);
gg.index(new DefaultStreetVertexIndexFactory());
ProfileRequest pr1 = new ProfileRequest();
pr1.date = new LocalDate(2015, 6, 10);
pr1.fromTime = 7 * 3600;
pr1.toTime = 9 * 3600;
pr1.fromLat = pr1.toLat = 39.9621;
pr1.fromLon = pr1.toLon = -83.0007;
pr1.accessModes = pr1.egressModes = pr1.directModes = new QualifiedModeSet("WALK");
pr1.transitModes = new TraverseModeSet("TRANSIT");
RepeatedRaptorProfileRouter rrpr1 = new RepeatedRaptorProfileRouter(gg, pr1);
rrpr1.route();
ProfileRequest pr2 = new ProfileRequest();
pr2.date = new LocalDate(2015, 6, 10);
pr2.fromTime = 7 * 3600;
pr2.toTime = 9 * 3600;
pr2.fromLat = pr2.toLat = 39.9621;
pr2.fromLon = pr2.toLon = -83.0007;
pr2.accessModes = pr2.egressModes = pr2.directModes = new QualifiedModeSet("WALK");
pr2.transitModes = new TraverseModeSet("TRANSIT");
ConvertToFrequency ctf = new ConvertToFrequency();
ctf.groupBy = ConvertToFrequency.ConversionGroup.ROUTE_DIRECTION;
ctf.routeId = new String[] { "route" };
ctf.windowStart = 5 * 3600;
ctf.windowEnd = 10 * 3600;
pr2.scenario = new Scenario(0);
pr2.scenario.modifications = Arrays.asList(ctf);
RepeatedRaptorProfileRouter rrpr2 = new RepeatedRaptorProfileRouter(gg, pr2);
rrpr2.route();
assertFalse(rrpr1.raptorWorkerData.hasFrequencies);
assertTrue(rrpr2.raptorWorkerData.hasFrequencies);
RaptorWorkerTimetable tt = rrpr2.raptorWorkerData.timetablesForPattern.get(0);
assertEquals(FakeGraph.FREQUENCY, tt.headwaySecs[0]);
assertEquals(FakeGraph.TRAVEL_TIME, tt.frequencyTrips[0][2]);
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class ConvertToFrequencyTest method testMultiplePatterns.
/**
* Test the case where there are multiple patterns that need to be chosen from.
*/
@Test
public void testMultiplePatterns() throws Exception {
Graph gg = buildGraphNoTransit();
addMultiplePatterns(gg);
link(gg);
gg.index(new DefaultStreetVertexIndexFactory());
ProfileRequest pr1 = new ProfileRequest();
pr1.date = new LocalDate(2015, 6, 10);
pr1.fromTime = 7 * 3600;
pr1.toTime = 9 * 3600;
pr1.fromLat = pr1.toLat = 39.9621;
pr1.fromLon = pr1.toLon = -83.0007;
pr1.accessModes = pr1.egressModes = pr1.directModes = new QualifiedModeSet("WALK");
pr1.transitModes = new TraverseModeSet("TRANSIT");
RepeatedRaptorProfileRouter rrpr1 = new RepeatedRaptorProfileRouter(gg, pr1);
rrpr1.route();
ProfileRequest pr2 = new ProfileRequest();
pr2.date = new LocalDate(2015, 6, 10);
pr2.fromTime = 7 * 3600;
pr2.toTime = 9 * 3600;
pr2.fromLat = pr2.toLat = 39.9621;
pr2.fromLon = pr2.toLon = -83.0007;
pr2.accessModes = pr2.egressModes = pr2.directModes = new QualifiedModeSet("WALK");
pr2.transitModes = new TraverseModeSet("TRANSIT");
ConvertToFrequency ctf = new ConvertToFrequency();
ctf.groupBy = ConvertToFrequency.ConversionGroup.ROUTE_DIRECTION;
ctf.routeId = new String[] { "route" };
ctf.windowStart = 5 * 3600;
ctf.windowEnd = 10 * 3600;
pr2.scenario = new Scenario(0);
pr2.scenario.modifications = Arrays.asList(ctf);
RepeatedRaptorProfileRouter rrpr2 = new RepeatedRaptorProfileRouter(gg, pr2);
rrpr2.route();
assertFalse(rrpr1.raptorWorkerData.hasFrequencies);
assertTrue(rrpr2.raptorWorkerData.hasFrequencies);
// everything should have gotten merged into one pattern
assertEquals(1, rrpr2.raptorWorkerData.timetablesForPattern.size());
RaptorWorkerTimetable tt = rrpr2.raptorWorkerData.timetablesForPattern.get(0);
// should be no frequency variation because trips on all patterns are considered for frequencies.
// there should be no travel time variation because only trips on the dominant pattern are considered
// for travel time.
assertEquals(FakeGraph.FREQUENCY, tt.headwaySecs[0]);
assertEquals(FakeGraph.TRAVEL_TIME, tt.frequencyTrips[0][2]);
// now try it with groupings by pattern
ConvertToFrequency ctf3 = new ConvertToFrequency();
ctf3.groupBy = ConvertToFrequency.ConversionGroup.PATTERN;
ctf3.routeId = new String[] { "route" };
ctf3.windowStart = 5 * 3600;
ctf3.windowEnd = 10 * 3600;
ProfileRequest pr3 = new ProfileRequest();
pr3.date = new LocalDate(2015, 6, 10);
pr3.fromTime = 7 * 3600;
pr3.toTime = 9 * 3600;
pr3.fromLat = pr2.toLat = 39.9621;
pr3.fromLon = pr2.toLon = -83.0007;
pr3.accessModes = pr2.egressModes = pr2.directModes = new QualifiedModeSet("WALK");
pr3.transitModes = new TraverseModeSet("TRANSIT");
pr3.scenario = new Scenario(0);
pr3.scenario.modifications = Arrays.asList(ctf3);
RepeatedRaptorProfileRouter rrpr3 = new RepeatedRaptorProfileRouter(gg, pr3);
rrpr3.route();
assertTrue(rrpr3.raptorWorkerData.hasFrequencies);
// should be converted to two independent patterns
assertEquals(2, rrpr3.raptorWorkerData.timetablesForPattern.size());
RaptorWorkerTimetable shrt, lng;
if (rrpr3.raptorWorkerData.timetablesForPattern.get(0).nStops == 2) {
shrt = rrpr3.raptorWorkerData.timetablesForPattern.get(0);
lng = rrpr3.raptorWorkerData.timetablesForPattern.get(1);
} else {
lng = rrpr3.raptorWorkerData.timetablesForPattern.get(0);
shrt = rrpr3.raptorWorkerData.timetablesForPattern.get(1);
}
assertEquals(3, lng.nStops);
assertEquals(2, shrt.nStops);
assertEquals(675, lng.headwaySecs[0]);
assertEquals((int) (FakeGraph.FREQUENCY / 0.1), shrt.headwaySecs[0]);
// make sure that the hop time is always FakeGraph.TRAVEL_TIME
assertEquals(FakeGraph.TRAVEL_TIME, shrt.frequencyTrips[0][2]);
assertEquals(FakeGraph.TRAVEL_TIME, lng.frequencyTrips[0][2]);
assertEquals(FakeGraph.TRAVEL_TIME * 2, lng.frequencyTrips[0][4]);
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class ProfileResource method profileRoute.
@GET
@Produces({ MediaType.APPLICATION_JSON })
public Response profileRoute(@QueryParam("from") LatLon from, @QueryParam("to") LatLon to, @QueryParam("analyst") @DefaultValue("false") boolean analyst, @QueryParam("date") @DefaultValue("today") YearMonthDay date, @QueryParam("startTime") @DefaultValue("07:30") HourMinuteSecond fromTime, @QueryParam("endTime") @DefaultValue("08:30") HourMinuteSecond toTime, // m/sec
@QueryParam("walkSpeed") @DefaultValue("1.4") float walkSpeed, // m/sec
@QueryParam("bikeSpeed") @DefaultValue("4.1") float bikeSpeed, // m/sec
@QueryParam("carSpeed") @DefaultValue("20") float carSpeed, // max minutes to reach destination WITHOUT transit
@QueryParam("streetTime") @DefaultValue("90") int streetTime, // max minutes to reach transit on foot
@QueryParam("maxWalkTime") @DefaultValue("15") int maxWalkTime, @QueryParam("maxCarTime") @DefaultValue("30") int maxCarTime, @QueryParam("maxBikeTime") @DefaultValue("20") int maxBikeTime, @QueryParam("minCarTime") @DefaultValue("1") int minCarTime, @QueryParam("minBikeTime") @DefaultValue("1") int minBikeTime, @QueryParam("orderBy") @DefaultValue("AVG") Option.SortOrder orderBy, // max options to return PER ACCESS MODE
@QueryParam("limit") @DefaultValue("15") int limit, @QueryParam("suboptimal") @DefaultValue("5") int suboptimalMinutes, @QueryParam("bikeSafe") @DefaultValue("1") int bikeSafe, @QueryParam("bikeSlope") @DefaultValue("1") int bikeSlope, @QueryParam("bikeTime") @DefaultValue("1") int bikeTime, @QueryParam("accessModes") @DefaultValue("WALK,BICYCLE") QualifiedModeSet accessModes, @QueryParam("egressModes") @DefaultValue("WALK") QualifiedModeSet egressModes, @QueryParam("directModes") @DefaultValue("WALK,BICYCLE") QualifiedModeSet directModes, @QueryParam("transitModes") @DefaultValue("TRANSIT") TraverseModeSet transitModes, @QueryParam("banAgency") String banAgency) throws Exception {
QueryParameter.checkRangeInclusive(limit, 0, Integer.MAX_VALUE);
QueryParameter.checkRangeInclusive(walkSpeed, 0.5, 7);
QueryParameter.checkRangeInclusive(bikeSpeed, 1, 21);
QueryParameter.checkRangeInclusive(carSpeed, 1, 36);
QueryParameter.checkRangeInclusive(streetTime, 1, 480);
QueryParameter.checkRangeInclusive(maxWalkTime, 1, 480);
QueryParameter.checkRangeInclusive(maxBikeTime, 1, 480);
QueryParameter.checkRangeInclusive(maxCarTime, 1, 480);
QueryParameter.checkRangeInclusive(minBikeTime, 0, maxBikeTime);
QueryParameter.checkRangeInclusive(minCarTime, 0, maxCarTime);
QueryParameter.checkRangeInclusive(suboptimalMinutes, 0, 30);
QueryParameter.checkRangeInclusive(bikeSafe, 0, 1000);
QueryParameter.checkRangeInclusive(bikeSlope, 0, 1000);
QueryParameter.checkRangeInclusive(bikeTime, 0, 1000);
ProfileRequest req = new ProfileRequest();
req.fromLat = from.lat;
req.fromLon = from.lon;
// We need to provide some value though because lower-level routing requests are intolerant of a missing 'to'.
if (to == null)
to = from;
req.toLat = to.lat;
req.toLon = to.lon;
req.fromTime = fromTime.toSeconds();
req.toTime = toTime.toSeconds();
req.walkSpeed = walkSpeed;
req.bikeSpeed = bikeSpeed;
req.carSpeed = carSpeed;
req.date = date.toJoda();
req.orderBy = orderBy;
req.limit = limit;
req.accessModes = accessModes;
req.egressModes = egressModes;
req.directModes = directModes;
req.transitModes = transitModes;
req.analyst = analyst;
req.streetTime = streetTime;
req.maxWalkTime = maxWalkTime;
req.maxBikeTime = maxBikeTime;
req.maxCarTime = maxCarTime;
req.minBikeTime = minBikeTime;
req.minCarTime = minCarTime;
req.bikeSafe = bikeSafe;
req.bikeSlope = bikeSlope;
req.bikeTime = bikeTime;
req.suboptimalMinutes = suboptimalMinutes;
if (req.analyst) {
if (surfaceCache == null) {
LOG.error("You must run OTP with the --analyst option to enable spatial analysis features.");
}
TimeSurface.RangeSet result;
/* There are rarely frequency-only graphs. Use the Raptor profile router for both freqs and schedules. */
RepeatedRaptorProfileRouter router = new RepeatedRaptorProfileRouter(graph, req);
router.banAgency = banAgency;
router.route();
result = router.timeSurfaceRangeSet;
Map<String, Integer> idForSurface = Maps.newHashMap();
// requires analyst mode turned on
idForSurface.put("min", surfaceCache.add(result.min));
idForSurface.put("avg", surfaceCache.add(result.avg));
idForSurface.put("max", surfaceCache.add(result.max));
return Response.status(Status.OK).entity(idForSurface).build();
} else {
ProfileRouter router = new ProfileRouter(graph, req);
try {
ProfileResponse response = router.route();
return Response.status(Status.OK).entity(response).build();
} catch (Throwable throwable) {
LOG.error("Exception caught in profile routing", throwable);
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(throwable.toString()).build();
} finally {
// destroy routing contexts even when an exception happens
router.cleanup();
}
}
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class RepeatedRaptorComparison method main.
public static void main(String... args) {
if (args.length == 0) {
System.err.println("too few arguments.");
return;
}
// build a graph
File graphDir = new File(args[0]);
Graph graph = buildGraph(graphDir);
DB comparisonDb = null;
BTreeMap<Fun.Tuple3<String, String, ResultEnvelope.Which>, Integer> comparison = null;
// open the comparison file, if we have one.
if (args.length > 1) {
comparisonDb = DBMaker.newFileDB(new File(args[1])).readOnly().transactionDisable().closeOnJvmShutdown().cacheSize(24).asyncWriteEnable().make();
comparison = comparisonDb.getTreeMap("results");
}
String outputName = args.length > 2 ? args[2] : MavenVersion.VERSION.commit + ".db";
DB outputDb = DBMaker.newFileDB(new File(outputName)).transactionDisable().cacheSize(48).closeOnJvmShutdown().make();
final BTreeMap<Fun.Tuple3<String, String, ResultEnvelope.Which>, Integer> output = outputDb.createTreeMap("results").valueSerializer(Serializer.JAVA).makeOrGet();
// if we have a comparison file, get the pointset from it. Otherwise choose some randomly.
Collection<String> vertexLabels;
PointSet pset;
if (comparison != null) {
// clooge, pointset is stored in its own map in db.
pset = comparisonDb.<String, PointSet>getTreeMap("pointset").get("pointset");
} else {
// choose some vertices
List<Vertex> vertices = graph.getVertices().stream().filter(v -> v.getLabel().startsWith("osm:node:")).limit(1000).collect(Collectors.toList());
// make a pointset
pset = new PointSet(vertices.size());
int featIdx = 0;
for (Vertex v : vertices) {
PointFeature pf = new PointFeature();
pf.setId(v.getLabel());
pf.setLat(v.getLat() + OFFSET_Y);
pf.setLon(v.getLon() + OFFSET_X);
pset.addFeature(pf, featIdx++);
}
outputDb.createTreeMap("pointset").<String, PointSet>make().put("pointset", pset);
}
SampleSet ss = new SampleSet(pset, graph.getSampleFactory());
final BTreeMap<Fun.Tuple3<String, String, ResultEnvelope.Which>, Integer> comparisonResults = comparison;
Histogram bestCaseHisto = new Histogram("Best case");
Histogram avgCaseHisto = new Histogram("Average");
Histogram worstCaseHisto = new Histogram("Worst case");
ProfileRequest template = new ProfileRequest();
template.accessModes = new QualifiedModeSet("WALK");
template.analyst = true;
template.maxWalkTime = 20 * 60;
template.walkSpeed = 1.3f;
template.fromTime = 7 * 3600;
template.toTime = 9 * 3600;
template.date = new LocalDate(2015, 8, 4);
RaptorWorkerData data = RepeatedRaptorProfileRouter.getRaptorWorkerData(template, graph, ss, new TaskStatistics());
// do the computation and comparison
IntStream.range(0, pset.featureCount()).parallel().forEach(idx -> {
if (idx % 100 == 0)
System.out.println(idx + " points complete");
Coordinate coord = pset.getCoordinate(idx);
String origin = pset.getFeature(idx).getId();
ProfileRequest req;
try {
req = template.clone();
} catch (CloneNotSupportedException e) {
/* can't happen */
throw new RuntimeException(e);
}
req.maxWalkTime = 20 * 60;
req.fromLat = req.toLat = coord.y;
req.fromLon = req.toLon = coord.x;
// 7 to 9 AM
req.fromTime = 7 * 3600;
req.toTime = 9 * 3600;
req.transitModes = new TraverseModeSet("TRANSIT");
RepeatedRaptorProfileRouter rrpr = new RepeatedRaptorProfileRouter(graph, req, ss);
rrpr.raptorWorkerData = data;
rrpr.includeTimes = true;
// TODO we really want to disable both isochrone and accessibility generation here.
// Because a sampleSet is provided it's going to make accessibility information (not isochrones).
ResultEnvelope results = new ResultEnvelope();
try {
results = rrpr.route();
} catch (Exception e) {
LOG.error("Exception during routing", e);
return;
}
for (ResultEnvelope.Which which : new ResultEnvelope.Which[] { ResultEnvelope.Which.BEST_CASE, ResultEnvelope.Which.AVERAGE, ResultEnvelope.Which.WORST_CASE }) {
Histogram histogram;
ResultSet resultSet;
switch(which) {
case BEST_CASE:
histogram = bestCaseHisto;
resultSet = results.bestCase;
break;
case WORST_CASE:
histogram = worstCaseHisto;
resultSet = results.worstCase;
break;
case AVERAGE:
histogram = avgCaseHisto;
resultSet = results.avgCase;
break;
default:
histogram = null;
resultSet = null;
}
// comparison.
for (int i = 0; i < resultSet.times.length; i++) {
int time = resultSet.times[i];
// TODO this is creating a PointFeature obj to hold the id at each call
// Cache?
String dest = pset.getFeature(i).getId();
Fun.Tuple3<String, String, ResultEnvelope.Which> key = new Fun.Tuple3<>(origin, dest, which);
output.put(key, time);
if (time < 0) {
LOG.error("Path from {} to {} has negative time {}", origin, dest, time);
}
if (comparisonResults != null) {
int time0 = comparisonResults.get(key);
int deltaMinutes;
if (time0 == RaptorWorker.UNREACHED && time != RaptorWorker.UNREACHED)
deltaMinutes = (time / 60) - 120;
else if (time == RaptorWorker.UNREACHED && time0 != RaptorWorker.UNREACHED)
deltaMinutes = 120 - (time0 / 60);
else
deltaMinutes = (time - time0) / 60;
// histograms are not threadsafe
synchronized (histogram) {
histogram.add(deltaMinutes);
}
}
}
}
});
output.close();
if (comparisonDb != null) {
comparisonDb.close();
bestCaseHisto.displayHorizontal();
System.out.println("mean: " + bestCaseHisto.mean());
avgCaseHisto.displayHorizontal();
System.out.println("mean: " + avgCaseHisto.mean());
worstCaseHisto.displayHorizontal();
System.out.println("mean: " + worstCaseHisto.mean());
}
}
Aggregations