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

Isochrone Plugin #2189 #2477

Closed
wants to merge 63 commits into from
Closed

Isochrone Plugin #2189 #2477

wants to merge 63 commits into from

Conversation

roroettg
Copy link

I hope I am doing this right.

As requested in #2189 this pullrequest contains the isochrone plugin I am working on.

  • The plugin is optional and can be set with parameter -I or --isochrone
  • No additional data gets loaded then the plugin is not used

roroettg added 30 commits March 17, 2016 10:26
…nto develop

Conflicts:
	features/bicycle/range.feature
	include/engine/api/isochrone_api.hpp
	include/engine/api/isochrone_parameters.hpp
	include/engine/plugins/isochrone.hpp
	src/engine/engine.cpp
	src/engine/plugins/isochrone.cpp
@danpat
Copy link
Member

danpat commented Dec 4, 2016

I have a possible strategy that does not require loading the edge-based-graph into memory at all - while we can't explore the CH directly, we can re-create the parts of the edge-based-graph we need on-the-fly.

The recent work I did on the debug tile plugin to add turn penalty data involved the re-derivation of the edge-based graph within the tile being queried. This is possible by fetching all data in a geographic area, then re-connecting the dots. See this code.

The rough idea would be to come up with a reasonable "search tile" size (my gut says 5km x 5km would be good starting point). The rough algorithm would be:

  1. Fetch a "tile" of data around our isochrone start point.
  2. Construct the local edge-based-graph from that data
  3. Begin our isochrone search
  4. If we hit the edge of our tile without terminating, fetch the neighbor tile and extend our edge-based-mini-graph
  5. Continue the isochrone search, repeating (4) as necessary until the search ends.

Performance would be dictated by (a) the cost of the bbox RTree search to fetch tile data, and (b) the cost of re-constructing the local edge-based-graph from that tile. For the example ranges above by @roroettg , I suspect we could fetch all data in a single "tile".

@danpat
Copy link
Member

danpat commented Dec 4, 2016

Ok, I just had a go at this to see what kind of performance we'd get. It was relatively easy to copy the logic from the tile plugin to create the edge-based-graph we need.

100 second radius
screen shot 2016-12-04 at 1 32 55 am
200 second radius
screen shot 2016-12-04 at 1 32 35 am
300 second radius
screen shot 2016-12-04 at 1 32 42 am

A 400-second isochrone on the car profile is rendered in about 200ms, including the generation of 1.2MB of GeoJSON. Its not doing the tile loading, but it's loading a 0.2 degree x 0.2 degree box (about 10km x 10km in Münster).

@roroettg For your use-case, how large were you planning on allowing the isochrones? If I push my code up, do you think you could adapt your concave hull to it?

@Komzpa
Copy link
Contributor

Komzpa commented Dec 4, 2016

@danpat just in case, we need 30 minute car isochrones with RPS of 50k. It looks like to achieve that some caching is needed.

@danpat
Copy link
Member

danpat commented Dec 4, 2016

@Komzpa RPS == Requests Per Second, or https://xkcd.com/645/ ?

@danpat
Copy link
Member

danpat commented Dec 4, 2016

screen shot 2016-12-04 at 11 47 30 am

@Komzpa ^^ this is a 30 minute driving isochrone centered on the same point as the above examples.

On my laptop (with an i7 CPU), it takes about 6.3 seconds, broken down into:

  • Fetch a 2x2 degree bounding box from the RTree - 102.185ms
  • Create an initial lookup table of edges - 283ms
  • Constrct the edge-based-graph - 383ms
  • Perform the dijkstra search on the edge-based-graph - 4869ms
  • Geojson serialization - ~900ms

This approach is basically the worst case for isochrone generation - it employs no speedups at all.

I'm of the opinion that even a limited isochrone feature would be good to have - the demo server can easily restrict the allowed isochrone size to something that won't eat up all our CPU, and folks that want to do bigger ones can set up their own servers.

Additional memory use is 🙅 for the demo server, but I think limited isochrone sizes would be just fine.

@roroettg
Copy link
Author

roroettg commented Dec 5, 2016

@danpat Nice Work. For our use-case isochrones with the size of up to two hours for a bicycle profile would be perfect. With my current approach the memory is most of the time the limit when the isochrones get too big. On a different branch I separated the isochrone-service from the current routed-service to avoid having two graphs at runtime.

@danpat Yes, probably i can adapt my code.

@danpat
Copy link
Member

danpat commented Dec 5, 2016

Yeah, the memory problem....I think we just need to make the limit configurable at runtime - if the average travel speed is slow, then 2 hrs may not actually be all that big of a maximum radius.

I'll push my changes up to a separate branch here and you can take a look.

@danpat
Copy link
Member

danpat commented Dec 5, 2016

Pushed to here: https://github.com/Project-OSRM/osrm-backend/tree/ch_isochrone_poc

This doesn't implement the tiled approach, it simply fetches a bounding box of data using a maximum-possible-radius calculation (200km/h for cars). The nice thing about this is that it scales down quite well - small isochrones are quite fast.

My code is simply returning the geometry of all edges inside the isochrone boundary - there's no data on points for age, and the data is not tree-like in anyway.

That said, these geometry adaptations should be relatively straight forward. It could also probably get quite a bit faster with some work on cache locality.

I spent a bit of time over the weekend reading up on one-to-many speedup approaches - I think there are some options for future work. For now, I'd just like to get a workable plugin in, and get folks using it, then we can get feedback on what needs to work better.

One thing I'd be very interested in knowing: do folks care for exact isochrone trees, or are approximate bounding polygons more useful?

@Komzpa
Copy link
Contributor

Komzpa commented Dec 6, 2016

@danpat
Thanks for the benchmark! :)
We do care for exact isochrone trees. At very least, there are different travel times to left and right sides of the two-way streets, up to serveral minutes - we need to distinguish those.

@DrewRay
Copy link

DrewRay commented Jan 19, 2017

Happy New year, is this still blocked by merge issues? is it even a priority to keep working on?

@danpat
Copy link
Member

danpat commented Jan 19, 2017

@DrewRay as far as I know this isn't a priority for anyone, thus the lack of progress.

If you've got time and are willing to work on it, please feel free :-) For my branch a couple of comments back, the thing I got stalled on was making a reasonably compact JSON-like serialization of the isochrone tree data. GeoJSON doesn't really work for this.

@frodrigo
Copy link
Member

One thing I'd be very interested in knowing: do folks care for exact isochrone trees, or are approximate bounding polygons more useful?

On my side, each time I need isochrones it is for the hull, never for the tree.

@frodrigo
Copy link
Member

It would be nice to have the maxspeed as parameter.

@DrewRay
Copy link

DrewRay commented Jan 23, 2017 via email

@frodrigo
Copy link
Member

frodrigo commented Jan 24, 2017

I test this branch and got two issues:

public:
explicit IsochronePlugin(const std::string base);

Status HandleRequest(const std::shared_ptr<datafacade::BaseDataFacade> facade,
Copy link
Contributor

Choose a reason for hiding this comment

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

This can't compile datafacade::BaseDataFacade need to be const.

@fijemax
Copy link
Contributor

fijemax commented Feb 3, 2017

The ch_isochrone_poc branch doesn't work since last rebased on master branch.
The query blocks the osrm-routed, it can't stop correctly :

./build/osrm-routed ../pbf-data/map.osrm
[info] starting up engines, v5.5.0
[info] Threads: 8
[info] IP address: 0.0.0.0
[info] IP port: 5000
[info] http 1.1 compression handled by zlib version 1.2.8
[info] Listening on: 0.0.0.0:5000
[info] load names from: "../pbf-data/map.osrm.names"
[info] set checksum: 4022734474
[info] running and waiting for requests
^C[info] initiating shutdown
[info] stopping threads
[warn] Didn't exit within 2 seconds. Hard abort!
terminate called after throwing an instance of 'std::future_error'
what(): std::future_error: No associated state
Abandon (core dumped)

@danpat danpat mentioned this pull request Feb 4, 2017
7 tasks
@danpat
Copy link
Member

danpat commented Feb 4, 2017

@fijemax I've rebased and removed some WIP code from that branch, and opened a new PR at #3652. It's in a working state right now.

@mloskot
Copy link
Member

mloskot commented Aug 7, 2017

Is this proposal deprecated (to-be-closed) as superseded by #3652 or both are being developed as alternative approaches?

@TheMarex
Copy link
Member

TheMarex commented Sep 3, 2021

Super-seeded by #3652

@TheMarex TheMarex closed this Sep 3, 2021
@mloskot
Copy link
Member

mloskot commented Sep 3, 2021

@TheMarex Does keeping the #3652 open mean the isochrone project is being reactivated?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants