Elevation provider inaccuracy

First of all, I’d like to deeply thank you for your project and efforts on keeping it an open source project. It’s amazing how great can the results be achieved :slight_smile:

I’m working on a hiking app and would like to pack the Graphhopper data for my offline maps. To start with, I’m setting up a local server so I can serve the results for the hike vehicle without having to pack the Graphhopper data (will do that later).

It’s going pretty good with this, since now I received the routing data and it’s almost as accurate as the one from your online API. To give some context related to my question, check this URL https://graphhopper.com/maps/?point=42.31575%2C2.482717&point=42.322636%2C2.51102&locale=en-GB&vehicle=hike&weighting=fastest&elevation=true&use_miles=false&layer=TF%20Outdoors

It has the vehicle hike set up, an origin and destination points, and the elevation tag set as true.

This I have tried to repeat on my local server, and the route that I receive is the same, except for the elevation data.

I have tried using CGIAR, SRTM, SRTMGL1 and MULTI providers, and so far, the one that gets closer to the online version of Graphhopper is SRTMGL1. But it’s still far from accurate.

In link provided above, I obtain the following results:

  • Lenght: 5.79km
  • Time: 1h 9min
  • Elevation gain: :arrow_upper_right:709m
  • Elevation loss: :arrow_lower_right:171m

However, on my local server using SRTMGL1, I obtain:

  • Lenght: 6.16km
  • Time: 1h 13min
  • Elevation gain: :arrow_upper_right:949m
  • Elevation loss: :arrow_lower_right:369m

With the other elevation providers (CGIAR, SRTM and MULTI) I get bigger data (longer length, time, elevation gain and elevation loss). So I assume SRTMGL1 is much more precise, and since the downloaded data are bigger, it makes sense.

So how could I achieve similar results (or even identical ones) than the online API Graphhopper ones? If the difference would be small, it would be OK for me, but I see that the difference is too big and doesn’t seem to be good enough.

Any help would be much appreciated.

P.S. If I use the online API, then I get identical elevation gain/loss and length. So the way I’m calculating the elevation gain/loss shouldn’t have anything to do with this. I’m basically assuming the first point has cumulated elevation gain/loss as 0, and then if the next value is bigger than the previous one, I add it to the cumulated elevation gain, if it’s lower, then I add it to the cumulated elevation loss.

First of all, I’d like to deeply thank you for your project and efforts on keeping it an open source project. It’s amazing how great can the results be achieved :slight_smile:

Thanks for your kind words!

Please share your configuration and version of GH that you are using.

Sure!

My Graphhopper version is 0.11 (just did git clone yesterday and I’m using the master branch), although I’ve tried with the stable 0.10 and get the same results (with a very similar config file).

I run the command app like this:

./graphhopper.sh -a web -i my_map.osm.pbf

This is my config.yml:

graphhopper:

  # OpenStreetMap input file
  # datareader.file: some.pbf

  ##### Vehicles #####


  # Possible options: car,foot,bike,bike2,mtb,racingbike,motorcycle (comma separated)
  # bike2 takes elevation data into account (like up-hill is slower than down-hill) and requires enabling graph.elevation.provider below
  graph.flag_encoders: hike


  # Enable turn restrictions for car or motorcycle.
  # graph.flag_encoders: car|turn_costs=true


  ##### Elevation #####


  # To populate your graph with elevation data use SRTM, default is noop (no elevation)
  graph.elevation.provider: srtmgl1


  # default location for cache is /tmp/srtm
  graph.elevation.cache_dir: ./srtmprovider/


  # If you have a slow disk or plenty of RAM change the default MMAP to:
  # graph.elevation.dataaccess: RAM_STORE



  #### Speed, hybrid and flexible mode ####


  # By default the speed mode with the 'fastest' weighting is used. Internally a graph preparation via
  # contraction hierarchies (CH) is done to speed routing up. This requires more RAM/disc space for holding the
  # graph but less for every request. You can also setup multiple weightings, by providing a comma separated list.
  prepare.ch.weightings: fastest


  # Disable the speed mode. Should be used only with routing.max_visited_nodes or when the hybrid mode is enabled instead
  # prepare.ch.weightings: no


  # To make CH preparation faster for multiple flagEncoders you can increase the default threads if you have enough RAM.
  # Change this setting only if you know what you are doing and if the default worked for you.
  # prepare.ch.threads: 1


  # The hybrid mode can be enabled with
  # prepare.lm.weightings: fastest

  # To tune the performance vs. memory usage for the hybrid mode use
  # prepare.lm.landmarks: 16

  # Make landmark preparation parallel if you have enough RAM. Change this only if you know what you are doing and if the default worked for you.
  # prepare.lm.threads: 1


  # avoid being stuck in a (oneway) subnetwork, see https://discuss.graphhopper.com/t/93
  prepare.min_network_size: 200
  prepare.min_one_way_network_size: 200



  ##### Routing #####


  # You can define the maximum visited nodes when routing. This may result in not found connections if there is no
  # connection between two points within the given visited nodes. The default is Integer.MAX_VALUE. Useful for flexibility mode
  # routing.max_visited_nodes: 1000000


  # If enabled, allows a user to run flexibility requests even if speed mode is enabled. Every request then has to include a hint routing.ch.disable=true.
  # Attention, non-CH route calculations take way more time and resources, compared to CH routing.
  # A possible attacker might exploit this to slow down your service. Only enable it if you need it and with routing.maxVisitedNodes
  # routing.ch.disabling_allowed: true


  # If enabled, allows a user to run flexible mode requests even if the hybrid mode is enabled. Every such request then has to include a hint routing.lm.disable=true.
  # routing.lm.disabling_allowed: true

  # Control how many active landmarks are picked per default, this can improve query performance
  # routing.lm.active_landmarks: 4


  # You can limit the max distance between two consecutive waypoints of flexible routing requests to be less or equal
  # the given distance in meter. Default is set to 1000km.
  routing.non_ch.max_waypoint_distance: 1000000


  ##### Storage #####


  # configure the memory access, use RAM_STORE for well equipped servers (default and recommended)
  graph.dataaccess: RAM_STORE


  # will write way names in the preferred language (language code as defined in ISO 639-1 or ISO 639-2):
  # datareader.preferred_language: en


  # Sort the graph after import to make requests roughly ~10% faster. Note that this requires significantly more RAM on import.
  # graph.do_sort: true



  ##### Spatial Rules #####
  # Spatial Rules require some configuration and only work with the DataFlagEncoder.


  # Spatial Rules require you to provide Polygons in which the rules are enforced
  # The line below contains the default location for these rules
  # spatial_rules.location: core/files/spatialrules/countries.geo.json

  # You can define the maximum BBox for which spatial rules are loaded.
  # You might want to do this if you are only importing a small area and don't need rules for other countries.
  # Having less rules, might result in a smaller graph. The line below contains the world-wide bounding box, uncomment and adapt to your need.
  # spatial_rules.max_bbox: -180,180,-90,90


# Uncomment the following to point /maps to the source directory in the filesystem instead of
# the Java resource path. Helpful for development of the web client.
# Assumes that the web module is the working directory.
#
# assets:
#  overrides:
#    /maps: web/src/main/resources/assets/

# Dropwizard server configuration
server:
  applicationConnectors:
  - type: http
    port: 8989
    # for security reasons bind to localhost
    bindHost: 192.168.0.11
  requestLog:
      appenders: []
  adminConnectors:
  - type: http
    port: 8990
    bindHost: 192.168.0.11

Can you try the multi provider and two other “smoothing” options? (See source code for multi here)

graphhopper:

  graph.elevation.provider: multi
  graph.elevation.calc_mean: true
  graph.elevation.smoothing: true

Wow! That worked like a charm :slight_smile: Exact data than I got in the online API tool. Thanks!

Now, one question related to the elevation data accuracy. Is using SRTMGL1 more accurate than the other options (except the MULTI provider, which loads the data from CGIARProvider and GMTEDProvider, and performs the smoothing)? If so, shouldn’t it be more accurate to use SRTMGL1 and CGIAR or GMTED in the MULTI provider?

What’s the elevation.calc_mean for? I’ve tried searching in the main graphhopper repository, but found no explanation in the code and cannot find anything about it.

Now, one question related to the elevation data accuracy. Is using SRTMGL1 more accurate than the other options (except the MULTI provider, which loads the data from CGIARProvider and GMTEDProvider, and performs the smoothing)? If so, shouldn’t it be more accurate to use SRTMGL1 and CGIAR or GMTED in the MULTI provider?

ping @boldtrn :wink:

What’s the elevation.calc_mean for? I’ve tried searching in the main graphhopper repository, but found no explanation in the code and cannot find anything about it.

See here:

Great, will wait for @boldtrn answer about using SRTMGL1 along with either CGIAR or GMTED.

Thank you again, you have been of tremendous help.

GMTED is definitely the most inaccurate provider, but it has world wide coverage. So the Multi provider uses either CGIAR or SRTMGL1 inside of the SRTM bounds and outside it uses GMTED.

CGIAR and SRTMGL1 are both based on the SRTM data. This data contains voids and incorrect measurements. Some good information can be found here.

CGIAR is based on the SRTM 3° data, which is not as accurate as SRTMGL1, but CGIAR used algorithms to improve the data, but the data is not as precise as the SRTMGL1 (1°). Both CGIAR and SRTMGL1 are void filled.

CGIAR is IIRC about 90*90m in resolution. SRTMGL1 is IIRC about 30*30m in resolution.

But it’s not that easy. SRTMGL1 still contains incorrect measurements. CGIAR has been improved with algorithms to fix incorrect measurements. So I think it’s valid to say that SRTMGL1 is more precise, but CGIAR contains less errors.

You should definitely use GMTED outside of the SRTM area. The question is if you should use SRTMGL1 or CGIAR inside of it. Since you reported better results with SRTMGL1, this might be the way to go.

Some more information on this can be found here as well:

2 Likes

Alright, I think I’ll stick with the MULTI provider as it is, since I doubt my tests were as deep as your work in this matter.

The explanation is more or less what I had been reading these days and makes lot of sense to use the CGIAR with the smoothing and calc_mean activated.

Thank you so much for the time taken in explaining the situation with this matter. I kindly appreciate it.

Hi!

In the past, I was using the multi elevation provider, however the URL for CGIAR seems to have changed to HTTPS, as I’ve read in this forum.

So I’ve tried using this config file for Graphhopper 0.13:

  graph.elevation.provider: multi
  graph.elevation.calc_mean: true
  graph.elevation.smoothing: true
  graph.elevation.base_url: https://srtm.csi.cgiar.org/wp-content/uploads/files/srtm_5x5/TIFF/;https://srtm.csi.cgiar.org/wp-content/uploads/files/srtm_5x5/TIFF/
  graph.elevation.cache_dir: srtmprovider/
  graph.elevation.dataaccess: RAM_STORE

However, and as you can observe, I was “forced” to introduce the same URL twice since I don’t know which one is the one for SRTMGL1. Could someone tell me the SRTMGL1 base URL please? Just in case I’m mixing things, I want to use the providers used in “multi” provider. I’m sure CGIAR is one of them, but don’t know if the other one was SRTMGL1 or GMTED…

Currently I’m mostly using Graphhopper for Spain and France. So perhaps I could be fine with CGIAR only and have the following config?

  graph.elevation.provider: cgiar
  graph.elevation.calc_mean: true
  graph.elevation.smoothing: true
  graph.elevation.base_url: https://srtm.csi.cgiar.org/wp-content/uploads/files/srtm_5x5/TIFF/
  graph.elevation.cache_dir: srtmprovider/
  graph.elevation.dataaccess: RAM_STORE

Thanks!

P.S. I know I should be using at least Graphhopper 1.0 (I’m using it with Android). But haven’t had the time to make the update yet :frowning: