-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Stop Time Interpolation #399
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code works well under a few test cases! I am not too familiar with Java, but we could probably make the error handling more robust in this function:
@@ -755,8 +755,9 @@ private int updateStopTimesForPatternStop(ObjectNode patternStop, int previousTr | |||
* | |||
* TODO? add param Set<String> serviceIdFilters service_id values to filter trips on | |||
*/ | |||
private int updateStopTimesForPatternStops(List<PatternStop> patternStops) throws SQLException { | |||
private int updateStopTimesForPatternStops(List<PatternStop> patternStops, boolean interpolateStopTimes) throws SQLException { | |||
PatternStop firstPatternStop = patternStops.iterator().next(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is best addressed by preventing the behaviour client side, although I'll defer to other reviewers if they'd like some additional checks
timepointNumber++; | ||
previousShapeDistTraveled = currentTimepoint.shape_dist_traveled; | ||
PatternStop nextTimePoint = timepoints.get(timepointNumber); | ||
timepointSpeed = (nextTimePoint.shape_dist_traveled - currentTimepoint.shape_dist_traveled) / nextTimePoint.default_travel_time; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check if default_travel_time
can't be zero before doing this division?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, yeah I'll add a case for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good enough for now, I'd either add a lot of tests and error cases or a comment that this could use a good refactor
int timepointNumber = 0; | ||
double timepointSpeed = 0; | ||
double previousShapeDistTraveled = 0; | ||
PatternStop currentTimepoint = patternStops.get(0); // First stop must be a timepoint |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a check here to verify that the item exists and is a timepoint
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, added in b585c9d
boolean isTimepoint = patternStop.timepoint == 1; | ||
// If we have reached a timepoint (which is not the last), we calculate the speed between it and the next timepoint. | ||
if (isTimepoint && interpolateStopTimes && timepointNumber < timepoints.size()-1){ | ||
timepointNumber++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include the ++
in the if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was gonna do this, but was worried it made the code less readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated this in b585c9d
if (isTimepoint && interpolateStopTimes && timepointNumber < timepoints.size()-1){ | ||
timepointNumber++; | ||
previousShapeDistTraveled = currentTimepoint.shape_dist_traveled; | ||
PatternStop nextTimePoint = timepoints.get(timepointNumber); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure this isn't null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in b585c9d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial feedback. If we can keep all updates to JdbcTableWriter in separate methods it might help with managing this class. I might also get you to merge this update into dev-flex!
@@ -788,10 +789,28 @@ private int updateStopTimesForPatternStops(List<PatternStop> patternStops) throw | |||
final BatchTracker stopTimesTracker = new BatchTracker("stop_times", updateStopTimeStatement); | |||
for (String tripId : timesForTripIds.keySet()) { | |||
// Initialize travel time with previous stop time value. | |||
int cumulativeTravelTime = timesForTripIds.get(tripId); | |||
int cumulativeTravelTime = timesForTripIds.get(tripId), timepointNumber = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Declare timepointNumber on a separate line e.g. int timepointNumber = 0;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 36f3043
@@ -788,10 +789,28 @@ private int updateStopTimesForPatternStops(List<PatternStop> patternStops) throw | |||
final BatchTracker stopTimesTracker = new BatchTracker("stop_times", updateStopTimeStatement); | |||
for (String tripId : timesForTripIds.keySet()) { | |||
// Initialize travel time with previous stop time value. | |||
int cumulativeTravelTime = timesForTripIds.get(tripId); | |||
int cumulativeTravelTime = timesForTripIds.get(tripId), timepointNumber = 0; | |||
double timepointSpeed = 0, previousShapeDistTraveled = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Declare previousShapeDistTraveled on a separate line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 36f3043
for (PatternStop patternStop : patternStops) { | ||
boolean isTimepoint = patternStop.timepoint == 1; | ||
// If we have reached a timepoint (which is not the last), we calculate the speed between it and the next timepoint. | ||
if (isTimepoint && interpolateStopTimes && timepointNumber++ < timepoints.size()-1){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of injecting the new code into this for loop, look to create a new interpolation method which will carry out the required tasks and return the updated travelTime value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to use a new method in 36f3043
PatternStop nextTimePoint = timepoints.get(timepointNumber); | ||
if (nextTimePoint == null) throw new IllegalStateException("Stop time interpolation is not possible with null timepoints."); | ||
timepointSpeed = nextTimePoint.default_travel_time == Entity.INT_MISSING ? 0 | ||
: (nextTimePoint.shape_dist_traveled - currentTimepoint.shape_dist_traveled) / nextTimePoint.default_travel_time; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit. Line up the ? and : makes this easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 36f3043
@Test | ||
public void canNormalizePatternStopTimes() throws IOException, SQLException, InvalidNamespaceException { | ||
// Store Table and Class values for use in test. | ||
private static String normalizeStopsForPattern(PatternStopDTO[] patternStops, int updatedStopSequence, boolean interpolateStopTimes, int initialTravelTime, int updatedTravelTime, int startTime, String patternId) throws SQLException, InvalidNamespaceException, IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reduce the length of this line by putting each param on a new line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 36f3043
src/test/java/com/conveyal/gtfs/loader/JDBCTableWriterTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is getting there, the method is much better. I just have some concerns over the impact of default values.
*/ | ||
public int normalizeStopTimesForPattern(int id, int beginWithSequence) throws SQLException { | ||
return normalizeStopTimesForPattern(id, beginWithSequence, false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit. New line after closing bracket.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in dbd09ce
@@ -745,6 +752,33 @@ private int updateStopTimesForPatternStop(ObjectNode patternStop, int previousTr | |||
return travelTime + dwellTime; | |||
} | |||
|
|||
private int interpolateTimesFromTimepoints( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method comment to describe what this is doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in dbd09ce
throw new IllegalStateException("All timepoints must have a default travel time specified."); | ||
} | ||
|
||
double timepointSpeed = (nextTimepoint.shape_dist_traveled - lastTimepoint.shape_dist_traveled) / nextTimepoint.default_travel_time; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If shape_dist_traveled
is not defined and set to Double.MIN_VALUE
, isn't that going to cause issues here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I added checks for every pattern stop and both timepoints in dbd09ce
// Gather travel/dwell time for pattern stop (being sure to check for missing values). | ||
int travelTime = patternStop.default_travel_time == Entity.INT_MISSING ? 0 : patternStop.default_travel_time; | ||
if (!isTimepoint && interpolateStopTimes) { | ||
// Override travel time if we're interpolating between timepoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit. Full stop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in dbd09ce
// Override travel time if we're interpolating between timepoints | ||
travelTime = interpolateTimesFromTimepoints(patternStop, timepoints, timepointNumber, previousShapeDistTraveled); | ||
} | ||
previousShapeDistTraveled += patternStop.shape_dist_traveled; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If any shape_dist_traveled
is set to Double.MIN_VALUE, will that cause an issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
likewise yes, I added a check here too dbd09ce
if (!isTimepoint && interpolateStopTimes) { | ||
// We don't want to increment the true cumulative travel time because that adjusts the timepoint | ||
// times later in the pattern. | ||
// TODO? We ignore dwell times in interpolation calculations right now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODOs have a habit of not being done. Can dwell times be incorporated easily now? If not, explain why they are ignored and remove the TODO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an explanation of why this is left out, and an explanation of how it could be implemented. Right now there's not much reason to since it doesn't fit the use case which is driving this feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Checklist
dev
before they can be merged tomaster
)Description
This PR supports interpolating stop times based on timepoints in the
normalizeStopTimesForPattern
method.