Added heat pump simulation persistence

This commit is contained in:
Peter Yefi 2022-11-22 20:20:12 -05:00
parent 7974317d13
commit 27456ffddd
10 changed files with 190 additions and 44 deletions

View File

@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group
Project CoderPeter Yefi peteryefi@gmail.com
"""
from persistence import CityRepo
from persistence import HeatPumpSimulationRepo
class DBFactory:
@ -15,6 +16,7 @@ class DBFactory:
def __init__(self, city, db_name, app_env):
self._city = city
self._city_repo = CityRepo(db_name=db_name, app_env=app_env)
self._hp_simulation_repo = HeatPumpSimulationRepo(db_name=db_name, app_env=app_env)
def get_city(self, city_id):
"""
@ -30,3 +32,16 @@ class DBFactory:
"""
return self._city_repo.get_by_name(city_name)
def get_hp_simulation(self, hp_sim_id: int):
"""
Retrieve a single heat pump simulation from postgres
:param hp_sim_id: the id of the heat pump to get
"""
return self._hp_simulation_repo.get_by_id(hp_sim_id)
def get_hp_simulation_by_city(self, city_id: int):
"""
Retrieve a single city from postgres
:param city_id: the id of the city
"""
return self._hp_simulation_repo.get_by_city(city_id)

View File

@ -56,7 +56,7 @@ class HeatPumpExport:
insel_file_handler.write(insel_template)
# Now run insel
self._delete_existing_output_files()
os.system('insel {}'.format(insel_file))
os.system('/usr/local/bin/insel {}'.format(insel_file))
# Writer headers to csv output files generated by insel
self._write_insel_output_headers()
# User output
@ -230,26 +230,20 @@ class HeatPumpExport:
from output files generated by insel
:return: Dict for json output
"""
demand_data = 'fileOut8'
fossil_data = 'fileOut4'
fossil_index = 2
demand_index = 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]
monthly_electricity_df = pd.read_csv(self._input_data['fileOut8'].strip("'")).iloc[:, 2]
monthly_fossil_df = pd.read_csv(self._input_data['fileOut4'].strip("'")).iloc[:, 2]
if self._output_path is None:
return {
'hourly_electricity_demand': electricity_df.values.tolist(),
'daily_fossil_consumption': fossil_df.values.tolist()
'hourly_electricity_demand': pd.read_csv(self._input_data['fileOut10'].strip("'")).iloc[:, 5].tolist(),
'monthly_electricity_demand': monthly_electricity_df.tolist(),
'daily_electricity_demand': pd.read_csv(self._input_data['fileOut6'].strip("'")).iloc[:, 2].tolist(),
'daily_fossil_consumption': pd.read_csv(self._input_data['fileOut9'].strip("'")).iloc[:, 2].tolist(),
'monthly_fossil_consumption': monthly_fossil_df.tolist()
}
data = [electricity_df, fossil_df]
data = [monthly_electricity_df, monthly_fossil_df]
df = pd.concat(data, axis=1)
df = pd.concat([df, df.agg(['sum'])])
s = pd.Series(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec", "Total"])

View File

@ -5,6 +5,8 @@ Copyright © 2022 Concordia CERC group
Project CoderPeter Yefi peteryefi@gmail.com
"""
from persistence import CityRepo
from persistence import HeatPumpSimulationRepo
from typing import Dict
class DBFactory:
@ -15,6 +17,7 @@ class DBFactory:
def __init__(self, city, db_name, app_env):
self._city = city
self._city_repo = CityRepo(db_name=db_name, app_env=app_env)
self._hp_simulation_repo = HeatPumpSimulationRepo(db_name=db_name, app_env=app_env)
def persist_city(self):
"""
@ -37,3 +40,19 @@ class DBFactory:
"""
self._city_repo.delete_city(city_id)
def persist_hp_simulation(self, hp_simulation_data: Dict, city_id: int):
"""
Persist heat pump simulation results
:param hp_simulation_data: the simulation results
:param city_id: the city object used in running the simulation
:return: HeatPumpSimulation object
"""
return self._hp_simulation_repo.insert(hp_simulation_data, city_id)
def delete_hp_simulation(self, hp_sim_id):
"""
Deletes a single heat pump simulation from postgres
:param hp_sim_id: the id of the heat pump simulation to get
"""
self._hp_simulation_repo.delete_hp_simulation(hp_sim_id)

View File

@ -1,3 +1,4 @@
from .base_repo import BaseRepo
from .repositories.city_repo import CityRepo
from .repositories.building_repo import BuildingRepo
from .repositories.heat_pump_simulation_repo import HeatPumpSimulationRepo

View File

@ -1,4 +1,5 @@
from .building import Building
from .city import City
from .heat_pump_simulation import HeatPumpSimulation
from .heat_pump_simulation import SimulationTypes
from .heat_pump_simulation import HeatPumpTypes

View File

@ -5,9 +5,11 @@ Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
from sqlalchemy import Column, Integer, String, Sequence, PickleType, Float
from sqlalchemy import Column, Integer, String, Sequence
from sqlalchemy import DateTime, PickleType, Float
from persistence.db_config import Base
from sqlalchemy.dialects.postgresql import JSONB
import datetime
class City(Base):
@ -27,4 +29,5 @@ class City(Base):
upper_corner = Column(JSONB, nullable=False)
hub_release = Column(String, nullable=False)
city_version = Column(Integer, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow)

View File

@ -5,18 +5,20 @@ Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
from sqlalchemy import Column, Integer, String, Sequence, Float, ForeignKey, Enum
from sqlalchemy import Column, Integer, String, Sequence
from sqlalchemy import Enum, ForeignKey, Float, DateTime
from sqlalchemy.dialects.postgresql import JSONB
from persistence.db_config import Base
from enum import Enum
import enum
import datetime
class SimulationTypes(Enum):
class SimulationTypes(enum.Enum):
Parallel = 'PARALLEL'
Series = 'SERIES'
class HeatPumpTypes(Enum):
class HeatPumpTypes(enum.Enum):
Air = 'Air Source'
Water = 'Water to Water'
@ -26,6 +28,7 @@ class HeatPumpSimulation(Base):
Attributes:
city_id, A reference to the city which was used to run this simulation.
hourly_electricity_demand, A JSON object that has hours and their electricity demand
daily_electricity_demand, A JSON object that has days and their electricity demand
monthly_electricity_demand, A JSON object that has months and their electricity demand
daily_fossil_fuel_consumption, A JSON object that has days and fossil fuel consumption
@ -51,6 +54,7 @@ class HeatPumpSimulation(Base):
id = Column(Integer, Sequence('hp_simulation_id_seq'), primary_key=True)
city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
daily_electricity_demand = Column(JSONB, nullable=False)
hourly_electricity_demand = Column(JSONB, nullable=False)
daily_fossil_fuel_consumption = Column(JSONB, nullable=False)
monthly_fossil_fuel_consumption = Column(JSONB, nullable=False)
monthly_electricity_demand = Column(JSONB, nullable=False)
@ -68,4 +72,5 @@ class HeatPumpSimulation(Base):
fuel_efficiency = Column(Float, nullable=False)
fuel_density = Column(Float, nullable=False)
hp_supply_temp = Column(Float, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow)

View File

@ -39,6 +39,7 @@ class HeatPumpSimulationRepo(BaseRepo):
if city is None:
return {'message': 'city not found in database'}
try:
hp_simulation = HeatPumpSimulation()
hp_simulation.city_id = city_id
hp_simulation.end_year = hp_simulation_data["EndYear"]
@ -53,19 +54,23 @@ class HeatPumpSimulationRepo(BaseRepo):
hp_simulation.fuel_density = hp_simulation_data["FuelDensity"]
hp_simulation.hp_supply_temp = hp_simulation_data["HPSupTemp"]
hp_simulation.daily_electricity_demand = hp_simulation_data["DailyElectricityDemand"]
hp_simulation.hourly_electricity_demand = hp_simulation_data["HourlyElectricityDemand"]
hp_simulation.monthly_electricity_demand = hp_simulation_data["MonthlyElectricityDemand"]
hp_simulation.daily_fossil_fuel_consumption = hp_simulation_data["DailyFossilFuelConsumption"]
hp_simulation.monthly_fossil_fuel_consumption = hp_simulation_data["MonthlyFossilFuelConsumption"]
hp_simulation.simulation_type = hp_simulation_data["SimulationType"]
hp_simulation.heat_pump_model = hp_simulation_data["HeatPumpModel"]
hp_simulation.heat_pump_type = hp_simulation_data["HeatPumpType"]
try:
# Persist heat pump simulation data
self.session.add(hp_simulation)
self.session.flush()
self.session.commit()
return hp_simulation
except SQLAlchemyError as err:
print(f'Error while saving heat pump simulation data: {err}')
except KeyError as err:
print(f'A required field is missing in your heat pump simulation dictionary: {err}')
def get_by_id(self, hp_simulation_id: int) -> HeatPumpSimulation:
"""

View File

@ -35,12 +35,12 @@ class TestDBFactory(TestCase):
self._export_db_factory = ExportDBFactory(city=self.city, db_name='hub_test', app_env='TEST')
def test_save_city(self):
self._saved_city = self._db_factory.persist_city()
self.assertEqual(self._saved_city.name, 'Montréal')
pickled_city = loads(self._saved_city.city)
saved_city = self._db_factory.persist_city()
self.assertEqual(saved_city.name, 'Montréal')
pickled_city = loads(saved_city.city)
self.assertEqual(len(pickled_city.buildings), 10)
self.assertEqual(pickled_city.buildings[0].floor_area, 1990.9913970530033)
self._db_factory.delete_city(self._saved_city.id)
self._db_factory.delete_city(saved_city.id)
def test_save_same_city_with_same_hub_version(self):
first_city = self._db_factory.persist_city()

View File

@ -0,0 +1,103 @@
"""
Test EnergySystemsFactory and various heatpump models
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
from unittest import TestCase
from imports.geometry_factory import GeometryFactory
from imports.energy_systems_factory import EnergySystemsFactory
from exports.energy_systems_factory import EnergySystemsExportFactory
from imports.db_factory import DBFactory
from exports.db_factory import DBFactory as ExportDBFactory
from persistence.db_config import BaseConfiguration
from sqlalchemy import create_engine
from persistence.models import City
from persistence.models import SimulationTypes
from persistence.models import HeatPumpTypes
from persistence.models import HeatPumpSimulation
# User defined paramenters
hp_sim_data = {
'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 TestHeatPumpSimulation(TestCase):
"""
Heat pump simulation test cases
"""
def setUp(self) -> None:
"""
Test setup
:return: None
"""
# Create test tables if they do not exit
config = BaseConfiguration(db_name='hub_test', app_env='TEST')
engine = create_engine(config.conn_string())
City.__table__.create(bind=engine, checkfirst=True)
HeatPumpSimulation.__table__.create(bind=engine, checkfirst=True)
city_file = "../unittests/tests_data/C40_Final.gml"
self._city = GeometryFactory('citygml', city_file).city
EnergySystemsFactory('air source hp', self._city).enrich()
self._db_factory = DBFactory(city=self._city, db_name='hub_test', app_env='TEST')
self._export_db_factory = ExportDBFactory(city=self._city, db_name='hub_test', app_env='TEST')
def test_heat_pump_simulation_persistence(self):
output = EnergySystemsExportFactory(city=self._city, user_input=hp_sim_data, hp_model='018',
output_path=None, sim_type=1).export()
hp_sim_data["HeatPumpModel"] = '018'
hp_sim_data["SimulationType"] = SimulationTypes.Parallel
hp_sim_data["HeatPumpType"] = HeatPumpTypes.Air
hp_sim_data["HourlyElectricityDemand"] = output["hourly_electricity_demand"]
hp_sim_data["DailyElectricityDemand"] = output["daily_electricity_demand"]
hp_sim_data["MonthlyElectricityDemand"] = output["monthly_electricity_demand"]
hp_sim_data["DailyFossilFuelConsumption"] = output["daily_fossil_consumption"]
hp_sim_data["MonthlyFossilFuelConsumption"] = output["monthly_fossil_consumption"]
saved_city = self._db_factory.persist_city()
hp_sim = self._db_factory.persist_hp_simulation(hp_sim_data, saved_city.id)
self.assertEqual(hp_sim.heat_pump_type, HeatPumpTypes.Air)
self.assertEqual(hp_sim.simulation_type, SimulationTypes.Parallel)
self.assertEqual(hp_sim.fuel_efficiency, hp_sim_data["FuelEF"])
self.assertEqual(hp_sim.monthly_electricity_demand, output["monthly_electricity_demand"])
self._db_factory.delete_hp_simulation(hp_sim.id)
self._db_factory.delete_city(saved_city.id)
def test_get_heat_pump_simulation_by_city(self):
output = EnergySystemsExportFactory(city=self._city, user_input=hp_sim_data, hp_model='012',
output_path=None, sim_type=0).export()
hp_sim_data["HeatPumpModel"] = '012'
hp_sim_data["SimulationType"] = SimulationTypes.Series
hp_sim_data["HeatPumpType"] = HeatPumpTypes.Air
hp_sim_data["HourlyElectricityDemand"] = output["hourly_electricity_demand"]
hp_sim_data["DailyElectricityDemand"] = output["daily_electricity_demand"]
hp_sim_data["MonthlyElectricityDemand"] = output["monthly_electricity_demand"]
hp_sim_data["DailyFossilFuelConsumption"] = output["daily_fossil_consumption"]
hp_sim_data["MonthlyFossilFuelConsumption"] = output["monthly_fossil_consumption"]
saved_city = self._db_factory.persist_city()
self._db_factory.persist_hp_simulation(hp_sim_data, saved_city.id)
# retrieved saved simulation by city id
hp_sim = self._export_db_factory.get_hp_simulation_by_city(saved_city.id)
self.assertEqual(hp_sim[0].heat_pump_type, HeatPumpTypes.Air)
self.assertEqual(hp_sim[0].simulation_type, SimulationTypes.Series)
self.assertEqual(hp_sim[0].fuel_price, hp_sim_data["FuelPrice"])
self.assertEqual(hp_sim[0].hourly_electricity_demand, output["hourly_electricity_demand"])
self._db_factory.delete_hp_simulation(hp_sim[0].id)
self._db_factory.delete_city(saved_city.id)