Python API Docs

Contents

Python API Docs#

routee.powertrain.io.load.list_available_models(registry: ModelRegistry | None = None, version_strategy: Literal['latest', 'all'] = 'latest') List[ModelId][source]#

Returns a list of model identifiers available in the registry.

This is a lightweight operation that returns only the model paths without fetching any metadata or binaries.

If no registry is provided, the default registry is used.

Parameters:
  • registry -- a ModelRegistry instance; defaults to get_default_registry()

  • version_strategy -- "latest" (default) returns only the highest version per (make, model, year, config_slug) group; "all" returns every versioned identifier.

Returns: list of ModelId matching the strategy

routee.powertrain.io.load.load_model(name_or_path: str | Path | ModelId, registry: ModelRegistry | None = None) Model[source]#

Load a pretrained model.

Supports two loading modes:

  1. File path — pass a Path or string pointing to a model directory (containing metadata.json), .zip archive, or .tar.gz archive on disk.

  2. Registry ModelId — pass a ModelId object or model id path to fetch from a registry (uses the default registry if none is provided). String paths may omit the v<N> segment to load the latest version.

Parameters:
  • name_or_path -- file/directory path or ModelId

  • registry -- optional ModelRegistry for remote loading

Returns: a routee-powertrain Model

Examples:

>>> import routee.powertrain as pt
>>>
>>> # load from a directory
>>> model = pt.load_model("path/to/my_model/")
>>>
>>> # load from a zip
>>> model = pt.load_model("MyModel.zip")
>>>
>>> # load via registry
>>> from routee.powertrain.registry import ModelId
>>> mid = ModelId("toyota", "camry", 2016, "rf_default", 1)
>>> model = pt.load_model(mid)
>>>
>>> # explicit version
>>> model = pt.load_model("toyota/camry/2016/rf_default/v1")
>>>
>>> # latest version (no version segment)
>>> model = pt.load_model("toyota/camry/2016/rf_default")
routee.powertrain.io.load.load_sample_route(name: str | None = None) DataFrame[source]#

A helper function to load sample routes

Parameters:

name -- The name of the route. Defaults to "sample_route".

Returns: a pandas DataFrame representing the route

routee.powertrain.io.load.query_available_models(make: str | None = None, model: str | None = None, year: int | None = None, config_slug: str | None = None, feature_names: Sequence[str] | None = None, powertrain_type: str | None = None, fuel_type: str | None = None, drivetrain: str | None = None, engine: str | None = None, trim: str | None = None, version: int | None = None, model_digest: str | None = None, version_strategy: Literal['latest', 'all'] = 'latest', custom_filters: Sequence[Callable[[ModelInfo], bool]] | None = None, registry: ModelRegistry | None = None, fuzzy: bool = True, fuzzy_threshold: int = 80) List[ModelInfo][source]#

Query available pretrained models from the registry with optional filters.

Returns full metadata and error metrics for each matching model. If no registry is provided, the default registry is used.

Parameters:
  • make -- filter by vehicle make

  • model -- filter by vehicle model — matches the bare metadata model name (e.g. "camry") or the derived vehicle_slug (e.g. "camry_ice")

  • year -- filter by model year

  • config_slug -- filter by config slug (e.g. "rf_default", "cnn_5link")

  • feature_names -- filter to models whose feature set contains every listed feature column (subset match, exact names)

  • powertrain_type -- filter by powertrain type (e.g. "ICE", "BEV", "HEV")

  • fuel_type -- filter by fuel type (e.g. "GASOLINE", "DIESEL", "ELECTRICITY")

  • drivetrain -- filter by drivetrain (e.g. "FWD", "RWD", "AWD")

  • engine -- filter by engine specification (e.g. "4cyl", "2.0tdi")

  • trim -- filter by trim level (e.g. "sport", "active")

  • version -- pin results to an exact version (e.g. 2). When set, version_strategy is ignored.

  • model_digest -- pin results to an exact instance identity — the model_digest from a model's metadata.json (with or without the sha256: prefix; always matched exactly). Use this to resolve a model file in hand back to its registry entry. When set, version_strategy is ignored.

  • version_strategy -- how to collapse multiple versions of the same model. "latest" (default) keeps only the highest version per (make, model, year, config_slug) group; "all" returns every version. Ignored when version is specified.

  • custom_filters -- optional list of callables that accept a ModelInfo and return True to keep the model or False to exclude it. For example: [lambda m: m.mass_lbs is not None and m.mass_lbs > 10000]

  • registry -- a ModelRegistry instance; defaults to get_default_registry()

  • fuzzy -- if True, use fuzzy string matching for string fields (default True)

  • fuzzy_threshold -- minimum score (0–100) for a fuzzy match (default 80)

Returns: list of ModelInfo with full metadata and error metrics

class routee.powertrain.core.model.Model(estimator: Estimator, metadata: Metadata)[source]#

A RouteE-Powertrain vehicle model represents a single vehicle (i.e. a 2016 Toyota Camry with a 1.5 L gasoline engine).

contour(x_feature: str, y_feature: str, n_samples: int | None = 100, output_path: str | None = None)[source]#

generates a contour plot of the two test features: x_feature and y_feature.

Parameters:
  • x_feature -- one of the features used to generate the energy matrix and will be the x-axis feature

  • y_feature -- one of the features used to generate the energy matrix and will be the y-axis feature

  • n_samples -- the number of samples used to generate the plots

  • output_path -- an optional path to save the plots as png files.

property digest: str | None#

This model's registry-independent instance identity.

The sha256:<hex> content digest minted at train time (see routee.powertrain.core.digest). Unlike key, which groups all retrains of the same configuration, the digest is unique per trained artifact — two models trained the same day on different data get distinct digests. None for legacy models saved before digests existed.

classmethod from_file(file: str | Path)[source]#

Load a vehicle model from a file or directory.

Supports directories (containing metadata.json + binary), .zip archives, and .tar.gz archives.

Parameters:

file -- the path to the file or directory to load

Returns: a powertrain vehicle

property key: ModelKey#

This model's intrinsic, version-less identity.

Derived from metadata (make/model/year + the derived config_slug), so it is always available — even for a freshly-trained model that has never been placed in a registry. The registry version is not part of this; it is assigned only by registry operations (save_to_registry returns a full ModelId).

predict(links_df: DataFrame) DataFrame[source]#

Predict absolute energy consumption for each link

Parameters:

links_df -- a dataframe containing the links to predict on. Must contain every column in self.feature_set plus the distance column, and (if the estimator's input_spec declares a grouping column) that grouping column.

Returns: a dataframe containing the predicted energy consumption for each link

save_to_registry(registry_root: str | Path, config_slug: str | None = None, version: int | None = None, schema_version: str = 'v2', overwrite: bool = False)[source]#

Save this model into a local registry directory tree.

Builds the canonical <registry_root>/<schema_version>/<make>/<model>/<year>/<config_slug>/v<N>/ layout from self.metadata.config. The config_slug is derived from metadata unless overridden, and version defaults to the next unused version. See routee.powertrain.io.archive.save_to_registry for full details.

Returns: the ModelId that was written.

to_file(file: str | Path)[source]#

Save a vehicle model to a file or directory.

If file has no suffix, saves as a flat directory. If it ends with .zip, saves as a ZIP archive. If it ends with .tar.gz, saves as a tar archive.

Parameters:

file -- the path to save to

to_lookup_table(feature_parameters: list[dict], energy_target: str) DataFrame[source]#

Convert the the model to a lookup table for the given feature parameters.

visualize_features(n_samples: int | None = 100, output_path: str | None = None, return_predictions: bool | None = False) Dict[str, 'Series'] | None[source]#

generates test links to independently test the model's features and creates plots of those predictions

Parameters:
  • n_samples -- the number of samples used to generate the plots

  • output_path -- an optional path to save the plots as png files.

  • return_predictions -- if true, returns the dictionary containing the prediction values

Returns: optionally returns a dictionary containing the predictions where the key is the feature tested

class routee.powertrain.core.model_config.Contract(*, feature_set: ~routee.powertrain.core.features.FeatureSet, distance: ~routee.powertrain.core.features.DataColumn, target: ~routee.powertrain.core.features.TargetSet, predict_method: ~routee.powertrain.core.predict_method.Annotated[~routee.powertrain.core.predict_method.PredictMethod, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_predict_method, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)] = PredictMethod.RATE, real_world_adjustment_factor: float = 1.0)[source]#

A model's input/output contract — everything needed to interpret a prediction: the feature columns it consumes, the distance column, the energy target(s) it emits, how the raw estimator output maps to energy (predict_method), and the real-world correction applied afterward.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

real_world_adjustment_factor: float#

Multiplicative factor applied to predicted energy to correct for real-world conditions. Resolved on the source ModelConfig (defaulting from the powertrain type) and stored concretely here.

class routee.powertrain.core.model_config.FastSimSource(*, method: ~typing.Literal[TrainingMethod.FASTSIM_SIMULATION] = TrainingMethod.FASTSIM_SIMULATION, fastsim_vehicle_id: str | None = None, fastsim_vehicles_ref: str | None = None, fastsim_version: str | None = None, pipeline_version: str | None = None, pipeline_run_id: str | None = None, pipeline_repo_ref: str | None = None, dataset_run_ids: ~typing.List[str] = <factory>, data_sources: ~typing.List[str] = <factory>, notes: str | None = None)[source]#

Training data produced by simulating a FASTSim vehicle.

The standard path: a model pipeline runs drive cycles through FASTSim and trains on the resulting energy traces. Recording the vehicle, the simulator version, and the pipeline that drove them is what makes a published model reproducible.

The pipeline keeps its own provenance database, so this records keys, not copies. pipeline_run_id and dataset_run_ids resolve there to the full configuration each run used — dataset filters, estimator settings, trip caps, the sampling seed, the identity of the assembled training frame, and everything else that would have to match to recreate the model. None of that is duplicated here: a copy drifts from the source of truth and can't be verified against it, while a key can't drift.

What remains alongside the keys describes what was simulated rather than how the training data was assembled — the vehicle, the simulator version, the pipeline version. Those are cheap, stable, and readable at a glance.

This assumes the provenance database is reachable whenever a model needs to be reproduced. That is a deliberate trade, and a cheap one to revisit: provenance is excluded from model_digest, so a field added here later is non-breaking and can even be backfilled onto already-published models without changing their identity.

data_sources: List[str]#

Dataset sources the training data was drawn from (e.g. ["wm1"]). Usually one, but a run can be configured to sample across several (e.g. ["wm1", "wm2"]).

fastsim_vehicle_id: str | None#

//github.com/NatLabRockies/fastsim-vehicles (e.g. "v1/fastsim-3/conv/toyota/camry-4cyl-2wd/2016/base/r1").

Type:

Vehicle identifier in https

fastsim_vehicles_ref: str | None#

Git tag / commit sha pinning the fastsim-vehicles repo the vehicle definition was read from.

fastsim_version: str | None#

Version of the FASTSim package that ran the simulation.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

pipeline_repo_ref: str | None#

Git commit sha of the pipeline repo at run time.

pipeline_version: str | None#

Version of the model pipeline that orchestrated simulation and training.

class routee.powertrain.core.model_config.LegacySource(*, method: Literal[TrainingMethod.LEGACY] = TrainingMethod.LEGACY, original_source: str | None = None, converted_from: str | None = None, dataset_name: str | None = None, dataset_hash: str | None = None, notes: str | None = None)[source]#

Provenance for models that predate this section.

Converted v1 archives record no simulator, pipeline, or dataset information — the honest answer is "we don't know", and this variant says so explicitly rather than leaving the source null.

converted_from: str | None#

The format it was converted from (e.g. "v1").

dataset_hash: str | None#

Fingerprint of that data — see routee.powertrain.hash_dataframe.

dataset_name: str | None#

Human-readable identifier of the training data, when the pre-conversion format happened to record one.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

original_source: str | None#

Where the model came from before conversion (e.g. a library name).

class routee.powertrain.core.model_config.ModelConfig(*, vehicle_description: str, powertrain_type: ~routee.powertrain.core.powertrain_type.Annotated[~routee.powertrain.core.powertrain_type.PowertrainType, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_powertrain, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)], feature_set: ~routee.powertrain.core.features.FeatureSet, distance: ~routee.powertrain.core.features.DataColumn, target: ~routee.powertrain.core.features.TargetSet, make: str, model: str, year: ~typing.Annotated[int | tuple[int, int], ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.year.parse_year, json_schema_input_type=PydanticUndefined)], variant: str | None = None, predict_method: ~routee.powertrain.core.predict_method.Annotated[~routee.powertrain.core.predict_method.PredictMethod, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_predict_method, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)] = PredictMethod.RATE, test_size: float | None = None, validation_size: float | None = None, random_seed: int = 42, trip_column: str = 'trip_id', training_source: ~typing.Annotated[~routee.powertrain.core.provenance.FastSimSource | ~routee.powertrain.core.provenance.RealWorldSource | ~routee.powertrain.core.provenance.LegacySource, FieldInfo(annotation=NoneType, required=True, discriminator='method')] | None = None, real_world_adjustment_factor: float = 1.0, mass_lbs: float | None = None, fuel_type: ~routee.powertrain.core.fuel_type.Annotated[~routee.powertrain.core.fuel_type.FuelType, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_fuel_type, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)] | None = None, drivetrain: ~routee.powertrain.core.drivetrain.Annotated[~routee.powertrain.core.drivetrain.Drivetrain, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_drivetrain, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)] | None = None, engine: str | None = None, trim: str | None = None)[source]#
property all_feature_names: List[str]#

Returns the list of feature names, including distance if predict method is RAW.

property all_features: List[DataColumn]#

Returns the list of features, including distance if predict method is RAW.

property feature_names: List[str]#

Returns the list of feature names from the feature set.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

real_world_adjustment_factor: float#

Multiplicative factor applied to predicted energy to correct for real-world conditions (e.g. temperature). Defaults to the powertrain-type factor in ADJUSTMENT_FACTORS; set to 1.0 to apply no adjustment.

training_source: TrainingSource | None#

What produced the training data — a FastSimSource, RealWorldSource, or LegacySource. Carries the dataset labels (dataset_name / dataset_hash) alongside the source-specific fields. Stored in the persisted provenance section; descriptive, so it does not feed the model digest.

variant: str | None#

Short label distinguishing configs that share the same architecture and feature set (e.g. "steady" vs "warmup" thermal regimes). Feeds the derived config_slug; leave None when no such distinction is needed.

class routee.powertrain.core.model_config.PredictMethod(value)[source]#

An enumeration.

class routee.powertrain.core.model_config.Provenance(*, source: ~typing.Annotated[~routee.powertrain.core.provenance.FastSimSource | ~routee.powertrain.core.provenance.RealWorldSource | ~routee.powertrain.core.provenance.LegacySource, FieldInfo(annotation=NoneType, required=True, discriminator='method')] | None = None, training: ~routee.powertrain.core.provenance.TrainingConfig = <factory>)[source]#

Where a model came from and how it was built.

Two complementary answers: source — what produced the training data (FASTSim simulation, real-world collection, or an unknown legacy origin), including the dataset labels for that data; and training — the hyperparameters the fit ran under.

Deliberately excluded from model_digest (see core.digest). The estimator binary's sha256 already pins the exact data and hyperparameters a model was fit to, so making provenance identity-bearing would only make it uncorrectable — backfilling a FASTSim version onto a published model would change the model's identity.

property dataset_hash: str | None#

The training data's fingerprint, when the source records one.

None for a FastSimSource, for the same reason as dataset_name, and None when no source is set.

property dataset_name: str | None#

The training dataset's label, when the source records one.

None for a FastSimSource — simulated training data is described by dataset_run_ids against the pipeline's provenance database rather than by a label in the artifact — and None when no source is set.

property method: TrainingMethod | None#

The recorded training method, or None when no source is set.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

source: TrainingSource | None#

What produced the training data. None when nothing is recorded.

class routee.powertrain.core.model_config.RealWorldSource(*, method: Literal[TrainingMethod.REAL_WORLD] = TrainingMethod.REAL_WORLD, data_source: str | None = None, fleet: str | None = None, collection_start: str | None = None, collection_end: str | None = None, n_vehicles: int | None = None, n_trips: int | None = None, dataset_name: str | None = None, dataset_hash: str | None = None, notes: str | None = None)[source]#

Training data collected from instrumented vehicles in the field.

collection_start: str | None#

Collection window, as ISO YYYY-MM-DD strings.

data_source: str | None#

Name of the data collection program or provider.

dataset_hash: str | None#

Fingerprint of that data — see routee.powertrain.hash_dataframe.

dataset_name: str | None#

Human-readable identifier of the collected dataset the model was fit to.

fleet: str | None#

Fleet the vehicles were drawn from, when the source spans several.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

n_vehicles: int | None#

Size of the underlying sample.

class routee.powertrain.core.model_config.TrainingConfig(*, test_size: float | None = None, validation_size: float | None = None, random_seed: int = 42, trip_column: str = 'trip_id', trained_date: str | None = None)[source]#

Build-time hyperparameters — needed to reproduce training, not to use the model. Safe to drop from a shipped artifact without affecting prediction.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

trained_date: str | None#

Calendar date the model was trained, as an ISO YYYY-MM-DD string. Stamped at training time by Trainer.train; None when unknown (e.g. legacy models converted from the v1 format).

class routee.powertrain.core.model_config.TrainingMethod(value)[source]#

How a model's training data was produced.

Doubles as the discriminator for the TrainingSource union — each source variant pins method to exactly one of these values.

class routee.powertrain.core.model_config.Vehicle(*, vehicle_description: str, powertrain_type: ~routee.powertrain.core.powertrain_type.Annotated[~routee.powertrain.core.powertrain_type.PowertrainType, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_powertrain, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)], make: str, model: str, year: ~typing.Annotated[int | tuple[int, int], ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.year.parse_year, json_schema_input_type=PydanticUndefined)], variant: str | None = None, mass_lbs: float | None = None, fuel_type: ~routee.powertrain.core.fuel_type.Annotated[~routee.powertrain.core.fuel_type.FuelType, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_fuel_type, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)] | None = None, drivetrain: ~routee.powertrain.core.drivetrain.Annotated[~routee.powertrain.core.drivetrain.Drivetrain, ~pydantic.functional_validators.BeforeValidator(func=~routee.powertrain.core.pydantic_fields._coerce_drivetrain, json_schema_input_type=PydanticUndefined), ~pydantic.functional_serializers.PlainSerializer(func=~routee.powertrain.core.pydantic_fields.<lambda>, return_type=str, when_used=always)] | None = None, engine: str | None = None, trim: str | None = None)[source]#

The vehicle a model describes — identity plus descriptive attributes.

make/model/year/variant feed the derived config_slug and ModelKey; the remaining fields are descriptive and registry-filterable.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class routee.powertrain.core.features.Constraints(*, lower: float | None = None, upper: float | None = None)[source]#
model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class routee.powertrain.core.features.DataColumn(*, name: str, units: str, dtype: str = 'float32', constraints: ~routee.powertrain.core.features.Constraints = <factory>)[source]#
model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class routee.powertrain.core.features.FeatureSet(*, features: List[DataColumn])[source]#
property feature_name_list: List[str]#

Returns a list of feature names in the order they appear in the feature set.

Order is important since the underlying estimator might expect it.

property features_id: str#

Returns a string that uniquely identifies this feature set. The names are sorted to provide a consistent id.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class routee.powertrain.core.features.TargetSet(*, targets: List[DataColumn])[source]#
model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

routee.powertrain.core.features.feature_id_to_names(feature_id: str) List[str][source]#

Returns a list of feature names from a feature set id.

routee.powertrain.core.features.feature_names_to_id(feature_names: List[str]) str[source]#

Returns a string that uniquely identifies a feature set. The names are sorted to provide a consistent id.

class routee.powertrain.core.metadata.EstimatorInfo(*, estimator_type: str, model_file: str, architecture_tag: str = 'unknown', input_spec: dict | None = None, estimator_sha256: str | None = None)[source]#

Describes the serialized estimator artifact: what to load and how to shape inputs. Everything a consumer needs to instantiate and run the binary, without cracking it open.

architecture_tag: str#

Coarse architecture family ("random_forest", "cnn", "ngboost" …). Used for registry-level filtering without parsing estimator_type strings.

estimator_sha256: str | None#

Bare lowercase-hex sha256 of the exact serialized estimator bytes (the file named by model_file). A pure content address, stamped at train time and verified against the raw bytes on load. None for legacy models saved before digests existed.

input_spec: dict | None#

Serialized Estimator.input_spec (lookback, grouping_column, pad_strategy). Allows a registry consumer to see lookback requirements before loading the binary.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class routee.powertrain.core.metadata.Metadata(*, vehicle: ~routee.powertrain.core.model_config.Vehicle, contract: ~routee.powertrain.core.model_config.Contract, estimator: ~routee.powertrain.core.metadata.EstimatorInfo, provenance: ~routee.powertrain.core.provenance.Provenance, errors: ~routee.powertrain.validation.errors.ModelErrors, routee_version: str = <factory>, schema_version: int = 2, model_digest: str | None = None)[source]#

Carries all model metadata that gets persisted alongside the estimator binary.

Serializes 1:1 with the metadata.json file inside a model archive. Fields are grouped by the job a reader needs them for:

  • vehicle — the model's identity and descriptive attributes

  • contract — the input/output contract needed to interpret a prediction

  • estimator — how to load and run the serialized binary

  • provenance — where the model came from and how it was built

  • errors — validation metrics

property config: ModelConfig#

A flat ModelConfig view reconstructed from the grouped sections.

The identity/contract/provenance fields are stored decomposed, but many runtime consumers (estimators, error computation, Model.predict) want the single flat object the model was trained from. This derives it on demand — nothing is stored twice.

classmethod from_config(config: ModelConfig, errors: ModelErrors, estimator_type: str, model_file: str, architecture_tag: str = 'unknown', input_spec: dict | None = None, routee_version: str | None = None, trained_date: str | None = None) Metadata[source]#

Build grouped metadata from a flat ModelConfig and estimator facts.

The inverse of the config property: decomposes the flat training config into the vehicle / contract / provenance sections and pairs them with the estimator descriptor. routee_version defaults to the running package version; pass it explicitly to record the version that actually trained a model (e.g. when converting legacy archives). trained_date (ISO YYYY-MM-DD) is stamped onto provenance.training; leave it None when the training date is unknown (e.g. converting legacy archives).

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_digest: str | None#

Registry-independent instance identity, minted at train time: sha256:<64 hex> over the frozen spec-1 identity payload (see core.digest), which embeds estimator.estimator_sha256 — so the digest pins the binary transitively while remaining recomputable from metadata alone. Registry versions (v<N>) are coordinates that map to this identity, never the reverse. None for legacy models.

property short_digest: str | None#

Truncated display form of model_digest (sha256:<12 hex>).

routee.powertrain.core.year.format_year(year: int | tuple[int, int]) str[source]#

Format a year for display and filesystem path usage.

routee.powertrain.core.year.parse_year(value) int | tuple[int, int][source]#

Parse a year value from various formats.

Accepts:
  • int: single year (e.g. 2020)

  • tuple/list of two ints: year range (e.g. (2020, 2026))

  • str: single year "2020" or range "2020-2026"

Returns: int for a single year, tuple[int, int] for a range.

routee.powertrain.core.year.serialize_year(year: int | tuple[int, int])[source]#

Serialize year for JSON/dict storage.

Returns int for a single year, "YYYY-YYYY" string for a range.

routee.powertrain.core.year.year_contains(year: int | tuple[int, int], query_year: int) bool[source]#

Check if a year value contains/matches a specific query year.

class routee.powertrain.registry.model_id.ModelId(make: object = None, vehicle_slug: object = None, year: object = None, config_slug: object = None, version: object = None)[source]#

Uniquely identifies a model in the registry.

A config_slug disambiguates multiple models for the same vehicle/year — e.g. rf_steady_a1b2c3d4, ngb_96224f1f. The slug is derived from the model's metadata (architecture + optional config.variant + feature-set hash) via derive_config_slug; it is not stored separately. The full feature composition and estimator architecture live in the archive's metadata.json (and in index.json for registry-level search).

A ModelId is a ModelKey (the intrinsic, version-less identity, derivable from metadata) plus a registry version (the only coordinate a registry assigns). Use id.key to get the version-less identity, or ModelId.from_key(key, version) / from_metadata(metadata, version) to attach a version. from_path reconstructs one from the frozen registry path.

classmethod from_key(key: ModelKey, version: int) ModelId[source]#

Attach a registry version to a version-less ModelKey.

classmethod from_metadata(metadata: Metadata, version: int) ModelId[source]#

Mint a ModelId from a model's metadata plus a registry version.

This is the canonical constructor: the version-less identity is derived from metadata (via ModelKey.from_metadata), so the only registry-assigned coordinate is version.

Parameters:
  • metadata -- the model metadata

  • version -- the registry version (positive integer)

Returns: a ModelId instance

classmethod from_path(path: str) ModelId[source]#

Parse a ModelId from a path string.

Expected format: make/vehicle_slug/year/config_slug/v<N>

Parameters:

path -- a /-separated path string

Returns: a ModelId instance

Raises:

ValueError -- if the path cannot be parsed as a valid model id

property key: ModelKey#

The version-less identity — everything except the registry version.

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_path() str[source]#

Build the registry path for this model.

Returns: e.g. "toyota/camry_ice/2016/rf_default/v1"

class routee.powertrain.registry.model_id.ModelInfo(*, model_id: ModelId, vehicle_model: str | None = None, estimator_type: str, feature_names: List[str], target_names: List[str], powertrain_type: str, vehicle_description: str, architecture_tag: str = 'unknown', input_spec: dict | None = None, path: str | None = None, mass_lbs: float | None = None, fuel_type: str | None = None, drivetrain: str | None = None, engine: str | None = None, trim: str | None = None, model_digest: str | None = None)[source]#

Lightweight model summary returned from registry queries (no binary data).

model_config: ClassVar[ConfigDict] = {}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_digest: str | None#

The model's registry-independent instance identity (sha256:<hex>), read from metadata.json. None for models published before digests existed.

vehicle_model: str | None#

The bare metadata vehicle.model name (e.g. "camry"), as distinct from the derived model_id.vehicle_slug (e.g. "camry_ice"). query(model=...) matches either. None for entries indexed before this field existed.

class routee.powertrain.registry.model_id.ModelKey(*, make: str, vehicle_slug: str, year: Annotated[int | tuple[int, int], BeforeValidator(func=parse_year, json_schema_input_type=PydanticUndefined)], config_slug: str)[source]#

A model's intrinsic, version-less identity.

make/vehicle_slug/year/config_slug are all pure functions of a model's metadata, so a ModelKey is fully determined the moment a model is trained — unlike version, which is a registry coordinate assigned when the model is placed into a registry. vehicle_slug is derived (via derive_vehicle_slug) as the model name plus the coarse powertrain family — e.g. camry_ice, volt_phev. Model.key exposes this, so every model self-describes its identity without needing a registry.

Frozen (and therefore hashable) so it can be used as a grouping key that collapses the versions of one model.

classmethod from_metadata(metadata: Metadata) ModelKey[source]#

Derive the version-less identity from a model's metadata.

classmethod from_path(path: str) ModelKey[source]#

Parse a ModelKey from a make/vehicle_slug/year/config_slug path.

model_config: ClassVar[ConfigDict] = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_path() str[source]#

Build the version-less registry path prefix for this model.

routee.powertrain.registry.registry.INDEX_FILENAME = 'index.json'#

Filename of the catalog the remote backends read to answer queries without walking the whole store.

exception routee.powertrain.registry.registry.IndexMissingError[source]#

Raised when index.json is missing or unreadable at the schema root.

class routee.powertrain.registry.registry.ModelRegistry[source]#

Abstract interface for a model registry backend.

Implementations provide model discovery (query) and retrieval (load). The registry is read-only from the package's perspective; publishing models is handled out-of-band by CI/scripts.

find_by_digest(digest: str) List[ModelInfo][source]#

Find the registry entries holding a model with the given instance identity.

This is the coordinate lookup for a model you already have in hand: given the model_digest from a metadata.json (or Model.digest), it returns every registry entry whose stored digest matches — normally one, but a byte-identical model legitimately published under multiple keys yields several.

Parameters:

digest -- the instance digest, with or without the sha256: prefix

Returns: matching ModelInfo entries (empty if the model was never

published to this registry)

abstract get_metadata(model_id: str | ModelId) dict[source]#

Fetch only the metadata for a model (without downloading the binary).

Parameters:

model_id -- unique identifier for the model. Can be a ModelId instance or a string path that will be parsed via ModelId.from_path().

Returns: the parsed metadata dictionary from the archive

abstract list_models(version_strategy: Literal['latest', 'all'] = 'latest') List[ModelId][source]#

List model identifiers in the registry.

This is a lightweight operation that returns only the model paths/identifiers without fetching any metadata or binaries.

Parameters:

version_strategy -- "latest" (default) returns only the highest version per (make, model, year, config_slug) group; "all" returns every versioned identifier.

Returns: list of ModelId matching the strategy

abstract load(model_id: str | ModelId) Model[source]#

Download and deserialize a specific model.

Parameters:

model_id -- unique identifier for the model to load. Can be a ModelId instance or a string path that will be parsed via ModelId.from_path().

Returns: a fully deserialized Model instance

abstract query(make: str | None = None, model: str | None = None, year: int | None = None, config_slug: str | None = None, feature_names: Sequence[str] | None = None, powertrain_type: str | None = None, fuel_type: str | None = None, drivetrain: str | None = None, engine: str | None = None, trim: str | None = None, version: int | None = None, model_digest: str | None = None, version_strategy: Literal['latest', 'all'] = 'latest', custom_filters: Sequence[Callable[[ModelInfo], bool]] | None = None, fuzzy: bool = True, fuzzy_threshold: int = 80) List[ModelInfo][source]#

List models matching the given filters.

All parameters are optional; passing none returns all models. Returns lightweight metadata — no model binaries are downloaded.

Parameters:
  • make -- filter by vehicle make

  • model -- filter by vehicle model — matches the bare metadata model name (e.g. "camry") or the derived vehicle_slug path segment (e.g. "camry_ice")

  • year -- filter by model year

  • config_slug -- filter by config slug (e.g. "rf_default", "cnn_5link")

  • feature_names -- filter to models whose feature set contains every listed feature column (subset match, exact names)

  • powertrain_type -- filter by powertrain type (e.g. "ICE", "BEV", "HEV")

  • fuel_type -- filter by fuel type (e.g. "GASOLINE", "DIESEL", "ELECTRICITY")

  • drivetrain -- filter by drivetrain (e.g. "FWD", "RWD", "AWD")

  • engine -- filter by engine specification (e.g. "4cyl", "2.0tdi")

  • trim -- filter by trim level (e.g. "sport", "active")

  • version -- pin results to an exact version (e.g. 2). When set, version_strategy is ignored.

  • model_digest -- pin results to an exact instance identity — the model_digest minted at train time and stored in metadata.json (accepted with or without the sha256: prefix; always matched exactly, never fuzzily). Resolves a metadata file in hand back to its registry entry. When set, version_strategy is ignored.

  • version_strategy -- how to collapse multiple versions of the same model. "latest" (default) keeps only the highest version per (make, vehicle_slug, year, config_slug) group; "all" returns every version. Ignored when version is specified.

  • custom_filters -- optional list of callables that accept a ModelInfo and return True to keep the model or False to exclude it

  • fuzzy -- if True, use fuzzy string matching for string fields (default True)

  • fuzzy_threshold -- minimum score (0–100) for a fuzzy match to be accepted (default 80)

class routee.powertrain.estimators.estimator_interface.ColumnSpec(*, name: str, units: str | None = None, dtype: str | None = None)[source]#

Identity of one positional column in an estimator's input or output tensor.

Carries the column name plus its units and dtype so a consumer holding only the serialized binary can both order its inputs correctly and interpret/convert their values.

model_config: ClassVar[ConfigDict] = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class routee.powertrain.estimators.estimator_interface.Estimator[source]#

Abstract base class for all estimator backends.

bind_io_contract(config: ModelConfig) None[source]#

Stamp the input/output contract derived from config onto input_spec.

Preserves any windowing fields already set by the trainer and records the ordered input columns (features, plus distance for RAW), the ordered output columns, the predict method, and the distance column — so the serialized binary and metadata are self-describing and a consumer never has to guess the positional order.

file_extension: str#

File extension used when serializing this estimator's binary in a ZIP archive.

abstract classmethod from_bytes(data: bytes) Estimator[source]#

Deserialize an estimator from raw bytes.

property input_spec: InputSpec#

The input/output contract this estimator implements.

Subclasses set the windowing fields at construction; the trainer stamps the ordered input/output columns via bind_io_contract().

output_column_specs(config: ModelConfig) List[ColumnSpec][source]#

Positional output tensor columns this estimator emits.

Default: one column per energy target, in order. Estimators that emit extra columns (e.g. per-target uncertainty) override this.

abstract predict(links_df: DataFrame, config: ModelConfig) DataFrame[source]#

Predict absolute energy consumption for each link.

Parameters:
  • links_df -- the input dataframe. Must contain every column in config.feature_set plus (if predict_method == RAW) the distance column, and (if input_spec.grouping_column is set) the grouping column.

  • config -- the model's ModelConfig. Estimators read feature_set, distance, target and predict_method from here.

abstract to_bytes() bytes[source]#

Serialize the estimator to raw bytes (native binary format).

This is the estimator's only serialization primitive. Estimators are not independently persistable artifacts: a model on disk is always an estimator binary paired with its metadata.json sidecar, and that pairing — along with the required input/output contract and the instance digest — is enforced exclusively at the Model save/load choke points (see routee.powertrain.io.archive). Persist via Model.to_file / Model.from_file, never by writing these bytes directly.

class routee.powertrain.estimators.estimator_interface.InputSpec(*, lookback: int = 0, grouping_column: str | None = None, pad_strategy: Literal['zero', 'repeat_first'] = 'repeat_first', input_columns: List[ColumnSpec] | None = None, output_columns: List[ColumnSpec] | None = None, predict_method: str | None = None, distance_column: str | None = None)[source]#

The full input/output contract an estimator's serialized binary implements.

Beyond the windowing fields (lookback/grouping_column/pad_strategy) it pins the positional order of the estimator's input and output tensors — the piece a downstream consumer (e.g. routee-compass) needs to feed columns in the right slots. The contract fields are Optional and default to None so legacy artifacts minted before the contract existed still parse.

distance_column: str | None#

The distance column — the RATE multiplier / the RAW input position.

grouping_column: str | None#

column used to bucket rows into independent sequences (e.g. "route_id"). Required whenever lookback > 0 so windows don't cross sequence boundaries.

input_columns: List[ColumnSpec] | None#

the feature columns, plus the distance column appended when predict_method == "raw". None on legacy artifacts that predate the contract.

Type:

Ordered positional columns of the input tensor

lookback: int#

rows of prior context required per prediction. 0 = pointwise (classic tabular).

model_config: ClassVar[ConfigDict] = {'frozen': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

output_columns: List[ColumnSpec] | None#

the energy target(s), in order. Estimators that emit uncertainty append their std columns.

Type:

Ordered positional columns of the output tensor

pad_strategy: PadStrategy#

how to pad the lookback window at the start of a group (first rows lack prior context).

predict_method: str | None#

"rate" (multiply by distance) or "raw" (already absolute energy).

Type:

How the raw estimator output maps to energy

class routee.powertrain.estimators.onnx.ONNXEstimator(onnx_model: ModelProto, input_spec: InputSpec = InputSpec(lookback=0, grouping_column=None, pad_strategy='repeat_first', input_columns=None, output_columns=None, predict_method=None, distance_column=None))[source]#

Runs any ONNX model via onnxruntime.

When input_spec.lookback > 0 the estimator wraps feature rows into a (N, lookback, F) windowed tensor grouped by input_spec.grouping_column (with padding at sequence starts per input_spec.pad_strategy) before inference. When lookback == 0 the estimator feeds a plain (N, F) tabular tensor — the common case for tree ensembles converted via skl2onnx.

file_extension: str = '.onnx'#

File extension used when serializing this estimator's binary in a ZIP archive.

classmethod from_bytes(data: bytes) ONNXEstimator[source]#

Deserialize an estimator from raw bytes.

predict(links_df: DataFrame, config: ModelConfig) DataFrame[source]#

Predict absolute energy consumption for each link.

Parameters:
  • links_df -- the input dataframe. Must contain every column in config.feature_set plus (if predict_method == RAW) the distance column, and (if input_spec.grouping_column is set) the grouping column.

  • config -- the model's ModelConfig. Estimators read feature_set, distance, target and predict_method from here.

to_bytes() bytes[source]#

Serialize the estimator to raw bytes (native binary format).

This is the estimator's only serialization primitive. Estimators are not independently persistable artifacts: a model on disk is always an estimator binary paired with its metadata.json sidecar, and that pairing — along with the required input/output contract and the instance digest — is enforced exclusively at the Model save/load choke points (see routee.powertrain.io.archive). Persist via Model.to_file / Model.from_file, never by writing these bytes directly.

class routee.powertrain.estimators.ngboost_estimator.NGBoostEstimator(ngboost)[source]#
file_extension: str = '.joblib'#

File extension used when serializing this estimator's binary in a ZIP archive.

classmethod from_bytes(data: bytes) NGBoostEstimator[source]#

Deserialize an estimator from raw bytes.

output_column_specs(config: ModelConfig) List[ColumnSpec][source]#

NGBoost emits a point prediction plus a per-target standard deviation.

predict(links_df: DataFrame, config: ModelConfig) DataFrame[source]#

Predict absolute energy consumption for each link.

Parameters:
  • links_df -- the input dataframe. Must contain every column in config.feature_set plus (if predict_method == RAW) the distance column, and (if input_spec.grouping_column is set) the grouping column.

  • config -- the model's ModelConfig. Estimators read feature_set, distance, target and predict_method from here.

to_bytes() bytes[source]#

Serialize the estimator to raw bytes (native binary format).

This is the estimator's only serialization primitive. Estimators are not independently persistable artifacts: a model on disk is always an estimator binary paired with its metadata.json sidecar, and that pairing — along with the required input/output contract and the instance digest — is enforced exclusively at the Model save/load choke points (see routee.powertrain.io.archive). Persist via Model.to_file / Model.from_file, never by writing these bytes directly.

class routee.powertrain.trainers.trainer.Trainer[source]#
architecture_tag: str = 'unknown'#

Coarse architecture family, used in Metadata for registry-level filtering. Subclasses override (e.g. "random_forest", "cnn", "ngboost").

default_test_size: float = 0.2#

Default split sizes used when ModelConfig leaves them unspecified.

abstract inner_train(features: DataFrame, target: DataFrame, config: ModelConfig, validation_features: DataFrame | None = None, validation_target: DataFrame | None = None) Estimator[source]#

Builds an estimator from the given data.

property required_extra_columns: List[str]#

Columns the trainer needs beyond the declared feature set.

Example: a CNN trainer with lookback needs a grouping column (e.g. route_id) so windows don't cross route boundaries.

property split_grouping_column: str | None#

If set, the train/test split keeps all rows of a given group together.

Sequence-aware trainers (e.g. the 1D CNN) must set this so that a route's links stay contiguous within train or test — otherwise the per-group lookback windows built at both train and predict time stitch together non-consecutive rows and the temporal signal is lost.

train(data: DataFrame, config: ModelConfig) Model[source]#

A wrapper for inner train that does some pre and post processing.

class routee.powertrain.trainers.sklearn_random_forest.RandomForestTrainerOutput(value)[source]#

An enumeration.

class routee.powertrain.trainers.sklearn_random_forest.SklearnRandomForestTrainer(max_depth: int = 10, min_samples_split: int = 10, n_estimators: int = 20, random_state: int = 52, cores: int = 4, output_type=RandomForestTrainerOutput.ONNX)[source]#
architecture_tag: str = 'random_forest'#

Coarse architecture family, used in Metadata for registry-level filtering. Subclasses override (e.g. "random_forest", "cnn", "ngboost").

inner_train(features: DataFrame, target: DataFrame, config: ModelConfig, validation_features: DataFrame | None = None, validation_target: DataFrame | None = None) Estimator[source]#

Uses a random forest to predict the energy rate values

class routee.powertrain.trainers.ngboost_trainer.NGBoostTrainer(n_estimators: int = 100, dist=<class 'ngboost.distns.normal.Normal'>, verbose: bool = True, verbose_eval: int = 20, learning_rate: float = 0.01, random_state: int = 52)[source]#
architecture_tag: str = 'ngboost'#

Coarse architecture family, used in Metadata for registry-level filtering. Subclasses override (e.g. "random_forest", "cnn", "ngboost").

inner_train(features: DataFrame, target: DataFrame, config: ModelConfig, validation_features: DataFrame | None = None, validation_target: DataFrame | None = None) Estimator[source]#

Uses a ngboost model to predict the energy rate values

routee.powertrain.validation.feature_visualization.contour_plot(model: Model, x_feature: str, y_feature: str, feature_ranges: Dict[str, Dict], output_path: str | Path | None = None)[source]#

takes a model and generates a contour plot of the two test features: x_feature and y_feature.

Parameters:
  • model -- the model that will be used to generate the plots

  • x_feature -- one of the features used to generate the energy matrix and will be the x-axis feature

  • y_feature -- one of the features used to generate the energy matrix and will be the y-axis feature

  • feature_ranges -- a nested dictionary where each key should be a feature name and each value should be another dictionary containing "lower", "upper", and "n_sample" keys/values. These correspond to the lower/upper boundaries and n samples used to generate the plot. n_samples must be an integer and lower/upper are floats.

  • output_path -- an optional path to save the plot as a png file.

routee.powertrain.validation.feature_visualization.visualize_features(model: Model, feature_ranges: Dict[str, dict], output_path: str | Path | None = None, return_predictions: bool | None = False) Dict[str, Series] | None[source]#

takes a model and generates test links to independently test the model's features and creates plots of those predictions

Parameters:
  • model -- the model that will be used to generate the plots

  • feature_ranges -- a nested dictionary where each key should be a feature name and each value should be another dictionary containing "lower", "upper", and "n_sample" keys/values. These correspond to the lower/upper boundaries and n samples used to generate the plot. n_samples must be an integer and lower/upper are floats.

  • output_path -- an optional path to save the plots as png files.

  • return_predictions -- if true, returns the dictionary containing the prediction values

Returns: optionally returns a dictionary containing the predictions where the key is the feature tested