@@ -192,28 +192,31 @@ private record HumanKey(FileStorageKey storageKey, String humanName) { };
192
192
private HumanKey getSingleCutoffGrid (
193
193
RegionalAnalysis analysis ,
194
194
OpportunityDataset destinations ,
195
- int cutoffMinutes ,
195
+ int threshold ,
196
196
int percentile ,
197
197
FileStorageFormat fileFormat
198
198
) throws IOException {
199
199
final String regionalAnalysisId = analysis ._id ;
200
200
final String destinationPointSetId = destinations ._id ;
201
201
// 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 );
206
209
}
207
210
LOG .info (
208
211
"Returning {} minute accessibility to pointset {} (percentile {}) for regional analysis {} in format {}." ,
209
- cutoffMinutes , destinationPointSetId , percentile , regionalAnalysisId , fileFormat
212
+ threshold , destinationPointSetId , percentile , regionalAnalysisId , fileFormat
210
213
);
211
214
// Analysis grids now have the percentile and cutoff in their S3 key, because there can be many of each.
212
215
// We do this even for results generated by older workers, so they will be re-extracted with the new name.
213
216
// These grids are reasonably small, we may be able to just send all cutoffs to the UI instead of selecting.
214
217
String singleCutoffKey = String .format (
215
218
"%s_%s_P%d_C%d.%s" ,
216
- regionalAnalysisId , destinationPointSetId , percentile , cutoffMinutes ,
219
+ regionalAnalysisId , destinationPointSetId , percentile , threshold ,
217
220
fileFormat .extension .toLowerCase (Locale .ROOT )
218
221
);
219
222
FileStorageKey singleCutoffFileStorageKey = new FileStorageKey (RESULTS , singleCutoffKey );
@@ -247,7 +250,7 @@ private HumanKey getSingleCutoffGrid (
247
250
LOG .debug ("Single-cutoff grid {} not found on S3, deriving it from {}." , singleCutoffKey , multiCutoffKey );
248
251
249
252
InputStream multiCutoffInputStream = new FileInputStream (fileStorage .getFile (multiCutoffFileStorageKey ));
250
- Grid grid = new SelectingGridReducer (cutoffIndex ).compute (multiCutoffInputStream );
253
+ Grid grid = new SelectingGridReducer (thresholdIndex ).compute (multiCutoffInputStream );
251
254
252
255
File localFile = FileUtils .createScratchFile (fileFormat .toString ());
253
256
FileOutputStream fos = new FileOutputStream (localFile );
@@ -270,7 +273,7 @@ private HumanKey getSingleCutoffGrid (
270
273
String analysisHumanName = humanNameForEntity (analysis );
271
274
String destinationHumanName = humanNameForEntity (destinations );
272
275
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 )
274
277
) + "." + fileFormat .extension .toLowerCase (Locale .ROOT );
275
278
// Note that the returned human filename already contains the appropriate extension.
276
279
return new HumanKey (singleCutoffFileStorageKey , resultHumanFilename );
@@ -405,17 +408,26 @@ private UrlWithHumanName getRegionalResults (Request req, Response res) throws I
405
408
// For newer analyses that have multiple cutoffs, percentiles, or destination pointsets, these initial values
406
409
// are coming from deprecated fields, are not meaningful and will be overwritten below from query parameters.
407
410
int percentile = analysis .travelTimePercentile ;
408
- int cutoffMinutes = analysis .cutoffMinutes ;
411
+ int threshold = analysis .cutoffMinutes ;
409
412
String destinationPointSetId = analysis .grid ;
410
413
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.
415
427
int nCutoffs = analysis .cutoffsMinutes .length ;
416
428
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 ),
419
431
"Travel time cutoff for this regional analysis must be taken from this list: (%s)" ,
420
432
Ints .join (", " , analysis .cutoffsMinutes )
421
433
);
@@ -452,7 +464,7 @@ private UrlWithHumanName getRegionalResults (Request req, Response res) throws I
452
464
}
453
465
// Significant overhead here: UI contacts backend, backend calls S3, backend responds to UI, UI contacts S3.
454
466
OpportunityDataset destinations = getDestinations (destinationPointSetId , userPermissions );
455
- HumanKey gridKey = getSingleCutoffGrid (analysis , destinations , cutoffMinutes , percentile , format );
467
+ HumanKey gridKey = getSingleCutoffGrid (analysis , destinations , threshold , percentile , format );
456
468
res .type (APPLICATION_JSON .asString ());
457
469
return fileStorage .getJsonUrl (gridKey .storageKey , gridKey .humanName );
458
470
}
0 commit comments