Complete the persistence update

test_save_result will be failing till systems are completed.
This commit is contained in:
Guille Gutierrez 2023-05-23 14:36:48 -04:00
parent 5a7427e457
commit 9f00208cbb
5 changed files with 170 additions and 52 deletions

View File

@ -377,8 +377,8 @@ class Building(CityObject):
monthly_values = PeakLoads(self).heating_peak_loads_from_methodology
if monthly_values is None:
return None
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=['heating peak loads'])
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=['heating peak loads'])
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=[cte.HEATING_PEAK_LOAD])
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=[cte.HEATING_PEAK_LOAD])
return results
@property
@ -394,8 +394,8 @@ class Building(CityObject):
monthly_values = PeakLoads(self).cooling_peak_loads_from_methodology
if monthly_values is None:
return None
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=['cooling peak loads'])
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=['cooling peak loads'])
results[cte.MONTH] = pd.DataFrame(monthly_values, columns=[cte.COOLING_PEAK_LOAD])
results[cte.YEAR] = pd.DataFrame([max(monthly_values)], columns=[cte.COOLING_PEAK_LOAD])
return results
@property

View File

@ -82,7 +82,7 @@ class InselMonthlyEnergyBalance:
if levels_of_detail.usage < 1:
raise Exception(f'Level of detail of usage = {levels_of_detail.usage}. Required minimum level 1')
if levels_of_detail.weather is None:
raise Exception(f'Level of detail of usage not assigned')
raise Exception(f'Level of detail of weather not assigned')
if levels_of_detail.weather < 1:
raise Exception(f'Level of detail of weather = {levels_of_detail.weather}. Required minimum level 1')
if levels_of_detail.surface_radiation is None:

View File

@ -201,7 +201,8 @@ MIN_FLOAT = float('-inf')
# Tools
SRA = 'sra'
INSEL_MEB = 'insel meb'
PEAK_LOAD = 'peak load'
COOLING_PEAK_LOAD = f'cooling peak load'
HEATING_PEAK_LOAD = f'heating peak load'
# Costs units
CURRENCY_PER_SQM = 'currency/m2'

View File

@ -30,7 +30,7 @@ class DBControl:
def application_info(self, application_uuid) -> Application:
"""
Retrieve the application info for the given uuid
Retrieve the application info for the given uuid from the database
:param application_uuid: the uuid for the application
:return: Application
"""
@ -38,7 +38,7 @@ class DBControl:
def user_info(self, name, password, application_id) -> User:
"""
Retrieve the user info for the given name and password and application_id
Retrieve the user info for the given name and password and application_id from the database
:param name: the username
:param password: the user password
:param application_id: the application id
@ -48,7 +48,7 @@ class DBControl:
def user_login(self, name, password, application_uuid) -> User:
"""
Retrieve the user info
Retrieve the user info from the database
:param name: the username
:param password: the user password
:param application_uuid: the application uuid
@ -58,7 +58,7 @@ class DBControl:
def cities_by_user_and_application(self, user_id, application_id) -> [City]:
"""
Retrieve the cities belonging to the user and the application
Retrieve the cities belonging to the user and the application from the database
:param user_id: User id
:param application_id: Application id
:return: [City]
@ -67,7 +67,7 @@ class DBControl:
def building_info(self, name, city_id) -> CityObject:
"""
Retrieve the building info
Retrieve the building info from the database
:param name: Building name
:param city_id: City ID
:return: CityObject
@ -76,7 +76,7 @@ class DBControl:
def results(self, user_id, application_id, cities, result_names=None) -> Dict:
"""
Retrieve the simulation results for the given cities
Retrieve the simulation results for the given cities from the database
:param user_id: the user id owning the results
:param application_id: the application id owning the results
:param cities: dictionary containing the city and building names for the results
@ -109,18 +109,18 @@ class DBControl:
def persist_city(self, city: City, pickle_path, application_id: int, user_id: int):
"""
Persist city into postgres database
Creates a city into the database
:param city: City to be stored
:param pickle_path: Path to save the pickle file
:param application_id: Application id owning this city
:param user_id: User who create the city
return identity_id
"""
self._city_repository.insert(city, pickle_path, application_id, user_id)
return self._city_repository.insert(city, pickle_path, application_id, user_id)
def update_city(self, city_id, city):
"""
Update an existing city in postgres database
Update an existing city in the database
:param city_id: the id of the city to update
:param city: the updated city object
"""
@ -128,7 +128,7 @@ class DBControl:
def persist_application(self, name: str, description: str, application_uuid: str):
"""
Creates an application
Creates information for an application in the database
:param name: name of application
:param description: the description of the application
:param application_uuid: the uuid of the application to be created
@ -137,40 +137,26 @@ class DBControl:
def update_application(self, name: str, description: str, application_uuid: str):
"""
Update an application
Update the application information stored in the database
:param name: name of application
:param description: the description of the application
:param application_uuid: the uuid of the application to be created
"""
return self._application.update(application_uuid, name, description)
def delete_city(self, city_id):
"""
Deletes a single city from postgres
:param city_id: the id of the city to get
"""
self._city_repository.delete(city_id)
def delete_application(self, application_uuid):
"""
Deletes a single application from postgres
:param application_uuid: the id of the application to get
"""
self._application.delete(application_uuid)
def add_simulation_results(self, name, values, city_id=None, city_object_id=None):
"""
Add simulation results to the city or to the city_object
Add simulation results to the city or to the city_object to the database
:param name: simulation and simulation engine name
:param values: simulation values in json format
:param city_id: city id or None
:param city_object_id: city object id or None
"""
self._simulation_results.insert(name, values, city_id, city_object_id)
return self._simulation_results.insert(name, values, city_id, city_object_id)
def create_user(self, name: str, application_id: int, password: str, role: UserRoles):
"""
Creates a new user
Creates a new user in the database
:param name: the name of the user
:param application_id: the application id of the user
:param password: the password of the user
@ -180,7 +166,7 @@ class DBControl:
def update_user(self, user_id: int, name: str, password: str, role: UserRoles):
"""
Creates a new user
Updates a user in the database
:param user_id: the id of the user
:param name: the name of the user
:param password: the password of the user
@ -188,17 +174,41 @@ class DBControl:
"""
return self._user.update(user_id, name, password, role)
def delete_user(self, user_id):
"""
Retrieve a single user
:param user_id: the id of the user to delete
"""
return self._user.delete(user_id)
def get_by_name_and_application(self, name: str, application: int):
"""
Retrieve a single user
Retrieve a single user from the database
:param name: username
:param application: application accessing hub
"""
return self._user.get_by_name_and_application(name, application)
def delete_user(self, user_id):
"""
Delete a single user from the database
:param user_id: the id of the user to delete
"""
self._user.delete(user_id)
def delete_city(self, city_id):
"""
Deletes a single city from the database
:param city_id: the id of the city to get
"""
self._city_repository.delete(city_id)
def delete_results_by_name(self, name, city_id=None, city_object_id=None):
"""
Deletes city object simulation results from the database
:param name: simulation name
:param city_id: if given, delete delete the results for the city with id city_id
:param city_object_id: if given, delete delete the results for the city object with id city_object_id
"""
self._simulation_results.delete(name, city_id=city_id, city_object_id=city_object_id)
def delete_application(self, application_uuid):
"""
Deletes a single application from the database
:param application_uuid: the id of the application to get
"""
self._application.delete(application_uuid)

View File

@ -4,8 +4,11 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder Peter Yefi peteryefi@gmail.com
"""
import glob
import json
import logging
import os
import subprocess
import unittest
from unittest import TestCase
from pathlib import Path
@ -14,14 +17,20 @@ import sqlalchemy.exc
from hub.imports.geometry_factory import GeometryFactory
from hub.imports.construction_factory import ConstructionFactory
from hub.imports.usage_factory import UsageFactory
from hub.imports.results_factory import ResultFactory
from hub.imports.weather_factory import WeatherFactory
from hub.exports.energy_building_exports_factory import EnergyBuildingsExportsFactory
from hub.exports.exports_factory import ExportsFactory
from hub.persistence.db_control import DBControl
from hub.persistence.repository import Repository
from sqlalchemy import create_engine
from hub.persistence.models import City, Application, CityObject
from hub.persistence.models import City, Application, CityObject, SimulationResults
from hub.persistence.models import User, UserRoles
from hub.helpers.dictionaries import Dictionaries
from sqlalchemy.exc import ProgrammingError
import uuid
import hub.helpers.constants as cte
import distutils.spawn
class Control:
@ -59,21 +68,34 @@ class Control:
User.__table__.create(bind=repository.engine, checkfirst=True)
City.__table__.create(bind=repository.engine, checkfirst=True)
CityObject.__table__.create(bind=repository.engine, checkfirst=True)
SimulationResults.__table__.create(bind=repository.engine, checkfirst=True)
city_file = "tests_data/FZK_Haus_LoD_2.gml"
weather_file = 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw'
output_path = Path('./tests_outputs/').resolve()
self._city = GeometryFactory('citygml',
city_file,
function_to_hub=Dictionaries().alkis_function_to_hub_function).city
ConstructionFactory('nrcan', self._city).enrich()
UsageFactory('nrcan', self._city).enrich()
WeatherFactory('epw', self._city, file_name='CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').enrich()
ExportsFactory('sra', self._city, output_path, weather_file=weather_file, weather_format='epw').export()
sra_file = str((output_path / f'{self._city.name}_sra.xml').resolve())
subprocess.run([self.sra, sra_file], stdout=subprocess.DEVNULL)
ResultFactory('sra', self._city, output_path).enrich()
EnergyBuildingsExportsFactory('insel_monthly_energy_balance', self._city, output_path).export()
_insel_files = glob.glob(f'{output_path}/*.insel')
for insel_file in _insel_files:
subprocess.run([self.insel, str(insel_file)], stdout=subprocess.DEVNULL)
ResultFactory('insel_monthly_energy_balance', self._city, output_path).enrich()
self._database = DBControl(
db_name=repository.configuration.db_name,
app_env='TEST',
dotenv_path=dotenv_path)
self._unique_id = str(uuid.uuid4())
self._application_id = self._database.persist_application("test", "test application", self.unique_id)
self._application_uuid = str(uuid.uuid4())
self._application_id = self._database.persist_application("test", "test application", self.application_uuid)
self._user_id = self._database.create_user("Admin", self._application_id, "Admin@123", UserRoles.Admin)
self._pickle_path = 'tests_data/pickle_path.bz2'
@ -82,8 +104,8 @@ class Control:
return self._database
@property
def unique_id(self):
return self._unique_id
def application_uuid(self):
return self._application_uuid
@property
def application_id(self):
@ -97,6 +119,18 @@ class Control:
def skip_test(self):
return self._skip_test
@property
def insel(self):
return distutils.spawn.find_executable("insel")
@property
def sra(self):
return distutils.spawn.find_executable("sra")
@property
def skip_insel_test(self):
return self.insel is None
@property
def skip_reason(self):
return self._skip_reason
@ -136,9 +170,9 @@ TestDBFactory
@unittest.skipIf(control.skip_test, control.skip_reason)
def test_get_update_city(self):
city_id = control.database.persist_city(control.city,
control.pickle_path,
control.application_id,
control.user_id)
control.pickle_path,
control.application_id,
control.user_id)
control.city.name = "Ottawa"
control.database.update_city(city_id, control.city)
cities = control.database.cities_by_user_and_application(
@ -146,6 +180,79 @@ TestDBFactory
control.application_id)
for updated_city in cities:
if updated_city.id == city_id:
self.assertEqual(updated_city.name,control.city.name)
self.assertEqual(updated_city.name, control.city.name)
break
control.database.delete_city(city_id)
@unittest.skipIf(control.skip_test, control.skip_reason)
@unittest.skipIf(control.skip_insel_test, 'insel is not installed')
def test_save_results(self):
city_id = control.database.persist_city(control.city,
control.pickle_path,
control.application_id,
control.user_id)
city_objects_id = []
for building in control.city.buildings:
_building = control.database.building_info(building.name, city_id)
if cte.MONTH not in building.cooling:
print(f'building {building.name} not calculated')
continue
monthly_cooling = building.cooling[cte.MONTH][cte.INSEL_MEB]
yearly_cooling = building.cooling[cte.YEAR][cte.INSEL_MEB]
monthly_heating = building.heating[cte.MONTH][cte.INSEL_MEB]
yearly_heating = building.heating[cte.YEAR][cte.INSEL_MEB]
monthly_cooling_peak_load = building.cooling_peak_load[cte.MONTH][cte.COOLING_PEAK_LOAD]
yearly_cooling_peak_load = building.cooling_peak_load[cte.YEAR][cte.COOLING_PEAK_LOAD]
monthly_heating_peak_load = building.heating_peak_load[cte.MONTH][cte.HEATING_PEAK_LOAD]
yearly_heating_peak_load = building.heating_peak_load[cte.YEAR][cte.HEATING_PEAK_LOAD]
monthly_lighting_electrical_demand = building.lighting_electrical_demand[cte.MONTH][cte.INSEL_MEB]
yearly_lighting_electrical_demand = building.lighting_electrical_demand[cte.YEAR][cte.INSEL_MEB]
monthly_appliances_electrical_demand = building.appliances_electrical_demand[cte.MONTH][cte.INSEL_MEB]
yearly_appliances_electrical_demand = building.appliances_electrical_demand[cte.YEAR][cte.INSEL_MEB]
monthly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.MONTH][cte.INSEL_MEB]
yearly_domestic_hot_water_heat_demand = building.domestic_hot_water_heat_demand[cte.YEAR][cte.INSEL_MEB]
monthly_heating_consumption = building.heating_consumption[cte.MONTH][cte.INSEL_MEB]
yearly_heating_consumption = building.heating_consumption[cte.YEAR][cte.INSEL_MEB]
monthly_cooling_consumption = building.cooling_consumption[cte.MONTH][cte.INSEL_MEB]
yearly_cooling_consumption = building.cooling_consumption[cte.YEAR][cte.INSEL_MEB]
monthly_domestic_hot_water_consumption = building.domestic_hot_water_consumption[cte.MONTH][cte.INSEL_MEB]
yearly_domestic_hot_water_consumption = building._domestic_hot_water_consumption[cte.YEAR][cte.INSEL_MEB]
db_building_id = _building.id
city_objects_id.append(db_building_id)
control.database.add_simulation_results(
cte.INSEL_MEB,
json.dumps({cte.INSEL_MEB: [
{"monthly_cooling": monthly_cooling.to_json()},
{"yearly_cooling": yearly_cooling.to_json()},
{"monthly_heating": monthly_heating.to_json()},
{"yearly_heating": yearly_heating.to_json()},
{"monthly_cooling_peak_load": monthly_cooling_peak_load.to_json()},
{"yearly_cooling_peak_load": yearly_cooling_peak_load.to_json()},
{"monthly_heating_peak_load": monthly_heating_peak_load.to_json()},
{"yearly_heating_peak_load": yearly_heating_peak_load.to_json()},
{"monthly_lighting_electrical_demand": monthly_lighting_electrical_demand.to_json()},
{"yearly_lighting_electrical_demand": yearly_lighting_electrical_demand.to_json()},
{"monthly_appliances_electrical_demand": monthly_appliances_electrical_demand.to_json()},
{"yearly_appliances_electrical_demand": yearly_appliances_electrical_demand.to_json()},
{"monthly_domestic_hot_water_heat_demand": monthly_domestic_hot_water_heat_demand.to_json()},
{"yearly_domestic_hot_water_heat_demand": yearly_domestic_hot_water_heat_demand.to_json()},
{"monthly_heating_consumption": monthly_heating_consumption.to_json()},
{"yearly_heating_consumption": yearly_heating_consumption.to_json()},
{"monthly_cooling_consumption": monthly_cooling_consumption.to_json()},
{"yearly_cooling_consumption": yearly_cooling_consumption.to_json()},
{"monthly_domestic_hot_water_consumption": monthly_domestic_hot_water_consumption.to_json()},
{"yearly_domestic_hot_water_consumption": yearly_domestic_hot_water_consumption.to_json()}
]}), city_object_id=db_building_id)
self.assertEqual(1, len(city_objects_id), 'wrong number of results')
self.assertIsNotNone(city_objects_id[0], 'city_object_id is None')
for _id in city_objects_id:
control.database.delete_results_by_name('insel meb', city_object_id=_id)
control.database.delete_city(city_id)
@classmethod
def tearDownClass(cls):
control.database.delete_application(control.application_uuid)
control.database.delete_user(control.user_id)