Skip to content

Commit

Permalink
Merge pull request #102 from NREL/feature/full-feature-for-dependency…
Browse files Browse the repository at this point in the history
…-reduction

Cargo features
  • Loading branch information
kylecarow authored Mar 8, 2024
2 parents 50f4975 + 2fb5d17 commit 92da6ca
Show file tree
Hide file tree
Showing 30 changed files with 2,329 additions and 2,216 deletions.
13 changes: 7 additions & 6 deletions python/fastsim/demos/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import sys
import os
from pathlib import Path
from fastsim.fastsimrust import abc_to_drag_coeffs
import numpy as np
import time
import pandas as pd
Expand Down Expand Up @@ -890,10 +889,12 @@ def get_sim_drive_vec(
# values.

# %%
test_veh = fsim.vehicle.Vehicle.from_vehdb(5, to_rust=True).to_rust()
(drag_coef, wheel_rr_coef) = abc_to_drag_coeffs(test_veh, 25.91, 0.1943, 0.01796, simdrive_optimize=True)
if "default" in fsim.fastsimrust.enabled_features():
from fastsim.fastsimrust import abc_to_drag_coeffs
test_veh = fsim.vehicle.Vehicle.from_vehdb(5, to_rust=True).to_rust()
(drag_coef, wheel_rr_coef) = abc_to_drag_coeffs(test_veh, 25.91, 0.1943, 0.01796, simdrive_optimize=True)

print(f'Drag Coefficient: {drag_coef:.3g}')
print(f'Wheel Rolling Resistance Coefficient: {wheel_rr_coef:.3g}')

# %%
print(f'Drag Coefficient: {drag_coef:.3g}')
print(f'Wheel Rolling Resistance Coefficient: {wheel_rr_coef:.3g}')
# %%
7 changes: 6 additions & 1 deletion python/fastsim/demos/test_demos.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import subprocess
import os
from pathlib import Path
from fastsim import fastsimrust
import pytest


Expand All @@ -9,18 +10,22 @@ def demo_paths():
demo_paths.remove(Path(__file__).resolve())
return demo_paths

REQUIRED_FEATURES = {"vehicle_import_demo": "vehicle-import"}

@pytest.mark.parametrize(
"demo_path", demo_paths(), ids=[dp.name for dp in demo_paths()]
)
def test_demo(demo_path: Path):
if demo_path.stem in REQUIRED_FEATURES.keys() and REQUIRED_FEATURES[demo_path.stem] not in fastsimrust.enabled_features():
pytest.skip(f'requires "{REQUIRED_FEATURES[demo_path.stem]}" feature')

os.environ["SHOW_PLOTS"] = "false"
os.environ["TESTING"] = "true"

rslt = subprocess.run(
["python", demo_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)

assert rslt.returncode == 0, rslt.stderr
15 changes: 12 additions & 3 deletions python/fastsim/demos/vehicle_import_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@
Vehicle Import Demonstration
This module demonstrates the vehicle import API
"""
# %%
from fastsim import fastsimrust

REQUIRED_FEATURE = "vehicle-import"
if __name__ == "__main__" and REQUIRED_FEATURE not in fastsimrust.enabled_features():
raise NotImplementedError(
f'Feature "{REQUIRED_FEATURE}" is required to run this demo'
)

# %%
# Preamble: Basic imports
import os, pathlib

import fastsim.fastsimrust as fsr
import fastsim.utils as utils

#for testing demo files, false when running automatic tests
# for testing demo files, false when running automatic tests
SHOW_PLOTS = utils.show_plots()

# %%
Expand Down Expand Up @@ -66,7 +75,7 @@

rv = fsr.vehicle_import_by_id_and_year(data.id, int(year), other_inputs)

fsr.export_vehicle_to_file(rv, str(OUTPUT_DIR / "demo-vehicle.yaml"))
rv.to_file(OUTPUT_DIR / "demo-vehicle.yaml")

# %%
# Alternative API for importing all vehicles at once
Expand All @@ -83,4 +92,4 @@
vehs = fsr.import_all_vehicles(int(year), make, model, other_inputs)
if SHOW_PLOTS:
for v in vehs:
print(f"Imported {v.scenario_name}")
print(f"Imported {v.scenario_name}")
8 changes: 1 addition & 7 deletions python/fastsim/fastsimrust.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ from __future__ import annotations
from typing_extensions import Self
from typing import Dict, List, Tuple, Optional, ByteString
from abc import ABC
from fastsim.vehicle import VEHICLE_DIR
import yaml
from pathlib import Path

class RustVec(ABC):
def __repr__(self) -> str:
Expand Down Expand Up @@ -1070,8 +1067,5 @@ def get_label_fe_phev(
props: RustPhysicalProperties,
) -> LabelFePHEV:
...

def get_label_fe_conv(veh: RustVehicle) -> LabelFe:
...


def enabled_features() -> List[str]: ...
5 changes: 4 additions & 1 deletion python/fastsim/tests/test_auxiliaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from fastsim import auxiliaries
from fastsim.vehicle import Vehicle
from fastsim import utils
from fastsim.fastsimrust import abc_to_drag_coeffs
from fastsim import fastsimrust
import numpy as np
import pytest

class test_auxiliaries(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -47,7 +48,9 @@ def test_drag_coeffs_to_abc(self):
self.assertAlmostEqual(0, b_lbf__mph)
self.assertAlmostEqual(0.020817239083920212, c_lbf__mph2)

@pytest.mark.skipif("default" not in fastsimrust.enabled_features(), reason='requires "default" feature')
def test_abc_to_drag_coeffs_rust_port(self):
from fastsim.fastsimrust import abc_to_drag_coeffs
with np.errstate(divide='ignore'):
veh = Vehicle.from_vehdb(5).to_rust()
a = 25.91
Expand Down
16 changes: 8 additions & 8 deletions python/fastsim/tests/test_simdrivelabel.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import unittest
import numpy as np

from fastsim import fastsimrust as fsr
import pytest

from fastsim import fastsimrust

@pytest.mark.skipif("simdrivelabel" not in fastsimrust.enabled_features(), reason='requires "simdrivelabel" feature')
class TestSimDriveLabel(unittest.TestCase):
def test_get_label_fe_conv(self):
veh = fsr.RustVehicle.mock_vehicle()
label_fe, _ = fsr.get_label_fe(veh, False, False) # Unpack the tuple
veh = fastsimrust.RustVehicle.mock_vehicle()
label_fe, _ = fastsimrust.get_label_fe(veh, False, False) # Unpack the tuple
# Because the full test is already implemented in Rust, we
# don't need a comprehensive check here.
self.assertEqual(label_fe.lab_udds_mpgge, 32.47503766676829)
Expand All @@ -16,10 +16,10 @@ def test_get_label_fe_conv(self):

def test_get_label_fe_phev(self):
# Set up the required parameters and objects needed for testing get_label_fe_phev
veh = fsr.RustVehicle.mock_vehicle()
label_fe, _ = fsr.get_label_fe(veh, False, False)
veh = fastsimrust.RustVehicle.mock_vehicle()
label_fe, _ = fastsimrust.get_label_fe(veh, False, False)
self.assertEqual(label_fe.adj_udds_mpgge, 25.246151811422468)


if __name__ == '__main__':
unittest.main()
unittest.main()
12 changes: 6 additions & 6 deletions rust/fastsim-cli/src/bin/fastsim-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,9 @@ pub fn main() -> anyhow::Result<()> {

// TODO: put in logic here for loading vehicle for adopt-hd
// with same file format as regular adopt and same outputs retured
let is_adopt: bool = fastsim_api.adopt.is_some() && fastsim_api.adopt.unwrap();
let mut fc_pwr_out_perc: Option<Vec<f64>> = None;
let mut hd_h2_diesel_ice_h2share: Option<Vec<f64>> = None;
let is_adopt = fastsim_api.adopt.is_some() && fastsim_api.adopt.unwrap();
let mut fc_pwr_out_perc = None;
let mut hd_h2_diesel_ice_h2share = None;
let veh = if let Some(veh_string) = fastsim_api.veh {
if is_adopt || is_adopt_hd {
let (veh_string, pwr_out_perc, h2share) = json_rewrite(veh_string)?;
Expand Down Expand Up @@ -401,8 +401,8 @@ impl SerdeAPI for ParsedValue {}
fn json_rewrite(x: String) -> anyhow::Result<(String, Option<Vec<f64>>, Option<Vec<f64>>)> {
let adoptstring = x;

let mut fc_pwr_out_perc: Option<Vec<f64>> = None;
let mut hd_h2_diesel_ice_h2share: Option<Vec<f64>> = None;
let mut fc_pwr_out_perc = None;
let mut hd_h2_diesel_ice_h2share = None;

let mut parsed_data: Value = serde_json::from_str(&adoptstring)?;

Expand Down Expand Up @@ -440,7 +440,7 @@ fn json_rewrite(x: String) -> anyhow::Result<(String, Option<Vec<f64>>, Option<V
parsed_data["forceAuxOnFC"] = json!(force_aux_on_fc_value != 0)
}

let mut is_rear_wheel_drive: bool = false;
let mut is_rear_wheel_drive = false;
let fwd1rwd2awd3_raw = &parsed_data["fwd1rwd2awd3"];
if fwd1rwd2awd3_raw.is_i64() {
let fwd1rwd2awd3_value = fwd1rwd2awd3_raw.as_i64().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion rust/fastsim-cli/src/bin/vehicle-import-cli.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{self, Context};
use clap::Parser;
use fastsim_core::utils::create_project_subdir;
use fastsim_core::vehicle_utils::{get_default_cache_url, import_and_save_all_vehicles_from_file};
use fastsim_core::vehicle_import::{get_default_cache_url, import_and_save_all_vehicles_from_file};
use std::fs;
use std::path::{Path, PathBuf};

Expand Down
39 changes: 28 additions & 11 deletions rust/fastsim-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,21 @@ serde_yaml = { workspace = true }
ndarray = { workspace = true }
csv = "1.1"
serde_json = "1.0.81"
bincode = "1.3.3"
log = "0.4.17"
polynomial = "0.2.4"
argmin = "0.7.0"
argmin-math = { version = "0.2.1", features = [
bincode = { optional = true, version = "1.3.3" }
log = { optional = true, version = "0.4.17" }
argmin = { optional = true, version = "0.7.0" }
argmin-math = { optional = true, version = "0.2.1", features = [
"ndarray_latest-nolinalg-serde",
] }
curl = "0.4.44"
validator = { version = "0.16", features = ["derive"] }
curl = { optional = true, version = "0.4.44" }
validator = { version = "0.16", features = ["derive"], optional = true }
lazy_static = "1.4.0"
regex = "1.7.1"
rayon = "1.7.0"
zip = "0.6.6"
directories = "5.0.1"
include_dir = "0.7.3"
directories = { optional = true, version = "5.0.1" }
include_dir = { optional = true, version = "0.7.3" }
itertools = "0.12.0"
ndarray-stats = "0.5.1"
tempfile = "3.8.1"
url = "2.5.0"
ureq = "2.9.1"
Expand All @@ -53,4 +51,23 @@ include = [
]

[features]
pyo3 = ["dep:pyo3"]
# to disable the default features, see
# https://doc.rust-lang.org/cargo/reference/features.html?highlight=no-default-features#the-default-feature
# and use the `--no-default-features` flag when compiling
default = [
"dep:argmin",
"dep:argmin-math",
"dep:directories",
"logging",
"resources",
"simdrivelabel",
"validation",
"vehicle-import",
]
bincode = ["dep:bincode"] # non-default: bincode broken for RustVehicle struct
logging = ["dep:log"]
pyo3 = ["dep:pyo3"] # non-default: feature for use with fastsim-py crate
resources = ["dep:include_dir"]
simdrivelabel = ["resources"]
validation = ["dep:validator"]
vehicle-import = ["dep:curl"]
2 changes: 1 addition & 1 deletion rust/fastsim-core/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
// path when building using build_and_test.sh
let build_path = "../../python/fastsim/resources".to_string();

let prepath: String = match PathBuf::from(&publish_path).exists() {
let prepath = match PathBuf::from(&publish_path).exists() {
true => publish_path,
false => build_path,
};
Expand Down
7 changes: 5 additions & 2 deletions rust/fastsim-core/fastsim-proc-macros/src/add_pyo3_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn add_pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut ast = syn::parse_macro_input!(item as syn::ItemStruct);
// println!("{}", ast.ident.to_string());
let ident = &ast.ident;
let _is_state_or_history: bool =
let _is_state_or_history =
ident.to_string().contains("State") || ident.to_string().contains("HistoryVec");

let mut impl_block = TokenStream2::default();
Expand Down Expand Up @@ -213,6 +213,7 @@ pub fn add_pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream {
///
/// * `filepath`: `str | pathlib.Path` - Filepath, relative to the top of the `resources` folder, from which to read the object
///
#[cfg(feature = "resources")]
#[staticmethod]
#[pyo3(name = "from_resource")]
pub fn from_resource_py(filepath: &PyAny) -> PyResult<Self> {
Expand Down Expand Up @@ -306,6 +307,7 @@ pub fn add_pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream {
}

/// Write (serialize) an object to bincode-encoded `bytes`
#[cfg(feature = "bincode")]
#[pyo3(name = "to_bincode")]
pub fn to_bincode_py<'py>(&self, py: Python<'py>) -> PyResult<&'py PyBytes> {
PyResult::Ok(PyBytes::new(py, &self.to_bincode()?)).map_err(|e| PyIOError::new_err(format!("{:?}", e)))
Expand All @@ -317,6 +319,7 @@ pub fn add_pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream {
///
/// * `encoded`: `bytes` - Encoded bytes to deserialize from
///
#[cfg(feature = "bincode")]
#[staticmethod]
#[pyo3(name = "from_bincode")]
pub fn from_bincode_py(encoded: &PyBytes) -> PyResult<Self> {
Expand All @@ -341,7 +344,7 @@ pub fn add_pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream {
final_output.extend::<TokenStream2>(quote! {
#[cfg_attr(feature="pyo3", pyclass(module = "fastsimrust", subclass))]
});
let mut output: TokenStream2 = ast.to_token_stream();
let mut output = ast.to_token_stream();
output.extend(impl_block);
// if ast.ident.to_string() == "RustSimDrive" {
// println!("{}", output.to_string());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn approx_eq_derive(input: TokenStream) -> TokenStream {
generated.append_all(quote! {
impl ApproxEq for #name {
fn approx_eq(&self, other: &#name, tol: f64) -> bool {
let mut approx_eq_vals: Vec<bool> = Vec::new();
let mut approx_eq_vals = Vec::new();
#(approx_eq_vals.push(self.#field_names.approx_eq(&other.#field_names, tol));)*
approx_eq_vals.iter().all(|&x| x)
}
Expand Down
4 changes: 2 additions & 2 deletions rust/fastsim-core/fastsim-proc-macros/src/doc_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn doc_field(_attr: TokenStream, item: TokenStream) -> TokenStream {

let new_fields = if let syn::Fields::Named(FieldsNamed { named, .. }) = &mut item_struct.fields
{
let mut new_doc_fields: Vec<TokenStream2> = Vec::new();
let mut new_doc_fields = Vec::new();
for field in named.iter_mut() {
let mut skip_doc = false;
remove_handled_attrs(field, &mut skip_doc);
Expand Down Expand Up @@ -57,7 +57,7 @@ pub fn doc_field(_attr: TokenStream, item: TokenStream) -> TokenStream {
let struct_vis = item_struct.vis;
let struct_attrs = item_struct.attrs;

let output: TokenStream2 = quote! {
let output = quote! {
#(#struct_attrs)*
#struct_vis struct #struct_ident {
#new_fields
Expand Down
Loading

0 comments on commit 92da6ca

Please sign in to comment.