Skip to content

Commit c7a9ef7

Browse files
Handle thresholds getRegionalResults and getSingleCutoffGrid
Handle `threshold` taken as the query parameter and when to check for `cutoffsMinutes` vs `dualAccessibilityThresholds`.
1 parent cbf7b8a commit c7a9ef7

File tree

1 file changed

+29
-17
lines changed

1 file changed

+29
-17
lines changed

src/main/java/com/conveyal/analysis/controllers/RegionalAnalysisController.java

+29-17
Original file line numberDiff line numberDiff line change
@@ -192,28 +192,31 @@ private record HumanKey(FileStorageKey storageKey, String humanName) { };
192192
private HumanKey getSingleCutoffGrid (
193193
RegionalAnalysis analysis,
194194
OpportunityDataset destinations,
195-
int cutoffMinutes,
195+
int threshold,
196196
int percentile,
197197
FileStorageFormat fileFormat
198198
) throws IOException {
199199
final String regionalAnalysisId = analysis._id;
200200
final String destinationPointSetId = destinations._id;
201201
// Selecting the zeroth cutoff still makes sense for older analyses that don't allow an array of N cutoffs.
202-
int cutoffIndex = 0;
203-
if (analysis.cutoffsMinutes != null) {
204-
cutoffIndex = new TIntArrayList(analysis.cutoffsMinutes).indexOf(cutoffMinutes);
205-
checkState(cutoffIndex >= 0);
202+
int thresholdIndex = 0;
203+
if (analysis.request.includeTemporalDensity) {
204+
thresholdIndex = new TIntArrayList(analysis.request.dualAccessibilityThresholds).indexOf(threshold);
205+
checkState(thresholdIndex >= 0);
206+
} else if (analysis.cutoffsMinutes != null) {
207+
thresholdIndex = new TIntArrayList(analysis.cutoffsMinutes).indexOf(threshold);
208+
checkState(thresholdIndex >= 0);
206209
}
207210
LOG.info(
208211
"Returning {} minute accessibility to pointset {} (percentile {}) for regional analysis {} in format {}.",
209-
cutoffMinutes, destinationPointSetId, percentile, regionalAnalysisId, fileFormat
212+
threshold, destinationPointSetId, percentile, regionalAnalysisId, fileFormat
210213
);
211214
// Analysis grids now have the percentile and cutoff in their S3 key, because there can be many of each.
212215
// We do this even for results generated by older workers, so they will be re-extracted with the new name.
213216
// These grids are reasonably small, we may be able to just send all cutoffs to the UI instead of selecting.
214217
String singleCutoffKey = String.format(
215218
"%s_%s_P%d_C%d.%s",
216-
regionalAnalysisId, destinationPointSetId, percentile, cutoffMinutes,
219+
regionalAnalysisId, destinationPointSetId, percentile, threshold,
217220
fileFormat.extension.toLowerCase(Locale.ROOT)
218221
);
219222
FileStorageKey singleCutoffFileStorageKey = new FileStorageKey(RESULTS, singleCutoffKey);
@@ -247,7 +250,7 @@ private HumanKey getSingleCutoffGrid (
247250
LOG.debug("Single-cutoff grid {} not found on S3, deriving it from {}.", singleCutoffKey, multiCutoffKey);
248251

249252
InputStream multiCutoffInputStream = new FileInputStream(fileStorage.getFile(multiCutoffFileStorageKey));
250-
Grid grid = new SelectingGridReducer(cutoffIndex).compute(multiCutoffInputStream);
253+
Grid grid = new SelectingGridReducer(thresholdIndex).compute(multiCutoffInputStream);
251254

252255
File localFile = FileUtils.createScratchFile(fileFormat.toString());
253256
FileOutputStream fos = new FileOutputStream(localFile);
@@ -270,7 +273,7 @@ private HumanKey getSingleCutoffGrid (
270273
String analysisHumanName = humanNameForEntity(analysis);
271274
String destinationHumanName = humanNameForEntity(destinations);
272275
String resultHumanFilename = filenameCleanString(
273-
String.format("%s_%s_P%d_C%d", analysisHumanName, destinationHumanName, percentile, cutoffMinutes)
276+
String.format("%s_%s_P%d_C%d", analysisHumanName, destinationHumanName, percentile, threshold)
274277
) + "." + fileFormat.extension.toLowerCase(Locale.ROOT);
275278
// Note that the returned human filename already contains the appropriate extension.
276279
return new HumanKey(singleCutoffFileStorageKey, resultHumanFilename);
@@ -405,17 +408,26 @@ private UrlWithHumanName getRegionalResults (Request req, Response res) throws I
405408
// For newer analyses that have multiple cutoffs, percentiles, or destination pointsets, these initial values
406409
// are coming from deprecated fields, are not meaningful and will be overwritten below from query parameters.
407410
int percentile = analysis.travelTimePercentile;
408-
int cutoffMinutes = analysis.cutoffMinutes;
411+
int threshold = analysis.cutoffMinutes;
409412
String destinationPointSetId = analysis.grid;
410413

411-
// Handle newer regional analyses with multiple cutoffs in an array.
412-
// If a query parameter is supplied, range check it, otherwise use the middle value in the list.
413-
// The cutoff variable holds the actual cutoff in minutes, not the position in the array of cutoffs.
414-
if (analysis.cutoffsMinutes != null) {
414+
if (analysis.request.includeTemporalDensity) {
415+
int nThresholds = analysis.request.dualAccessibilityThresholds.length;
416+
int[] thresholds = analysis.request.dualAccessibilityThresholds;
417+
checkState(nThresholds > 0, "Regional analysis has no thresholds.");
418+
threshold = getIntQueryParameter(req, "threshold", thresholds[nThresholds / 2]);
419+
checkArgument(new TIntArrayList(thresholds).contains(threshold),
420+
"Dual accessibility thresholds for this regional analysis must be taken from this list: (%s)",
421+
Ints.join(", ", thresholds)
422+
);
423+
} else if (analysis.cutoffsMinutes != null) {
424+
// Handle newer regional analyses with multiple cutoffs in an array.
425+
// If a query parameter is supplied, range check it, otherwise use the middle value in the list.
426+
// The cutoff variable holds the actual cutoff in minutes, not the position in the array of cutoffs.
415427
int nCutoffs = analysis.cutoffsMinutes.length;
416428
checkState(nCutoffs > 0, "Regional analysis has no cutoffs.");
417-
cutoffMinutes = getIntQueryParameter(req, "cutoff", analysis.cutoffsMinutes[nCutoffs / 2]);
418-
checkArgument(new TIntArrayList(analysis.cutoffsMinutes).contains(cutoffMinutes),
429+
threshold = getIntQueryParameter(req, "cutoff", analysis.cutoffsMinutes[nCutoffs / 2]);
430+
checkArgument(new TIntArrayList(analysis.cutoffsMinutes).contains(threshold),
419431
"Travel time cutoff for this regional analysis must be taken from this list: (%s)",
420432
Ints.join(", ", analysis.cutoffsMinutes)
421433
);
@@ -452,7 +464,7 @@ private UrlWithHumanName getRegionalResults (Request req, Response res) throws I
452464
}
453465
// Significant overhead here: UI contacts backend, backend calls S3, backend responds to UI, UI contacts S3.
454466
OpportunityDataset destinations = getDestinations(destinationPointSetId, userPermissions);
455-
HumanKey gridKey = getSingleCutoffGrid(analysis, destinations, cutoffMinutes, percentile, format);
467+
HumanKey gridKey = getSingleCutoffGrid(analysis, destinations, threshold, percentile, format);
456468
res.type(APPLICATION_JSON.asString());
457469
return fileStorage.getJsonUrl(gridKey.storageKey, gridKey.humanName);
458470
}

0 commit comments

Comments
 (0)