Java tutorial
/* * Copyright 2017 Public Transit Analytics. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.publictransitanalytics.scoregenerator; import com.bitvantage.bitvantagecaching.GsonSerializer; import com.publictransitanalytics.scoregenerator.geography.GeoLatitude; import com.publictransitanalytics.scoregenerator.geography.GeoPoint; import com.publictransitanalytics.scoregenerator.geography.AngleUnit; import com.publictransitanalytics.scoregenerator.geography.GeoBounds; import com.publictransitanalytics.scoregenerator.geography.GeoLongitude; import com.bitvantage.bitvantagecaching.RangedStore; import com.bitvantage.bitvantagecaching.Serializer; import com.bitvantage.bitvantagecaching.Store; import com.publictransitanalytics.scoregenerator.console.NetworkConsoleFactory; import com.publictransitanalytics.scoregenerator.console.DummyNetworkConsole; import com.publictransitanalytics.scoregenerator.console.InteractiveNetworkConsole; import com.publictransitanalytics.scoregenerator.console.NetworkConsole; import com.publictransitanalytics.scoregenerator.comparison.OperationDescription; import com.publictransitanalytics.scoregenerator.workflow.Environment; import com.publictransitanalytics.scoregenerator.workflow.Calculation; import com.google.common.collect.BiMap; import com.publictransitanalytics.scoregenerator.location.Landmark; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.publictransitanalytics.scoregenerator.comparison.ComparisonOperation; import com.publictransitanalytics.scoregenerator.comparison.Extension; import com.publictransitanalytics.scoregenerator.comparison.Reroute; import com.publictransitanalytics.scoregenerator.comparison.SequenceItem; import com.publictransitanalytics.scoregenerator.comparison.Stop; import com.publictransitanalytics.scoregenerator.comparison.Truncation; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; import java.time.LocalDateTime; import java.util.List; import java.util.NavigableSet; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ExecutionException; import lombok.extern.slf4j.Slf4j; import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.ArgumentParserException; import net.sourceforge.argparse4j.inf.Namespace; import com.publictransitanalytics.scoregenerator.datalayer.directories.ServiceDataDirectory; import com.publictransitanalytics.scoregenerator.datalayer.directories.StopDetailsDirectory; import com.publictransitanalytics.scoregenerator.datalayer.directories.types.StopDetails; import com.publictransitanalytics.scoregenerator.datalayer.environment.GridInfo; import com.publictransitanalytics.scoregenerator.datalayer.environment.GridPointAssociation; import com.publictransitanalytics.scoregenerator.datalayer.environment.SectorInfo; import com.publictransitanalytics.scoregenerator.datalayer.environment.GridIdKey; import com.publictransitanalytics.scoregenerator.datalayer.environment.GridPointAssociationKey; import com.publictransitanalytics.scoregenerator.datalayer.environment.SectorKey; import com.publictransitanalytics.scoregenerator.environment.Grid; import com.publictransitanalytics.scoregenerator.environment.StoredGrid; import com.publictransitanalytics.scoregenerator.environment.ReadingSegmentFinder; import com.publictransitanalytics.scoregenerator.geography.GeoJsonInEnvironmentDetector; import com.publictransitanalytics.scoregenerator.geography.InEnvironmentDetectorException; import com.publictransitanalytics.scoregenerator.location.Center; import com.publictransitanalytics.scoregenerator.output.ComparativeNetworkAccessibility; import com.publictransitanalytics.scoregenerator.output.ComparativePointAccessibility; import com.publictransitanalytics.scoregenerator.output.ComparativeTimeQualifiedPointAccessibility; import com.publictransitanalytics.scoregenerator.output.MapGenerator; import com.publictransitanalytics.scoregenerator.output.NetworkAccessibility; import com.publictransitanalytics.scoregenerator.output.PointAccessibility; import com.publictransitanalytics.scoregenerator.output.TimeQualifiedPointAccessibility; import com.publictransitanalytics.scoregenerator.publishing.LocalFilePublisher; import com.publictransitanalytics.scoregenerator.scoring.ScoreCard; import com.publictransitanalytics.scoregenerator.workflow.ProgressiveRangeExecutor; import java.util.ArrayList; import java.util.Collections; import net.sourceforge.argparse4j.inf.Subparser; import net.sourceforge.argparse4j.inf.Subparsers; import com.publictransitanalytics.scoregenerator.workflow.Workflow; import java.util.Map; import com.publictransitanalytics.scoregenerator.scoring.PathScoreCard; import com.publictransitanalytics.scoregenerator.scoring.PathScoreCardFactory; import com.publictransitanalytics.scoregenerator.scoring.ScoreCardFactory; import com.publictransitanalytics.scoregenerator.walking.BackwardTimeTracker; import com.publictransitanalytics.scoregenerator.walking.ForwardTimeTracker; import com.publictransitanalytics.scoregenerator.walking.TimeTracker; import com.publictransitanalytics.scoregenerator.workflow.DynamicProgrammingAlgorithm; import com.publictransitanalytics.scoregenerator.workflow.ForwardMovementAssembler; import com.publictransitanalytics.scoregenerator.workflow.MovementAssembler; import com.publictransitanalytics.scoregenerator.workflow.ParallelTaskExecutor; import com.publictransitanalytics.scoregenerator.workflow.RetrospectiveMovementAssembler; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.HashMap; import com.publictransitanalytics.scoregenerator.location.Sector; import com.publictransitanalytics.scoregenerator.location.TransitStop; import com.publictransitanalytics.scoregenerator.schedule.patching.Patch; import com.publictransitanalytics.scoregenerator.schedule.patching.ReferenceDirection; import com.publictransitanalytics.scoregenerator.schedule.patching.RouteDeletion; import com.publictransitanalytics.scoregenerator.schedule.patching.RouteExtension; import com.publictransitanalytics.scoregenerator.schedule.patching.RouteReroute; import com.publictransitanalytics.scoregenerator.schedule.patching.RouteSequenceItem; import com.publictransitanalytics.scoregenerator.schedule.patching.RouteTruncation; import com.publictransitanalytics.scoregenerator.schedule.patching.StopDeletion; import com.publictransitanalytics.scoregenerator.scoring.CountScoreCardFactory; import java.util.function.Function; @Slf4j /** * Parses inputs, builds up infrastructure, and delegates to solve reachability * problems. * * @author Public Transit Analytics */ public class Main { private static final double ESTIMATE_WALK_METERS_PER_SECOND = 2.0; private static final int RESOLUTION_METERS = 80; private static final String OSM_FILE = "environment.osm.pbf"; private static final String GRID_INFO_STORE = "grid_info_store"; private static final String SECTOR_INFO_STORE = "sector_info_store"; private static final String GRID_POINT_ASSOCATION_STORE = "grid_point_association_store"; private static final String WATER_BODIES_FILE = "water.json"; private static final String BORDER_FILE = "border.json"; public static void main(String[] args) throws FileNotFoundException, IOException, ArgumentParserException, InterruptedException, ExecutionException, InEnvironmentDetectorException { final Gson serializer = new GsonBuilder().setPrettyPrinting().create(); final ArgumentParser parser = ArgumentParsers.newArgumentParser("ScoreGenerator").defaultHelp(true) .description("Generate isochrone map data."); parser.addArgument("-l", "--tripLengths").action(Arguments.append()); parser.addArgument("-i", "--samplingInterval"); parser.addArgument("-s", "--span"); parser.addArgument("-d", "--baseDirectory"); parser.addArgument("-k", "--backward").action(Arguments.storeTrue()); parser.addArgument("-n", "--inMemCache").action(Arguments.storeTrue()); parser.addArgument("-t", "--interactive").action(Arguments.storeTrue()); parser.addArgument("-b", "--baseFile"); parser.addArgument("-u", "--bounds"); parser.addArgument("-c", "--comparisonFile"); parser.addArgument("-o", "--outputName"); final Subparsers subparsers = parser.addSubparsers().dest("command"); subparsers.addParser("generateNetworkAccessibility"); final Subparser generateSampledNetworkAccessibilityParser = subparsers .addParser("generateSampledNetworkAccessibility"); generateSampledNetworkAccessibilityParser.addArgument("-m", "--samples"); final Subparser generatePointAccessibilityParser = subparsers.addParser("generatePointAccessibility"); generatePointAccessibilityParser.addArgument("-c", "--coordinate"); final Namespace namespace = parser.parseArgs(args); final List<String> durationMinuteStrings = namespace.getList("tripLengths"); final NavigableSet<Duration> durations = new TreeSet<>(); for (String durationMinuteString : durationMinuteStrings) { final Duration duration = Duration.ofMinutes(Integer.valueOf(durationMinuteString)); durations.add(duration); } final String baseDirectoryString = namespace.get("baseDirectory"); final Path root = Paths.get(baseDirectoryString); final String baseFile = namespace.get("baseFile"); final OperationDescription baseDescription = serializer.fromJson( new String(Files.readAllBytes(Paths.get(baseFile)), StandardCharsets.UTF_8), OperationDescription.class); final String comparisonFile = namespace.get("comparisonFile"); final OperationDescription comparisonDescription = (comparisonFile == null) ? null : serializer.fromJson( new String(Files.readAllBytes(Paths.get(comparisonFile)), StandardCharsets.UTF_8), OperationDescription.class); final Boolean backwardObject = namespace.getBoolean("backward"); final boolean backward = (backwardObject == null) ? false : backwardObject; final Boolean interactiveObject = namespace.getBoolean("interactive"); final boolean interactive = (interactiveObject == null) ? false : interactiveObject; final NetworkConsoleFactory consoleFactory; if (interactive) { consoleFactory = (network, stopIdMap) -> new InteractiveNetworkConsole(network, stopIdMap); } else { consoleFactory = (network, stopIdMap) -> new DummyNetworkConsole(); } final String samplingIntervalString = namespace.get("samplingInterval"); final Duration samplingInterval = (samplingIntervalString != null) ? Duration.ofMinutes(Long.valueOf(samplingIntervalString)) : null; final String spanString = namespace.get("span"); final Duration span = (spanString != null) ? Duration.parse(spanString) : null; final String outputName = namespace.get("outputName"); final String command = namespace.get("command"); final LocalFilePublisher publisher = new LocalFilePublisher(); final ImmutableSet.Builder<String> fileNamesBuilder = ImmutableSet.builder(); fileNamesBuilder.add(baseDescription.getFiles()); if (comparisonDescription != null) { fileNamesBuilder.add(comparisonDescription.getFiles()); } final Set<String> fileNames = fileNamesBuilder.build(); final Boolean inMemCacheObject = namespace.getBoolean("inMemCache"); final StoreFactory storeFactory = (inMemCacheObject == null || inMemCacheObject == false) ? new NoCacheStoreFactory() : new UnboundedCacheStoreFactory(); final Map<String, ServiceDataDirectory> serviceDirectoriesMap = new HashMap<>(); for (final String fileName : fileNames) { if (!serviceDirectoriesMap.containsKey(fileName)) { final ServiceDataDirectory directory = new ServiceDataDirectory(root, fileName, storeFactory); serviceDirectoriesMap.put(fileName, directory); } } final String boundsString = namespace.get("bounds"); final GeoBounds bounds = parseBounds(boundsString); final Grid grid = getGrid(root, bounds, storeFactory); final MapGenerator mapGenerator = new MapGenerator(); final TimeTracker timeTracker; if (!backward) { timeTracker = new ForwardTimeTracker(); } else { timeTracker = new BackwardTimeTracker(); } if ("generatePointAccessibility".equals(command)) { generatePointAccessibility(namespace, baseDescription, backward, samplingInterval, span, durations, grid, serviceDirectoriesMap, comparisonDescription, publisher, serializer, mapGenerator, outputName, consoleFactory); } else if ("generateNetworkAccessibility".equals(command)) { final ScoreCardFactory scoreCardFactory = new CountScoreCardFactory(); final Set<Center> centers = getAllCenters(grid); final BiMap<OperationDescription, Calculation<ScoreCard>> result = Main.<ScoreCard>runComparison( baseDescription, scoreCardFactory, centers, samplingInterval, span, backward, timeTracker, grid, serviceDirectoriesMap, durations.last(), comparisonDescription, consoleFactory); final Set<Sector> sectors = grid.getReachableSectors(); publishNetworkAccessibility(baseDescription, comparisonDescription, result, grid, sectors, false, durations, span, samplingInterval, backward, publisher, serializer, mapGenerator, outputName); } else if ("generateSampledNetworkAccessibility".equals(command)) { final ScoreCardFactory scoreCardFactory = new CountScoreCardFactory(); final int samples = Integer.valueOf(namespace.get("samples")); final Set<Sector> allReachableSectors = grid.getReachableSectors(); final List<Sector> sectorList = new ArrayList<>(allReachableSectors); Collections.shuffle(sectorList); final Set<Sector> sampleSectors = ImmutableSet.copyOf(sectorList.subList(0, samples)); final Set<Center> centers = getSampleCenters(sampleSectors, grid); final BiMap<OperationDescription, Calculation<ScoreCard>> result = Main.<ScoreCard>runComparison( baseDescription, scoreCardFactory, centers, samplingInterval, span, backward, timeTracker, grid, serviceDirectoriesMap, durations.last(), comparisonDescription, consoleFactory); publishNetworkAccessibility(baseDescription, comparisonDescription, result, grid, sampleSectors, true, durations, span, samplingInterval, backward, publisher, serializer, mapGenerator, outputName); } } private static Set<Center> getSampleCenters(final Set<Sector> samples, final Grid grid) { final ImmutableSet.Builder<Center> builder = ImmutableSet.builder(); for (final Sector sector : samples) { builder.add(new Center(sector, grid.getGridPoints(sector))); } return builder.build(); } private static Set<Center> getAllCenters(final Grid grid) { final ImmutableSet.Builder<Center> builder = ImmutableSet.builder(); for (final Sector sector : grid.getReachableSectors()) { builder.add(new Center(sector, grid.getGridPoints(sector))); } return builder.build(); } private static List<Patch> getTripPatches(final OperationDescription description, final BiMap<String, TransitStop> stopIdMap) { final ImmutableList.Builder<Patch> builder = ImmutableList.builder(); final List<ComparisonOperation> operations = description.getOperations(); if (operations != null) { for (final ComparisonOperation operation : operations) { final String route = operation.getRoute(); final Stop stop = operation.getStop(); switch (operation.getOperator()) { case DELETE: if (route == null && stop != null) { final TransitStop deletedStop = stopIdMap.get(stop.getStopId()); final StopDeletion deletion = new StopDeletion(deletedStop); builder.add(deletion); } else if (route != null && stop == null) { final RouteDeletion deletion = new RouteDeletion(route); builder.add(deletion); } break; case ADD: break; case EXTEND: final Extension extension = operation.getExtension(); final RouteExtension routeExtension = getRouteExtension(route, extension, stopIdMap); builder.add(routeExtension); break; case TRUNCATE: final Truncation truncation = operation.getTruncation(); final RouteTruncation routeTruncation = getRouteTruncation(route, truncation, stopIdMap); builder.add(routeTruncation); break; case REROUTE: final Reroute reroute = operation.getReroute(); final RouteReroute routeReroute = getRouteReroute(route, reroute, stopIdMap); builder.add(routeReroute); break; } } } return builder.build(); } private static RouteTruncation getRouteTruncation(final String route, final Truncation truncation, final Map<String, TransitStop> stopIdMap) { final ReferenceDirection type = mapDirection(truncation.getDirection()); final TransitStop referenceStop = stopIdMap.get(truncation.getReferenceStopId()); final RouteTruncation routeTruncation = new RouteTruncation(route, referenceStop, type); return routeTruncation; } private static RouteExtension getRouteExtension(final String route, final Extension extension, final Map<String, TransitStop> stopIdMap) { final ReferenceDirection type = mapDirection(extension.getDirection()); final TransitStop referenceStop = stopIdMap.get(extension.getReferenceStopId()); final List<RouteSequenceItem> sequence = mapSequence(extension.getSequence(), stopIdMap); final RouteExtension routeExtension = new RouteExtension(route, referenceStop, type, sequence); return routeExtension; } private static RouteReroute getRouteReroute(final String route, final Reroute reroute, final Map<String, TransitStop> stopIdMap) { final ReferenceDirection type = mapDirection(reroute.getDirection()); final TransitStop referenceStop = stopIdMap.get(reroute.getReferenceStopId()); final String returnStopId = reroute.getReturnStopId(); final TransitStop returnStop = (returnStopId == null) ? null : stopIdMap.get(returnStopId); final String deltaString = reroute.getReturnDelta(); final Duration returnDelta = (deltaString == null) ? null : Duration.parse(deltaString); final List<RouteSequenceItem> sequence = mapSequence(reroute.getSequence(), stopIdMap); final RouteReroute routeReroute = new RouteReroute(route, referenceStop, type, sequence, returnStop, returnDelta); return routeReroute; } private static ReferenceDirection mapDirection( final com.publictransitanalytics.scoregenerator.comparison.ReferenceDirection type) { switch (type) { case BEFORE_FIRST: return ReferenceDirection.BEFORE_FIRST; case AFTER_LAST: return ReferenceDirection.AFTER_LAST; default: throw new ScoreGeneratorFatalException(String.format("Cannot convert extension type %s", type)); } } private static List<RouteSequenceItem> mapSequence(final List<SequenceItem> sequence, final Map<String, TransitStop> stopIdMap) { final ImmutableList.Builder<RouteSequenceItem> builder = ImmutableList.builder(); for (final SequenceItem item : sequence) { final String deltaString = item.getDelta(); final String stopId = item.getStopId(); final Duration delta = Duration.parse(deltaString); final TransitStop stop = stopIdMap.get(stopId); builder.add(new RouteSequenceItem(delta, stop)); } return builder.build(); } private static ServiceDataDirectory getServiceData(final OperationDescription description, final Map<String, ServiceDataDirectory> serviceDirectoriesMap) { final String files = description.getFiles(); final ServiceDataDirectory serviceDirectory = serviceDirectoriesMap.get(files); return serviceDirectory; } private static Set<TransitStop> getAddedStops(final OperationDescription description, final Grid grid) { final List<ComparisonOperation> operations = description.getOperations(); final ImmutableSet.Builder<TransitStop> builder = ImmutableSet.builder(); if (operations != null) { for (final ComparisonOperation operation : operations) { switch (operation.getOperator()) { case ADD: final Stop stopData = operation.getStop(); final GeoPoint location = GeoPoint.parseDegreeString(stopData.getLocation()); if (grid.coversPoint(location)) { final String name = stopData.getStopId(); final TransitStop newStop = new TransitStop(name, name, location); builder.add(newStop); } } } } return builder.build(); } private static Set<TransitStop> getDeletedStops(final OperationDescription description, final BiMap<String, TransitStop> stopIdMap) { final List<ComparisonOperation> operations = description.getOperations(); final ImmutableSet.Builder<TransitStop> builder = ImmutableSet.builder(); if (operations != null) { for (final ComparisonOperation operation : operations) { switch (operation.getOperator()) { case DELETE: final Stop stopData = operation.getStop(); if (stopData != null) { builder.add(stopIdMap.get(stopData.getStopId())); } } } } return builder.build(); } private static BiMap<String, TransitStop> buildTransitStopIdMap(final Grid grid, final StopDetailsDirectory stopDetailsDirectory) throws InterruptedException { final ImmutableBiMap.Builder<String, TransitStop> stopMapBuilder = ImmutableBiMap.builder(); for (final StopDetails stopDetails : stopDetailsDirectory.getAllStopDetails()) { final GeoPoint location = new GeoPoint( new GeoLongitude(stopDetails.getCoordinate().getLongitude(), AngleUnit.DEGREES), new GeoLatitude(stopDetails.getCoordinate().getLatitude(), AngleUnit.DEGREES)); if (grid.coversPoint(location)) { final TransitStop stop = new TransitStop(stopDetails.getStopId(), stopDetails.getStopName(), location); stopMapBuilder.put(stop.getIdentifier(), stop); } else { log.debug("Stop at {} location {} was skipped because it was not in the sector table.", stopDetails, location); } } return stopMapBuilder.build(); } private static <S extends ScoreCard> BiMap<OperationDescription, Calculation<S>> runComparison( final OperationDescription baseDescription, final ScoreCardFactory scoreCardFactory, final Set<Center> centers, final Duration samplingInterval, final Duration span, final boolean backward, final TimeTracker timeTracker, final Grid grid, final Map<String, ServiceDataDirectory> serviceDirectoriesMap, final Duration longestDuration, final OperationDescription comparisonDescription, final NetworkConsoleFactory consoleFactory) throws InterruptedException, IOException, ExecutionException { final ImmutableBiMap.Builder<OperationDescription, Calculation<S>> resultBuilder = ImmutableBiMap.builder(); final Calculation<S> calculation = buildCalculation(baseDescription, serviceDirectoriesMap, grid, centers, longestDuration, backward, span, samplingInterval, timeTracker, scoreCardFactory); final NetworkConsole console = consoleFactory.getConsole(calculation.getTransitNetwork(), calculation.getStopIdMap()); console.enterConsole(); resultBuilder.put(baseDescription, calculation); final Environment environment = new Environment(grid, longestDuration); if (comparisonDescription != null) { final Calculation trialCalculation = buildCalculation(comparisonDescription, serviceDirectoriesMap, grid, centers, longestDuration, backward, span, samplingInterval, timeTracker, scoreCardFactory); final NetworkConsole trialConsole = consoleFactory.getConsole(trialCalculation.getTransitNetwork(), trialCalculation.getStopIdMap()); trialConsole.enterConsole(); log.info("Trial in service time = {}; original in service time = {}.", trialCalculation.getTransitNetwork().getInServiceTime(), calculation.getTransitNetwork().getInServiceTime()); resultBuilder.put(comparisonDescription, trialCalculation); } final BiMap<OperationDescription, Calculation<S>> calculations = resultBuilder.build(); final Workflow workflow = new ParallelTaskExecutor( new ProgressiveRangeExecutor(new DynamicProgrammingAlgorithm(), environment)); workflow.calculate(calculations.values()); return calculations; } private static <S extends ScoreCard> Calculation<S> buildCalculation(final OperationDescription description, final Map<String, ServiceDataDirectory> serviceDirectoriesMap, final Grid grid, final Set<Center> centers, final Duration longestDuration, final boolean backward, final Duration span, final Duration samplingInterval, final TimeTracker timeTracker, final ScoreCardFactory scoreCardFactory) throws InterruptedException { final LocalDateTime startTime = LocalDateTime.parse(description.getStartTime()); final ServiceDataDirectory serviceDirectory = getServiceData(description, serviceDirectoriesMap); final BiMap<String, TransitStop> baseOriginalStopIdMap = buildTransitStopIdMap(grid, serviceDirectory.getStopDetailsDirectory()); final Set<TransitStop> addedStops = getAddedStops(description, grid); final BiMap<String, TransitStop> addedStopIdMap = addedStops.stream() .collect(ImmutableBiMap.toImmutableBiMap(stop -> stop.getIdentifier(), Function.identity())); final BiMap<String, TransitStop> stopIdMap = ImmutableBiMap.<String, TransitStop>builder() .putAll(addedStopIdMap).putAll(baseOriginalStopIdMap).build(); final List<Patch> basePatches = getTripPatches(description, baseOriginalStopIdMap); final Set<TransitStop> deletedStops = getDeletedStops(description, stopIdMap); final Calculation<S> calculation = new Calculation<>(grid, centers, longestDuration, backward, span, samplingInterval, ESTIMATE_WALK_METERS_PER_SECOND, timeTracker, serviceDirectoriesMap, scoreCardFactory, startTime, serviceDirectory, basePatches, addedStops, deletedStops, stopIdMap); return calculation; } private static void publishNetworkAccessibility(final OperationDescription base, final OperationDescription comparison, final BiMap<OperationDescription, Calculation<ScoreCard>> calculations, final Grid grid, final Set<Sector> centerSectors, final boolean markCenters, final NavigableSet<Duration> durations, final Duration span, final Duration samplingInterval, final boolean backward, final LocalFilePublisher publisher, final Gson serializer, final MapGenerator mapGenerator, final String outputName) throws InterruptedException, IOException { final Calculation baseCalculation = calculations.get(base); final ScoreCard scoreCard = baseCalculation.getScoreCard(); final Duration inServiceTime = baseCalculation.getTransitNetwork().getInServiceTime(); final int taskCount = scoreCard.getTaskCount(); final LocalDateTime startTime = LocalDateTime.parse(base.getStartTime()); final LocalDateTime endTime = startTime.plus(span); if (comparison == null) { final NetworkAccessibility map = new NetworkAccessibility(taskCount, scoreCard, grid, centerSectors, startTime, endTime, durations.last(), samplingInterval, backward, inServiceTime); publisher.publish(outputName, serializer.toJson(map)); mapGenerator.makeRangeMap(grid, scoreCard, Collections.emptySet(), 0, 0.2, outputName); } else { for (final OperationDescription trialComparison : calculations.keySet()) { final String name = comparison.getName(); final Calculation trialCalculation = calculations.get(trialComparison); final Duration trialInServiceTime = trialCalculation.getTransitNetwork().getInServiceTime(); final ScoreCard trialScoreCard = trialCalculation.getScoreCard(); final int trialTaskCount = trialScoreCard.getTaskCount(); final LocalDateTime trialStartTime = LocalDateTime.parse(comparison.getStartTime()); final LocalDateTime trialEndTime = startTime.plus(span); final ComparativeNetworkAccessibility map = new ComparativeNetworkAccessibility(taskCount, trialTaskCount, scoreCard, trialScoreCard, grid, centerSectors, startTime, endTime, trialStartTime, trialEndTime, durations.last(), samplingInterval, backward, name, inServiceTime, trialInServiceTime); publisher.publish(outputName, serializer.toJson(map)); mapGenerator.makeComparativeMap(grid, scoreCard, trialScoreCard, Collections.emptySet(), 0.2, outputName); } } } private static void generatePointAccessibility(final Namespace namespace, final OperationDescription baseDescription, final boolean backward, final Duration samplingInterval, final Duration span, final NavigableSet<Duration> durations, final Grid grid, final Map<String, ServiceDataDirectory> serviceDirectoriesMap, final OperationDescription comparison, final LocalFilePublisher publisher, final Gson serializer, final MapGenerator mapGenerator, final String outputName, final NetworkConsoleFactory consoleFactory) throws IOException, InterruptedException, ExecutionException { final String coordinateString = namespace.get("coordinate"); final GeoPoint centerCoordinate = (coordinateString == null) ? null : GeoPoint.parseDegreeString(coordinateString); final Landmark centerPoint = buildCenterPoint(grid, centerCoordinate); final MovementAssembler assembler; final TimeTracker timeTracker; if (!backward) { assembler = new ForwardMovementAssembler(); timeTracker = new ForwardTimeTracker(); } else { assembler = new RetrospectiveMovementAssembler(); timeTracker = new BackwardTimeTracker(); } final PathScoreCardFactory scoreCardFactory = new PathScoreCardFactory(assembler, timeTracker); final Center center = new Center(centerPoint, Collections.singleton(centerPoint)); final Map<OperationDescription, Calculation<PathScoreCard>> calculations = runComparison(baseDescription, scoreCardFactory, Collections.singleton(center), samplingInterval, span, backward, timeTracker, grid, serviceDirectoriesMap, durations.last(), comparison, consoleFactory); final Calculation<PathScoreCard> baseCalculation = calculations.get(baseDescription); final PathScoreCard scoreCard = baseCalculation.getScoreCard(); final int taskCount = scoreCard.getTaskCount(); final LocalDateTime startTime = LocalDateTime.parse(baseDescription.getStartTime()); final String name = baseDescription.getName(); final Duration inServiceTime = baseCalculation.getTransitNetwork().getInServiceTime(); if (comparison == null) { if (span != null) { final LocalDateTime endTime = startTime.plus(span); final PointAccessibility map = new PointAccessibility(taskCount, scoreCard, grid, centerPoint, startTime, endTime, samplingInterval, durations.last(), backward, inServiceTime); publisher.publish(outputName, serializer.toJson(map)); mapGenerator.makeRangeMap(grid, scoreCard, Collections.singleton(centerPoint), 0, 1, outputName); } else { final TimeQualifiedPointAccessibility map = new TimeQualifiedPointAccessibility(scoreCard, grid, center, startTime, durations.last(), backward, inServiceTime); publisher.publish(outputName, serializer.toJson(map)); mapGenerator.makeRangeMap(grid, scoreCard, Collections.singleton(centerPoint), 0, 1, outputName); } } else { for (final OperationDescription trialComparison : calculations.keySet()) { final String trialName = comparison.getName(); final Calculation<PathScoreCard> trialCalculation = calculations.get(trialComparison); final PathScoreCard trialScoreCard = trialCalculation.getScoreCard(); final int trialTaskCount = trialScoreCard.getTaskCount(); final LocalDateTime trialStartTime = LocalDateTime.parse(comparison.getStartTime()); final Duration trialInServiceTime = trialCalculation.getTransitNetwork().getInServiceTime(); if (span != null) { final LocalDateTime endTime = startTime.plus(span); final LocalDateTime trialEndTime = trialStartTime.plus(span); final ComparativePointAccessibility map = new ComparativePointAccessibility(taskCount, trialTaskCount, scoreCard, trialScoreCard, grid, centerPoint, startTime, endTime, trialStartTime, trialEndTime, samplingInterval, durations.last(), backward, trialName, inServiceTime, trialInServiceTime); publisher.publish(outputName, serializer.toJson(map)); } else { final ComparativeTimeQualifiedPointAccessibility map = new ComparativeTimeQualifiedPointAccessibility( scoreCard, trialScoreCard, grid, center, startTime, trialStartTime, durations.last(), backward, name, trialName, inServiceTime, trialInServiceTime); publisher.publish(outputName, serializer.toJson(map)); } mapGenerator.makeComparativeMap(grid, scoreCard, trialScoreCard, Collections.singleton(centerPoint), 0.2, outputName); } } } private static Landmark buildCenterPoint(final Grid grid, final GeoPoint centerCoordinate) { if (!grid.coversPoint(centerCoordinate)) { throw new ScoreGeneratorFatalException( String.format("Starting location %s was not in the SectorTable", centerCoordinate)); } final Landmark centerPoint = new Landmark(centerCoordinate); return centerPoint; } private static GeoBounds parseBounds(final String boundsString) { final String boundsStrings[] = boundsString.split(","); final GeoBounds bounds = new GeoBounds(new GeoLongitude(boundsStrings[0], AngleUnit.DEGREES), new GeoLatitude(boundsStrings[1], AngleUnit.DEGREES), new GeoLongitude(boundsStrings[2], AngleUnit.DEGREES), new GeoLatitude(boundsStrings[3], AngleUnit.DEGREES)); return bounds; } private static Grid getGrid(final Path root, final GeoBounds bounds, final StoreFactory storeFactory) throws IOException, InEnvironmentDetectorException, InterruptedException { final Path osmPath = root.resolve(OSM_FILE); final Path borderFilePath = root.resolve(BORDER_FILE); final Path waterFilePath = root.resolve(WATER_BODIES_FILE); final GeoJsonInEnvironmentDetector detector = new GeoJsonInEnvironmentDetector(borderFilePath, waterFilePath); final ReadingSegmentFinder segmentFinder = new ReadingSegmentFinder(osmPath, bounds); final Serializer<GridInfo> gridInfoSerializer = new GsonSerializer<>(GridInfo.class); final Store<GridIdKey, GridInfo> gridInfoStore = storeFactory.getStore(root.resolve(GRID_INFO_STORE), gridInfoSerializer); final Serializer<SectorInfo> sectorInfoSerializer = new GsonSerializer<>(SectorInfo.class); final RangedStore<SectorKey, SectorInfo> sectorStore = storeFactory.<SectorKey, SectorInfo>getRangedStore( root.resolve(SECTOR_INFO_STORE), new SectorKey.Materializer(), sectorInfoSerializer); final Serializer<GridPointAssociation> gridPointAssociationSerializer = new GsonSerializer<>( GridPointAssociation.class); final RangedStore<GridPointAssociationKey, GridPointAssociation> assocationStore = storeFactory .<GridPointAssociationKey, GridPointAssociation>getRangedStore( root.resolve(GRID_POINT_ASSOCATION_STORE), new GridPointAssociationKey.Materializer(), gridPointAssociationSerializer); return new StoredGrid(segmentFinder, bounds, RESOLUTION_METERS, detector, gridInfoStore, sectorStore, assocationStore); } }