Skip to content

Commit

Permalink
add import/parse of appliance propensities to FHS
Browse files Browse the repository at this point in the history
  • Loading branch information
shieldo committed Sep 19, 2024
1 parent d56eb18 commit e948c4e
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 14 deletions.
50 changes: 36 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,16 @@ pub fn run_project(
let heat_capacity_parameter = corpus.calc_hcp();
let heat_loss_form_factor = corpus.calc_hlff();

write_core_output_file_static(&output, StaticOutputFileArgs {
output_key: "results_static".to_string(),
heat_transfer_coefficient,
heat_loss_parameter,
heat_capacity_parameter,
heat_loss_form_factor
})?;
write_core_output_file_static(
&output,
StaticOutputFileArgs {
output_key: "results_static".to_string(),
heat_transfer_coefficient,
heat_loss_parameter,
heat_capacity_parameter,
heat_loss_form_factor,
},
)?;

if fhs_assumptions || fhs_not_a_assumptions || fhs_not_b_assumptions {
let notional = fhs_not_a_assumptions || fhs_not_b_assumptions;
Expand Down Expand Up @@ -1105,27 +1108,46 @@ struct StaticOutputFileArgs {
heat_transfer_coefficient: f64,
heat_loss_parameter: f64,
heat_capacity_parameter: f64,
heat_loss_form_factor: f64
heat_loss_form_factor: f64,
}

fn write_core_output_file_static(output: &impl Output, args: StaticOutputFileArgs) -> Result<(), anyhow::Error> {
fn write_core_output_file_static(
output: &impl Output,
args: StaticOutputFileArgs,
) -> Result<(), anyhow::Error> {
let StaticOutputFileArgs {
output_key,
heat_transfer_coefficient,
heat_loss_parameter,
heat_capacity_parameter,
heat_loss_form_factor
heat_loss_form_factor,
} = args;

println!("writing out to {output_key}");

let writer = output.writer_for_location_key(&output_key)?;
let mut writer = WriterBuilder::new().flexible(true).from_writer(writer);

writer.write_record(["Heat transfer coefficient".to_owned(), "W / K".to_owned(), heat_transfer_coefficient.to_string() ])?;
writer.write_record(["Heat loss parameter".to_owned(), "W / m2.K".to_owned(), heat_loss_parameter.to_string() ])?;
writer.write_record(["Heat capacity parameter".to_owned(), "kJ / m2.K".to_owned(), heat_capacity_parameter.to_string() ])?;
writer.write_record(["Heat loss form factor".to_owned(), "".to_owned(), heat_loss_form_factor.to_string() ])?;
writer.write_record([
"Heat transfer coefficient".to_owned(),
"W / K".to_owned(),
heat_transfer_coefficient.to_string(),
])?;
writer.write_record([
"Heat loss parameter".to_owned(),
"W / m2.K".to_owned(),
heat_loss_parameter.to_string(),
])?;
writer.write_record([
"Heat capacity parameter".to_owned(),
"kJ / m2.K".to_owned(),
heat_capacity_parameter.to_string(),
])?;
writer.write_record([
"Heat loss form factor".to_owned(),
"".to_owned(),
heat_loss_form_factor.to_string(),
])?;

println!("flushing out static CSV");
writer.flush()?;
Expand Down
183 changes: 183 additions & 0 deletions src/wrappers/future_homes_standard/future_homes_standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use serde_json::{json, Number, Value};
use std::collections::{HashMap, HashSet};
use std::io::{BufReader, Cursor, Read};
use std::iter::{repeat, zip};
use std::marker::PhantomData;

const _EMIS_FACTOR_NAME: &str = "Emissions Factor kgCO2e/kWh";
const _EMIS_OOS_FACTOR_NAME: &str = "Emissions Factor kgCO2e/kWh including out-of-scope emissions";
Expand Down Expand Up @@ -111,6 +112,9 @@ lazy_static! {
static ref COLD_WATER_LOSS_PROFILE_DATA: Vec<EvaporativeProfile> =
load_evaporative_profile(Cursor::new(include_str!("./cold_water_loss_profile.csv")))
.expect("Could not read cold_water_loss_profile.csv");
static ref APPLIANCE_PROPENSITIES: AppliancePropensities<Normalised> =
load_appliance_propensities(Cursor::new(include_str!("./appliance_propensities.csv")))
.expect("Could not read and parse appliance_propensities.csv");
}

#[derive(Clone, Debug, Deserialize)]
Expand Down Expand Up @@ -821,6 +825,185 @@ fn create_evaporative_losses(
Ok(())
}

fn load_appliance_propensities(
file: impl Read,
) -> anyhow::Result<AppliancePropensities<Normalised>> {
let mut propensities_reader = Reader::from_reader(BufReader::new(file));
let appliance_propensities_rows: Vec<AppliancePropensityRow> = propensities_reader
.deserialize()
.collect::<Result<Vec<AppliancePropensityRow>, _>>()
.expect("Could not parse out appliance propensities CSV file correctly.");

let (
hour,
occupied,
cleaning_washing_machine,
cleaning_tumble_dryer,
cleaning_dishwasher,
cooking_electric_oven,
cooking_microwave,
cooking_kettle,
cooking_gas_cooker,
consumer_electronics,
): (
[usize; 24],
[f64; 24],
[f64; 24],
[f64; 24],
[f64; 24],
[f64; 24],
[f64; 24],
[f64; 24],
[f64; 24],
[f64; 24],
) = appliance_propensities_rows.iter().enumerate().fold(
Default::default(),
|acc, (i, item)| {
let (
mut hour,
mut occupied,
mut cleaning_washing_machine,
mut cleaning_tumble_dryer,
mut cleaning_dishwasher,
mut cooking_electric_oven,
mut cooking_microwave,
mut cooking_kettle,
mut cooking_gas_cooker,
mut consumer_electronics,
) = acc;
hour[i] = item.hour;
occupied[i] = item.occupied;
cleaning_washing_machine[i] = item.cleaning_washing_machine;
cleaning_tumble_dryer[i] = item.cleaning_tumble_dryer;
cleaning_dishwasher[i] = item.cleaning_dishwasher;
cooking_electric_oven[i] = item.cooking_electric_oven;
cooking_microwave[i] = item.cooking_microwave;
cooking_kettle[i] = item.cooking_kettle;
cooking_gas_cooker[i] = item.cooking_gas_cooker;
consumer_electronics[i] = item.consumer_electronics;
acc
},
);
Ok(AppliancePropensities {
hour: hour.try_into()?,
occupied: occupied.try_into()?,
cleaning_washing_machine: cleaning_washing_machine.try_into()?,
cleaning_tumble_dryer,
cleaning_dishwasher,
cooking_electric_oven,
cooking_microwave,
cooking_kettle,
cooking_gas_cooker,
consumer_electronics,
state: Default::default(),
}
.normalise())
}

// + appliance_propensities_file = os.path.join(this_directory, 'appliance_propensities.csv')
// + with open(appliance_propensities_file,'r') as appfile:
// + appfilereader = csv.DictReader(appfile)
// + appliance_propensities = {fieldname:[] for fieldname in appfilereader.fieldnames}
// + for row in appfilereader:
// + for key in row.keys():
// + appliance_propensities[key].append(float(row[key]))
// + #normalise appliance propensities, but not occupancy
// + for key in list(appliance_propensities.keys())[2:]:
// + sumcol = sum(appliance_propensities[key])
// + appliance_propensities[key] = [ x / sumcol for x in appliance_propensities[key]]

#[derive(Copy, Clone)]
struct AppliancePropensities<T> {
hour: [usize; 24],
occupied: [f64; 24],
cleaning_washing_machine: [f64; 24],
cleaning_tumble_dryer: [f64; 24],
cleaning_dishwasher: [f64; 24],
cooking_electric_oven: [f64; 24],
cooking_microwave: [f64; 24],
cooking_kettle: [f64; 24],
cooking_gas_cooker: [f64; 24],
consumer_electronics: [f64; 24],
state: PhantomData<T>,
}

impl AppliancePropensities<AsDataFile> {
fn normalise(self) -> AppliancePropensities<Normalised> {
let AppliancePropensities {
cleaning_washing_machine,
cleaning_tumble_dryer,
cleaning_dishwasher,
cooking_electric_oven,
cooking_microwave,
cooking_kettle,
cooking_gas_cooker,
consumer_electronics,
..
} = self;

let [cleaning_washing_machine, cleaning_tumble_dryer, cleaning_dishwasher, cooking_electric_oven, cooking_microwave, cooking_kettle, cooking_gas_cooker, consumer_electronics] =
[
cleaning_washing_machine,
cleaning_tumble_dryer,
cleaning_dishwasher,
cooking_electric_oven,
cooking_microwave,
cooking_kettle,
cooking_gas_cooker,
consumer_electronics,
]
.into_iter()
.map(|probabilities| -> [f64; 24] {
let sumcol = probabilities.iter().sum::<f64>();
probabilities.map(|x| x / sumcol)
})
.collect::<Vec<_>>()
.try_into()
.expect("Problem normalising appliance propensities.");

AppliancePropensities {
hour: self.hour,
occupied: self.occupied,
cleaning_washing_machine,
cleaning_tumble_dryer,
cleaning_dishwasher,
cooking_electric_oven,
cooking_microwave,
cooking_kettle,
cooking_gas_cooker,
consumer_electronics,
state: Default::default(),
}
}
}

struct AsDataFile;
struct Normalised;

#[derive(Deserialize)]
struct AppliancePropensityRow {
#[serde(rename = "Hour")]
hour: usize,
#[serde(rename = "Occupied prop ( Chance the house is occupied)")]
occupied: f64,
#[serde(rename = "Cleaning Washing machine Prop")]
cleaning_washing_machine: f64,
#[serde(rename = "Cleaning Tumble dryer")]
cleaning_tumble_dryer: f64,
#[serde(rename = "Cleaning Dishwasher")]
cleaning_dishwasher: f64,
#[serde(rename = "Cooking Electric Oven")]
cooking_electric_oven: f64,
#[serde(rename = "Cooking Microwave")]
cooking_microwave: f64,
#[serde(rename = "Cooking Kettle")]
cooking_kettle: f64,
#[serde(rename = "Cooking Gas Cooker")]
cooking_gas_cooker: f64,
#[serde(rename = "Consumer Electronics")]
consumer_electronics: f64,
}

/// Calculate the annual energy requirement in kWh using the procedure described in SAP 10.2 up to and including step 9.
/// Divide this by 365 to get the average daily energy use.
/// Multiply the daily energy consumption figure by the following profiles to
Expand Down

0 comments on commit e948c4e

Please sign in to comment.