11
11
import com .conveyal .analysis .models .OpportunityDataset ;
12
12
import com .conveyal .analysis .models .RegionalAnalysis ;
13
13
import com .conveyal .analysis .persistence .Persistence ;
14
+ import com .conveyal .analysis .results .AccessCsvResultWriter ;
14
15
import com .conveyal .analysis .results .CsvResultType ;
16
+ import com .conveyal .analysis .results .GridResultWriter ;
15
17
import com .conveyal .analysis .results .MultiOriginAssembler ;
18
+ import com .conveyal .analysis .results .PathCsvResultWriter ;
19
+ import com .conveyal .analysis .results .RegionalResultWriter ;
20
+ import com .conveyal .analysis .results .TemporalDensityCsvResultWriter ;
21
+ import com .conveyal .analysis .results .TimeCsvResultWriter ;
16
22
import com .conveyal .analysis .util .JsonUtil ;
17
23
import com .conveyal .file .FileStorage ;
18
24
import com .conveyal .file .FileStorageFormat ;
47
53
import static com .conveyal .analysis .util .JsonUtil .toJson ;
48
54
import static com .conveyal .file .FileCategory .BUNDLES ;
49
55
import static com .conveyal .file .FileCategory .RESULTS ;
56
+ import static com .conveyal .r5 .common .Util .notNullOrEmpty ;
50
57
import static com .conveyal .r5 .transit .TransportNetworkCache .getScenarioFilename ;
51
58
import static com .google .common .base .Preconditions .checkArgument ;
52
59
import static com .google .common .base .Preconditions .checkNotNull ;
@@ -459,7 +466,7 @@ private RegionalAnalysis createRegionalAnalysis (Request req, Response res) thro
459
466
// In fact, there are three separate classes all containing almost the same info:
460
467
// AnalysisRequest (from UI to backend), RegionalTask (template sent to worker), RegionalAnalysis (in Mongo).
461
468
// And for regional analyses, two instances of the worker task: the one with the scenario, and the templateTask.
462
- RegionalAnalysis regionalAnalysis = new RegionalAnalysis ();
469
+ final RegionalAnalysis regionalAnalysis = new RegionalAnalysis ();
463
470
regionalAnalysis .request = task ;
464
471
regionalAnalysis .height = task .height ;
465
472
regionalAnalysis .north = task .north ;
@@ -508,13 +515,16 @@ private RegionalAnalysis createRegionalAnalysis (Request req, Response res) thro
508
515
509
516
// Persist this newly created RegionalAnalysis to Mongo.
510
517
// This assigns it creation/update time stamps and an ID, which is needed to name any output CSV files.
511
- regionalAnalysis = Persistence .regionalAnalyses .create (regionalAnalysis );
518
+ Persistence .regionalAnalyses .create (regionalAnalysis );
512
519
513
520
// Create the regional job
514
521
var regionalJob = new Job (task , WorkerTags .fromRegionalAnalysis (regionalAnalysis ));
515
522
523
+ // Create the result writers
524
+ var writers = createResultWriters (regionalAnalysis , task );
525
+
516
526
// Create the multi-origin assembler with the writers.
517
- var assembler = new MultiOriginAssembler (regionalJob , regionalAnalysis . createResultWriters ( task ) );
527
+ var assembler = new MultiOriginAssembler (regionalJob , writers );
518
528
519
529
// Stored scenario is needed by workers. Must be done ahead of enqueueing the job.
520
530
storeRegionalAnalysisScenarioJson (task );
@@ -530,6 +540,57 @@ private RegionalAnalysis createRegionalAnalysis (Request req, Response res) thro
530
540
return regionalAnalysis ;
531
541
}
532
542
543
+ /**
544
+ * Create results writers for this regional analysis and a task. Stores the result paths that are created by the
545
+ * writers.
546
+ */
547
+ private static List <RegionalResultWriter > createResultWriters (RegionalAnalysis analysis , RegionalTask task ) {
548
+ // Create the result writers. Store their result file paths in the database.
549
+ var resultWriters = new ArrayList <RegionalResultWriter >();
550
+ if (!task .makeTauiSite ) {
551
+ if (task .recordAccessibility ) {
552
+ if (task .originPointSet != null ) {
553
+ // Freeform origins - create CSV regional analysis results
554
+ var accessWriter = new AccessCsvResultWriter (task );
555
+ resultWriters .add (accessWriter );
556
+ analysis .resultStorage .put (accessWriter .resultType (), accessWriter .getFileName ());
557
+ } else {
558
+ // Gridded origins - create gridded regional analysis results
559
+ resultWriters .addAll (GridResultWriter .createWritersFromTask (analysis .destinationPointSetIds , task ));
560
+ }
561
+ }
562
+
563
+ if (task .recordTimes ) {
564
+ var timesWriter = new TimeCsvResultWriter (task );
565
+ resultWriters .add (timesWriter );
566
+ analysis .resultStorage .put (timesWriter .resultType (), timesWriter .getFileName ());
567
+ }
568
+
569
+ if (task .includePathResults ) {
570
+ var pathsWriter = new PathCsvResultWriter (task );
571
+ resultWriters .add (pathsWriter );
572
+ analysis .resultStorage .put (pathsWriter .resultType (), pathsWriter .getFileName ());
573
+ }
574
+
575
+ if (task .includeTemporalDensity ) {
576
+ if (task .originPointSet == null ) {
577
+ // Gridded origins. The full temporal density information is probably too voluminous to be useful.
578
+ // We might want to record a grid of dual accessibility values, but this will require some serious
579
+ // refactoring of the GridResultWriter.
580
+ // if (job.templateTask.dualAccessibilityThreshold > 0) { ... }
581
+ throw new RuntimeException ("Temporal density of opportunities cannot be recorded for gridded origin points." );
582
+ } else {
583
+ var tDensityWriter = new TemporalDensityCsvResultWriter (task );
584
+ resultWriters .add (tDensityWriter );
585
+ analysis .resultStorage .put (tDensityWriter .resultType (), tDensityWriter .getFileName ());
586
+ }
587
+ }
588
+
589
+ checkArgument (notNullOrEmpty (resultWriters ), "A regional analysis should always create at least one grid or CSV file." );
590
+ }
591
+ return resultWriters ;
592
+ }
593
+
533
594
/**
534
595
* Store the regional analysis scenario as JSON for retrieval by the workers.
535
596
*/
0 commit comments