fastsim_core/vehicle/powertrain/
fuel_storage.rs1use super::*;
2
3#[serde_api]
4#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, SetCumulative)]
5#[cfg_attr(feature = "pyo3", pyclass(module = "fastsim", subclass, eq))]
6#[non_exhaustive]
7#[serde(deny_unknown_fields)]
8pub struct FuelStorage {
9 pub pwr_out_max: si::Power,
11 pub pwr_ramp_lag: si::Time,
13 pub energy_capacity: si::Energy,
15 pub(in super::super) specific_energy: Option<si::SpecificEnergy>,
17 #[serde(default)]
19 pub(in super::super) mass: Option<si::Mass>,
20 }
23
24#[pyo3_api]
25impl FuelStorage {
26 }
38
39impl SerdeAPI for FuelStorage {}
40impl Init for FuelStorage {}
41
42impl Mass for FuelStorage {
43 fn mass(&self) -> anyhow::Result<Option<si::Mass>> {
44 let derived_mass = self
45 .derived_mass()
46 .with_context(|| anyhow!(format_dbg!()))?;
47 if let (Some(derived_mass), Some(set_mass)) = (derived_mass, self.mass) {
48 ensure!(
49 utils::almost_eq_uom(&set_mass, &derived_mass, None),
50 format!(
51 "{}",
52 format_dbg!(utils::almost_eq_uom(&set_mass, &derived_mass, None)),
53 )
54 );
55 }
56 Ok(self.mass)
57 }
58
59 fn set_mass(
60 &mut self,
61 new_mass: Option<si::Mass>,
62 side_effect: MassSideEffect,
63 ) -> anyhow::Result<()> {
64 let derived_mass = self
65 .derived_mass()
66 .with_context(|| anyhow!(format_dbg!()))?;
67 if let (Some(derived_mass), Some(new_mass)) = (derived_mass, new_mass) {
68 if derived_mass != new_mass {
69 match side_effect {
70 MassSideEffect::Extensive => {
71 self.energy_capacity = self.specific_energy.with_context(|| {
72 format!(
73 "{}\nExpected `self.specific_energy` to be `Some`.",
74 format_dbg!()
75 )
76 })? * new_mass;
77 }
78 MassSideEffect::Intensive => {
79 self.specific_energy = Some(self.energy_capacity / new_mass);
80 }
81 MassSideEffect::None => {
82 self.specific_energy = None;
83 }
84 }
85 }
86 } else if new_mass.is_none() {
87 self.specific_energy = None;
88 }
89 self.mass = new_mass;
90
91 Ok(())
92 }
93
94 fn derived_mass(&self) -> anyhow::Result<Option<si::Mass>> {
95 Ok(self
96 .specific_energy
97 .map(|specific_energy| self.energy_capacity / specific_energy))
98 }
99
100 fn expunge_mass_fields(&mut self) {
101 self.mass = None;
102 self.specific_energy = None;
103 }
104}