From 9d254ca45e1e62e72767fc092a49b0c0f8cbb7ef Mon Sep 17 00:00:00 2001 From: Chengqi Lu <43133404+luchengqi7@users.noreply.github.com> Date: Wed, 24 Jan 2024 11:50:18 +0100 Subject: [PATCH] Major update Switch to node-based zone generation --- ...=> HeuristicRebalancingZoneGenerator.java} | 344 ++++++++---------- .../matsim/project/utils/ProgressPrinter.java | 7 +- 2 files changed, 167 insertions(+), 184 deletions(-) rename src/main/java/org/matsim/project/drt_zone_generation/{HeuristicZoneGenerator.java => HeuristicRebalancingZoneGenerator.java} (59%) diff --git a/src/main/java/org/matsim/project/drt_zone_generation/HeuristicZoneGenerator.java b/src/main/java/org/matsim/project/drt_zone_generation/HeuristicRebalancingZoneGenerator.java similarity index 59% rename from src/main/java/org/matsim/project/drt_zone_generation/HeuristicZoneGenerator.java rename to src/main/java/org/matsim/project/drt_zone_generation/HeuristicRebalancingZoneGenerator.java index cd4ad66..2fd8754 100644 --- a/src/main/java/org/matsim/project/drt_zone_generation/HeuristicZoneGenerator.java +++ b/src/main/java/org/matsim/project/drt_zone_generation/HeuristicRebalancingZoneGenerator.java @@ -28,23 +28,19 @@ import java.util.*; -// TODO make an interface / abstract class to eliminate repeating code - -public class HeuristicZoneGenerator { +public class HeuristicRebalancingZoneGenerator { private final Network network; private final String outputNetworkWithZonesPath; private final double timeRadius; - private final Map, Set>> reachableLinksMap = new HashMap<>(); + private final Map, Set>> reachableLinksMap = new HashMap<>(); private final SparseMatrix freeSpeedTravelTimeSparseMatrix; private final Set> linksTobeCovered = new HashSet<>(); private final Map, MutableInt> departuresMap = new HashMap<>(); private final int zoneGenerationIterations; private final List consideredTripModes; - private final Map, List> zonalSystemData = new LinkedHashMap<>(); - - private static final Logger log = LogManager.getLogger(HeuristicZoneGenerator.class); - + private final Map, List> zonalSystemData = new LinkedHashMap<>(); + private static final Logger log = LogManager.getLogger(HeuristicRebalancingZoneGenerator.class); public static void main(String[] args) { // TODO currently only support car only network (need to use mode-specific subnetwork in the normal MATSim simulations) @@ -56,17 +52,16 @@ public static void main(String[] args) { int zoneGenerationIterations = args[2] == null ? 0 : Integer.parseInt(args[2]); Population inputPlans = args.length == 4 ? PopulationUtils.readPopulation(args[3]) : null; - HeuristicZoneGenerator heuristicZoneGenerator = new ZoneGeneratorBuilder(inputNetwork, visualisationNetworkPath) + HeuristicRebalancingZoneGenerator heuristicRebalancingZoneGenerator = new ZoneGeneratorBuilder(inputNetwork, visualisationNetworkPath) .setInputPlans(inputPlans) .setZoneIterations(zoneGenerationIterations) .build(); - heuristicZoneGenerator.run(); + heuristicRebalancingZoneGenerator.compute(); } - public void run(){ + public void compute() { analyzeNetwork(); selectInitialCentroids(); - removeRedundantCentroid(); generateZones(); writeOutputNetworkWithZones(); //exportDrtZonalSystems(); @@ -127,18 +122,18 @@ public ZoneGeneratorBuilder setConsideredTripModes(List consideredTripMo return this; } - public HeuristicZoneGenerator build(){ + public HeuristicRebalancingZoneGenerator build() { SparseMatrix freeSpeedTravelTimeSparseMatrix = TravelTimeMatrices.calculateTravelTimeSparseMatrix(network, sparseMatrixMaxDistance, 0, travelTime, travelDisutility, Runtime.getRuntime().availableProcessors()); - return new HeuristicZoneGenerator(network, outputNetworkWithZonesPath, timeRadius, + return new HeuristicRebalancingZoneGenerator(network, outputNetworkWithZonesPath, timeRadius, freeSpeedTravelTimeSparseMatrix, inputPlans, zoneIterations, consideredTripModes); } } - private HeuristicZoneGenerator(Network network, String outputNetworkWithZonesPath, - double timeRadius, SparseMatrix sparseMatrix, Population inputPlans, - int zoneGenerationIterations, List consideredTripModes) { + private HeuristicRebalancingZoneGenerator(Network network, String outputNetworkWithZonesPath, + double timeRadius, SparseMatrix sparseMatrix, Population inputPlans, + int zoneGenerationIterations, List consideredTripModes) { this.network = network; this.outputNetworkWithZonesPath = outputNetworkWithZonesPath; this.timeRadius = timeRadius; @@ -180,7 +175,6 @@ public void processPlans(Population inputPlans) { } else { log.info("Population file is provided. We will only cover the links with at least one departure or arrival"); log.info("There are " + linksTobeCovered.size() + " (out of " + network.getLinks().size() + ") links to be covered. "); - // Note that, the centroid of a zone may have no departure or arrival } } @@ -188,142 +182,126 @@ public void processPlans(Population inputPlans) { public void analyzeNetwork() { // Explore reachable links log.info("Begin analyzing network. This may take some time..."); - int networkSize = network.getLinks().size(); - ProgressPrinter networkAnalysisCounter = new ProgressPrinter("Network analysis", networkSize); - - network.getLinks().keySet().forEach(linkId -> reachableLinksMap.put(linkId, new HashSet<>())); - List linkList = new ArrayList<>(network.getLinks().values()); - for (int i = 0; i < networkSize; i++) { - Link fromLink = linkList.get(i); - - // Add the itself to the reachable links set (if the link is to be covered) - if (linksTobeCovered.contains(fromLink.getId())) { - reachableLinksMap.get(fromLink.getId()).add(fromLink.getId()); - } - - for (int j = i + 1; j < networkSize; j++) { - Link toLink = linkList.get(j); - - // If the links are too far away (beyond sparse matrix), skip directly - if (freeSpeedTravelTimeSparseMatrix.get(fromLink.getToNode(), toLink.getFromNode()) == -1) { - continue; - } - - // Check forward direction: from link -> to link - double forwardTravelTime = calculateVrpLinkToLinkTravelTime(fromLink, toLink); - if (forwardTravelTime > timeRadius) { + int numOfNodesInNetwork = network.getNodes().size(); + ProgressPrinter networkAnalysisCounter = new ProgressPrinter("Network analysis", numOfNodesInNetwork); + + network.getNodes().keySet().forEach(nodeId -> reachableLinksMap.put(nodeId, new HashSet<>())); + for (Node node1 : network.getNodes().values()) { + // All outgoing links from this node should be considered reachable + node1.getOutLinks().values().stream() + .filter(link -> linksTobeCovered.contains(link.getId())) + .forEach(link -> reachableLinksMap.get(node1.getId()).add(link.getId())); + for (Node node2 : network.getNodes().values()) { + // if same node, then skip + if (node1.getId().toString().equals(node2.getId().toString())) { continue; } - // Check backward direction: to Link -> from link - double backwardTravelTime = calculateVrpLinkToLinkTravelTime(toLink, fromLink); - if (backwardTravelTime > timeRadius) { + double node1ToNode2TravelTime = freeSpeedTravelTimeSparseMatrix.get(node1, node2); + // if the node 2 is too far away from node 1, then skip + if (node1ToNode2TravelTime == -1 || node1ToNode2TravelTime > timeRadius) { + // note: -1 means not even recorded in the sparse matrix --> too far away continue; } - // If we reach here, then the fromLink and toLink are reachable to each other - // Add them into the reachable map, if they are to be covered - if (linksTobeCovered.contains(toLink.getId())) { - reachableLinksMap.get(fromLink.getId()).add(toLink.getId()); - } - if (linksTobeCovered.contains(fromLink.getId())) { - reachableLinksMap.get(toLink.getId()).add(fromLink.getId()); + // if we reach here, node 2 is reachable from node 1. Then, we check each outgoing links from node 2 + for (Link link : node2.getOutLinks().values()) { + if (linksTobeCovered.contains(link.getId())) { + double linkTravelTime = Math.floor(link.getLength() / link.getFreespeed()) + 1; + if (2 + node1ToNode2TravelTime + linkTravelTime <= timeRadius) { + // above is how VRP travel time calculated + reachableLinksMap.get(node1.getId()).add(link.getId()); + } + } } } + // node1 is analyzed, move on to next node networkAnalysisCounter.countUp(); } } public void selectInitialCentroids() { log.info("Begin selecting centroids. This may take some time..."); + int totalLinksToCover = linksTobeCovered.size(); + ProgressPrinter centroidSelectionPrinter = new ProgressPrinter("Initial centroid selection", totalLinksToCover); + // Copy the reachable links map,including copying the sets in the values of the map - Map, Set>> newlyCoveredLinksMap = createReachableLInksMapCopy(); + Map, Set>> newlyCoveredLinksMap = createReachableLInksMapCopy(); // Initialize uncovered links Set> uncoveredLinkIds = new HashSet<>(linksTobeCovered); while (!uncoveredLinkIds.isEmpty()) { // score the links - Map, Double> linksScoresMap = scoreTheLinks(newlyCoveredLinksMap); + Map, Double> nodesScoresMap = scoreTheNodes(newlyCoveredLinksMap); + // choose the centroid based on score map - Id selectedLinkId = selectBasedOnScoreMap(linksScoresMap); + Id selectedNodeId = selectBasedOnScoreMap(nodesScoresMap); - // add that link to the zonal system - zonalSystemData.put(selectedLinkId, new ArrayList<>()); + // add that node to the zonal system + zonalSystemData.put(selectedNodeId, new ArrayList<>()); // remove all the newly covered links from the uncoveredLinkIds - uncoveredLinkIds.removeAll(reachableLinksMap.get(selectedLinkId)); + uncoveredLinkIds.removeAll(reachableLinksMap.get(selectedNodeId)); // update the newlyCoveredLinksMap by removing links that are already covered - for (Id linkId : newlyCoveredLinksMap.keySet()) { - newlyCoveredLinksMap.get(linkId).removeAll(reachableLinksMap.get(selectedLinkId)); + for (Id nodeId : newlyCoveredLinksMap.keySet()) { + newlyCoveredLinksMap.get(nodeId).removeAll(reachableLinksMap.get(selectedNodeId)); } + + // Print the progress + int numLinksAlreadyCovered = totalLinksToCover - uncoveredLinkIds.size(); + centroidSelectionPrinter.countTo(numLinksAlreadyCovered); } + log.info("Potential centroids identified. There are in total " + zonalSystemData.size() + " potential centroid points"); + // remove redundant centroid + removeRedundantCentroid(); } - private Id selectBasedOnScoreMap(Map, Double> linksScoresMap) { + private Id selectBasedOnScoreMap(Map, Double> nodesScoresMap) { // Current implementation: Simply choose the link with best score - Id selectedLinkId = null; + Id selectedNodeId = null; double bestScore = 0; - for (Id linkId : linksScoresMap.keySet()) { - if (linksScoresMap.get(linkId) > bestScore) { - bestScore = linksScoresMap.get(linkId); - selectedLinkId = linkId; + for (Id nodeId : nodesScoresMap.keySet()) { + if (nodesScoresMap.get(nodeId) > bestScore) { + bestScore = nodesScoresMap.get(nodeId); + selectedNodeId = nodeId; } } - return selectedLinkId; + return selectedNodeId; } - private Map, Double> scoreTheLinks(Map, Set>> newlyCoveredLinksMap) { - // weight for number of links newly covered (main objective) - double alpha = 10; - // weight for avg distances to newly covered departures from this point (secondary objective) - double beta = 1; - - Map, Double> linkScoresMap = new HashMap<>(); - for (Id linkId : network.getLinks().keySet()) { - Set> newlyCoveredLinkIds = newlyCoveredLinksMap.get(linkId); - double score = alpha * newlyCoveredLinkIds.size(); - if (!departuresMap.isEmpty()) { - List distancesToDepartures = new ArrayList<>(); - for (Id newlyCoveredLinkId : newlyCoveredLinkIds) { - if (!departuresMap.containsKey(newlyCoveredLinkId)) { - // No departures on from this link - continue; - } - int numDepartures = departuresMap.get(newlyCoveredLinkId).intValue(); - double distance = calculateVrpLinkToLinkTravelTime(network.getLinks().get(linkId), network.getLinks().get(newlyCoveredLinkId)) / timeRadius; - for (int i = 0; i < numDepartures; i++) { - distancesToDepartures.add(distance); - } - } - double avgDistanceToDepartures = distancesToDepartures.isEmpty() ? 1 : distancesToDepartures.stream().mapToDouble(d -> d).average().orElse(1); - score += beta * (1 - avgDistanceToDepartures * avgDistanceToDepartures); - } - linkScoresMap.put(linkId, score); + private Map, Double> scoreTheNodes(Map, Set>> newlyCoveredLinksMap) { + // Current implementation: simply count the number of newly covered links + Map, Double> nodeScoresMap = new HashMap<>(); + for (Node node : network.getNodes().values()) { + Set> newlyCoveredLinkIds = newlyCoveredLinksMap.get(node.getId()); + double score = newlyCoveredLinkIds.size(); + nodeScoresMap.put(node.getId(), score); } - return linkScoresMap; + return nodeScoresMap; } - private Map, Set>> createReachableLInksMapCopy() { - Map, Set>> reachableLinksMapCopy = new HashMap<>(); - for (Id linkId : network.getLinks().keySet()) { - reachableLinksMapCopy.put(linkId, new HashSet<>(reachableLinksMap.get(linkId))); + private Map, Set>> createReachableLInksMapCopy() { + Map, Set>> reachableLinksMapCopy = new HashMap<>(); + for (Id nodeId : network.getNodes().keySet()) { + reachableLinksMapCopy.put(nodeId, new HashSet<>(reachableLinksMap.get(nodeId))); } return reachableLinksMapCopy; } - public void removeRedundantCentroid() { + private void removeRedundantCentroid() { log.info("Begin removing redundant centroids"); // Find all redundant centroids - Set> redundantCentroids = identifyRedundantCentroids(); + Set> redundantCentroids = identifyRedundantCentroids(); + log.info("Initial number of redundant centroids (i.e., zones) identified = " + redundantCentroids.size()); // Remove the redundant centroid that covers the minimum number of links while (!redundantCentroids.isEmpty()) { int minReachableLinks = Integer.MAX_VALUE; - Id centroidToRemove = null; - for (Id redundantCentroid : redundantCentroids) { + Id centroidToRemove = null; + for (Id redundantCentroid : redundantCentroids) { int numReachableLinks = reachableLinksMap.get(redundantCentroid).size(); if (numReachableLinks < minReachableLinks) { minReachableLinks = numReachableLinks; @@ -336,32 +314,30 @@ public void removeRedundantCentroid() { redundantCentroids = identifyRedundantCentroids(); log.info("Removing in progress: " + redundantCentroids.size() + " redundant centroids (i.e., zones) left"); } - log.info("Removal of redundant centroids complete. There are " + zonalSystemData.size() + " centroids (i.e., zones) remaining"); } - protected Set> identifyRedundantCentroids() { - Set> redundantCentroids = new HashSet<>(); - for (Id centroidLinkId : zonalSystemData.keySet()) { - Set> uniqueReachableLinkIds = new HashSet<>(reachableLinksMap.get(centroidLinkId)); - for (Id anotherCentriodLinkId : zonalSystemData.keySet()) { - if (centroidLinkId.toString().equals(anotherCentriodLinkId.toString())) { + protected Set> identifyRedundantCentroids() { + Set> redundantCentroids = new HashSet<>(); + for (Id centroidNodeId : zonalSystemData.keySet()) { + Set> uniqueReachableLinkIds = new HashSet<>(reachableLinksMap.get(centroidNodeId)); + for (Id anotherCentriodNodeId : zonalSystemData.keySet()) { + if (centroidNodeId.toString().equals(anotherCentriodNodeId.toString())) { // skip itself continue; } - uniqueReachableLinkIds.removeAll(reachableLinksMap.get(anotherCentriodLinkId)); + uniqueReachableLinkIds.removeAll(reachableLinksMap.get(anotherCentriodNodeId)); } if (uniqueReachableLinkIds.isEmpty()) { // There is no unique links covered by this zone, this zone is redundant - redundantCentroids.add(centroidLinkId); + redundantCentroids.add(centroidNodeId); } } return redundantCentroids; } private void generateZones() { - log.info("Generating zones now."); - // generate initial zones by assigning links to nearest centroid + log.info("Assigning links to the closest centroid"); assignLinksToNearestZone(); // after the zone is generated, update the location of the centroids (move to a better location) @@ -370,37 +346,42 @@ private void generateZones() { int it = i + 1; log.info("Improving zones now. Iteration #" + it + " out of " + zoneGenerationIterations); - List> updatedCentroids = new ArrayList<>(); - for (Id originalZoneCentroidLinkId : zonalSystemData.keySet()) { - Link currentBestCentroidLink = network.getLinks().get(originalZoneCentroidLinkId); - if (currentBestCentroidLink == null) { - // dummy zone (all the irrelevant zones), skip - continue; - } - List linksInZone = zonalSystemData.get(originalZoneCentroidLinkId); - double bestScore = Double.POSITIVE_INFINITY; + List> updatedCentroids = new ArrayList<>(); + for (Id originalZoneCentroidNodeId : zonalSystemData.keySet()) { + Node currentBestCentroidNode = network.getNodes().get(originalZoneCentroidNodeId); + List linksInZone = zonalSystemData.get(originalZoneCentroidNodeId); + Set potentialCentroidNodes = new HashSet<>(); + linksInZone.forEach(link -> potentialCentroidNodes.add(link.getToNode())); - for (Link link : linksInZone) { - // Initialize score with free speed travel time on that link * a factor - // Reason: when rebalancing is performed, the centroid links (i.e., the target) will be driven on many times - double score = (Math.floor(link.getLength() / link.getFreespeed()) + 1) * 10; - for (Link anotherLink : linksInZone) { - if (!linksTobeCovered.contains(anotherLink.getId())) { + double bestScore = Double.POSITIVE_INFINITY; + for (Node potentialNewCentroidNode : potentialCentroidNodes) { + double cost = 0; + for (Link link : linksInZone) { + if (!linksTobeCovered.contains(link.getId())) { + // if this link is not relevant -> zero cost continue; } - if (!reachableLinksMap.get(link.getId()).contains(anotherLink.getId())) { - // if some link in the original zone is not reachable from here, this link cannot be a centroid - score = Double.POSITIVE_INFINITY; + if (!reachableLinksMap.get(potentialNewCentroidNode.getId()).contains(link.getId())) { + // if some link in the original zone is not reachable from here, this node cannot be a centroid + cost = Double.POSITIVE_INFINITY; break; } - score += calculateVrpLinkToLinkTravelTime(link, anotherLink); + + double baseCost = calculateVrpNodeToLinkTravelTime(potentialNewCentroidNode, link); + if (departuresMap.isEmpty()) { + cost += baseCost; + } else { + int departures = departuresMap.getOrDefault(link.getId(), new MutableInt()).intValue(); + cost += (1 + departures) * baseCost; + } } - if (score < bestScore) { - bestScore = score; - currentBestCentroidLink = link; + + if (cost < bestScore) { + bestScore = cost; + currentBestCentroidNode = potentialNewCentroidNode; } } - updatedCentroids.add(currentBestCentroidLink.getId()); + updatedCentroids.add(currentBestCentroidNode.getId()); } // re-generate the zone based on updated centroids @@ -411,42 +392,29 @@ private void generateZones() { } } - public void assignLinksToNearestZone() { + private void assignLinksToNearestZone() { log.info("Assigning links into nearest zones (i.e., nearest centroid)"); - for (Id linkId : network.getLinks().keySet()) { - // If the link is one of the centroid link, then assign directly - if (zonalSystemData.containsKey(linkId)) { - zonalSystemData.get(linkId).add(network.getLinks().get(linkId)); - continue; - } - - // Otherwise, find the closest centroid and assign the link to that zone - Link linkBeingAssigned = network.getLinks().get(linkId); + for (Link linkBeingAssigned : network.getLinks().values()) { + // Find the closest centroid and assign the link to that zone double minDistance = Double.POSITIVE_INFINITY; - Id closestCentralLinkId = zonalSystemData.keySet().iterator().next(); + Id closestCentralNodeId = zonalSystemData.keySet().iterator().next(); // Assign to a random centroid as initialization - for (Id centroidLinkId : zonalSystemData.keySet()) { - Link centroidLink = network.getLinks().get(centroidLinkId); - if (freeSpeedTravelTimeSparseMatrix.get(centroidLink.getToNode(), linkBeingAssigned.getFromNode()) != -1) { - double distance = calculateVrpLinkToLinkTravelTime(centroidLink, linkBeingAssigned); - // double distance = calculateVrpLinkToLinkTravelTime(centroidLink, linkBeingAssigned) + calculateVrpLinkToLinkTravelTime(linkBeingAssigned, centroidLink); - // Forward + backward : better for travel time matrix - // only forward: better for rebalancing zone? - if (distance < minDistance) { - minDistance = distance; - closestCentralLinkId = centroidLinkId; - } + for (Id centroidNodeId : zonalSystemData.keySet()) { + Node centroidNode = network.getNodes().get(centroidNodeId); + double distance = calculateVrpNodeToLinkTravelTime(centroidNode, linkBeingAssigned); + if (distance < minDistance) { + minDistance = distance; + closestCentralNodeId = centroidNodeId; } } - zonalSystemData.get(closestCentralLinkId).add(linkBeingAssigned); + zonalSystemData.get(closestCentralNodeId).add(linkBeingAssigned); } } - - + private void writeOutputNetworkWithZones() { // Identify the neighbours for each zone, such that we can color the neighboring zones in different colors Map> zoneNeighborsMap = new HashMap<>(); - zonalSystemData.keySet().forEach(linkId -> zoneNeighborsMap.put(linkId.toString(), new HashSet<>())); + zonalSystemData.keySet().forEach(nodeId -> zoneNeighborsMap.put(nodeId.toString(), new HashSet<>())); List centroids = new ArrayList<>(zoneNeighborsMap.keySet()); int numZones = centroids.size(); for (int i = 0; i < numZones; i++) { @@ -455,12 +423,12 @@ private void writeOutputNetworkWithZones() { String zoneJ = centroids.get(j); Set nodesInZoneI = new HashSet<>(); - zonalSystemData.get(Id.createLinkId(zoneI)).forEach(link -> nodesInZoneI.add(link.getFromNode())); - zonalSystemData.get(Id.createLinkId(zoneI)).forEach(link -> nodesInZoneI.add(link.getToNode())); + zonalSystemData.get(Id.createNodeId(zoneI)).forEach(link -> nodesInZoneI.add(link.getFromNode())); + zonalSystemData.get(Id.createNodeId(zoneI)).forEach(link -> nodesInZoneI.add(link.getToNode())); Set nodesInZoneJ = new HashSet<>(); - zonalSystemData.get(Id.createLinkId(zoneJ)).forEach(link -> nodesInZoneJ.add(link.getFromNode())); - zonalSystemData.get(Id.createLinkId(zoneJ)).forEach(link -> nodesInZoneJ.add(link.getToNode())); + zonalSystemData.get(Id.createNodeId(zoneJ)).forEach(link -> nodesInZoneJ.add(link.getFromNode())); + zonalSystemData.get(Id.createNodeId(zoneJ)).forEach(link -> nodesInZoneJ.add(link.getToNode())); if (!Collections.disjoint(nodesInZoneI, nodesInZoneJ)) { // If two zones shared any node, then we know they are neighbors @@ -492,42 +460,52 @@ private void writeOutputNetworkWithZones() { coloringMap.put(zoneId, i); } - for (Id centroiLinkId : zonalSystemData.keySet()) { - int color = coloringMap.get(centroiLinkId.toString()); - for (Link link : zonalSystemData.get(centroiLinkId)) { + // Marking the color idx of each link + for (Id centroidNodeId : zonalSystemData.keySet()) { + int color = coloringMap.get(centroidNodeId.toString()); + for (Link link : zonalSystemData.get(centroidNodeId)) { link.getAttributes().putAttribute("zone_color", color); - link.getAttributes().putAttribute("zone_id", centroiLinkId.toString()); + link.getAttributes().putAttribute("zone_id", centroidNodeId.toString()); } } - // Marking centroid links and relevant links (i.e., links to be covered) + // Marking the relevant links (i.e. links to be covered) for (Id linkId : network.getLinks().keySet()) { - if (zonalSystemData.containsKey(linkId)) { - network.getLinks().get(linkId).getAttributes().putAttribute("isCentroid", "yes"); - } else { - network.getLinks().get(linkId).getAttributes().putAttribute("isCentroid", "no"); - } - if (linksTobeCovered.contains(linkId)) { network.getLinks().get(linkId).getAttributes().putAttribute("relevant", "yes"); } else { network.getLinks().get(linkId).getAttributes().putAttribute("relevant", "no"); } } + + // Marking centroid nodes + for (Node node : network.getNodes().values()) { + if (zonalSystemData.containsKey(node.getId())) { + node.getAttributes().putAttribute("isCentroid", "yes"); + node.getAttributes().putAttribute("zone_color", coloringMap.get(node.getId().toString())); + } else { + node.getAttributes().putAttribute("isCentroid", "no"); + node.getAttributes().putAttribute("zone_color", Double.NaN); + } + } + new NetworkWriter(network).write(outputNetworkWithZonesPath); } public DrtZonalSystem exportDrtZonalSystems() { List drtZones = new ArrayList<>(); - for (Id centroidLinkId : zonalSystemData.keySet()) { - drtZones.add(DrtZone.createDummyZone(centroidLinkId.toString(), zonalSystemData.get(centroidLinkId), - network.getLinks().get(centroidLinkId).getToNode().getCoord())); + for (Id centroidNodeId : zonalSystemData.keySet()) { + drtZones.add(DrtZone.createDummyZone(centroidNodeId.toString(), zonalSystemData.get(centroidNodeId), + network.getNodes().get(centroidNodeId).getCoord())); } return new DrtZonalSystem(drtZones); } - private double calculateVrpLinkToLinkTravelTime(Link fromLink, Link toLink) { - return freeSpeedTravelTimeSparseMatrix.get(fromLink.getToNode(), toLink.getFromNode()) + + private double calculateVrpNodeToLinkTravelTime(Node fromNode, Link toLink) { + if (freeSpeedTravelTimeSparseMatrix.get(fromNode, toLink.getFromNode()) == -1) { + return Double.POSITIVE_INFINITY; + } + return freeSpeedTravelTimeSparseMatrix.get(fromNode, toLink.getFromNode()) + Math.ceil(toLink.getLength() / toLink.getFreespeed()) + 2; } diff --git a/src/main/java/org/matsim/project/utils/ProgressPrinter.java b/src/main/java/org/matsim/project/utils/ProgressPrinter.java index 3b98d78..cee5d88 100644 --- a/src/main/java/org/matsim/project/utils/ProgressPrinter.java +++ b/src/main/java/org/matsim/project/utils/ProgressPrinter.java @@ -12,7 +12,6 @@ public class ProgressPrinter { private int pct = 0; private boolean valid = true; - /** * Progress printer with customizable step size */ @@ -44,4 +43,10 @@ public void countUp() { log.info(processName + " in progress: " + pct + "% completed"); } } + + public void countTo(int currentProgress) { + while (counter < currentProgress) { + countUp(); + } + } }