Expand description
This crate provides the application runtime for the RouteE-Compass energy-aware routing engine. For more information, visit https://www.nrel.gov/transportation/route-energy-prediction-model.html.
This crate is part of a workspace and depends on two other crates from that workspace:
- routee-compass-core - core data structures and algorithms used by Compass
- routee-compass-powertrain - traversal model supporting energy-optimal route planning via RouteE Powertrain
This document provides an introduction to working with RouteE Compass by introducing the following concepts:
§Modules
§CompassApp
A CompassApp is a value containing the system configuration, the SearchApp, and the collection of InputPlugins and OutputPlugins instantiated by this configuration, each described below.
The following graphic shows generally the lifecycle for the primary objects of a Compass app.
–>
§SearchApp
The SearchApp is a value containing the various long-running assets that can create SearchInstance objects for each query. In some cases these are final models such as the Graph and MapModel instances. In other cases these are services such as the TraversalModelService which will build a TraversalModel instance based on the contents of the user search query. See routee-compass-core documentation for more information on the relationships between model and service types.
§InputPlugin
Input plugins pre-process the incoming user queries as JSON before submitting them to the SearchApp.
For more information, seecrate::plugin::input.
§OutputPlugin
Output plugins post-process the outgoing search results as JSON after submitting them to the SearchApp.
For more information, seecrate::plugin::output.
§Usage
§Building CompassApp instances
A RouteE Compass app exists as a value of type CompassApp on a given system.
An instance can be built using one of two try_from methods:
- from a path, which assumes the default CompassBuilderInventory
- from an instance of Config along with a (possibly customized) CompassBuilderInventory
Customizing a CompassBuilderInventory is the extension point for adding 3rd party extensions to CompassApp.
If this is not needed, then sticking to the default is sufficient, via the CompassApp::try_from(path) builder method.
§Running queries on CompassApp
With a running instance of CompassApp, one can repeatedly issue queries via the run method:
use serde_json::{Value, to_string_pretty};
use std::path::Path;
let config_path = Path::new("config.toml");
let queries: Vec<Value> = vec![]; // each value is a JSON query
let app = CompassApp::try_from(config_path).unwrap();
for query_file in query_files {
let responses: Vec<serde_json::Value> = app.run(queries).unwrap();
for res in responses {
let res_str = to_string_pretty(&res).unwrap();
println!(res_str);
}
}
§Resource Utilization
§CPU Usage
Based on the configured parallelism value, the batch of queries will be split into chunks run across the available system threads.
Keep in mind that each chunk needs enough RAM to conduct a (single) complete search over your road network.
For example, if a road network has 1 million links, and parallelism is 8, then (in the worst case) there should be sufficient RAM to store 8 million rows of search data at a time to avoid out-of-memory errors.
To manage resource utilization within each thread, use TerminationModel arguments ([termination] in the configuration TOML file).
§Memory Usage
Memory use of each query is reported in MiB by profiling the resulting search tree(s) by way of the Allocative crate. Memory requirements for the CompassApp at this time are not reported.
§Extending Compass
In order to add capabilities to Compass, you can choose from a number of trait objects to implement your solution. The way this is typically done is as follows:
- write custom models or input plugins
- create a CompassBuilderInventory object and inject your custom modules into it
- create your own run application (such as a
fn main) which uses your CompassBuilderInventory to create a CompassApp
§Custom Models
The traversal and constraint modules all contain Builder, Service, and Model traits that can be implemented. For each new type of model, you must implement the builder and service as well, such that
- your builder’s
buildmethod creates or reads all data related to your model that can be shared across all queries (see lifetime image, above) - your service’s
buildmethod can gather values from the incoming query that may further paramerize or override your service while producing a model for the incoming query - while your service is available for all queries, your model is available for exactly one
- your model and service should be thread-safe
For an example, review the implementation of the built-in models:
To understand how these each interact with the state model, review the documentation of the state module.
§Custom Plugins
Plugins have a simpler initialization process where the InputPluginBuilder and OutputPluginBuilder expose a build method to create the plugin.
For examples, review the implementation of the built-in plugins: