Skip to content

Commit

Permalink
Merge pull request #148 from NREL/feature/add-list-resources
Browse files Browse the repository at this point in the history
Add List Resources feature to FASTSim-2 (SerdeAPI tweaks, list_resources)
  • Loading branch information
calbaker authored Aug 27, 2024
2 parents 3fd6055 + b2c3330 commit 73ffd38
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 7 deletions.
27 changes: 27 additions & 0 deletions python/fastsim/tests/test_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Test getting resource lists via Rust API"""
import unittest

import fastsim as fsim
from fastsim import cycle, vehicle

class TestListResources(unittest.TestCase):
def test_list_resources_for_cycle(self):
"check if list_resources works for RustCycle"
c = cycle.Cycle.from_dict({
"cycSecs": [0.0, 1.0],
"cycMps": [0.0, 0.0]})
rc = c.to_rust()
resources = rc.list_resources()
self.assertTrue(len(resources) > 0)

def test_list_resources_for_vehicles(self):
"check if list_resources works for RustVehicle"
# NOTE: at the time of writing this test,
# there are no vehicle assets in resources.
# Therefore, we expect to get an empty vector.
# If resources are committed, this test should
# fail and we should use the following assert:
# self.assertTrue(len(resources) > 0)
rv = vehicle.Vehicle.from_vehdb(1).to_rust()
resources = rv.list_resources()
self.assertTrue(len(resources) == 0)
6 changes: 6 additions & 0 deletions rust/fastsim-core/src/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,12 @@ impl RustCycleCache {
pub fn get_delta_elev_m(&self) -> Vec<f64> {
self.delta_elev_m().to_vec()
}
#[pyo3(name = "list_resources")]
/// list available cycle resources
pub fn list_resources_py(&self) -> Vec<String> {
RustCycle::list_resources()
}
)]
/// Struct for containing:
/// * time_s, cycle time, $s$
Expand Down
3 changes: 0 additions & 3 deletions rust/fastsim-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ pub mod vehicle_import;
pub mod vehicle_thermal;
pub mod vehicle_utils;

#[cfg(feature = "dev-proc-macros")]
pub use dev_proc_macros as proc_macros;
#[cfg(not(feature = "dev-proc-macros"))]
pub use fastsim_proc_macros as proc_macros;

#[cfg_attr(feature = "pyo3", pyo3imports::pyfunction)]
Expand Down
37 changes: 37 additions & 0 deletions rust/fastsim-core/src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,40 @@

use include_dir::{include_dir, Dir};
pub const RESOURCES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/resources");

/// List the available resources in the resources directory
/// - subdir: &str, a subdirectory to choose from the resources directory
/// NOTE: if subdir cannot be resolved, returns an empty list
/// RETURNS: a vector of strings for resources that can be loaded
pub fn list_resources(subdir: &str) -> Vec<String> {
if subdir.is_empty() {
Vec::<String>::new()
} else if let Some(resources_path) = RESOURCES_DIR.get_dir(subdir) {
let mut file_names: Vec<String> = resources_path
.files()
.filter_map(|entry| entry.path().file_name()?.to_str().map(String::from))
.collect();
file_names.sort();
file_names
} else {
Vec::<String>::new()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_list_resources() {
let result = list_resources("cycles");
assert!(result.len() == 3);
assert!(result[0] == "HHDDTCruiseSmooth.csv");
// NOTE: at the time of writing this test, there is no
// vehicles subdirectory. The agreed-upon behavior in
// that case is that list_resources should return an
// empty vector of string.
let another_result = list_resources("vehicles");
assert!(another_result.len() == 0);
}
}
10 changes: 9 additions & 1 deletion rust/fastsim-core/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::imports::*;
use crate::{imports::*, resources};
use std::collections::HashMap;
use ureq;

Expand All @@ -13,6 +13,14 @@ pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> {
Ok(())
}

/// List available (compiled) resources (stored in the rust binary)
/// RESULT:
/// vector of string of resource names that can be loaded
#[cfg(feature = "resources")]
fn list_resources() -> Vec<String> {
resources::list_resources(Self::RESOURCE_PREFIX)
}

/// Read (deserialize) an object from a resource file packaged with the `fastsim-core` crate
///
/// # Arguments:
Expand Down
13 changes: 10 additions & 3 deletions rust/fastsim-core/src/vehicle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ lazy_static! {
self.clone()
}
#[pyo3(name = "list_resources")]
/// list available vehicle resources
pub fn list_resources_py(&self) -> Vec<String> {
RustVehicle::list_resources()
}
#[staticmethod]
#[pyo3(name = "mock_vehicle")]
fn mock_vehicle_py() -> Self {
Expand Down Expand Up @@ -771,7 +777,8 @@ impl RustVehicle {
self.modern_max = MODERN_MAX;
}
let modern_diff = self.modern_max - arrmax(&LARGE_BASELINE_EFF);
let large_baseline_eff_adj: Vec<f64> = LARGE_BASELINE_EFF.iter().map(|x| x + modern_diff).collect();
let large_baseline_eff_adj: Vec<f64> =
LARGE_BASELINE_EFF.iter().map(|x| x + modern_diff).collect();
let mc_kw_adj_perc = max(
0.0,
min(
Expand Down Expand Up @@ -1068,8 +1075,8 @@ impl RustVehicle {
}
None => Self::VEHICLE_DIRECTORY_URL.to_string() + vehicle_file_name.as_ref(),
};
let mut vehicle =
Self::from_url(&url_internal, false).with_context(|| "Could not parse vehicle from url")?;
let mut vehicle = Self::from_url(&url_internal, false)
.with_context(|| "Could not parse vehicle from url")?;
let vehicle_origin = "Vehicle from ".to_owned() + url_internal.as_str();
vehicle.doc = Some(vehicle_origin);
Ok(vehicle)
Expand Down

0 comments on commit 73ffd38

Please sign in to comment.