Skip to content

Commit

Permalink
allow collection of extra, 'non-core' controls
Browse files Browse the repository at this point in the history
  • Loading branch information
shieldo committed Jan 29, 2024
1 parent cce938c commit 9439d40
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 38 deletions.
11 changes: 7 additions & 4 deletions src/core/heating_systems/storage_tank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1347,10 +1347,13 @@ mod tests {
55.0,
cold_water_source,
simulation_time_for_storage_tank.step,
&Controls::new(vec![HeatSourceControl::new(
Some(control_for_storage_tank.clone()),
None,
)]),
&Controls::new(
vec![HeatSourceControl::new(
Some(control_for_storage_tank.clone()),
None,
)],
Default::default(),
),
HashMap::from([(
"imheater".to_string(),
HeatSourceInput::ImmersionHeater {
Expand Down
51 changes: 35 additions & 16 deletions src/corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,44 +390,54 @@ fn internal_gains_from_details(details: InternalGainsDetails) -> InternalGains {
)
}

pub struct Controls(Vec<HeatSourceControl<Option<Arc<Control>>>>);

impl Deref for Controls {
type Target = Vec<HeatSourceControl<Option<Arc<Control>>>>;

fn deref(&self) -> &Self::Target {
&self.0
}
pub struct Controls {
core: Vec<HeatSourceControl<Option<Arc<Control>>>>,
extra: HashMap<String, Arc<Control>>,
}

impl Controls {
pub fn new(controls: <Self as Deref>::Target) -> Self {
Self(controls)
pub fn new(
core: Vec<HeatSourceControl<Option<Arc<Control>>>>,
extra: HashMap<String, Arc<Control>>,
) -> Self {
Self { core, extra }
}

pub fn get(&self, control_type: &HeatSourceControlType) -> Option<&Arc<Control>> {
self.iter()
self.core
.iter()
.find(|heat_source_control| heat_source_control.get(control_type).is_some())
.and_then(|heat_source_control| heat_source_control.get(control_type).unwrap().as_ref())
}

// access a control using a string, possibly because it is one of the "extra" controls
pub fn get_with_string(&self, control_name: &str) -> Option<&Arc<Control>> {
match control_name {
// hard-code ways of resolving to core control types (for now)
"hw timer" => self.get(&HeatSourceControlType::HotWaterTimer),
"window opening" => self.get(&HeatSourceControlType::WindowOpening),
other => self.extra.get(other),
}
}
}

fn control_from_input(
control_input: ControlInput,
simulation_time_iterator: &SimulationTimeIterator,
) -> Controls {
let mut controls: Vec<HeatSourceControl<Option<Arc<Control>>>> = vec![];
let mut core: Vec<HeatSourceControl<Option<Arc<Control>>>> = Default::default();
let mut extra: HashMap<String, Arc<Control>> = Default::default();

// this is very ugly(!) but is just a reflection of the lack of clarity in the schema
// and the way the variants-struct crate works;
// we should be able to improve it in time
for control in control_input {
for control in control_input.core {
match control {
HeatSourceControl {
hot_water_timer: Some(control),
..
} => {
controls.push(HeatSourceControl::new(
core.push(HeatSourceControl::new(
Some(Arc::new(single_control_from_details(
control,
simulation_time_iterator,
Expand All @@ -439,7 +449,7 @@ fn control_from_input(
window_opening: Some(control),
..
} => {
controls.push(HeatSourceControl::new(
core.push(HeatSourceControl::new(
None,
Some(Arc::new(single_control_from_details(
control,
Expand All @@ -453,8 +463,17 @@ fn control_from_input(
),
}
}
for (name, control) in control_input.extra {
extra.insert(
name,
Arc::new(single_control_from_details(
control,
simulation_time_iterator,
)),
);
}

Controls(controls)
Controls { core, extra }
}

fn single_control_from_details(
Expand Down
44 changes: 26 additions & 18 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,34 +246,42 @@ pub struct ColdWaterSourceDetails {

pub type Schedule = HashMap<String, Value>; // TODO: possible values are too undefined and unpredictable to reverse-engineer at time of writing! (2023-07-06)

pub type Control = Vec<HeatSourceControl<Option<ControlDetails>>>;
pub type CoreControls = Vec<HeatSourceControl<Option<ControlDetails>>>;

pub type ExtraControls = HashMap<String, ControlDetails>;

#[derive(Debug)]
pub struct Control {
pub core: CoreControls,
pub extra: ExtraControls,
}

// specialised deserialisation logic for converting a map of controls into a list of HeatSourceControl structs
fn deserialize_control<'de, D>(deserializer: D) -> Result<Control, D::Error>
where
D: Deserializer<'de>,
{
let map: HashMap<String, ControlDetails> = Deserialize::deserialize(deserializer)?;
let mut controls: Control = vec![];
let mut core: CoreControls = Default::default();
let mut extra: ExtraControls = Default::default();
for (control_type, control_details) in map {
controls.push(match control_type.as_str() {
match control_type.as_str() {
// following strings need to be in sync with HeatSourceControlType known values
"hw timer" => HeatSourceControl::new(Some(control_details), None),
"window opening" => HeatSourceControl::new(None, Some(control_details)),
// there are some erroneous-looking entries like "hw timer 2" and "zone 1 radiators timer"
// in the example JSON, even though nothing looks likely to read them -
// for now let's just allow but ignore these extra controls
_ => continue,
// NB. following is code that could be used for rejecting values when parsing:
// other => {
// return Err(serde::de::Error::invalid_value(
// serde::de::Unexpected::Str(other),
// &"hw timer or similar",
// ))
// }
});
"hw timer" => {
core.push(HeatSourceControl::new(Some(control_details), None));
}
"window opening" => {
core.push(HeatSourceControl::new(None, Some(control_details)));
}
// there are some extra control definitions from time to time called things like
// "hw timer 2" and "zone 1 radiators timer" - can only presume now to store these keys as-is
// and perhaps match on other references
other => {
extra.insert(other.to_string(), control_details);
}
}
}
Ok(controls)
Ok(Control { core, extra })
}

#[derive(Debug, Deserialize)]
Expand Down

0 comments on commit 9439d40

Please sign in to comment.