Skip to content
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

Chunnel Routing #3038

Merged
merged 8 commits into from
May 10, 2021
Merged

Chunnel Routing #3038

merged 8 commits into from
May 10, 2021

Conversation

kevinkreiser
Copy link
Member

@kevinkreiser kevinkreiser commented Apr 26, 2021

Every now and then the Chunnel stops routing properly...

Recently (2 months ago) I made a planet build and the chunnel isn't the suggested route when going from the UK to France even if you put the origin and destination right at the chunnel entry and exit. Instead the route goes way south first and crosses on a ferry to France and then drives up north again to get back to the chunnel exit.

@rzyc and I debugged this for a while and found out a couple of things. First we found that if we took an extract of the planet that has only the parts of the uk and france with the chunnel connections in them the route still fails first and then succeeds on the second pass in routing_action.cc

osmium extract -f pbf -o chunnel.pbf planet-latest.osm.pbf -b 1.0787,50.89,1.9803,51.1277

then we started commenting out the 3 different relaxation types in the second pass. first the not_through and the destination_only stuff. the route still succeeded on the second pass. then we commented out the hierarchy relaxation and it failed the route.

this made me think that it had to do with reclassification. but ive added a unit test here that proves the reclassification does work for the chunnels tagging (route = shuttle_train).

after looking at the ferry reclassification for a little bit it seems that indeed the chunnels surrounding edges are not getting reclassified. what happen is that this function https://github.com/valhalla/valhalla/blob/master/src/mjolnir/ferry_connections.cc#L209 seems to think the chunnel is too short to be worth reclassifying for. if i disable this, routing works as expected (although the reclassified path it takes is kind of crappy (has a uturn)).

@dnesbitt61 what was the purpose of not reclassifying near short ferries? were we assuming there must be alternate ways around without taking the ferries themselves? it looks to me like maybe the chunnel is connected to a bunch of little edges in the queueing area on the british side and that might be triggering the shortferry logic to stop us from connecting up the chunnel.

@gknisely have you been suffering with the chunnel at all lately?

@dnesbitt61
Copy link
Member

I think not reclassifying around short ferries was done to avoid some river ferries that had plenty of alternate paths. I think this was before any ferry penalties might have been in place.

@gknisely
Copy link
Member

@kevinkreiser checking on a status for you.

@SvetlanaBayarovich
Copy link
Contributor

SvetlanaBayarovich commented Apr 27, 2021

@kevinkreiser just curious about weights. If I use intermediate point to force ferry or chunnel I get chunnel route to be like 25% more expensive than the ferry one. Is it different for you? I'm checking regarding ferry connections reclassification now, but even if it's the case, difference in weight will still prevent us from getting adequate routes generally

@SvetlanaBayarovich
Copy link
Contributor

@kevinkreiser So I think there IS a problem with ferry connections. GB side pictures: current connection(s) with chunnel edges omitted, entering and exiting the chunnel. The ‘exiting’, is the only one that follows level 0 (red) edges. ‘Entering’ is a trash (and causes “search exhausted” stuff). To me it looks like the connection is built correctly only in one direction and not in reverse. Something similar happens on the France end as well.

Edges by level:
image
Entering the chunnel:
image
Exiting the chunnel:
image

@SvetlanaBayarovich
Copy link
Contributor

Also the France side:
Edges by level:
image
Entering:
image
Exiting:
image

@kevinkreiser
Copy link
Member Author

@SvetlanaBayarovich yep that is what we saw. we are pretty sure about the issue and actually @rzyc made a unit test to show why this is happening and the fix. i'll let him explain it, he should be pushing to this branch shortly

@rzyc
Copy link
Contributor

rzyc commented Apr 27, 2021

@SvetlanaBayarovich The issue was in the ShortFerry function in ferry_connections.cc as we originally suspected. According to the function's docstring, it is supposed to exclude ferries that are "just one edge and length < 2 km". However, the "just one edge" check was not actually performed and only the 2km check was. The Chunnel's entrance area consists of multiple short edges connected together, some of which are definitely < 2km. Therefore, ShortFerry thinks the Chunnel entrance edge is a short ferry and doesn't perform the reclassification around the entrance.

In this PR, I added the "just one edge" check by looping over all other connected edges (at both source and destination nodes) and seeing if any of them were also ferry edges. The function returns false immediately if it finds a connecting ferry edge. I also added a new unit test that checks for this issue, and made sure that this unit test was failing if we temporarily removed the "just one edge" check.

Comment on lines +235 to +246
// If we notice that either the end node or source node is a connection to another ferry edge,
// be cautious and assume this isn't a short edge.
for (const auto& edge2 : bundle.node_edges) {
if (edge2.first.llindex_ != edge.first.llindex_ && edge2.first.attributes.driveable_ferry) {
return false;
}
}
for (const auto& edge2 : bundle2.node_edges) {
if (edge2.first.llindex_ != edge.first.llindex_ && edge2.first.attributes.driveable_ferry) {
return false;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "just one edge" check. Looping over all other connected edges at both source and destination nodes. Sees if any of them were also ferry edges, with a check on the latlong index to make sure we're not looking at the original ferry edge. Return false immediately if we find one, since we know that means this ferry consists of more than one edge.

CHANGELOG.md Outdated Show resolved Hide resolved
ReclassifyFerryConnectionEdge(std::map<std::string, std::string> const& way_description) {
constexpr double gridsize_metres = 1000;

const std::string ascii_map = R"(
A--B--b--C----D--E
F--G--g--H----I--J
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a parallel test case ensuring that the behavior for rail ferries is the same as for ferries. The only difference in these two test cases is that HI is a rail ferry and CD is a ferry.

Comment on lines +55 to +59
const std::string ascii_map = R"(
A--B--C--F--D--E--G
|
N
)";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a test case here to cover the issue discovered. Both CF and FD are ferry edges, but they are both < 2km. This means that ShortFerry should return false since the ferry consists of > 1 edge. Thus, we should be reclassifying BC and DE and we check that in this unit test.

Also made sure that this unit test was failing if we temporarily removed this PR's changes to ShortFerry.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah the intuition here is we shouldnt assume the ferry is short just because it has 1 short edge in it. seems like somewhere along the chunnel another drivable edge intersects it and so makes the first edge short but then of course the whole rest of the chunnel is many km long. basically shortFerry was tricked. it still might be better to completely disable shortFerry, you can think of malicious cases where a short single edge ferry is the only way to get from one place to another but it likely doesnt happen in the wild that often (or maybe ever)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may never know when it appears)

}
}

// If the end node has a non-ferry edge check the length of the edge
if (bundle2.node.non_ferry_edge_) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code previously had this if statement here as the "just one edge" check, but it wasn't sufficient. If we consider this case (used in the unit test described below):

          A--B--C--F--D--E--G
                   |
                   N

where CF and FD are ferry edges and FN is not a ferry edge. Suppose that ShortFerry is analyzing CF and bundle2 is created at F. Then bundle2.node.non_ferry_edge_ will be true since FN exists.

Copy link
Contributor

@SvetlanaBayarovich SvetlanaBayarovich Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, guess it was working in most cases because not typical for a 'traditional' ferry to have a non-ferry edge somewhere in the middle
Disregard what i just said 😅

@SvetlanaBayarovich
Copy link
Contributor

SvetlanaBayarovich commented Apr 27, 2021

@rzyc Wow that was a tricky one! And such an interesting intersection of different circumstances to make it happen in the wild.

Copy link
Contributor

@SvetlanaBayarovich SvetlanaBayarovich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable to me

@kevinkreiser
Copy link
Member Author

We're going to do a round of RAD before we merge this to make sure no other unexpected changes occur.

@rzyc
Copy link
Contributor

rzyc commented May 7, 2021

Did a regression test with @kevinkreiser to check differences in routing before and after this PR. We did not notice any particularly drastic routing differences; most differences seem to be one-offs with just a couple slightly differing instructions ending up with similar cost values.

One interesting route change involving a ferry was this:

master branch:
image
After this fix:
image

Both routes have similar costs, but we noticed that after this fix with ferry reclassification, it elected to get on the ferry earlier in the route.

Since there aren't any drastic differences, we are looking to merge this PR on Monday.

@kevinkreiser
Copy link
Member Author

@mandeep, looks like macos builds "just work" again, im going to maek them required again

@kevinkreiser kevinkreiser merged commit a3e57b6 into master May 10, 2021
@mandeepsandhu
Copy link
Contributor

@mandeep, looks like macos builds "just work" again, im going to maek them required again

@kevinkreiser yeah. I got an email notification from circle saying they are updating all macos executors to use newer homebrew version. So looks like that did the trick. Glad its working without needing any change from us.

@kevinkreiser kevinkreiser deleted the chunnel_woes branch January 5, 2022 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants