From 8671193d18dbb5626d1cbc55c92b895173e44d55 Mon Sep 17 00:00:00 2001 From: Corin Staves Date: Wed, 6 Dec 2023 17:10:00 +0100 Subject: [PATCH] Accessibility update --- .../accessibility/AccessibilityWriter.java | 91 +++++-------- .../java/accessibility/FeatureCalculator.java | 120 ++++++++++-------- src/main/java/accessibility/FeatureData.java | 10 +- .../accessibility/InterventionCalculator.java | 33 ++--- src/main/java/accessibility/LocationData.java | 20 ++- .../java/accessibility/NodeCalculator.java | 85 +++++++------ src/main/java/accessibility/RunAnalysis.java | 73 ++++++----- .../java/accessibility/RunIntervention.java | 4 +- .../accessibility/decay/DecayFunction.java | 6 +- .../resources/AccessibilityProperties.java | 4 +- .../resources/AccessibilityResources.java | 41 +++++- .../resources/analysisExample.properties | 19 ++- src/main/java/network/NetworkUtils2.java | 10 +- src/main/java/network/WriteNetworkGpkg.java | 41 +++--- .../routing/detour/NodeDetourCalculator.java | 14 +- .../routing/disutility/JibeDisutility3.java | 46 +++---- ...utility4.java => JibeDisutility3Fast.java} | 75 +++++------ .../disutility/components/LinkStress.java | 3 +- ...astCostPathTree3.java => LcpTree1Way.java} | 32 +++-- src/main/java/routing/graph/LcpTree2Way.java | 55 ++++++++ src/main/java/routing/graph/PathTree.java | 20 +++ .../java/routing/graph/StopCriterion.java | 5 + src/main/java/trads/RunRouter.java | 10 +- 23 files changed, 479 insertions(+), 338 deletions(-) rename src/main/java/routing/disutility/{JibeDisutility4.java => JibeDisutility3Fast.java} (76%) rename src/main/java/routing/graph/{LeastCostPathTree3.java => LcpTree1Way.java} (87%) create mode 100644 src/main/java/routing/graph/LcpTree2Way.java create mode 100644 src/main/java/routing/graph/PathTree.java create mode 100644 src/main/java/routing/graph/StopCriterion.java diff --git a/src/main/java/accessibility/AccessibilityWriter.java b/src/main/java/accessibility/AccessibilityWriter.java index 743c77e..c1df1d2 100644 --- a/src/main/java/accessibility/AccessibilityWriter.java +++ b/src/main/java/accessibility/AccessibilityWriter.java @@ -5,7 +5,6 @@ package accessibility; import org.apache.log4j.Logger; -import org.geotools.data.simple.SimpleFeatureReader; import org.geotools.feature.DefaultFeatureCollection; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; @@ -18,20 +17,17 @@ import org.locationtech.jts.geom.Point; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.IdMap; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; -import org.matsim.core.utils.io.IOUtils; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.referencing.FactoryException; import resources.Properties; import resources.Resources; -import java.io.BufferedWriter; import java.io.File; import java.io.IOException; -import java.util.Collections; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; /** * Helper methods to write and read matrices as CSV files (well, actually semi-colon separated files). @@ -45,44 +41,38 @@ public final class AccessibilityWriter { private final static char SEP = ','; private final static char NL = '\n'; - public static void writeNodesAsCsv(IdMap accessibilityData, String filename) throws IOException { - - double min = Collections.min(accessibilityData.values()); - double max = Collections.max(accessibilityData.values()); - double diff = max-min; - - BufferedWriter writer = IOUtils.getBufferedWriter(filename); - writer.append("NODE" + SEP + "ACCESSIBILITY" + SEP + "NORMALISED" + NL); - for (Map.Entry,Double> e : accessibilityData.entrySet()) { - writer.append(e.getKey().toString()); - writer.append(SEP); - writer.append(Double.toString(e.getValue())); - writer.append(SEP); - writer.append(Double.toString((e.getValue() - min)/diff)); - writer.append(NL); - } - writer.flush(); - } - - public static void writeNodesAsGpkg(Map,Double> accessibilityData, Network network, String filename) throws IOException { + public static void writeNodesAsGpkg(Map, double[]> accessibilityData, List endLocationDescriptions, Network network, String filename) throws IOException { - final double min = Collections.min(accessibilityData.values()); - final double max = Collections.max(accessibilityData.values()); - final double diff = max-min; - - final SimpleFeatureType TYPE = createNodeFeatureType(); + final SimpleFeatureType TYPE = createNodeFeatureType(endLocationDescriptions); final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(TYPE); final DefaultFeatureCollection collection = new DefaultFeatureCollection("Nodes",TYPE); + int endLocationCount = endLocationDescriptions.size(); + + double[] mins = new double[endLocationCount]; + double[] maxs = new double[endLocationCount]; + double[] diffs = new double[endLocationCount]; + + for(int i = 0 ; i < endLocationCount ; i++) { + int finalI = i; + Set result = accessibilityData.values().stream().map(v -> v[finalI]).collect(Collectors.toSet()); + mins[i] = Collections.min(result); + maxs[i] = Collections.max(result); + diffs[i] = maxs[i] - mins[i]; + } + // Convert map entries to feature data to create a feature collection - for(Map.Entry,Double> e : accessibilityData.entrySet()) { + for(Map.Entry,double[]> e : accessibilityData.entrySet()) { Node node = network.getNodes().get(e.getKey()); Coord c = node.getCoord(); Point p = GEOMETRY_FACTORY.createPoint(new Coordinate(c.getX(),c.getY(),c.getZ())); builder.add(p); // point geometry - builder.add(Integer.parseInt(e.getKey().toString())); // node ID todo: check this works - builder.add(e.getValue()); // accessibility - builder.add((e.getValue() - min) / diff); // normalised accessibility + builder.add(Integer.parseInt(e.getKey().toString())); // node ID + double[] values = e.getValue(); + for(int i = 0 ; i < endLocationCount ; i++) { + builder.add(values[i]); + builder.add((values[i] - mins[i]) / diffs[i]); + } collection.add(builder.buildFeature(null)); } @@ -100,7 +90,7 @@ public static void writeNodesAsGpkg(Map,Double> accessibilityData, Netw out.close(); } - private static SimpleFeatureType createNodeFeatureType() { + private static SimpleFeatureType createNodeFeatureType(List endLocationDescriptions) { SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); builder.setName("Nodes"); @@ -112,30 +102,13 @@ private static SimpleFeatureType createNodeFeatureType() { } // add attributes in order - builder.add("Node", Point.class); - builder.add("Id",Integer.class); - builder.add("Accessibility",Double.class); - builder.add("Normalised",Double.class); - - // build the type - return builder.buildFeatureType(); - } - - private static SimpleFeatureType createZoneFeatureType(String originalFilePath) throws IOException { - - // Get base type from original file - GeoPackage geopkg = new GeoPackage(new File(originalFilePath)); - SimpleFeatureReader r = geopkg.reader(geopkg.features().get(0), null,null); - - SimpleFeatureType schema = r.getFeatureType(); - - SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); - builder.setName(schema.getName()); - builder.setSuperType((SimpleFeatureType) schema.getSuper()); - builder.addAll(schema.getAttributeDescriptors()); - builder.add("accessibility",Double.class); - builder.add("normalised",Double.class); + builder.add("node", Point.class); + builder.add("id",Integer.class); + for(String description : endLocationDescriptions) { + builder.add("accessibility_" + description,Double.class); + builder.add("normalised_" + description,Double.class); + } // build the type return builder.buildFeatureType(); diff --git a/src/main/java/accessibility/FeatureCalculator.java b/src/main/java/accessibility/FeatureCalculator.java index bcd83ef..be51c6b 100644 --- a/src/main/java/accessibility/FeatureCalculator.java +++ b/src/main/java/accessibility/FeatureCalculator.java @@ -25,8 +25,7 @@ import org.opengis.feature.simple.SimpleFeature; import resources.Properties; import resources.Resources; -import routing.graph.LeastCostPathTree3; -import routing.graph.SpeedyGraph; +import routing.graph.*; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; @@ -36,9 +35,9 @@ public class FeatureCalculator { private final static Person PERSON = PopulationUtils.getFactory().createPerson(Id.create("thePerson", Person.class)); public static void calculate(Network routingNetwork, SimpleFeatureCollection collection, - Map> endNodes, Map endWeights, - Map,Double> nodeResults, int polygonRadius, - boolean fwd, TravelTime travelTime, TravelDisutility travelDisutility, + List endDataList, + Map,double[]> nodeResults, int polygonRadius, + Boolean fwd, TravelTime travelTime, TravelDisutility travelDisutility, Vehicle vehicle, DecayFunction decayFunction) { int numberOfThreads = Resources.instance.getInt(Properties.NUMBER_OF_THREADS); @@ -73,7 +72,7 @@ public static void calculate(Network routingNetwork, SimpleFeatureCollection col Thread[] threads = new Thread[numberOfThreads]; for (int i = 0; i < numberOfThreads; i++) { - FeatureWorker worker = new FeatureWorker(featuresQueue, polygonRadius, nodeResults,endNodes,endWeights,fwd,nodesPerZone, + FeatureWorker worker = new FeatureWorker(featuresQueue, polygonRadius, nodeResults,endDataList,fwd,nodesPerZone, routingNetwork,routingGraph, decayFunction,marginalTravelTimes,marginalDisutilities,counter); threads[i] = new Thread(worker, "PolygonAccessibility-" + i); threads[i].start(); @@ -89,23 +88,25 @@ public static void calculate(Network routingNetwork, SimpleFeatureCollection col } // normalise results - double min = features.stream().mapToDouble(c -> (double) c.getAttribute("accessibility")).min().orElseThrow(); - double max = features.stream().mapToDouble(c -> (double) c.getAttribute("accessibility")).max().orElseThrow(); - double diff = max - min; - for (SimpleFeature feature : features) { - double accessibility = (double) feature.getAttribute("accessibility"); - feature.setAttribute("normalised",(accessibility-min) / diff); + for(LocationData endData : endDataList) { + String attributeName = "accessibility_" + endData.getDescription(); + double min = features.stream().mapToDouble(c -> (double) c.getAttribute(attributeName)).min().orElseThrow(); + double max = features.stream().mapToDouble(c -> (double) c.getAttribute(attributeName)).max().orElseThrow(); + double diff = max - min; + for (SimpleFeature feature : features) { + double accessibility = (double) feature.getAttribute(attributeName); + feature.setAttribute("normalised_" + endData.getDescription(),(accessibility-min) / diff); + } } } private static class FeatureWorker implements Runnable { - private final ConcurrentLinkedQueue polygons; + private final ConcurrentLinkedQueue features; private final int zoneRadius; - private final Map, Double> nodeResults; - private final Map endWeights; - private final Map> endNodes; - private final boolean fwd; + private final Map, double[]> nodeResults; + private final List endDataList; + private final Boolean fwd; private final Map,Double> marginalTravelTimes; private final Map,Double> marginalDisutilities; private final Map> nodesInPolygons; @@ -114,17 +115,16 @@ private static class FeatureWorker implements Runnable { private final Counter counter; private final DecayFunction decayFunction; - FeatureWorker(ConcurrentLinkedQueue polygons, int zoneRadius, Map, Double> nodeResults, - Map> endNodes, Map endWeights, boolean fwd, + FeatureWorker(ConcurrentLinkedQueue features, int zoneRadius, Map, double[]> nodeResults, + List endDataList, Boolean fwd, Map> nodesInPolygons, Network network, SpeedyGraph graph, DecayFunction decayFunction, Map,Double> marginalTravelTimes, Map,Double> marginalDisutilities, Counter counter) { - this.polygons = polygons; + this.features = features; this.zoneRadius = zoneRadius; this.nodeResults = nodeResults; - this.endWeights = endWeights; - this.endNodes = endNodes; + this.endDataList = endDataList; this.fwd = fwd; this.nodesInPolygons = nodesInPolygons; this.network = network; @@ -136,11 +136,19 @@ private static class FeatureWorker implements Runnable { } public void run() { - LeastCostPathTree3 lcpTree = new LeastCostPathTree3(this.graph); - LeastCostPathTree3.StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); + PathTree lcpTree; + if(fwd != null) { + log.info("Initialising 1-way least cost path tree in " + (fwd ? " FORWARD " : " REVERSE ") + " direction..."); + lcpTree = new LcpTree1Way(this.graph,fwd); + } else { + log.info("Initialising 2-way least cost path tree..."); + lcpTree = new LcpTree2Way(this.graph); + } + + StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); while (true) { - SimpleFeature feature = this.polygons.poll(); + SimpleFeature feature = this.features.poll(); if (feature == null) { return; } @@ -156,7 +164,11 @@ public void run() { // If no nodes fall inside zone, then use to & from node of nearest link if(nodesWithin > 0) { - feature.setAttribute("accessibility", nodesInside.stream().mapToDouble(nodeResults::get).average().orElseThrow()); + for(int i = 0 ; i < endDataList.size() ; i++) { + int finalI = i; + feature.setAttribute("accessibility_" + endDataList.get(finalI).getDescription(), + nodesInside.stream().mapToDouble(n -> nodeResults.get(n)[finalI]).average().orElseThrow()); + } } else { Coord centroid = new Coord((double) feature.getAttribute("centroid_x"), (double) feature.getAttribute("centroid_y")); calculateForPoint(feature, centroid, lcpTree, stopCriterion); @@ -168,7 +180,7 @@ public void run() { } } } - void calculateForPoint(SimpleFeature feature, Coord coord, LeastCostPathTree3 lcpTree, LeastCostPathTree3.StopCriterion stopCriterion) { + void calculateForPoint(SimpleFeature feature, Coord coord, PathTree lcpTree, StopCriterion stopCriterion) { Link link = NetworkUtils.getNearestLinkExactly(network, coord); Id linkId = link.getId(); double connectorMarginalCost = marginalDisutilities.get(linkId); @@ -186,39 +198,41 @@ void calculateForPoint(SimpleFeature feature, Coord coord, LeastCostPathTree3 lc double timeA = connectorMarginalTime * connectorLengthA; double timeB = connectorMarginalTime * connectorLengthB; + feature.setAttribute("nodeA",nodeA.getId().toString()); + feature.setAttribute("costA",costA); + feature.setAttribute("nodeB",nodeB.getId().toString()); + feature.setAttribute("costB",costB); + lcpTree.calculate( nodeA.getId().index(),costA,timeA,connectorLengthA, nodeB.getId().index(),costB,timeB,connectorLengthB, - 0.,stopCriterion,fwd); - - double accessibility = 0.; - - for (Map.Entry endWeight : this.endWeights.entrySet()) { - - double cost = Double.MAX_VALUE; - - for (Id toNodeId : this.endNodes.get(endWeight.getKey())) { - int toNodeIndex = toNodeId.index(); - double nodeDist = lcpTree.getDistance(toNodeIndex); - double nodeTime = lcpTree.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY); - if(decayFunction.beyondCutoff(nodeDist, nodeTime)) { - continue; + 0.,stopCriterion); + + for(LocationData endData: endDataList) { + Map> endNodes = endData.getNodes(); + Map endWeights = endData.getWeights(); + + double accessibility = 0.; + for (Map.Entry endWeight : endWeights.entrySet()) { + double cost = Double.MAX_VALUE; + for (Id toNodeId : endNodes.get(endWeight.getKey())) { + int toNodeIndex = toNodeId.index(); + double nodeDist = lcpTree.getDistance(toNodeIndex); + double nodeTime = lcpTree.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY); + if(decayFunction.beyondCutoff(nodeDist, nodeTime)) { + continue; + } + double nodeCost = lcpTree.getCost(toNodeIndex); + if (nodeCost < cost) { + cost = nodeCost; + } } - double nodeCost = lcpTree.getCost(toNodeIndex); - if (nodeCost < cost) { - cost = nodeCost; + if(cost != Double.MAX_VALUE) { + accessibility += decayFunction.getDecay(cost) * endWeight.getValue(); } } - if(cost != Double.MAX_VALUE) { - accessibility += decayFunction.getDecay(cost) * endWeight.getValue(); - } + feature.setAttribute("accessibility_" + endData.getDescription(),accessibility); } - - feature.setAttribute("accessibility",accessibility); - feature.setAttribute("nodeA",nodeA.getId().toString()); - feature.setAttribute("costA",costA); - feature.setAttribute("nodeB",nodeB.getId().toString()); - feature.setAttribute("costB",costB); } } } diff --git a/src/main/java/accessibility/FeatureData.java b/src/main/java/accessibility/FeatureData.java index 1febff1..5ea7f77 100644 --- a/src/main/java/accessibility/FeatureData.java +++ b/src/main/java/accessibility/FeatureData.java @@ -14,6 +14,7 @@ import java.io.File; import java.io.IOException; +import java.util.List; // Tools for reading zone system for accessibility analysis @@ -25,7 +26,7 @@ public class FeatureData { private final Geometries geometryType; private final Integer radius; - public FeatureData(String filePath) throws IOException { + public FeatureData(String filePath, List endLocationDescriptions) throws IOException { GeoPackage geopkg = new GeoPackage(openFile(filePath)); FeatureEntry entry = geopkg.features().get(0); this.geometryType = entry.getGeometryType(); @@ -66,8 +67,11 @@ public FeatureData(String filePath) throws IOException { builder.add("nodeB",String.class); builder.add("costA",Double.class); builder.add("costB",Double.class); - builder.add("accessibility",Double.class); - builder.add("normalised",Double.class); + for(String description : endLocationDescriptions) { + builder.add("accessibility_" + description,Double.class); + builder.add("normalised_" + description,Double.class); + } + SimpleFeatureType newSchema = builder.buildFeatureType(); // Create set of zones with updated feature types diff --git a/src/main/java/accessibility/InterventionCalculator.java b/src/main/java/accessibility/InterventionCalculator.java index 52d67e0..c4e26d8 100644 --- a/src/main/java/accessibility/InterventionCalculator.java +++ b/src/main/java/accessibility/InterventionCalculator.java @@ -17,8 +17,7 @@ import org.matsim.vehicles.Vehicle; import resources.Properties; import resources.Resources; -import routing.graph.LeastCostPathTree3; -import routing.graph.SpeedyGraph; +import routing.graph.*; import java.util.Collections; import java.util.HashMap; @@ -74,23 +73,20 @@ public Map,Double> calculate(Set> startNodes, Map,Dou public Map,Double> calculateSingle(Set> startNodes, Id newNode, Double wt) { - LeastCostPathTree3 lcpTreeFwd = new LeastCostPathTree3(routingGraph); - LeastCostPathTree3 lcpTreeRev = new LeastCostPathTree3(routingGraph); - LeastCostPathTree3.StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); + PathTree lcpTree = new LcpTree2Way(routingGraph); + StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); - lcpTreeFwd.calculate(newNode.index(),0.,stopCriterion,true); - lcpTreeRev.calculate(newNode.index(),0.,stopCriterion,false); + lcpTree.calculate(newNode.index(),0.,stopCriterion); IdMap result = new IdMap<>(Node.class); for(Id node : startNodes) { int toNodeIndex = node.index(); - double dist = (lcpTreeFwd.getDistance(toNodeIndex) + lcpTreeRev.getDistance(toNodeIndex))/2; - double time = (lcpTreeFwd.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY) + - lcpTreeRev.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY))/2; + double dist = lcpTree.getDistance(toNodeIndex); + double time = lcpTree.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY); if(decayFunction.beyondCutoff(dist,time)) { result.put(node,0.); } else { - double cost = (lcpTreeFwd.getCost(toNodeIndex) + lcpTreeRev.getCost(toNodeIndex))/2; + double cost = lcpTree.getCost(toNodeIndex); result.put(node,decayFunction.getDecay(cost) * wt); } @@ -113,9 +109,8 @@ private class NodeWorker implements Runnable { } public void run() { - LeastCostPathTree3 lcpTreeFwd = new LeastCostPathTree3(routingGraph); - LeastCostPathTree3 lcpTreeRev = new LeastCostPathTree3(routingGraph); - LeastCostPathTree3.StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); + PathTree lcpTree = new LcpTree2Way(routingGraph); + StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); while (true) { Id fromNodeId = this.startNodes.poll(); @@ -124,18 +119,16 @@ public void run() { } this.counter.incCounter(); - lcpTreeFwd.calculate(fromNodeId.index(),0.,stopCriterion,true); - lcpTreeRev.calculate(fromNodeId.index(),0.,stopCriterion,false); + lcpTree.calculate(fromNodeId.index(),0.,stopCriterion); double accessibility = 0.; for (Map.Entry, Double> e : this.endNodes.entrySet()) { int toNodeIndex = e.getKey().index(); - double dist = (lcpTreeFwd.getDistance(toNodeIndex) + lcpTreeRev.getDistance(toNodeIndex))/2; - double time = (lcpTreeFwd.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY) + - lcpTreeRev.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY))/2; + double dist = lcpTree.getDistance(toNodeIndex); + double time = lcpTree.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY); if(!decayFunction.beyondCutoff(dist,time)) { - double cost = (lcpTreeFwd.getCost(toNodeIndex) + lcpTreeRev.getCost(toNodeIndex))/2; + double cost = lcpTree.getCost(toNodeIndex); accessibility += decayFunction.getDecay(cost) * e.getValue(); } } diff --git a/src/main/java/accessibility/LocationData.java b/src/main/java/accessibility/LocationData.java index 312d2c5..905ea20 100644 --- a/src/main/java/accessibility/LocationData.java +++ b/src/main/java/accessibility/LocationData.java @@ -19,6 +19,8 @@ import java.util.*; public class LocationData { + + private final String description; private final static Logger log = Logger.getLogger(LocationData.class); private final static GeometryFactory gf = new GeometryFactory(); private final static String SEP = ";"; @@ -31,7 +33,12 @@ public class LocationData { private final Map> nodes = new LinkedHashMap<>(); private final Map weights = new LinkedHashMap<>(); - public LocationData(String filename, Geometry boundary) throws IOException { + public LocationData(String description, String filename, Geometry boundary) throws IOException { + + // Set description + this.description = description; + + // Read destinations String recString; int destinationsOutsideBoundary = 0; @@ -85,6 +92,13 @@ public Map> getCoords() { return Collections.unmodifiableMap(coords); } + public void transformWeights(double exponent) { + if(exponent != 1) { + log.info("Transforming all weights using exponent alpha = " + exponent); + weights.replaceAll((k,v) -> Math.pow(v,exponent)); + } + } + public Map getWeights() { return Collections.unmodifiableMap(weights); } @@ -131,6 +145,10 @@ public IdMap getNodeWeightMap() { return nodeWeightMap; } + public String getDescription() { + return this.description; + } + private static int findPositionInArray (String string, String[] array) { int ind = -1; for (int a = 0; a < array.length; a++) { diff --git a/src/main/java/accessibility/NodeCalculator.java b/src/main/java/accessibility/NodeCalculator.java index fdc233f..fe7fc83 100644 --- a/src/main/java/accessibility/NodeCalculator.java +++ b/src/main/java/accessibility/NodeCalculator.java @@ -17,8 +17,7 @@ import org.matsim.vehicles.Vehicle; import resources.Properties; import resources.Resources; -import routing.graph.LeastCostPathTree3; -import routing.graph.SpeedyGraph; +import routing.graph.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -33,16 +32,16 @@ private NodeCalculator() { private final static Person PERSON = PopulationUtils.getFactory().createPerson(Id.create("thePerson", Person.class)); - public static Map,Double> calculate(Network routingNetwork, Set> startNodes, - Map> endNodes, Map endWeights, - boolean fwd, TravelTime travelTime, TravelDisutility travelDisutility, + public static Map,double[]> calculate(Network routingNetwork, Set> startNodes, + List endData, + Boolean fwd, TravelTime travelTime, TravelDisutility travelDisutility, Vehicle vehicle, DecayFunction decayFunction) { int numberOfThreads = Resources.instance.getInt(Properties.NUMBER_OF_THREADS); SpeedyGraph routingGraph = new SpeedyGraph(routingNetwork,travelTime,travelDisutility,PERSON,vehicle); // prepare calculation - ConcurrentHashMap,Double> accessibilityResults = new ConcurrentHashMap<>(startNodes.size()); + ConcurrentHashMap,double[]> accessibilityResults = new ConcurrentHashMap<>(startNodes.size()); // do calculation ConcurrentLinkedQueue> startNodesQueue = new ConcurrentLinkedQueue<>(startNodes); @@ -50,7 +49,7 @@ public static Map,Double> calculate(Network routingNetwork, Set,Double> calculate(Network routingNetwork, Set> startNodes; - private final Map> endNodes; - private final Map endWeights; - private final boolean fwd; + private final List endDataList; + private final Boolean fwd; private final SpeedyGraph graph; - private final ConcurrentHashMap,Double> accessibilityData; + private final ConcurrentHashMap,double[]> accessibilityData; private final DecayFunction decayFunction; private final Counter counter; - NodeWorker(ConcurrentLinkedQueue> startNodes, Map> endNodes, Map endWeights, - boolean fwd, SpeedyGraph graph, ConcurrentHashMap,Double> results, + NodeWorker(ConcurrentLinkedQueue> startNodes, List endDataList, + Boolean fwd, SpeedyGraph graph, ConcurrentHashMap,double[]> results, DecayFunction decayFunction, Counter counter) { this.startNodes = startNodes; - this.endNodes = endNodes; - this.endWeights = endWeights; + this.endDataList = endDataList; this.fwd = fwd; this.graph = graph; this.accessibilityData = results; @@ -92,8 +89,13 @@ private static class NodeWorker implements Runnable { } public void run() { - LeastCostPathTree3 lcpTree = new LeastCostPathTree3(this.graph); - LeastCostPathTree3.StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); + PathTree lcpTree; + if(fwd != null) { + lcpTree = new LcpTree1Way(this.graph,fwd); + } else { + lcpTree = new LcpTree2Way(this.graph); + } + StopCriterion stopCriterion = decayFunction.getTreeStopCriterion(); while (true) { Id fromNodeId = this.startNodes.poll(); @@ -102,31 +104,38 @@ public void run() { } this.counter.incCounter(); - lcpTree.calculate(fromNodeId.index(),0.,stopCriterion,fwd); - - double accessibility = 0.; - - for (Map.Entry endWeight : this.endWeights.entrySet()) { - - double cost = Double.MAX_VALUE; - - for (Id toNodeId : this.endNodes.get(endWeight.getKey())) { - int toNodeIndex = toNodeId.index(); - double nodeDist = lcpTree.getDistance(toNodeIndex); - double nodeTime = lcpTree.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY); - if(decayFunction.beyondCutoff(nodeDist, nodeTime)) { - continue; + lcpTree.calculate(fromNodeId.index(), 0., stopCriterion); + + + double[] accessibilities = new double[endDataList.size()]; + int i = 0; + for (LocationData endData : endDataList) { + Map> endNodes = endData.getNodes(); + Map endWeights = endData.getWeights(); + + double accessibility = 0.; + for (Map.Entry endWeight : endWeights.entrySet()) { + double cost = Double.MAX_VALUE; + for (Id toNodeId : endNodes.get(endWeight.getKey())) { + int toNodeIndex = toNodeId.index(); + double nodeDist = lcpTree.getDistance(toNodeIndex); + double nodeTime = lcpTree.getTime(toNodeIndex).orElse(Double.POSITIVE_INFINITY); + if (decayFunction.beyondCutoff(nodeDist, nodeTime)) { + continue; + } + double nodeCost = lcpTree.getCost(toNodeIndex); + if (nodeCost < cost) { + cost = nodeCost; + } } - double nodeCost = lcpTree.getCost(toNodeIndex); - if (nodeCost < cost) { - cost = nodeCost; + if (cost != Double.MAX_VALUE) { + accessibility += decayFunction.getDecay(cost) * endWeight.getValue(); } } - if(cost != Double.MAX_VALUE) { - accessibility += decayFunction.getDecay(cost) * endWeight.getValue(); - } + accessibilities[i] = accessibility; + i++; } - this.accessibilityData.put(fromNodeId,accessibility); + this.accessibilityData.put(fromNodeId, accessibilities); } } } diff --git a/src/main/java/accessibility/RunAnalysis.java b/src/main/java/accessibility/RunAnalysis.java index f101a6e..dcf6833 100644 --- a/src/main/java/accessibility/RunAnalysis.java +++ b/src/main/java/accessibility/RunAnalysis.java @@ -9,7 +9,6 @@ import org.geotools.geometry.jts.Geometries; import org.locationtech.jts.geom.Geometry; import org.matsim.api.core.v01.Id; -import org.matsim.api.core.v01.IdSet; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; import org.matsim.core.router.util.TravelDisutility; @@ -18,11 +17,10 @@ import resources.Resources; import org.apache.log4j.Logger; -import routing.disutility.JibeDisutility4; import java.io.IOException; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; public class RunAnalysis { @@ -75,48 +73,53 @@ private static void runAnalysis(String propertiesFilepath) throws IOException { Vehicle veh = AccessibilityResources.instance.getVehicle(); TravelDisutility td = AccessibilityResources.instance.getTravelDisutility(); - if(td instanceof JibeDisutility4) { - ((JibeDisutility4) td).setNetwork(network); - ((JibeDisutility4) td).setVehicle(veh); - ((JibeDisutility4) td).precalculateDisutility(); - } - // Inputs/outputs - String endLocationsFilename = AccessibilityResources.instance.getString(AccessibilityProperties.END_LOCATIONS); - String outputNodesFilename = AccessibilityResources.instance.getString(AccessibilityProperties.OUTPUT_NODES); String inputFilename = AccessibilityResources.instance.getString(AccessibilityProperties.INPUT); - String outputFilename = AccessibilityResources.instance.getString(AccessibilityProperties.OUTPUT); + + List endLocationsFilenames = AccessibilityResources.instance.getStringList(AccessibilityProperties.END_LOCATIONS); + List endLocationsDescriptions = AccessibilityResources.instance.getStringList(AccessibilityProperties.END_DESCRIPTION); + List endLocationsAlpha = AccessibilityResources.instance.getStringList(AccessibilityProperties.END_ALPHA).stream().map(Double::parseDouble).collect(Collectors.toList()); + + String outputNodesFilename = AccessibilityResources.instance.getString(AccessibilityProperties.OUTPUT_NODES); + String outputFeaturesFilename = AccessibilityResources.instance.getString(AccessibilityProperties.OUTPUT_FEATURES); // Input locations (to calculate accessibility for) - FeatureData features = new FeatureData(inputFilename); + FeatureData features = new FeatureData(inputFilename, endLocationsDescriptions); // Parameters DecayFunction df = DecayFunctions.getFromProperties(network,networkBoundary); - boolean fwd = AccessibilityResources.instance.fwdCalculation(); + Boolean fwd = AccessibilityResources.instance.fwdCalculation(); // Checks on whether to perform ANY calculations if(df == null) { - log.warn("No decay function. Skipping all accessibility calculations."); + log.error("No decay function. Skipping all accessibility calculations."); return; } - if(endLocationsFilename == null) { - log.warn("No end locations given. Skipping all accessibility calculations."); + if(endLocationsFilenames.size() == 0) { + log.error("No end locations given. Skipping all accessibility calculations."); return; } - if (outputNodesFilename == null && (inputFilename == null || outputFilename == null)) { - log.warn("No input/output files given. Skipping all accessibility calculations."); + int endLocationsSize = endLocationsFilenames.size(); + if(endLocationsSize != endLocationsDescriptions.size()) { + log.error("Number of end locations does not match number of end descriptions."); + } + if (outputNodesFilename == null && (inputFilename == null || outputFeaturesFilename == null)) { + log.error("No input/output files given. Skipping all accessibility calculations."); return; } - LocationData endData = new LocationData(endLocationsFilename,networkBoundary); - endData.estimateNetworkNodes(network); - Map> endNodes = endData.getNodes(); - Map endWeights = endData.getWeights(); - // Accessibility calculation on NODES (if using polygons or node output requested) - Map,Double> nodeResults = null; + List endDataList = new ArrayList<>(endLocationsSize); + for(int i = 0 ; i < endLocationsSize ; i++) { + LocationData endData = new LocationData(endLocationsDescriptions.get(i),endLocationsFilenames.get(i),networkBoundary); + endData.estimateNetworkNodes(network); + endData.transformWeights(endLocationsAlpha.get(i)); + endDataList.add(endData); + } + + // Accessibility calculation on NODES (if using polygons) + Map,double[]> nodeResults = null; if(Geometries.POLYGON.equals(features.getGeometryType()) - || Geometries.MULTIPOLYGON.equals(features.getGeometryType()) - || outputNodesFilename != null) { + || Geometries.MULTIPOLYGON.equals(features.getGeometryType())) { // Get applicable start nodes log.info("Identifying origin nodes within area of analysis..."); @@ -125,25 +128,25 @@ private static void runAnalysis(String propertiesFilepath) throws IOException { // Run node accessibility calculation log.info("Running node accessibility calculation..."); long startTime = System.currentTimeMillis(); - nodeResults = NodeCalculator.calculate(network, startNodes, endNodes, endWeights, fwd, tt, td, veh, df); + nodeResults = NodeCalculator.calculate(network, startNodes, endDataList, fwd, tt, td, veh, df); long endTime = System.currentTimeMillis(); log.info("Calculation time: " + (endTime - startTime)); // Output nodes as CSV (if it was provided in properties file) if(outputNodesFilename != null) { - AccessibilityWriter.writeNodesAsGpkg(nodeResults,fullNetwork,outputNodesFilename); + AccessibilityWriter.writeNodesAsGpkg(nodeResults,endLocationsDescriptions,fullNetwork,outputNodesFilename); } } - if(inputFilename != null && outputFilename != null) { + if(inputFilename != null && outputFeaturesFilename != null) { log.info("Running accessibility calculation..."); - FeatureCalculator.calculate(network, features.getCollection(), endNodes, endWeights, + FeatureCalculator.calculate(network, features.getCollection(), endDataList, nodeResults, features.getRadius(), fwd, tt, td, veh, df); // Output grid as gpkg - log.info("Saving output features to " + outputFilename); - GisUtils.writeFeaturesToGpkg(features.getCollection(), features.getDescription() + "_result", outputFilename); + log.info("Saving output features to " + outputFeaturesFilename); + GisUtils.writeFeaturesToGpkg(features.getCollection(), features.getDescription() + "_result", outputFeaturesFilename); } } -} +} \ No newline at end of file diff --git a/src/main/java/accessibility/RunIntervention.java b/src/main/java/accessibility/RunIntervention.java index bc4c428..f742fec 100644 --- a/src/main/java/accessibility/RunIntervention.java +++ b/src/main/java/accessibility/RunIntervention.java @@ -93,14 +93,14 @@ private static void runIntervention(String propertiesFilepath) throws IOExceptio assert maxDestinations > 0; // Read population - LocationData populationData = new LocationData(populationFile,regionBoundary); + LocationData populationData = new LocationData(null,populationFile,regionBoundary); populationData.estimateNetworkNodes(network); IdMap populationNodeIdMap = populationData.getNodeIdMap(); IdMap populationNodeWtMap = populationData.getNodeWeightMap(); Set> populationNodes = populationNodeWtMap.keySet(); // Read current destinations - LocationData currentDestinations = new LocationData(currentDestinationsFile,networkBoundary); + LocationData currentDestinations = new LocationData(null,currentDestinationsFile,networkBoundary); currentDestinations.estimateNetworkNodes(network); IdMap destinationNodeWtMap = currentDestinations.getNodeWeightMap(); diff --git a/src/main/java/accessibility/decay/DecayFunction.java b/src/main/java/accessibility/decay/DecayFunction.java index 55137c2..db3f566 100644 --- a/src/main/java/accessibility/decay/DecayFunction.java +++ b/src/main/java/accessibility/decay/DecayFunction.java @@ -1,12 +1,12 @@ package accessibility.decay; -import routing.graph.LeastCostPathTree3; +import routing.graph.StopCriterion; public class DecayFunction { final private double cutoffTime; final private double cutoffDist; - final private LeastCostPathTree3.StopCriterion stopCriterion; + final private StopCriterion stopCriterion; public DecayFunction(double cutoffTime, double cutoffDist) { this.cutoffTime = Double.isNaN(cutoffTime) ? Double.MAX_VALUE : cutoffTime; @@ -32,7 +32,7 @@ public boolean beyondCutoff(double distance, double time) { return distance > cutoffDist || time > cutoffTime; } - public LeastCostPathTree3.StopCriterion getTreeStopCriterion() { + public StopCriterion getTreeStopCriterion() { return stopCriterion; } } diff --git a/src/main/java/accessibility/resources/AccessibilityProperties.java b/src/main/java/accessibility/resources/AccessibilityProperties.java index 55a2868..f0c7aea 100644 --- a/src/main/java/accessibility/resources/AccessibilityProperties.java +++ b/src/main/java/accessibility/resources/AccessibilityProperties.java @@ -5,6 +5,8 @@ public class AccessibilityProperties { public static final String MODE = "mode"; public static final String IMPEDANCE = "disutility"; public static final String END_LOCATIONS = "end.coords"; + public static final String END_DESCRIPTION = "end.description"; + public static final String END_ALPHA = "end.alpha"; public static final String FORWARD = "forward"; // todo: check this works // Related to decay function @@ -24,7 +26,7 @@ public class AccessibilityProperties { // For accessibility analysis public static final String INPUT = "input"; - public static final String OUTPUT = "output"; + public static final String OUTPUT_FEATURES = "output"; public static final String OUTPUT_NODES = "output.nodes"; // For Intervention diff --git a/src/main/java/accessibility/resources/AccessibilityResources.java b/src/main/java/accessibility/resources/AccessibilityResources.java index 19ed2ef..0bc1ce4 100644 --- a/src/main/java/accessibility/resources/AccessibilityResources.java +++ b/src/main/java/accessibility/resources/AccessibilityResources.java @@ -10,7 +10,7 @@ import org.matsim.vehicles.Vehicle; import routing.Bicycle; import routing.disutility.DistanceDisutility; -import routing.disutility.JibeDisutility4; +import routing.disutility.JibeDisutility3; import routing.travelTime.WalkTravelTime; import trip.Purpose; @@ -18,6 +18,8 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; public class AccessibilityResources { @@ -74,7 +76,17 @@ public static void initializeResources(String propertiesFile) { } // Direction - instance.fwd = Boolean.parseBoolean(properties.getProperty(AccessibilityProperties.FORWARD)); + String input = properties.getProperty(AccessibilityProperties.FORWARD); + if(input == null) { + instance.fwd = null; + } else if(input.equalsIgnoreCase("true")) { + instance.fwd = true; + } + else if (input.equalsIgnoreCase("false")) { + instance.fwd = false; + } else { + throw new RuntimeException("Unknown value " + input + " given for forward property. Must be \"true\", \"false\", or left out for a two-way analysis."); + } } catch (IOException e) { e.printStackTrace(); @@ -100,7 +112,7 @@ private void setActiveDisutility() { double mcComfort = getMarginalCostOrDefault(mode, resources.Properties.COMFORT); double mcAmbience = getMarginalCostOrDefault(mode, resources.Properties.AMBIENCE); double mcStress = getMarginalCostOrDefault(mode, resources.Properties.STRESS); - td = new JibeDisutility4(mode,tt,dayOverride,mcGrad,mcComfort,mcAmbience,mcStress); + td = new JibeDisutility3(mode,tt,dayOverride,mcGrad,mcComfort,mcAmbience,mcStress); break; default: throw new RuntimeException("Disutility type " + type + " not recognised for mode " + mode); @@ -120,7 +132,7 @@ public synchronized String getMode() { return this.mode; } - public synchronized boolean fwdCalculation() { return this.fwd; } + public synchronized Boolean fwdCalculation() { return this.fwd; } public synchronized Vehicle getVehicle() { return this.veh; @@ -168,4 +180,25 @@ public synchronized Purpose.PairList getPurposePairs() { } return list; } + + public synchronized List getStringList(String key) { + ArrayList strings = new ArrayList<>(); + + String onlyString = properties.getProperty(key); + if(onlyString != null) { + // Case 1: only single item (i.e., non-numbered) + strings.add(onlyString); + } else { + // Case 2: multiple numbered items (starting from 0) + int counter = 0; + String nextString = properties.getProperty(key + "." + counter); + while(nextString != null) { + strings.add(nextString); + counter++; + nextString = properties.getProperty(key + "." + counter); + } + } + return strings; + } + } diff --git a/src/main/java/accessibility/resources/analysisExample.properties b/src/main/java/accessibility/resources/analysisExample.properties index 5e8125f..a7b85d0 100644 --- a/src/main/java/accessibility/resources/analysisExample.properties +++ b/src/main/java/accessibility/resources/analysisExample.properties @@ -1,14 +1,25 @@ ## PROPERTIES FOR ACCESSIBILITY CALCULATIONS # This is an example file. Copy this into your working directory and change the configuration and filepaths as appropriate. -# End locations file -end.coords = JIBE/accessibility/food.csv +# End locations files +end.coords.0 = accessibility/Public_open_space_v3.0.csv +end.coords.1 = accessibility/Early_year_access.csv +end.coords.2 = accessibility/Food_retail.csv -# Calculation direction. true = forward (active). false = reverse (passive). +end.description.0 = green +end.description.1 = edu +end.description.2 = food + +# Power transforms for weights (WEIGHT ^ ALPHA) +end.alpha.0 = 0.25 +end.alpha.1 = 0.5 +end.alpha.2 = 0.5 + +# Calculation direction. true = forward (active). false = reverse (passive). Comment out for 2-way (roundtrip) estimation forward = true # Node analysis - output file (.gpkg) -output.nodes = JIBE/accessibility/food_results.gpkg +output.nodes = accessibility/food_results.gpkg # Grid analysis - grid input & output (for grid analysis only, otherwise comment out) input = manchester/grid/grid100.gpkg diff --git a/src/main/java/network/NetworkUtils2.java b/src/main/java/network/NetworkUtils2.java index fcad2ab..91a0acd 100644 --- a/src/main/java/network/NetworkUtils2.java +++ b/src/main/java/network/NetworkUtils2.java @@ -24,6 +24,8 @@ import resources.Properties; import resources.Resources; import routing.disutility.JibeDisutility; +import routing.disutility.JibeDisutility3; +import routing.disutility.JibeDisutility3Fast; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -170,7 +172,13 @@ public static Map,Double> precalculateLinkMarginalDisutilities(Network counter.incCounter(); double linkDisutility = disutility.getLinkTravelDisutility(link,time,person,vehicle); if(disutility instanceof JibeDisutility) { - linkDisutility -= ((JibeDisutility) disutility).getJunctionComponent(link); // todo: check this is happening + linkDisutility -= ((JibeDisutility) disutility).getJunctionComponent(link); + } + if(disutility instanceof JibeDisutility3) { + linkDisutility -= ((JibeDisutility3) disutility).getJunctionComponent(link,vehicle); + } + if(disutility instanceof JibeDisutility3Fast) { + linkDisutility -= ((JibeDisutility3Fast) disutility).getJunctionComponent(link); } marginalDisutilities.put(link.getId(), linkDisutility / link.getLength()); } diff --git a/src/main/java/network/WriteNetworkGpkg.java b/src/main/java/network/WriteNetworkGpkg.java index 1cd0273..7a38bed 100644 --- a/src/main/java/network/WriteNetworkGpkg.java +++ b/src/main/java/network/WriteNetworkGpkg.java @@ -1,13 +1,12 @@ package network; import gis.GpkgReader; -import org.matsim.api.core.v01.Id; import org.matsim.core.network.algorithms.TransportModeNetworkFilter; import resources.Properties; import resources.Resources; import routing.Bicycle; import routing.Gradient; -import routing.disutility.JibeDisutility; +import routing.disutility.JibeDisutility3Fast; import routing.disutility.components.*; import routing.travelTime.WalkTravelTime; import com.google.common.math.LongMath; @@ -94,8 +93,8 @@ private static SimpleFeatureType createFeatureType() throws FactoryException { builder.add("walkTime",Double.class); builder.add("carSpeedLimitMPH",Double.class); builder.add("car85PercSpeedKPH",Double.class); - builder.add("bikeJibeMarginalDisutility",Double.class); - builder.add("walkJibeMarginalDisutility",Double.class); +// builder.add("bikeJibeMarginalDisutility",Double.class); +// builder.add("walkJibeMarginalDisutility",Double.class); builder.add("width",Double.class); builder.add("lanes",Integer.class); builder.add("aadt",Integer.class); @@ -108,10 +107,10 @@ private static SimpleFeatureType createFeatureType() throws FactoryException { builder.add("motorway",Boolean.class); builder.add("trunk",Boolean.class); builder.add("dismount",Boolean.class); - builder.add("stravaBikeSpeed",Double.class); - builder.add("stravaBikeVol",Double.class); - builder.add("stravaWalkSpeed",Double.class); - builder.add("stravaWalkVol",Double.class); +// builder.add("stravaBikeSpeed",Double.class); +// builder.add("stravaBikeVol",Double.class); +// builder.add("stravaWalkSpeed",Double.class); +// builder.add("stravaWalkVol",Double.class); builder.add("disconnected_car",Boolean.class); builder.add("disconnected_bike",Boolean.class); builder.add("disconnected_walk",Boolean.class); @@ -164,12 +163,16 @@ public static void write(Network network, String outputEdgesFilePath) throws IOE TravelTime ttWalk = new WalkTravelTime(); // Travel Disutilities - JibeDisutility tdJibeBike = new JibeDisutility(TransportMode.bike, ttBike); - JibeDisutility tdJibeWalk = new JibeDisutility(TransportMode.walk, ttWalk); + JibeDisutility3Fast tdJibeBikeDay = new JibeDisutility3Fast(network,bike,TransportMode.bike, ttBike,true); + JibeDisutility3Fast tdJibeBikeNight = new JibeDisutility3Fast(network,bike,TransportMode.bike, ttBike,false); - // Marginal Disutility maps - Map,Double> bikeMarginalDisutilities = NetworkUtils2.precalculateLinkMarginalDisutilities(network,tdJibeBike,0.,null,bike); - Map,Double> walkMarginalDisutilities = NetworkUtils2.precalculateLinkMarginalDisutilities(network,tdJibeWalk,0.,null,null); + JibeDisutility3Fast tdJibeWalkDay = new JibeDisutility3Fast(network,null,TransportMode.walk, ttWalk,true); + JibeDisutility3Fast tdJibeWalkNight = new JibeDisutility3Fast(network,null,TransportMode.walk, ttWalk,false); + + +// // Marginal Disutility maps +// Map,Double> bikeMarginalDisutilities = NetworkUtils2.precalculateLinkMarginalDisutilities(network,tdJibeBike,0.,null,bike); +// Map,Double> walkMarginalDisutilities = NetworkUtils2.precalculateLinkMarginalDisutilities(network,tdJibeWalk,0.,null,null); // Prepare geopackage data final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); @@ -242,8 +245,8 @@ public static void write(Network network, String outputEdgesFilePath) throws IOE featureBuilder.add(walkTime); featureBuilder.add(link.getAttributes().getAttribute("speedLimitMPH")); featureBuilder.add(link.getAttributes().getAttribute("veh85percSpeedKPH")); - featureBuilder.add(bikeMarginalDisutilities.get(link.getId())); - featureBuilder.add(walkMarginalDisutilities.get(link.getId())); +// featureBuilder.add(bikeMarginalDisutilities.get(link.getId())); +// featureBuilder.add(walkMarginalDisutilities.get(link.getId())); featureBuilder.add(link.getAttributes().getAttribute("width")); featureBuilder.add((int) link.getNumberOfLanes()); featureBuilder.add(aadt); @@ -256,10 +259,10 @@ public static void write(Network network, String outputEdgesFilePath) throws IOE featureBuilder.add(link.getAttributes().getAttribute("motorway")); featureBuilder.add(link.getAttributes().getAttribute("trunk")); featureBuilder.add(link.getAttributes().getAttribute("dismount")); - featureBuilder.add(link.getAttributes().getAttribute("stravaBikeSpeed")); - featureBuilder.add(link.getAttributes().getAttribute("stravaBikeVol")); - featureBuilder.add(link.getAttributes().getAttribute("stravaWalkSpeed")); - featureBuilder.add(link.getAttributes().getAttribute("stravaWalkVol")); +// featureBuilder.add(link.getAttributes().getAttribute("stravaBikeSpeed")); +// featureBuilder.add(link.getAttributes().getAttribute("stravaBikeVol")); +// featureBuilder.add(link.getAttributes().getAttribute("stravaWalkSpeed")); +// featureBuilder.add(link.getAttributes().getAttribute("stravaWalkVol")); featureBuilder.add(link.getAttributes().getAttribute("disconnected_"+ TransportMode.car)); featureBuilder.add(link.getAttributes().getAttribute("disconnected_"+ TransportMode.bike)); featureBuilder.add(link.getAttributes().getAttribute("disconnected_"+ TransportMode.walk)); diff --git a/src/main/java/routing/detour/NodeDetourCalculator.java b/src/main/java/routing/detour/NodeDetourCalculator.java index 3839bec..0e52990 100644 --- a/src/main/java/routing/detour/NodeDetourCalculator.java +++ b/src/main/java/routing/detour/NodeDetourCalculator.java @@ -18,7 +18,7 @@ import org.matsim.vehicles.Vehicle; import resources.Properties; import resources.Resources; -import routing.graph.LeastCostPathTree3; +import routing.graph.LcpTree1Way; import routing.graph.SpeedyGraph; import java.util.Set; @@ -112,8 +112,8 @@ private static class NodeWorker implements Runnable { } public void run() { - LeastCostPathTree3 lcpTreeFast; - LeastCostPathTree3 lcpTreeJibe; + LcpTree1Way lcpTreeFast; + LcpTree1Way lcpTreeJibe; while (true) { Id fromNodeId = this.originNodes.poll(); @@ -123,11 +123,11 @@ public void run() { this.counter.incCounter(); - lcpTreeFast = new LeastCostPathTree3(this.graphFast); - lcpTreeJibe = new LeastCostPathTree3(this.graphJibe); + lcpTreeFast = new LcpTree1Way(this.graphFast,true); + lcpTreeJibe = new LcpTree1Way(this.graphJibe,true); - lcpTreeFast.calculate(fromNodeId.index(),0.,true); - lcpTreeJibe.calculate(fromNodeId.index(),0.,true); + lcpTreeFast.calculate(fromNodeId.index(),0.); + lcpTreeJibe.calculate(fromNodeId.index(),0.); for (Id toNodeId : destinationNodes) { diff --git a/src/main/java/routing/disutility/JibeDisutility3.java b/src/main/java/routing/disutility/JibeDisutility3.java index f72bf5d..cadeb96 100644 --- a/src/main/java/routing/disutility/JibeDisutility3.java +++ b/src/main/java/routing/disutility/JibeDisutility3.java @@ -16,6 +16,8 @@ import routing.disutility.components.LinkComfort; import routing.disutility.components.LinkStress; +import java.util.Objects; + /** * Custom walk and bicycle disutility for JIBE * based on BicycleTravelDisutility by Dominik Ziemke @@ -29,16 +31,18 @@ public class JibeDisutility3 implements TravelDisutility { private final double marginalCostAmbience_s; private final double marginalCostStress_s; private final TravelTime timeCalculator; + private Boolean dayNightOverride; // Default parameters - public JibeDisutility3(String mode, TravelTime tt) { + public JibeDisutility3(String mode, TravelTime tt, Boolean dayNightOverride) { if(!mode.equals(TransportMode.bike) && !mode.equals(TransportMode.walk)) { - throw new RuntimeException("Mode " + mode + " not suported for JIBE disutility."); + throw new RuntimeException("Mode " + mode + " not supported for JIBE disutility."); } this.mode = mode; this.timeCalculator = tt; + this.dayNightOverride = dayNightOverride; this.marginalCostOfGradient_s = Resources.instance.getMarginalCost(mode,Properties.GRADIENT); this.marginalCostOfComfort_s = Resources.instance.getMarginalCost(mode,Properties.COMFORT); this.marginalCostAmbience_s = Resources.instance.getMarginalCost(mode,Properties.AMBIENCE); @@ -47,7 +51,7 @@ public JibeDisutility3(String mode, TravelTime tt) { } // Custom parameters - public JibeDisutility3(String mode, TravelTime tt, + public JibeDisutility3(String mode, TravelTime tt, Boolean dayNightOverride, double marginalCostOfGradient_s, double marginalCostOfComfort_s, double marginalCostAmbience_s, double marginalCostStress_s) { @@ -57,6 +61,7 @@ public JibeDisutility3(String mode, TravelTime tt, this.mode = mode; this.timeCalculator = tt; + this.dayNightOverride = dayNightOverride; this.marginalCostOfGradient_s = marginalCostOfGradient_s; this.marginalCostOfComfort_s = marginalCostOfComfort_s; this.marginalCostAmbience_s = marginalCostAmbience_s; @@ -64,21 +69,6 @@ public JibeDisutility3(String mode, TravelTime tt, printMarginalCosts(); } - public JibeDisutility3(String mode, TravelTime tt, double marginalCostAmbience_s, double marginalCostStress_s) { - - if(!mode.equals(TransportMode.bike) && !mode.equals(TransportMode.walk)) { - throw new RuntimeException("Mode " + mode + " not supported for JIBE disutility."); - } - - this.mode = mode; - this.timeCalculator = tt; - this.marginalCostOfGradient_s = Resources.instance.getMarginalCost(mode,Properties.GRADIENT); - this.marginalCostOfComfort_s = Resources.instance.getMarginalCost(mode,Properties.COMFORT); - this.marginalCostAmbience_s = marginalCostAmbience_s; - this.marginalCostStress_s = marginalCostStress_s; - printMarginalCosts(); - } - private void printMarginalCosts() { logger.info("Initialised JIBE disutility with the following parameters:" + "\nMode: " + this.mode + @@ -104,8 +94,11 @@ public double getLinkTravelDisutility(Link link, double time, Person person, Veh // Comfort of surface double comfortFactor = LinkComfort.getComfortFactor(link); - // Ambience factor - double ambience = LinkAmbience.getDayAmbience(link); + // Set day/night + boolean day = Objects.requireNonNullElseGet(dayNightOverride, () -> (time >= 21600 && time < 72000)); + + // Ambience + double ambience = day ? LinkAmbience.getDayAmbience(link) : LinkAmbience.getNightAmbience(link);; // Stress factors double linkStress = LinkStress.getStress(link,mode); @@ -144,7 +137,16 @@ public double getLinkMinimumTravelDisutility(Link link) { return 0; } - public double getLinkTravelTime(Link link, double time, Person person, Vehicle vehicle) { - return timeCalculator.getLinkTravelTime(link, time, person, vehicle); + public double getJunctionComponent(Link link, Vehicle vehicle) { + if((boolean) link.getAttributes().getAttribute("crossVehicles")) { + double distance = link.getLength(); + double travelTime = timeCalculator.getLinkTravelTime(link, 0., null, vehicle); + double junctionStress = JctStress.getStress(link,mode); + double junctionWidth = (double) link.getAttributes().getAttribute("crossWidth"); + if(junctionWidth > distance) junctionWidth = distance; + double junctionTime = travelTime * (junctionWidth / distance); + return marginalCostStress_s * junctionTime * junctionStress; + } + else return 0; } } diff --git a/src/main/java/routing/disutility/JibeDisutility4.java b/src/main/java/routing/disutility/JibeDisutility3Fast.java similarity index 76% rename from src/main/java/routing/disutility/JibeDisutility4.java rename to src/main/java/routing/disutility/JibeDisutility3Fast.java index be54ab9..ff74161 100644 --- a/src/main/java/routing/disutility/JibeDisutility4.java +++ b/src/main/java/routing/disutility/JibeDisutility3Fast.java @@ -22,32 +22,32 @@ * Custom walk and bicycle disutility for JIBE * based on BicycleTravelDisutility by Dominik Ziemke */ -public class JibeDisutility4 implements TravelDisutility { +public class JibeDisutility3Fast implements TravelDisutility { - private final static Logger logger = Logger.getLogger(JibeDisutility4.class); + private final static Logger logger = Logger.getLogger(JibeDisutility3Fast.class); private final String mode; private final double marginalCostOfGradient_s; private final double marginalCostOfComfort_s; private final double marginalCostAmbience_s; private final double marginalCostStress_s; private final TravelTime timeCalculator; - private Network network; - private Vehicle vehicle; - private final Boolean dayOverride; + private final Network network; + private final Vehicle vehicle; + private final Boolean dayNightOverride; private final double[] disutilities = new double[Id.getNumberOfIds(Link.class) * 2]; // Default parameters - public JibeDisutility4(Network network, Vehicle vehicle, String mode, TravelTime tt, Boolean dayOverride) { + public JibeDisutility3Fast(Network network, Vehicle vehicle, String mode, TravelTime tt, Boolean dayNightOverride) { if(!mode.equals(TransportMode.bike) && !mode.equals(TransportMode.walk)) { - throw new RuntimeException("Mode " + mode + " not suported for JIBE disutility."); + throw new RuntimeException("Mode " + mode + " not supported for JIBE disutility."); } this.network = network; this.vehicle = vehicle; this.mode = mode; this.timeCalculator = tt; - this.dayOverride = dayOverride; + this.dayNightOverride = dayNightOverride; this.marginalCostOfGradient_s = Resources.instance.getMarginalCost(mode,Properties.GRADIENT); this.marginalCostOfComfort_s = Resources.instance.getMarginalCost(mode,Properties.COMFORT); this.marginalCostAmbience_s = Resources.instance.getMarginalCost(mode,Properties.AMBIENCE); @@ -57,9 +57,9 @@ public JibeDisutility4(Network network, Vehicle vehicle, String mode, TravelTime } // Custom parameters - public JibeDisutility4(Network network, Vehicle vehicle, String mode, TravelTime tt, Boolean dayOverride, - double marginalCostOfGradient_s, double marginalCostOfComfort_s, - double marginalCostAmbience_s, double marginalCostStress_s) { + public JibeDisutility3Fast(Network network, Vehicle vehicle, String mode, TravelTime tt, Boolean dayNightOverride, + double marginalCostOfGradient_s, double marginalCostOfComfort_s, + double marginalCostAmbience_s, double marginalCostStress_s) { if(!mode.equals(TransportMode.bike) && !mode.equals(TransportMode.walk)) { throw new RuntimeException("Mode " + mode + " not supported for JIBE disutility."); @@ -69,7 +69,7 @@ public JibeDisutility4(Network network, Vehicle vehicle, String mode, TravelTime this.vehicle = vehicle; this.mode = mode; this.timeCalculator = tt; - this.dayOverride = dayOverride; + this.dayNightOverride = dayNightOverride; this.marginalCostOfGradient_s = marginalCostOfGradient_s; this.marginalCostOfComfort_s = marginalCostOfComfort_s; this.marginalCostAmbience_s = marginalCostAmbience_s; @@ -78,34 +78,6 @@ public JibeDisutility4(Network network, Vehicle vehicle, String mode, TravelTime precalculateDisutility(); } - public JibeDisutility4(String mode, TravelTime tt, Boolean dayOverride, - double marginalCostOfGradient_s, double marginalCostOfComfort_s, - double marginalCostAmbience_s, double marginalCostStress_s) { - - if(!mode.equals(TransportMode.bike) && !mode.equals(TransportMode.walk)) { - throw new RuntimeException("Mode " + mode + " not supported for JIBE disutility."); - } - - this.network = null; - this.vehicle = null; - this.mode = mode; - this.timeCalculator = tt; - this.dayOverride = dayOverride; - this.marginalCostOfGradient_s = marginalCostOfGradient_s; - this.marginalCostOfComfort_s = marginalCostOfComfort_s; - this.marginalCostAmbience_s = marginalCostAmbience_s; - this.marginalCostStress_s = marginalCostStress_s; - printMarginalCosts(); - } - - public void setNetwork(Network network) { - this.network = network; - } - - public void setVehicle(Vehicle vehicle) { - this.vehicle = vehicle; - } - private void printMarginalCosts() { logger.info("Initialised JIBE disutility with the following parameters:" + "\nMode: " + this.mode + @@ -117,21 +89,21 @@ private void printMarginalCosts() { public void precalculateDisutility() { logger.info("precalculating disutilities..."); - if(dayOverride != null) { + if(dayNightOverride != null) { for(Link link : network.getLinks().values()) { - double linkDisutility = calculateDisutility(link,dayOverride,vehicle); + double linkDisutility = calculateDisutility(link, dayNightOverride); disutilities[link.getId().index() * 2] = linkDisutility; disutilities[link.getId().index() * 2 + 1] = linkDisutility; } } else { for(Link link : network.getLinks().values()) { - disutilities[link.getId().index() * 2] = calculateDisutility(link,true,vehicle); - disutilities[link.getId().index() * 2 + 1] = calculateDisutility(link,false,vehicle); + disutilities[link.getId().index() * 2] = calculateDisutility(link,true); + disutilities[link.getId().index() * 2 + 1] = calculateDisutility(link,false); } } } - private double calculateDisutility(Link link, boolean day, Vehicle vehicle) { + private double calculateDisutility(Link link, boolean day) { if(link.getAllowedModes().contains(this.mode)) { double travelTime = timeCalculator.getLinkTravelTime(link, 0., null, vehicle); @@ -194,4 +166,17 @@ public double getLinkMinimumTravelDisutility(Link link) { return 0; } + public double getJunctionComponent(Link link) { + if((boolean) link.getAttributes().getAttribute("crossVehicles")) { + double distance = link.getLength(); + double travelTime = timeCalculator.getLinkTravelTime(link, 0., null, vehicle); + double junctionStress = JctStress.getStress(link,mode); + double junctionWidth = (double) link.getAttributes().getAttribute("crossWidth"); + if(junctionWidth > distance) junctionWidth = distance; + double junctionTime = travelTime * (junctionWidth / distance); + return marginalCostStress_s * junctionTime * junctionStress; + } + else return 0; + } + } diff --git a/src/main/java/routing/disutility/components/LinkStress.java b/src/main/java/routing/disutility/components/LinkStress.java index b1205e2..7a0034a 100644 --- a/src/main/java/routing/disutility/components/LinkStress.java +++ b/src/main/java/routing/disutility/components/LinkStress.java @@ -85,14 +85,13 @@ private static double getWalkStress(Link link) { if ((boolean) link.getAttributes().getAttribute("allowsCar")) { double speedLimit = ((Integer) link.getAttributes().getAttribute("speedLimitMPH")).doubleValue(); double speed85perc = (double) link.getAttributes().getAttribute("veh85percSpeedKPH") * 0.621371; - double aadt = ((int) link.getAttributes().getAttribute("aadt")) * 0.865; if (speed85perc >= speedLimit * 1.1) { speedLimit = speed85perc; } double freightPoiFactor = getFreightPoiFactor(link); - stress = -1.625 + 0.0625 * speedLimit + 0.000125 * aadt + 0.2 * freightPoiFactor; + stress = -1.5 + 0.05 * speedLimit + 0.2 * freightPoiFactor; if (stress < 0.) { stress = 0; diff --git a/src/main/java/routing/graph/LeastCostPathTree3.java b/src/main/java/routing/graph/LcpTree1Way.java similarity index 87% rename from src/main/java/routing/graph/LeastCostPathTree3.java rename to src/main/java/routing/graph/LcpTree1Way.java index 57f5303..857665b 100644 --- a/src/main/java/routing/graph/LeastCostPathTree3.java +++ b/src/main/java/routing/graph/LcpTree1Way.java @@ -11,12 +11,12 @@ *

* In some limited tests, this resulted in a speed-up of at least a factor 2.5 compared to MATSim's default LeastCostPathTree. *

- * The implementation does not allocate any memory in the {@link #calculate(int, double, boolean)} method. All required memory is pre-allocated in the constructor. This makes the + * The implementation does not allocate any memory in the calculate method. All required memory is pre-allocated in the constructor. This makes the * implementation NOT thread-safe. * * @author mrieser / Simunto, sponsored by SBB Swiss Federal Railways */ -public class LeastCostPathTree3 { +public class LcpTree1Way implements PathTree { private final SpeedyGraph graph; private final double[] data; // 3 entries per node: time, cost, distance @@ -24,9 +24,11 @@ public class LeastCostPathTree3 { private final SpeedyGraph.LinkIterator outLI; private final SpeedyGraph.LinkIterator inLI; private final NodeMinHeap pq; + private final boolean fwd; - public LeastCostPathTree3(SpeedyGraph graph) { + public LcpTree1Way(SpeedyGraph graph, boolean fwd) { this.graph = graph; + this.fwd = fwd; this.data = new double[graph.nodeCount * 3]; this.comingFrom = new int[graph.nodeCount]; this.pq = new NodeMinHeap(graph.nodeCount, this::getCost, this::setCost); @@ -34,11 +36,13 @@ public LeastCostPathTree3(SpeedyGraph graph) { this.inLI = graph.getInLinkIterator(); } - public void calculate(int startNode, double startTime, boolean fwd) { - this.calculate(startNode, startTime, (node, arrTime, cost, distance, depTime) -> false, fwd); + @Override + public void calculate(int startNode, double startTime) { + this.calculate(startNode, startTime, (node, arrTime, cost, distance, depTime) -> false); } - public void calculate(int startNode, double startTime, StopCriterion stopCriterion, boolean fwd) { + @Override + public void calculate(int startNode, double startTime, StopCriterion stopCriterion) { Arrays.fill(this.data, Double.POSITIVE_INFINITY); Arrays.fill(this.comingFrom, -1); @@ -48,12 +52,13 @@ public void calculate(int startNode, double startTime, StopCriterion stopCriteri this.pq.clear(); this.pq.insert(startNode); - fillTree(startTime, stopCriterion, fwd); + fillTree(startTime, stopCriterion); } + @Override public void calculate(int startNode1, double cost1, double time1, double dist1, int startNode2, double cost2, double time2, double dist2, - double startTime, StopCriterion stopCriterion, boolean fwd) { + double startTime, StopCriterion stopCriterion) { Arrays.fill(this.data, Double.POSITIVE_INFINITY); Arrays.fill(this.comingFrom, -1); @@ -70,10 +75,10 @@ public void calculate(int startNode1, double cost1, double time1, double dist1, this.pq.insert(startNode1); } - fillTree(startTime, stopCriterion, fwd); + fillTree(startTime, stopCriterion); } - private void fillTree(double startTime, StopCriterion stopCriterion, boolean fwd) { + private void fillTree(double startTime, StopCriterion stopCriterion) { SpeedyGraph.LinkIterator LI = fwd ? this.outLI : this.inLI; while (!this.pq.isEmpty()) { final int nodeIdx = this.pq.poll(); @@ -112,10 +117,12 @@ private void fillTree(double startTime, StopCriterion stopCriterion, boolean fwd } } + @Override public double getCost(int nodeIndex) { return this.data[nodeIndex * 3]; } + @Override public OptionalTime getTime(int nodeIndex) { double time = this.data[nodeIndex * 3 + 1]; if (Double.isInfinite(time)) { @@ -124,6 +131,7 @@ public OptionalTime getTime(int nodeIndex) { return OptionalTime.defined(time); } + @Override public double getDistance(int nodeIndex) { return this.data[nodeIndex * 3 + 2]; } @@ -143,8 +151,4 @@ public int getComingFrom(int nodeIndex) { return this.comingFrom[nodeIndex]; } - public interface StopCriterion { - - boolean stop(int nodeIndex, double arrivalTime, double travelCost, double distance, double departureTime); - } } diff --git a/src/main/java/routing/graph/LcpTree2Way.java b/src/main/java/routing/graph/LcpTree2Way.java new file mode 100644 index 0000000..50eb444 --- /dev/null +++ b/src/main/java/routing/graph/LcpTree2Way.java @@ -0,0 +1,55 @@ +package routing.graph; + +import org.matsim.core.utils.misc.OptionalTime; + +public class LcpTree2Way implements PathTree { + + LcpTree1Way lcpTreeFwd; + LcpTree1Way lcpTreeRev; + + public LcpTree2Way(SpeedyGraph graph) { + lcpTreeFwd = new LcpTree1Way(graph,true); + lcpTreeRev = new LcpTree1Way(graph,false); + } + + @Override + public void calculate(int startNode, double startTime) { + lcpTreeFwd.calculate(startNode,startTime); + lcpTreeRev.calculate(startNode,startTime); + } + + @Override + public void calculate(int startNode, double startTime, StopCriterion stopCriterion) { + lcpTreeFwd.calculate(startNode,startTime); + lcpTreeRev.calculate(startNode,startTime); + } + + @Override + public void calculate(int startNode1, double cost1, double time1, double dist1, + int startNode2, double cost2, double time2, double dist2, + double startTime, StopCriterion stopCriterion) { + lcpTreeFwd.calculate(startNode1,cost1,time1,dist1,startNode2,cost2,time2,dist2,startTime,stopCriterion); + lcpTreeRev.calculate(startNode1,cost1,time1,dist1,startNode2,cost2,time2,dist2,startTime,stopCriterion); + } + + @Override + public double getCost(int nodeIndex) { + return (lcpTreeFwd.getCost(nodeIndex) + lcpTreeRev.getCost(nodeIndex))/2; + } + + @Override + public double getDistance(int nodeIndex) { + return (lcpTreeFwd.getDistance(nodeIndex) + lcpTreeFwd.getDistance(nodeIndex))/2; + } + + @Override + public OptionalTime getTime(int nodeIndex) { + double timeFwd = lcpTreeFwd.getTime(nodeIndex).orElse(Double.POSITIVE_INFINITY); + double timeRev = lcpTreeRev.getTime(nodeIndex).orElse(Double.POSITIVE_INFINITY); + double time = timeFwd + timeRev; + if (Double.isInfinite(time)) { + return OptionalTime.undefined(); + } + return OptionalTime.defined(time/2); + } +} diff --git a/src/main/java/routing/graph/PathTree.java b/src/main/java/routing/graph/PathTree.java new file mode 100644 index 0000000..5219a23 --- /dev/null +++ b/src/main/java/routing/graph/PathTree.java @@ -0,0 +1,20 @@ +package routing.graph; + +import org.matsim.core.utils.misc.OptionalTime; + +public interface PathTree { + + void calculate(int startNode, double startTime); + + void calculate(int startNode, double startTime, StopCriterion stopCriterion); + + void calculate(int startNode1, double cost1, double time1, double dist1, + int startNode2, double cost2, double time2, double dist2, + double startTime, StopCriterion stopCriterion); + + double getCost(int nodeIndex); + double getDistance(int nodeIndex); + OptionalTime getTime(int nodeIndex); + +} + diff --git a/src/main/java/routing/graph/StopCriterion.java b/src/main/java/routing/graph/StopCriterion.java new file mode 100644 index 0000000..7c970dd --- /dev/null +++ b/src/main/java/routing/graph/StopCriterion.java @@ -0,0 +1,5 @@ +package routing.graph; + +public interface StopCriterion { + boolean stop(int nodeIndex, double arrivalTime, double travelCost, double distance, double departureTime); +} diff --git a/src/main/java/trads/RunRouter.java b/src/main/java/trads/RunRouter.java index 19fe941..5742e7b 100644 --- a/src/main/java/trads/RunRouter.java +++ b/src/main/java/trads/RunRouter.java @@ -17,7 +17,7 @@ import routing.ActiveAttributes; import routing.Bicycle; import routing.disutility.DistanceDisutility; -import routing.disutility.JibeDisutility4; +import routing.disutility.JibeDisutility3Fast; import routing.travelTime.WalkTravelTime; import trads.calculate.RouteIndicatorCalculator; import trads.io.TradsCsvWriter; @@ -111,13 +111,13 @@ public static void main(String[] args) throws IOException, FactoryException { // calc.network("car_congested", ORIGIN, DESTINATION, null, networkCar, carXy2l, congestedDisutility, congestedTime, null,savePath); // bike (shortest and fastest) - calc.network("bike_jibe_day", ORIGIN, DESTINATION, bike, networkBike, networkBike, new JibeDisutility4(networkBike,bike,TransportMode.bike,ttBike,true), ttBike, ActiveAttributes.getJibe4(TransportMode.bike,bike),savePath); - calc.network("bike_jibe_night", ORIGIN, DESTINATION, bike, networkBike, networkBike, new JibeDisutility4(networkBike,bike,TransportMode.bike,ttBike,false), ttBike, ActiveAttributes.getJibe4(TransportMode.bike,bike),savePath); + calc.network("bike_jibe_day", ORIGIN, DESTINATION, bike, networkBike, networkBike, new JibeDisutility3Fast(networkBike,bike,TransportMode.bike,ttBike,true), ttBike, ActiveAttributes.getJibe4(TransportMode.bike,bike),savePath); + calc.network("bike_jibe_night", ORIGIN, DESTINATION, bike, networkBike, networkBike, new JibeDisutility3Fast(networkBike,bike,TransportMode.bike,ttBike,false), ttBike, ActiveAttributes.getJibe4(TransportMode.bike,bike),savePath); calc.network("bike_short", ORIGIN, DESTINATION, bike, networkBike, networkBike, new DistanceDisutility(), ttBike, null,savePath); calc.network("bike_fast", ORIGIN, DESTINATION, bike, networkBike, networkBike, new OnlyTimeDependentTravelDisutility(ttBike), ttBike, null,savePath); - calc.network("walk_jibe_day", ORIGIN, DESTINATION, null, networkWalk, networkWalk, new JibeDisutility4(networkWalk,null,TransportMode.walk,ttWalk,true), ttWalk, ActiveAttributes.getJibe4(TransportMode.walk,null), savePath); - calc.network("walk_jibe_night", ORIGIN, DESTINATION, null, networkWalk, networkWalk, new JibeDisutility4(networkWalk,null,TransportMode.walk,ttWalk,false), ttWalk, ActiveAttributes.getJibe4(TransportMode.walk,null), savePath); + calc.network("walk_jibe_day", ORIGIN, DESTINATION, null, networkWalk, networkWalk, new JibeDisutility3Fast(networkWalk,null,TransportMode.walk,ttWalk,true), ttWalk, ActiveAttributes.getJibe4(TransportMode.walk,null), savePath); + calc.network("walk_jibe_night", ORIGIN, DESTINATION, null, networkWalk, networkWalk, new JibeDisutility3Fast(networkWalk,null,TransportMode.walk,ttWalk,false), ttWalk, ActiveAttributes.getJibe4(TransportMode.walk,null), savePath); calc.network("walk_short", ORIGIN, DESTINATION, null, networkWalk, networkWalk, new DistanceDisutility(), ttWalk, ActiveAttributes.getJibe4(TransportMode.walk,null),savePath); calc.network("walk_fast", ORIGIN, DESTINATION, null, networkWalk, networkWalk, new OnlyTimeDependentTravelDisutility(ttWalk), ttWalk, null,savePath);