forked from s_ranjbar/city_retrofit
Merge branch 'hp_energy_demand' into db_persistence
This commit is contained in:
commit
7974317d13
|
@ -13,13 +13,12 @@ Cp: 4190
|
|||
Rhow: 1000
|
||||
TESDiameter: 5
|
||||
AuxHeaterEfficiency: 0.9
|
||||
|
||||
HPNominalCapacity: 256
|
||||
# These come from the data model according to other student's work
|
||||
ElecGridEF: 0.5
|
||||
ElectricityPrice: 0.073
|
||||
|
||||
# Water to Water HP constants
|
||||
HPNominalCapacity: 256
|
||||
LowestPossibleLoadFlow: 4.73
|
||||
HighestPossibleLoadFlow: 9.46
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
from exports.energy_systems.heat_pump_export import HeatPumpExport
|
||||
from typing import List, Tuple, Union
|
||||
from typing import List, Dict, Union
|
||||
|
||||
|
||||
class AirSourceHPExport(HeatPumpExport):
|
||||
|
@ -15,17 +15,18 @@ class AirSourceHPExport(HeatPumpExport):
|
|||
after executing insel
|
||||
"""
|
||||
|
||||
def __init__(self, base_path, city, output_path, sim_type):
|
||||
def __init__(self, base_path, city, output_path, sim_type, demand_path=None):
|
||||
"""
|
||||
|
||||
:param base_path: path to energy system files
|
||||
:param city: the city object
|
||||
:param output_path: the file to hold insel simulation results
|
||||
:param sim_type: the simulation type to run: 0 for series, 1 for parallel
|
||||
:param demand_path: path to hourly energy demand file
|
||||
"""
|
||||
tmp_file = 'heat_pumps/as_series.txt' if sim_type == 0 else 'heat_pumps/as_parallel.txt'
|
||||
template_path = (base_path / tmp_file)
|
||||
super().__init__(base_path, city, output_path, template_path)
|
||||
super().__init__(base_path, city, output_path, template_path, demand_path)
|
||||
|
||||
def _extract_model_coff(self, hp_model: str, data_type='heat') -> Union[List, None]:
|
||||
"""
|
||||
|
@ -43,7 +44,7 @@ class AirSourceHPExport(HeatPumpExport):
|
|||
return energy_system.air_source_hp.cooling_capacity_coff
|
||||
return None
|
||||
|
||||
def execute_insel(self, user_input, hp_model, data_type):
|
||||
def execute_insel(self, user_input, hp_model, data_type) -> Union[Dict, None]:
|
||||
"""
|
||||
Runs insel and produces output files
|
||||
Runs insel and write the necessary files
|
||||
|
@ -54,7 +55,6 @@ class AirSourceHPExport(HeatPumpExport):
|
|||
:param data_type: a string that indicates whether
|
||||
insel should run for heat or cooling performance
|
||||
:return:
|
||||
:return:
|
||||
"""
|
||||
capacity_coeff = self._extract_model_coff(hp_model, data_type)
|
||||
super(AirSourceHPExport, self)._run_insel(user_input, capacity_coeff, 'air_source.insel')
|
||||
return super(AirSourceHPExport, self)._run_insel(user_input, capacity_coeff, 'air_source.insel')
|
||||
|
|
|
@ -5,7 +5,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
import os
|
||||
from typing import List, Tuple, Union, Dict
|
||||
from typing import List, Union, Dict
|
||||
import yaml
|
||||
from string import Template
|
||||
import pandas as pd
|
||||
|
@ -17,18 +17,18 @@ class HeatPumpExport:
|
|||
of some defined function
|
||||
"""
|
||||
|
||||
def __init__(self, base_path, city, output_path, template, water_temp=None):
|
||||
def __init__(self, base_path, city, output_path, template, demand_path=None, water_temp=None):
|
||||
self._template_path = template
|
||||
self._water_temp = water_temp
|
||||
self._constants_path = (base_path / 'heat_pumps/constants.yaml')
|
||||
# needed to compute max demand.
|
||||
self._demand_path = (base_path / 'heat_pumps/demand.txt')
|
||||
self._demand_path = (base_path / 'heat_pumps/demand.txt') if demand_path is None else demand_path
|
||||
self._city = city
|
||||
self._input_data = None
|
||||
self._base_path = base_path
|
||||
self._output_path = output_path
|
||||
|
||||
def _run_insel(self, user_input: Dict, capacity_coeff: List, filename: str) -> None:
|
||||
def _run_insel(self, user_input: Dict, capacity_coeff: List, filename: str) -> Union[Dict, None]:
|
||||
"""
|
||||
Runs insel and write the necessary files
|
||||
:param user_input: a dictionary containing the user
|
||||
|
@ -60,7 +60,7 @@ class HeatPumpExport:
|
|||
# Writer headers to csv output files generated by insel
|
||||
self._write_insel_output_headers()
|
||||
# User output
|
||||
self._get_user_out_put()
|
||||
return self._get_user_out_put()
|
||||
except IOError as err:
|
||||
print("I/O exception: {}".format(err))
|
||||
finally:
|
||||
|
@ -72,8 +72,22 @@ class HeatPumpExport:
|
|||
Write headers to the various csv file generated by insel
|
||||
:return:
|
||||
"""
|
||||
header_data = {
|
||||
self._input_data['fileOut1']: ['Year', ' Month', ' Day', 'Hour', 'Minute', 'HP Heat Output (kW)',
|
||||
header = [
|
||||
'Year', ' Month', ' Day', 'Hour', 'Minute', 'HP Heat Output (kW)', 'Heating Demand (kW)', 'HP output flow rate',
|
||||
'Building Required Flow Rate', 'TES Charging Rate (kg/s)', 'Water Flow Rate After Splitter',
|
||||
'water temperature after splitter', 'TES Discharging Rate (kg/s)', 'TES discharge temperature',
|
||||
'Mixer Outlet Flow Rate (kg/s)', 'Mixer outlet temperature', 'Auxiliary heater fuel flow rate',
|
||||
'Auxiliary heater energy input (kW)', 'Building Inlet Flow Rate (kg/s)', 'Building inlet temperature',
|
||||
'Building return temperature', 'TES Return Flow Rate (kg/s)', 'TES return temperature',
|
||||
'TES Bypass Line Flow Rate (kg/s)', 'TES bypass line temperature', 'Flow Rate from TES to mixer 2 (kg/s)',
|
||||
'Temperature from Tes to mixer', 'HP Inlet Flow Rate (kg/s)', 'HP Inlet temperature', 'TES Node 1 Temperature',
|
||||
'TES Node 2 Temperature', 'TES Node 3 Temperature', 'TES Node 4 Temperature', 'TES Energy Content (J)',
|
||||
'HP Electricity Consumption (kW)', 'HP COP', 'Ambient Temperature', 'HP Operational Cost (CAD)',
|
||||
'Auxiliary Heater Operational Cost (CAD)', 'Operational CO2 Emissions of HP (g)',
|
||||
'Operational CO2 Emissions of Auxiliary Heater (g)']
|
||||
if 'series' in str(self._template_path):
|
||||
header = [
|
||||
'Year', ' Month', ' Day', 'Hour', 'Minute', 'HP Heat Output (kW)',
|
||||
'HP Electricity Consumption (kW)', 'HP COP', 'TES Charging Rate (kg/s)',
|
||||
'TES Discharging Rate (kg/s)', 'TES Node 1 Temperature', 'TES Node 2 Temperature',
|
||||
'TES Node 3 Temperature', 'TES Node 4 Temperature', 'TES Energy Content (J)',
|
||||
|
@ -82,7 +96,9 @@ class HeatPumpExport:
|
|||
'HP Operational Cost (CAD)', 'Auxiliary Heater Operational Cost (CAD)',
|
||||
'Operational CO2 Emissions of HP (g)',
|
||||
'Operational CO2 Emissions of Auxiliary Heater (g)',
|
||||
'Return Temperature', 'Demand (kW)'],
|
||||
'Return Temperature', 'Demand (kW)']
|
||||
header_data = {
|
||||
self._input_data['fileOut1']: header,
|
||||
self._input_data['fileOut2']: ['Day', 'Operational Daily Emissions from Heat Pumps (g)',
|
||||
'Operational Daily Emissions from Auxiliary Heater (g)'],
|
||||
self._input_data['fileOut3']: ['Month', 'Monthly Operational Costs of Heat Pumps (CAD)',
|
||||
|
@ -102,7 +118,7 @@ class HeatPumpExport:
|
|||
file_path = file_path.strip("'")
|
||||
df = pd.read_csv(file_path, header=None, sep='\s+')
|
||||
# ignore ambient temperature for air source series run
|
||||
if df.shape[1] > 25:
|
||||
if df.shape[1] > 25 and 'series' in str(self._template_path):
|
||||
df.drop(columns=df.columns[-1],
|
||||
axis=1,
|
||||
inplace=True)
|
||||
|
@ -161,6 +177,8 @@ class HeatPumpExport:
|
|||
with open(self._constants_path) as file:
|
||||
constants_dict = yaml.load(file, Loader=yaml.FullLoader)
|
||||
for key, value in constants_dict.items():
|
||||
if key in ['LowestPossibleLoadFlow', 'HighestPossibleLoadFlow'] and self._water_temp is None:
|
||||
continue
|
||||
self._input_data[key] = value
|
||||
# compute water to water HP specific values
|
||||
if 55 <= self._input_data['HPSupTemp'] <= 60:
|
||||
|
@ -206,15 +224,30 @@ class HeatPumpExport:
|
|||
self._input_data["a10"] = a_coeff[9]
|
||||
self._input_data["a11"] = a_coeff[10]
|
||||
|
||||
def _get_user_out_put(self):
|
||||
def _get_user_out_put(self) -> Union[Dict, None]:
|
||||
"""
|
||||
Extracts monthly electricity demand and fossil fuel consumption
|
||||
from output files generated by insel
|
||||
:return:
|
||||
:return: Dict for json output
|
||||
"""
|
||||
demand_data = 'fileOut8'
|
||||
fossil_data = 'fileOut4'
|
||||
fossil_index = 2
|
||||
demand_index = 2
|
||||
|
||||
electricity_df = pd.read_csv(self._input_data['fileOut8'].strip("'")).iloc[:, 2]
|
||||
fossil_df = pd.read_csv(self._input_data['fileOut4'].strip("'")).iloc[:, 2]
|
||||
if self._output_path is None:
|
||||
demand_data = 'fileOut10'
|
||||
fossil_data = 'fileOut9'
|
||||
demand_index = 5
|
||||
|
||||
electricity_df = pd.read_csv(self._input_data[demand_data].strip("'")).iloc[:, demand_index]
|
||||
fossil_df = pd.read_csv(self._input_data[fossil_data].strip("'")).iloc[:, fossil_index]
|
||||
|
||||
if self._output_path is None:
|
||||
return {
|
||||
'hourly_electricity_demand': electricity_df.values.tolist(),
|
||||
'daily_fossil_consumption': fossil_df.values.tolist()
|
||||
}
|
||||
|
||||
data = [electricity_df, fossil_df]
|
||||
df = pd.concat(data, axis=1)
|
||||
|
@ -222,3 +255,5 @@ class HeatPumpExport:
|
|||
s = pd.Series(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec", "Total"])
|
||||
df = df.set_index([s])
|
||||
df.to_csv(self._output_path)
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Copyright © 2022 Concordia CERC group
|
|||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
from exports.energy_systems.heat_pump_export import HeatPumpExport
|
||||
from typing import List, Tuple, Union
|
||||
from typing import List, Dict, Union
|
||||
|
||||
|
||||
class WaterToWaterHPExport(HeatPumpExport):
|
||||
|
@ -15,17 +15,19 @@ class WaterToWaterHPExport(HeatPumpExport):
|
|||
after executing insel
|
||||
"""
|
||||
|
||||
def __init__(self, base_path, city, output_path, sim_type):
|
||||
def __init__(self, base_path, city, output_path, sim_type, demand_path):
|
||||
"""
|
||||
:param base_path: path to energy system files
|
||||
:param city: the city object
|
||||
:param output_path: the file to hold insel simulation results
|
||||
:param sim_type: the simulation type to run: 1 for series, 0 for parallel
|
||||
:param demand_path: path to hourly energy demand file
|
||||
"""
|
||||
tmp_file = 'heat_pumps/w2w_series.txt' if sim_type == 0 else 'heat_pumps/w2w_parallel.txt'
|
||||
template_path = (base_path / tmp_file)
|
||||
water_temp = (base_path / 'heat_pumps/wt_hourly3.txt')
|
||||
super().__init__(base_path, city, output_path, template_path, water_temp)
|
||||
super().__init__(base_path=base_path, city=city, output_path=output_path, template=template_path,
|
||||
demand_path=demand_path, water_temp=water_temp)
|
||||
|
||||
def _extract_model_coff(self, hp_model: str) -> Union[List, None]:
|
||||
"""
|
||||
|
@ -39,7 +41,7 @@ class WaterToWaterHPExport(HeatPumpExport):
|
|||
return energy_system.water_to_water_hp.power_demand_coff
|
||||
return None
|
||||
|
||||
def execute_insel(self, user_input, hp_model):
|
||||
def execute_insel(self, user_input, hp_model) -> Union[Dict, None]:
|
||||
"""
|
||||
Runs insel and produces output files
|
||||
Runs insel and write the necessary files
|
||||
|
@ -50,4 +52,4 @@ class WaterToWaterHPExport(HeatPumpExport):
|
|||
:return:
|
||||
"""
|
||||
pow_demand_coeff = self._extract_model_coff(hp_model)
|
||||
super(WaterToWaterHPExport, self)._run_insel(user_input, pow_demand_coeff, 'w2w.insel')
|
||||
return super(WaterToWaterHPExport, self)._run_insel(user_input, pow_demand_coeff, 'w2w.insel')
|
||||
|
|
|
@ -16,7 +16,8 @@ class EnergySystemsExportFactory:
|
|||
Exports factory class for energy systems
|
||||
"""
|
||||
|
||||
def __init__(self, city, user_input, hp_model, output_path, sim_type=0, data_type='heat', base_path=None):
|
||||
def __init__(self, city, user_input, hp_model, output_path, sim_type=0, data_type='heat', base_path=None,
|
||||
demand_path=None):
|
||||
"""
|
||||
|
||||
:param city: the city object
|
||||
|
@ -26,7 +27,9 @@ class EnergySystemsExportFactory:
|
|||
:param sim_type: the simulation type, 0 for series 1 for parallel
|
||||
:param data_type: indicates whether cooling or heating data is used
|
||||
:param base_path: the data directory of energy systems
|
||||
:param demand_path: path to hourly energy dempand file
|
||||
"""
|
||||
|
||||
self._city = city
|
||||
if base_path is None:
|
||||
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
||||
|
@ -36,6 +39,7 @@ class EnergySystemsExportFactory:
|
|||
self._data_type = data_type
|
||||
self._output_path = output_path
|
||||
self._sim_type = sim_type
|
||||
self._demand_path = demand_path
|
||||
|
||||
def _export_heat_pump(self, source):
|
||||
"""
|
||||
|
@ -44,10 +48,10 @@ class EnergySystemsExportFactory:
|
|||
:return: None
|
||||
"""
|
||||
if source == 'air':
|
||||
AirSourceHPExport(self._base_path, self._city, self._output_path, self._sim_type)\
|
||||
return AirSourceHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\
|
||||
.execute_insel(self._user_input, self._hp_model, self._data_type)
|
||||
elif source == 'water':
|
||||
WaterToWaterHPExport(self._base_path, self._city, self._output_path, self._sim_type)\
|
||||
return WaterToWaterHPExport(self._base_path, self._city, self._output_path, self._sim_type, self._demand_path)\
|
||||
.execute_insel(self._user_input, self._hp_model)
|
||||
|
||||
def export(self, source='air'):
|
||||
|
|
|
@ -12,6 +12,21 @@ from city_model_structure.energy_systems.air_source_hp import AirSourceHP
|
|||
from exports.energy_systems_factory import EnergySystemsExportFactory
|
||||
import os
|
||||
|
||||
# User defined paramenters
|
||||
user_input = {
|
||||
'StartYear': 2020,
|
||||
'EndYear': 2021,
|
||||
'MaximumHPEnergyInput': 8000,
|
||||
'HoursOfStorageAtMaxDemand': 1,
|
||||
'BuildingSuppTemp': 40,
|
||||
'TemperatureDifference': 15,
|
||||
'FuelLHV': 47100,
|
||||
'FuelPrice': 0.12,
|
||||
'FuelEF': 1887,
|
||||
'FuelDensity': 0.717,
|
||||
'HPSupTemp': 60
|
||||
}
|
||||
|
||||
|
||||
class TestEnergySystemsFactory(TestCase):
|
||||
"""
|
||||
|
@ -34,27 +49,20 @@ class TestEnergySystemsFactory(TestCase):
|
|||
self.assertEqual(self._city.energy_systems[0].air_source_hp.model, '012')
|
||||
self.assertEqual(self._city.energy_systems[16].air_source_hp.model, '140')
|
||||
|
||||
def test_air_source_heat_pump_export(self):
|
||||
# User defined paramenters
|
||||
user_input = {
|
||||
'StartYear': 2020,
|
||||
'EndYear': 2021,
|
||||
'MaximumHPEnergyInput': 8000,
|
||||
'HoursOfStorageAtMaxDemand': 1,
|
||||
'BuildingSuppTemp': 40,
|
||||
'TemperatureDifference': 15,
|
||||
'FuelLHV': 47100,
|
||||
'FuelPrice': 0.12,
|
||||
'FuelEF': 1887,
|
||||
'FuelDensity': 0.717,
|
||||
'HPSupTemp': 60
|
||||
}
|
||||
|
||||
EnergySystemsExportFactory(self._city, user_input, '012', self._output_path).export()
|
||||
def test_air_source_series_heat_pump_export(self):
|
||||
EnergySystemsExportFactory(city=self._city, user_input=user_input, hp_model='012',
|
||||
output_path=self._output_path).export()
|
||||
df = pd.read_csv(self._output_path)
|
||||
self.assertEqual(df.shape, (13, 3))
|
||||
self.assertEqual(df.iloc[0, 1], 1867715.88)
|
||||
|
||||
def test_air_source_parallel_heat_pump_export(self):
|
||||
output = EnergySystemsExportFactory(city=self._city, user_input=user_input, hp_model='018',
|
||||
output_path=None, sim_type=1).export()
|
||||
self.assertEqual(output["hourly_electricity_demand"][0], 38748.5625)
|
||||
self.assertIsNotNone(output["daily_fossil_consumption"])
|
||||
self.assertEqual(len(output["hourly_electricity_demand"]), 8760)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
try:
|
||||
os.remove(self._output_path)
|
||||
|
|
|
@ -13,6 +13,21 @@ import pandas as pd
|
|||
|
||||
import os
|
||||
|
||||
# User defined paramenters
|
||||
user_input = {
|
||||
'StartYear': 2020,
|
||||
'EndYear': 2021,
|
||||
'MaximumHPEnergyInput': 8000,
|
||||
'HoursOfStorageAtMaxDemand': 1,
|
||||
'BuildingSuppTemp': 40,
|
||||
'TemperatureDifference': 15,
|
||||
'FuelLHV': 47100,
|
||||
'FuelPrice': 0.12,
|
||||
'FuelEF': 1887,
|
||||
'FuelDensity': 0.717,
|
||||
'HPSupTemp': 60
|
||||
}
|
||||
|
||||
|
||||
class TestEnergySystemsFactory(TestCase):
|
||||
"""
|
||||
|
@ -35,27 +50,21 @@ class TestEnergySystemsFactory(TestCase):
|
|||
self.assertEqual(self._city.energy_systems[0].water_to_water_hp.model, 'ClimateMaster 156 kW')
|
||||
self.assertEqual(self._city.energy_systems[2].water_to_water_hp.model, 'ClimateMaster 335 kW')
|
||||
|
||||
def test_water_to_water_heat_pump_export(self):
|
||||
# User defined paramenters
|
||||
user_input = {
|
||||
'StartYear': 2020,
|
||||
'EndYear': 2021,
|
||||
'MaximumHPEnergyInput': 8000,
|
||||
'HoursOfStorageAtMaxDemand': 1,
|
||||
'BuildingSuppTemp': 40,
|
||||
'TemperatureDifference': 15,
|
||||
'FuelLHV': 47100,
|
||||
'FuelPrice': 0.12,
|
||||
'FuelEF': 1887,
|
||||
'FuelDensity': 0.717,
|
||||
'HPSupTemp': 60
|
||||
}
|
||||
def test_water_to_water_series_heat_pump_export(self):
|
||||
|
||||
EnergySystemsExportFactory(self._city, user_input, 'ClimateMaster 156 kW', self._output_path).export('water')
|
||||
EnergySystemsExportFactory(city=self._city, user_input=user_input, hp_model='ClimateMaster 156 kW',
|
||||
output_path=self._output_path).export('water')
|
||||
df = pd.read_csv(self._output_path)
|
||||
print(df.shape)
|
||||
#self.assertEqual(df.shape, (13, 3))
|
||||
#self.assertEqual(df.iloc[0, 1], 3045398.0)
|
||||
self.assertEqual(df.shape, (13, 3))
|
||||
self.assertEqual(df.iloc[0, 1], 1162387.5)
|
||||
|
||||
def test_water_to_water_parallel_heat_pump_export(self):
|
||||
|
||||
EnergySystemsExportFactory(city=self._city, user_input=user_input, hp_model='ClimateMaster 256 kW',
|
||||
output_path=self._output_path, sim_type=1).export('water')
|
||||
df = pd.read_csv(self._output_path)
|
||||
self.assertEqual(df.shape, (13, 3))
|
||||
self.assertEqual(df.iloc[0, 1], 1031544.62)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
try:
|
||||
|
|
Loading…
Reference in New Issue
Block a user