Partial completion of new persistence.

Results are still missing and need to be added to the final commit. including the db table creation that seems to be missing
This commit is contained in:
Guille Gutierrez 2023-05-16 18:06:22 -04:00
parent 48dddae525
commit a33bf0b366
15 changed files with 125 additions and 109 deletions

View File

@ -246,7 +246,9 @@ class Polygon:
polygon = shapley_polygon(coordinates)
try:
vertices_2d, faces = trimesh.creation.triangulate_polygon(polygon, engine='triangle')
mesh = Trimesh(vertices=vertices, faces=faces)
# check orientation

View File

@ -92,7 +92,6 @@ class Polyhedron:
points = polygon.coordinates
if len(points) != 3:
sub_polygons = polygon.triangles
# todo: I modified this! To be checked @Guille
if len(sub_polygons) >= 1:
for sub_polygon in sub_polygons:
face = []

View File

@ -494,6 +494,8 @@ class Building(CityObject):
"""
_usage = ''
for internal_zone in self.internal_zones:
if internal_zone.usages is None:
continue
for usage in internal_zone.usages:
_usage = f'{_usage}{usage.name}_{usage.percentage} '
return _usage.rstrip()

View File

@ -77,7 +77,7 @@ class InselMonthlyEnergyBalance(Insel):
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:
raise Exception(f'Level of detail of usage not assigned')
raise Exception(f'Level of detail of surface radiation not assigned')
if levels_of_detail.surface_radiation < 1:
raise Exception(f'Level of detail of surface radiation = {levels_of_detail.surface_radiation}. '
f'Required minimum level 1')

View File

@ -37,7 +37,7 @@ class DBFactory:
def user_info(self, name, password, application_id):
"""
Retrieve the user info for the given name and password and application_id
:param name: the user name
:param name: the username
:param password: the user password
:param application_id: the application id
:return: User or None
@ -47,7 +47,7 @@ class DBFactory:
def user_login(self, name, password, application_uuid):
"""
Retrieve the user info
:param name: the user name
:param name: the username
:param password: the user password
:param application_uuid: the application uuid
:return: User or None

View File

@ -4,10 +4,11 @@ import os
import sys
def get_logger(file_logger=False):
def get_logger(file_logger=False, debug_level=logger.ERROR):
"""
Returns a logging object
:param file_logger: a boolean to indicate the kind of logging
:param debug_level: the value for the logger level (default error)
object to return, true (default) means a file logger is required
:return:
"""
@ -21,11 +22,11 @@ def get_logger(file_logger=False):
os.mkdir(log_dir)
with open(log_file, 'x'):
pass
logger.basicConfig(filename=log_file, format=log_format, level=logger.DEBUG)
logger.basicConfig(filename=log_file, format=log_format, level=debug_level)
return logger
except IOError as err:
print(f'I/O exception: {err}')
else:
logger.getLogger().addHandler(logger.StreamHandler(stream=sys.stdout))
logger.getLogger().setLevel(logger.DEBUG)
logger.getLogger().setLevel(debug_level)
return logger.getLogger()

View File

@ -35,6 +35,10 @@ class NrcanPhysicsParameters:
city = self._city
nrcan_catalog = ConstructionCatalogFactory('nrcan').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_nrcan_construction_function.keys():
logger.error(f'Building {building.name} has an unknown building function {building.function}\n')
sys.stderr.write(f'Building {building.name} has an unknown building function {building.function}\n')
continue
function = Dictionaries().hub_function_to_nrcan_construction_function[building.function]
try:
archetype = self._search_archetype(nrcan_catalog, function, building.year_of_construction, self._climate_zone)

View File

@ -35,21 +35,27 @@ class NrelPhysicsParameters:
city = self._city
nrel_catalog = ConstructionCatalogFactory('nrel').catalog
for building in city.buildings:
if building.function not in Dictionaries().hub_function_to_nrel_construction_function.keys():
logger.error(f'Building {building.name} has unknown function [{building.function}]')
sys.stderr.write(f'Building {building.name} has unknown function [{building.function}]\n')
continue
if building.function not in Dictionaries().hub_function_to_nrel_construction_function.keys():
logger.error(f'Building {building.name} has unknown function {building.function}\n')
sys.stderr.write(f'Building {building.name} has unknown function {building.function}\n')
continue
function = Dictionaries().hub_function_to_nrel_construction_function[building.function]
try:
archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction,
self._climate_zone)
archetype = self._search_archetype(nrel_catalog, function, building.year_of_construction, self._climate_zone)
except KeyError:
logger.error(f'Building {building.name} has unknown construction archetype for building function: '
f'{function} [{building.function}], building year of construction: {building.year_of_construction} '
f'and climate zone {self._climate_zone}\n')
f'{function} [{building.function}], building year of construction: {building.year_of_construction}'
f' and climate zone {self._climate_zone}\n')
sys.stderr.write(f'Building {building.name} has unknown construction archetype for building function: '
f'{function} [{building.function}], '
f'building year of construction: {building.year_of_construction} '
f'and climate zone {self._climate_zone}\n')
continue
# if building has no thermal zones defined from geometry, and the building will be divided in storeys,
# one thermal zone per storey is assigned
if len(building.internal_zones) == 1:

View File

@ -13,36 +13,57 @@ from sqlalchemy import DateTime
from hub.city_model_structure.building import Building
from hub.persistence.configuration import Models
class CityObject(Models):
"""
"""
A model representation of an application
"""
__tablename__ = 'city_object'
id = Column(Integer, Sequence('city_object_id_seq'), primary_key=True)
city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
name = Column(String, nullable=False)
alias = Column(String, nullable=True)
type = Column(String, nullable=False)
year_of_construction = Column(Integer, nullable=True)
function = Column(String, nullable=True)
usage = Column(String, nullable=True)
volume = Column(Float, nullable=False)
area = Column(Float, nullable=False)
total_heating_area = Column(Float, nullable=False)
wall_area = Column(Float, nullable=False)
windows_area = Column(Float, nullable=False)
system_name = Column(String, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow)
updated = Column(DateTime, default=datetime.datetime.utcnow)
__tablename__ = 'city_object'
id = Column(Integer, Sequence('city_object_id_seq'), primary_key=True)
city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
name = Column(String, nullable=False)
alias = Column(String, nullable=True)
type = Column(String, nullable=False)
year_of_construction = Column(Integer, nullable=True)
function = Column(String, nullable=True)
usage = Column(String, nullable=True)
volume = Column(Float, nullable=False)
area = Column(Float, nullable=False)
total_heating_area = Column(Float, nullable=False)
wall_area = Column(Float, nullable=False)
windows_area = Column(Float, nullable=False)
system_name = Column(String, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow)
updated = Column(DateTime, default=datetime.datetime.utcnow)
# def __init__(self, city_id, name, alias, object_type, year_of_construction, function, usage, volume, area):
def __init__(self, city_id, building: Building):
self.city_id = city_id
self.name = building.name
self.alias = building.alias
self.type = building.type
self.year_of_construction = building.year_of_construction
self.function = building.function
self.usage = building.usages_percentage
self.volume = building.volume
self.area = building.floor_area
# def __init__(self, city_id, name, alias, object_type, year_of_construction, function, usage, volume, area):
def __init__(self, city_id, building: Building):
self.city_id = city_id
self.name = building.name
self.alias = building.alias
self.type = building.type
self.year_of_construction = building.year_of_construction
self.function = building.function
self.usage = building.usages_percentage
self.volume = building.volume
self.area = building.floor_area
storeys = building.storeys_above_ground
if storeys is None:
print(building.average_storey_height)
storeys = building.max_height / building.average_storey_height
self.total_heating_area = building.floor_area * storeys
wall_area = 0
for wall in building.walls:
wall_area += wall.solid_polygon.area
self.wall_area = wall_area
window_ratio = 0
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
for thermal_boundary in thermal_zone.thermal_boundaries:
window_ratio = thermal_boundary.window_ratio
break
self.windows_area = wall_area * window_ratio
system_name = building.energy_systems_archetype_name
if system_name is None:
system_name = ''
self.system_name = system_name

View File

@ -76,7 +76,8 @@ class City(Repository):
"""
try:
now = datetime.datetime.utcnow()
self.session.query(Model).filter(Model.id == city_id).update({'name': city.name,'updated': now})
print(f'{now}')
self.session.query(Model).filter(Model.id == city_id).update({'name': city.name, 'updated': now})
self.session.commit()
except SQLAlchemyError as err:
logger.error(f'Error while updating city: {err}')

View File

@ -41,20 +41,8 @@ class CityObject(Repository):
city_object = self.get_by_name_and_city(building.name, city_id)
if city_object is None:
try:
object_usage = ''
for internal_zone in building.internal_zones:
for usage in internal_zone.usages:
object_usage = f'{object_usage}{usage.name}_{usage.percentage} '
object_usage = object_usage.rstrip()
city_object = Model(city_id=city_id,
name=building.name,
alias=building.alias,
object_type=building.type,
year_of_construction=building.year_of_construction,
function=building.function,
usage=object_usage,
volume=building.volume,
area=building.floor_area)
building=building)
self.session.add(city_object)
self.session.flush()
self.session.commit()

View File

@ -284,12 +284,3 @@ class TestConstructionFactory(TestCase):
self.assertIsNotNone(thermal_boundary.layers, 'layers is none')
self._check_thermal_openings(thermal_boundary)
self._check_surfaces(thermal_boundary)
def test_archetype_not_found(self):
file = 'pluto_building.gml'
city = self._get_citygml(file)
for building in city.buildings:
building.year_of_construction = 1990
building.function = 'office'
ConstructionFactory('nrel', city).enrich()

View File

@ -11,6 +11,8 @@ from pathlib import Path
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.db_factory import DBFactory as ImportDBFactory
from hub.imports.user_factory import UserFactory
from hub.exports.db_factory import DBFactory as ExportDBFactory
@ -18,29 +20,34 @@ from hub.persistence.repository import Repository
from sqlalchemy import create_engine
from hub.persistence.models import City, Application, CityObject
from hub.persistence.models import User, UserRoles
from hub.helpers.dictionaries import Dictionaries
from sqlalchemy.exc import ProgrammingError
import uuid
class Configure:
class Configure:
_skip_test = False
_skip_reason = 'PostgreSQL not properly installed in host machine'
def __init__(self):
"""
Test
setup
:return: None
"""
Test
setup
:return: None
"""
self._skip_test = False
# Create test database
dotenv_path = str(Path("{}/.local/etc/hub/.env".format(os.path.expanduser('~'))).resolve())
repository = Repository(db_name='hub_unittest', app_env='TEST', dotenv_path=dotenv_path)
dotenv_path = Path("{}/.local/etc/hub/.env".format(os.path.expanduser('~'))).resolve()
if not dotenv_path.exists():
self._skip_test = True
self._skip_reason = f'.env file missing at {dotenv_path}'
return
dotenv_path = str(dotenv_path)
repository = Repository(db_name='hub_unittests', app_env='TEST', dotenv_path=dotenv_path)
engine = create_engine(repository.configuration.connection_string)
try:
# delete test database if it exists
connection = engine.connect()
connection.execute('commit')
connection.close()
except ProgrammingError:
print(f'Database does not exist. Nothing to delete')
@ -55,7 +62,12 @@ class Configure:
CityObject.__table__.create(bind=repository.engine, checkfirst=True)
city_file = "tests_data/FZK_Haus_LoD_2.gml"
self._city = GeometryFactory('citygml', city_file).city
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()
self._import_db_factory = ImportDBFactory(
db_name=repository.configuration.db_name,
app_env='TEST',
@ -103,7 +115,7 @@ class Configure:
@property
def message(self):
return self._skip_message
return self._skip_reason
@property
def city(self):
@ -113,12 +125,14 @@ class Configure:
def pickle_path(self):
return self._pickle_path
configure = Configure()
class TestDBFactory(TestCase):
"""
TestDBFactory
"""
TestDBFactory
"""
@unittest.skipIf(configure.skip_test, configure.skip_reason)
def test_save_application(self):
@ -129,43 +143,29 @@ class TestDBFactory(TestCase):
@unittest.skipIf(configure.skip_test, configure.skip_reason)
def test_save_city(self):
configure.city.name = "Montreal"
saved_city = configure.import_db_factory.persist_city(
city = configure.import_db_factory.persist_city(
configure.city,
configure.pickle_path,
configure.application.id,
configure.user.id)
self.assertEqual(saved_city.name, 'Montreal')
self.assertEqual(saved_city.pickle_path, self.pickle_path)
self.assertEqual(saved_city.level_of_detail, self.city.level_of_detail.geometry)
self._db_factory.delete_city(saved_city.id)
@unittest.skipIf(configure.skip_test, configure.skip_reason)
def test_get_city_by_name(self):
city = self._db_factory.persist_city(self.city, self.pickle_path, self.application.id, self._user.id)
retrieved_city = self._export_db_factory.get_city_by_name(city.name)
self.assertEqual(retrieved_city[0].application_id, 1)
self.assertEqual(retrieved_city[0].user_id, self._user.id)
self._db_factory.delete_city(city.id)
@unittest.skipIf(configure.skip_test, configure.skip_reason)
def test_get_city_by_user(self):
city = self._import_db_factory.persist_city(self.city, self.pickle_path, self.application.id, self._user.id)
retrieved_city = self._export_db_factory.get_city_by_user(self._user.id)
self.assertEqual(retrieved_city[0].pickle_path, self.pickle_path)
self._db_factory.delete_city(city.id)
@unittest.skipIf(configure.skip_test, configure.skip_reason)
def test_get_city_by_id(self):
city = self._db_factory.persist_city(self.city, self.pickle_path, self.application.id, self._user.id)
retrieved_city = self._export_db_factory.get_city(city.id)
self.assertEqual(retrieved_city.level_of_detail, self.city.level_of_detail.geometry)
self._db_factory.delete_city(city.id)
self.assertEqual(city.name, 'Montreal')
self.assertEqual(city.pickle_path, configure.pickle_path)
self.assertEqual(city.level_of_detail, configure.city.level_of_detail.geometry)
configure.import_db_factory.delete_city(city.id)
@unittest.skipIf(configure.skip_test, configure.skip_reason)
def test_get_update_city(self):
city = self._db_factory.persist_city(self.city, self.pickle_path, self.application.id, self._user.id)
self.city.name = "Ottawa"
self._db_factory.update_city(city.id, self.city)
updated_city = self._export_db_factory.get_city(city.id)
self.assertEqual(updated_city.name, self.city.name)
self._db_factory.delete_city(city.id)
city = configure.import_db_factory.persist_city(configure.city,
configure.pickle_path,
configure.application.id,
configure._user.id)
city.name = "Ottawa"
configure.import_db_factory.update_city(city.id, configure.city)
cities = configure.export_db_factory.cities_by_user_and_application(
configure.user.id,
configure.application.id)
for updated_city in cities:
if updated_city.id == city.id:
self.assertEqual(updated_city.name, city.name)
break
configure.import_db_factory.delete_city(city.id)

View File

@ -63,6 +63,7 @@ class TestExports(TestCase):
:parameter city: city
:return: none
"""
city.level_of_detail.surface_radiation = 2
for radiation in self._read_sra_file:
city_object_name = radiation.columns.values.tolist()[1].split(':')[1]
building = city.city_object(city_object_name)