Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BEL can fail trace without triggering error #99

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions python/altrios/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from pkg_resources import get_distribution
__version__ = get_distribution("altrios").version

from importlib.metadata import version
__version__ = version("altrios")
from pathlib import Path
import re
import numpy as np
Expand Down Expand Up @@ -48,7 +47,7 @@ def variable_path_list(self, element_as_list:bool=False) -> List[str]:
# Arguments:
- `element_as_list`: if True, each element is itself a list of the path elements
"""
return variable_path_list_from_py_objs(self.to_pydict(), element_as_list=element_as_list)
return variable_path_list_from_py_objs(self.to_pydict(flatten=False), element_as_list=element_as_list)

def variable_path_list_from_py_objs(
obj: Union[Dict, List],
Expand Down Expand Up @@ -121,25 +120,32 @@ def history_path_list(self, element_as_list:bool=False) -> List[str]:
]
return history_path_list

def to_pydict(self) -> Dict:
def to_pydict(self, flatten: bool=True) -> Dict:
"""
Returns self converted to pure python dictionary with no nested Rust objects
# Arguments
- `flatten`: if True, returns dict without any hierarchy
"""
from yaml import load
try:
from yaml import CLoader as Loader
except ImportError:
from yaml import Loader
pydict = load(self.to_yaml(), Loader = Loader)
return pydict

pydict = load(self.to_yaml(), Loader=Loader)
if not flatten:
return pydict
else:
return next(iter(pd.json_normalize(pydict, sep=".").to_dict(orient='records')))

@classmethod
def from_pydict(cls, pydict: Dict) -> Self:
"""
Instantiates Self from pure python dictionary
"""
import yaml
return cls.from_yaml(yaml.dump(pydict),skip_init=False)
return cls.from_yaml(yaml.dump(pydict))


def to_dataframe(self, pandas:bool=False) -> [pd.DataFrame, pl.DataFrame, pl.LazyFrame]:
"""
Expand All @@ -148,7 +154,7 @@ def to_dataframe(self, pandas:bool=False) -> [pd.DataFrame, pl.DataFrame, pl.Laz
# Arguments
- `pandas`: returns pandas dataframe if True; otherwise, returns polars dataframe by default
"""
obj_dict = self.to_pydict()
obj_dict = self.to_pydict(flatten=False)
history_paths = self.history_path_list(element_as_list=True)
cols = [".".join(hp) for hp in history_paths]
vals = []
Expand Down
1 change: 1 addition & 0 deletions python/altrios/altrios_pyo3.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ class LocomotiveSimulation(SerdeAPI):
i: int
loco_unit: Locomotive
power_trace: PowerTrace
allow_trace_miss: bool
@classmethod
def __init__(cls) -> None: ...
def clone(self) -> Self: ...
Expand Down
8 changes: 6 additions & 2 deletions python/altrios/demos/bel_demo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# %% Copied from ALTRIOS version 'v0.2.3'. Guaranteed compatibility with this version only.
# %%
# Script for running the Wabtech BEL consist for sample data from Barstow to Stockton
# Consist comprises [2X Tier 4](https://www.wabteccorp.com/media/3641/download?inline)
Expand All @@ -10,6 +11,7 @@
import time
import os
import seaborn as sns
import pandas as pd

sns.set_theme()

Expand Down Expand Up @@ -44,7 +46,7 @@

# instantiate battery model
t0 = time.perf_counter()
sim = alt.LocomotiveSimulation(bel, pt, SAVE_INTERVAL)
sim = alt.LocomotiveSimulation(bel, pt, False, SAVE_INTERVAL)
t1 = time.perf_counter()
print(f"Time to load: {t1-t0:.3g}")

Expand All @@ -54,7 +56,7 @@
t1 = time.perf_counter()
print(f"Time to simulate: {t1-t0:.5g}")


#%%
bel_rslt = sim.loco_unit
t_s = np.array(sim.power_trace.time_seconds)

Expand Down Expand Up @@ -102,3 +104,5 @@
if SHOW_PLOTS:
plt.tight_layout()
plt.show()

# %%
2 changes: 1 addition & 1 deletion python/altrios/demos/conv_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

pt = alt.PowerTrace.default()

sim = alt.LocomotiveSimulation(conv, pt, SAVE_INTERVAL)
sim = alt.LocomotiveSimulation(conv, pt, save_interval=SAVE_INTERVAL)
t1 = time.perf_counter()

print(f"Time to load: {t1-t0:.3g}")
Expand Down
4 changes: 2 additions & 2 deletions python/altrios/tests/mock_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ def mock_locomotive_simulation(
pt: alt.PowerTrace = mock_power_trace(),
save_interval: Optional[int] = 1,
) -> alt.LocomotiveSimulation:
if not loco:
if loco is None:
loco = mock_conventional_loco(save_interval=save_interval)
sim = alt.LocomotiveSimulation(loco, pt, save_interval)
sim = alt.LocomotiveSimulation(loco, pt, False, save_interval)
return sim


Expand Down
48 changes: 31 additions & 17 deletions rust/altrios-core/src/consist/locomotive/loco_sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,10 @@ pub struct PowerTraceElement {
fn __new__(
loco_unit: Locomotive,
power_trace: PowerTrace,
allow_trace_miss: Option<bool>,
save_interval: Option<usize>,
) -> Self {
Self::new(loco_unit, power_trace, save_interval)
Self::new(loco_unit, power_trace, allow_trace_miss.unwrap_or_default(), save_interval)
}

#[pyo3(name = "walk")]
Expand Down Expand Up @@ -178,18 +179,23 @@ pub struct PowerTraceElement {
pub struct LocomotiveSimulation {
pub loco_unit: Locomotive,
pub power_trace: PowerTrace,
/// Whether to allow the Locomotive to miss the power trace. If true, the
/// locomotive will produce whatever power it can.
pub allow_trace_miss: bool,
pub i: usize,
}

impl LocomotiveSimulation {
pub fn new(
loco_unit: Locomotive,
power_trace: PowerTrace,
allow_trace_miss: bool,
save_interval: Option<usize>,
) -> Self {
let mut loco_sim = Self {
loco_unit,
power_trace,
allow_trace_miss,
i: 1,
};
loco_sim.loco_unit.set_save_interval(save_interval);
Expand All @@ -216,7 +222,7 @@ impl LocomotiveSimulation {

pub fn step(&mut self) -> anyhow::Result<()> {
self.solve_step()
.map_err(|err| err.context(format!("time step: {}", self.i)))?;
.with_context(|| format!("time step: {}", self.i))?;
self.save_state();
self.i += 1;
self.loco_unit.step();
Expand All @@ -232,24 +238,32 @@ impl LocomotiveSimulation {
self.loco_unit
.set_cur_pwr_max_out(None, self.power_trace.dt(self.i))?;
self.solve_energy_consumption(
self.power_trace.pwr[self.i],
if self.allow_trace_miss {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SWRIganderson , this did it!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@calbaker I'll check this out tonight.

self.power_trace.pwr[self.i]
.min(self.loco_unit.state.pwr_out_max)
.max(-self.loco_unit.state.pwr_regen_max)
} else {
self.power_trace.pwr[self.i]
},
self.power_trace.dt(self.i),
engine_on,
)?;
ensure!(
utils::almost_eq_uom(
&self.power_trace.pwr[self.i],
&self.loco_unit.state.pwr_out,
None
),
format_dbg!(
(utils::almost_eq_uom(
if !self.allow_trace_miss {
ensure!(
utils::almost_eq_uom(
&self.power_trace.pwr[self.i],
&self.loco_unit.state.pwr_out,
None
))
)
);
),
format_dbg!(
(utils::almost_eq_uom(
&self.power_trace.pwr[self.i],
&self.loco_unit.state.pwr_out,
None
))
)
);
}
Ok(())
}

Expand Down Expand Up @@ -297,7 +311,7 @@ impl Default for LocomotiveSimulation {
fn default() -> Self {
let power_trace = PowerTrace::default();
let loco_unit = Locomotive::default();
Self::new(loco_unit, power_trace, None)
Self::new(loco_unit, power_trace, false, None)
}
}

Expand Down Expand Up @@ -390,7 +404,7 @@ mod tests {
fn test_conventional_locomotive_sim() {
let cl = Locomotive::default();
let pt = PowerTrace::default();
let mut loco_sim = LocomotiveSimulation::new(cl, pt, None);
let mut loco_sim = LocomotiveSimulation::new(cl, pt, false, None);
loco_sim.walk().unwrap();
}

Expand All @@ -410,7 +424,7 @@ mod tests {
fn test_battery_locomotive_sim() {
let bel = Locomotive::default_battery_electric_loco();
let pt = PowerTrace::default();
let mut loco_sim = LocomotiveSimulation::new(bel, pt, None);
let mut loco_sim = LocomotiveSimulation::new(bel, pt, false, None);
loco_sim.walk().unwrap();
}

Expand Down
Loading