routee-compass 0.19.3

The RouteE-Compass energy-aware routing engine
Documentation
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](https://www.nrel.gov/transportation/route-energy-prediction-model.html).

This crate is part of a [workspace](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) 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](https://github.com/nrel/routee-powertrain)

This document provides an introduction to working with RouteE Compass by introducing the following concepts:

  1. [Modules](#modules)
      - [CompassApp](#compassapp)
      - [SearchApp](#searchapp)
      - [InputPlugin](#inputplugin)
      - [OutputPlugin](#outputplugin)
  2. [Usage](#usage)
      - [Building CompassApp instances](#building-compassapp-instances)
      - [Running queries on CompassApp](#running-queries-on-compassapp)
  3. [Resource Utilization](#resource-utilization)
  4. [Extending Compass](#extending-compass)
      - [Custom Models](#custom-models)
      - [Custom Plugins](#custom-plugins)

## Modules

### CompassApp

A [CompassApp] is a value containing the system configuration, the [SearchApp], and the collection of [InputPlugin]s and [OutputPlugin]s instantiated by this configuration, each described below. 

The following graphic shows generally the lifecycle for the primary objects of a Compass app.

<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAyAAAAHCCAIAAACYATqfAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAAA8AAAAAQAAADwAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAyCgAwAEAAAAAQAAAcIAAAAABjiIfgAAAAlwSFlzAAAJOgAACToB8GSSSgAAQABJREFUeAHt3Xd8VFXCxnETWiAgLRIBIz2AgEgAAUFAEBsgIEXRBRVwVdzXj+uuBV1FZVddWFxFRWVxVTooKCKLdEKv0nsHpShFhGAoJu8j1707zEyGTOZOcssvf8Q7Z84995zvGTMP555MYjIzMy/jCwEEEEAAAQQQQMA6gVjrmqIlBBBAAAEEEEAAgV8FCFi8DhBAAAEEEEAAAYsFCFgWg9IcAggggAACCCBAwOI1gAACCCCAAAIIWCxAwLIYlOYQQAABBBBAAAECFq8BBBBAAAEEEEDAYgEClsWgNIcAAggggAACCBCweA0ggAACCCCAAAIWCxCwLAalOQQQQAABBBBAgIDFawABBBBAAAEEELBYgIBlMSjNIYAAAggggAACBCxeAwgggAACCCCAgMUCBCyLQWkOAQQQQAABBBAgYPEaQAABBBBAAAEELBYgYFkMSnMIIIAAAggggAABi9cAAggggAACCCBgsQABy2JQmkMAAQQQQAABBAhYvAYQQAABBBBAAAGLBQhYFoPSHAIIIIAAAgggQMDiNYAAAggggAACCFgsQMCyGJTmEEAAAQQQQAABAhavAQQQQAABBBBAwGIBApbFoDSHAAIIIIAAAggQsHgNIIAAAggggAACFgsQsCwGpTkEEEAAAQQQQICAxWsAAQQQQAABBBCwWICAZTEozSGAAAIIIIAAAgQsXgMIIIAAAggggIDFAgQsi0FpDgEEEEAAAQQQIGDxGkAAAQQQQAABBCwWIGBZDEpzCCCAAAIIIIAAAYvXAAIIIIAAAgggYLEAActiUJpDAAEEEEAAAQQIWLwGEEAAAQQQQAABiwUIWBaD0hwCCCCAAAIIIEDA4jWAAAIIIIAAAghYLEDAshiU5hBAAAEEEEAAAQIWrwEEEEAAAQQQQMBiAQKWxaA0hwACCCCAAAIIELB4DSCAAAIIIIAAAhYLELAsBqU5BBBAAAEEEECAgMVrAAEEEEAAAQQQsFiAgGUxKM0hgAACCCCAAAIELF4DCCCAAAIIIICAxQIELItBaQ4BBBBAAAEEECBg8RpAAAEEEEAAAQQsFiBgWQxKcwgggAACCCCAAAGL1wACCCCAAAIIIGCxAAHLYlCaQwABBBBAAAEECFi8BhBAAAEEEEAAAYsFCFgWg9IcAggggAACCCBAwOI1gAACCCCAAAIIWCxAwLIYlOYQQAABBBBAAAECFq8BBBBAAAEEEEDAYgEClsWgNIcAAggggAACCBCweA0ggAACCCCAAAIWCxCwLAalOQQQQAABBBBAgIDFawABBBBAAAEEELBYgIBlMSjNIYAAAggggAACBCxeAwgggAACCCCAgMUCBCyLQWkOAQQQQAABBBAgYPEaQAABBBBAAAEELBYgYFkMSnMIIIAAAggggAABi9cAAggggAACCCBgsQABy2JQmkMAAQQQQAABBAhYvAYQQAABBBBAAAGLBQhYFoPSHAIIIIAAAgggQMDiNYAAAggggAACCFgsQMCyGJTmEEAAAQQQQAABAhavAQQQQAABBBBAwGIBApbFoDSHAAJRFTh/4Suql4hq45mZmVFt36/xn3/++eTJk36FznpolZhV7ThLj97moQABKw/xXXVpvevpR3noIWWnTugWnPKsd36Uv/jiiyNHjrzkvBw6dOj9998PUW3OnDm9evUKUcF46p///GeZMmWGDRt2yZq2rdCiRYv9+/dfsnvz58+XSYhqkh8xYkSICnpq3LhxN910U6NGjR577LHQNe38bDbFhg8f/u2334YYiNrZt29fiAo8hYC1AgQsaz2929onn3zSr1+/0OMPrNO/f//Qp+T+s5f8MR2iS4oIc+fOVYVsviWEaMpBT507d27BggWHDx82+6yoLQezRBUUF8aMGbNy5crvv//erKbjmTNnmtVUvnv37kWLFoWIp4ULF+7Ro4fZgkMPTpw4MXv27PT0dLP/fmLHjh2bOnXqlClTJOb775ZNmzaJ+tSpU+aJqqBC86HfwT333LN06dINGzaotV27dvk966CHgWJHjhyRoYmzd+9epcl58+atWbPGHJdeSAsXLly9erVegUbhmTNn9Mr0fRGalY0D/Uvg6NGjoVX9TuEhAlkJELCykqE8DIH169fXrVv3z3/+s3FOWlranj17/N4s/eqopn7uf/jhh/pZtnPnzjAuZmlVvbtPmzZt48aNRqtBf0z7/Sjfvn277rn4/ZjeunWr8VPbDAd+bwkarBbwdBXhbNu2zdJB5HFjr7zyymeffdasWTO9i6srmvr7779/xowZ119//apVq1Ty008/KStodUErLlu2bDG6+/vf/75bt256j5wwYYJRorD17LPPqrUXXnjBKAn8/sgjj5QsWTKw3Fklffr0+fTTT+vUqWMsZQWK6RWyfPly/a8hsR9//FGj00uuefPm+gfJpEmTlixZYoz31Vdf/eijjzp37jxr1qwQArGxv/6cL1SoUIg6Nn/KT2zy5Ml6qeh79erVjfCkBK/Vqa+++mr8+PHGWARYv359xfqhQ4f+8MMPRuEDDzzw5ZdfXnvttVndNlXlpk2bZkfV5mJ0zxYCej/gC4EIBfSm2KZNG70vGu3oXfOqq67S2+ctt9zy/PPPG4V+dVSoexzFixf/v//7Py0aRdiBnJ3+7rvvNmnSRB176aWXjBb0flatWrW7775bP76Nki+++KJ3797qZFJS0tmzZ1V444033nDDDU888URiYqKig0pee+21evXqqU758uU1dqOO7ss8/PDDVatW1c99ldx1110KGTrQTa6nn35aB+740qS//fbbGovS1b333msOSlYvv/zygAEDjJLNmze3b9/efHbHjh2KX+ZDHcitU6dOOlBNJQnfp/yOFTI0cX6FDnqo14/+saEOP/XUU7rXafbcT+y9994bPHiw+az+KaL65kMdSP6tt97SgWrqfyXfp/yONTW33367X6GDHmYlpn+r6MeOlvSMseh/WwV6c1xa6dTAzYc6UDtr167VgWrq9qvvU+Zx9lXNUzhAICuB/LZIeXTC4QL6qaRoondNcxwNGzbUPyW1XKGQYRQG1tEbsP59OWTIEPOsXD7QwpWCkfJTuXLljEsbP5QVgFJSUoySDhe+Tp8+rbEsW7ZM6zQq11ua/hF88OBBrTFoj4veJr/55psSJUqoxByCUmPt2rXV1Ndff/3QQw/pn84abLt27fRdVmY1FxxcfvnlGoWipPECOHDggBjz5cun2zFKokEHqBs3eoX4PSVAlShzK2r4PeWyhzkQU4xo27atn4MpppVXv6fMh7rnpfj1+eefmyVOPPATS01N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FizQ96xKzNY4QAABBBCwswD7sew8O5fsGwHrkkRZVsjIyNi9e/edd96pGrpJly9fPh0MHz785ptvfuuttxo3bqw8tG3btvr16z/77LMNGzZ85plnXnnlFdXp3bt3u3btJkyYUKdOHSUzlUyePFl19L169epGeFJu69Sp08qVK83wpMWqevXqzZ8/f8yYMenp6TpLX5MmTfrwww8///xz46HOatSo0aefftqsWTOFMxUGlhg1+Y4AAgggYH8BMpb95yirHhKwspK5dLkWopSx/OopWk2fPn3UqFENGjT4+uuv9ayi1aBBgypWrPj3v/9decuorxz2wQcfdOjQwaijA5W8/vrrNWrU0P0+1dHCleKUolj//v2NU3bs2FG2bNkuXboMGTKkWLFiKtywYYOSlhHIFL+Man/+859V4c0331QOy6rEKOc7AggggID9BcyMxee823+yfHtIwPLVCO+4dOnSW7duNReTdLKWrI4dO6YtWTrW6pTWn3Sgze+FChUqXLiwvpuB7PLLL9dTycnJRuRKTU1VDuvevfu+ffvUiJ567bXXEhMTb7rppm7dup0/f14lilY9evTo27evgtf+/ftVosWtypUra++X0pu50OXXsqoFlqiQLwQQQAABpwgoY6UdPVT+ykSndJh+SoCAlfOXgYKUFpx0p09NnD17Vrus4uPjK1WqtH79ev1m34wZM9q0aZNV62vXrtVTc+bM0b08HfzjH/944YUXxo8fX6pUKeODM5SKXnzxxc2bN2uZasuWLaqju5B9+vTR/irdBNTNRJVMnDjx/fff103AYcOG6Vgl+jJa1lYto+WgJRcq8g0BBBBAwBkCZ7csrVe9yp4FU53RXXp5QSA/DpEI6L5e586dBw4cqPTz17/+VXf6XnrpJd3X05qTbhE2b95cCSlo+7pd2K9fv2uuuaZVq1aq0LVr1yeeeKJIkSJlypQ5evSoSnRXUXcP1ex1111Xs2ZNlWiVS/u0lMBOnTql+4bG0le1atX0lFKd1smM7fBz587VpWNjY0eMGKGn9BVYYpTzHQEEEEDA/gJKV7WTEvlALPvPlF8P+ZgGP5CcPPzhhx+uuOIK3zO1mmVsk/ItNI8VvLRJS2tUJUqUMAtPnDhRtGhRY6e8UajfK9SSmO4tmnV091C/eKiMZZb4HWjRq2rVqh07dtTVFc70bGCJ3ykeecjHNHhkohkmAi4TIF05d0JZwbJg7vzSlVoMka6M6yn9+KYrFRYvXtyvK8ZeLt9C5S19+ZYEHqtlY9OV+VRgifmUpw7OnzjiqfEyWAQQcJxAbKEi2m5ldpt0ZVI48YAVrDyYNW111y28aFw48FPdA0uicV37t6kVLP5Ujv2niR4i4GUB/amcgmWS4pNTDATSldNfDAQsp88g/UcAAQQQcIPAK0OGDZqcavwtQtKVC2Y0KusoLnBhCAgggAACCOSJAOkqT9gtvygBy3JSGkQAAQQQQCCHAqSrHMLZ7zQClv3mhB4hgAACCHhSIH3fVj6RwTUzT8ByzVQyEAQQQAABBwvs/e6Aes/nXTl4Ci/uOpvcL/bgEQIIIIAAAnkhkLpsVYtG9fPiylwzKgIErKiw0igCCCCAAAIIeFmAW4Renn3GjgACCCCAAAJRESBgRYWVRhFAAAEEEEDAywIELC/PPmNHAAEEEEAAgagIELCiwkqjCCCAAAIIIOBlAQKWl2efsSOAAAIIIIBAVAQIWFFhpVEEEEAAAQQQ8LIAAcvLs8/YEUAAAQQQQCAqAgSsqLDSKAIIIIAAAgh4WYCA5eXZZ+wIIIAAAgggEBUBAlZUWGkUAQQQQAABBLwsQMDy8uwzdgQQQAABBBCIigABKyqsNIoAAggggAACXhYgYHl59t0zdv0VevcMhpEggAACCDhfgIDl/DlkBJddNmLSlALVGiCBAAIIIICATQQIWDaZCLphgUCzbr0saIUmEEAAAQQQiFiAgBUxIQ3YQKBC+XIFyyRtO5JGxrLBbNAFBBBAAIHLCFi8CFwiEBtXJCOxMhnLJdPJMBBAAAGHCxCwHD6BdN9HgIzlg8EhAggggEBeCsRkZmbm5fW5tqsFtPG8bu1rcmGIazdsiru6euGra+haGemnYw/vSk6IXzjh37lwaS6BAAIIIIBAoIC9Atbp06dPnjyZmJgY2FFKTIEffvjhiiuuMB/a+UABq1idprnQQ4Wq/MUTtIJlXIuMlQvmXAIBBBBAIISAXQKWFtIeeuihzz//vEKFCqVLl545c2aITkfpqQ4dOpw7d+4///mP5e0PHz78tttuu+qqqyJvuWHDhiVLluzevfuDDz4YeWvRbkEBq2SzDtG+StD2yVhBWShEAAEEEMgdAbvswVq7du2uC1/ffPONb8RZsWLFjz/+aFjs3Llz//79qnDkyJGNGzeqMC0tbc+ePRs2bDAemmQ7duxYtGhRRkaGWbJ169avv/7622+/zapEK2erV69WO+bl1Ox33323cOFC85TAEj2lPmzbts2sE1iyd+/ecePGzZs3b82aNUY1naKxqnzu3Lk///yzUp3Z/0OHDh08eNC3NfP4+++//+KLL3755ZdXX321ffv2Rvn69evVYeVRmRglak191nfjofqssetaW7ZsOXz4sNma6w/Yj+X6KWaACCCAgJ0F7LKC9cYbb5QoUaJXr14mllJIq1atkpOTFT4ee+yx3r17d+7cWXfHFBeaNGmyePFihYYlS5Z07dpVK0/KGe3atevfv79OHzBgwIkTJxS8lEW0JKaSu+++OyYmpmbNmlWqVPnd734XtGTs2LGKO/nz52/cuHHPnj0VzooUKXLzzTcXLFhQrc2ePTuwxOiqLvHuu+/OmjXLeKjvfiUjR45Ul1JSUipVqvTaa6+pwrJly3r06KHxJiUl6SmNsXLlyopfpUqV6tix48MPP3z77bebrZkHusSHH364fPnytm3b3nPPPTfccIOeSkhIqF69esWKFe+444777rtv5cqVWtnSEJYuXfrxxx/Xr1+/TJkyWvRSfr322ms1EOVOs8FcOMjDFSxjdKxj5cIscwkEEEAAgUABuwSse++9V/lJX2YXP/300/nz57/99tsKVa1bt163bp2effLJJ//2t7+9+OKLylLKZFqSGTp06GefffbTTz/VrVt39+7d5unHjh2rUaOGVoPy5ctXq1atP/3pT4pixYoVMyoElnTp0uW6665TwFJomzx5suJUuXLltOKlEgUULUEpHvmVKK6Zlwt9oDz09NNPK2MZ1RSwlKL0vVChQkaJuqecpB4qEm3fvl19DtqgQthLL72kdSzzWWUyLekpYBklSqJKpYKSSWpqqvR0X1JZUz0/cOCAqvmu4ZmNRO8gzwOWhmZkrCLnTu1ZMDV6I6VlBBBAAAEEfAXscotQQUGrLL49W7VqVe3atVWiDd1Hjx7V/ncdx8XFKZQULlxY35WBVHL55Zcb38+fP69FLx0rVTRo0ODRRx89e/asClWiRKLWtII1cOBAPQwsUeO6raYIsm/fPuUe3S5UHa1gKV3pQCtMxk3AwJJf28rRl8Kfma7UwAMPPDB69GilIi22ZZWugl6nePHiZrpSBROtTp06Ws1SiYag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" alt="CompassApp Object Lifecycles" width="800" height="450"> -->

##### 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, see[`crate::plugin::input`].

##### OutputPlugin

Output plugins post-process the outgoing search results as JSON after submitting them to the [SearchApp]. 
For more information, see[`crate::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:
  1. from a path, which assumes the default [CompassBuilderInventory]
  2. from an instance of [Config](https://docs.rs/config/latest/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:

```ignore
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](https://crates.io/crates/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:
  1. write custom models or input plugins
  2. create a [CompassBuilderInventory] object and inject your custom modules into it
  3. 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 `build` method creates or reads all data related to your model that can be shared across all queries (see lifetime image, above)
  - your service's `build` method 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](https://en.wikipedia.org/wiki/Thread_safety)

For an example, review the implementation of the built-in models:
  - [`routee_compass_core::model::traversal::default`]
  - [`routee_compass_core::model::constraint::default`]

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:
  - [`crate::plugin::input::default`]
  - [`crate::plugin::output::default`]

[CompassApp]: crate::app::compass::CompassApp
[SearchApp]: crate::app::search::SearchApp
[SearchInstance]: routee_compass_core::algorithm::search::SearchInstance
[CompassBuilderInventory]: crate::app::compass::CompassBuilderInventory

[traversal]: routee_compass_core::model::traversal
[constraint]: routee_compass_core::model::constraint
[state]:routee_compass_core::model::state

[TraversalModelBuilder]: routee_compass_core::model::traversal::TraversalModelBuilder
[TraversalModelService]: routee_compass_core::model::traversal::TraversalModelService
[TraversalModel]: routee_compass_core::model::traversal::TraversalModel

[ConstraintModelBuilder]: routee_compass_core::model::constraint::ConstraintModelBuilder

[TerminationModel]: routee_compass_core::model::termination::TerminationModel

[InputPluginBuilder]: crate::plugin::input::InputPluginBuilder
[InputPlugin]: crate::plugin::input::InputPlugin
[OutputPluginBuilder]: crate::plugin::output::OutputPluginBuilder
[OutputPlugin]: crate::plugin::output::OutputPlugin

[routee-compass-core]: routee_compass_core
[routee-compass-powertrain]: routee_compass_powertrain
[routee-compass]: self
[Graph]: routee_compass_core::model::network::Graph
[MapModel]: routee_compass_core::model::map::MapModel