use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class ConvertToFrequencyTest method testBidirectional.
/**
* Test bidirectional conversion
*/
@Test
public void testBidirectional() throws Exception {
Graph gg = buildGraphNoTransit();
addTransitBidirectional(gg);
link(gg);
gg.index(new DefaultStreetVertexIndexFactory());
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();
assertTrue(rrpr2.raptorWorkerData.hasFrequencies);
assertEquals(2, rrpr2.raptorWorkerData.timetablesForPattern.size());
// make sure we got trips in both directions
RaptorWorkerTimetable tt = rrpr2.raptorWorkerData.timetablesForPattern.get(0);
RaptorWorkerTimetable tt2 = rrpr2.raptorWorkerData.timetablesForPattern.get(1);
assertEquals(2, tt2.stopIndices.length);
assertEquals(2, tt.stopIndices.length);
assertEquals(tt.stopIndices[0], tt2.stopIndices[1]);
assertEquals(tt.stopIndices[1], tt2.stopIndices[0]);
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class InitialStopsTest method testInitialStopWalkSpeedIncrease.
/**
* Test that increasing the walk speed on a walk-to-transit search
* a) decreases or leaves unchanged all access times.
* b) allows access to a superset of the originally accessible stops.
* c) decreases at least some access times.
*
* There was once a bug where bike speed was not correctly applied because we used the distance not the speed.
*/
@Test
public void testInitialStopWalkSpeedIncrease() throws Exception {
Graph g = buildGraphNoTransit();
addRegularStopGrid(g);
addTransitMultipleLines(g);
link(g);
g.index(new DefaultStreetVertexIndexFactory());
ProfileRequest req = new ProfileRequest();
req.fromLon = req.toLon = -83.0118;
req.fromLat = req.toLat = 39.9908;
req.date = new LocalDate(2015, 9, 17);
req.bikeSpeed = 4.1f;
req.walkSpeed = 1.3f;
req.fromTime = 7 * 3600;
req.toTime = 9 * 3600;
req.maxBikeTime = 20;
req.maxWalkTime = 20;
req.transitModes = new TraverseModeSet("TRANSIT");
req.accessModes = req.egressModes = req.directModes = new QualifiedModeSet("WALK");
RaptorWorkerData data = RepeatedRaptorProfileRouter.getRaptorWorkerData(req, g, null, new TaskStatistics());
assertNotNull(data);
RepeatedRaptorProfileRouter rrpr = new RepeatedRaptorProfileRouter(g, req);
TIntIntMap initialStops1 = rrpr.findInitialStops(false, data);
assertFalse(initialStops1.isEmpty());
// let's get crazy, set walk speed really high.
req.walkSpeed = 25f;
data = RepeatedRaptorProfileRouter.getRaptorWorkerData(req, g, null, new TaskStatistics());
assertNotNull(data);
rrpr = new RepeatedRaptorProfileRouter(g, req);
TIntIntMap initialStops2 = rrpr.findInitialStops(false, data);
// we should find decreases to at least some stops
boolean foundDecreases = false;
for (TIntIntIterator it = initialStops1.iterator(); it.hasNext(); ) {
it.advance();
// the reached stops from the faster search should be a superset of the reached stops from the slower search
assertTrue(initialStops2.containsKey(it.key()));
assertTrue("Found increase in travel time to stop", initialStops2.get(it.key()) <= it.value());
foundDecreases = foundDecreases || initialStops2.get(it.key()) < it.value() - EPSILON;
}
assertTrue("No decreases were found due to increased walk speed", foundDecreases);
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class InitialStopsTest method testInitialStopBikeSpeedIncrease.
/**
* Test that increasing the bike speed on a bike-to-transit search
* a) decreases or leaves unchanged all access times.
* b) allows access to a superset of the originally accessible stops.
*
* There was once a bug where bike speed was not correctly applied because we used the distance not the speed.
*/
@Test
public void testInitialStopBikeSpeedIncrease() throws Exception {
Graph g = buildGraphNoTransit();
addRegularStopGrid(g);
addTransitMultipleLines(g);
link(g);
g.index(new DefaultStreetVertexIndexFactory());
ProfileRequest req = new ProfileRequest();
req.fromLon = req.toLon = -83.0118;
req.fromLat = req.toLat = 39.9908;
req.date = new LocalDate(2015, 9, 17);
req.bikeSpeed = 4.1f;
req.walkSpeed = 1.3f;
req.fromTime = 7 * 3600;
req.toTime = 9 * 3600;
req.maxBikeTime = 20;
req.transitModes = new TraverseModeSet("TRANSIT");
req.accessModes = req.egressModes = req.directModes = new QualifiedModeSet("BICYCLE");
RaptorWorkerData data = RepeatedRaptorProfileRouter.getRaptorWorkerData(req, g, null, new TaskStatistics());
assertNotNull(data);
RepeatedRaptorProfileRouter rrpr = new RepeatedRaptorProfileRouter(g, req);
TIntIntMap initialStops1 = rrpr.findInitialStops(false, data);
assertFalse(initialStops1.isEmpty());
// let's get crazy, set bike speed really high.
req.bikeSpeed = 25f;
data = RepeatedRaptorProfileRouter.getRaptorWorkerData(req, g, null, new TaskStatistics());
assertNotNull(data);
rrpr = new RepeatedRaptorProfileRouter(g, req);
TIntIntMap initialStops2 = rrpr.findInitialStops(false, data);
// we should find decreases to at least some stops
boolean foundDecreases = false;
for (TIntIntIterator it = initialStops1.iterator(); it.hasNext(); ) {
it.advance();
// the reached stops from the faster search should be a superset of the reached stops from the slower search
assertTrue(initialStops2.containsKey(it.key()));
assertTrue("Found increase in travel time to stop", initialStops2.get(it.key()) <= it.value());
foundDecreases = foundDecreases || initialStops2.get(it.key()) < it.value() - EPSILON;
}
assertTrue(foundDecreases);
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class RepeatedRaptorTestResource method oneOrigin.
private void oneOrigin(double lat, double lon, String banAgency) {
ProfileRequest req = new ProfileRequest();
req.fromLat = lat;
req.fromLon = lon;
req.fromTime = 60 * 60 * 8;
req.toTime = 60 * 60 * 9;
req.walkSpeed = 2;
req.bikeSpeed = 4;
req.carSpeed = 8;
req.date = new LocalDate(2015, 04, 20);
// minutes
req.maxWalkTime = 20;
req.accessModes = new QualifiedModeSet("WALK");
req.egressModes = new QualifiedModeSet("WALK");
req.transitModes = new TraverseModeSet("TRANSIT");
req.analyst = true;
if (surfaceCache == null) {
LOG.error("You must run OTP with the --analyst option to enable spatial analysis features.");
}
final RepeatedRaptorProfileRouter router_a = new RepeatedRaptorProfileRouter(graph, req);
final RepeatedRaptorProfileRouter router_b = new RepeatedRaptorProfileRouter(graph, req);
router_b.banAgency = banAgency;
try {
router_a.route();
router_b.route();
} catch (VertexNotFoundException ex) {
LOG.error("vertex not found");
return;
}
System.out.printf("stop, min_a, min_b, min_diff, max_a, max_b, max_diff\n");
boolean decreased = false;
// Compare the propagated results
decreased = false;
TimeSurface.RangeSet timeSurfaces_a = router_a.timeSurfaceRangeSet;
TimeSurface.RangeSet timeSurfaces_b = router_b.timeSurfaceRangeSet;
for (Vertex destVertex : timeSurfaces_a.min.times.keySet()) {
int min_a = timeSurfaces_a.min.getTime(destVertex);
int max_a = timeSurfaces_a.max.getTime(destVertex);
int avg_a = timeSurfaces_a.avg.getTime(destVertex);
int min_b = timeSurfaces_b.min.getTime(destVertex);
int max_b = timeSurfaces_b.max.getTime(destVertex);
int avg_b = timeSurfaces_b.avg.getTime(destVertex);
long min_diff = (long) min_b - min_a;
long max_diff = (long) max_b - max_a;
long avg_diff = (long) avg_b - avg_a;
if (min_b == TimeSurface.UNREACHABLE) {
min_diff = Integer.MAX_VALUE;
max_diff = Integer.MAX_VALUE;
avg_diff = Integer.MAX_VALUE;
}
n_total += 1;
if (min_diff < 0 || max_diff < 0 || avg_diff < 0) {
n_decrease += 1;
sum_decrease += max_diff;
// Time decreased due to banning a route. This is bad, print it out.
System.out.printf("\"%s\",%d,%d,%d,%d,%d,%d\n", destVertex.getName(), min_a, min_b, min_diff, max_a, max_b, max_diff);
decreased = true;
} else if (avg_diff > 0) {
n_increase += 1;
}
}
if (decreased) {
LOG.error("Decreases happened at propagated street vertices for this origin!");
}
LOG.info("Street Vertices: {} increased, {} decreased out of {} destinations total", n_increase, n_decrease, n_total);
}
use of org.opentripplanner.profile.RepeatedRaptorProfileRouter in project OpenTripPlanner by opentripplanner.
the class AnalystWorker method handleOneRequest.
/**
* This is the callback that processes a single task and returns the results upon completion.
* It may be called several times simultaneously on different executor threads.
*/
private void handleOneRequest(AnalystClusterRequest clusterRequest) {
if (dryRunFailureRate >= 0) {
// but will fail a certain percentage of the time.
if (random.nextInt(100) >= dryRunFailureRate) {
// Pretend to succeed.
deleteRequest(clusterRequest);
} else {
LOG.info("Intentionally failing on task {}", clusterRequest.taskId);
}
return;
}
try {
long startTime = System.currentTimeMillis();
LOG.info("Handling message {}", clusterRequest.toString());
// We need to distinguish between and handle four different types of requests here:
// Either vector isochrones or accessibility to a pointset,
// as either a single-origin priority request (where the result is returned immediately)
// or a job task (where the result is saved to output location on S3).
boolean isochrone = (clusterRequest.destinationPointsetId == null);
boolean singlePoint = (clusterRequest.outputLocation == null);
boolean transit = (clusterRequest.profileRequest.transitModes != null && clusterRequest.profileRequest.transitModes.isTransit());
if (singlePoint) {
lastHighPriorityRequestProcessed = startTime;
if (!sideChannelOpen) {
openSideChannel();
}
}
TaskStatistics ts = new TaskStatistics();
ts.pointsetId = clusterRequest.destinationPointsetId;
ts.graphId = clusterRequest.graphId;
ts.awsInstanceType = instanceType;
ts.jobId = clusterRequest.jobId;
ts.workerId = machineId;
ts.single = singlePoint;
// Get the graph object for the ID given in the request, fetching inputs and building as needed.
// All requests handled together are for the same graph, and this call is synchronized so the graph will
// only be built once.
long graphStartTime = System.currentTimeMillis();
Graph graph = clusterGraphBuilder.getGraph(clusterRequest.graphId);
// Record graphId so we "stick" to this same graph on subsequent polls
graphId = clusterRequest.graphId;
ts.graphBuild = (int) (System.currentTimeMillis() - graphStartTime);
ts.graphTripCount = graph.index.patternForTrip.size();
ts.graphStopCount = graph.index.stopForId.size();
ts.lon = clusterRequest.profileRequest.fromLon;
ts.lat = clusterRequest.profileRequest.fromLat;
final SampleSet sampleSet;
// fetch the set of points we will use as destinations.
if (isochrone) {
// This is an isochrone request, tell the RepeatedRaptorProfileRouter there are no targets.
sampleSet = null;
} else {
// This is not an isochrone request. There is necessarily a destination point set supplied.
PointSet pointSet = pointSetDatastore.get(clusterRequest.destinationPointsetId);
// TODO this breaks if graph has been rebuilt
sampleSet = pointSet.getOrCreateSampleSet(graph);
}
// Note that all parameters to create the Raptor worker data are passed in the constructor except ts.
// Why not pass in ts as well since this is a throwaway calculator?
RepeatedRaptorProfileRouter router = new RepeatedRaptorProfileRouter(graph, clusterRequest.profileRequest, sampleSet);
router.ts = ts;
// But then we'd need to pass in both the cache and the key, which is weird.
if (transit && !singlePoint) {
long dataStart = System.currentTimeMillis();
router.raptorWorkerData = workerDataCache.get(clusterRequest.jobId, () -> RepeatedRaptorProfileRouter.getRaptorWorkerData(clusterRequest.profileRequest, graph, sampleSet, ts));
ts.raptorData = (int) (System.currentTimeMillis() - dataStart);
} else {
// The worker will generate a one-time throw-away table.
router.raptorWorkerData = null;
}
// Run the core repeated-raptor analysis.
// This result envelope will contain the results of the one-to-many profile or single-departure-time search.
ResultEnvelope envelope = new ResultEnvelope();
try {
// TODO when router runs, if there are no transit modes defined it should just skip the transit work.
router.includeTimes = clusterRequest.includeTimes;
envelope = router.route();
envelope.id = clusterRequest.id;
ts.success = true;
} catch (Exception ex) {
// An error occurred. Leave the envelope empty and TODO include error information.
LOG.error("Error occurred in profile request", ex);
ts.success = false;
}
// Send the ResultEnvelope back to the user.
// The results are either stored on S3 (for multi-origin jobs) or sent back through the broker (for
// immediate interactive display of isochrones).
envelope.id = clusterRequest.id;
envelope.jobId = clusterRequest.jobId;
envelope.destinationPointsetId = clusterRequest.destinationPointsetId;
if (clusterRequest.outputLocation != null) {
// Convert the result envelope and its contents to JSON and gzip it in this thread.
// Transfer the results to Amazon S3 in another thread, piping between the two.
String s3key = String.join("/", clusterRequest.jobId, clusterRequest.id + ".json.gz");
PipedInputStream inPipe = new PipedInputStream();
PipedOutputStream outPipe = new PipedOutputStream(inPipe);
new Thread(() -> {
s3.putObject(clusterRequest.outputLocation, s3key, inPipe, null);
}).start();
OutputStream gzipOutputStream = new GZIPOutputStream(outPipe);
// We could do the writeValue() in a thread instead, in which case both the DELETE and S3 options
// could consume it in the same way.
objectMapper.writeValue(gzipOutputStream, envelope);
gzipOutputStream.close();
// Tell the broker the task has been handled and should not be re-delivered to another worker.
deleteRequest(clusterRequest);
} else {
// No output location was provided. Instead of saving the result on S3,
// return the result immediately via a connection held open by the broker and mark the task completed.
finishPriorityTask(clusterRequest, envelope);
}
// Record information about the current task so we can analyze usage and efficiency over time.
ts.total = (int) (System.currentTimeMillis() - startTime);
statsStore.store(ts);
} catch (Exception ex) {
LOG.error("An error occurred while routing", ex);
}
}
Aggregations