Graphopper using chConfig

I’m having some difficulty to use a chConfig when using an existing graph;
I have it working using a random graph (code below) but I cannot do the same with my graph that has already been created.

When ever I try to load my existing graph it says that: There is no CH graph ‘x’, existing: []

Is there something extra I need to do to the graph?

graphHopper = new GraphHopperOSM()
                .setGraphHopperLocation(locationGraphHopperFiles)
                .setEncodingManager(encodingManager) 
                .setDataReaderFile(locationRoutingFile)
                .setElevation(true).setAllowWrites(true)
                .setMemoryMapped()
                .setElevationProvider(new CGIARProvider(System.getProperty("user.home")+File.separator+"srtm"+File.separator))
                
                .setProfiles(Arrays.asList(
                    new Profile("foot").setVehicle("foot").setWeighting("fastest"),
                    new Profile("car").setVehicle("car").setWeighting("fastest"),
                    new Profile("rural").setVehicle("motorcycle").setWeighting("fastest").setTurnCosts(true).putHint("u_turn_costs", 3),
                    new CustomProfile("paxster").setCustomModel(model).setVehicle("foot").setWeighting("custom")
                    ))  

                .forDesktop();

            graphHopper.importOrLoad();

Here is the working example with a random graph.

public static void main(String[] args) {

        dir = new RAMDirectory();
        int maxTurnCosts = 10;

        encoder = new CarFlagEncoder(5, 5, maxTurnCosts);
        encodingManager = EncodingManager.create(encoder);
        graph = new GraphBuilder(encodingManager).setDir(dir).withTurnCosts(true).build();
        turnCostStorage = graph.getTurnCostStorage();
        weighting = new FastestWeighting(encoder, new DefaultTurnCostProvider(encoder, turnCostStorage, uTurnCosts));
        chConfig = CHConfig.edgeBased("x", weighting);
        
        graph.addCHGraph(chConfig);
        graph.create(1000);
        
        final long seed = System.nanoTime();
        final int numQueries = 10000;
        Random rnd = new Random(seed);
        GHUtility.buildRandomGraph(graph, rnd, 100, 2.2, true, true, encoder.getAverageSpeedEnc(), 0.7, 0.8, 0.8);
        GHUtility.addRandomTurnCosts(graph, seed, encodingManager, encoder, maxTurnCosts, turnCostStorage);

        preProcessGraph(graph);

        long startNano = System.currentTimeMillis();
        for (int i = 0; i < numQueries; i++) {
            int source = getRandom(rnd, graph);
            int target = getRandom(rnd, graph);
            int sourceOutEdge = getSourceOutEdge(rnd, source, graph);
            int targetInEdge = getTargetInEdge(rnd, target, graph);

            Path path = createAlgo()
                    .calcPath(source, target, sourceOutEdge, targetInEdge);
            
            System.out.println(path.getDistance());
        }
        long endNano = System.currentTimeMillis();
        System.out.println("Done in "+(endNano - startNano)/ 1000+" seconds");
    }
    
    private static BidirRoutingAlgorithm createAlgo() {
        CHRoutingAlgorithmFactory algoFactory = new CHRoutingAlgorithmFactory(routingCHGraph);
        return algoFactory.createAlgo(new PMap().putObject(ALGORITHM, DIJKSTRA_BI));
    }
    
    private static int getTargetInEdge(Random rnd, int node, Graph graph) {
        return getAdjEdge(rnd, node, graph);
    }

    private static int getSourceOutEdge(Random rnd, int node, Graph graph) {
        return getAdjEdge(rnd, node, graph);
    }
    
    private static int getAdjEdge(Random rnd, int node, Graph graph) {
        // sometimes do not restrict anything
        if (rnd.nextDouble() < 0.05) {
            return ANY_EDGE;
        }
        // sometimes use NO_EDGE
        if (rnd.nextDouble() < 0.05) {
            return NO_EDGE;
        }
        // use all edge explorer, sometimes we will find an edge we can restrict sometimes we do not
        EdgeExplorer explorer = graph.createEdgeExplorer();
        EdgeIterator iter = explorer.setBaseNode(node);
        List<Integer> edgeIds = new ArrayList<>();
        while (iter.next()) {
            edgeIds.add(iter.getOrigEdgeFirst());
            edgeIds.add(iter.getOrigEdgeLast());
        }
        return edgeIds.isEmpty() ? ANY_EDGE : edgeIds.get(rnd.nextInt(edgeIds.size()));
    }
  
    
    private static int getRandom(Random rnd, GraphHopperStorage graph) {
        return rnd.nextInt(graph.getNodes());
    }
    
    private static void preProcessGraph(GraphHopperStorage graph) {
        graph.freeze();
        if (!prepareCH) {
            return;
        }
        if (prepareCH) {
            PrepareContractionHierarchies pch = PrepareContractionHierarchies.fromGraphHopperStorage(graph, chConfig);
            pch.doWork();
            routingCHGraph = graph.getRoutingCHGraph(chConfig.getName());
        }

    }
   
}

Your two examples are a bit different: The first uses the GraphHopper class while the second is a bit more low level. To use CH with the GraphHopper graph you need to enable CH like this: hopper.getCHPreparationHandler().setCHProfiles(...). Have a look at the javadocs for GraphHopper#setProfiles for more details.

Thanks Easbar,

It’s now working but there is a large difference between process times for the random graph and using a graph that already exists.
Using randomly generated graph produces 1 million relations in about 30 seconds.
Using actual existing graph takes about 1 second per 1,000 relations.
Is it simply because the actual graph is more complex? Or is there something that I’m missing?

public static void testGraph() {

        GHPoint[] points = createLargePointSet();
        
        em = EncodingManager.create(FlagEncoderFactory.FOOT + "|block_private=false," + FlagEncoderFactory.CAR + "," + FlagEncoderFactory.MOTORCYCLE + "|turn_costs=true");
        carEncoder = em.getEncoder("car");
        defaultWeighting = new ShortestWeighting(carEncoder);
        
        CHConfig chConfig = CHConfig.nodeBased("car", defaultWeighting);

        GraphHopperStorage graph = createStorage(em, chConfig);
        graph.loadExisting();
        
        LocationIndexTree index = new LocationIndexTree(graph, graph.getDirectory());
        index.prepareIndex();
        
        // Error : Given CHGraph has been contracted already
        //PrepareContractionHierarchies pch = PrepareContractionHierarchies.fromGraphHopperStorage(graph, chConfig);
        //pch.doWork();
        
        graph.freeze();
        
        long startNano = System.currentTimeMillis();

        for (int i = 0; i < points.length-1; i++) {
            for(int y = 0; y < points.length-1; y++){
                Snap fromSnap = index.findClosest(points[i].getLat(), points[i].getLon(), EdgeFilter.ALL_EDGES);
                Snap toSnap = index.findClosest(points[y].getLat(), points[y].getLon(), EdgeFilter.ALL_EDGES);

                Path path = createAlgo(graph).calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
            }
            System.out.println("Done with point "+i);
        }
        long endNano = System.currentTimeMillis();
        System.out.println("Done in "+(endNano - startNano)/ 1000+" seconds");
    }
    
    private static BidirRoutingAlgorithm createAlgo(GraphHopperStorage graph) {
        RoutingCHGraph routingCHGraph = graph.getRoutingCHGraph("car");
        CHRoutingAlgorithmFactory algoFactory = new CHRoutingAlgorithmFactory(routingCHGraph);
        return algoFactory.createAlgo(new PMap().putObject(ALGORITHM, DIJKSTRA_BI));
    }

    private static GraphHopperStorage createStorage(EncodingManager em, CHConfig chConfig) {
        GraphHopperStorage ghStorage = new GraphBuilder(em).setRAM("C:\\Program Files\\ETL Data Load Processes\\nz_latest_gh\\", true).set3D(true).setCHConfigs(chConfig).build();
        return ghStorage;
    }

Also the link down the bottom of https://github.com/graphhopper/graphhopper/blob/master/docs/core/low-level-api.md
Links to 404 page not found

Edit
It seems just using the Snap fromSnap and Snap toSnap is what takes the time.
How do you find the fromID and toID without using LocationIndex where you only have the GPS location?

1ms/request sounds reasonable to me. How large is your map (how many nodes)? The random graph in your example has only 100 nodes.

Yes I just fixed this.

What do you mean? This literally is the purpose of LocationIndex.

553,053 nodes.

It is faster if I store all node indexes separately.

List<Integer> nodeIndexes = new ArrayList<Integer>();

        for (int i = 0; i < points.length; i++) {
            Snap fromSnap = index.findClosest(points[i].getLat(), points[i].getLon(), EdgeFilter.ALL_EDGES);
            nodeIndexes.add(fromSnap.getClosestNode());
        }
        for(int i=0; i<nodeIndexes.size(); i++){
            for(int y=0; y<nodeIndexes.size(); y++){
                BidirRoutingAlgorithm algo = createAlgo(graph);
                Path path = algo.calcPath(nodeIndexes.get(i), nodeIndexes.get(y));
            }
        }

For 896 points this takes 144 seconds. So this will give me every nodes path to every other node.
And splitting the task into 4 threads takes 64 seconds (on a old laptop)
totalPaths = 802816

In your opinion is this about right?

Powered by Discourse