Skip to content

Latest commit

 

History

History
387 lines (313 loc) · 18.2 KB

profiles.md

File metadata and controls

387 lines (313 loc) · 18.2 KB

Profiles

Standard Profiles

When calculating routes with GraphHopper you can customize how different kinds of roads shall be prioritized. For example when travelling long distances with a car you typically want to use the highway to minimize your travelling time. However, if you are going by bike you certainly do not want to use the highway and rather take some shorter route, use designated bike lanes and so on.

GraphHopper includes the following pre-configured 'vehicles', that you can choose from depending on the type of vehicle you want to calculate routes for:

  • foot
  • hike
  • wheelchair
  • bike
  • racingbike
  • bike2
  • mtb
  • car
  • car4wd
  • motorcycle

By choosing a vehicle GraphHopper determines the accessibility and an average travel speed for the different road types. If you are interested in the low-level Java API note that these pre-configured vehicles correspond to implementations of the FlagEncoder interface.

Besides the vehicle it is also possible to use different weightings (=cost functions) for the route calculation. GraphHopper includes the following weightings:

  • fastest
  • shortest
  • short_fastest (yields a compromise between short and fast routes)
  • curvature (prefers routes with lots of curves for enjoyable motorcycle rides)
  • custom (see the next section)

The different travelling modes are called 'profiles'. When starting the GraphHopper server at least one such profile needs to be configured upfront, which is done in the 'profiles' section of config.yml. Here is an example:

profiles:
  - name: car
    vehicle: car
    weighting: fastest
  - name: some_other_profile
    vehicle: bike
    weighting: shortest

Every profile has to include a unique name that is used to select the profile when executing routing queries. The vehicle and weighting fields are also required and need to match one of the values listed above. To choose one of the profiles you need to use the profile parameter for your request, like /route?point=49.5,11.1&profile=car or /route?point=49.5,11.1&profile=some_other_profile in this example.

Speed and Hybrid Mode

GraphHopper can drastically improve the execution time of the route calculations by preprocessing the routing profiles during import. To enable this you need to list the profiles you want GraphHopper to do the preprocessing for like this:

# profiles you want to use with speed mode need to go here
profiles_ch:
  - profile: car
  - profile: some_other_profile

# profiles you want to use with hybrid mode need to go here
profiles_lm:
  - profile: car
  - profile: some_other_profile 

Note that 'CH' is short for 'Contraction Hierarchies', the underlying technique used to realize speed mode and 'LM' is short for 'Landmarks', which is the algorithm used for the hybrid mode.

For hybrid mode there is a special feature that allows 're-using' the prepared data for different profiles. You can do this like this:

profiles_lm:
  - profile: car
  - profile: some_other_profile
    preparation_profile: car

which means that for some_other_profile the preparation of the car profile will be used. However, this will only give correct routing results if some_other_profile yields larger or equal weights for all edges than the car profile. Better do not use this feature unless you know what you are doing.

Custom Profiles

Disclaimer: Custom profiles should still be considered a beta feature. Using them should be working, but details about the weight formula and the meaning of the different parameters is still subject to change. Also this feature will strongly benefit from community feedback, so do not hesitate with sharing your experience, custom models or problems you are running into!

You can take the customization of the routing profiles much further than just selecting one of the default vehicles and weightings, by using 'custom' profiles that let you adjust the cost function on a much more fine-grained level. Using a custom profile you can make adjustments to a 'base' vehicle. By choosing the base vehicle you inherit the road accessibilty rules and default speeds of this vehicle, but the custom weighting gives you the freedom to overwrite certain parts of the cost function depending on the different road properties.

Custom Weighting

The weight or 'cost' of travelling along an 'edge' (a road segment of the routing network) depends on the length of the road segment (the distance), the travelling speed, the 'priority' and the 'distance_influence' factor (see below). To be more precise, the cost function has the following form:

edge_weight = edge_distance / (speed * priority) + edge_distance * distance_influence

The edge_distance is calculated during the initial import of the road network and you cannot change it here. Note that the edge weights are proportional to this distance. What can be customized is the speed, the priority and the distance_influence, which we will discuss in a moment. First we need to have a look at the 'properties' of an edge:

Edge properties: Encoded Values

GraphHopper assigns values of different categories ('encoded values') to each road segment. For example for OSM data they are derived from the OSM way tags. The available categories are specified by using the graph.encoded_values field in config.yml and (unless you do further customization of GraphHopper) the possible categories are defined in DefaultEncodedValueFactory.java. For example there are the following categories (some of their possible values are given in brackets).

  • road_class: (other,motorway,trunk,primary,secondary,track,steps,cycleway,footway,...)
  • road_environment: (road,ferry,bridge,tunnel,...)
  • road_access: (destination,delivery,private,no,...)
  • surface: (paved,dirt,sand,gravel,...)

To find out about all the possible values of a category you can take a look at the corresponding Java files like RoadClass.java, query the /info endpoint of the server or use the auto-complete feature of the text box that opens when clicking the 'flex' icon in the web UI.

Besides these kind of categories, which can take multiple different string values, there are also some that represent a boolean value (they are either true or false for a given edge), like:

  • get_off_bike
  • road_class_link

And there are others that take on a numeric value, like:

  • max_weight
  • max_width

Important note: Whenever you want to use any of these categories for a custom profile you need to add them to graph.encoded_values in config.yml.

Setting up a Custom Model

As mentioned above, the custom weighting function has three parameters that you can adjust: speed, priority and distance_influence. You can set up rules that determine these parameters from the edge's properties. A set of such rules is called a 'custom model' and it is written in a dedicated YAML format. We will now see how the cost function parameters can be influenced by the different fields of such a custom model.

Customizing speed

For every edge a default speed is inherited from the base vehicle, but you have multiple options to adjust it. The first thing you can do is rescaling the default speeds using the speed_factor section. For example this is how you can reduce the the speed of every edge that has the value 'motorway' for the category 'road_class' to fifty percent of the default speed that is normally used by the base vehicle for this road class:

speed_factor:
  road_class: {motorway: 0.5}

Note that road_class: {motorway: 0.5} is an alternative YAML notation that is equivalent to:

speed_factor:
  road_class:
    motorway: 0.5

You can also setup speed factors for multiple road classes like this

speed_factor:
  road_class: {motorway: 0.5, primary: 0.7, tertiary: 0.9}

and use multiple categories to influence the speed factor

speed_factor:
  road_class: {motorway: 0.5}
  road_environment: {tunnel: 0.8}

If an edge matches multiple rules the speed factor values will be multiplied. For example, here the speed factor of a road segment that has road_class=motorway will be 0.5, the speed factor of a road segment that additionally has road_environment=tunnel will be 0.4 and the speed factor of a road segment that has road_class=secondary and road_environment=tunnel will be 0.8.

Instead of setting the speed factors for certain values you can instead set the speed factors for all other values using as special key ("*"), like this:

speed_factor: 
  road_class: {"*": 0.5}
  road_environment: {tunnel: 0.8, "*": 0.6}

So in this example we set a speed factor of 0.5 regardless of the road_class and all road_environment values yield a speed factor of 0.6 except tunnel which gets a speed factor of 0.8. And as mentioned above for edges that match multiple of these rules the different factors get multiplied.

For encoded values with boolean values, like get_off_bike you set the speed factor like this:

speed_factor:
  get_off_bike: {true: 0.6, false: 1.0}

which means that for edges with get_off_bike=true the speed factor will be 0.6 and otherwise it will be 1.0. You can skip any of these values to retain the default.

For encoded values with numeric values, like max_width you use the < and > operators, like this:

speed_factor:
  max_width: {"<2.5": 0.8}

which means that for all edges with max_width smaller than 2.5m the speed factor is 0.8.

In any case values of speed_factor have to be in the range [0,1] and it is not possible to increase the speed for edges of certain types.

Another way to change the speed is using the max_speed section, for example:

max_speed:
  surface: {gravel: 60}

implies that on all road segments with surface=gravel the speed will be at most 60km/h, regardless of the default speed of this edge or the adjustments made by the speed_factor section. Just like with speed_factor you can setup max_speed values for multiple category values and different categories. If multiple rules match for a given edge the most restrictive rule will determine the speed (the minimum max_speed will be applied). Values for max_speed must be in the range [0,max_vehicle_speed] where max_vehicle_speed is the maximum speed that is set for the base vehicle (which you cannot change).

You can also modify the speed for all edges in a certain area. To do this first add some areas to the areas section of the custom model and then use this name to set a speed_factor or max_speed for this area. In the following example we set the speed_factor of an area called my_area to 0.7. For max_speed it works the same way. All area names need to be prefixed with area_.

speed_factor:
  area_my_area: 0.7

max_speed:
  area_my_area: 50

areas:
  my_area:
    type: "Feature"
    geometry:
      type: "Polygon"
      coordinates: [
        [10.75, 46.65],
        [9.54, 45.65],
        [10.75, 44.65],
        [8.75, 44.65],
        [8.75, 45.65],
        [8.75, 46.65]
      ]

The areas are given in GeoJson format. Using the areas feature you can also block entire areas completely, but you should rather use the priority section for this (see below).

The last custom model field you can to customize the speed is the max_speed_fallback. By default this is set to the maximum speed of the base vehicle. It allows setting a global maximum for the speeds, so for example

max_speed_fallback: 50

means that the speed is at most 50km/h for any edge regardless of its properties.

Customizing priority

Looking at the custom cost function formula above might make you wonder what the difference between speed and priority is, because it enters the formula in the same way. When calculating the edge weights (which determine the optimal route) changing the speed in fact has the same effect as changing the priority. But do not forget that GraphHopper not only calculates the optimal route, but also the time (and distance) it takes to drive (or walk) this route. Changing the speeds also means changing the resulting travelling times, but priority allows you to alter the route calculation without changing the travelling time of a given route.

By default the priority is 1 for every edge, so without doing anything it does not affect the weight. However, changing the priority for certain kinds of roads yields a relative weight difference depending on the edges' properties.

You change the priority very much like you change the speed_factor, so

priority:
  road_class: {motorway: 0.5, secondary: 0.9}
  road_environment: {tunnel: 0.1}

means that road segments with road_class=motorway and road_environment=tunnel get priority 0.5*0.1=0.05 and those with road_class=secondary get priority 0.9 and so on.

Edges with lower priority values will be less likely part of the optimal route calculated by GraphHopper, higher values mean that these kind of road segments shall be preferred. To prefer certain roads you need to decrease the priority of others, which you can do using the special key "*", i.e.

priority: 
  road_class: {cycleway: 1.0, "*": 0.8}

means decreasing the priority for all road_classes except cycleways. priority values need to be in the range [0, 1]. Just like we saw for speed_factor and max_speed you can also adjust the priority for all edges in a certain area. It works the same way:

priority:
  area_my_area: 0.7 

To block an entire area completely set the priority value to 0. Some other useful encoded values to restrict access to certain roads depending on your vehicle dimensions are the following:

priority: 
  max_width: {"<2.5": 0}
  max_length: {"<10.0": 0}
  max_weight: {"<3.5": 0}

which means that the priority for all edges that allow a maximum vehicle width of 2.5m, a maximum vehicle length of 10m or a maximum vehicle weight of 3.5tons is zero (these edges are blocked).

Customizing distance_influence

distance_influence allows you to control the trade-off between a fast route (minimum time) and a short route (minimum distance). Setting it to 0 means that GraphHopper will return the fastest possible route, unless you set the priority of any edges to something different than 1.0. Using the priority factors will always to some part favor some routes because they are shorter as well. Higher values of distance_influence will prioritize routes that are fast (but maybe not fastest), but at the same time are short in distance.

You use it like this:

distance_influence: 100

The default is 70. More precisely, by specifying the distance_influence you tell the routing engine how much time you need to save on a detour (a longer distance route) such that you prefer taking the detour compared to a shorter distance route. Assuming that all priorities are 1 a value of zero means that no matter how little time you can save when doing a detour you will take it, i.e. you always prefer the fastest route. A value of 30 means that one extra kilometer must save you 30s of travelling time. Or to put it another way if a reference route takes 600s and is 10km long, distance_influence=30 means that you are willing to take an alternative route that is 11km long only if it takes no longer than 570s (saves 30s).

Setting up a Custom Profile

Custom profiles work very much the same way as the 'standard' profiles described at the beginning of this document. The custom model needs to be written in a separate YAML (or JSON) file and the weighting has to be set to custom. Use the custom_model_file field to point to the custom model file like this:

profiles:
  - name: my_custom_profile
    vehicle: car
    weighting: custom
    custom_model_file: path/to/my_custom_profile.yaml
  

Selecting a custom profile also works like selecting a standard profile. In our example just add profile=my_custom_profile to your routing request. To set up hybrid- or speed-mode, simply use the profiles_ch/lm sections and add the name of your custom profile (just like you do for standard profiles).

Changing the Custom Profile for a single routing request

With flex- and hybrid mode its even possible to define the custom model on a per-request basis and doing this you can even adjust a custom model configured on the server side for a single request. To do this you first set up a 'base' custom profile in your server configuration, like:

profiles:
  - name: my_flexible_car_profile
    vehicle: car
    weighting: custom
    custom_model_file: my_custom_model.yml

You do not necessarily need to define a proper custom model here and instead you can also set custom_model_file: empty (which means an empty custom model containing no rules will be used on the server-side). You then use the /route-custom (not /route) endpoint and send your custom model (using the format explained above, but as JSON) with the request body. The model you send will be merged with the profile you select using the profile parameter (which has to be a custom profile). For the Hybrid mode (not only "pure" Dijkstra or A*) the merge process has to ensure that all weights resulting from the merged custom model are equal or larger than those of the base profile that was used during the preparation process. This is necessary to maintain the optimality of the underlying routing algorithm. Therefore we use the following rules to merge the two models:

  • for priority: an existing factor is multiplied with the factor specified in the request
  • for speed_factor: an existing factor is multiplied with the factor specified in the request
  • for max_speed: an existing speed value is replaced if it is higher than the speed value specified in the request. If it is smaller an exception is thrown.
  • Comparisons like max_weight: { "<3.5": 0 } are special cases. The merge will be only accepted if the factor in the query is 0. And the range can be only "expanded", which means:
    • The 'smaller than' comparison key (like in this example the <3.5) can only be replaced by bigger comparison keys like <4.5.
    • The 'greater than' comparison key (e.g. >2) can only be replaced by smaller comparison keys like >1.9.