From 93aeba2bbda5d9be927404d8777d48eecfc80591 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 17:13:30 +0200 Subject: [PATCH 01/16] =?UTF-8?q?Jaakkonen=20(2013)=E2=80=99s=20values?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streets/BasicTraversalTimeCalculator.java | 7 ++++ .../conveyal/r5/streets/CongestionLevel.java | 13 ++++++ .../conveyal/r5/streets/CrossingPenalty.java | 41 +++++++++++++++++++ .../r5/streets/JaakkonenStreetClass.java | 31 ++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 src/main/java/com/conveyal/r5/streets/CongestionLevel.java create mode 100644 src/main/java/com/conveyal/r5/streets/CrossingPenalty.java create mode 100644 src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java diff --git a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java index a41d97eed..9a4292b83 100644 --- a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java @@ -27,9 +27,16 @@ public class BasicTraversalTimeCalculator implements TraversalTimeCalculator { public boolean driveOnRight; // TODO instead of a field, this should be a different implementation class + public CongestionLevel congestionLevel; + public BasicTraversalTimeCalculator (StreetLayer layer, boolean driveOnRight) { + this(layer, driveOnRight, CongestionLevel.AVERAGE); + } + + public BasicTraversalTimeCalculator (StreetLayer layer, boolean driveOnRight, CongestionLevel congestionLevel) { this.layer = layer; this.driveOnRight = driveOnRight; + this.congestionLevel = congestionLevel; } @Override diff --git a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java new file mode 100644 index 000000000..93e1d1504 --- /dev/null +++ b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java @@ -0,0 +1,13 @@ +package com.conveyal.r5.streets; + +/** + * These congestion levels relate to Jaakkonen (2013)’s assessment of crossing penalties in the Helsinki metropolitan area + * See: http://urn.fi/URN:NBN:fi-fe2017112252365, table 28 on page 61, + */ +public enum CongestionLevel { + RUSH_HOUR, + OFF_PEAK, + AVERAGE + +} + diff --git a/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java b/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java new file mode 100644 index 000000000..a3d73cb6e --- /dev/null +++ b/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java @@ -0,0 +1,41 @@ +package com.conveyal.r5.streets; + +import java.util.HashMap; + +/** + * Crossing penalties according to Jaakkonen (2013)’s analysis for the Helsinki metropolitan area + * See: http://urn.fi/URN:NBN:fi-fe2017112252365, table 28 on page 61, + */ +public class CrossingPenalty { + public static final HashMap> CROSSING_PENALTIES = new HashMap<>(); + + static { + CROSSING_PENALTIES.put( + CongestionLevel.AVERAGE, new HashMap<>() { + { + put(JaakkonenStreetClass.CLASS_1_2, 11.311); + put(JaakkonenStreetClass.CLASS_3, 9.439); + put(JaakkonenStreetClass.CLASS_4_5_6, 9.362); + } + } + ); + CROSSING_PENALTIES.put( + CongestionLevel.OFF_PEAK, new HashMap<>() { + { + put(JaakkonenStreetClass.CLASS_1_2, 9.979); + put(JaakkonenStreetClass.CLASS_3, 6.650); + put(JaakkonenStreetClass.CLASS_4_5_6, 7.752); + } + } + ); + CROSSING_PENALTIES.put( + CongestionLevel.RUSH_HOUR, new HashMap<>() { + { + put(JaakkonenStreetClass.CLASS_1_2, 12.195); + put(JaakkonenStreetClass.CLASS_3, 11.199); + put(JaakkonenStreetClass.CLASS_4_5_6, 10.633); + } + } + ); + } +} diff --git a/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java b/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java new file mode 100644 index 000000000..84ebe108b --- /dev/null +++ b/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java @@ -0,0 +1,31 @@ +package com.conveyal.r5.streets; + +import com.conveyal.r5.labeling.StreetClass; + +/** + * Translates the com.conveyal.r5.labeling.StreetClass (OSM tags) into Jaakkonen (2013)’s street classes, + * which are based on ‘functional classes’ in the DigiRoad’s road classification, + * see https://ava.vaylapilvi.fi/ava/Tie/Digiroad/Aineistojulkaisut/latest/Julkaisudokumentit + * and + */ +public enum JaakkonenStreetClass { + CLASS_1_2, + CLASS_3, + CLASS_4_5_6; +} + +/* + public static JaakkonenStreetClass fromR5StreetClass(StreetClass streetClass) { + if(streetClass.equals(StreetClass.MOTORWAY) || streetClass.equals(StreetClass.PRIMARY)){ + return JaakkonenStreetClass.CLASS_1_2; + } else if (streetClass.equals(StreetClass.SECONDARY)){ + return JaakkonenStreetClass.CLASS_3; + } else if (streetClass.equals(StreetClass.TERTIARY) || streetClass.equals(StreetClass.OTHER)){ + return JaakkonenStreetClass.CLASS_4_5_6; + } else { // catch-all, not really necessary here? + return JaakkonenStreetClass.CLASS_4_5_6; + } + } + +} +*/ \ No newline at end of file From 9cc5a19b292985b5a9052d30906eedd2638379a7 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 17:29:19 +0200 Subject: [PATCH 02/16] float -> int delays --- .../streets/BasicTraversalTimeCalculator.java | 17 +++++++++++- .../conveyal/r5/streets/CrossingPenalty.java | 27 ++++++++++++------- .../r5/streets/JaakkonenStreetClass.java | 2 -- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java index 9a4292b83..a3f2f8ecf 100644 --- a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java @@ -1,6 +1,7 @@ package com.conveyal.r5.streets; import com.conveyal.r5.common.GeometryUtils; +import com.conveyal.r5.labeling.StreetClass; import com.conveyal.r5.profile.ProfileRequest; import com.conveyal.r5.profile.StreetMode; import org.apache.commons.math3.util.FastMath; @@ -56,7 +57,7 @@ public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode) { if (streetMode == StreetMode.CAR) { double angle = calculateNewTurnAngle(fromEdge, toEdge); if (angle < 27) - return STRAIGHT_ON; + return straightOnDelay(fromEdge); else if (angle < 153) return driveOnRight ? LEFT_TURN : RIGHT_TURN; else if (angle < 207) @@ -69,6 +70,20 @@ else if (angle < 333) return 0; } + /** + * Get the delay for driving straight over a crossing, depending on fromEdge’s StreetClass, and the time of the day + * Based on Jaakkonen (2013) + */ + private int straightOnDelay(int fromEdge){ + EdgeStore.Edge e = layer.edgeStore.getCursor(fromEdge); + StreetClass streetClass = new StreetClass(e.getStreetClassCode() + int delay = CrossingPenalty.getDelay( + congestionLevel, + JaakkonenStreetClass.fromR5StreetClass(streetClass) + ); + return delay; + } + /** * Gets in/out angles from edges and calculates angle between them * @return angle in degrees from 0-360 diff --git a/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java b/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java index a3d73cb6e..846ba3d96 100644 --- a/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java +++ b/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java @@ -5,37 +5,44 @@ /** * Crossing penalties according to Jaakkonen (2013)’s analysis for the Helsinki metropolitan area * See: http://urn.fi/URN:NBN:fi-fe2017112252365, table 28 on page 61, + * + * Note that delays are in integer seconds, as com.conveyal.r5.streets.BasicTraversalTimeCalculator.turnTimeSeconds + * returns full seconds, only (probably a question of performance?) */ public class CrossingPenalty { - public static final HashMap> CROSSING_PENALTIES = new HashMap<>(); + public static final HashMap> CROSSING_PENALTIES = new HashMap<>(); static { CROSSING_PENALTIES.put( CongestionLevel.AVERAGE, new HashMap<>() { { - put(JaakkonenStreetClass.CLASS_1_2, 11.311); - put(JaakkonenStreetClass.CLASS_3, 9.439); - put(JaakkonenStreetClass.CLASS_4_5_6, 9.362); + put(JaakkonenStreetClass.CLASS_1_2, 11 /*11.311*/); + put(JaakkonenStreetClass.CLASS_3, 9 /*9.439*/); + put(JaakkonenStreetClass.CLASS_4_5_6, 9 /*9.362*/); } } ); CROSSING_PENALTIES.put( CongestionLevel.OFF_PEAK, new HashMap<>() { { - put(JaakkonenStreetClass.CLASS_1_2, 9.979); - put(JaakkonenStreetClass.CLASS_3, 6.650); - put(JaakkonenStreetClass.CLASS_4_5_6, 7.752); + put(JaakkonenStreetClass.CLASS_1_2, 10 /*9.979*/); + put(JaakkonenStreetClass.CLASS_3, 7 /*6.650*/); + put(JaakkonenStreetClass.CLASS_4_5_6, 8 /*7.752*/); } } ); CROSSING_PENALTIES.put( CongestionLevel.RUSH_HOUR, new HashMap<>() { { - put(JaakkonenStreetClass.CLASS_1_2, 12.195); - put(JaakkonenStreetClass.CLASS_3, 11.199); - put(JaakkonenStreetClass.CLASS_4_5_6, 10.633); + put(JaakkonenStreetClass.CLASS_1_2, 12 /*12.195*/); + put(JaakkonenStreetClass.CLASS_3, 11 /*11.199*/); + put(JaakkonenStreetClass.CLASS_4_5_6, 11 /*10.633*/); } } ); } + + public static int getDelay(CongestionLevel congestionLevel, JaakkonenStreetClass jaakkonenStreetClass){ + return CROSSING_PENALTIES.get(congestionLevel).get(jaakkonenStreetClass); + } } diff --git a/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java b/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java index 84ebe108b..52264ec15 100644 --- a/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java +++ b/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java @@ -14,7 +14,6 @@ public enum JaakkonenStreetClass { CLASS_4_5_6; } -/* public static JaakkonenStreetClass fromR5StreetClass(StreetClass streetClass) { if(streetClass.equals(StreetClass.MOTORWAY) || streetClass.equals(StreetClass.PRIMARY)){ return JaakkonenStreetClass.CLASS_1_2; @@ -28,4 +27,3 @@ public static JaakkonenStreetClass fromR5StreetClass(StreetClass streetClass) { } } -*/ \ No newline at end of file From bc91069f4242a568d3af73a587fd5e9af831b64d Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 18:14:12 +0200 Subject: [PATCH 03/16] =?UTF-8?q?let=E2=80=99s=20try=20this?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streets/BasicTraversalTimeCalculator.java | 9 ++++----- .../conveyal/r5/streets/CongestionLevel.java | 18 +++++++++++++++++- .../r5/streets/JaakkonenStreetClass.java | 11 +++++------ .../com/conveyal/r5/streets/StreetRouter.java | 9 +++++++++ 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java index a3f2f8ecf..40639b24b 100644 --- a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java @@ -65,7 +65,7 @@ else if (angle < 207) else if (angle < 333) return driveOnRight ? RIGHT_TURN : LEFT_TURN; else - return STRAIGHT_ON; + return straightOnDelay(fromEdge); } return 0; } @@ -76,12 +76,11 @@ else if (angle < 333) */ private int straightOnDelay(int fromEdge){ EdgeStore.Edge e = layer.edgeStore.getCursor(fromEdge); - StreetClass streetClass = new StreetClass(e.getStreetClassCode() - int delay = CrossingPenalty.getDelay( + Byte streetClassCode = e.getStreetClassCode(); + return CrossingPenalty.getDelay( congestionLevel, - JaakkonenStreetClass.fromR5StreetClass(streetClass) + JaakkonenStreetClass.fromR5StreetClassCode(streetClassCode) ); - return delay; } /** diff --git a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java index 93e1d1504..7ee44769d 100644 --- a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java +++ b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java @@ -7,7 +7,23 @@ public enum CongestionLevel { RUSH_HOUR, OFF_PEAK, - AVERAGE + AVERAGE; + + public static CongestionLevel fromFromTime(int secondsSinceMidnight) { + /* + * based on https://www.tomtom.com/traffic-index/helsinki-traffic/ + */ + if (secondsSinceMidnight < 25_200) // 7:00 + return CongestionLevel.OFF_PEAK; + else if (secondsSinceMidnight < 36_000) // 10:00 + return CongestionLevel.RUSH_HOUR; + else if (secondsSinceMidnight < 50_400) // 14:00 + return CongestionLevel.AVERAGE; + else if (secondsSinceMidnight < 64800) // 18:00 + return CongestionLevel.RUSH_HOUR; + else + return CongestionLevel.OFF_PEAK; + } } diff --git a/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java b/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java index 52264ec15..815c3efca 100644 --- a/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java +++ b/src/main/java/com/conveyal/r5/streets/JaakkonenStreetClass.java @@ -5,21 +5,20 @@ /** * Translates the com.conveyal.r5.labeling.StreetClass (OSM tags) into Jaakkonen (2013)’s street classes, * which are based on ‘functional classes’ in the DigiRoad’s road classification, - * see https://ava.vaylapilvi.fi/ava/Tie/Digiroad/Aineistojulkaisut/latest/Julkaisudokumentit + * see ... * and */ public enum JaakkonenStreetClass { CLASS_1_2, CLASS_3, CLASS_4_5_6; -} - public static JaakkonenStreetClass fromR5StreetClass(StreetClass streetClass) { - if(streetClass.equals(StreetClass.MOTORWAY) || streetClass.equals(StreetClass.PRIMARY)){ + public static JaakkonenStreetClass fromR5StreetClassCode(Byte streetClassCode) { + if(streetClassCode.equals(StreetClass.MOTORWAY.code) || streetClassCode.equals(StreetClass.PRIMARY.code)){ return JaakkonenStreetClass.CLASS_1_2; - } else if (streetClass.equals(StreetClass.SECONDARY)){ + } else if (streetClassCode.equals(StreetClass.SECONDARY.code)){ return JaakkonenStreetClass.CLASS_3; - } else if (streetClass.equals(StreetClass.TERTIARY) || streetClass.equals(StreetClass.OTHER)){ + } else if (streetClassCode.equals(StreetClass.TERTIARY.code) || streetClassCode.equals(StreetClass.OTHER.code)){ return JaakkonenStreetClass.CLASS_4_5_6; } else { // catch-all, not really necessary here? return JaakkonenStreetClass.CLASS_4_5_6; diff --git a/src/main/java/com/conveyal/r5/streets/StreetRouter.java b/src/main/java/com/conveyal/r5/streets/StreetRouter.java index fa3750e35..674219c4d 100644 --- a/src/main/java/com/conveyal/r5/streets/StreetRouter.java +++ b/src/main/java/com/conveyal/r5/streets/StreetRouter.java @@ -28,6 +28,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; +import java.time.DayOfWeek; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -459,6 +460,14 @@ public void route () { // FIXME this class is supposed to be throw-away, should we be reusing instances at all? change this variable name to be clearer. final int tmpTimeLimitSeconds; + // set the congestion level (rush hour/off peak) depending on week day and time of day + CongestionLevel congestionLevel; + DayOfWeek dayOfWeek = profileRequest.date.getDayOfWeek(); + if (dayOfWeek.equals(DayOfWeek.SUNDAY) || dayOfWeek.equals(DayOfWeek.SATURDAY)) + congestionLevel = CongestionLevel.OFF_PEAK; + else + congestionLevel = CongestionLevel.fromFromTime(profileRequest.fromTime); + // Set up goal direction. if (destinationSplit != null) { // This search has a destination, so enable A* goal direction. From 2b94e5f18d0bd10713d136f64eb15a7c3a866293 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 18:39:06 +0200 Subject: [PATCH 04/16] enough for today --- .../com/conveyal/r5/streets/BasicTraversalTimeCalculator.java | 1 - src/main/java/com/conveyal/r5/streets/CongestionLevel.java | 2 +- src/main/java/com/conveyal/r5/streets/CrossingPenalty.java | 2 +- src/main/java/com/conveyal/r5/streets/StreetRouter.java | 4 ++++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java index 40639b24b..2b89d52d2 100644 --- a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java @@ -1,7 +1,6 @@ package com.conveyal.r5.streets; import com.conveyal.r5.common.GeometryUtils; -import com.conveyal.r5.labeling.StreetClass; import com.conveyal.r5.profile.ProfileRequest; import com.conveyal.r5.profile.StreetMode; import org.apache.commons.math3.util.FastMath; diff --git a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java index 7ee44769d..87f82707d 100644 --- a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java +++ b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java @@ -2,7 +2,7 @@ /** * These congestion levels relate to Jaakkonen (2013)’s assessment of crossing penalties in the Helsinki metropolitan area - * See: http://urn.fi/URN:NBN:fi-fe2017112252365, table 28 on page 61, + * See: ..., table 28 on page 61, */ public enum CongestionLevel { RUSH_HOUR, diff --git a/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java b/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java index 846ba3d96..36ab4a036 100644 --- a/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java +++ b/src/main/java/com/conveyal/r5/streets/CrossingPenalty.java @@ -4,7 +4,7 @@ /** * Crossing penalties according to Jaakkonen (2013)’s analysis for the Helsinki metropolitan area - * See: http://urn.fi/URN:NBN:fi-fe2017112252365, table 28 on page 61, + * See: ..., table 28 on page 61, * * Note that delays are in integer seconds, as com.conveyal.r5.streets.BasicTraversalTimeCalculator.turnTimeSeconds * returns full seconds, only (probably a question of performance?) diff --git a/src/main/java/com/conveyal/r5/streets/StreetRouter.java b/src/main/java/com/conveyal/r5/streets/StreetRouter.java index 674219c4d..649f97b37 100644 --- a/src/main/java/com/conveyal/r5/streets/StreetRouter.java +++ b/src/main/java/com/conveyal/r5/streets/StreetRouter.java @@ -468,6 +468,10 @@ public void route () { else congestionLevel = CongestionLevel.fromFromTime(profileRequest.fromTime); + // TODO: this following line does not work, since timeCalculator implements a TraversalTimeCalculator + // and does not necessarily have a .congestionLevel + //timeCalculator.congestionLevel = congestionLevel; + // Set up goal direction. if (destinationSplit != null) { // This search has a destination, so enable A* goal direction. From c7015528af2114669e63347a9f403a93ccf4ce63 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 18:57:25 +0200 Subject: [PATCH 05/16] =?UTF-8?q?too=20many=20changes=20for=20such=20a=20s?= =?UTF-8?q?mall=20patch=20=F0=9F=98=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streets/BasicTraversalTimeCalculator.java | 17 +++++------------ .../conveyal/r5/streets/CongestionLevel.java | 13 +++++++++++++ .../com/conveyal/r5/streets/EdgeStore.java | 6 ++++-- .../r5/streets/EdgeTraversalTimes.java | 2 +- .../MultistageTraversalTimeCalculator.java | 4 ++-- .../com/conveyal/r5/streets/StreetRouter.java | 18 ++++-------------- .../r5/streets/TraversalTimeCalculator.java | 2 +- .../r5/streets/TimeDependentRoutingTest.java | 2 +- 8 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java index 2b89d52d2..dc5937aae 100644 --- a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java @@ -27,16 +27,9 @@ public class BasicTraversalTimeCalculator implements TraversalTimeCalculator { public boolean driveOnRight; // TODO instead of a field, this should be a different implementation class - public CongestionLevel congestionLevel; - public BasicTraversalTimeCalculator (StreetLayer layer, boolean driveOnRight) { - this(layer, driveOnRight, CongestionLevel.AVERAGE); - } - - public BasicTraversalTimeCalculator (StreetLayer layer, boolean driveOnRight, CongestionLevel congestionLevel) { - this.layer = layer; + this.layer = layer; this.driveOnRight = driveOnRight; - this.congestionLevel = congestionLevel; } @Override @@ -52,11 +45,11 @@ public int traversalTimeSeconds (EdgeStore.Edge currentEdge, StreetMode streetMo * TODO pull this out into an interface to allow generalization to data from generalized cost tags */ @Override - public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode) { + public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode, CongestionLevel congestionLevel) { if (streetMode == StreetMode.CAR) { double angle = calculateNewTurnAngle(fromEdge, toEdge); if (angle < 27) - return straightOnDelay(fromEdge); + return straightOnDelay(fromEdge, congestionLevel); else if (angle < 153) return driveOnRight ? LEFT_TURN : RIGHT_TURN; else if (angle < 207) @@ -64,7 +57,7 @@ else if (angle < 207) else if (angle < 333) return driveOnRight ? RIGHT_TURN : LEFT_TURN; else - return straightOnDelay(fromEdge); + return straightOnDelay(fromEdge, congestionLevel); } return 0; } @@ -73,7 +66,7 @@ else if (angle < 333) * Get the delay for driving straight over a crossing, depending on fromEdge’s StreetClass, and the time of the day * Based on Jaakkonen (2013) */ - private int straightOnDelay(int fromEdge){ + private int straightOnDelay(int fromEdge, CongestionLevel congestionLevel){ EdgeStore.Edge e = layer.edgeStore.getCursor(fromEdge); Byte streetClassCode = e.getStreetClassCode(); return CrossingPenalty.getDelay( diff --git a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java index 87f82707d..dacb3dd4c 100644 --- a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java +++ b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java @@ -1,5 +1,9 @@ package com.conveyal.r5.streets; +import com.conveyal.r5.profile.ProfileRequest; + +import java.time.DayOfWeek; + /** * These congestion levels relate to Jaakkonen (2013)’s assessment of crossing penalties in the Helsinki metropolitan area * See: ..., table 28 on page 61, @@ -25,5 +29,14 @@ else if (secondsSinceMidnight < 64800) // 18:00 return CongestionLevel.OFF_PEAK; } + public static CongestionLevel fromProfileRequest(ProfileRequest profileRequest) { + // set the congestion level (rush hour/off peak) depending on week day and time of day + DayOfWeek dayOfWeek = profileRequest.date.getDayOfWeek(); + if (dayOfWeek.equals(DayOfWeek.SUNDAY) || dayOfWeek.equals(DayOfWeek.SATURDAY)) + return CongestionLevel.OFF_PEAK; + else + return CongestionLevel.fromFromTime(profileRequest.fromTime); + } + } diff --git a/src/main/java/com/conveyal/r5/streets/EdgeStore.java b/src/main/java/com/conveyal/r5/streets/EdgeStore.java index bc2719c58..7042d3302 100644 --- a/src/main/java/com/conveyal/r5/streets/EdgeStore.java +++ b/src/main/java/com/conveyal/r5/streets/EdgeStore.java @@ -693,13 +693,15 @@ public StreetRouter.State traverse ( // This was rounding up, now truncating ... maybe change back for consistency? // int roundedTime = (int) Math.ceil(time); + CongestionLevel congestionLevel = CongestionLevel.fromProfileRequest(req); + int turnTimeSeconds = 0; // Negative backEdge means this state is not the result of traversing an edge (it's the start of a search). if (s0.backEdge >= 0) { if (req.reverseSearch) { - turnTimeSeconds = timeCalculator.turnTimeSeconds(getEdgeIndex(), s0.backEdge, streetMode); + turnTimeSeconds = timeCalculator.turnTimeSeconds(getEdgeIndex(), s0.backEdge, streetMode, congestionLevel); } else { - turnTimeSeconds = timeCalculator.turnTimeSeconds(s0.backEdge, getEdgeIndex(), streetMode); + turnTimeSeconds = timeCalculator.turnTimeSeconds(s0.backEdge, getEdgeIndex(), streetMode, congestionLevel); } } // TODO add checks for negative increment values to these functions. diff --git a/src/main/java/com/conveyal/r5/streets/EdgeTraversalTimes.java b/src/main/java/com/conveyal/r5/streets/EdgeTraversalTimes.java index 07d515bdf..78342c898 100644 --- a/src/main/java/com/conveyal/r5/streets/EdgeTraversalTimes.java +++ b/src/main/java/com/conveyal/r5/streets/EdgeTraversalTimes.java @@ -32,7 +32,7 @@ public int traversalTimeSeconds (EdgeStore.Edge currentEdge, StreetMode streetMo } @Override - public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode) { + public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode, CongestionLevel congestionLevel) { if (streetMode == StreetMode.WALK) { return walkTraversalTimes.turnTimeSeconds(fromEdge, toEdge); } else if (streetMode == StreetMode.BICYCLE) { diff --git a/src/main/java/com/conveyal/r5/streets/MultistageTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/MultistageTraversalTimeCalculator.java index 952bb603c..1ae4fc2df 100644 --- a/src/main/java/com/conveyal/r5/streets/MultistageTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/MultistageTraversalTimeCalculator.java @@ -51,8 +51,8 @@ public int traversalTimeSeconds (EdgeStore.Edge currentEdge, StreetMode streetMo } @Override - public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode) { - return base.turnTimeSeconds(fromEdge, toEdge, streetMode); + public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode, CongestionLevel congestionLevel) { + return base.turnTimeSeconds(fromEdge, toEdge, streetMode, congestionLevel); } } diff --git a/src/main/java/com/conveyal/r5/streets/StreetRouter.java b/src/main/java/com/conveyal/r5/streets/StreetRouter.java index 649f97b37..e2b50e076 100644 --- a/src/main/java/com/conveyal/r5/streets/StreetRouter.java +++ b/src/main/java/com/conveyal/r5/streets/StreetRouter.java @@ -460,18 +460,6 @@ public void route () { // FIXME this class is supposed to be throw-away, should we be reusing instances at all? change this variable name to be clearer. final int tmpTimeLimitSeconds; - // set the congestion level (rush hour/off peak) depending on week day and time of day - CongestionLevel congestionLevel; - DayOfWeek dayOfWeek = profileRequest.date.getDayOfWeek(); - if (dayOfWeek.equals(DayOfWeek.SUNDAY) || dayOfWeek.equals(DayOfWeek.SATURDAY)) - congestionLevel = CongestionLevel.OFF_PEAK; - else - congestionLevel = CongestionLevel.fromFromTime(profileRequest.fromTime); - - // TODO: this following line does not work, since timeCalculator implements a TraversalTimeCalculator - // and does not necessarily have a .congestionLevel - //timeCalculator.congestionLevel = congestionLevel; - // Set up goal direction. if (destinationSplit != null) { // This search has a destination, so enable A* goal direction. @@ -765,6 +753,8 @@ public State getState (Split split) { // Start on the forward edge of the pair that was split EdgeStore.Edge e = streetLayer.edgeStore.getCursor(split.edge); + CongestionLevel congestionLevel = CongestionLevel.fromProfileRequest(profileRequest); + TIntList edgeList; if (profileRequest.reverseSearch) { edgeList = streetLayer.outgoingEdges.get(split.vertex1); @@ -782,7 +772,7 @@ public State getState (Split split) { ret.streetMode = s.streetMode; // figure out the turn cost - int turnCost = this.timeCalculator.turnTimeSeconds(s.backEdge, split.edge, s.streetMode); + int turnCost = this.timeCalculator.turnTimeSeconds(s.backEdge, split.edge, s.streetMode, congestionLevel); int traversalCost = (int) Math.round(split.distance0_mm / 1000d / e.calculateSpeed(profileRequest, s.streetMode)); // TODO length of perpendicular @@ -811,7 +801,7 @@ public State getState (Split split) { } State ret = new State(-1, split.edge + 1, state); ret.streetMode = state.streetMode; - int turnCost = this.timeCalculator.turnTimeSeconds(state.backEdge, split.edge + 1, state.streetMode); + int turnCost = this.timeCalculator.turnTimeSeconds(state.backEdge, split.edge + 1, state.streetMode, congestionLevel); int traversalCost = (int) Math.round(split.distance1_mm / 1000d / e.calculateSpeed(profileRequest, state.streetMode)); ret.distance += split.distance1_mm; // TODO length of perpendicular diff --git a/src/main/java/com/conveyal/r5/streets/TraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/TraversalTimeCalculator.java index 8b06eb56a..89e3c3fe0 100644 --- a/src/main/java/com/conveyal/r5/streets/TraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/TraversalTimeCalculator.java @@ -39,7 +39,7 @@ public interface TraversalTimeCalculator extends Serializable { * * @return the expected value of the time in seconds to make the turn. */ - public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode); + public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode, CongestionLevel congestionLevel); } diff --git a/src/test/java/com/conveyal/r5/streets/TimeDependentRoutingTest.java b/src/test/java/com/conveyal/r5/streets/TimeDependentRoutingTest.java index 1c9020562..632cb2761 100644 --- a/src/test/java/com/conveyal/r5/streets/TimeDependentRoutingTest.java +++ b/src/test/java/com/conveyal/r5/streets/TimeDependentRoutingTest.java @@ -45,7 +45,7 @@ public int traversalTimeSeconds (EdgeStore.Edge currentEdge, StreetMode streetMo } @Override - public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode) { + public int turnTimeSeconds (int fromEdge, int toEdge, StreetMode streetMode, CongestionLevel congestionLevel) { return 0; } }; From 88357b5a4eabd0997730bf993f62ed4f81e62c2d Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 19:00:51 +0200 Subject: [PATCH 06/16] fixed test --- .../conveyal/r5/streets/BasicTraversalTimeCalculatorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/conveyal/r5/streets/BasicTraversalTimeCalculatorTest.java b/src/test/java/com/conveyal/r5/streets/BasicTraversalTimeCalculatorTest.java index bb6db493c..4d145904e 100644 --- a/src/test/java/com/conveyal/r5/streets/BasicTraversalTimeCalculatorTest.java +++ b/src/test/java/com/conveyal/r5/streets/BasicTraversalTimeCalculatorTest.java @@ -43,7 +43,7 @@ public void testAngleSouthernHemisphere() throws Exception { public void testCost () throws Exception { setUp(false); BasicTraversalTimeCalculator calculator = new BasicTraversalTimeCalculator(streetLayer, true); - assertEquals(calculator.LEFT_TURN, calculator.turnTimeSeconds(ee + 1, es, StreetMode.CAR)); + assertEquals(calculator.LEFT_TURN, calculator.turnTimeSeconds(ee + 1, es, StreetMode.CAR, CongestionLevel.OFF_PEAK)); } /** From 2f163bcc84e98f3346356581423535d88ad8feb4 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 19:12:55 +0200 Subject: [PATCH 07/16] shield against undefined date --- .../com/conveyal/r5/streets/CongestionLevel.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java index dacb3dd4c..f799b13c4 100644 --- a/src/main/java/com/conveyal/r5/streets/CongestionLevel.java +++ b/src/main/java/com/conveyal/r5/streets/CongestionLevel.java @@ -31,11 +31,14 @@ else if (secondsSinceMidnight < 64800) // 18:00 public static CongestionLevel fromProfileRequest(ProfileRequest profileRequest) { // set the congestion level (rush hour/off peak) depending on week day and time of day - DayOfWeek dayOfWeek = profileRequest.date.getDayOfWeek(); - if (dayOfWeek.equals(DayOfWeek.SUNDAY) || dayOfWeek.equals(DayOfWeek.SATURDAY)) - return CongestionLevel.OFF_PEAK; - else - return CongestionLevel.fromFromTime(profileRequest.fromTime); + if (profileRequest.date != null) { + DayOfWeek dayOfWeek = profileRequest.date.getDayOfWeek(); + if (dayOfWeek.equals(DayOfWeek.SUNDAY) || dayOfWeek.equals(DayOfWeek.SATURDAY)) + return CongestionLevel.OFF_PEAK; + else + return CongestionLevel.fromFromTime(profileRequest.fromTime); + } else + return CongestionLevel.AVERAGE; } } From b42c6de0131f32de2851bb7bc34f66eb720d97f7 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Thu, 2 Feb 2023 19:20:47 +0200 Subject: [PATCH 08/16] =?UTF-8?q?=F0=9F=98=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fee0a0898..a9432a1fd 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ publishing { repositories { maven { name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/conveyal/r5") + url = uri("https://maven.pkg.github.com/christophfink/dgl-r5") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") From 9eab1b11a28a60e81f5dca2e715946155dc79aff Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 15:31:14 +0200 Subject: [PATCH 09/16] =?UTF-8?q?am=20I=20allowed=20to=20push=20to=20DGL?= =?UTF-8?q?=E2=80=99s=20packages=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a9432a1fd..9851b4592 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ publishing { repositories { maven { name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/christophfink/dgl-r5") + url = uri("https://maven.pkg.github.com/DigitalGeographyLab/r5") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") From c763ec1faf32ebd34394e4517c0f3736a22b59c5 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 15:33:50 +0200 Subject: [PATCH 10/16] linted, moved package destination to my own fork --- .../com/conveyal/r5/streets/BasicTraversalTimeCalculator.java | 2 +- src/main/java/com/conveyal/r5/streets/StreetRouter.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java index dc5937aae..4ce00ea57 100644 --- a/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java +++ b/src/main/java/com/conveyal/r5/streets/BasicTraversalTimeCalculator.java @@ -28,7 +28,7 @@ public class BasicTraversalTimeCalculator implements TraversalTimeCalculator { public boolean driveOnRight; // TODO instead of a field, this should be a different implementation class public BasicTraversalTimeCalculator (StreetLayer layer, boolean driveOnRight) { - this.layer = layer; + this.layer = layer; this.driveOnRight = driveOnRight; } diff --git a/src/main/java/com/conveyal/r5/streets/StreetRouter.java b/src/main/java/com/conveyal/r5/streets/StreetRouter.java index e2b50e076..0c1bb5270 100644 --- a/src/main/java/com/conveyal/r5/streets/StreetRouter.java +++ b/src/main/java/com/conveyal/r5/streets/StreetRouter.java @@ -28,7 +28,6 @@ import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; -import java.time.DayOfWeek; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; From bda044b0bd1e9fca54e96e97d3a7cb9d824403bd Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 15:38:40 +0200 Subject: [PATCH 11/16] moved repo to fork --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9851b4592..a9432a1fd 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ publishing { repositories { maven { name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/DigitalGeographyLab/r5") + url = uri("https://maven.pkg.github.com/christophfink/dgl-r5") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") From ea242fce8d5c085860d842148df2cd4acef4eb0e Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 16:35:04 +0200 Subject: [PATCH 12/16] =?UTF-8?q?build=20package=20on=20pull=20request,=20?= =?UTF-8?q?publish=20to=20dgl=E2=80=99s=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 22691e6d1..bb60935d1 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -6,7 +6,7 @@ on: # The push event's ref reveals the branch name for S3 upload, unlike pull_request which sees the merge target. push # Try to catch PRs from outside authors, which don't need to be uploaded to S3. - # pull_request: + pull_request # branches: # - dev # - master diff --git a/build.gradle b/build.gradle index a9432a1fd..f259fdd37 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ publishing { repositories { maven { name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/christophfink/dgl-r5") + url = uri("https://maven.pkg.github.com/DigitalGeographyLab/dgl-r5") credentials { username = System.getenv("GITHUB_ACTOR") password = System.getenv("GITHUB_TOKEN") From 921e40d76b2cd8c04b623a32e35e57953514d3c0 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 16:36:08 +0200 Subject: [PATCH 13/16] =?UTF-8?q?build=20package=20on=20pull=20request,=20?= =?UTF-8?q?publish=20to=20dgl=E2=80=99s=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index bb60935d1..8676a0732 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -6,10 +6,11 @@ on: # The push event's ref reveals the branch name for S3 upload, unlike pull_request which sees the merge target. push # Try to catch PRs from outside authors, which don't need to be uploaded to S3. - pull_request + # pull_request: # branches: # - dev # - master + pull_request # added for DGL jobs: build: runs-on: ubuntu-latest From 74957247d02da64250467686178ac1d2c0e9bb96 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 16:37:04 +0200 Subject: [PATCH 14/16] =?UTF-8?q?build=20package=20on=20pull=20request,=20?= =?UTF-8?q?publish=20to=20dgl=E2=80=99s=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 8676a0732..c63a4b925 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -10,7 +10,9 @@ on: # branches: # - dev # - master - pull_request # added for DGL + pull_request: + branches: + - dev jobs: build: runs-on: ubuntu-latest From 34fc62c63fb16d6baf2157f31f0aedbb0f58ab5b Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 16:40:45 +0200 Subject: [PATCH 15/16] =?UTF-8?q?build=20package=20on=20pull=20request,=20?= =?UTF-8?q?publish=20to=20dgl=E2=80=99s=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index c63a4b925..94f78781b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -5,14 +5,12 @@ on: # Should catch merged pull requests, pushes to Conveyal PR branches, and tags. # The push event's ref reveals the branch name for S3 upload, unlike pull_request which sees the merge target. push + pull_request # Try to catch PRs from outside authors, which don't need to be uploaded to S3. # pull_request: # branches: # - dev # - master - pull_request: - branches: - - dev jobs: build: runs-on: ubuntu-latest From 101893b1d80b12af6a6b79df18de44c309d76061 Mon Sep 17 00:00:00 2001 From: Christoph Fink Date: Fri, 3 Feb 2023 16:54:36 +0200 Subject: [PATCH 16/16] =?UTF-8?q?build=20package=20on=20pull=20request,=20?= =?UTF-8?q?publish=20to=20dgl=E2=80=99s=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 94f78781b..3ef2b995f 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -4,8 +4,8 @@ name: Java CI on: # Should catch merged pull requests, pushes to Conveyal PR branches, and tags. # The push event's ref reveals the branch name for S3 upload, unlike pull_request which sees the merge target. - push - pull_request + push: + pull_request: # Try to catch PRs from outside authors, which don't need to be uploaded to S3. # pull_request: # branches: