-
Notifications
You must be signed in to change notification settings - Fork 704
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
control default speed assignment via config #3055
Conversation
strange that the changelog CI passed... i didnt add a changelog entry yet... |
src/mjolnir/graphenhancer.cc
Outdated
const std::string& country_state_code) { | ||
|
||
// If we have config loaded we'll use that | ||
if (!tables.empty() && FromConfig(directededge, density, country_state_code)) | ||
return; |
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 highly recommend viewing this diff with whitespace hidden. if you dont do that it will look like i really modified a lot more than i did. what really happened here is i made this anonymous namespace function UpdateSpeed
into a member function of SpeedAssigner
other than indentation (and so also line wrapping) I didnt modify this function except to call the FromConfig
method to first see if the config-driven speed assignment should be used.
so if you run valhalla_build_tiles
as normal and don't pass it a speed config file in your regular valhalla json config, the code will hit this if
above which will immediately return false
and the rest of the unchange code in the UpdateSpeed
function will be run as it always was.
src/mjolnir/graphenhancer.cc
Outdated
uint32_t urban_rc_speed[] = { | ||
89, // 55 MPH - motorway | ||
73, // 45 MPH - trunk | ||
57, // 35 MPH - primary | ||
49, // 30 MPH - secondary | ||
40, // 25 MPH - tertiary | ||
35, // 22 MPH - unclassified | ||
30, // 20 MPH - residential | ||
20, // 13 MPH - service/other | ||
}; |
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 did make this change because i thought it was easier to read
src/mjolnir/graphenhancer.cc
Outdated
end_node_code = admin->country_iso(); | ||
if (!end_node_code.empty()) | ||
country_state_code += admin->state_iso(); |
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.
here i got a concatination of country and state codes for lookup in the config
@@ -1360,16 +1538,21 @@ void enhance(const boost::property_tree::ptree& pt, | |||
// Local Graphreader | |||
GraphReader reader(hierarchy_properties); | |||
|
|||
// Config driven speed assignment | |||
auto speeds_config = pt.get_optional<std::string>("default_speeds"); | |||
SpeedAssigner speed_assigner(speeds_config); |
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.
here we potentially parse the speed config
src/mjolnir/graphenhancer.cc
Outdated
speed_assigner.UpdateSpeed(directededge, density, urban_rc_speed, infer_turn_channels, | ||
country_state_code); |
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.
here we call the anonymous namespace struct to update the speed
src/mjolnir/graphenhancer.cc
Outdated
} else { | ||
speed = static_cast<uint32_t>((speed * kRampFactor) + 0.5f); | ||
struct SpeedAssigner { | ||
struct SpeedTable { |
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 object closely mirrors the json but is easier to use than a rapidjson object so we parse the json into it
src/mjolnir/graphenhancer.cc
Outdated
SpeedTable(cs["urban"]), | ||
SpeedTable(cs["rural"]), |
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.
at the moment we have only urban and rural speed tables per each geographic region (country/state combo)
src/mjolnir/graphenhancer.cc
Outdated
tables.clear(); | ||
} // something else was thrown | ||
catch (...) { | ||
LOG_WARN("Could not load default speeds from config"); | ||
tables.clear(); |
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 anything goes wrong when parsing the config its completely disabled
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.
maybe this should be parsed when the tile building starts even before the enhancer stage and fail the whole build?
src/mjolnir/graphenhancer.cc
Outdated
// Reduce speed on rough pavements. TODO - do we want to increase | ||
// more on worse surface types? | ||
if (directededge.surface() >= Surface::kPavedRough) { | ||
bool FromConfig(DirectedEdge& directededge, |
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 the main function that either uses a speed from config or aborts and relies on the previous method. anywhere where the method returns false
it is signalling that it couldnt assign a speed for this edge. ive commented the sections below to make it pretty clear. if its a kind of edge we know we cant find a speed for either becuase its a special edge that we dont handle or because the geography is not in the config then we abort immediately and rely on the conventional speed setting. once it gets past that point it figures out whether it needs rural or urban speeds. finally it picks which speed to assign.
ill add a javadoc to this function
src/mjolnir/graphenhancer.cc
Outdated
: static_cast<uint32_t>((speed * kRampFactor) + 0.5f); | ||
} else { | ||
speed = static_cast<uint32_t>((speed * kRampFactor) + 0.5f); | ||
struct SpeedAssigner { |
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.
anyone have opinions on moving this new class out into a private header?
@kevinkreiser what are the resulting RAD diffs with this PR |
@gknisely I wasn't planning on doing RAD for this but I can do a small area if you prefer. Please see my PR comments, especially this one: #3055 (comment) (i've updated the comment a bit for clarity) The new code is disabled completely and the old code is called as normal so long as you dont pass a speeds config file in your valhalla config json. |
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 small RAD testing looked good, then merge. Thanks.
@gknisely ill do a quick RAD and I want to flesh out another unit test to get more coverage of how it handles country/state specific logic |
@gknisely i ran RAD on 1k routes i generated from 3 corners of rhode island (providence, newport and westerly) there were 0 diffs. i'm going to add a more extensive unit test and then call it a day on this one. |
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
|
||
// If we have config loaded we'll use that | ||
if (!tables.empty() && FromConfig(directededge, density, country_code, state_code)) { | ||
directededge.set_speed_type(SpeedType::kClassified); |
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.
@rzyc i added this since you last reviewed realizing that it would be set improperly if the speed was a tagged speed
throw std::runtime_error("Duplicate country/state entry"); | ||
tables.emplace(std::move(code), std::array<SpeedTable, 3>{ | ||
SpeedTable(cs["rural"]), | ||
SpeedTable(cs["suburban"]), |
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.
we now support a 3rd delinieation of road density
@kevinkreiser just had a little time going over this nice addition! Looks really good, thanks for that. Do I read the code correctly, that, provided a valid JSON exists, the speed enhancer doesn't care whether the edge was tagged or not and updates its speed regardless, i.e. here: valhalla/src/mjolnir/speed_assigner.h Lines 257 to 260 in edf42ea
If so, why would you prefer to change the tagged speed to a default speed from the JSON? My assumption would be the tagged speed is (hopefully) closer to the ground truth than a country/state-wide default speed. |
Maybe it could/should be adjustable in the config by a boolean whether one wants to override tagged speeds with the JSON values? And if tagged speeds won't be overridden by default, how about preparing a default JSON following the "official" OSM recommendations with all values being the same for urban/suburban/rural? That also reminds me: IMO it should be possible to have missing keys or at least have some keys populated with |
I think not actually! The vast vast majority of tagged speeds are maxspeed tags. Speed limit is not a measured speed it is a suggested speed. I would agree that in areas with low traffic volumes most people either drive at or above the speed limit and in these scenarios it is a good proxy for actual travel speed. I suspect that by using a measured speed that in those areas where this is the case we'll probably not much change from what the tagged speed is. Where this will make a difference is in cities or areas with high road congestion (hopefully). I did a manual tuning and tested an area in philly and got much better times out of it. Basically places where the speed limit is aspirational 😄 However you question does resurface a thought that I was having and I think i commented somewhere. We could, instead of putting these values into Regarding the other questions about when and with what to override they are all good points. I'm trying to add this support iteratively meaning I wanted to get something working and merged and come back to do further enhancements and protections which you've listed. I think its ok to not have the perfect solution just yet because the whole thing is opt-in and by default its turned off so no one is being forced into this new code path.
|
makes sense:) That does hit close to being able to distinguish I'll help out a little on adding those things, starting with 1. which I can already see clients whining about 😅 |
This PR adds initial support for what was proposed in #3021 of note is the change in proposed file format. We'll document that over in the other repo where the code that generates this output can be found.
At the moment this PR is still in draft because the unit tests fail. I'm having trouble getting the enhancer to think the gurka map is dense enough to be considered as urban.