Migrating from v1#
RouteE-Powertrain 2.0 is a breaking release. Beyond the package rename, the model file format,
the model catalog, and much of the Model API changed. This page walks through the migration in
the order you are likely to hit each change.
If you just want the checklist, jump to Migration checklist.
1. Install the new package#
The project was previously published as nrel.routee.powertrain. Following the lab's rename it is
now published as routee.powertrain:
pip uninstall nrel.routee.powertrain
pip install routee.powertrain
The 1.x line is frozen. nrel.routee.powertrain 1.4.1 is the final 1.x release and emits a
DeprecationWarning on import; nrel.routee.powertrain 2.0.0 is a tombstone that installs
routee.powertrain and raises ImportError pointing here.
2. Update your imports#
The import root dropped the nrel namespace:
-import nrel.routee.powertrain as pt
+import routee.powertrain as pt
Submodule imports change the same way:
-from nrel.routee.powertrain.trainers.sklearn_random_forest import SklearnRandomForestTrainer
+from routee.powertrain.trainers.sklearn_random_forest import SklearnRandomForestTrainer
3. Replace model names with model ids#
v1 loaded models by flat name from a hardcoded catalog:
# v1
model = pt.load_model("2016_TOYOTA_Camry_4cyl_2WD")
v2 resolves models through a registry using a structured id,
<make>/<vehicle_slug>/<year>/<config_slug>, with an optional trailing v<N>:
# v2
model = pt.load_model("toyota/camry_ice/2016/rf_c3326385") # latest version
model = pt.load_model("toyota/camry_ice/2016/rf_c3326385/v1") # pinned version
Rather than translating names by hand, search the registry:
for info in pt.query_available_models(make="toyota", model="camry", year=2016):
print(info.model_id, info.feature_names)
query_available_models() also filters on powertrain_type, fuel_type, drivetrain, engine,
trim, feature_names, and config_slug, and does fuzzy matching by default — so
model="camry" will find camry_ice without you knowing the slug.
One v1 model is now several v2 models#
v1 packed every feature set into a single file and picked an estimator at predict time based on which columns you passed. v2 publishes one model per feature set, so a v1 model typically maps to three v2 models:
v1 feature set |
v2 |
|---|---|
|
|
|
|
|
|
Pick the one whose features match the columns you actually have. rf_c3326385 (speed and grade) is
the closest match to what v1 usually selected.
Other slug patterns you may see:
PHEV models carry the mode:
rf_charge_depleting_*,rf_charge_sustaining_*Thermal models:
rf_steady_thermal_*,rf_transient_thermal_*Probabilistic (NGBoost) models:
ngb_stochastic_*
list_available_models() also changed shape — it now takes registry and version_strategy
instead of local/external, and returns ModelId objects instead of strings:
-names: list[str] = pt.list_available_models(local=True, external=True)
+ids: list[ModelId] = pt.list_available_models()
4. Convert your own v1 model files#
v1 stored an entire model as one .json file with base64-encoded binaries. v2 models are
archives — a directory, .zip, or .tar.gz containing metadata.json plus a separate binary
(model.onnx or model.joblib). Loading a v1 .json now raises with a pointer to the converter.
Convert from the command line:
routee-powertrain convert-v1 MyModel.json out/ \
--make toyota --model camry --year 2016 --trim 4cyl_2wd
or from Python:
paths = pt.convert_legacy_model(
"MyModel.json", "out/", make="toyota", model="camry", year=2016
)
models = [pt.load_model(p) for p in paths]
Because one v1 file holds several feature sets, conversion writes one v2 model directory per feature set and returns all of their paths.
--make, --model, and --year are required: v1 metadata had no structured vehicle identity,
only a free-text vehicle_description, so there is nothing to infer them from. They matter because
the registry path is derived from them. --variant, --fuel-type, --drivetrain, --engine,
and --trim are optional; run routee-powertrain convert-v1 --help for the full list.
Note
Models saved with the v1 SmartCoreEstimator cannot be converted — the smartcore/Rust path was
removed in v2. Retrain those with SklearnRandomForestTrainer, which exports to ONNX.
5. API changes#
Model#
v1 |
v2 |
|---|---|
|
|
|
|
|
|
— |
|
|
removed — use |
|
removed — remote fetching is the registry's job |
|
directory, |
— |
|
predict() lost its optional arguments:
-model.predict(links_df, feature_columns=[...], distance_column="miles",
- apply_real_world_adjustment=True)
+model.predict(links_df)
Rename your columns to match the model's contract before calling predict(); the model now raises
if a required feature is missing rather than silently choosing a different estimator. The real-world
adjustment is always applied, using real_world_adjustment_factor from the model config.
ModelConfig#
ModelConfig (and Metadata, ModelErrors, FeatureSet, and friends) moved from
@dataclass to pydantic, so hand-written from_dict() / to_dict() / to_json() methods are
gone — use model_validate() and model_dump().
config = pt.ModelConfig(
vehicle_description="2016 Toyota Camry",
powertrain_type=pt.PowertrainType.ICE,
- feature_sets=[pt.FeatureSet([...])],
+ feature_set=pt.FeatureSet([...]),
+ make="toyota",
+ model="camry",
+ year=2016,
distance=...,
target=...,
- apply_real_world_adjustment=False,
+ real_world_adjustment_factor=1.0,
)
make, model, and year are now required — they feed the derived registry path. New optional
fields include variant, mass_lbs, fuel_type, drivetrain, engine, trim, and
training_source (which carries the dataset_name / dataset_hash labels).
Models converted from v1 record a pt.LegacySource under provenance.source: the v1 format stored
nothing about how a model was produced, so there is no simulator, pipeline, or dataset information
to carry over. Pass provenance_source= to convert_legacy_json when you know more than the format
does.
Note
Put the vehicle's full commercial designation in model (golf_1.5tsi vs golf_2.0tdi).
engine, drivetrain, and trim are descriptive metadata — filterable and correctable without
renaming registry paths.
Removed#
SmartCoreEstimator,SmartCoreRandomForestTrainer, and the Rust cratethe sklearn-native estimator and
port_to_c— random forests go through ONNX onlyroutee/powertrain/io/api.pyandread_modelresources/default_models/and the Box-hostedexternal_model_links.jsoncatalog
Custom trainers#
If you subclass Trainer, add the two new members required_extra_columns and
split_grouping_column.
6. What's new#
Worth knowing about even though nothing forces you to use it:
Registry — pluggable model discovery over HuggingFace Hub (the default), S3, or a local directory, configured with
ROUTEE_REGISTRY_BACKENDand friends. See Publishing a model.Digests — every model carries a content-addressed
model_digestminted at train time, and the estimator binary is checksummed on load. Seept.compute_model_digest().Self-describing binaries — the
.onnxfile embeds its own input/output contract, so a downstream consumer can reconstruct the exact positional input order withoutmetadata.json. See Estimator input contract.CNN trainer — a 1D CNN with sequence/lookback support, via the
pytorchextra.
Migration checklist#
pip uninstall nrel.routee.powertrainandpip install routee.powertrainimport nrel.routee.powertrain→import routee.powertrainReplace flat model names in
load_model()with model ids, choosing the feature set you haveReplace
list_available_models(local=..., external=...)calls; it returnsModelIds nowConvert any v1
.jsonmodels withroutee-powertrain convert-v1ModelConfig(feature_sets=[...])→feature_set=..., and addmake/model/yearapply_real_world_adjustment=False→real_world_adjustment_factor=1.0Drop the extra
predict()arguments; rename input columns to match the model contractmodel.errors→model.metadata.errorsReplace
Model.from_dict/to_dict/from_url, smartcore, the sklearn native estimator, andport_to_cCustom
Trainersubclasses: addrequired_extra_columnsandsplit_grouping_column