diff --git a/hub/DEPLOYMENT.md b/hub/DEPLOYMENT.md index 05299696..422b1aa7 100644 --- a/hub/DEPLOYMENT.md +++ b/hub/DEPLOYMENT.md @@ -74,7 +74,7 @@ from hub.persistence import DBSetup from pathlib import Path dotenv_path = (Path(__file__).parent / '.env').resolve() -DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path) +DBSetup(db_name='hub_db', app_env='PROD', dotenv_path=dotenv_path, admin_password="your password here", application_uuid="your admin application uuid") ``` The *DBSetUp* class also creates a default admin user with default credentials that can be changed. with the import UserFactory class. The admin user (name, email, password and role) is logged into the console after it is created by the diff --git a/hub/city_model_structure/building.py b/hub/city_model_structure/building.py index 040af1c9..296182f1 100644 --- a/hub/city_model_structure/building.py +++ b/hub/city_model_structure/building.py @@ -34,7 +34,7 @@ class Building(CityObject): self._roof_type = None self._internal_zones = None self._shell = None - self._human_readable_name = None + self._alias = None self._type = 'building' self._heating = dict() self._cooling = dict() @@ -404,16 +404,27 @@ class Building(CityObject): return False @property - def human_readable_name(self): + def alias(self): """ - Get the human-readable name for the building + Get the alias name for the building :return: str """ - return self._human_readable_name + return self._alias - @human_readable_name.setter - def human_readable_name(self, value): + @alias.setter + def alias(self, value): """ - Set the human-readable name for the building + Set the alias name for the building """ - self._human_readable_name = value + self._alias = value + + @property + def usages_percentage(self): + """ + Get the usages and percentages for the building + """ + _usage = '' + for internal_zone in self.internal_zones: + for usage in internal_zone.usages: + _usage = f'{_usage}{usage.name}_{usage.percentage} ' + return _usage.rstrip() diff --git a/hub/city_model_structure/city.py b/hub/city_model_structure/city.py index 69960c50..ef8ebbd1 100644 --- a/hub/city_model_structure/city.py +++ b/hub/city_model_structure/city.py @@ -101,13 +101,19 @@ class City: """ return self._get_location().country + @property + def location(self): + return self._get_location().city + @property def name(self): """ Get city name :return: str """ - return self._get_location().city + if self._name is None: + return self._get_location().city + return self._name @property def climate_reference_city(self) -> Union[None, str]: diff --git a/hub/city_model_structure/level_of_detail.py b/hub/city_model_structure/level_of_detail.py index d673971c..2c8665b9 100644 --- a/hub/city_model_structure/level_of_detail.py +++ b/hub/city_model_structure/level_of_detail.py @@ -14,6 +14,8 @@ class LevelOfDetail: self._geometry = None self._construction = None self._usage = None + self._weather = None + self._surface_radiation = None @property def geometry(self): @@ -59,3 +61,33 @@ class LevelOfDetail: Set the city minimal usage level of detail, 1 or 2 """ self._usage = value + + @property + def weather(self): + """ + Get the city minimal weather level of detail, 0 (yearly), 1 (monthly), 2 (hourly) + :return: int + """ + return self._weather + + @weather.setter + def weather(self, value): + """ + Set the city minimal weather level of detail, 0 (yearly), 1 (monthly), 2 (hourly) + """ + self._usage = value + + @property + def surface_radiation(self): + """ + Get the city minimal surface radiation level of detail, 0 (yearly), 1 (monthly), 2 (hourly) + :return: int + """ + return self._surface_radiation + + @surface_radiation.setter + def surface_radiation(self, value): + """ + Set the city minimal surface radiation level of detail, 0 (yearly), 1 (monthly), 2 (hourly) + """ + self._surface_radiation = value diff --git a/hub/exports/building_energy/energy_ade.py b/hub/exports/building_energy/energy_ade.py index bb42f988..53afcb08 100644 --- a/hub/exports/building_energy/energy_ade.py +++ b/hub/exports/building_energy/energy_ade.py @@ -75,7 +75,7 @@ class EnergyAde: 'energy:type': 'grossVolume', 'energy:value': { '@uom': 'm3', - 'energy:value': building.volume + '#text': f'{building.volume}' } } } @@ -169,7 +169,7 @@ class EnergyAde: def _building_geometry(self, building, building_dic, city): building_dic['bldg:Building']['bldg:function'] = building.function - building_dic['bldg:Building']['bldg:usage'] = ', '.join([u.name for u in building.usages]) + building_dic['bldg:Building']['bldg:usage'] = building.usages_percentage building_dic['bldg:Building']['bldg:yearOfConstruction'] = building.year_of_construction building_dic['bldg:Building']['bldg:roofType'] = building.roof_type building_dic['bldg:Building']['bldg:measuredHeight'] = { @@ -178,16 +178,86 @@ class EnergyAde: } building_dic['bldg:Building']['bldg:storeysAboveGround'] = building.storeys_above_ground - if building.lod == 1: + if city.level_of_detail.geometry == 1: building_dic = self._lod1(building, building_dic, city) - elif building.lod == 2: + elif city.level_of_detail.geometry == 2: building_dic = self._lod2(building, building_dic, city) else: raise NotImplementedError('Only lod 1 and 2 can be exported') return building_dic def _lod1(self, building, building_dic, city): - raise NotImplementedError('Only lod 1 and 2 can be exported') + self._surface_members = [] + boundaries = [{ + 'gml:Envelope': { + '@srsName': city.srs_name, + '@srsDimension': 3, + 'gml:lowerCorner': ' '.join([str(e) for e in city.lower_corner]), + 'gml:upperCorner': ' '.join([str(e) for e in city.upper_corner]) + }}] + for surface in building.surfaces: + surface_member = {'@xlink:href': f'#PolyId{surface.name}'} + self._surface_members.append(surface_member) + if surface.type == 'Wall': + surface_type = 'bldg:WallSurface' + elif surface.type == 'Ground': + surface_type = 'bldg:GroundSurface' + else: + surface_type = 'bldg:RoofSurface' + surface_dic = { + surface_type: { + '@gml:id': f'GML_{uuid.uuid4()}', + 'gml:name': f'{surface.name} ({surface.type})', + 'gml:boundedBy': { + 'gml:Envelope': { + '@srsName': city.srs_name, + 'gml:lowerCorner': f'{surface.lower_corner[0]} {surface.lower_corner[1]}' + f' {surface.lower_corner[2]}', + 'gml:upperCorner': f'{surface.upper_corner[0]} {surface.upper_corner[1]}' + f' {surface.upper_corner[2]}' + } + }, + 'bldg:lod1MultiSurface': { + 'gml:MultiSurface': { + '@srsName': city.srs_name, + '@gml:id': f'GML_{uuid.uuid4()}', + 'surfaceMember': { + 'gml:Polygon': { + '@srsName': city.srs_name, + '@gml:id': f'PolyId{surface.name}', + 'gml:exterior': { + 'gml:LinearRing': { + '@gml:id': f'PolyId{surface.name}_0', + 'gml:posList': { + '@srsDimension': '3', + '@count': len(surface.solid_polygon.coordinates) + 1, + '#text': f'{" ".join(map(str, surface.solid_polygon.points_list))} ' + f'{" ".join(map(str, surface.solid_polygon.coordinates[0]))}' + } + } + } + } + } + } + } + } + } + boundaries.append(surface_dic) + building_dic['bldg:Building']['bldg:lod1Solid'] = { + 'gml:Solid': { + '@gml:id': f'GML_{uuid.uuid4()}', + 'gml:exterior': { + 'gml:CompositeSurface': { + '@srsName': city.srs_name, + '@gml:id': f'GML_{uuid.uuid4()}', + 'gml:surfaceMember': self._surface_members + } + } + } + } + + building_dic['bldg:Building']['gml:boundedBy'] = boundaries + return building_dic def _lod2(self, building, building_dic, city): self._surface_members = [] @@ -264,53 +334,53 @@ class EnergyAde: def _thermal_zones(self, building, city): thermal_zones = [] - for index, thermal_zone in enumerate(building.thermal_zones): - usages = [] - for usage in thermal_zone.usages: - usages.append({'@xlink:href': f'#GML_{usage.id}'}) - thermal_zone_dic = { - 'energy:ThermalZone': { - '@gml:id': f'GML_{thermal_zone.id}', - 'gml:name': f'Thermal zone {index} in {building.name} building', - 'energy:contains': [], - 'energy:floorArea': { - 'energy:FloorArea': { - 'energy:type': 'grossFloorArea', - 'energy:value': { - '@uom': 'm2', - '#text': f'{thermal_zone.footprint_area}' - } - } - }, - 'energy:volume': { - 'energy:VolumeType': { - 'energy:type': 'grossVolume', - 'energy:value': { - '@uom': 'm3', - # todo: for now we have just one thermal zone, therefore is the building volume, this need to be changed - '#text': f'{building.volume}' - } - } - }, - 'energy:isCooled': f'{thermal_zone.is_cooled}', - 'energy:isHeated': f'{thermal_zone.is_heated}', - 'energy:volumeGeometry': { - 'gml:Solid': { - '@gml:id': f'GML_{uuid.uuid4()}', - 'gml:exterior': { - 'gml:CompositeSurface': { - '@srsName': f'{city.srs_name}', - '@gml:id': f'GML_{uuid.uuid4()}', - 'gml:surfaceMember': self._surface_members + for internal_zone in building.internal_zones: + for index, thermal_zone in enumerate(internal_zone.thermal_zones): + usages = [] + for usage in internal_zone.usages: + usages.append({'@xlink:href': f'#GML_{usage.id}'}) + thermal_zone_dic = { + 'energy:ThermalZone': { + '@gml:id': f'GML_{thermal_zone.id}', + 'gml:name': f'Thermal zone {index} in {building.name} building', + 'energy:contains': [], + 'energy:floorArea': { + 'energy:FloorArea': { + 'energy:type': 'grossFloorArea', + 'energy:value': { + '@uom': 'm2', + '#text': f'{thermal_zone.footprint_area}' } } - } - }, - 'energy:boundedBy': self._thermal_boundaries(city, thermal_zone) + }, + 'energy:volume': { + 'energy:VolumeType': { + 'energy:type': 'grossVolume', + 'energy:value': { + '@uom': 'm3', + '#text': f'{thermal_zone.volume}' + } + } + }, + 'energy:isCooled': f'{building.is_conditioned}'.lower(), + 'energy:isHeated': f'{building.is_conditioned}'.lower(), + 'energy:volumeGeometry': { + 'gml:Solid': { + '@gml:id': f'GML_{uuid.uuid4()}', + 'gml:exterior': { + 'gml:CompositeSurface': { + '@srsName': f'{city.srs_name}', + '@gml:id': f'GML_{uuid.uuid4()}', + 'gml:surfaceMember': self._surface_members + } + } + } + }, + 'energy:boundedBy': self._thermal_boundaries(city, thermal_zone) + } } - } - thermal_zone_dic['energy:ThermalZone']['energy:contains'] = usages - thermal_zones.append(thermal_zone_dic) + thermal_zone_dic['energy:ThermalZone']['energy:contains'] = usages + thermal_zones.append(thermal_zone_dic) return thermal_zones @staticmethod @@ -323,11 +393,11 @@ class EnergyAde: 'energy:thermalBoundaryType': thermal_boundary.type, 'energy:azumuth': { '@uom': 'rad', - '#text': f'{thermal_boundary.azimuth}' + '#text': f'{thermal_boundary.parent_surface.azimuth}' }, 'energy:inclination': { '@uom': 'rad', - '#text': f'{thermal_boundary.inclination}' + '#text': f'{thermal_boundary.parent_surface.inclination}' }, 'energy:area': { '@uom': 'm2', @@ -346,9 +416,9 @@ class EnergyAde: '@gml:id': f'GML_{uuid.uuid4()}', 'gml:posList': { '@srsDimension': '3', - '@count': len(thermal_boundary.surface.solid_polygon.coordinates) + 1, - '#text': f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.points_list))} ' - f'{" ".join(map(str, thermal_boundary.surface.solid_polygon.coordinates[0]))}' + '@count': len(thermal_boundary.parent_surface.solid_polygon.coordinates) + 1, + '#text': f'{" ".join(map(str, thermal_boundary.parent_surface.solid_polygon.points_list))} ' + f'{" ".join(map(str, thermal_boundary.parent_surface.solid_polygon.coordinates[0]))}' } } } diff --git a/hub/exports/db_factory.py b/hub/exports/db_factory.py index 482ed481..32906fde 100644 --- a/hub/exports/db_factory.py +++ b/hub/exports/db_factory.py @@ -4,8 +4,10 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project CoderPeter Yefi peteryefi@gmail.com """ -from hub.persistence import CityRepo -from hub.persistence import HeatPumpSimulationRepo +from hub.persistence import City +from hub.persistence import Application +from hub.persistence import User +from hub.persistence import CityObject class DBFactory: @@ -14,40 +16,38 @@ class DBFactory: """ def __init__(self, db_name, app_env, dotenv_path): - self._city_repo = CityRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) - self._hp_simulation_repo = HeatPumpSimulationRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + self._city = City(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + self._application = Application(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + self._user = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) def get_city(self, city_id): """ Retrieve a single city from postgres :param city_id: the id of the city to get """ - return self._city_repo.get_by_id(city_id) + return self._city.get_by_id(city_id) def get_city_by_name(self, city_name): """ Retrieve a single city from postgres :param city_name: the name of the city to get """ - return self._city_repo.get_by_name(city_name) + return self._city.get_by_name(city_name) def get_city_by_user(self, user_id): """ Retrieve cities created by user :param user_id: the id of the user """ - return self._city_repo.get_by_user(user_id) + return self._city.get_by_user(user_id) - 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 application_info(self, application_uuid): + return self._application.get_by_uuid(application_uuid) + + def user_info(self, name, password, application_id): + return self._user.get_by_name_application_and_password(name, password, application_id) + + def building_info(self, name, city_id): + return self._city_object.get_by_name_and_city(name, city_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) diff --git a/hub/exports/exports_factory.py b/hub/exports/exports_factory.py index 2d769af0..678b5a06 100644 --- a/hub/exports/exports_factory.py +++ b/hub/exports/exports_factory.py @@ -17,7 +17,11 @@ class ExportsFactory: """ Exports factory class """ - def __init__(self, export_type, city, path, target_buildings=None, adjacent_buildings=None): + def __init__(self, export_type, city, path, + target_buildings=None, + adjacent_buildings=None, + weather_file=None, + weather_format=None): self._city = city self._export_type = '_' + export_type.lower() class_funcs = validate_import_export_type(ExportsFactory) @@ -30,6 +34,8 @@ class ExportsFactory: self._path = path self._target_buildings = target_buildings self._adjacent_buildings = adjacent_buildings + self._weather_file = weather_file + self._weather_format = weather_format @property def _citygml(self): @@ -73,7 +79,10 @@ class ExportsFactory: Export the city to Simplified Radiosity Algorithm xml format :return: None """ - return SimplifiedRadiosityAlgorithm(self._city, (self._path / f'{self._city.name}_sra.xml'), + return SimplifiedRadiosityAlgorithm(self._city, + (self._path / f'{self._city.name}_sra.xml'), + self._weather_file, + self._weather_format, target_buildings=self._target_buildings) def export(self): diff --git a/hub/exports/formats/simplified_radiosity_algorithm.py b/hub/exports/formats/simplified_radiosity_algorithm.py index 84e6bd30..8a19cac3 100644 --- a/hub/exports/formats/simplified_radiosity_algorithm.py +++ b/hub/exports/formats/simplified_radiosity_algorithm.py @@ -6,12 +6,25 @@ Project Coder Guillermo.GutierrezMorote@concordia.ca """ import xmltodict +from hub.imports.weather_factory import WeatherFactory +import hub.helpers.constants as cte + class SimplifiedRadiosityAlgorithm: """ Export to SRA format """ - def __init__(self, city, file_name, target_buildings=None, begin_month=1, begin_day=1, end_month=12, end_day=31): + + def __init__(self, + city, + file_name, + weather_file, + weather_format, + target_buildings=None, + begin_month=1, + begin_day=1, + end_month=12, + end_day=31): self._file_name = file_name self._begin_month = begin_month self._begin_day = begin_day @@ -19,6 +32,8 @@ class SimplifiedRadiosityAlgorithm: self._end_day = end_day self._city = city self._target_buildings = target_buildings + self._weather_format = weather_format + self._weather_file = weather_file self._export() def _correct_point(self, point): @@ -29,6 +44,34 @@ class SimplifiedRadiosityAlgorithm: return [x, y, z] def _export(self): + self._export_sra_xml() + self._export_sra_cli() + + def _export_sra_cli(self): + file = self._city.climate_file + days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + WeatherFactory(self._weather_format, self._city, file_name=self._weather_file).enrich() + content = self._city.name + '\n' + content += str(self._city.latitude) + ',' + str(self._city.longitude) + ',0.0,' + str(self._city.time_zone) + '\n' + content += '\ndm m h G_Dh G_Bn\n' + total_days = 0 + for month in range(1, 13): + if month > 1: + total_days += days_in_month[month - 2] + for day in range(1, days_in_month[month - 1] + 1): + for hour in range(1, 25): + if month == 1: + i = 24 * (day - 1) + hour - 1 + else: + i = (total_days + day - 1) * 24 + hour - 1 + representative_building = self._city.buildings[0] + content += str(day) + ' ' + str(month) + ' ' + str(hour) + ' ' \ + + str(representative_building.global_horizontal[cte.HOUR].epw[i]) + ' ' \ + + str(representative_building.beam[cte.HOUR].epw[i]) + '\n' + with open(file, "w") as file: + file.write(content) + + def _export_sra_xml(self): buildings = [] for building_index, building in enumerate(self._city.buildings): if self._target_buildings is None: diff --git a/hub/helpers/auth.py b/hub/helpers/auth.py index f6cefa66..a9cc34b9 100644 --- a/hub/helpers/auth.py +++ b/hub/helpers/auth.py @@ -11,20 +11,6 @@ import re class Auth(object): - @staticmethod - def validate_password(password: str) -> bool: - """ - Validates a password - :param password: the password to validate - :return: - """ - pattern = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!#%*?&]{6,20}$" - pattern = re.compile(pattern) - if not re.search(pattern, password): - raise ValueError("Password must be between 6 to 20 characters and must have at least a number, an uppercase " - "letter, a lowercase letter, and a special character") - return True - @staticmethod def hash_password(password: str) -> str: """ diff --git a/hub/helpers/constants.py b/hub/helpers/constants.py index 479c9dd5..b75d9d2d 100644 --- a/hub/helpers/constants.py +++ b/hub/helpers/constants.py @@ -152,3 +152,7 @@ FULL_HVAC = 'Heating and cooling and ventilation' # Floats MAX_FLOAT = float('inf') MIN_FLOAT = float('-inf') + +# Tools +SRA = 'sra' +INSEL_MEB = 'insel meb' diff --git a/hub/helpers/data/alkis_function_to_hub_function.py b/hub/helpers/data/alkis_function_to_hub_function.py new file mode 100644 index 00000000..37273db0 --- /dev/null +++ b/hub/helpers/data/alkis_function_to_hub_function.py @@ -0,0 +1,185 @@ +""" +Dictionaries module for Alkis function to hub function +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + + +import hub.helpers.constants as cte + +class AlkisFunctionToHubFunction: + + def __init__(self): + self._dictionary = {"1000": cte.RESIDENTIAL, + "1010": "tenement", + "1020": "hostel", + "1030": "residential- and administration building", + "1040": "residential- and office building", + "1050": "residential- and business building", + "1060": "residential- and plant building", + "1070": "agrarian- and forestry building", + "1080": "residential- and commercial building", + "1090": "forester's lodge", + "1100": "holiday house", + "1110": "summer house", + "1120": "office building", + "1130": "credit institution", + "1140": "insurance", + "1150": "business building", + "1160": "department store", + "1170": "shopping centre", + "1180": "kiosk", + "1190": "pharmacy", + "1200": "pavilion", + "1210": cte.HOTEL, + "1220": "youth hostel", + "1230": "campsite building", + "1240": "restaurant", + "1250": "cantine", + "1260": "recreational site", + "1270": "function room", + "1280": "cinema", + "1290": "bowling alley", + "1300": "casino", + "1310": "industrial building", + "1320": "factory", + "1330": cte.WORKSHOP, + "1340": "petrol / gas station", + "1350": "washing plant", + "1360": "cold store", + "1370": "depot", + "1380": "building for research purposes", + "1390": "quarry", + "1400": "salt works", + "1410": "miscellaneous industrial building", + "1420": "mill", + "1430": "windmill", + "1440": "water mill", + "1450": "bucket elevator", + "1460": "weather station", + "1470": "traffic assets office", + "1480": "street maintenance", + "1490": "waiting hall", + "1500": "signal control box", + "1510": "engine shed", + "1520": "signal box or stop signal", + "1530": "plant building for air traffic", + "1540": "hangar", + "1550": "plant building for shipping", + "1560": "shipyard", + "1570": "dock", + "1580": "plant building for canal lock", + "1590": "boathouse", + "1600": "plant building for cablecar", + "1610": "multi-storey car park", + "1620": "parking level", + "1630": "garage", + "1640": "vehicle hall", + "1650": "underground garage", + "1660": "building for supply", + "1670": "waterworks", + "1680": "pump station", + "1690": "water basin", + "1700": "electric power station", + "1710": "transformer station", + "1720": "converter", + "1730": "reactor", + "1740": "turbine house", + "1750": "boiler house", + "1760": "building for telecommunications", + "1770": "gas works", + "1780": "heat plant", + "1790": "pumping station", + "1800": "building for disposal", + "1810": "building for effluent disposal", + "1820": "building for filter plant", + "1830": "toilet", + "1840": "rubbish bunker", + "1850": "building for rubbish incineration", + "1860": "building for rubbish disposal", + "1870": "building for agrarian and forestry", + "1880": "barn", + "1890": "stall", + "1900": "equestrian hall", + "1910": "alpine cabin", + "1920": "hunting lodge", + "1930": "arboretum", + "1940": "glass house", + "1950": "moveable glass house", + "1960": "public building", + "1970": "administration building", + "1980": "parliament", + "1990": "guildhall", + "2000": "post office", + "2010": "customs office", + "2020": "court", + "2030": "embassy or consulate", + "2040": "district administration", + "2050": "district government", + "2060": "tax office", + "2070": "building for education and research", + "2080": "comprehensive school", + "2090": "vocational school", + "2100": "college or university", + "2110": "research establishment", + "2120": "building for cultural purposes", + "2130": "castle", + "2140": "theatre or opera", + "2150": "concert building", + "2160": cte.MUSEUM, + "2170": "broadcasting building", + "2180": "activity building", + "2190": cte.LIBRARY, + "2200": "fort", + "2210": "religious building", + "2220": "church", + "2230": "synagogue", + "2240": "chapel", + "2250": "community center", + "2260": "place of worship", + "2270": "mosque", + "2280": "temple", + "2290": "convent", + "2300": "building for health care", + "2310": cte.HOSPITAL, + "2320": "healing centre or care home", + "2330": "health centre or outpatients clinic", + "2340": "building for social purposes", + "2350": "youth centre", + "2360": "seniors centre", + "2370": "homeless shelter", + "2380": "kindergarten or nursery", + "2390": "asylum seekers home", + "2400": cte.POLICE_STATION, + "2410": cte.FIRE_STATION, + "2420": "barracks", + "2430": "bunker", + "2440": cte.PENITENTIARY, + "2450": "cemetery building", + "2460": "funeral parlor", + "2470": "crematorium", + "2480": "train station", + "2490": "airport building", + "2500": "building for underground station", + "2510": "building for tramway", + "2520": "building for bus station", + "2530": "shipping terminal", + "2540": "building for recuperation purposes", + "2550": "building for sport purposes", + "2560": "sports hall", + "2570": "building for sports field", + "2580": "swimming baths", + "2590": "indoor swimming pool", + "2600": "sanatorium", + "2610": "zoo building", + "2620": cte.GREEN_HOUSE, + "2630": "botanical show house", + "2640": "bothy", + "2650": "tourist information centre", + "2700": "others", + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/hft_function_to_hub_function.py b/hub/helpers/data/hft_function_to_hub_function.py new file mode 100644 index 00000000..00f63a53 --- /dev/null +++ b/hub/helpers/data/hft_function_to_hub_function.py @@ -0,0 +1,32 @@ +""" +Dictionaries module for Hft function to hub function +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class HftFunctionToHubFunction: + + def __init__(self): + self._dictionary = { + 'residential': cte.RESIDENTIAL, + 'single family house': cte.SINGLE_FAMILY_HOUSE, + 'multifamily house': cte.MULTI_FAMILY_HOUSE, + 'hotel': cte.HOTEL, + 'hospital': cte.HOSPITAL, + 'outpatient': cte.OUT_PATIENT_HEALTH_CARE, + 'commercial': cte.SUPERMARKET, + 'strip mall': cte.STRIP_MALL, + 'warehouse': cte.WAREHOUSE, + 'primary school': cte.PRIMARY_SCHOOL, + 'secondary school': cte.EDUCATION, + 'office': cte.MEDIUM_OFFICE, + 'large office': cte.LARGE_OFFICE + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/hub_function_to_nrcan_construction_function.py b/hub/helpers/data/hub_function_to_nrcan_construction_function.py new file mode 100644 index 00000000..c54382c3 --- /dev/null +++ b/hub/helpers/data/hub_function_to_nrcan_construction_function.py @@ -0,0 +1,78 @@ +""" +Dictionaries module for hub function to nrcan construction function +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class HubFunctionToNrcanConstructionFunction: + + def __init__(self): + self._dictionary = { + cte.RESIDENTIAL: 'MidriseApartment', + cte.SINGLE_FAMILY_HOUSE: 'MidriseApartment', + cte.MULTI_FAMILY_HOUSE: 'HighriseApartment', + cte.ROW_HOUSE: 'MidriseApartment', + cte.MID_RISE_APARTMENT: 'MidriseApartment', + cte.HIGH_RISE_APARTMENT: 'HighriseApartment', + cte.OFFICE_AND_ADMINISTRATION: 'MediumOffice', + cte.SMALL_OFFICE: 'SmallOffice', + cte.MEDIUM_OFFICE: 'MediumOffice', + cte.LARGE_OFFICE: 'LargeOffice', + cte.COURTHOUSE: 'MediumOffice', + cte.FIRE_STATION: 'n/a', + cte.PENITENTIARY: 'LargeHotel', + cte.POLICE_STATION: 'n/a', + cte.POST_OFFICE: 'MediumOffice', + cte.LIBRARY: 'MediumOffice', + cte.EDUCATION: 'SecondarySchool', + cte.PRIMARY_SCHOOL: 'PrimarySchool', + cte.PRIMARY_SCHOOL_WITH_SHOWER: 'PrimarySchool', + cte.SECONDARY_SCHOOL: 'SecondarySchool', + cte.UNIVERSITY: 'SecondarySchool', + cte.LABORATORY_AND_RESEARCH_CENTER: 'SecondarySchool', + cte.STAND_ALONE_RETAIL: 'RetailStandalone', + cte.HOSPITAL: 'Hospital', + cte.OUT_PATIENT_HEALTH_CARE: 'Outpatient', + cte.HEALTH_CARE: 'Outpatient', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'SmallHotel', + cte.COMMERCIAL: 'RetailStripmall', + cte.STRIP_MALL: 'RetailStripmall', + cte.SUPERMARKET: 'RetailStripmall', + cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'RetailStandalone', + cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'RetailStandalone', + cte.RESTAURANT: 'FullServiceRestaurant', + cte.QUICK_SERVICE_RESTAURANT: 'QuickServiceRestaurant', + cte.FULL_SERVICE_RESTAURANT: 'FullServiceRestaurant', + cte.HOTEL: 'SmallHotel', + cte.HOTEL_MEDIUM_CLASS: 'SmallHotel', + cte.SMALL_HOTEL: 'SmallHotel', + cte.LARGE_HOTEL: 'LargeHotel', + cte.DORMITORY: 'SmallHotel', + cte.EVENT_LOCATION: 'n/a', + cte.CONVENTION_CENTER: 'n/a', + cte.HALL: 'n/a', + cte.GREEN_HOUSE: 'n/a', + cte.INDUSTRY: 'n/a', + cte.WORKSHOP: 'n/a', + cte.WAREHOUSE: 'Warehouse', + cte.WAREHOUSE_REFRIGERATED: 'Warehouse', + cte.SPORTS_LOCATION: 'n/a', + cte.SPORTS_ARENA: 'n/a', + cte.GYMNASIUM: 'n/a', + cte.MOTION_PICTURE_THEATRE: 'n/a', + cte.MUSEUM: 'n/a', + cte.PERFORMING_ARTS_THEATRE: 'n/a', + cte.TRANSPORTATION: 'n/a', + cte.AUTOMOTIVE_FACILITY: 'n/a', + cte.PARKING_GARAGE: 'n/a', + cte.RELIGIOUS: 'n/a', + cte.NON_HEATED: 'n/a' + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/hub_function_to_nrel_construction_function.py b/hub/helpers/data/hub_function_to_nrel_construction_function.py new file mode 100644 index 00000000..e1f62aec --- /dev/null +++ b/hub/helpers/data/hub_function_to_nrel_construction_function.py @@ -0,0 +1,78 @@ +""" +Dictionaries module for hub function to NREL construction function +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class HubFunctionToNrelConstructionFunction: + + def __init__(self): + self._dictionary = { + cte.RESIDENTIAL: 'residential', + cte.SINGLE_FAMILY_HOUSE: 'residential', + cte.MULTI_FAMILY_HOUSE: 'midrise apartment', + cte.ROW_HOUSE: 'midrise apartment', + cte.MID_RISE_APARTMENT: 'midrise apartment', + cte.HIGH_RISE_APARTMENT: 'high-rise apartment', + cte.OFFICE_AND_ADMINISTRATION: 'medium office', + cte.SMALL_OFFICE: 'small office', + cte.MEDIUM_OFFICE: 'medium office', + cte.LARGE_OFFICE: 'large office', + cte.COURTHOUSE: 'medium office', + cte.FIRE_STATION: 'n/a', + cte.PENITENTIARY: 'large hotel', + cte.POLICE_STATION: 'n/a', + cte.POST_OFFICE: 'medium office', + cte.LIBRARY: 'medium office', + cte.EDUCATION: 'secondary school', + cte.PRIMARY_SCHOOL: 'primary school', + cte.PRIMARY_SCHOOL_WITH_SHOWER: 'primary school', + cte.SECONDARY_SCHOOL: 'secondary school', + cte.UNIVERSITY: 'secondary school', + cte.LABORATORY_AND_RESEARCH_CENTER: 'secondary school', + cte.STAND_ALONE_RETAIL: 'stand-alone retail', + cte.HOSPITAL: 'hospital', + cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare', + cte.HEALTH_CARE: 'outpatient healthcare', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'small hotel', + cte.COMMERCIAL: 'strip mall', + cte.STRIP_MALL: 'strip mall', + cte.SUPERMARKET: 'supermarket', + cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'stand-alone retail', + cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'stand-alone retail', + cte.RESTAURANT: 'full service restaurant', + cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant', + cte.FULL_SERVICE_RESTAURANT: 'full service restaurant', + cte.HOTEL: 'small hotel', + cte.HOTEL_MEDIUM_CLASS: 'small hotel', + cte.SMALL_HOTEL: 'small hotel', + cte.LARGE_HOTEL: 'large hotel', + cte.DORMITORY: 'small hotel', + cte.EVENT_LOCATION: 'n/a', + cte.CONVENTION_CENTER: 'n/a', + cte.HALL: 'n/a', + cte.GREEN_HOUSE: 'n/a', + cte.INDUSTRY: 'n/a', + cte.WORKSHOP: 'n/a', + cte.WAREHOUSE: 'warehouse', + cte.WAREHOUSE_REFRIGERATED: 'warehouse', + cte.SPORTS_LOCATION: 'n/a', + cte.SPORTS_ARENA: 'n/a', + cte.GYMNASIUM: 'n/a', + cte.MOTION_PICTURE_THEATRE: 'n/a', + cte.MUSEUM: 'n/a', + cte.PERFORMING_ARTS_THEATRE: 'n/a', + cte.TRANSPORTATION: 'n/a', + cte.AUTOMOTIVE_FACILITY: 'n/aquebec_to_hub', + cte.PARKING_GARAGE: 'n/a', + cte.RELIGIOUS: 'n/a', + cte.NON_HEATED: 'n/a' + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/hub_usage_to_comnet_usage.py b/hub/helpers/data/hub_usage_to_comnet_usage.py new file mode 100644 index 00000000..8a6cc2c3 --- /dev/null +++ b/hub/helpers/data/hub_usage_to_comnet_usage.py @@ -0,0 +1,78 @@ +""" +Dictionaries module for hub usage to Comnet usage +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class HubUsageToComnetUsage: + + def __init__(self): + self._dictionary = { + cte.RESIDENTIAL: 'BA Multifamily', + cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily', + cte.MULTI_FAMILY_HOUSE: 'BA Multifamily', + cte.ROW_HOUSE: 'BA Multifamily', + cte.MID_RISE_APARTMENT: 'BA Multifamily', + cte.HIGH_RISE_APARTMENT: 'BA Multifamily', + cte.OFFICE_AND_ADMINISTRATION: 'BA Office', + cte.SMALL_OFFICE: 'BA Office', + cte.MEDIUM_OFFICE: 'BA Office', + cte.LARGE_OFFICE: 'BA Office', + cte.COURTHOUSE: 'BA Courthouse', + cte.FIRE_STATION: 'BA Fire Station', + cte.PENITENTIARY: 'BA Penitentiary', + cte.POLICE_STATION: 'BA Police Station', + cte.POST_OFFICE: 'BA Post Office', + cte.LIBRARY: 'BA Library', + cte.EDUCATION: 'BA School/University', + cte.PRIMARY_SCHOOL: 'BA School/University', + cte.PRIMARY_SCHOOL_WITH_SHOWER: 'BA School/University', + cte.SECONDARY_SCHOOL: 'BA School/University', + cte.UNIVERSITY: 'BA School/University', + cte.LABORATORY_AND_RESEARCH_CENTER: 'BA School/University', + cte.STAND_ALONE_RETAIL: 'BA Retail', + cte.HOSPITAL: 'BA Hospital', + cte.OUT_PATIENT_HEALTH_CARE: 'BA Healthcare Clinic', + cte.HEALTH_CARE: 'BA Healthcare Clinic', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Healthcare Clinic', + cte.COMMERCIAL: 'BA Retail', + cte.STRIP_MALL: 'BA Retail', + cte.SUPERMARKET: 'BA Retail', + cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail', + cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail', + cte.RESTAURANT: 'BA Dining: Bar Lounge/Leisure', + cte.QUICK_SERVICE_RESTAURANT: 'BA Dining: Cafeteria/Fast Food', + cte.FULL_SERVICE_RESTAURANT: 'BA Dining: Bar Lounge/Leisure', + cte.HOTEL: 'BA Hotel', + cte.HOTEL_MEDIUM_CLASS: 'BA Motel', + cte.SMALL_HOTEL: 'BA Motel', + cte.LARGE_HOTEL: 'BA Hotel', + cte.DORMITORY: 'BA Dormitory', + cte.EVENT_LOCATION: 'BA Convention Center', + cte.CONVENTION_CENTER: 'BA Convention Center', + cte.HALL: 'BA Town Hall', + cte.GREEN_HOUSE: 'n/a', + cte.INDUSTRY: 'BA Manufacturing Facility', + cte.WORKSHOP: 'BA Workshop', + cte.WAREHOUSE: 'BA Warehouse', + cte.WAREHOUSE_REFRIGERATED: 'BA Warehouse', + cte.SPORTS_LOCATION: 'BA Exercise Center', + cte.SPORTS_ARENA: 'BA Sports Arena', + cte.GYMNASIUM: 'BA Gymnasium', + cte.MOTION_PICTURE_THEATRE: 'BA Motion Picture Theater', + cte.MUSEUM: 'BA Museum', + cte.PERFORMING_ARTS_THEATRE: 'BA Performing Arts Theater', + cte.TRANSPORTATION: 'BA Transportation', + cte.AUTOMOTIVE_FACILITY: 'BA Automotive Facility', + cte.PARKING_GARAGE: 'BA Parking Garage', + cte.RELIGIOUS: 'BA Religious Building', + cte.NON_HEATED: 'n/a' + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/hub_usage_to_hft_usage.py b/hub/helpers/data/hub_usage_to_hft_usage.py new file mode 100644 index 00000000..a05a2ba0 --- /dev/null +++ b/hub/helpers/data/hub_usage_to_hft_usage.py @@ -0,0 +1,78 @@ +""" +Dictionaries module for hub usage to Hft usage +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class HubUsageToHftUsage: + + def __init__(self): + self._dictionary = { + cte.RESIDENTIAL: 'residential', + cte.SINGLE_FAMILY_HOUSE: 'single family house', + cte.MULTI_FAMILY_HOUSE: 'multifamily house', + cte.ROW_HOUSE: 'single family house', + cte.MID_RISE_APARTMENT: 'multifamily house', + cte.HIGH_RISE_APARTMENT: 'multifamily house', + cte.OFFICE_AND_ADMINISTRATION: 'office and administration', + cte.SMALL_OFFICE: 'office and administration', + cte.MEDIUM_OFFICE: 'office and administration', + cte.LARGE_OFFICE: 'office and administration', + cte.COURTHOUSE: 'office and administration', + cte.FIRE_STATION: 'office and administration', + cte.PENITENTIARY: 'school with shower', + cte.POLICE_STATION: 'office and administration', + cte.POST_OFFICE: 'office and administration', + cte.LIBRARY: 'office and administration', + cte.EDUCATION: 'education', + cte.PRIMARY_SCHOOL: 'school without shower', + cte.PRIMARY_SCHOOL_WITH_SHOWER: 'school with shower', + cte.SECONDARY_SCHOOL: 'education', + cte.UNIVERSITY: 'education', + cte.LABORATORY_AND_RESEARCH_CENTER: 'laboratory and research centers', + cte.STAND_ALONE_RETAIL: 'retail', + cte.HOSPITAL: 'health care', + cte.OUT_PATIENT_HEALTH_CARE: 'health care', + cte.HEALTH_CARE: 'health care', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage', + cte.COMMERCIAL: 'retail', + cte.STRIP_MALL: 'retail', + cte.SUPERMARKET: 'retail shop / refrigerated food', + cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail', + cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food', + cte.RESTAURANT: 'restaurant', + cte.QUICK_SERVICE_RESTAURANT: 'restaurant', + cte.FULL_SERVICE_RESTAURANT: 'restaurant', + cte.HOTEL: 'hotel', + cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)', + cte.SMALL_HOTEL: 'hotel', + cte.LARGE_HOTEL: 'hotel', + cte.DORMITORY: 'dormitory', + cte.EVENT_LOCATION: 'event location', + cte.CONVENTION_CENTER: 'event location', + cte.HALL: 'hall', + cte.GREEN_HOUSE: 'green house', + cte.INDUSTRY: 'industry', + cte.WORKSHOP: 'industry', + cte.WAREHOUSE: 'industry', + cte.WAREHOUSE_REFRIGERATED: 'industry', + cte.SPORTS_LOCATION: 'sport location', + cte.SPORTS_ARENA: 'sport location', + cte.GYMNASIUM: 'sport location', + cte.MOTION_PICTURE_THEATRE: 'event location', + cte.MUSEUM: 'event location', + cte.PERFORMING_ARTS_THEATRE: 'event location', + cte.TRANSPORTATION: 'n/a', + cte.AUTOMOTIVE_FACILITY: 'n/a', + cte.PARKING_GARAGE: 'n/a', + cte.RELIGIOUS: 'event location', + cte.NON_HEATED: 'non-heated' + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/hub_usage_to_nrcan_usage.py b/hub/helpers/data/hub_usage_to_nrcan_usage.py new file mode 100644 index 00000000..b792d0d2 --- /dev/null +++ b/hub/helpers/data/hub_usage_to_nrcan_usage.py @@ -0,0 +1,78 @@ +""" +Dictionaries module for hub usage to NRCAN usage +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class HubUsageToNrcanUsage: + + def __init__(self): + self._dictionary = { + cte.RESIDENTIAL: 'Multi-unit residential building', + cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building', + cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building', + cte.ROW_HOUSE: 'Multi-unit residential building', + cte.MID_RISE_APARTMENT: 'Multi-unit residential building', + cte.HIGH_RISE_APARTMENT: 'Multi-unit residential building', + cte.OFFICE_AND_ADMINISTRATION: 'Office', + cte.SMALL_OFFICE: 'Office', + cte.MEDIUM_OFFICE: 'Office', + cte.LARGE_OFFICE: 'Office', + cte.COURTHOUSE: 'Courthouse', + cte.FIRE_STATION: 'Fire station', + cte.PENITENTIARY: 'Penitentiary', + cte.POLICE_STATION: 'Police station', + cte.POST_OFFICE: 'Post office', + cte.LIBRARY: 'Library', + cte.EDUCATION: 'School/university', + cte.PRIMARY_SCHOOL: 'School/university', + cte.PRIMARY_SCHOOL_WITH_SHOWER: 'School/university', + cte.SECONDARY_SCHOOL: 'School/university', + cte.UNIVERSITY: 'School/university', + cte.LABORATORY_AND_RESEARCH_CENTER: 'School/university', + cte.STAND_ALONE_RETAIL: 'Retail', + cte.HOSPITAL: 'Hospital', + cte.OUT_PATIENT_HEALTH_CARE: 'Health-care clinic', + cte.HEALTH_CARE: 'Health-care clinic', + cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Health-care clinic', + cte.COMMERCIAL: 'Retail', + cte.STRIP_MALL: 'Retail', + cte.SUPERMARKET: 'Retail', + cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail', + cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail', + cte.RESTAURANT: 'Dining - bar/lounge', + cte.QUICK_SERVICE_RESTAURANT: 'Dining - cafeteria', + cte.FULL_SERVICE_RESTAURANT: 'Dining - bar/lounge', + cte.HOTEL: 'Hotel', + cte.HOTEL_MEDIUM_CLASS: 'Motel', + cte.SMALL_HOTEL: 'Motel', + cte.LARGE_HOTEL: 'Hotel', + cte.DORMITORY: 'Dormitory', + cte.EVENT_LOCATION: 'Convention centre', + cte.CONVENTION_CENTER: 'Convention centre', + cte.HALL: 'Town hall', + cte.GREEN_HOUSE: 'n/a', + cte.INDUSTRY: 'Manufacturing facility', + cte.WORKSHOP: 'Workshop', + cte.WAREHOUSE: 'Warehouse', + cte.WAREHOUSE_REFRIGERATED: 'Warehouse - refrigerated', + cte.SPORTS_LOCATION: 'Exercise centre', + cte.SPORTS_ARENA: 'Sports arena', + cte.GYMNASIUM: 'Gymnasium', + cte.MOTION_PICTURE_THEATRE: 'Motion picture theatre', + cte.MUSEUM: 'Museum', + cte.PERFORMING_ARTS_THEATRE: 'Performing arts theatre', + cte.TRANSPORTATION: 'Transportation', + cte.AUTOMOTIVE_FACILITY: 'Automotive facility', + cte.PARKING_GARAGE: 'Parking garage', + cte.RELIGIOUS: 'Religious', + cte.NON_HEATED: 'n/a' + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/montreal_function_to_hub_function.py b/hub/helpers/data/montreal_function_to_hub_function.py new file mode 100644 index 00000000..6658ec86 --- /dev/null +++ b/hub/helpers/data/montreal_function_to_hub_function.py @@ -0,0 +1,550 @@ +""" +Dictionaries module for Montreal function to hub function +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class MontrealFunctionToHubFunction: + + # Todo: "office" and "hotel/motel" need to be replaced for a constant value. + def __init__(self): + self._dictionary = { + "Administration publique municipale et régionale": "Office", + "Administration publique provinciale": "Office", + "Agence de voyages ou d'expéditions": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Aiguillage et cour de triage de chemins de fer": cte.WAREHOUSE, + "Amphithéâtre et auditorium": cte.EVENT_LOCATION, + "Archives (incluant cinémathèquevidéothèque)": cte.EVENT_LOCATION, + "Aréna et activités connexes (patinage sur glace)": cte.SPORTS_LOCATION, + "Association civiquesociale et fraternelle": cte.OFFICE_AND_ADMINISTRATION, + "Associationunion ou coop d'épargne et de prêt (inclus caisses populaires locales)": cte.OFFICE_AND_ADMINISTRATION, + "Atelier d'artiste": cte.WAREHOUSE, + "Atelier d'artiste ou d'artisan": cte.WAREHOUSE, + "Atelier d'usinage": cte.WAREHOUSE, + "Atelier de mécanicien-dentiste": cte.WAREHOUSE, + "Auberge ou gîte touristique (Hôtel à caractère familiald'au plus 3 étages en hauteur de bâtiment)": cte.SMALL_HOTEL, + "Autoroute": cte.WAREHOUSE, + "Autres activités agricoles": cte.INDUSTRY, + "Autres activités culturelles": cte.EVENT_LOCATION, + "Autres activités d'hébergement": cte.MULTI_FAMILY_HOUSE, + "Autres activités d'impression commerciale": cte.WAREHOUSE, + "Autres activités de la restauration": cte.WAREHOUSE, + "Autres activités de récupération et de triage": cte.WAREHOUSE, + "Autres activités de vente au détail (inclus les kiosques d'autres choses que vêtements et accessoires de vêtements)": cte.STAND_ALONE_RETAIL, + "Autres activités de vente au détail de produits de l'alimentation": cte.STAND_ALONE_RETAIL, + "Autres activités de vente au détail de vêtements comme les accessoires": cte.STAND_ALONE_RETAIL, + "Autres activités de vente au détail reliées aux automobilesaux embarcationsaux avions et à leurs accessoires": cte.STAND_ALONE_RETAIL, + "Autres activités de vente en gros": cte.WAREHOUSE, + "Autres activités minières et extraction de carrières de minerais non métalliques (sauf le pétrole)": cte.INDUSTRY, + "Autres activités nautiques": cte.WAREHOUSE, + "Autres activités religieuses": cte.OFFICE_AND_ADMINISTRATION, + "Autres activités reliées au transport de matériaux par camion": cte.WAREHOUSE, + "Autres activités reliées au transport par autobus": cte.WAREHOUSE, + "Autres activités reliées au transport par chemin de fer": cte.WAREHOUSE, + "Autres activités sportives (inclus centres de tir à l'arc)": cte.SPORTS_LOCATION, + "Autres aménagements d'assemblées publiques": cte.OFFICE_AND_ADMINISTRATION, + "Autres aménagements publics pour différentes activités": cte.OFFICE_AND_ADMINISTRATION, + "Autres aéroports": cte.WAREHOUSE, + "Autres bases et réserves militaires": cte.WAREHOUSE, + "Autres centres de recherche": cte.SECONDARY_SCHOOL, + "Autres centres de services sociaux ou bureaux de travailleurs sociaux": cte.OFFICE_AND_ADMINISTRATION, + "Autres centres et réseaux de télévision et de radiodiffusion (système combiné)": "Office", + "Autres entreposages": cte.WAREHOUSE, + "Autres espaces de plancher inoccupé": cte.WAREHOUSE, + "Autres espaces de terrain et étendues d'eau inexploités": cte.WAREHOUSE, + "Autres expositions d'objets culturels": cte.EVENT_LOCATION, + "Autres immeubles résidentiels": cte.MID_RISE_APARTMENT, + "Autres industries d'appareils d'éclairage": cte.INDUSTRY, + "Autres industries de boissons": cte.INDUSTRY, + "Autres industries de la fabrication d'éléments de charpentes métalliques": cte.INDUSTRY, + "Autres industries de la fonte et de l'affinage de métaux non-ferreux": cte.INDUSTRY, + "Autres industries de la machinerie industrielle et de l'équipement industriel": cte.INDUSTRY, + "Autres industries de pièces et d'accessoires pour véhicules automobiles": cte.INDUSTRY, + "Autres industries de produits alimentaires": cte.INDUSTRY, + "Autres industries de produits alimentaires à base de fruits et de légumes": cte.INDUSTRY, + "Autres industries de produits chimiques": cte.INDUSTRY, + "Autres industries de produits du pétrole et du charbon": cte.INDUSTRY, + "Autres industries de produits en béton": cte.INDUSTRY, + "Autres industries de produits en caoutchouc": cte.INDUSTRY, + "Autres industries de produits en fil métallique": cte.INDUSTRY, + "Autres industries de produits en plastique": cte.INDUSTRY, + "Autres industries de produits manufacturés": cte.INDUSTRY, + "Autres industries de produits métalliques d'ornement et d'architecture": cte.INDUSTRY, + "Autres industries de produits métalliques divers": cte.INDUSTRY, + "Autres industries de produits textiles": cte.INDUSTRY, + "Autres industries de produits électriques.": cte.INDUSTRY, + "Autres industries de vêtements coupés cousus pour femmes et filles": cte.INDUSTRY, + "Autres industries du bois": cte.INDUSTRY, + "Autres industries du laminagedu moulage et de l'extrusion de métaux non-ferreux": cte.INDUSTRY, + "Autres industries du matériel de transport": cte.INDUSTRY, + "Autres industries du matériel scientifique et professionnel": cte.INDUSTRY, + "Autres industries du matériel électrique d'usage industriel": cte.INDUSTRY, + "Autres industries du matériel électronique et de communication": cte.INDUSTRY, + "Autres industries du meuble de bureau": cte.INDUSTRY, + "Autres industries du meuble et d'articles d'ameublement": cte.INDUSTRY, + "Autres industries du meuble résidentiel.": cte.INDUSTRY, + "Autres industries du papier": cte.INDUSTRY, + "Autres industries sidérurgiques": cte.INDUSTRY, + "Autres infrastructures de transport maritime": cte.INDUSTRY, + "Autres installations inhérentes aux ordures": cte.WAREHOUSE, + "Autres installations pour les sports": cte.SPORTS_LOCATION, + "Autres institutions de formation spécialisée (inclus écoles de langues de coutured'arts martiaux de combats et autres)": cte.SECONDARY_SCHOOL, + "Autres lieux d'assemblée pour les loisirs": cte.OFFICE_AND_ADMINISTRATION, + "Autres locaux de groupes": cte.OFFICE_AND_ADMINISTRATION, + "Autres maisons d'institutions religieuses": cte.OFFICE_AND_ADMINISTRATION, + "Autres maisons et locaux fraternels": cte.OFFICE_AND_ADMINISTRATION, + "Autres maisons pour personnes retraitées": cte.OFFICE_AND_ADMINISTRATION, + "Autres parcs": cte.WAREHOUSE, + "Autres routes et voies publiques": "Office", + "Autres résidences d'étudiants": "Office", + "Autres résidences provisoires": "Office", + "Autres services connexes aux valeurs mobilières et aux marchandises": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Autres services d'affaires": "Office", + "Autres services d'aqueduc et d'irrigation": cte.WAREHOUSE, + "Autres services de construction de bâtiments": cte.WAREHOUSE, + "Autres services de génie civil (entrepreneur général)": cte.WAREHOUSE, + "Autres services de l'automobile": cte.WAREHOUSE, + "Autres services de location (sauf entreposage)": cte.WAREHOUSE, + "Autres services de nettoyage": cte.WAREHOUSE, + "Autres services de réparation et d'entretien d'articles personnels et ménagers": cte.STAND_ALONE_RETAIL, + "Autres services de soins thérapeutiques": cte.OUT_PATIENT_HEALTH_CARE, + "Autres services de travaux de construction spécialisés": cte.WAREHOUSE, + "Autres services de travaux de finition de bâtiment (entrepreneur spécialisé)": cte.WAREHOUSE, + "Autres services de télécommunications": cte.STAND_ALONE_RETAIL, + "Autres services divers": cte.WAREHOUSE, + "Autres services du pétrole": cte.WAREHOUSE, + "Autres services gouvernementaux": cte.OFFICE_AND_ADMINISTRATION, + "Autres services immobiliersfinanciers et d'assurance": cte.OFFICE_AND_ADMINISTRATION, + "Autres services médicaux et de santé": cte.OUT_PATIENT_HEALTH_CARE, + "Autres services personnels": cte.OUT_PATIENT_HEALTH_CARE, + "Autres services pour animaux domestiques": cte.OUT_PATIENT_HEALTH_CARE, + "Autres services pour le transport": cte.WAREHOUSE, + "Autres services pour les bâtiments": cte.WAREHOUSE, + "Autres services professionnels": cte.OFFICE_AND_ADMINISTRATION, + "Autres services publics (infrastructure)": cte.WAREHOUSE, + "Autres services reliés à la foresterie": cte.WAREHOUSE, + "Autres terrains de jeux et pistes athlétiques": cte.SPORTS_LOCATION, + "Autres transports par avion (infrastructure)": cte.WAREHOUSE, + "Autres transports par véhicule automobile": cte.WAREHOUSE, + "Autres transportscommunications et services publics (infrastructure)": cte.GREEN_HOUSE, + "Autres types de production végétale": cte.GREEN_HOUSE, + "Autres ventes au détail de marchandises en général": cte.STAND_ALONE_RETAIL, + "Autres établissements avec service complet ou restreint": cte.STAND_ALONE_RETAIL, + "Autres établissements de débits de boissons alcoolisées": cte.STAND_ALONE_RETAIL, + "Aéroport et aérodrome": cte.EVENT_LOCATION, + "Bar à crème glacée": cte.QUICK_SERVICE_RESTAURANT, + "Bar à spectacles": cte.FULL_SERVICE_RESTAURANT, + "Bibliothèque": cte.OFFICE_AND_ADMINISTRATION, + "Bureau de poste": cte.OFFICE_AND_ADMINISTRATION, + "Bâtiment incendié et inutilisable": cte.NON_HEATED, + "C.E.G.E.P. (collège d'enseignement général et professionnel)": cte.SECONDARY_SCHOOL, + "Centre commercial de quartier (15 à 44 magasins)": cte.STRIP_MALL, + "Centre commercial de voisinage (14 magasins et moins)": cte.STAND_ALONE_RETAIL, + "Centre commercial local (45 à 99 magasins)": cte.STRIP_MALL, + "Centre commercial régional (100 à 199 magasins)": cte.STRIP_MALL, + "Centre commercial super régional (200 magasins et plus)": cte.STRIP_MALL, + "Centre communautaire ou de quartier (inclus Centre diocésain)": cte.OFFICE_AND_ADMINISTRATION, + "Centre d'accueil ou établissement curatif (inclus centre de réadaptation pour handicapés physiques et mentaux)": cte.OUT_PATIENT_HEALTH_CARE, + "Centre d'appels téléphoniques": "Office", + "Centre d'entraide et de ressources communautaires (inclus ressources d'hébergement de meubles et d'alimentation)": cte.OUT_PATIENT_HEALTH_CARE, + "Centre d'entreposage de produits pétroliers (pétrole brutgaz pétrole liquéfiémazout domestique et autres produits raffinés)": cte.WAREHOUSE, + "Centre d'entreposage du gaz (avant distrib.aux consommateurs)": cte.WAREHOUSE, + "Centre de distribution ou d'expédition de marchandises diverses": cte.WAREHOUSE, + "Centre de recherche d'activités émergentes (inclus technologies langagières et la photonique)": cte.SECONDARY_SCHOOL, + "Centre de santé (inclus saunas spas et bains thérapeutiques ou turcs)": cte.OUT_PATIENT_HEALTH_CARE, + "Centre de services sociaux (C.S.S. et C.R.S.S.S.)": cte.OUT_PATIENT_HEALTH_CARE, + "Centre de transfert ou d'entreposage de déchets dangereux": cte.WAREHOUSE, + "Centre de tri postal": cte.WAREHOUSE, + "Centre de vérification technique d'automobiles et d'estimation": cte.WAREHOUSE, + "Centre local de services communautaires (C.L.S.C.)": cte.OFFICE_AND_ADMINISTRATION, + "Centre militaire de transport et d'entreposage": cte.WAREHOUSE, + "Centre récréatif en général (activités récréatives diversifiées pour tous groupes d'âge)": cte.EVENT_LOCATION, + "Centre sportif multidisciplinaire (couvert).": cte.SPORTS_LOCATION, + "Chalet ou maison de villégiature": cte.SINGLE_FAMILY_HOUSE, + "Chemin de fer (sauf train touristiqueaiguillage et cour de triage)": cte.WAREHOUSE, + "Cimetière": cte.WAREHOUSE, + "Cinéma": cte.EVENT_LOCATION, + "Clinique médicale (cabinet de médecins généralistes)": cte.OUT_PATIENT_HEALTH_CARE, + "Commission scolaire": cte.OFFICE_AND_ADMINISTRATION, + "Conserveriemarinagesaumurage et séchage de fruits et de légumes": cte.WAREHOUSE, + "Construction d'immeubles pour revente": cte.WAREHOUSE, + "Couvent": cte.EVENT_LOCATION, + "Dépanneur (sans vente d'essence)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Entreposage de tout genre": cte.WAREHOUSE, + "Entreposage du mobilier et d'appareils ménagersincluant les mini-entrepôts": cte.WAREHOUSE, + "Entreposage en vrac à l'extérieur": cte.WAREHOUSE, + "Entreposage frigorifique (sauf les armoires frigorifiques)": cte.WAREHOUSE, + "Entreprise d'excavationde nivellementde défrichage et installation de fosses septiques": cte.WAREHOUSE, + "Entrepôt pour le transport par camion": cte.WAREHOUSE, + "Entretien et équipement de chemins de fer": cte.WAREHOUSE, + "Espace de plancher inoccupé dont l'usage serait commercial autre": cte.NON_HEATED, + "Espace de plancher inoccupé dont l'usage serait industriel": cte.NON_HEATED, + "Espace de plancher inoccupé dont l'usage serait pour des fins culturelles": cte.NON_HEATED, + "Espace de plancher inoccupé dont l'usage serait pour services publics": cte.NON_HEATED, + "Espace de rangement (condo non résidentiel)": cte.NON_HEATED, + "Espace de rangement (condo)": cte.NON_HEATED, + "Espace de terrain non aménagé et non exploité (sauf l'exploitation non commerciale de la forêt)": cte.NON_HEATED, + "Espace pour le séchage des boues provenant de l'usine d'épuration": cte.WAREHOUSE, + "Fabrication de crème glacée et de desserts congelés": cte.INDUSTRY, + "Fondations et organismes de charité": cte.OFFICE_AND_ADMINISTRATION, + "Galerie d'art": cte.EVENT_LOCATION, + "Garage d'autobus et équipement d'entretien": cte.WAREHOUSE, + "Garage de stationnement pour automobiles (infrastructure)": cte.WAREHOUSE, + "Garage de stationnement pour véhicules lourds (Infrastructure)": cte.WAREHOUSE, + "Garage et équipement d'entretien pour le transport par camion (incluant garages municipaux)": cte.WAREHOUSE, + "Gare d'autobus pour passagers": cte.WAREHOUSE, + "Gare de chemins de fer": cte.WAREHOUSE, + "Gymnase et formation athlétique": cte.SPORTS_LOCATION, + "Hangar à avion": cte.WAREHOUSE, + "Hôtel (incluant les hôtels-motels)": "Hotel/Motel", + "Hôtel résidentiel": "Hotel/Motel", + "Immeuble commercial": cte.STAND_ALONE_RETAIL, + "Immeuble non résidentiel en construction": "Office", + "Immeuble résidentiel en construction": cte.RESIDENTIAL, + "Immeuble à bureaux": "Office", + "Immeuble à temps partagé («time share») Propriété ou copropriété ou groupe d'usufruitier ont chacun droit de jouissancepériodique et successif.": "Office", + "Incinérateur": cte.INDUSTRY, + "Industrie d'accessoires vestimentaires et d'autres vêtements": cte.INDUSTRY, + "Industrie d'alcools destinés à la consommation (distillerie)": cte.INDUSTRY, + "Industrie d'appareils d'éclairage (sauf ampoules et tubes)": cte.INDUSTRY, + "Industrie d'appareils orthopédiques et chirurgicaux": cte.INDUSTRY, + "Industrie d'armoires de placards de cuisine et de coiffeuses de salle de bains en bois": cte.INDUSTRY, + "Industrie d'articles de maison en textile et d'articles d'hygiène en textile": cte.INDUSTRY, + "Industrie d'articles de sport et d'athlétisme": cte.INDUSTRY, + "Industrie d'assaisonnements et de vinaigrettes": cte.INDUSTRY, + "Industrie d'autres produits de boulangerie et de pâtisseries": cte.INDUSTRY, + "Industrie d'autres vêtements coupés cousus pour hommes et garçons": cte.INDUSTRY, + "Industrie d'engrais chimique et d'engrais composé": cte.INDUSTRY, + "Industrie d'enseignes au néon (excluant les enseignes en bois) éclairage interne": cte.INDUSTRY, + "Industrie d'équipements de télécommunication": cte.INDUSTRY, + "Industrie de bas et de chaussettes": cte.INDUSTRY, + "Industrie de boissons gazeuses": cte.INDUSTRY, + "Industrie de boîtes en carton ondulé et en carton compact": cte.INDUSTRY, + "Industrie de boîtes pliantes et rigides": cte.INDUSTRY, + "Industrie de carrosseries de véhicules automobiles": cte.INDUSTRY, + "Industrie de chaudièresd'échangeurs de chaleur et de plaques métalliques": cte.INDUSTRY, + "Industrie de contenants en plastique (sauf en mousse)": cte.INDUSTRY, + "Industrie de contreplaqués en bois": cte.INDUSTRY, + "Industrie de fabrication de gaz industriel": cte.INDUSTRY, + "Industrie de fils et de câbles électriques": cte.INDUSTRY, + "Industrie de filés et de tissus tissés (coton)": cte.INDUSTRY, + "Industrie de garnitures et de raccords de plomberie en métal": cte.INDUSTRY, + "Industrie de jouets et de jeux": cte.INDUSTRY, + "Industrie de l'abattage et du conditionnement de la viande (sauf la volaille et le petit gibier)": cte.INDUSTRY, + "Industrie de l'abattage et du conditionnement de la volaille et du petit gibier": cte.INDUSTRY, + "Industrie de l'impression de formulaires commerciaux": cte.INDUSTRY, + "Industrie de l'équipement de manutention": cte.INDUSTRY, + "Industrie de l'étirage de l'extrusion et alliage de l'aluminiumfabriqué à partir d'aluminium acheté": cte.INDUSTRY, + "Industrie de la bijouterie et de l'orfèvrerie (sauf l'affinage secondaire de métaux précieux)": cte.INDUSTRY, + "Industrie de la bière": cte.INDUSTRY, + "Industrie de la chaussure": cte.INDUSTRY, + "Industrie de la confection à forfait de vêtements pour femmes et filles": cte.INDUSTRY, + "Industrie de la construction et de la réparation de navires": cte.INDUSTRY, + "Industrie de la fabrication de supports d'enregistrement de la reproduction du son et des instruments de musique": cte.INDUSTRY, + "Industrie de la glace": cte.INDUSTRY, + "Industrie de la machinerie pour la construction et du matériel d'entretien": cte.INDUSTRY, + "Industrie de la préparation et du conditionnement de poissons et de fruits de mer": cte.INDUSTRY, + "Industrie de la quincaillerie de base": cte.INDUSTRY, + "Industrie de la transformation de la viande et de la fonte des graisses animales": cte.INDUSTRY, + "Industrie de la tôlerie pour ventilation": cte.INDUSTRY, + "Industrie de lampes électriques (ampoules et tubes)": cte.INDUSTRY, + "Industrie de moteurs et de pièces de moteurs de véhicules automobiles": cte.INDUSTRY, + "Industrie de mélange de farine et de pâte": cte.INDUSTRY, + "Industrie de peinturede teinture et de vernis": cte.INDUSTRY, + "Industrie de pellicules et de feuilles non renforcées en plastique": cte.INDUSTRY, + "Industrie de pièces en plastique pour véhicules automobiles": cte.INDUSTRY, + "Industrie de pièces et de composantes électroniques": cte.INDUSTRY, + "Industrie de pneus et de chambres à air": cte.INDUSTRY, + "Industrie de portes et de fenêtres en métal": cte.INDUSTRY, + "Industrie de portes et fenêtres en plastique": cte.INDUSTRY, + "Industrie de produits chimiques inorganiques d'usage industriel": cte.INDUSTRY, + "Industrie de produits d'architecture en plastique": cte.INDUSTRY, + "Industrie de produits de boulangerie commerciale de produits de boulangerie congelés et de pâtisseries": cte.INDUSTRY, + "Industrie de produits de toilette": cte.INDUSTRY, + "Industrie de produits en pierre": cte.INDUSTRY, + "Industrie de produits en plastique stratifié sous pression ou renforcé": cte.INDUSTRY, + "Industrie de produits en verre fabriqué à partir de verre acheté": cte.INDUSTRY, + "Industrie de produits pharmaceutiques et de médicaments": cte.INDUSTRY, + "Industrie de produits pétrochimiques": cte.INDUSTRY, + "Industrie de produits pétroliers raffinés (sauf les huiles de graissage et les graisses lubrifiantes)": cte.INDUSTRY, + "Industrie de pâtes alimentaires sèches": cte.INDUSTRY, + "Industrie de récipients et de boîtes en métal": cte.INDUSTRY, + "Industrie de résines synthétiques et de caoutchouc synthétique": cte.INDUSTRY, + "Industrie de sacs et de poches en matière textile": cte.INDUSTRY, + "Industrie de sacs et de sachets en plastique": cte.INDUSTRY, + "Industrie de savons et de détachants pour le nettoyage": cte.INDUSTRY, + "Industrie de sommiers et de matelas": cte.INDUSTRY, + "Industrie de soupapes en métal": cte.INDUSTRY, + "Industrie de tapis carpettes et moquettes": cte.INDUSTRY, + "Industrie de tous les autres produits divers en bois": cte.INDUSTRY, + "Industrie de tous les autres produits en papier transformé (sauf pour le bureau)": cte.INDUSTRY, + "Industrie de ventilateursde soufflantes et de purificateurs d'air industriels et commerciaux": cte.INDUSTRY, + "Industrie de vêtements de sport pour femmes et filles": cte.INDUSTRY, + "Industrie de vêtements professionnels coupés cousus": cte.INDUSTRY, + "Industrie des pièces et accessoires d'aéronefs (incluant avions et hélicoptères)": cte.INDUSTRY, + "Industrie du béton préparé": cte.INDUSTRY, + "Industrie du cannabis": cte.INDUSTRY, + "Industrie du ciment": cte.INDUSTRY, + "Industrie du clichagede la composition de la reliure et de la lithographie": cte.INDUSTRY, + "Industrie du fromage": cte.INDUSTRY, + "Industrie du lait de consommation": cte.INDUSTRY, + "Industrie du laminagede l'étirage et de l'extrusion du cuivre et de ses alliages": cte.INDUSTRY, + "Industrie du matériel de chauffage et du matériel de réfrigération commerciale": cte.INDUSTRY, + "Industrie du matériel de transport": cte.INDUSTRY, + "Industrie du matériel ferroviaire roulant": cte.INDUSTRY, + "Industrie du matériel électrique de communication et de protection": cte.INDUSTRY, + "Industrie du meuble de maison en bois": cte.INDUSTRY, + "Industrie du meuble et d'articles d'ameublement pour hôtelsrestaurants et institutions": cte.INDUSTRY, + "Industrie du pain": cte.INDUSTRY, + "Industrie du revêtement métallique sur commande": cte.INDUSTRY, + "Industrie du sucre de canne et de betterave à sucre": cte.INDUSTRY, + "Industrie du thé et du café": cte.INDUSTRY, + "Industries des appareils d'aéronefs (incluant avions et hélicoptères)": cte.INDUSTRY, + "Installation d'équipements de réfrigération commerciale": cte.WAREHOUSE, + "Installation portuaire en général": cte.WAREHOUSE, + "Jardin botanique": cte.WAREHOUSE, + "Ligne de l'oléoduc": cte.WAREHOUSE, + "Local pour les associations fraternelles": "Office", + "Logement": cte.RESIDENTIAL, + "Logement vacant dans un bâtiment comportant plusieurs logements ou autres locaux": cte.RESIDENTIAL, + "Loisir et autres activités culturelles": "Office", + "Maison d'agentsde courtiers et de services d'administration des biens-fonds": "Office", + "Maison d'étudiants (collège et université)": "Office", + "Maison de chambres et pension": "Office", + "Maison de chambres pour personnes ayant une déficience intellectuelle": "Office", + "Maison de courtiers et de négociants de marchandises": "Office", + "Maison de réhabilitation": "Office", + "Maison des jeunes": "Office", + "Maison pour personnes en difficulté (séjours périodes limitées)": "Office", + "Maison pour personnes retraitées autonomes": cte.DORMITORY, + "Maison pour personnes retraitées non autonomes (inclus les CHLSD)": cte.DORMITORY, + "Marché public": cte.STRIP_MALL, + "Meunerie et minoterie": "Office", + "Monastère": cte.DORMITORY, + "Monument et site historique": cte.EVENT_LOCATION, + "Motel": "hotel/Motel", + "Musée": cte.EVENT_LOCATION, + "Organisme international et autres organismes extraterritoriaux": "Office", + "Parc d'amusement (extérieur)": cte.NON_HEATED, + "Parc de maisons mobiles (fonds de terre seulement)": cte.NON_HEATED, + "Parc pour la récréation en général": cte.NON_HEATED, + "Parc à caractère récréatif et ornemental": cte.NON_HEATED, + "Passage": cte.NON_HEATED, + "Piscine extérieure et activités connexes": cte.NON_HEATED, + "Piscine intérieure et activités connexes": cte.SPORTS_LOCATION, + "Pose et réparation de parement métalliques et autres (entrepreneur spécialisé)": cte.WAREHOUSE, + "Poste et bureau de douanes": cte.OFFICE_AND_ADMINISTRATION, + "Pouponnière ou garderie de nuit": cte.HOSPITAL, + "Presbytère": cte.OFFICE_AND_ADMINISTRATION, + "Prison provinciale": cte.DORMITORY, + "Protection contre l'incendie et activités connexes": cte.WAREHOUSE, + "Raffinerie de pétrole": cte.INDUSTRY, + "Restaurant et établissement avec service complet (avec terrasse) - Établissements avec permis alcool inclus pub café et brasserie": cte.FULL_SERVICE_RESTAURANT, + "Restaurant et établissement avec service complet (sans terrasse) -Établissements avec permis alcoolinclus pub café et brasserie": cte.FULL_SERVICE_RESTAURANT, + "Restaurant et établissement avec service restreint ( commande au comptoir ou par téléphone)": cte.QUICK_SERVICE_RESTAURANT, + "Restaurant et établissement offrant des repas à libre-service (cafétéria cantine)": cte.QUICK_SERVICE_RESTAURANT, + "Rue et avenue pour l'accès local": cte.NON_HEATED, + "Ruelle": cte.NON_HEATED, + "Récupération et triage de matières polluantes et toxiques": cte.WAREHOUSE, + "Récupération et triage de métaux": cte.WAREHOUSE, + "Réparation et entretien des avions": cte.WAREHOUSE, + "Réserve pour la protection de la faune": cte.NON_HEATED, + "Réservoir d'eau (installation d'emmagasinage de l'eau par retenue et réservoirs)": cte.NON_HEATED, + "Résidence de tourismeappartement maison ou chalet (meublé et équipé pour repas)": "hotel/Motel", + "Salle d'exposition": cte.EVENT_LOCATION, + "Salle et terrain de squash de racquetball et de tennis": cte.SPORTS_LOCATION, + "Salle ou salon de quilles": cte.NON_HEATED, + "Salon de beauté (maquillagemanucureetc..)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Salon de coiffure": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Salon funéraire": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Service bancaire (dépôts et prêtsincluant banque à charte)": cte.OFFICE_AND_ADMINISTRATION, + "Service d'ambulance": cte.WAREHOUSE, + "Service d'architecture": cte.OFFICE_AND_ADMINISTRATION, + "Service d'assainissement de l'environnement": cte.WAREHOUSE, + "Service d'emballage et de protection de marchandises": cte.WAREHOUSE, + "Service d'envoi de marchandises": cte.WAREHOUSE, + "Service d'hébergement des données (sites Web diffusion audio et vidéo en continu services d'application)": cte.WAREHOUSE, + "Service d'hôpital (inclus hôpitaux psychiatriques)": cte.HOSPITAL, + "Service d'optométrie": cte.OUT_PATIENT_HEALTH_CARE, + "Service de buanderie de nettoyage à sec et de teinture (sauf les tapis)": cte.WAREHOUSE, + "Service de comptabilitéde vérification et de tenue de livre": cte.OFFICE_AND_ADMINISTRATION, + "Service de construction de routesde rues et de pontsde trottoirs et de pistes (entrepreneur général)": cte.WAREHOUSE, + "Service de construction non résidentiellecommerciale et institutionnelle (entrepreneur général)": cte.WAREHOUSE, + "Service de construction non résidentielleindustrielle (entrepreneur général)": cte.WAREHOUSE, + "Service de construction résidentielle (entrepreneur)": cte.WAREHOUSE, + "Service de débosselage et de peinture d'automobiles": cte.WAREHOUSE, + "Service de garderie (prématernelle moins de 50 % de poupons)": cte.PRIMARY_SCHOOL, + "Service de génie": cte.OFFICE_AND_ADMINISTRATION, + "Service de holding et d'investissement et de fiducie": cte.OFFICE_AND_ADMINISTRATION, + "Service de laboratoire dentaire": cte.OUT_PATIENT_HEALTH_CARE, + "Service de laboratoire médical": cte.OUT_PATIENT_HEALTH_CARE, + "Service de lavage d'automobiles": cte.WAREHOUSE, + "Service de limousine": cte.WAREHOUSE, + "Service de lingerie et de buanderie industrielle": cte.WAREHOUSE, + "Service de location d'automobiles": cte.WAREHOUSE, + "Service de location d'outils ou d'équipements": cte.WAREHOUSE, + "Service de location d'équipements": cte.WAREHOUSE, + "Service de location de boites postales (sauf le publipostage) et centre de courrier privé": cte.OFFICE_AND_ADMINISTRATION, + "Service de location de camions de remorques utilitaires et de véhicules de plaisance": cte.WAREHOUSE, + "Service de maçonnerie (entrepreneur spécialisé)": cte.INDUSTRY, + "Service de messagers": "Office", + "Service de notaires": "Office", + "Service de paysagement ou de déneigement": cte.WAREHOUSE, + "Service de petite menuiserie et de finition (entrepreneur spécialisé)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Service de plomberie de chauffagede climatisation et de ventilation (entrepreneur spécialisé)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Service de police fédérale et activités connexes": cte.OFFICE_AND_ADMINISTRATION, + "Service de police municipale et activités connexes": cte.OFFICE_AND_ADMINISTRATION, + "Service de pose de portesde fenêtres et de panneaux de verre": cte.WAREHOUSE, + "Service de publicité en général": "Office", + "Service de recherche de développement et d'essais": cte.SECONDARY_SCHOOL, + "Service de remplacement de pièces et d'accessoires d'automobiles (amortisseurs silencieux toits ouvrants glacespare-brises...)": cte.WAREHOUSE, + "Service de revêtement en asphalte et en bitume": cte.WAREHOUSE, + "Service de réparation d'automobiles (garage) sans pompes à essence(5531)": cte.WAREHOUSE, + "Service de réparation d'autres véhicules légers": cte.WAREHOUSE, + "Service de réparation de véhicules légers motorisés (motocyclettemotoneige véhicule tout terrain)": cte.WAREHOUSE, + "Service de réparation et d'entretien de machines et de matériel d'usage commercial et industriel": "Office", + "Service de réparation et d'entretien de matériel informatique": "Office", + "Service de réparation et d'entretien de systèmes de plomberieschauffageventilation et climatisation.(entrepreneur spécialisé)": cte.WAREHOUSE, + "Service de réparation et d'entretien de véhicules lourds": cte.WAREHOUSE, + "Service de réparation et de rembourrage de meubles": cte.WAREHOUSE, + "Service de soudure": cte.WAREHOUSE, + "Service de toilettage pour animaux domestiques": cte.OUT_PATIENT_HEALTH_CARE, + "Service de traitement pour automobiles (antirouilleetc.)": cte.WAREHOUSE, + "Service de travaux d'électricité et installation de câblage (entrepreneur spécialisé)": cte.WAREHOUSE, + "Service de travaux de toiture (entrepreneur spécialisé)": cte.WAREHOUSE, + "Service de télécommunication sans fil (appareil mobile sauf par Internet)": cte.WAREHOUSE, + "Service de vétérinaires (animaux domestiques)": cte.OUT_PATIENT_HEALTH_CARE, + "Service de vétérinaires et d'hôpital pour animaux de ferme": cte.OUT_PATIENT_HEALTH_CARE, + "Service dentaire (inclus chirurgie et hygiène)": cte.OUT_PATIENT_HEALTH_CARE, + "Service en santé mentale (cabinet) (comprend tous services professionnelspsychiatre psychologuepsychanalyste)": cte.OUT_PATIENT_HEALTH_CARE, + "Service en travaux de fondation et de structures en béton (entrepreneur spécialisé)": "Office", + "Service informatique (location ou utilisation partagée services auxiliaires programmation planification et analyse de système)": "Office", + "Service médical (cabinet de médecins et chirurgiens spécialisés)": cte.OUT_PATIENT_HEALTH_CARE, + "Service photographique (incluant les services commerciaux)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Service pour l'entretien ménager": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Service éducationnel et de recherche scientifique": cte.SECONDARY_SCHOOL, + "Services spécialisés reliés à l'activité bancaire": cte.OFFICE_AND_ADMINISTRATION, + "Stade": cte.SPORTS_LOCATION, + "Station de contrôle de la pression de l'eau": cte.WAREHOUSE, + "Station de contrôle de la pression des eaux usées": cte.WAREHOUSE, + "Station de métro": cte.WAREHOUSE, + "Station libre-serviceou avec service et dépanneur sans réparation de véhicules automobiles": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Station libre-serviceou avec service sans réparation de véhicules automobiles": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Station-service avec réparation de véhicules automobiles": cte.WAREHOUSE, + "Stationnement extérieur (condo non résidentiel)": cte.NON_HEATED, + "Stationnement extérieur (condo)": cte.NON_HEATED, + "Stationnement intérieur ( condo non résidentiel)": cte.WAREHOUSE, + "Stationnement intérieur (condo)": cte.WAREHOUSE, + "Studio d'enregistrement du son (disque cassette et disque compact)": "Office", + "Studio de production de filmsde vidéos ou de publicités (ne comprends pas le laboratoire de production)": "Office", + "Studio de télévision (sans public)": "Office", + "Syndicat et organisation similaire": "Office", + "Terminus maritime (passagers) incluant les gares de traversiers": cte.WAREHOUSE, + "Terrain de golf (avec chalet et autres aménagements sportifs)": cte.NON_HEATED, + "Terrain de sport (jeux et pistes pour compétitions et sportgradins)": cte.NON_HEATED, + "Terrain de stationnement pour automobiles": cte.WAREHOUSE, + "Terrains de stationnement pour véhicules lourds": cte.WAREHOUSE, + "Théâtre": cte.EVENT_LOCATION, + "Tour de relais (micro-ondes)": cte.NON_HEATED, + "Tous les autres services d'information": cte.NON_HEATED, + "Transport et gestion d'électricité en bloc": cte.NON_HEATED, + "Transport et gestion du gaz par canalisation": cte.NON_HEATED, + "Université": cte.SECONDARY_SCHOOL, + "Usine de traitement des eaux (filtration)": cte.INDUSTRY, + "Usine de traitement des eaux usées (épuration)": cte.INDUSTRY, + "Vente au détail (fleuriste)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'accessoires pour femmes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'animaux de maison (animalerie)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'antiquités (sauf le marché aux puces)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'appareils orthopédiques et articles spécialisés de santé": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'articles de sport": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'articles d'accessoires d'aménagement paysager et de jardin": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'instruments et de matériel médical": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'équipements de ferme": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'équipements de plomberie de chauffagede ventilationde climatisation et de foyer": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail d'équipements et d'accessoires de chasse et pêche": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de bicyclettes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de boissons alcoolisées": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de chaussures": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de fruits et de légumes": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détail de la viande": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détail de livres et de papeterie": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de marchandises en général (sauf les marchés aux puces)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de matériaux de construction": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de matériaux de construction (cour à bois)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de matériel électrique": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de meubles": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de motocyclettes de motoneiges et de leurs accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de médicaments et d'articles divers (pharmacie)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de peinturede verre et de papier tenture": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de piscinesde spas et leurs accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de pièces de véhicules automobiles et d'accessoires usagés": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de pneus de batteries et d'accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de produits d'épicerie (avec boucherie)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détail de produits d'épicerie (sans boucherie)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détail de produits de la boulangerie et de la pâtisserie (manufacturés sur place en totalité ou non)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détail de quincaillerie": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de radiosde téléviseurssystèmes de son et appareils électroniques": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de revêtements de planchers et de murs (bois franc plancher flottant carreaux céramiques tapisserie)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de serruresde clés et d'accessoires": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de véhicules automobiles neufs et usagés": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de véhicules automobiles usagés seulement": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de vêtement prêt-à-porter pour femmes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de vêtements et d'accessoires pour hommes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de vêtements et d'articles usagésfriperies (sauf le marché aux puces)": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail de vêtements unisexes": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détail du cafédu théd'épices et d'aromates": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détailclubs de gros et hypermarchés (entrepôt-club)": cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD, + "Vente au détailfournitures pour la maison et l'auto": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente au détailmagasin à rayons": cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD, + "Vente en gros d'ameublements de matériels de bureau et de magasin": cte.STRIP_MALL, + "Vente en gros d'appareils et d'équipements de plomberie et de chauffage": cte.STRIP_MALL, + "Vente en gros d'appareils et d'équipements électriques de fils et de matériel électronique de construction": cte.STRIP_MALL, + "Vente en gros d'appareils électriquesde téléviseurs et de radios": cte.STRIP_MALL, + "Vente en gros d'automobiles et autres véhicules automobiles neufs ou d'occasions incluent VR)": cte.STRIP_MALL, + "Vente en gros d'autres appareils ou matériels électriques et électroniques": cte.STRIP_MALL, + "Vente en gros d'autres médicaments de produits chimiques et de produits connexes": cte.STRIP_MALL, + "Vente en gros d'autres pièces d'équipement ou de machinerie (incluant machinerie lourde)": cte.STRIP_MALL, + "Vente en gros d'autres produits reliés à l'épicerie": cte.STRIP_MALL, + "Vente en gros d'équipements et de pièces de machinerie commercialeindustrielle ou agricole (incluant machinerie lourde)": cte.STRIP_MALL, + "Vente en gros d'équipements et de pièces pour la réfrigération ventilation la climatisation et le chauffage (système combiné)": cte.STRIP_MALL, + "Vente en gros d'équipements et de pièces pour les entreprises de services": cte.STRIP_MALL, + "Vente en gros de bois et de matériaux de construction": cte.STRIP_MALL, + "Vente en gros de chaussures": cte.STRIP_MALL, + "Vente en gros de fruits et de légumes frais": cte.STRIP_MALL, + "Vente en gros de médicaments et de produits médicamenteux": cte.STRIP_MALL, + "Vente en gros de pièces et d'accessoires neufs pour véhicules automobiles": cte.STRIP_MALL, + "Vente en gros de pièces et d'équipements électroniques": cte.STRIP_MALL, + "Vente en gros de pneus et de chambres à air": cte.STRIP_MALL, + "Vente en gros de poissons et de fruits de mer": cte.STRIP_MALL, + "Vente en gros de produits de beauté": cte.STRIP_MALL, + "Vente en gros de produits de boulangerie et de pâtisserie": cte.STRIP_MALL, + "Vente en gros de produits laitiers": cte.STRIP_MALL, + "Vente en gros de quincaillerie": cte.STRIP_MALL, + "Vente en gros de tissus et de textiles": cte.STRIP_MALL, + "Vente en gros de viandes et de produits de la viande": cte.STRIP_MALL, + "Vente en gros de vêtements de lingerie de bas et d'accessoires": cte.STRIP_MALL, + "Vente en gros pour l'épicerie en général": cte.STRIP_MALL, + "École commerciale et de secrétariat (non intégrée aux polyvalentes)": cte.SECONDARY_SCHOOL, + "École de beaux-arts et de musique (exclus arts publicitaires arts graphiques et photographie publicitaire)": cte.SECONDARY_SCHOOL, + "École de danse": cte.SECONDARY_SCHOOL, + "École de métiers (non intégrée aux polyvalentes)": cte.SECONDARY_SCHOOL, + "École maternelle": cte.SECONDARY_SCHOOL, + "École polyvalente": cte.SECONDARY_SCHOOL, + "École secondaire": cte.SECONDARY_SCHOOL, + "École à caractère familial (exploité par une personne physique dans sa résidence moins de 15 élèves)": cte.SECONDARY_SCHOOL, + "École élémentaire": cte.SECONDARY_SCHOOL, + "École élémentaire et secondaire": cte.SECONDARY_SCHOOL, + "Église synagogue mosquée et temple": cte.EVENT_LOCATION, + "Établissement avec salle de réception ou de banquet": cte.FULL_SERVICE_RESTAURANT, + "Établissement avec service de boissons alcoolisées (Bar)": cte.QUICK_SERVICE_RESTAURANT, + "Établissement dont l'activité principale est la danse (discothèque avec service alcool boite de nuit) sans alcool code 7397": cte.QUICK_SERVICE_RESTAURANT + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/data/pluto_function_to_hub_function.py b/hub/helpers/data/pluto_function_to_hub_function.py new file mode 100644 index 00000000..c7a640d8 --- /dev/null +++ b/hub/helpers/data/pluto_function_to_hub_function.py @@ -0,0 +1,217 @@ +""" +Dictionaries module for Pluto function to hub function +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import hub.helpers.constants as cte + + +class PlutoFunctionToHubFunction: + + def __init__(self): + self._dictionary = { + 'A0': cte.SINGLE_FAMILY_HOUSE, + 'A1': cte.SINGLE_FAMILY_HOUSE, + 'A2': cte.SINGLE_FAMILY_HOUSE, + 'A3': cte.SINGLE_FAMILY_HOUSE, + 'A4': cte.SINGLE_FAMILY_HOUSE, + 'A5': cte.SINGLE_FAMILY_HOUSE, + 'A6': cte.SINGLE_FAMILY_HOUSE, + 'A7': cte.SINGLE_FAMILY_HOUSE, + 'A8': cte.SINGLE_FAMILY_HOUSE, + 'A9': cte.SINGLE_FAMILY_HOUSE, + 'B1': cte.MULTI_FAMILY_HOUSE, + 'B2': cte.MULTI_FAMILY_HOUSE, + 'B3': cte.MULTI_FAMILY_HOUSE, + 'B9': cte.MULTI_FAMILY_HOUSE, + 'C0': cte.RESIDENTIAL, + 'C1': cte.RESIDENTIAL, + 'C2': cte.RESIDENTIAL, + 'C3': cte.RESIDENTIAL, + 'C4': cte.RESIDENTIAL, + 'C5': cte.RESIDENTIAL, + 'C6': cte.RESIDENTIAL, + 'C7': cte.RESIDENTIAL, + 'C8': cte.RESIDENTIAL, + 'C9': cte.RESIDENTIAL, + 'D0': cte.RESIDENTIAL, + 'D1': cte.RESIDENTIAL, + 'D2': cte.RESIDENTIAL, + 'D3': cte.RESIDENTIAL, + 'D4': cte.RESIDENTIAL, + 'D5': cte.RESIDENTIAL, + 'D6': cte.RESIDENTIAL, + 'D7': cte.RESIDENTIAL, + 'D8': cte.RESIDENTIAL, + 'D9': cte.RESIDENTIAL, + 'E1': cte.WAREHOUSE, + 'E3': cte.WAREHOUSE, + 'E4': cte.WAREHOUSE, + 'E5': cte.WAREHOUSE, + 'E7': cte.WAREHOUSE, + 'E9': cte.WAREHOUSE, + 'F1': cte.WAREHOUSE, + 'F2': cte.WAREHOUSE, + 'F4': cte.WAREHOUSE, + 'F5': cte.WAREHOUSE, + 'F8': cte.WAREHOUSE, + 'F9': cte.WAREHOUSE, + 'G0': cte.SMALL_OFFICE, + 'G1': cte.SMALL_OFFICE, + 'G2': cte.SMALL_OFFICE, + 'G3': cte.SMALL_OFFICE, + 'G4': cte.SMALL_OFFICE, + 'G5': cte.SMALL_OFFICE, + 'G6': cte.SMALL_OFFICE, + 'G7': cte.SMALL_OFFICE, + 'G8': cte.SMALL_OFFICE, + 'G9': cte.SMALL_OFFICE, + 'H1': cte.HOTEL, + 'H2': cte.HOTEL, + 'H3': cte.HOTEL, + 'H4': cte.HOTEL, + 'H5': cte.HOTEL, + 'H6': cte.HOTEL, + 'H7': cte.HOTEL, + 'H8': cte.HOTEL, + 'H9': cte.HOTEL, + 'HB': cte.HOTEL, + 'HH': cte.HOTEL, + 'HR': cte.HOTEL, + 'HS': cte.HOTEL, + 'I1': cte.HOSPITAL, + 'I2': cte.OUT_PATIENT_HEALTH_CARE, + 'I3': cte.OUT_PATIENT_HEALTH_CARE, + 'I4': cte.RESIDENTIAL, + 'I5': cte.OUT_PATIENT_HEALTH_CARE, + 'I6': cte.OUT_PATIENT_HEALTH_CARE, + 'I7': cte.OUT_PATIENT_HEALTH_CARE, + 'I9': cte.OUT_PATIENT_HEALTH_CARE, + 'J1': cte.LARGE_OFFICE, + 'J2': cte.LARGE_OFFICE, + 'J3': cte.LARGE_OFFICE, + 'J4': cte.LARGE_OFFICE, + 'J5': cte.LARGE_OFFICE, + 'J6': cte.LARGE_OFFICE, + 'J7': cte.LARGE_OFFICE, + 'J8': cte.LARGE_OFFICE, + 'J9': cte.LARGE_OFFICE, + 'K1': cte.STRIP_MALL, + 'K2': cte.STRIP_MALL, + 'K3': cte.STRIP_MALL, + 'K4': cte.RESIDENTIAL, + 'K5': cte.RESTAURANT, + 'K6': cte.SUPERMARKET, + 'K7': cte.SUPERMARKET, + 'K8': cte.SUPERMARKET, + 'K9': cte.SUPERMARKET, + 'L1': cte.RESIDENTIAL, + 'L2': cte.RESIDENTIAL, + 'L3': cte.RESIDENTIAL, + 'L8': cte.RESIDENTIAL, + 'L9': cte.RESIDENTIAL, + 'M1': cte.LARGE_OFFICE, + 'M2': cte.LARGE_OFFICE, + 'M3': cte.LARGE_OFFICE, + 'M4': cte.LARGE_OFFICE, + 'M9': cte.LARGE_OFFICE, + 'N1': cte.RESIDENTIAL, + 'N2': cte.RESIDENTIAL, + 'N3': cte.RESIDENTIAL, + 'N4': cte.RESIDENTIAL, + 'N9': cte.RESIDENTIAL, + 'O1': cte.SMALL_OFFICE, + 'O2': cte.SMALL_OFFICE, + 'O3': cte.SMALL_OFFICE, + 'O4': cte.SMALL_OFFICE, + 'O5': cte.SMALL_OFFICE, + 'O6': cte.SMALL_OFFICE, + 'O7': cte.SMALL_OFFICE, + 'O8': cte.SMALL_OFFICE, + 'O9': cte.SMALL_OFFICE, + 'P1': cte.LARGE_OFFICE, + 'P2': cte.HOTEL, + 'P3': cte.SMALL_OFFICE, + 'P4': cte.SMALL_OFFICE, + 'P5': cte.SMALL_OFFICE, + 'P6': cte.SMALL_OFFICE, + 'P7': cte.LARGE_OFFICE, + 'P8': cte.LARGE_OFFICE, + 'P9': cte.SMALL_OFFICE, + 'Q0': cte.SMALL_OFFICE, + 'Q1': cte.SMALL_OFFICE, + 'Q2': cte.SMALL_OFFICE, + 'Q3': cte.SMALL_OFFICE, + 'Q4': cte.SMALL_OFFICE, + 'Q5': cte.SMALL_OFFICE, + 'Q6': cte.SMALL_OFFICE, + 'Q7': cte.SMALL_OFFICE, + 'Q8': cte.SMALL_OFFICE, + 'Q9': cte.SMALL_OFFICE, + 'R0': cte.RESIDENTIAL, + 'R1': cte.RESIDENTIAL, + 'R2': cte.RESIDENTIAL, + 'R3': cte.RESIDENTIAL, + 'R4': cte.RESIDENTIAL, + 'R5': cte.RESIDENTIAL, + 'R6': cte.RESIDENTIAL, + 'R7': cte.RESIDENTIAL, + 'R8': cte.RESIDENTIAL, + 'R9': cte.RESIDENTIAL, + 'RA': cte.RESIDENTIAL, + 'RB': cte.RESIDENTIAL, + 'RC': cte.RESIDENTIAL, + 'RD': cte.RESIDENTIAL, + 'RG': cte.RESIDENTIAL, + 'RH': cte.RESIDENTIAL, + 'RI': cte.RESIDENTIAL, + 'RK': cte.RESIDENTIAL, + 'RM': cte.RESIDENTIAL, + 'RR': cte.RESIDENTIAL, + 'RS': cte.RESIDENTIAL, + 'RW': cte.RESIDENTIAL, + 'RX': cte.RESIDENTIAL, + 'RZ': cte.RESIDENTIAL, + 'S0': cte.RESIDENTIAL, + 'S1': cte.RESIDENTIAL, + 'S2': cte.RESIDENTIAL, + 'S3': cte.RESIDENTIAL, + 'S4': cte.RESIDENTIAL, + 'S5': cte.RESIDENTIAL, + 'S9': cte.RESIDENTIAL, + 'U0': cte.WAREHOUSE, + 'U1': cte.WAREHOUSE, + 'U2': cte.WAREHOUSE, + 'U3': cte.WAREHOUSE, + 'U4': cte.WAREHOUSE, + 'U5': cte.WAREHOUSE, + 'U6': cte.WAREHOUSE, + 'U7': cte.WAREHOUSE, + 'U8': cte.WAREHOUSE, + 'U9': cte.WAREHOUSE, + 'W1': cte.PRIMARY_SCHOOL, + 'W2': cte.PRIMARY_SCHOOL, + 'W3': cte.SECONDARY_SCHOOL, + 'W4': cte.EDUCATION, + 'W5': cte.SECONDARY_SCHOOL, + 'W6': cte.SECONDARY_SCHOOL, + 'W7': cte.SECONDARY_SCHOOL, + 'W8': cte.PRIMARY_SCHOOL, + 'W9': cte.SECONDARY_SCHOOL, + 'Y1': cte.LARGE_OFFICE, + 'Y2': cte.LARGE_OFFICE, + 'Y3': cte.LARGE_OFFICE, + 'Y4': cte.LARGE_OFFICE, + 'Y5': cte.LARGE_OFFICE, + 'Y6': cte.LARGE_OFFICE, + 'Y7': cte.LARGE_OFFICE, + 'Y8': cte.LARGE_OFFICE, + 'Y9': cte.LARGE_OFFICE, + 'Z1': cte.LARGE_OFFICE + } + + @property + def dictionary(self) -> dict: + return self._dictionary diff --git a/hub/helpers/dictionaries.py b/hub/helpers/dictionaries.py index 46588375..3561d682 100644 --- a/hub/helpers/dictionaries.py +++ b/hub/helpers/dictionaries.py @@ -5,591 +5,88 @@ Copyright © 2022 Concordia CERC group Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import hub.helpers.constants as cte - +from hub.helpers.data.hft_function_to_hub_function import HftFunctionToHubFunction +from hub.helpers.data.montreal_function_to_hub_function import MontrealFunctionToHubFunction +from hub.helpers.data.alkis_function_to_hub_function import AlkisFunctionToHubFunction +from hub.helpers.data.pluto_function_to_hub_function import PlutoFunctionToHubFunction +from hub.helpers.data.hub_function_to_nrel_construction_function import HubFunctionToNrelConstructionFunction +from hub.helpers.data.hub_function_to_nrcan_construction_function import HubFunctionToNrcanConstructionFunction +from hub.helpers.data.hub_usage_to_comnet_usage import HubUsageToComnetUsage +from hub.helpers.data.hub_usage_to_hft_usage import HubUsageToHftUsage +from hub.helpers.data.hub_usage_to_nrcan_usage import HubUsageToNrcanUsage class Dictionaries: """ Dictionaries class """ - _usage_to_hft_usage = { - cte.RESIDENTIAL: 'residential', - cte.SINGLE_FAMILY_HOUSE: 'single family house', - cte.MULTI_FAMILY_HOUSE: 'multifamily house', - cte.ROW_HOUSE: 'single family house', - cte.MID_RISE_APARTMENT: 'multifamily house', - cte.HIGH_RISE_APARTMENT: 'multifamily house', - cte.OFFICE_AND_ADMINISTRATION: 'office and administration', - cte.SMALL_OFFICE: 'office and administration', - cte.MEDIUM_OFFICE: 'office and administration', - cte.LARGE_OFFICE: 'office and administration', - cte.COURTHOUSE: 'office and administration', - cte.FIRE_STATION: 'office and administration', - cte.PENITENTIARY: 'school with shower', - cte.POLICE_STATION: 'office and administration', - cte.POST_OFFICE: 'office and administration', - cte.LIBRARY: 'office and administration', - cte.EDUCATION: 'education', - cte.PRIMARY_SCHOOL: 'school without shower', - cte.PRIMARY_SCHOOL_WITH_SHOWER: 'school with shower', - cte.SECONDARY_SCHOOL: 'education', - cte.UNIVERSITY: 'education', - cte.LABORATORY_AND_RESEARCH_CENTER: 'laboratory and research centers', - cte.STAND_ALONE_RETAIL: 'retail', - cte.HOSPITAL: 'health care', - cte.OUT_PATIENT_HEALTH_CARE: 'health care', - cte.HEALTH_CARE: 'health care', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Home for the aged or orphanage', - cte.COMMERCIAL: 'retail', - cte.STRIP_MALL: 'retail', - cte.SUPERMARKET: 'retail shop / refrigerated food', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'retail shop / refrigerated food', - cte.RESTAURANT: 'restaurant', - cte.QUICK_SERVICE_RESTAURANT: 'restaurant', - cte.FULL_SERVICE_RESTAURANT: 'restaurant', - cte.HOTEL: 'hotel', - cte.HOTEL_MEDIUM_CLASS: 'hotel (Medium-class)', - cte.SMALL_HOTEL: 'hotel', - cte.LARGE_HOTEL: 'hotel', - cte.DORMITORY: 'dormitory', - cte.EVENT_LOCATION: 'event location', - cte.CONVENTION_CENTER: 'event location', - cte.HALL: 'hall', - cte.GREEN_HOUSE: 'green house', - cte.INDUSTRY: 'industry', - cte.WORKSHOP: 'industry', - cte.WAREHOUSE: 'industry', - cte.WAREHOUSE_REFRIGERATED: 'industry', - cte.SPORTS_LOCATION: 'sport location', - cte.SPORTS_ARENA: 'sport location', - cte.GYMNASIUM: 'sport location', - cte.MOTION_PICTURE_THEATRE: 'event location', - cte.MUSEUM: 'event location', - cte.PERFORMING_ARTS_THEATRE: 'event location', - cte.TRANSPORTATION: 'n/a', - cte.AUTOMOTIVE_FACILITY: 'n/a', - cte.PARKING_GARAGE: 'n/a', - cte.RELIGIOUS: 'event location', - cte.NON_HEATED: 'non-heated' - } - - _usage_to_comnet_usage = { - cte.RESIDENTIAL: 'BA Multifamily', - cte.SINGLE_FAMILY_HOUSE: 'BA Multifamily', - cte.MULTI_FAMILY_HOUSE: 'BA Multifamily', - cte.ROW_HOUSE: 'BA Multifamily', - cte.MID_RISE_APARTMENT: 'BA Multifamily', - cte.HIGH_RISE_APARTMENT: 'BA Multifamily', - cte.OFFICE_AND_ADMINISTRATION: 'BA Office', - cte.SMALL_OFFICE: 'BA Office', - cte.MEDIUM_OFFICE: 'BA Office', - cte.LARGE_OFFICE: 'BA Office', - cte.COURTHOUSE: 'BA Courthouse', - cte.FIRE_STATION: 'BA Fire Station', - cte.PENITENTIARY: 'BA Penitentiary', - cte.POLICE_STATION: 'BA Police Station', - cte.POST_OFFICE: 'BA Post Office', - cte.LIBRARY: 'BA Library', - cte.EDUCATION: 'BA School/University', - cte.PRIMARY_SCHOOL: 'BA School/University', - cte.PRIMARY_SCHOOL_WITH_SHOWER: 'BA School/University', - cte.SECONDARY_SCHOOL: 'BA School/University', - cte.UNIVERSITY: 'BA School/University', - cte.LABORATORY_AND_RESEARCH_CENTER: 'BA School/University', - cte.STAND_ALONE_RETAIL: 'BA Retail', - cte.HOSPITAL: 'BA Hospital', - cte.OUT_PATIENT_HEALTH_CARE: 'BA Healthcare Clinic', - cte.HEALTH_CARE: 'BA Healthcare Clinic', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'BA Healthcare Clinic', - cte.COMMERCIAL: 'BA Retail', - cte.STRIP_MALL: 'BA Retail', - cte.SUPERMARKET: 'BA Retail', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'BA Retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'BA Retail', - cte.RESTAURANT: 'BA Dining: Bar Lounge/Leisure', - cte.QUICK_SERVICE_RESTAURANT: 'BA Dining: Cafeteria/Fast Food', - cte.FULL_SERVICE_RESTAURANT: 'BA Dining: Bar Lounge/Leisure', - cte.HOTEL: 'BA Hotel', - cte.HOTEL_MEDIUM_CLASS: 'BA Motel', - cte.SMALL_HOTEL: 'BA Motel', - cte.LARGE_HOTEL: 'BA Hotel', - cte.DORMITORY: 'BA Dormitory', - cte.EVENT_LOCATION: 'BA Convention Center', - cte.CONVENTION_CENTER: 'BA Convention Center', - cte.HALL: 'BA Town Hall', - cte.GREEN_HOUSE: 'n/a', - cte.INDUSTRY: 'BA Manufacturing Facility', - cte.WORKSHOP: 'BA Workshop', - cte.WAREHOUSE: 'BA Warehouse', - cte.WAREHOUSE_REFRIGERATED: 'BA Warehouse', - cte.SPORTS_LOCATION: 'BA Exercise Center', - cte.SPORTS_ARENA: 'BA Sports Arena', - cte.GYMNASIUM: 'BA Gymnasium', - cte.MOTION_PICTURE_THEATRE: 'BA Motion Picture Theater', - cte.MUSEUM: 'BA Museum', - cte.PERFORMING_ARTS_THEATRE: 'BA Performing Arts Theater', - cte.TRANSPORTATION: 'BA Transportation', - cte.AUTOMOTIVE_FACILITY: 'BA Automotive Facility', - cte.PARKING_GARAGE: 'BA Parking Garage', - cte.RELIGIOUS: 'BA Religious Building', - cte.NON_HEATED: 'n/a' - } - - _usage_to_nrcan_usage = { - cte.RESIDENTIAL: 'Multi-unit residential building', - cte.SINGLE_FAMILY_HOUSE: 'Multi-unit residential building', - cte.MULTI_FAMILY_HOUSE: 'Multi-unit residential building', - cte.ROW_HOUSE: 'Multi-unit residential building', - cte.MID_RISE_APARTMENT: 'Multi-unit residential building', - cte.HIGH_RISE_APARTMENT: 'Multi-unit residential building', - cte.OFFICE_AND_ADMINISTRATION: 'Office', - cte.SMALL_OFFICE: 'Office', - cte.MEDIUM_OFFICE: 'Office', - cte.LARGE_OFFICE: 'Office', - cte.COURTHOUSE: 'Courthouse', - cte.FIRE_STATION: 'Fire station', - cte.PENITENTIARY: 'Penitentiary', - cte.POLICE_STATION: 'Police station', - cte.POST_OFFICE: 'Post office', - cte.LIBRARY: 'Library', - cte.EDUCATION: 'School/university', - cte.PRIMARY_SCHOOL: 'School/university', - cte.PRIMARY_SCHOOL_WITH_SHOWER: 'School/university', - cte.SECONDARY_SCHOOL: 'School/university', - cte.UNIVERSITY: 'School/university', - cte.LABORATORY_AND_RESEARCH_CENTER: 'School/university', - cte.STAND_ALONE_RETAIL: 'Retail', - cte.HOSPITAL: 'Hospital', - cte.OUT_PATIENT_HEALTH_CARE: 'Health-care clinic', - cte.HEALTH_CARE: 'Health-care clinic', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'Health-care clinic', - cte.COMMERCIAL: 'Retail', - cte.STRIP_MALL: 'Retail', - cte.SUPERMARKET: 'Retail', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'Retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'Retail', - cte.RESTAURANT: 'Dining - bar/lounge', - cte.QUICK_SERVICE_RESTAURANT: 'Dining - cafeteria', - cte.FULL_SERVICE_RESTAURANT: 'Dining - bar/lounge', - cte.HOTEL: 'Hotel', - cte.HOTEL_MEDIUM_CLASS: 'Motel', - cte.SMALL_HOTEL: 'Motel', - cte.LARGE_HOTEL: 'Hotel', - cte.DORMITORY: 'Dormitory', - cte.EVENT_LOCATION: 'Convention centre', - cte.CONVENTION_CENTER: 'Convention centre', - cte.HALL: 'Town hall', - cte.GREEN_HOUSE: 'n/a', - cte.INDUSTRY: 'Manufacturing facility', - cte.WORKSHOP: 'Workshop', - cte.WAREHOUSE: 'Warehouse', - cte.WAREHOUSE_REFRIGERATED: 'Warehouse - refrigerated', - cte.SPORTS_LOCATION: 'Exercise centre', - cte.SPORTS_ARENA: 'Sports arena', - cte.GYMNASIUM: 'Gymnasium', - cte.MOTION_PICTURE_THEATRE: 'Motion picture theatre', - cte.MUSEUM: 'Museum', - cte.PERFORMING_ARTS_THEATRE: 'Performing arts theatre', - cte.TRANSPORTATION: 'Transportation', - cte.AUTOMOTIVE_FACILITY: 'Automotive facility', - cte.PARKING_GARAGE: 'Parking garage', - cte.RELIGIOUS: 'Religious', - cte.NON_HEATED: 'n/a' - } - - _function_to_nrcan_construction_function = { - cte.RESIDENTIAL: 'MidriseApartment', - cte.SINGLE_FAMILY_HOUSE: 'MidriseApartment', - cte.MULTI_FAMILY_HOUSE: 'HighriseApartment', - cte.ROW_HOUSE: 'MidriseApartment', - cte.MID_RISE_APARTMENT: 'MidriseApartment', - cte.HIGH_RISE_APARTMENT: 'HighriseApartment', - cte.OFFICE_AND_ADMINISTRATION: 'MediumOffice', - cte.SMALL_OFFICE: 'SmallOffice', - cte.MEDIUM_OFFICE: 'MediumOffice', - cte.LARGE_OFFICE: 'LargeOffice', - cte.COURTHOUSE: 'MediumOffice', - cte.FIRE_STATION: 'n/a', - cte.PENITENTIARY: 'LargeHotel', - cte.POLICE_STATION: 'n/a', - cte.POST_OFFICE: 'MediumOffice', - cte.LIBRARY: 'MediumOffice', - cte.EDUCATION: 'SecondarySchool', - cte.PRIMARY_SCHOOL: 'PrimarySchool', - cte.PRIMARY_SCHOOL_WITH_SHOWER: 'PrimarySchool', - cte.SECONDARY_SCHOOL: 'SecondarySchool', - cte.UNIVERSITY: 'SecondarySchool', - cte.LABORATORY_AND_RESEARCH_CENTER: 'SecondarySchool', - cte.STAND_ALONE_RETAIL: 'RetailStandalone', - cte.HOSPITAL: 'Hospital', - cte.OUT_PATIENT_HEALTH_CARE: 'Outpatient', - cte.HEALTH_CARE: 'Outpatient', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'SmallHotel', - cte.COMMERCIAL: 'RetailStripmall', - cte.STRIP_MALL: 'RetailStripmall', - cte.SUPERMARKET: 'RetailStripmall', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'RetailStandalone', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'RetailStandalone', - cte.RESTAURANT: 'FullServiceRestaurant', - cte.QUICK_SERVICE_RESTAURANT: 'QuickServiceRestaurant', - cte.FULL_SERVICE_RESTAURANT: 'FullServiceRestaurant', - cte.HOTEL: 'SmallHotel', - cte.HOTEL_MEDIUM_CLASS: 'SmallHotel', - cte.SMALL_HOTEL: 'SmallHotel', - cte.LARGE_HOTEL: 'LargeHotel', - cte.DORMITORY: 'SmallHotel', - cte.EVENT_LOCATION: 'n/a', - cte.CONVENTION_CENTER: 'n/a', - cte.HALL: 'n/a', - cte.GREEN_HOUSE: 'n/a', - cte.INDUSTRY: 'n/a', - cte.WORKSHOP: 'n/a', - cte.WAREHOUSE: 'Warehouse', - cte.WAREHOUSE_REFRIGERATED: 'Warehouse', - cte.SPORTS_LOCATION: 'n/a', - cte.SPORTS_ARENA: 'n/a', - cte.GYMNASIUM: 'n/a', - cte.MOTION_PICTURE_THEATRE: 'n/a', - cte.MUSEUM: 'n/a', - cte.PERFORMING_ARTS_THEATRE: 'n/a', - cte.TRANSPORTATION: 'n/a', - cte.AUTOMOTIVE_FACILITY: 'n/a', - cte.PARKING_GARAGE: 'n/a', - cte.RELIGIOUS: 'n/a', - cte.NON_HEATED: 'n/a' - } - - _function_to_nrel_construction_function = { - cte.RESIDENTIAL: 'residential', - cte.SINGLE_FAMILY_HOUSE: 'residential', - cte.MULTI_FAMILY_HOUSE: 'midrise apartment', - cte.ROW_HOUSE: 'midrise apartment', - cte.MID_RISE_APARTMENT: 'midrise apartment', - cte.HIGH_RISE_APARTMENT: 'high-rise apartment', - cte.OFFICE_AND_ADMINISTRATION: 'medium office', - cte.SMALL_OFFICE: 'small office', - cte.MEDIUM_OFFICE: 'medium office', - cte.LARGE_OFFICE: 'large office', - cte.COURTHOUSE: 'medium office', - cte.FIRE_STATION: 'n/a', - cte.PENITENTIARY: 'large hotel', - cte.POLICE_STATION: 'n/a', - cte.POST_OFFICE: 'medium office', - cte.LIBRARY: 'medium office', - cte.EDUCATION: 'secondary school', - cte.PRIMARY_SCHOOL: 'primary school', - cte.PRIMARY_SCHOOL_WITH_SHOWER: 'primary school', - cte.SECONDARY_SCHOOL: 'secondary school', - cte.UNIVERSITY: 'secondary school', - cte.LABORATORY_AND_RESEARCH_CENTER: 'secondary school', - cte.STAND_ALONE_RETAIL: 'stand-alone retail', - cte.HOSPITAL: 'hospital', - cte.OUT_PATIENT_HEALTH_CARE: 'outpatient healthcare', - cte.HEALTH_CARE: 'outpatient healthcare', - cte.RETIREMENT_HOME_OR_ORPHANAGE: 'small hotel', - cte.COMMERCIAL: 'strip mall', - cte.STRIP_MALL: 'strip mall', - cte.SUPERMARKET: 'supermarket', - cte.RETAIL_SHOP_WITHOUT_REFRIGERATED_FOOD: 'stand-alone retail', - cte.RETAIL_SHOP_WITH_REFRIGERATED_FOOD: 'stand-alone retail', - cte.RESTAURANT: 'full service restaurant', - cte.QUICK_SERVICE_RESTAURANT: 'quick service restaurant', - cte.FULL_SERVICE_RESTAURANT: 'full service restaurant', - cte.HOTEL: 'small hotel', - cte.HOTEL_MEDIUM_CLASS: 'small hotel', - cte.SMALL_HOTEL: 'small hotel', - cte.LARGE_HOTEL: 'large hotel', - cte.DORMITORY: 'small hotel', - cte.EVENT_LOCATION: 'n/a', - cte.CONVENTION_CENTER: 'n/a', - cte.HALL: 'n/a', - cte.GREEN_HOUSE: 'n/a', - cte.INDUSTRY: 'n/a', - cte.WORKSHOP: 'n/a', - cte.WAREHOUSE: 'warehouse', - cte.WAREHOUSE_REFRIGERATED: 'warehouse', - cte.SPORTS_LOCATION: 'n/a', - cte.SPORTS_ARENA: 'n/a', - cte.GYMNASIUM: 'n/a', - cte.MOTION_PICTURE_THEATRE: 'n/a', - cte.MUSEUM: 'n/a', - cte.PERFORMING_ARTS_THEATRE: 'n/a', - cte.TRANSPORTATION: 'n/a', - cte.AUTOMOTIVE_FACILITY: 'n/a', - cte.PARKING_GARAGE: 'n/a', - cte.RELIGIOUS: 'n/a', - cte.NON_HEATED: 'n/a' - } - - _pluto_function_to_hub_function = { - 'A0': cte.SINGLE_FAMILY_HOUSE, - 'A1': cte.SINGLE_FAMILY_HOUSE, - 'A2': cte.SINGLE_FAMILY_HOUSE, - 'A3': cte.SINGLE_FAMILY_HOUSE, - 'A4': cte.SINGLE_FAMILY_HOUSE, - 'A5': cte.SINGLE_FAMILY_HOUSE, - 'A6': cte.SINGLE_FAMILY_HOUSE, - 'A7': cte.SINGLE_FAMILY_HOUSE, - 'A8': cte.SINGLE_FAMILY_HOUSE, - 'A9': cte.SINGLE_FAMILY_HOUSE, - 'B1': cte.MULTI_FAMILY_HOUSE, - 'B2': cte.MULTI_FAMILY_HOUSE, - 'B3': cte.MULTI_FAMILY_HOUSE, - 'B9': cte.MULTI_FAMILY_HOUSE, - 'C0': cte.RESIDENTIAL, - 'C1': cte.RESIDENTIAL, - 'C2': cte.RESIDENTIAL, - 'C3': cte.RESIDENTIAL, - 'C4': cte.RESIDENTIAL, - 'C5': cte.RESIDENTIAL, - 'C6': cte.RESIDENTIAL, - 'C7': cte.RESIDENTIAL, - 'C8': cte.RESIDENTIAL, - 'C9': cte.RESIDENTIAL, - 'D0': cte.RESIDENTIAL, - 'D1': cte.RESIDENTIAL, - 'D2': cte.RESIDENTIAL, - 'D3': cte.RESIDENTIAL, - 'D4': cte.RESIDENTIAL, - 'D5': cte.RESIDENTIAL, - 'D6': cte.RESIDENTIAL, - 'D7': cte.RESIDENTIAL, - 'D8': cte.RESIDENTIAL, - 'D9': cte.RESIDENTIAL, - 'E1': cte.WAREHOUSE, - 'E3': cte.WAREHOUSE, - 'E4': cte.WAREHOUSE, - 'E5': cte.WAREHOUSE, - 'E7': cte.WAREHOUSE, - 'E9': cte.WAREHOUSE, - 'F1': cte.WAREHOUSE, - 'F2': cte.WAREHOUSE, - 'F4': cte.WAREHOUSE, - 'F5': cte.WAREHOUSE, - 'F8': cte.WAREHOUSE, - 'F9': cte.WAREHOUSE, - 'G0': cte.SMALL_OFFICE, - 'G1': cte.SMALL_OFFICE, - 'G2': cte.SMALL_OFFICE, - 'G3': cte.SMALL_OFFICE, - 'G4': cte.SMALL_OFFICE, - 'G5': cte.SMALL_OFFICE, - 'G6': cte.SMALL_OFFICE, - 'G7': cte.SMALL_OFFICE, - 'G8': cte.SMALL_OFFICE, - 'G9': cte.SMALL_OFFICE, - 'H1': cte.HOTEL, - 'H2': cte.HOTEL, - 'H3': cte.HOTEL, - 'H4': cte.HOTEL, - 'H5': cte.HOTEL, - 'H6': cte.HOTEL, - 'H7': cte.HOTEL, - 'H8': cte.HOTEL, - 'H9': cte.HOTEL, - 'HB': cte.HOTEL, - 'HH': cte.HOTEL, - 'HR': cte.HOTEL, - 'HS': cte.HOTEL, - 'I1': cte.HOSPITAL, - 'I2': cte.OUT_PATIENT_HEALTH_CARE, - 'I3': cte.OUT_PATIENT_HEALTH_CARE, - 'I4': cte.RESIDENTIAL, - 'I5': cte.OUT_PATIENT_HEALTH_CARE, - 'I6': cte.OUT_PATIENT_HEALTH_CARE, - 'I7': cte.OUT_PATIENT_HEALTH_CARE, - 'I9': cte.OUT_PATIENT_HEALTH_CARE, - 'J1': cte.LARGE_OFFICE, - 'J2': cte.LARGE_OFFICE, - 'J3': cte.LARGE_OFFICE, - 'J4': cte.LARGE_OFFICE, - 'J5': cte.LARGE_OFFICE, - 'J6': cte.LARGE_OFFICE, - 'J7': cte.LARGE_OFFICE, - 'J8': cte.LARGE_OFFICE, - 'J9': cte.LARGE_OFFICE, - 'K1': cte.STRIP_MALL, - 'K2': cte.STRIP_MALL, - 'K3': cte.STRIP_MALL, - 'K4': cte.RESIDENTIAL, - 'K5': cte.RESTAURANT, - 'K6': cte.SUPERMARKET, - 'K7': cte.SUPERMARKET, - 'K8': cte.SUPERMARKET, - 'K9': cte.SUPERMARKET, - 'L1': cte.RESIDENTIAL, - 'L2': cte.RESIDENTIAL, - 'L3': cte.RESIDENTIAL, - 'L8': cte.RESIDENTIAL, - 'L9': cte.RESIDENTIAL, - 'M1': cte.LARGE_OFFICE, - 'M2': cte.LARGE_OFFICE, - 'M3': cte.LARGE_OFFICE, - 'M4': cte.LARGE_OFFICE, - 'M9': cte.LARGE_OFFICE, - 'N1': cte.RESIDENTIAL, - 'N2': cte.RESIDENTIAL, - 'N3': cte.RESIDENTIAL, - 'N4': cte.RESIDENTIAL, - 'N9': cte.RESIDENTIAL, - 'O1': cte.SMALL_OFFICE, - 'O2': cte.SMALL_OFFICE, - 'O3': cte.SMALL_OFFICE, - 'O4': cte.SMALL_OFFICE, - 'O5': cte.SMALL_OFFICE, - 'O6': cte.SMALL_OFFICE, - 'O7': cte.SMALL_OFFICE, - 'O8': cte.SMALL_OFFICE, - 'O9': cte.SMALL_OFFICE, - 'P1': cte.LARGE_OFFICE, - 'P2': cte.HOTEL, - 'P3': cte.SMALL_OFFICE, - 'P4': cte.SMALL_OFFICE, - 'P5': cte.SMALL_OFFICE, - 'P6': cte.SMALL_OFFICE, - 'P7': cte.LARGE_OFFICE, - 'P8': cte.LARGE_OFFICE, - 'P9': cte.SMALL_OFFICE, - 'Q0': cte.SMALL_OFFICE, - 'Q1': cte.SMALL_OFFICE, - 'Q2': cte.SMALL_OFFICE, - 'Q3': cte.SMALL_OFFICE, - 'Q4': cte.SMALL_OFFICE, - 'Q5': cte.SMALL_OFFICE, - 'Q6': cte.SMALL_OFFICE, - 'Q7': cte.SMALL_OFFICE, - 'Q8': cte.SMALL_OFFICE, - 'Q9': cte.SMALL_OFFICE, - 'R0': cte.RESIDENTIAL, - 'R1': cte.RESIDENTIAL, - 'R2': cte.RESIDENTIAL, - 'R3': cte.RESIDENTIAL, - 'R4': cte.RESIDENTIAL, - 'R5': cte.RESIDENTIAL, - 'R6': cte.RESIDENTIAL, - 'R7': cte.RESIDENTIAL, - 'R8': cte.RESIDENTIAL, - 'R9': cte.RESIDENTIAL, - 'RA': cte.RESIDENTIAL, - 'RB': cte.RESIDENTIAL, - 'RC': cte.RESIDENTIAL, - 'RD': cte.RESIDENTIAL, - 'RG': cte.RESIDENTIAL, - 'RH': cte.RESIDENTIAL, - 'RI': cte.RESIDENTIAL, - 'RK': cte.RESIDENTIAL, - 'RM': cte.RESIDENTIAL, - 'RR': cte.RESIDENTIAL, - 'RS': cte.RESIDENTIAL, - 'RW': cte.RESIDENTIAL, - 'RX': cte.RESIDENTIAL, - 'RZ': cte.RESIDENTIAL, - 'S0': cte.RESIDENTIAL, - 'S1': cte.RESIDENTIAL, - 'S2': cte.RESIDENTIAL, - 'S3': cte.RESIDENTIAL, - 'S4': cte.RESIDENTIAL, - 'S5': cte.RESIDENTIAL, - 'S9': cte.RESIDENTIAL, - 'U0': cte.WAREHOUSE, - 'U1': cte.WAREHOUSE, - 'U2': cte.WAREHOUSE, - 'U3': cte.WAREHOUSE, - 'U4': cte.WAREHOUSE, - 'U5': cte.WAREHOUSE, - 'U6': cte.WAREHOUSE, - 'U7': cte.WAREHOUSE, - 'U8': cte.WAREHOUSE, - 'U9': cte.WAREHOUSE, - 'W1': cte.PRIMARY_SCHOOL, - 'W2': cte.PRIMARY_SCHOOL, - 'W3': cte.SECONDARY_SCHOOL, - 'W4': cte.EDUCATION, - 'W5': cte.SECONDARY_SCHOOL, - 'W6': cte.SECONDARY_SCHOOL, - 'W7': cte.SECONDARY_SCHOOL, - 'W8': cte.PRIMARY_SCHOOL, - 'W9': cte.SECONDARY_SCHOOL, - 'Y1': cte.LARGE_OFFICE, - 'Y2': cte.LARGE_OFFICE, - 'Y3': cte.LARGE_OFFICE, - 'Y4': cte.LARGE_OFFICE, - 'Y5': cte.LARGE_OFFICE, - 'Y6': cte.LARGE_OFFICE, - 'Y7': cte.LARGE_OFFICE, - 'Y8': cte.LARGE_OFFICE, - 'Y9': cte.LARGE_OFFICE, - 'Z1': cte.LARGE_OFFICE - } - _hft_function_to_hub_function = { - 'residential': cte.RESIDENTIAL, - 'single family house': cte.SINGLE_FAMILY_HOUSE, - 'multifamily house': cte.MULTI_FAMILY_HOUSE, - 'hotel': cte.HOTEL, - 'hospital': cte.HOSPITAL, - 'outpatient': cte.OUT_PATIENT_HEALTH_CARE, - 'commercial': cte.SUPERMARKET, - 'strip mall': cte.STRIP_MALL, - 'warehouse': cte.WAREHOUSE, - 'primary school': cte.PRIMARY_SCHOOL, - 'secondary school': cte.EDUCATION, - 'office': cte.MEDIUM_OFFICE, - 'large office': cte.LARGE_OFFICE - } @property - def hub_usage_to_hft_usage(self): + def hub_usage_to_hft_usage(self) -> dict: """ - Get HfT usage from the given internal usage + Hub usage to HfT usage, transformation dictionary :return: dict """ - return self._usage_to_hft_usage + return HubUsageToHftUsage().dictionary @property - def hub_usage_to_comnet_usage(self): + def hub_usage_to_comnet_usage(self) -> dict: """ - Get Comnet usage from the given internal usage + Hub usage to Comnet usage, transformation dictionary :return: dict """ - return self._usage_to_comnet_usage + return HubUsageToComnetUsage().dictionary @property - def hub_usage_to_nrcan_usage(self): + def hub_usage_to_nrcan_usage(self) -> dict: """ - Get Nrcan usage from the given internal usage + Get hub usage to NRCAN usage, transformation dictionary :return: dict """ - return self._usage_to_nrcan_usage + return HubUsageToNrcanUsage().dictionary @property - def hub_function_to_nrcan_construction_function(self): + def hub_function_to_nrcan_construction_function(self) -> dict: """ - Get Nrcan construction function from the given internal function + Get hub function to NRCAN construction function, transformation dictionary :return: dict """ - return self._function_to_nrcan_construction_function + return HubFunctionToNrcanConstructionFunction().dictionary @property - def hub_function_to_nrel_construction_function(self): + def hub_function_to_nrel_construction_function(self) -> dict: """ - Get Nrel construction function from the given internal function + Get hub function to NREL construction function, transformation dictionary :return: dict """ - return self._function_to_nrel_construction_function + return HubFunctionToNrelConstructionFunction().dictionary @property - def pluto_function_to_hub_function(self): + def pluto_function_to_hub_function(self) -> dict: """ - Set internal function from pluto standard + Get Pluto function to hub function, transformation dictionary :return: dict """ - return self._pluto_function_to_hub_function + return PlutoFunctionToHubFunction().dictionary @property - def hft_function_to_hub_function(self): + def hft_function_to_hub_function(self) -> dict: """ - Set internal function from functions used in hft files + Get Hft function to hub function, transformation dictionary :return: dict """ - return self._hft_function_to_hub_function + return HftFunctionToHubFunction().dictionary + + @property + def montreal_function_to_hub_function(self) -> dict: + """ + Get Montreal function to hub function, transformation dictionary + """ + return MontrealFunctionToHubFunction().dictionary + + @property + def alkis_function_to_hub_function(self) -> dict: + """ + Get Alkis function to hub function, transformation dictionary + """ + return AlkisFunctionToHubFunction().dictionary + diff --git a/hub/imports/db_factory.py b/hub/imports/db_factory.py index f4d75ba8..7ec0e4f4 100644 --- a/hub/imports/db_factory.py +++ b/hub/imports/db_factory.py @@ -4,10 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project CoderPeter Yefi peteryefi@gmail.com """ -from hub.persistence import CityRepo -from hub.persistence import HeatPumpSimulationRepo -from typing import Dict from hub.city_model_structure.city import City +from hub.persistence import City as CityRepository +from hub.persistence import SimulationResults class DBFactory: @@ -16,14 +15,17 @@ class DBFactory: """ def __init__(self, db_name, dotenv_path, app_env): - self._city_repo = CityRepo(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) - self._hp_simulation_repo = HeatPumpSimulationRepo(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) + self._city_repository = CityRepository(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) + self._simulation_results = SimulationResults(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) - def persist_city(self, user_id: int, city: City): + def persist_city(self, city: City, application_id: int, user_id: int): """ Persist city into postgres database + :param city: City to be stored + :param application_id: Application id owning this city + :param user_id: User who create the city """ - return self._city_repo.insert(city, user_id) + return self._city_repository.insert(city, application_id, user_id) def update_city(self, city_id, city): """ @@ -31,27 +33,21 @@ class DBFactory: :param city_id: the id of the city to update :param city: the updated city object """ - return self._city_repo.update(city_id, city) + return self._city_repository.update(city_id, city) def delete_city(self, city_id): """ Deletes a single city from postgres :param city_id: the id of the city to get """ - self._city_repo.delete_city(city_id) + self._city_repository.delete(city_id) - def persist_hp_simulation(self, hp_simulation_data: Dict, city_id: int): + def add_simulation_results(self, name, values, city_id=None, city_object_id=None): """ - 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 + Add simulation results to the city or to the city_object + :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 """ - 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) + self._simulation_results.insert(name, values,city_id, city_object_id) diff --git a/hub/imports/geometry/citygml.py b/hub/imports/geometry/citygml.py index d6701393..bcd3dec8 100644 --- a/hub/imports/geometry/citygml.py +++ b/hub/imports/geometry/citygml.py @@ -19,12 +19,18 @@ class CityGml: """ CityGml class """ - def __init__(self, path, extrusion_height_field=None, year_of_construction_field=None, function_field=None): + def __init__(self, + path, + extrusion_height_field=None, + year_of_construction_field='yearOfConstruction', + function_field='function', + function_to_hub=None): self._city = None self._lod = None self._lod1_tags = ['lod1Solid', 'lod1MultiSurface'] self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve'] self._extrusion_height_field = extrusion_height_field + self._function_to_hub = function_to_hub self._year_of_construction_field = year_of_construction_field if function_field is None: function_field = 'function' @@ -110,12 +116,15 @@ class CityGml: name = city_object['@id'] function = None year_of_construction = None - if 'yearOfConstruction' in city_object: - year_of_construction = city_object['yearOfConstruction'] - if 'function' in city_object: + if self._year_of_construction_field in city_object: + year_of_construction = city_object[self._year_of_construction_field] + if self._function_field in city_object: function = city_object[self._function_field] if type(function) != str: function = function['#text'] + if self._function_to_hub is not None: + # use the transformation dictionary to retrieve the proper function + function = self._function_to_hub[function] if any(key in city_object for key in self._lod1_tags): if self._lod is None or self._lod > 1: diff --git a/hub/imports/geometry/geojson.py b/hub/imports/geometry/geojson.py index f7c91082..2735982f 100644 --- a/hub/imports/geometry/geojson.py +++ b/hub/imports/geometry/geojson.py @@ -26,7 +26,12 @@ class Geojson: X = 0 Y = 1 - def __init__(self, path, extrusion_height_field=None, year_of_construction_field=None, function_field=None): + def __init__(self, + path, + extrusion_height_field=None, + year_of_construction_field=None, + function_field=None, + function_to_hub=None): # todo: destination epsg should change according actual the location self._transformer = Transformer.from_crs('epsg:4326', 'epsg:26911') self._min_x = cte.MAX_FLOAT @@ -38,6 +43,7 @@ class Geojson: self._extrusion_height_field = extrusion_height_field self._year_of_construction_field = year_of_construction_field self._function_field = function_field + self._function_to_hub = function_to_hub with open(path) as json_file: self._geojson = json.loads(json_file.read()) @@ -118,6 +124,9 @@ class Geojson: function = None if self._function_field is not None: function = feature['properties'][self._function_field] + if self._function_to_hub is not None: + # use the transformation dictionary to retrieve the proper function + function = self._function_to_hub[function] geometry = feature['geometry'] if 'id' in feature: building_name = feature['id'] diff --git a/hub/imports/geometry_factory.py b/hub/imports/geometry_factory.py index f80580a5..b8ba7e68 100644 --- a/hub/imports/geometry_factory.py +++ b/hub/imports/geometry_factory.py @@ -26,7 +26,8 @@ class GeometryFactory: data_frame=None, height_field=None, year_of_construction_field=None, - function_field=None): + function_field=None, + function_to_hub=None): self._file_type = '_' + file_type.lower() class_funcs = validate_import_export_type(GeometryFactory) if self._file_type not in class_funcs: @@ -38,6 +39,7 @@ class GeometryFactory: self._height_field = height_field self._year_of_construction_field = year_of_construction_field self._function_field = function_field + self._function_to_hub = function_to_hub @property def _citygml(self) -> City: @@ -45,7 +47,11 @@ class GeometryFactory: Enrich the city by using CityGML information as data source :return: City """ - return CityGml(self._path, self._height_field, self._year_of_construction_field, self._function_field).city + return CityGml(self._path, + self._height_field, + self._year_of_construction_field, + self._function_field, + self._function_to_hub).city @property def _obj(self) -> City: @@ -71,7 +77,11 @@ class GeometryFactory: Enrich the city by using Geojson information as data source :return: City """ - return Geojson(self._path, self._height_field, self._year_of_construction_field, self._function_field).city + return Geojson(self._path, + self._height_field, + self._year_of_construction_field, + self._function_field, + self._function_to_hub).city @property def _osm_subway(self) -> City: diff --git a/hub/imports/results/insel_monthly_energry_balance.py b/hub/imports/results/insel_monthly_energry_balance.py new file mode 100644 index 00000000..385a8aa8 --- /dev/null +++ b/hub/imports/results/insel_monthly_energry_balance.py @@ -0,0 +1,53 @@ +""" +Insel monthly energy balance +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guillermo.GutierrezMorote@concordia.ca +""" + +from pathlib import Path +import pandas as pd +import csv +import hub.helpers.constants as cte + +class InselMonthlyEnergyBalance: + """ + Import SRA results + """ + def __init__(self, city, base_path): + + self._city = city + self._base_path = base_path + + @staticmethod + def _demand(insel_output_file_path): + heating = [] + cooling = [] + with open(Path(insel_output_file_path).resolve()) as csv_file: + csv_reader = csv.reader(csv_file) + for line in csv_reader: + demand = str(line).replace("['", '').replace("']", '').split() + for i in range(0, 2): + if demand[i] != 'NaN': + aux = float(demand[i]) * 1000 # kWh to Wh + demand[i] = str(aux) + else: + demand[i] = '0' + heating.append(demand[0]) + cooling.append(demand[1]) + monthly_heating = pd.DataFrame(heating, columns=[cte.INSEL_MEB]) + monthly_cooling = pd.DataFrame(cooling, columns=[cte.INSEL_MEB]) + return monthly_heating, monthly_cooling + + def enrich(self): + for building in self._city.buildings: + file_name = building.name + '.out' + insel_output_file_path = Path(self._base_path / file_name).resolve() + if insel_output_file_path.is_file(): + building.heating[cte.MONTH], building.cooling[cte.MONTH] = self._demand(insel_output_file_path) + building.heating[cte.YEAR] = pd.DataFrame( + [building.heating[cte.MONTH][cte.INSEL_MEB].sum()], columns=[cte.INSEL_MEB] + ) + building.cooling[cte.YEAR] = pd.DataFrame( + [building.cooling[cte.MONTH][cte.INSEL_MEB].sum()], columns=[cte.INSEL_MEB] + ) diff --git a/hub/imports/results/simplified_radiosity_algorithm.py b/hub/imports/results/simplified_radiosity_algorithm.py new file mode 100644 index 00000000..334a26b1 --- /dev/null +++ b/hub/imports/results/simplified_radiosity_algorithm.py @@ -0,0 +1,97 @@ +""" +Simplified Radiosity Algorithm +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guillermo.GutierrezMorote@concordia.ca +""" +import pandas as pd +import numpy as np +import calendar as cal +import hub.helpers.constants as cte + + +class SimplifiedRadiosityAlgorithm: + """ + Import SRA results + """ + def __init__(self, city, base_path): + + self._city = city + self._base_path = base_path + self._input_file_path = (self._base_path / f'{self._city.name}_sra_SW.out') + self._month_hour = self._month_hour_data_frame + self._results = self._read_results() + self._radiation_list = [] + + @property + def _month_hour_data_frame(self): + array = [] + for i in range(0, 12): + days_of_month = cal.monthrange(2015, i+1)[1] + total_hours = days_of_month * 24 + array = np.concatenate((array, np.full(total_hours, i + 1))) + return pd.DataFrame(array, columns=[cte.MONTH]) + + def _get_monthly_mean_values(self, values): + out = None + if values is not None: + if cte.MONTH not in values.columns: + values = pd.concat([self._month_hour, pd.DataFrame(values)], axis=1) + out = values.groupby(cte.MONTH, as_index=False).mean() + del out[cte.MONTH] + return out + + def _get_yearly_mean_values(self, values): + return values.mean() + + def _read_results(self): + try: + return pd.read_csv(self._input_file_path, sep='\s+', header=0) + except Exception: + raise Exception('No SRA output file found') + + @property + def _radiation(self) -> []: + if len(self._radiation_list) == 0: + id_building = '' + header_building = [] + for column in self._results.columns.values: + if id_building != column.split(':')[1]: + id_building = column.split(':')[1] + if len(header_building) > 0: + self._radiation_list.append(pd.concat([self._month_hour, self._results[header_building]],axis=1)) + header_building = [column] + else: + header_building.append(column) + self._radiation_list.append(pd.concat([self._month_hour, self._results[header_building]], axis=1)) + return self._radiation_list + + def enrich(self): + """ + saves in building surfaces the correspondent irradiance at different time-scales depending on the mode + if building is None, it saves all buildings' surfaces in file, if building is specified, it saves only that + specific building values + :return: none + """ + for radiation in self._radiation: + city_object_name = radiation.columns.values.tolist()[1].split(':')[1] + building = self._city.city_object(city_object_name) + for column in radiation.columns.values: + if column == cte.MONTH: + continue + header_id = column + surface_id = header_id.split(':')[2] + surface = building.surface_by_id(surface_id) + new_value = pd.DataFrame(radiation[[header_id]].to_numpy(), columns=[cte.SRA]) + month_new_value = self._get_monthly_mean_values(new_value) + if cte.MONTH not in surface.global_irradiance: + surface.global_irradiance[cte.MONTH] = month_new_value + else: + pd.concat([surface.global_irradiance[cte.MONTH], month_new_value], axis=1) + if cte.HOUR not in surface.global_irradiance: + surface.global_irradiance[cte.HOUR] = new_value + else: + pd.concat([surface.global_irradiance[cte.HOUR], new_value], axis=1) + if cte.YEAR not in surface.global_irradiance: + surface.global_irradiance[cte.YEAR] = self._get_yearly_mean_values(new_value) + self._city.level_of_detail.surface_radiation = 2 diff --git a/hub/imports/results_factory.py b/hub/imports/results_factory.py new file mode 100644 index 00000000..afa90fb6 --- /dev/null +++ b/hub/imports/results_factory.py @@ -0,0 +1,49 @@ +""" +Result factory retrieve the specific tool results and store the data in the given city +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca +Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca +""" +from pathlib import Path + +from hub.helpers.utils import validate_import_export_type +from hub.hub_logger import logger +from hub.imports.results.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm +from hub.imports.results.insel_monthly_energry_balance import InselMonthlyEnergyBalance + + +class ResultFactory: + """ + UsageFactory class + """ + def __init__(self, handler, city, base_path=None): + if base_path is None: + base_path = Path(Path(__file__).parent.parent / 'data/results') + self._handler = '_' + handler.lower().replace(' ', '_') + class_funcs = validate_import_export_type(ResultFactory) + if self._handler not in class_funcs: + err_msg = f"Wrong import type [{self._handler}]. Valid functions include {class_funcs}" + logger.error(err_msg) + raise Exception(err_msg) + self._city = city + self._base_path = base_path + + def _sra(self): + """ + Enrich the city with Simplified Radiosity Algorithm results + """ + SimplifiedRadiosityAlgorithm(self._city, self._base_path).enrich() + + def _insel_meb(self): + """ + Enrich the city with insel monthly energy balance results + """ + InselMonthlyEnergyBalance(self._city, self._base_path).enrich() + + def enrich(self): + """ + Enrich the city given to the class using the usage factory given handler + :return: None + """ + getattr(self, self._handler, lambda: None)() diff --git a/hub/imports/weather/epw_weather_parameters.py b/hub/imports/weather/epw_weather_parameters.py index 658e1871..47ddb5fe 100644 --- a/hub/imports/weather/epw_weather_parameters.py +++ b/hub/imports/weather/epw_weather_parameters.py @@ -9,6 +9,7 @@ import sys from pathlib import Path import pandas as pd import hub.helpers.constants as cte +from hub.imports.weather.helpers.weather import Weather as wh class EpwWeatherParameters: @@ -110,3 +111,10 @@ class EpwWeatherParameters: building.beam[cte.HOUR] = new_value else: pd.concat([building.beam[cte.HOUR], new_value], axis=1) + # create the monthly and yearly values out of the hourly + for building in self._city.buildings: + if cte.MONTH not in building.external_temperature: + building.external_temperature[cte.MONTH] = wh().get_monthly_mean_values(building.external_temperature[cte.HOUR][['epw']]) + if cte.YEAR not in building.external_temperature: + building.external_temperature[cte.YEAR] = wh(). get_yearly_mean_values(building.external_temperature[cte.HOUR][['epw']]) + self._city.level_of_detail.weather = 2 diff --git a/hub/imports/weather/helpers/weather.py b/hub/imports/weather/helpers/weather.py index 94769078..ae4c9ad2 100644 --- a/hub/imports/weather/helpers/weather.py +++ b/hub/imports/weather/helpers/weather.py @@ -6,6 +6,9 @@ Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ import math import hub.helpers.constants as cte +import pandas as pd +import calendar as cal +import numpy as np class Weather: @@ -28,3 +31,38 @@ class Weather: + 0.32 * (temperature + cte.KELVIN) - cte.KELVIN values.append(value) return values + + def get_monthly_mean_values(self, values): + out = None + if values is not None: + if 'month' not in values.columns: + values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1) + out = values.groupby('month', as_index=False).mean() + del out['month'] + return out + + def get_yearly_mean_values(self, values): + return values.mean() + + def get_total_month(self, values): + out = None + if values is not None: + if 'month' not in values.columns: + values = pd.concat([self.month_hour, pd.DataFrame(values)], axis=1) + out = pd.DataFrame(values).groupby('month', as_index=False).sum() + del out['month'] + return out + + @property + def month_hour(self): + """ + returns a DataFrame that has x values of the month number (January = 1, February = 2...), + being x the number of hours of the corresponding month + :return: DataFrame(int) + """ + array = [] + for i in range(0, 12): + days_of_month = cal.monthrange(2015, i+1)[1] + total_hours = days_of_month * 24 + array = np.concatenate((array, np.full(total_hours, i + 1))) + return pd.DataFrame(array, columns=['month']) diff --git a/hub/persistence/__init__.py b/hub/persistence/__init__.py index caebc883..19c4e0dc 100644 --- a/hub/persistence/__init__.py +++ b/hub/persistence/__init__.py @@ -1,6 +1,8 @@ -from .base_repo import BaseRepo -from .repositories.city_repo import CityRepo -from .repositories.heat_pump_simulation_repo import HeatPumpSimulationRepo +from .repository import Repository +from .repositories.city import City +from .repositories.application import Application +from .repositories.simulation_results import SimulationResults +from .repositories.city_object import CityObject from .db_setup import DBSetup -from .repositories.user_repo import UserRepo +from .repositories.user import User from .models.user import UserRoles diff --git a/hub/persistence/db_config.py b/hub/persistence/configuration.py similarity index 91% rename from hub/persistence/db_config.py rename to hub/persistence/configuration.py index 4ef2dc14..c3afdc77 100644 --- a/hub/persistence/db_config.py +++ b/hub/persistence/configuration.py @@ -10,13 +10,12 @@ from dotenv import load_dotenv from sqlalchemy.ext.declarative import declarative_base from hub.hub_logger import logger -Base = declarative_base() +Models = declarative_base() - -class BaseConfiguration(object): +class Configuration: + """ + Configuration class to hold common persistence configuration """ - Base configuration class to hold common persistence configuration - """ def __init__(self, db_name: str, dotenv_path: str, app_env='TEST'): """ diff --git a/hub/persistence/db_setup.py b/hub/persistence/db_setup.py index 5bdcb13c..cf3786f1 100644 --- a/hub/persistence/db_setup.py +++ b/hub/persistence/db_setup.py @@ -1,42 +1,67 @@ +""" +Database setup +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Peter Yefi peteryefi@gmail.com +""" -from hub.persistence import BaseRepo +from hub.persistence import Repository +from hub.persistence.models import Application from hub.persistence.models import City -from hub.persistence.models import HeatPumpSimulation +from hub.persistence.models import CityObject from hub.persistence.models import User from hub.persistence.models import UserRoles -from hub.persistence.models import Application -from hub.persistence.models import UserApplications -from hub.persistence.repositories import UserRepo +from hub.persistence.models import SimulationResults +from hub.persistence.repositories import User as UserRepository +from hub.persistence.repositories import Application as ApplicationRepository from hub.hub_logger import logger class DBSetup: - def __init__(self, db_name, app_env, dotenv_path): + def __init__(self, db_name, app_env, dotenv_path, admin_password, application_uuid): """ - Creates database tables and a default admin user + Creates database tables a default admin user and a default admin app with the given password and uuid :param db_name: :param app_env: :param dotenv_path: """ - repo = BaseRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) - User.__table__.create(bind=repo.engine, checkfirst=True) - City.__table__.create(bind=repo.engine, checkfirst=True) - Application.__table__.create(bind=repo.engine, checkfirst=True) - UserApplications.__table__.create(bind=repo.engine, checkfirst=True) - HeatPumpSimulation.__table__.create(bind=repo.engine, checkfirst=True) - self._user_repo = UserRepo(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) - self._create_admin_user(self._user_repo) + repository = Repository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + + # Create the tables using the models + Application.__table__.create(bind=repository.engine, checkfirst=True) + 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) + + self._user_repo = UserRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + self._application_repo = ApplicationRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) + application_id = self._create_admin_app(self._application_repo, application_uuid) + self._create_admin_user(self._user_repo, admin_password, application_id) @staticmethod - def _create_admin_user(user_repo): - email = 'admin@hub.com' - password = 'HubAdmin#!98' + def _create_admin_app(application_repo, application_uuid): + name = 'AdminTool' + description = 'Admin tool to control city persistence and to test the API v1.4' + print('Creating default admin tool application...') + application = application_repo.insert(name, description, application_uuid) + + if type(application) is dict: + logger.info(application) + else: + msg = f'Created Admin tool with application_uuid: {application_uuid}' + print(msg) + logger.info(msg) + return application.id + + @staticmethod + def _create_admin_user(user_repo, admin_password, application_id): + password = admin_password print('Creating default admin user...') - user = user_repo.insert('Administrator', email, password, UserRoles.Admin) + user = user_repo.insert('Administrator', password, UserRoles.Admin, application_id) if type(user) is dict: logger.info(user) else: - print(f'Created Admin user with email: {email}, password: {password} and role: {UserRoles.Admin.value}') - logger.info(f'Created Admin user with email: {email}, password: {password} and role: {UserRoles.Admin.value}') - print('Remember to change the admin default password and email address with the UserFactory') + print(f'Created Admin user') + logger.info(f'Created Admin user') diff --git a/hub/persistence/models/__init__.py b/hub/persistence/models/__init__.py index 89986d04..77f5c105 100644 --- a/hub/persistence/models/__init__.py +++ b/hub/persistence/models/__init__.py @@ -1,7 +1,5 @@ -from .city import City -from .heat_pump_simulation import HeatPumpSimulation -from .heat_pump_simulation import SimulationTypes -from .heat_pump_simulation import HeatPumpTypes -from .user import User, UserRoles -from .user_applications import UserApplications from .application import Application +from .city import City +from .city_object import CityObject +from .simulation_results import SimulationResults +from .user import User, UserRoles diff --git a/hub/persistence/models/application.py b/hub/persistence/models/application.py index d62baf8f..3da947f4 100644 --- a/hub/persistence/models/application.py +++ b/hub/persistence/models/application.py @@ -7,23 +7,25 @@ Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca import datetime +from sqlalchemy.dialects.postgresql import UUID from sqlalchemy import Column, Integer, String, Sequence from sqlalchemy import DateTime - -from hub.persistence.db_config import Base +from hub.persistence.configuration import Models -class Application(Base): +class Application(Models): """ A model representation of an application """ - __tablename__ = "application" + __tablename__ = 'application' id = Column(Integer, Sequence('application_id_seq'), primary_key=True) name = Column(String, nullable=False) description = Column(String, nullable=False) + application_uuid = Column(UUID(as_uuid=True), nullable=False) created = Column(DateTime, default=datetime.datetime.utcnow) updated = Column(DateTime, default=datetime.datetime.utcnow) - def __init__(self, name, description): + def __init__(self, name, description, application_uuid): self.name = name self.description = description + self.application_uuid = application_uuid diff --git a/hub/persistence/models/city.py b/hub/persistence/models/city.py index 3242d17f..dfec2b63 100644 --- a/hub/persistence/models/city.py +++ b/hub/persistence/models/city.py @@ -5,44 +5,33 @@ Copyright © 2022 Concordia CERC group Project Coder Peter Yefi peteryefi@gmail.com """ -from sqlalchemy import Column, Integer, String, Sequence, ForeignKey -from sqlalchemy import DateTime, PickleType, Float -from hub.persistence.db_config import Base -from sqlalchemy.dialects.postgresql import JSONB -from sqlalchemy.orm import relationship import datetime -import numpy as np + +from sqlalchemy import Column, Integer, String, Sequence, ForeignKey +from sqlalchemy import DateTime, PickleType +from hub.persistence.configuration import Models -class City(Base): +class City(Models): """A model representation of a city """ - __tablename__ = "city" + __tablename__ = 'city' id = Column(Integer, Sequence('city_id_seq'), primary_key=True) city = Column(PickleType, nullable=False) name = Column(String, nullable=False) - srs_name = Column(String, nullable=False) - climate_reference_city = Column(String, nullable=True) - time_zone = Column(String, nullable=True) - country_code = Column(String, nullable=False) - latitude = Column(Float) - longitude = Column(Float) - lower_corner = Column(JSONB, nullable=False) - upper_corner = Column(JSONB, nullable=False) + level_of_detail = Column(Integer, nullable=False) + climate_file = Column(String, nullable=False) + application_id = Column(Integer, ForeignKey('application.id'), nullable=False) + user_id = Column(Integer, ForeignKey('user.id'), nullable=True) hub_release = Column(String, nullable=False) - city_version = Column(Integer, nullable=False) - user_id = Column(Integer, ForeignKey('user.id')) - user = relationship("User", back_populates="cities") created = Column(DateTime, default=datetime.datetime.utcnow) updated = Column(DateTime, default=datetime.datetime.utcnow) - def __init__(self, city, name, srs_name, country_code, l_corner, u_corner, user_id): + def __init__(self, city, name, level_of_detail, climate_file, application_id, user_id, hub_release): self.city = city - self.user_id = user_id self.name = name - self.srs_name = srs_name - self.country_code = country_code - l_corner = l_corner.tolist() if type(l_corner) == np.ndarray else l_corner - u_corner = u_corner.tolist() if type(u_corner) == np.ndarray else u_corner - self.lower_corner = l_corner - self.upper_corner = u_corner + self.level_of_detail = level_of_detail + self.climate_file = climate_file + self.application_id = application_id + self.user_id = user_id + self.hub_release = hub_release diff --git a/hub/persistence/models/city_object.py b/hub/persistence/models/city_object.py new file mode 100644 index 00000000..7229a2ac --- /dev/null +++ b/hub/persistence/models/city_object.py @@ -0,0 +1,41 @@ +""" +Model representation of a city object +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import datetime + +from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float +from sqlalchemy import DateTime +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) + 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): + self.city_id = city_id + self.name = name + self.alias = alias + self.type = object_type + self.year_of_construction = year_of_construction + self.function = function + self.usage = usage + self.volume = volume + self.area = area diff --git a/hub/persistence/models/heat_pump_simulation.py b/hub/persistence/models/heat_pump_simulation.py deleted file mode 100644 index bcc89a5a..00000000 --- a/hub/persistence/models/heat_pump_simulation.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -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 -from sqlalchemy import Enum, ForeignKey, Float, DateTime -from sqlalchemy.dialects.postgresql import JSONB -from hub.persistence.db_config import Base -import enum -import datetime - - -class SimulationTypes(enum.Enum): - Parallel = 'PARALLEL' - Series = 'SERIES' - - -class HeatPumpTypes(enum.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. - 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 - 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) - 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) - 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) - created = Column(DateTime, default=datetime.datetime.utcnow) - - def __init__(self, city_id, hourly_elec_demand, daily_elec_demand, monthly_elec_demand, daily_fossil, monthly_fossil): - self.city_id = city_id - self.hourly_electricity_demand = hourly_elec_demand - self.daily_electricity_demand = daily_elec_demand - self.monthly_electricity_demand = monthly_elec_demand - self.daily_fossil_fuel_consumption = daily_fossil - self.monthly_fossil_fuel_consumption = monthly_fossil diff --git a/hub/persistence/models/simulation_results.py b/hub/persistence/models/simulation_results.py new file mode 100644 index 00000000..defc3e7e --- /dev/null +++ b/hub/persistence/models/simulation_results.py @@ -0,0 +1,32 @@ +""" +Model representation of simulation results +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import datetime + +from sqlalchemy import Column, Integer, String, Sequence, ForeignKey +from sqlalchemy import DateTime +from sqlalchemy.dialects.postgresql import JSONB +from hub.persistence.configuration import Models + +class SimulationResults(Models): + """ + A model representation of an application + """ + __tablename__ = 'simulation_results' + id = Column(Integer, Sequence('simulation_results_id_seq'), primary_key=True) + city_id = Column(Integer, ForeignKey('city.id'), nullable=True) + city_object_id = Column(Integer, ForeignKey('city_object.id'), nullable=True) + name = Column(String, nullable=False) + values = Column(JSONB, nullable=False) + created = Column(DateTime, default=datetime.datetime.utcnow) + updated = Column(DateTime, default=datetime.datetime.utcnow) + + def __init__(self, name, values, city_id=None, city_object_id=None): + self.name = name + self.values = values + self.city_id = city_id + self.city_object_id = city_object_id diff --git a/hub/persistence/models/user.py b/hub/persistence/models/user.py index 91027b27..a40ccece 100644 --- a/hub/persistence/models/user.py +++ b/hub/persistence/models/user.py @@ -5,14 +5,13 @@ Copyright © 2022 Concordia CERC group Project Coder Peter Yefi peteryefi@gmail.com """ +import datetime +import enum + from sqlalchemy import Column, Integer, String, Sequence from sqlalchemy import DateTime, Enum -from hub.persistence.db_config import Base -import datetime -from sqlalchemy.orm import validates -import re -import enum -from sqlalchemy.orm import relationship + +from hub.persistence.configuration import Models class UserRoles(enum.Enum): @@ -20,28 +19,21 @@ class UserRoles(enum.Enum): Hub_Reader = 'Hub_Reader' -class User(Base): - """A model representation of a city +class User(Models): """ - __tablename__ = "user" + A model representation of a city + """ + __tablename__ = 'user' id = Column(Integer, Sequence('user_id_seq'), primary_key=True) name = Column(String, nullable=False) - email = Column(String, nullable=False, unique=True) password = Column(String, nullable=False) role = Column(Enum(UserRoles), nullable=False, default=UserRoles.Hub_Reader) - cities = relationship("City", back_populates="user") + application_id = Column(Integer, nullable=False) created = Column(DateTime, default=datetime.datetime.utcnow) updated = Column(DateTime, default=datetime.datetime.utcnow) - @validates("email") - def validate_email(self, key, address): - pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' - if not re.match(pattern, address): - raise ValueError("failed simple email validation") - return address - - def __init__(self, name, email, password, role): + def __init__(self, name, password, role, application_id): self.name = name - self.email = email self.password = password self.role = role + self.application_id = application_id diff --git a/hub/persistence/models/user_applications.py b/hub/persistence/models/user_applications.py deleted file mode 100644 index 978803f8..00000000 --- a/hub/persistence/models/user_applications.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -Model representation of the user applications -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca -""" - -import datetime - -from sqlalchemy import Column, Integer, ForeignKey, PrimaryKeyConstraint -from sqlalchemy import DateTime - -from hub.persistence.db_config import Base - - -class UserApplications(Base): - """ - A model representation of the user applications - """ - __tablename__ = "user_applications" - user_id = Column(Integer, ForeignKey('user.id')) - application_id = Column(Integer, ForeignKey('application.id')) - - created = Column(DateTime, default=datetime.datetime.utcnow) - updated = Column(DateTime, default=datetime.datetime.utcnow) - __table_args__ = (PrimaryKeyConstraint(user_id, application_id),) - - def __init__(self, user_id, application_id): - self.user_id = user_id - self.application_id = application_id diff --git a/hub/persistence/repositories/__init__.py b/hub/persistence/repositories/__init__.py index febdaca3..158b8448 100644 --- a/hub/persistence/repositories/__init__.py +++ b/hub/persistence/repositories/__init__.py @@ -1 +1,2 @@ -from .user_repo import UserRepo +from .user import User +from .application import Application diff --git a/hub/persistence/repositories/application.py b/hub/persistence/repositories/application.py new file mode 100644 index 00000000..91d720ec --- /dev/null +++ b/hub/persistence/repositories/application.py @@ -0,0 +1,98 @@ +""" +Application repository with database CRUD operations +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import datetime +from typing import Union, Dict + +from sqlalchemy import select +from sqlalchemy.exc import SQLAlchemyError + +from hub.hub_logger import logger +from hub.persistence import Repository +from hub.persistence.models import Application as Model + + +class Application(Repository): + _instance = None + + def __init__(self, db_name: str, dotenv_path: str, app_env: str): + super().__init__(db_name, dotenv_path, app_env) + + def __new__(cls, db_name, dotenv_path, app_env): + """ + Implemented for a singleton pattern + """ + if cls._instance is None: + cls._instance = super(Application, cls).__new__(cls) + return cls._instance + + def insert(self, name: str, description: str, application_uuid: str) -> Union[Model, Dict]: + """ + Inserts a new application + :param name: Application name + :param description: Application description + :param application_uuid: Unique identifier for the application + :return: application and dictionary + """ + application = self.get_by_uuid(application_uuid) + if application is None: + try: + application = Model(name=name, description=description, application_uuid=application_uuid) + self.session.add(application) + self.session.commit() + return application + except SQLAlchemyError as err: + logger.error(f'An error occurred while creating application: {err}') + else: + return {'message': f'An application with {application_uuid} application uuid, already exists'} + + def update(self, application_uuid: str, name: str, description: str) -> Union[Dict, None]: + """ + Updates an application + :param application_uuid: the application uuid of the application to be updated + :param name: the application name + :param description: the application description + :return: + """ + try: + self.session.query(Model).filter( + Model.application_uuid == application_uuid + ).update({'name': name, 'description': description, 'updated': datetime.datetime.utcnow()}) + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while updating application: {err}') + return {'message': 'Error occurred while updating application'} + + def delete(self, application_uuid: str): + """ + Deletes an application with the application_uuid + :param application_uuid: The application uuid + :return: None + """ + try: + self.session.query(Model).filter(Model.application_uuid == application_uuid).delete() + self.session.flush() + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while deleting application: {err}') + + def get_by_uuid(self, application_uuid: str) -> Union[Model, None]: + """ + Fetch Application based on the application uuid + :param application_uuid: the application uuid + :return: Application with the provided application_uuid or None + """ + try: + result_set = self.session.execute(select(Model).where( + Model.application_uuid == application_uuid) + ).first() + if result_set is None: + return None + return result_set[0] + except SQLAlchemyError as err: + logger.error(f'Error while fetching application by application_uuid: {err}') + diff --git a/hub/persistence/repositories/city.py b/hub/persistence/repositories/city.py new file mode 100644 index 00000000..47f36e94 --- /dev/null +++ b/hub/persistence/repositories/city.py @@ -0,0 +1,153 @@ +""" +City 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 +""" + +import datetime +import pickle +from typing import Union, Dict + +from sqlalchemy import select +from sqlalchemy.exc import SQLAlchemyError + +from hub.city_model_structure.city import City as CityHub +from hub.hub_logger import logger +from hub.persistence import Repository +from hub.persistence.models import City as Model +from hub.persistence.models import CityObject +from hub.version import __version__ + + +class City(Repository): + _instance = None + + def __init__(self, db_name: str, dotenv_path: str, app_env: str): + super().__init__(db_name, dotenv_path, app_env) + + def __new__(cls, db_name, dotenv_path, app_env): + """ + Implemented for a singleton pattern + """ + if cls._instance is None: + cls._instance = super(City, cls).__new__(cls) + return cls._instance + + def insert(self, city: CityHub, application_id, user_id: int) -> Union[Model, Dict]: + """ + Inserts a city + :param city: The complete city instance + :param application_id: Application id owning the instance + :param user_id: User id owning the instance + :return: City and Dictionary + """ + try: + db_city = Model( + pickle.dumps(city), + city.name, + city.level_of_detail.geometry, + 'None' if city.climate_file is None else str(city.climate_file), + application_id, + user_id, + __version__) + + self.session.add(db_city) + self.session.flush() + for building in city.buildings: + 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() + db_city_object = CityObject(db_city.id, + building.name, + building.alias, + building.type, + building.year_of_construction, + building.function, + object_usage, + building.volume, + building.floor_area) + self.session.add(db_city_object) + self.session.flush() + self.session.commit() + return db_city + except SQLAlchemyError as err: + print(f'An error occurred while creating city: {err}') + logger.error(f'An error occurred while creating city: {err}') + + def update(self, city_id: int, city: CityHub): + """ + Updates a city name (other updates makes no sense) + :param city_id: the id of the city to be updated + :param city: the city object + :return: + """ + try: + now = datetime.datetime.utcnow() + 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}') + + def delete(self, city_id: int): + """ + Deletes a City with the id + :param city_id: the city id + :return: a city + """ + try: + self.session.query(Model).filter(Model.id == city_id).delete() + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while fetching city: {err}') + + def get_by_id(self, city_id: int) -> Model: + """ + Fetch a City based on the id + :param city_id: the city id + :return: a city + """ + try: + return self.session.execute(select(Model).where(Model.id == city_id)).first()[0] + except SQLAlchemyError as err: + logger.error(f'Error while fetching city: {err}') + + def _get_by_hub_version_and_name(self, hub_release: str, city_name: str) -> Model: + """ + Fetch a City based on the name and hub project + :param hub_release: the hub release + :param city_name: the name of the city + :return: a city + """ + try: + return self.session.execute(select(Model) + .where(Model.hub_release == hub_release, Model.name == city_name) + ).first() + except SQLAlchemyError as err: + logger.error(f'Error while fetching city: {err}') + + def get_by_name(self, city_name: str) -> [Model]: + """ + Fetch city based on the name + :param city_name: the name of the building + :return: [ModelCity] with the provided name + """ + try: + result_set = self.session.execute(select(Model).where(Model.name == city_name)) + return [building[0] for building in result_set] + except SQLAlchemyError as err: + logger.error(f'Error while fetching city by name: {err}') + + def get_by_user(self, user_id: int) -> [Model]: + """ + Fetch city based on the user who created it + :param user_id: the id of the user + :return: [ModelCity] with the provided name + """ + try: + result_set = self.session.execute(select(Model).where(Model.user_id == user_id)) + return [building[0] for building in result_set] + except SQLAlchemyError as err: + logger.error(f'Error while fetching city by name: {err}') diff --git a/hub/persistence/repositories/city_object.py b/hub/persistence/repositories/city_object.py new file mode 100644 index 00000000..ded9a1ad --- /dev/null +++ b/hub/persistence/repositories/city_object.py @@ -0,0 +1,124 @@ +""" +City Object repository with database CRUD operations +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import datetime +from typing import Union, Dict + +from sqlalchemy import select +from sqlalchemy.exc import SQLAlchemyError + +from hub.hub_logger import logger +from hub.persistence import Repository +from hub.persistence.models import CityObject as Model +from hub.city_model_structure.building import Building + + +class CityObject(Repository): + _instance = None + + def __init__(self, db_name: str, dotenv_path: str, app_env: str): + super().__init__(db_name, dotenv_path, app_env) + + def __new__(cls, db_name, dotenv_path, app_env): + """ + Implemented for a singleton pattern + """ + if cls._instance is None: + cls._instance = super(CityObject, cls).__new__(cls) + return cls._instance + + def insert(self, city_id:int, building: Building) -> Union[Model, Dict]: + """ + Inserts a new city object + :param city_id: city id for the city owning this city object + :param building: the city object (only building for now) to be inserted + return CityObject model and dictionary + """ + 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) + self.session.add(city_object) + self.session.flush() + self.session.commit() + return city_object + except SQLAlchemyError as err: + logger.error(f'An error occurred while creating city_object: {err}') + else: + return {'message': f'A city_object named {building.name} already exists in that city'} + + def update(self,city_id: int, building: Building) -> Union[Dict, None]: + """ + Updates an application + :param city_id: the city id of the city owning the city object + :param building: the city object + :return: + """ + 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() + self.session.query(Model).filter(Model.name == building.name, Model.city_id == city_id).update( + {'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, + 'updated': datetime.datetime.utcnow()}) + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while updating city object: {err}') + return {'message': 'Error occurred while updating application'} + + def delete(self, city_id: int, name: str): + """ + Deletes an application with the application_uuid + :param city_id: The id for the city owning the city object + :param name: The city object name + :return: None + """ + try: + self.session.query(Model).filter(Model.city_id == city_id, Model.name == name).delete() + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while deleting application: {err}') + + def get_by_name_and_city(self, name, city_id) -> [Model]: + """ + Fetch a city object based on name and city id + :param name: city object name + :param city_id: a city identifier + :return: [CityObject] with the provided name belonging to the city with id city_id + """ + try: + _city_object = self.session.execute(select(Model).where( + Model.name == name, Model.city_id == city_id + )).first() + if _city_object is None: + return None + return _city_object[0] + except SQLAlchemyError as err: + print(err) + logger.error(f'Error while fetching application by application_uuid: {err}') diff --git a/hub/persistence/repositories/city_repo.py b/hub/persistence/repositories/city_repo.py deleted file mode 100644 index cda51259..00000000 --- a/hub/persistence/repositories/city_repo.py +++ /dev/null @@ -1,152 +0,0 @@ -""" -City 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 hub.city_model_structure.city import City -from hub.persistence import BaseRepo -from sqlalchemy.exc import SQLAlchemyError -from sqlalchemy import select -from hub.persistence.models import City as DBCity -import pickle -import requests -from urllib3.exceptions import HTTPError -from typing import Union, Dict -from hub.hub_logger import logger -import datetime - - -class CityRepo(BaseRepo): - _instance = None - - def __init__(self, db_name: str, dotenv_path: str, app_env: str): - super().__init__(db_name, dotenv_path, app_env) - - def __new__(cls, db_name, dotenv_path, app_env): - """ - Implemented for a singleton pattern - """ - if cls._instance is None: - cls._instance = super(CityRepo, cls).__new__(cls) - return cls._instance - - def insert(self, city: City, user_id: int) -> Union[City, Dict]: - db_city = DBCity(pickle.dumps(city), city.name, city.srs_name, city.country_code, city.lower_corner, - city.upper_corner, user_id) - db_city.climate_reference_city = city.climate_reference_city - db_city.longitude = city.longitude - db_city.latitude = city.latitude - db_city.time_zone = city.time_zone - - try: - # Retrieve hub project latest release - response = requests.get("https://rs-loy-gitlab.concordia.ca/api/v4/projects/2/repository/branches/master", - headers={"PRIVATE-TOKEN": self.config.hub_token}) - recent_commit = response.json()["commit"]["id"] - logger.info(f'Current commit of hub is {recent_commit}') - exiting_city = self._get_by_hub_version(recent_commit, city.name) - - # Do not persist the same city for the same version of Hub - if exiting_city is None: - db_city.hub_release = recent_commit - cities = self.get_by_name(city.name) - # update version for the same city but different hub versions - - if len(cities) == 0: - db_city.city_version = 0 - else: - db_city.city_version = cities[-1].city_version + 1 - - # Persist city - self.session.add(db_city) - self.session.flush() - self.session.commit() - return db_city - else: - return {'message': f'Same version of {city.name} exist'} - except SQLAlchemyError as err: - logger.error(f'Error while adding city: {err}') - except HTTPError as err: - logger.error(f'Error retrieving Hub latest release: {err}') - - def get_by_id(self, city_id: int) -> DBCity: - """ - Fetch a City based on the id - :param city_id: the city id - :return: a city - """ - try: - return self.session.execute(select(DBCity).where(DBCity.id == city_id)).first()[0] - except SQLAlchemyError as err: - logger.error(f'Error while fetching city: {err}') - - def _get_by_hub_version(self, hub_commit: str, city_name: str) -> City: - """ - Fetch a City based on the name and hub project recent commit - :param hub_commit: the latest hub commit - :param city_name: the name of the city - :return: a city - """ - try: - return self.session.execute(select(DBCity) - .where(DBCity.hub_release == hub_commit, DBCity.name == city_name)).first() - except SQLAlchemyError as err: - logger.error(f'Error while fetching city: {err}') - - def update(self, city_id: int, city: City): - """ - Updates a city - :param city_id: the id of the city to be updated - :param city: the city object - :return: - """ - try: - self.session.query(DBCity).filter(DBCity.id == city_id) \ - .update({ - 'name': city.name, 'srs_name': city.srs_name, 'country_code': city.country_code, 'longitude': city.longitude, - 'latitude': city.latitude, 'time_zone': city.time_zone, 'lower_corner': city.lower_corner.tolist(), - 'upper_corner': city.upper_corner.tolist(), 'climate_reference_city': city.climate_reference_city, - 'updated': datetime.datetime.utcnow() - }) - - self.session.commit() - except SQLAlchemyError as err: - logger.error(f'Error while updating city: {err}') - - def get_by_name(self, city_name: str) -> [DBCity]: - """ - Fetch city based on the name - :param city_name: the name of the building - :return: [ModelCity] with the provided name - """ - try: - result_set = self.session.execute(select(DBCity).where(DBCity.name == city_name)) - return [building[0] for building in result_set] - except SQLAlchemyError as err: - logger.error(f'Error while fetching city by name: {err}') - - def get_by_user(self, user_id: int) -> [DBCity]: - """ - Fetch city based on the user who created it - :param user_id: the id of the user - :return: [ModelCity] with the provided name - """ - try: - result_set = self.session.execute(select(DBCity).where(DBCity.user_id == user_id)) - return [building[0] for building in result_set] - except SQLAlchemyError as err: - logger.error(f'Error while fetching city by name: {err}') - - def delete_city(self, city_id: int): - """ - Deletes a City with the id - :param city_id: the city id - :return: a city - """ - try: - self.session.query(DBCity).filter(DBCity.id == city_id).delete() - self.session.commit() - except SQLAlchemyError as err: - logger.error(f'Error while fetching city: {err}') diff --git a/hub/persistence/repositories/heat_pump_simulation_repo.py b/hub/persistence/repositories/heat_pump_simulation_repo.py deleted file mode 100644 index 4f0ef60e..00000000 --- a/hub/persistence/repositories/heat_pump_simulation_repo.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -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 hub.persistence import BaseRepo, CityRepo -from sqlalchemy.exc import SQLAlchemyError -from sqlalchemy import select -from hub.persistence.models import HeatPumpSimulation -from typing import Union, Dict -from hub.hub_logger import logger - - -class HeatPumpSimulationRepo(BaseRepo): - _instance = None - - def __init__(self, db_name, dotenv_path, app_env): - super().__init__(db_name, dotenv_path, app_env) - self._city_repo = CityRepo(db_name, dotenv_path, app_env) - - def __new__(cls, db_name, dotenv_path, 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_sim_data: Dict, city_id: int) -> Union[HeatPumpSimulation, Dict]: - """ - Inserts the results of heat pump simulation - :param hp_sim_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'} - - try: - hp_simulation = HeatPumpSimulation(city_id, hp_sim_data["HourlyElectricityDemand"], - hp_sim_data["DailyElectricityDemand"], hp_sim_data["MonthlyElectricityDemand"], - hp_sim_data["DailyFossilFuelConsumption"], - hp_sim_data["MonthlyFossilFuelConsumption"]) - hp_simulation.city_id = city_id - hp_simulation.end_year = hp_sim_data["EndYear"] - hp_simulation.start_year = hp_sim_data["StartYear"] - hp_simulation.max_demand_storage_hour = hp_sim_data["HoursOfStorageAtMaxDemand"] - hp_simulation.max_hp_energy_input = hp_sim_data["MaximumHPEnergyInput"] - hp_simulation.building_supply_temp = hp_sim_data["BuildingSuppTemp"] - hp_simulation.temp_difference = hp_sim_data["TemperatureDifference"] - hp_simulation.fuel_lhv = hp_sim_data["FuelLHV"] - hp_simulation.fuel_price = hp_sim_data["FuelPrice"] - hp_simulation.fuel_efficiency = hp_sim_data["FuelEF"] - hp_simulation.fuel_density = hp_sim_data["FuelDensity"] - hp_simulation.hp_supply_temp = hp_sim_data["HPSupTemp"] - hp_simulation.simulation_type = hp_sim_data["SimulationType"] - hp_simulation.heat_pump_model = hp_sim_data["HeatPumpModel"] - hp_simulation.heat_pump_type = hp_sim_data["HeatPumpType"] - - # Persist heat pump simulation data - self.session.add(hp_simulation) - self.session.flush() - self.session.commit() - return hp_simulation - except SQLAlchemyError as err: - logger.error(f'Error while saving heat pump simulation data: {err}') - except KeyError as err: - logger.error(f'A required field is missing in your heat pump simulation dictionary: {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: - logger.error(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: - logger.error(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: - logger.error(f'Error while fetching city: {err}') diff --git a/hub/persistence/repositories/simulation_results.py b/hub/persistence/repositories/simulation_results.py new file mode 100644 index 00000000..ce612620 --- /dev/null +++ b/hub/persistence/repositories/simulation_results.py @@ -0,0 +1,137 @@ +""" +Simulation results repository with database CRUD operations +SPDX - License - Identifier: LGPL - 3.0 - or -later +Copyright © 2022 Concordia CERC group +Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca +""" + +import datetime +from typing import Union, Dict + +from sqlalchemy import select +from sqlalchemy.exc import SQLAlchemyError + +from hub.hub_logger import logger +from hub.persistence import Repository +from hub.persistence.models import SimulationResults as Model +from hub.persistence.models import City +from hub.persistence.models import CityObject + +from hub.city_model_structure.building import Building + + +class SimulationResults(Repository): + _instance = None + + def __init__(self, db_name: str, dotenv_path: str, app_env: str): + super().__init__(db_name, dotenv_path, app_env) + + def __new__(cls, db_name, dotenv_path, app_env): + """ + Implemented for a singleton pattern + """ + if cls._instance is None: + cls._instance = super(SimulationResults, cls).__new__(cls) + return cls._instance + + def insert(self, name: str, values: str, city_id=None, city_object_id=None) -> Union[Model, Dict]: + """ + Inserts simulations results linked either with a city as a whole or with a city object + :param name: results name + :param values: the simulation results in json format + :param city_id: optional city id + :param city_object_id: optional city object id + :return SimulationResults or Dictionary + """ + if city_id is not None: + city = self.get_city(city_id) + if city is None: + return {'message': f'City does not exists'} + else: + city_object = self.get_city_object(city_object_id) + if city_object is None: + return {'message': f'City object does not exists'} + try: + simulation_result = Model(name=name, + values=values, + city_id=city_id, + city_object_id=city_object_id) + self.session.add(simulation_result) + self.session.flush() + self.session.commit() + return simulation_result + except SQLAlchemyError as err: + logger.error(f'An error occurred while creating city_object: {err}') + + def update(self, name: str, values: str, city_id=None, city_object_id=None) -> Union[Dict, None]: + """ + Updates simulation results for a city or a city object + :param name: The simulation results tool and workflow name + :param values: the simulation results in json format + :param city_id: optional city id + :param city_object_id: optional city object id + :return: None or dictionary + """ + try: + if city_id is not None: + self.session.query(Model).filter(Model.name == name, Model.city_id == city_id).update( + { + 'values': values, + 'updated': datetime.datetime.utcnow() + }) + self.session.commit() + elif city_object_id is not None: + self.session.query(Model).filter(Model.name == name, Model.city_object_id == city_object_id).update( + { + 'values': values, + 'updated': datetime.datetime.utcnow() + }) + self.session.commit() + else: + return {'message': 'Missing either city_id or city_object_id'} + except SQLAlchemyError as err: + logger.error(f'Error while updating city object: {err}') + return {'message': 'Error occurred while updating application'} + + def delete(self, name: str, city_id=None, city_object_id=None): + """ + Deletes an application with the application_uuid + :param name: The simulation results tool and workflow name + :param city_id: The id for the city owning the simulation results + :param city_object_id: the id for the city_object ownning these simulation results + + :return: None + """ + try: + if city_id is not None: + self.session.query(Model).filter(Model.name == name, Model.city_id == city_id).delete() + self.session.commit() + elif city_object_id is not None: + self.session.query(Model).filter(Model.name == name, Model.city_object_id == city_object_id).delete() + self.session.commit() + else: + return {'message': 'Missing either city_id or city_object_id'} + except SQLAlchemyError as err: + logger.error(f'Error while deleting application: {err}') + + def get_city(self, city_id) -> [City]: + """ + Fetch a city object based city id + :param city_id: a city identifier + :return: [City] with the provided city_id + """ + try: + return self.session.execute(select(City).where(City.id == city_id)).first() + except SQLAlchemyError as err: + logger.error(f'Error while fetching city by city_id: {err}') + + def get_city_object(self, city_object_id) -> [CityObject]: + """ + Fetch a city object based city id + :param city_object_id: a city object identifier + :return: [CityObject] with the provided city_object_id + """ + try: + return self.session.execute(select(CityObject).where(CityObject.id == city_object_id)).first() + except SQLAlchemyError as err: + logger.error(f'Error while fetching city by city_id: {err}') diff --git a/hub/persistence/repositories/user.py b/hub/persistence/repositories/user.py new file mode 100644 index 00000000..dfa797d6 --- /dev/null +++ b/hub/persistence/repositories/user.py @@ -0,0 +1,120 @@ +""" +User 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 hub.persistence import Repository +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy import select +from hub.persistence.models import User as Model +from hub.persistence.models import UserRoles +from hub.helpers.auth import Auth +from typing import Union, Dict +from hub.hub_logger import logger +import datetime + + +class User(Repository): + _instance = None + + def __init__(self, db_name: str, dotenv_path: str, app_env: str): + super().__init__(db_name, dotenv_path, app_env) + + def __new__(cls, db_name, dotenv_path, app_env): + """ + Implemented for a singleton pattern + """ + if cls._instance is None: + cls._instance = super(User, cls).__new__(cls) + return cls._instance + + def insert(self, name: str, password: str, role: UserRoles, application_id: int) -> Union[Model, Dict]: + """ + Inserts a new user + :param name: user name + :param password: user password + :param role: user rol [Admin or Hub_Reader] + :param application_id: user application id + :return: [User, Dictionary] + """ + user = self.get_by_name_and_application(name, application_id) + if user is None: + try: + user = Model(name=name, password=Auth.hash_password(password), role=role, application_id=application_id) + self.session.add(user) + self.session.flush() + self.session.commit() + return user + except SQLAlchemyError as err: + logger.error(f'An error occurred while creating user: {err}') + else: + return {'message': f'user {name} already exists for that application'} + + def update(self, user_id: int, name: str, password: str, role: UserRoles) -> Union[Dict, None]: + """ + Updates a user + :param user_id: the id of the user to be updated + :param name: the name of the user + :param password: the password of the user + :param role: the role of the user + :return: + """ + try: + self.session.query(Model).filter(Model.id == user_id).update({ + 'name': name, + 'password': Auth.hash_password(password), + 'role': role, + 'updated': datetime.datetime.utcnow() + }) + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while updating user: {err}') + return {'err_msg': 'Error occurred while updated user'} + + def delete(self, user_id: int): + """ + Deletes a user with the id + :param user_id: the user id + :return: None + """ + try: + self.session.query(Model).filter(Model.id == user_id).delete() + self.session.commit() + except SQLAlchemyError as err: + logger.error(f'Error while fetching user: {err}') + + def get_by_name_and_application(self, name: str, application_id: int) -> [Model]: + """ + Fetch user based on the email address + :param name: User name + :param application_id: User application name + :return: [User] matching the search criteria + """ + try: + return self.session.execute( + select(Model).where(Model.name == name, Model.application_id == application_id) + ).first() + except SQLAlchemyError as err: + logger.error(f'Error while fetching user by name and application: {err}') + + def get_by_name_application_and_password(self, name: str, password: str, application_id: int) -> [Model]: + """ + Fetch user based on the email and password + :param name: User name + :param password: User password + :param application_id: User password + + :return: [User] with the provided email and password + """ + try: + user = self.session.execute( + select(Model).where(Model.name == name, Model.application_id == application_id) + ).first() + if user: + if Auth.check_password(password, user[0].password): + return user[0] + return {'message': 'invalid login information'} + except SQLAlchemyError as err: + logger.error(f'Error while fetching user by email: {err}') diff --git a/hub/persistence/repositories/user_repo.py b/hub/persistence/repositories/user_repo.py deleted file mode 100644 index d4979c12..00000000 --- a/hub/persistence/repositories/user_repo.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -City 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 hub.persistence import BaseRepo -from sqlalchemy.exc import SQLAlchemyError -from sqlalchemy import select -from hub.persistence.models import User -from hub.persistence.models import UserRoles -from hub.helpers.auth import Auth -from typing import Union, Dict -from hub.hub_logger import logger -import datetime - - -class UserRepo(BaseRepo): - _instance = None - - def __init__(self, db_name: str, dotenv_path: str, app_env: str): - super().__init__(db_name, dotenv_path, app_env) - - def __new__(cls, db_name, dotenv_path, app_env): - """ - Implemented for a singleton pattern - """ - if cls._instance is None: - cls._instance = super(UserRepo, cls).__new__(cls) - return cls._instance - - def insert(self, name: str, email: str, password: str, role: UserRoles) -> Union[User, Dict]: - user = self.get_by_email(email) - if user is None: - try: - if Auth.validate_password(password): - user = User(name=name, email=email, password=Auth.hash_password(password), role=role) - self.session.add(user) - self.session.flush() - self.session.commit() - return user - except SQLAlchemyError as err: - logger.error(f'An error occurred while creating user: {err}') - else: - return {'message': f'user with {email} email already exists'} - - def update(self, user_id: int, name: str, email: str, password: str, role: UserRoles) -> Union[Dict, None]: - """ - Updates a user - :param user_id: the id of the user to be updated - :param name: the name of the user - :param email: the email of the user - :param password: the password of the user - :param role: the role of the user - :return: - """ - try: - if Auth.validate_password(password): - self.session.query(User).filter(User.id == user_id) \ - .update({'name': name, 'email': email, 'password': Auth.hash_password(password), 'role': role, - 'updated': datetime.datetime.utcnow()}) - self.session.commit() - except SQLAlchemyError as err: - logger.error(f'Error while updating user: {err}') - return {'err_msg': 'Error occurred while updated user'} - - def get_by_email(self, email: str) -> [User]: - """ - Fetch user based on the email address - :param email: the email of the user - :return: [User] with the provided email - """ - try: - return self.session.execute(select(User).where(User.email == email)).first() - except SQLAlchemyError as err: - logger.error(f'Error while fetching user by email: {err}') - - def delete_user(self, user_id: int): - """ - Deletes a user with the id - :param user_id: the user id - :return: None - """ - try: - self.session.query(User).filter(User.id == user_id).delete() - self.session.commit() - except SQLAlchemyError as err: - logger.error(f'Error while fetching user: {err}') - - def get_user_by_email_and_password(self, email: str, password: str) -> [User]: - """ - Fetch user based on the email and password - :param email: the email of the user - :param password: the password of the user - :return: [User] with the provided email and password - """ - try: - user = self.session.execute(select(User).where(User.email == email)).first() - if user: - if Auth.check_password(password, user[0].password): - return user - else: - return {'message': 'Wrong email/password combination'} - return {'message': 'user not found'} - except SQLAlchemyError as err: - logger.error(f'Error while fetching user by email: {err}') diff --git a/hub/persistence/base_repo.py b/hub/persistence/repository.py similarity index 68% rename from hub/persistence/base_repo.py rename to hub/persistence/repository.py index 97d5ac1e..d9cea244 100644 --- a/hub/persistence/base_repo.py +++ b/hub/persistence/repository.py @@ -5,17 +5,17 @@ Copyright © 2022 Concordia CERC group Project Coder Peter Yefi peteryefi@gmail.com """ -from hub.persistence.db_config import BaseConfiguration +from hub.persistence.configuration import Configuration from sqlalchemy import create_engine from sqlalchemy.orm import Session -class BaseRepo: +class Repository: def __init__(self, db_name, dotenv_path: str, app_env='TEST'): try: - self.config = BaseConfiguration(db_name, dotenv_path, app_env) - self.engine = create_engine(self.config.conn_string()) + self.configuration = Configuration(db_name, dotenv_path, app_env) + self.engine = create_engine(self.configuration.conn_string()) self.session = Session(self.engine) except ValueError as err: print(f'Missing value for credentials: {err}') diff --git a/requirements.txt b/hub/requirements.txt similarity index 86% rename from requirements.txt rename to hub/requirements.txt index 2847b47c..aefb96c6 100644 --- a/requirements.txt +++ b/hub/requirements.txt @@ -1,6 +1,6 @@ xmltodict numpy -trimesh +trimesh[all]==3.12.0 pyproj pandas requests @@ -22,4 +22,4 @@ bcrypt==4.0.1 shapely geopandas triangle - +psycopg2-binary \ No newline at end of file diff --git a/hub/unittests/test_construction_factory.py b/hub/unittests/test_construction_factory.py index 24cacdb3..7e37777a 100644 --- a/hub/unittests/test_construction_factory.py +++ b/hub/unittests/test_construction_factory.py @@ -104,7 +104,7 @@ class TestConstructionFactory(TestCase): self.assertIsNone(building.households, 'building households is not none') self.assertFalse(building.is_conditioned, 'building is conditioned') self.assertIsNotNone(building.shell, 'building shell is none') - self.assertIsNone(building.human_readable_name, 'building human_readable_name is not none') + self.assertIsNone(building.alias, 'building alias is not none') def _check_thermal_zones(self, internal_zone): for thermal_zone in internal_zone.thermal_zones: diff --git a/hub/unittests/test_exports.py b/hub/unittests/test_exports.py index 2b8afe63..283c9595 100644 --- a/hub/unittests/test_exports.py +++ b/hub/unittests/test_exports.py @@ -91,6 +91,7 @@ class TestExports(TestCase): """ self._export_building_energy('energy_ade') + def test_sra_export(self): """ export to SRA diff --git a/hub/version.py b/hub/version.py new file mode 100644 index 00000000..4020e111 --- /dev/null +++ b/hub/version.py @@ -0,0 +1 @@ +__version__ = '0.1.7.5' diff --git a/pyproject.toml b/pyproject.toml index 0588c800..8c148403 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,49 +4,5 @@ requires = ["setuptools>=61.0.0", "wheel"] build-backend = "setuptools.build_meta" -[project] -name = "cerc_hub" -version = "0.1.7.3" -description = "CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers to create better and sustainable cities" -readme = "README.md" -authors = [{ name = "Guillermo Gutierrez", email = "Guillermo.GutierrezMorote@concordia.ca" }] -license = { file = "LICENSE.md" } -classifiers = [ - "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", - "Programming Language :: Python", - "Programming Language :: Python :: 3", -] -keywords = ["city", "hub", "cerc"] -dependencies = [ - "xmltodict", - "numpy", - "trimesh", - "pyproj", - "pandas", - "requests", - "esoreader", - "geomeppy", - "PyWavefront", - "xlrd", - "openpyxl", - "networkx", - "parseidf==1.0.0", - "ply", - "rhino3dm==7.7.0", - "scipy", - "PyYAML", - "pyecore==0.12.2", - "python-dotenv", - "SQLAlchemy", - "bcrypt==4.0.1", - "shapely", - "geopandas", - "triangle" -] -requires-python = ">=3.9" - -[project.optional-dependencies] -dev = ["pip-tools", "pytest"] - -[project.urls] -Homepage = "https://rs-loy-gitlab.concordia.ca/Guille/hub" +[options.packages.find_namespace] +where = "hub" \ No newline at end of file diff --git a/setup.py b/setup.py index f143896c..ba917de2 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,112 @@ -from setuptools import setup, find_packages -import os.path import glob +import pathlib +from distutils.util import convert_path + +import pkg_resources +from setuptools import setup + +with pathlib.Path('hub/requirements.txt').open() as r: + install_requires = [ + str(requirement) + for requirement + in pkg_resources.parse_requirements(r) + ] + +install_requires.append('setuptools') + +main_ns = {} +version = convert_path('hub/version.py') +with open(version) as f: + exec(f.read(), main_ns) + setup( - name='hub', - version="0.1", - packages=find_packages(exclude="unittests"), - data_files=[ - ('config', [os.path.join('hub/config', 'configuration.ini')]), - ('greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')), - ('data', glob.glob('hub/data/construction/*.xml')), - ('data', glob.glob('hub/data/customized_imports/*.xml')), - ('data', glob.glob('hub/data/energy_systems/*.xml')), - ('data', glob.glob('hub/data/energy_systems/*.insel')), - ('data', glob.glob('hub/data/energy_systems/*.xlsx')), - ('data', glob.glob('hub/data/energy_systems/*.txt')), - ('data', glob.glob('hub/data/energy_systems/*.yaml')), - ('data', glob.glob('hub/data/greenery/*.xml')), - ('data', glob.glob('hub/data/life_cycle_assessment/*.xml')), - ('data', glob.glob('hub/data/schedules/*.xml')), - ('data', glob.glob('hub/data/schedules/*.xlsx')), - ('data', glob.glob('hub/data/schedules/idf_files/*.idf')), - ('data', glob.glob('hub/data/sensors/*.json')), - ('data', glob.glob('hub/data/usage/*.xml')), - ('data', glob.glob('hub/data/usage/*.xlsx')), - ('data', glob.glob('hub/data/weather/*.dat')), - ('data', glob.glob('hub/data/weather/epw/*.epw')), - ('data', glob.glob('hub/data/weather/*.dat')) - ], - setup_requires=['setuptools'] + name='cerc-hub', + version=main_ns['__version__'], + description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help researchers " + "to create better and sustainable cities", + long_description="CERC Hub consist in a set of classes (Central data model), importers and exporters to help " + "researchers to create better and sustainable cities.\n\nDevelop at Concordia university in canada " + "as part of the research group from the next generation cities institute our aim among others it's " + "to provide a comprehensive set of tools to help researchers and urban developers to make decisions " + "to improve the livability and efficiency of our cities", + classifiers=[ + "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + ], + include_package_data=True, + packages=['hub', + 'hub.catalog_factories', + 'hub.catalog_factories.construction', + 'hub.catalog_factories.data_models', + 'hub.catalog_factories.data_models.construction', + 'hub.catalog_factories.data_models.greenery', + 'hub.catalog_factories.data_models.usages', + 'hub.catalog_factories.greenery', + 'hub.catalog_factories.greenery.ecore_greenery', + 'hub.catalog_factories.usage', + 'hub.city_model_structure', + 'hub.city_model_structure.attributes', + 'hub.city_model_structure.building_demand', + 'hub.city_model_structure.energy_systems', + 'hub.city_model_structure.greenery', + 'hub.city_model_structure.iot', + 'hub.city_model_structure.transport', + 'hub.config', + 'hub.data', + 'hub.exports', + 'hub.exports.building_energy', + 'hub.exports.building_energy.idf_files', + 'hub.exports.building_energy.insel', + 'hub.exports.energy_systems', + 'hub.exports.formats', + 'hub.helpers', + 'hub.helpers.data', + 'hub.hub_logger', + 'hub.imports', + 'hub.imports.construction', + 'hub.imports.construction.helpers', + 'hub.imports.construction.data_classes', + 'hub.imports.energy_systems', + 'hub.imports.geometry', + 'hub.imports.geometry.citygml_classes', + 'hub.imports.geometry.helpers', + 'hub.imports.results', + 'hub.imports.usage', + 'hub.imports.weather', + 'hub.imports.weather.helpers', + 'hub.persistence', + 'hub.persistence.models', + 'hub.persistence.repositories', + 'hub.imports' + ], + setup_requires=install_requires, + data_files=[ + ('hub', glob.glob('hub/requirements.txt')), + ('hub/config', glob.glob('hub/config/*.ini')), + ('hub/catalog_factories/greenery/ecore_greenery', glob.glob('hub/catalog_factories/greenery/ecore_greenery/*.ecore')), + ('hub/data/construction.', glob.glob('hub/data/construction/*.xml')), + ('hub/data/customized_imports/', glob.glob('hub/data/customized_imports/*.xml')), + ('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xml')), + ('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.insel')), + ('hub/data/energy_systems/', glob.glob('hub/data/energy_systems/*.xlsx')), + ('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.txt')), + ('hub/data/energy_systems/*', glob.glob('hub/data/energy_systems/*.yaml')), + ('hub/data/greenery/', glob.glob('hub/data/greenery/*.xml')), + ('hub/data/life_cycle_assessment/', glob.glob('hub/data/life_cycle_assessment/*.xml')), + ('hub/data/schedules/', glob.glob('hub/data/schedules/*.xml')), + ('hub/data/schedules/', glob.glob('hub/data/schedules/*.xlsx')), + ('hub/data/schedules/idf_files/', glob.glob('hub/data/schedules/idf_files/*.idf')), + ('hub/data/sensors/', glob.glob('hub/data/sensors/*.json')), + ('hub/data/usage/', glob.glob('hub/data/usage/*.xml')), + ('hub/data/usage/', glob.glob('hub/data/usage/*.xlsx')), + ('hub/data/weather/', glob.glob('hub/data/weather/*.dat')), + ('hub/data/weather/epw/', glob.glob('hub/data/weather/epw/*.epw')), + ('hub/data/weather/', glob.glob('hub/data/weather/*.dat')), + ('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idf')), + ('hub/exports/building_energy/idf_files', glob.glob('hub/exports/building_energy/idf_files/*.idd')), + ('hub/helpers/data', glob.glob('hub/helpers/data/quebec_to_hub.json')) + ], + )