From 30f56c463007c59c5cf88794066925092c1d7639 Mon Sep 17 00:00:00 2001 From: Peter Yefi Date: Tue, 22 Nov 2022 17:49:02 -0500 Subject: [PATCH] Added a model and repo for hp simulation --- persistence/__init__.py | 2 +- persistence/{base.py => base_repo.py} | 0 persistence/models/__init__.py | 3 +- persistence/models/heat_pump_simulation.py | 71 ++++++++++++ .../repositories/heat_pump_simulation_repo.py | 104 ++++++++++++++++++ 5 files changed, 178 insertions(+), 2 deletions(-) rename persistence/{base.py => base_repo.py} (100%) create mode 100644 persistence/models/heat_pump_simulation.py create mode 100644 persistence/repositories/heat_pump_simulation_repo.py diff --git a/persistence/__init__.py b/persistence/__init__.py index 116dfd91..7f052c43 100644 --- a/persistence/__init__.py +++ b/persistence/__init__.py @@ -1,3 +1,3 @@ -from .base import BaseRepo +from .base_repo import BaseRepo from .repositories.city_repo import CityRepo from .repositories.building_repo import BuildingRepo diff --git a/persistence/base.py b/persistence/base_repo.py similarity index 100% rename from persistence/base.py rename to persistence/base_repo.py diff --git a/persistence/models/__init__.py b/persistence/models/__init__.py index 2ae48ed8..e28a23db 100644 --- a/persistence/models/__init__.py +++ b/persistence/models/__init__.py @@ -1,3 +1,4 @@ from .building import Building from .city import City -from .city import City +from .heat_pump_simulation import HeatPumpSimulation + diff --git a/persistence/models/heat_pump_simulation.py b/persistence/models/heat_pump_simulation.py new file mode 100644 index 00000000..e6bc0c3f --- /dev/null +++ b/persistence/models/heat_pump_simulation.py @@ -0,0 +1,71 @@ +""" +Model representation of the results of heat pump simulation +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Peter Yefi peteryefi@gmail.com +""" + +from sqlalchemy import Column, Integer, String, Sequence, Float, ForeignKey, Enum +from sqlalchemy.dialects.postgresql import JSONB +from persistence.db_config import Base +from enum import Enum + + +class SimulationTypes(Enum): + Parallel = 'PARALLEL' + Series = 'SERIES' + + +class HeatPumpTypes(Enum): + Air = 'Air Source' + Water = 'Water to Water' + + +class HeatPumpSimulation(Base): + """A model representation of a building + + Attributes: + city_id, A reference to the city which was used to run this simulation. + 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 + monthly_fossil_fuel_consumption, A JSON object that has months and fossil fuel consumption + heat_pump_type, Water or air heat pump + simulation_type, The type of heat pump simulation (parallel or series) + heat_pump_model, The model of the heat pump (either water to water or air source) + start year, HP simulation start year + end year, HP simulation end year + max_hp_energy_input, Maximum heat pump energy input + max_demand_storage_hour, Hours of storage at maximum demand + building_supply_temp, building supply temperature + temp_difference, Difference in HP and building supply temperatures + fuel_lhv, The lower heating value of fuel + fuel_price, The price of fuel + fuel_efficiency, the efficiency of fuel + fuel_density, the density of fuel + hp_supply_temp, supply temperature of heat pump + + + """ + __tablename__ = "heat_pump_simulation" + 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) + daily_fossil_fuel_consumption = Column(JSONB, nullable=False) + monthly_fossil_fuel_consumption = Column(JSONB, nullable=False) + monthly_electricity_demand = Column(JSONB, nullable=False) + heat_pump_type = Column(Enum(HeatPumpTypes), nullable=False) + simulation_type = Column(Enum(SimulationTypes), nullable=False) + heat_pump_model = Column(String, nullable=False) + start_year = Column(Integer, nullable=False) + end_year = Column(Integer, nullable=False) + max_hp_energy_input = Column(Float, nullable=False) + max_demand_storage_hour = Column(Float, nullable=False) + building_supply_temp = Column(Float, nullable=False) + temp_difference = Column(Float, nullable=False) + fuel_lhv = Column(Float, nullable=False) + fuel_price = Column(Float, nullable=False) + fuel_efficiency = Column(Float, nullable=False) + fuel_density = Column(Float, nullable=False) + hp_supply_temp = Column(Float, nullable=False) + diff --git a/persistence/repositories/heat_pump_simulation_repo.py b/persistence/repositories/heat_pump_simulation_repo.py new file mode 100644 index 00000000..daab4d37 --- /dev/null +++ b/persistence/repositories/heat_pump_simulation_repo.py @@ -0,0 +1,104 @@ +""" +Heat pump simulation repository with database CRUD operations +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Peter Yefi peteryefi@gmail.com +""" + +from persistence import BaseRepo, CityRepo +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy import select +from persistence.models import HeatPumpSimulation +from typing import Union, Dict + + +class HeatPumpSimulationRepo(BaseRepo): + _instance = None + + def __init__(self, db_name, app_env): + super().__init__(db_name, app_env) + self._city_repo = CityRepo(db_name, app_env) + + def __new__(cls, db_name, app_env): + """ + Implemented for a singleton pattern + """ + if cls._instance is None: + cls._instance = super(HeatPumpSimulationRepo, cls).__new__(cls) + return cls._instance + + def insert(self, hp_simulation_data: Dict, city_id: int) -> Union[HeatPumpSimulation, Dict]: + """ + Inserts the results of heat pump simulation + :param hp_simulation_data: dictionary with heatpump the simulation inputs and output + :param city_id: the city that was used in running the simulation + :return: HeatPumpSimulation + """ + + city = self._city_repo.get_by_id(city_id) + if city is None: + return {'message': 'city not found in database'} + + hp_simulation = HeatPumpSimulation() + hp_simulation.city_id = city_id + hp_simulation.end_year = hp_simulation_data["EndYear"] + hp_simulation.start_year = hp_simulation_data["StartYear"] + hp_simulation.max_demand_storage_hour = hp_simulation_data["HoursOfStorageAtMaxDemand"] + hp_simulation.max_hp_energy_input = hp_simulation_data["MaximumHPEnergyInput"] + hp_simulation.building_supply_temp = hp_simulation_data["BuildingSuppTemp"] + hp_simulation.temp_difference = hp_simulation_data["TemperatureDifference"] + hp_simulation.fuel_lhv = hp_simulation_data["FuelLHV"] + hp_simulation.fuel_price = hp_simulation_data["FuelPrice"] + hp_simulation.fuel_efficiency = hp_simulation_data["FuelEF"] + 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.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"] + + 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}') + + def get_by_id(self, hp_simulation_id: int) -> HeatPumpSimulation: + """ + Fetches heat pump simulation data + :param hp_simulation_id: the city id + :return: a HeatPumpSimulation + """ + try: + return self.session.execute(select(HeatPumpSimulation).where(HeatPumpSimulation.id == hp_simulation_id)).first()[ + 0] + except SQLAlchemyError as err: + print(f'Error while fetching city: {err}') + + def get_by_city(self, city_id: int) -> [HeatPumpSimulation]: + """ + Fetch heat pump simulation results by city + :param city_id: the name of the building + :return: [HeatPumpSimulation] with the provided name + """ + try: + result_set = self.session.execute(select(HeatPumpSimulation).where(HeatPumpSimulation.city_id == city_id)) + return [sim_data[0] for sim_data in result_set] + except SQLAlchemyError as err: + print(f'Error while fetching city by name: {err}') + + def delete_hp_simulation(self, hp_simulation_id: int): + """ + Deletes a heat pump simulation results + :param hp_simulation_id: the heat pump simulation results id + :return: + """ + try: + self.session.query(HeatPumpSimulation).filter(HeatPumpSimulation.id == hp_simulation_id).delete() + self.session.commit() + except SQLAlchemyError as err: + print(f'Error while fetching city: {err}')